Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1165 lines
28 KiB

  1. /*++
  2. Module Name:
  3. mpsyssup.c
  4. Abstract:
  5. This file contains APIC-related funtions that are
  6. specific to halmps. The functions that can be
  7. shared with the APIC version of the ACPI HAL are
  8. still in mpsys.c.
  9. Author:
  10. Ron Mosgrove (Intel)
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. Jake Oshins - 10-20-97 - split off from mpsys.c
  15. */
  16. #include "halp.h"
  17. #include "apic.inc"
  18. #include "pcmp_nt.inc"
  19. VOID
  20. HalpMpsPCIPhysicalWorkaround (
  21. VOID
  22. );
  23. NTSTATUS
  24. HalpSearchBusForVector(
  25. IN INTERFACE_TYPE BusType,
  26. IN ULONG BusNo,
  27. IN ULONG Vector,
  28. IN OUT PBUS_HANDLER *BusHandler
  29. );
  30. BOOLEAN
  31. HalpMPSBusId2NtBusId (
  32. IN UCHAR ApicBusId,
  33. OUT PPCMPBUSTRANS *ppBusType,
  34. OUT PULONG BusNo
  35. );
  36. //
  37. // Packed, somewhat arbitrary representation of an interrupt source.
  38. // This array, when taken with the next one, allows you to figure
  39. // out which bus-relative source maps to which APIC-relative source.
  40. //
  41. ULONG HalpSourceIrqIds[MAX_SOURCE_IRQS];
  42. //
  43. // Linear mapping of interrupt input on array of I/O APICs, where all the
  44. // APICs have an ordering. (Used as index into HalpIntiInfo. Paired with
  45. // HalpSourceIrqIds.)
  46. //
  47. USHORT HalpSourceIrqMapping[MAX_SOURCE_IRQS];
  48. //
  49. // HalpLastEnumeratedActualProcessor - Number of the last processor
  50. // enumerated and returned to the OS. (Reset on resume from hibernate).
  51. //
  52. // This variable is incremented independently of the processor number
  53. // NT uses.
  54. //
  55. UCHAR HalpLastEnumeratedActualProcessor = 0;
  56. extern USHORT HalpEisaIrqMask;
  57. extern USHORT HalpEisaIrqIgnore;
  58. #ifdef ALLOC_PRAGMA
  59. #pragma alloc_text(INIT,HalpInitIntiInfo)
  60. #pragma alloc_text(INIT,HalpMpsPCIPhysicalWorkaround)
  61. #pragma alloc_text(PAGELK,HalpGetApicInterruptDesc)
  62. #pragma alloc_text(PAGELK, HalpEnableLocalNmiSources)
  63. #pragma alloc_text(PAGE, HalpMPSBusId2NtBusId)
  64. #pragma alloc_text(PAGE, HalpFindIdeBus)
  65. #pragma alloc_text(PAGE, HalpSearchBusForVector)
  66. #pragma alloc_text(PAGE, HalpInterruptsDescribedByMpsTable)
  67. #pragma alloc_text(PAGE, HalpPci2MpsBusNumber)
  68. #endif
  69. VOID
  70. HalpInitIntiInfo (
  71. VOID
  72. )
  73. /*++
  74. Routine Description:
  75. This function is called at initialization time before any interrupts
  76. are connected. It reads the PC+MP Inti table and builds internal
  77. information needed to route each Inti.
  78. Return Value:
  79. The following structures are filled in:
  80. HalpIntiInfo
  81. HalpSourceIrqIds
  82. HalpSourceIrqMapping
  83. HalpISAIqpToVector
  84. --*/
  85. {
  86. ULONG ApicNo, BusNo, InterruptInput, IdIndex;
  87. PPCMPINTI pInti;
  88. PPCMPIOAPIC pIoApic;
  89. PPCMPPROCESSOR pProc;
  90. PPCMPBUSTRANS pBusType;
  91. ULONG i, id;
  92. UCHAR Level, Polarity;
  93. //
  94. // Clear IntiInfo table
  95. //
  96. for (i=0; i < MAX_INTI; i++) {
  97. HalpIntiInfo[i].Type = 0xf;
  98. HalpIntiInfo[i].Level = 0;
  99. HalpIntiInfo[i].Polarity = 0;
  100. }
  101. //
  102. // Check for MPS bios work-around
  103. //
  104. HalpMpsPCIPhysicalWorkaround();
  105. //
  106. // Initialize HalpMaxApicInti table
  107. //
  108. for (pInti = HalpMpInfoTable.IntiEntryPtr;
  109. pInti->EntryType == ENTRY_INTI;
  110. pInti++) {
  111. //
  112. // Which IoApic number is this?
  113. //
  114. for (pIoApic = HalpMpInfoTable.IoApicEntryPtr, ApicNo = 0;
  115. pIoApic->EntryType == ENTRY_IOAPIC;
  116. pIoApic++, ApicNo++) {
  117. if ( (pInti->IoApicId == pIoApic->IoApicId) ||
  118. (pInti->IoApicId == 0xff) ) {
  119. break;
  120. }
  121. }
  122. if ( (pInti->IoApicId != pIoApic->IoApicId) &&
  123. (pInti->IoApicId != 0xff) ) {
  124. DBGMSG ("PCMP table corrupt - IoApic not found for Inti\n");
  125. continue;
  126. }
  127. if (!(pIoApic->IoApicFlag & IO_APIC_ENABLED)) {
  128. DBGMSG ("PCMP IoApic for Inti is disabled\n");
  129. continue;
  130. }
  131. //
  132. // Make sure we are below the max # of IOApic which
  133. // are supported
  134. //
  135. ASSERT (ApicNo < MAX_IOAPICS);
  136. //
  137. // Track Max Inti line per IOApic
  138. //
  139. if (pInti->IoApicInti >= HalpMaxApicInti[ApicNo]) {
  140. HalpMaxApicInti[ApicNo] = pInti->IoApicInti+1;
  141. }
  142. }
  143. //
  144. // Make sure there aren't more Inti lines then we can support
  145. //
  146. InterruptInput = 0;
  147. for (i=0; i < MAX_IOAPICS; i++) {
  148. InterruptInput += HalpMaxApicInti[i];
  149. }
  150. ASSERT (InterruptInput < MAX_INTI);
  151. //
  152. // Look at each Inti and record it's type in it's
  153. // corresponding array entry
  154. //
  155. IdIndex = 0;
  156. for (pInti = HalpMpInfoTable.IntiEntryPtr;
  157. pInti->EntryType == ENTRY_INTI;
  158. pInti++) {
  159. //
  160. // Which IoApic number is this?
  161. //
  162. for (pIoApic = HalpMpInfoTable.IoApicEntryPtr, ApicNo = 0;
  163. pIoApic->EntryType == ENTRY_IOAPIC;
  164. pIoApic++, ApicNo++) {
  165. if ( (pInti->IoApicId == pIoApic->IoApicId) ||
  166. (pInti->IoApicId == 0xff) ) {
  167. break;
  168. }
  169. }
  170. if (!(pIoApic->IoApicFlag & IO_APIC_ENABLED)) {
  171. continue;
  172. }
  173. //
  174. // Determine the NT bus this INTI is on
  175. //
  176. if (!HalpMPSBusId2NtBusId (pInti->SourceBusId, &pBusType, &BusNo)) {
  177. DBGMSG ("HAL: Initialize INTI - unkown MPS bus type\n");
  178. continue;
  179. }
  180. //
  181. // Calulcate InterruptInput value for this APIC Inti
  182. //
  183. InterruptInput = pInti->IoApicInti;
  184. for (i = 0; i < ApicNo; i++) {
  185. InterruptInput += HalpMaxApicInti[i];
  186. }
  187. //
  188. // Get IntiInfo for this vector.
  189. //
  190. Polarity = (UCHAR) pInti->Signal.Polarity;
  191. Level = HalpInitLevel[pInti->Signal.Level][pBusType->Level];
  192. //
  193. // Verify Level & Polarity mappings made sense
  194. //
  195. #if DBG
  196. if (!(pBusType->NtType == MicroChannel || !(Level & CFG_ERROR))) {
  197. DbgPrint("\n\n\n MPS BIOS problem! WHQL, fail this machine!\n");
  198. DbgPrint("Intin: BusType %s BusNo: %x\n",
  199. pBusType->PcMpType,
  200. pInti->SourceBusId);
  201. DbgPrint(" SrcBusIRQ: %x EL: %x PO: %x\n",
  202. pInti->SourceBusIrq,
  203. pInti->Signal.Level,
  204. pInti->Signal.Polarity);
  205. if (pBusType->NtType == PCIBus) {
  206. DbgPrint("This entry is for PCI device %x on bus %x, PIN %x\n",
  207. pInti->SourceBusIrq >> 2,
  208. pInti->SourceBusId,
  209. (pInti->SourceBusIrq & 0x3) + 1);
  210. }
  211. }
  212. #endif
  213. Level &= ~CFG_ERROR;
  214. //
  215. // See if this inti should go into the mask of inti that
  216. // we won't assign to ISA devices.
  217. //
  218. // The last part of the test here guarantees that we are not
  219. // picky about any devices that are in the HalpEisaIrqIgnore
  220. // mask. This keep the mouse (and possibly other weird devices
  221. // alive.)
  222. //
  223. if ((pBusType->NtType == Isa) &&
  224. ((Level & ~CFG_MUST_BE) == CFG_LEVEL) &&
  225. !((1 << pInti->SourceBusIrq) & HalpEisaIrqIgnore)) {
  226. HalpPciIrqMask |= (1 << pInti->SourceBusIrq);
  227. }
  228. if ((pBusType->NtType == Eisa) &&
  229. ((Level & ~CFG_MUST_BE) == CFG_LEVEL)) {
  230. HalpEisaIrqMask |= (1 << pInti->SourceBusIrq);
  231. if (HalpBusType != MACHINE_TYPE_EISA) {
  232. //
  233. // The BIOS thinks that this is an EISA
  234. // inti. But we don't think that this
  235. // is an EISA machine. So put this on the
  236. // list of PCI inti, too.
  237. //
  238. HalpPciIrqMask |= (1 << pInti->SourceBusIrq);
  239. }
  240. }
  241. #if DBG
  242. if (HalpIntiInfo[InterruptInput].Type != 0xf) {
  243. //
  244. // Multiple irqs are connected to the Inti line. Make
  245. // sure Type, Level, and Polarity are all the same.
  246. //
  247. ASSERT (HalpIntiInfo[InterruptInput].Type == pInti->IntType);
  248. ASSERT (HalpIntiInfo[InterruptInput].Level == Level);
  249. ASSERT (HalpIntiInfo[InterruptInput].Polarity == Polarity);
  250. }
  251. #endif
  252. //
  253. // Remember this Inti's configuration info
  254. //
  255. HalpIntiInfo[InterruptInput].Type = pInti->IntType;
  256. HalpIntiInfo[InterruptInput].Level = Level;
  257. HalpIntiInfo[InterruptInput].Polarity = Polarity;
  258. //
  259. // Get IRQs encoding for translations
  260. //
  261. ASSERT (pBusType->NtType < 16);
  262. ASSERT (BusNo < 256);
  263. if ( (pBusType->NtType == PCIBus) &&
  264. (pInti->SourceBusIrq == 0) ) {
  265. id = BusIrq2Id(pBusType->NtType, BusNo, 0x80);
  266. } else {
  267. id = BusIrq2Id(pBusType->NtType, BusNo, pInti->SourceBusIrq);
  268. }
  269. //
  270. // Addinti mapping to translation table, do it now
  271. //
  272. HalpSourceIrqIds[IdIndex] = id;
  273. HalpSourceIrqMapping[IdIndex] = (USHORT) InterruptInput;
  274. IdIndex++;
  275. //
  276. // Lots of source IRQs are supported; however, the PC+MP table
  277. // allows for an aribtrary number even beyond the APIC limit.
  278. //
  279. if (IdIndex >= MAX_SOURCE_IRQS) {
  280. DBGMSG ("MAX_SOURCE_IRQS exceeded\n");
  281. break;
  282. }
  283. }
  284. //
  285. // Fill in the boot processors PCMP Apic ID.
  286. //
  287. pProc = HalpMpInfoTable.ProcessorEntryPtr;
  288. for (i=0; i < HalpMpInfoTable.ProcessorCount; i++, pProc++) {
  289. if (pProc->CpuFlags & BSP_CPU) {
  290. ((PHALPRCB)KeGetCurrentPrcb()->HalReserved)->PCMPApicID = pProc->LocalApicId;
  291. }
  292. }
  293. //
  294. // If this is an EISA machine check the ELCR
  295. //
  296. if (HalpBusType == MACHINE_TYPE_EISA) {
  297. HalpCheckELCR ();
  298. }
  299. }
  300. BOOLEAN
  301. HalpMPSBusId2NtBusId (
  302. IN UCHAR MPSBusId,
  303. OUT PPCMPBUSTRANS *ppBusType,
  304. OUT PULONG BusNo
  305. )
  306. /*++
  307. Routine Description:
  308. Lookup MPS Table BusId into PCMPBUSTRANS (NtType) and instance #.
  309. Arguments:
  310. MPSBusId - Bus ID # in MPS table
  311. ppBusType - Returned pointer to PPCMPBUSTRANS for this bus type
  312. BusNo - Returned instance # of given bus
  313. Return Value:
  314. TRUE if MPSBusId was cross referenced into an NT id.
  315. --*/
  316. {
  317. PPCMPBUS pBus, piBus;
  318. PPCMPBUSTRANS pBusType;
  319. NTSTATUS status;
  320. UCHAR parentBusNo;
  321. BOOLEAN foundFirstRootBus = FALSE;
  322. PAGED_CODE();
  323. //
  324. // What Bus is this?
  325. //
  326. for (pBus = HalpMpInfoTable.BusEntryPtr;
  327. pBus->EntryType == ENTRY_BUS;
  328. pBus++) {
  329. if (MPSBusId == pBus->BusId) {
  330. break;
  331. }
  332. }
  333. if (MPSBusId != pBus->BusId) {
  334. DBGMSG ("PCMP table corrupt - Bus not found for Inti\n");
  335. return FALSE;
  336. }
  337. //
  338. // What InterfaceType is this Bus?
  339. //
  340. for (pBusType = HalpTypeTranslation;
  341. pBusType->NtType != MaximumInterfaceType;
  342. pBusType++) {
  343. if (pBus->BusType[0] == pBusType->PcMpType[0] &&
  344. pBus->BusType[1] == pBusType->PcMpType[1] &&
  345. pBus->BusType[2] == pBusType->PcMpType[2] &&
  346. pBus->BusType[3] == pBusType->PcMpType[3] &&
  347. pBus->BusType[4] == pBusType->PcMpType[4] &&
  348. pBus->BusType[5] == pBusType->PcMpType[5]) {
  349. break;
  350. }
  351. }
  352. //
  353. // Which instance of this BusType?
  354. //
  355. if (!pBusType->PhysicalInstance) {
  356. //
  357. // This algorithm originally just counted the number
  358. // of busses of this type. The newer algorithm works
  359. // around bugs in the MPS tables. The rules are listed.
  360. //
  361. // 1) The first PCI bus of a given type is always bus
  362. // number 0.
  363. //
  364. // 2) For busses that are secondary root PCI busses, the
  365. // bus number count is incremented to equal the MPS bus
  366. // number.
  367. //
  368. // 3) For busses that are generated by PCI to PCI bridges,
  369. // the bus number is incremented by one.
  370. //
  371. // N.B. Rule #3 implies that if one bus under a bridge
  372. // is described, all must be.
  373. //
  374. for (piBus = HalpMpInfoTable.BusEntryPtr, *BusNo = 0;
  375. piBus < pBus;
  376. piBus++) {
  377. if (pBus->BusType[0] == piBus->BusType[0] &&
  378. pBus->BusType[1] == piBus->BusType[1] &&
  379. pBus->BusType[2] == piBus->BusType[2] &&
  380. pBus->BusType[3] == piBus->BusType[3] &&
  381. pBus->BusType[4] == piBus->BusType[4] &&
  382. pBus->BusType[5] == piBus->BusType[5]) {
  383. status = HalpMpsGetParentBus(piBus->BusId,
  384. &parentBusNo);
  385. if (NT_SUCCESS(status)) {
  386. //
  387. // This is a child bus.
  388. //
  389. *BusNo += 1;
  390. } else {
  391. //
  392. // This is a root bus.
  393. //
  394. if (!foundFirstRootBus) {
  395. //
  396. // This is the first root bus.
  397. // To work around buggy MPS BIOSes, this
  398. // root is always numbered 0.
  399. //
  400. *BusNo = 0;
  401. foundFirstRootBus = TRUE;
  402. } else {
  403. //
  404. // This is a secondary root of this type. Believe
  405. // the MPS tables.
  406. //
  407. *BusNo = piBus->BusId;
  408. }
  409. }
  410. }
  411. }
  412. } else {
  413. *BusNo = pBus->BusId;
  414. }
  415. if (pBusType->NtType == MaximumInterfaceType) {
  416. return FALSE;
  417. }
  418. *ppBusType = pBusType;
  419. return TRUE;
  420. }
  421. VOID
  422. HalpMpsPCIPhysicalWorkaround (
  423. VOID
  424. )
  425. {
  426. PPCMPBUS pBus;
  427. PPCMPBUSTRANS pBusType;
  428. //
  429. // The MPS specification has a subtle comment that PCI bus IDs are
  430. // suppose to match their physical PCI bus number. Many BIOSes don't
  431. // do this, so unless there's a PCI bus #0 listed in the MPS table
  432. // assume that the BIOS is broken
  433. //
  434. //
  435. // Find the PCI interface type
  436. //
  437. for (pBusType = HalpTypeTranslation;
  438. pBusType->NtType != MaximumInterfaceType;
  439. pBusType++) {
  440. if (pBusType->PcMpType[0] == 'P' &&
  441. pBusType->PcMpType[1] == 'C' &&
  442. pBusType->PcMpType[2] == 'I' &&
  443. pBusType->PcMpType[3] == ' ' &&
  444. pBusType->PcMpType[4] == ' ' &&
  445. pBusType->PcMpType[5] == ' ' ) {
  446. break;
  447. }
  448. }
  449. //
  450. // Find the bus with ID == 0
  451. //
  452. pBus = HalpMpInfoTable.BusEntryPtr;
  453. while (pBus->EntryType == ENTRY_BUS) {
  454. if (pBus->BusId == 0) {
  455. //
  456. // If it's a PCI bus, assume physical bus IDs
  457. //
  458. if (pBus->BusType[0] != 'P' ||
  459. pBus->BusType[1] != 'C' ||
  460. pBus->BusType[2] != 'I' ||
  461. pBus->BusType[3] != ' ' ||
  462. pBus->BusType[4] != ' ' ||
  463. pBus->BusType[5] != ' ' ) {
  464. //
  465. // Change default behaviour of PCI type
  466. // from physical to virtual
  467. //
  468. pBusType->PhysicalInstance = FALSE;
  469. }
  470. break;
  471. }
  472. pBus += 1;
  473. }
  474. }
  475. BOOLEAN
  476. HalpGetApicInterruptDesc (
  477. IN INTERFACE_TYPE BusType,
  478. IN ULONG BusNumber,
  479. IN ULONG BusInterruptLevel,
  480. OUT PUSHORT PcMpInti
  481. )
  482. /*++
  483. Routine Description:
  484. This procedure gets a "Inti" describing the requested interrupt
  485. Arguments:
  486. BusType - The Bus type as known to the IO subsystem
  487. BusNumber - The number of the Bus we care for
  488. BusInterruptLevel - IRQ on the Bus
  489. Return Value:
  490. TRUE if PcMpInti found; otherwise FALSE.
  491. PcMpInti - A number that describes the interrupt to the HAL.
  492. --*/
  493. {
  494. ULONG i, id;
  495. if (BusType < 16 && BusNumber < 256 && BusInterruptLevel < 256) {
  496. //
  497. // get unique BusType,BusNumber,BusInterrupt ID
  498. //
  499. id = BusIrq2Id(BusType, BusNumber, BusInterruptLevel);
  500. //
  501. // Search for ID of Bus Irq mapping, and return the corresponding
  502. // InterruptLine.
  503. //
  504. for (i=0; i < MAX_SOURCE_IRQS; i++) {
  505. if (HalpSourceIrqIds[i] == id) {
  506. *PcMpInti = HalpSourceIrqMapping[i];
  507. return TRUE;
  508. }
  509. }
  510. }
  511. //
  512. // Not found or search out of range
  513. //
  514. return FALSE;
  515. }
  516. PBUS_HANDLER
  517. HalpFindIdeBus(
  518. IN ULONG Vector
  519. )
  520. {
  521. PBUS_HANDLER ideBus;
  522. NTSTATUS status;
  523. ULONG pciNo;
  524. PAGED_CODE();
  525. status = HalpSearchBusForVector(Isa, 0, Vector, &ideBus);
  526. if (NT_SUCCESS(status)) {
  527. return ideBus;
  528. }
  529. status = HalpSearchBusForVector(Eisa, 0, Vector, &ideBus);
  530. if (NT_SUCCESS(status)) {
  531. return ideBus;
  532. }
  533. status = HalpSearchBusForVector(MicroChannel, 0, Vector, &ideBus);
  534. if (NT_SUCCESS(status)) {
  535. return ideBus;
  536. }
  537. for (pciNo = 0; pciNo <= 255; pciNo++) {
  538. status = HalpSearchBusForVector(PCIBus, pciNo, Vector, &ideBus);
  539. if (NT_SUCCESS(status)) {
  540. return ideBus;
  541. }
  542. if (status == STATUS_NO_SUCH_DEVICE) {
  543. break;
  544. }
  545. }
  546. return NULL;
  547. }
  548. NTSTATUS
  549. HalpSearchBusForVector(
  550. IN INTERFACE_TYPE BusType,
  551. IN ULONG BusNo,
  552. IN ULONG Vector,
  553. IN OUT PBUS_HANDLER *BusHandler
  554. )
  555. {
  556. PBUS_HANDLER ideBus;
  557. NTSTATUS status;
  558. BOOLEAN found;
  559. USHORT inti;
  560. PAGED_CODE();
  561. ideBus = HaliHandlerForBus(BusType, BusNo);
  562. if (!ideBus) {
  563. return STATUS_NO_SUCH_DEVICE;
  564. }
  565. found = HalpGetApicInterruptDesc(BusType,
  566. BusNo,
  567. Vector,
  568. &inti);
  569. if (!found) {
  570. return STATUS_NOT_FOUND;
  571. }
  572. *BusHandler = ideBus;
  573. return STATUS_SUCCESS;
  574. }
  575. ULONG
  576. HalpGetIoApicId(
  577. ULONG ApicNo
  578. )
  579. {
  580. return (ULONG) HalpMpInfoTable.IoApicEntryPtr[ApicNo].IoApicId;
  581. }
  582. VOID
  583. HalpMarkProcessorStarted(
  584. ULONG ApicID,
  585. ULONG NtNumber
  586. )
  587. {
  588. return;
  589. }
  590. ULONG
  591. HalpInti2BusInterruptLevel(
  592. ULONG Inti
  593. )
  594. /*++
  595. Routine Description:
  596. This procedure does a lookup to find a bus-relative
  597. interrupt vector associated with an Inti.
  598. Note: If two different devices are sharing an interrupt,
  599. this function will return the answer for the first one
  600. that it finds. Fortunately, the only devices that use
  601. their bus-relative vectors for anything (ISA devices)
  602. can't share interrupts.
  603. Arguments:
  604. Inti - Interrupt Input on an I/O APIC
  605. Return Value:
  606. A bus-relative interrupt vector.
  607. --*/
  608. {
  609. ULONG i;
  610. for (i=0; i < MAX_SOURCE_IRQS; i++) {
  611. if (HalpSourceIrqMapping[i] == Inti) {
  612. return Id2BusIrq(HalpSourceIrqIds[i]);
  613. }
  614. }
  615. //
  616. // We should never fail to find a mapping.
  617. //
  618. #if DBG
  619. KeBugCheckEx(HAL_INITIALIZATION_FAILED, 5, Inti, 0, 0);
  620. #endif
  621. return 0;
  622. }
  623. NTSTATUS
  624. HalpGetNextProcessorApicId(
  625. IN ULONG PrcbProcessorNumber,
  626. IN OUT UCHAR *ApicId
  627. )
  628. /*++
  629. Routine Description:
  630. This function returns an APIC ID of a non-started processor,
  631. which will be started by HalpStartProcessor.
  632. Arguments:
  633. PrcbProcessorNumber - The logical processor number that will
  634. be associated with this APIC ID.
  635. ApicId - pointer to a value to fill in with the APIC ID.
  636. Return Value:
  637. status
  638. --*/
  639. {
  640. PPCMPPROCESSOR ApPtr;
  641. ULONG ProcessorNumber;
  642. if (PrcbProcessorNumber == 0) {
  643. //
  644. // I don't believe anyone ever askes for 0 and I plan not
  645. // to handle it. peterj 12/5/00.
  646. //
  647. KeBugCheckEx(HAL_INITIALIZATION_FAILED,
  648. 6,
  649. HalpLastEnumeratedActualProcessor,
  650. 0,
  651. 0);
  652. }
  653. if (HalpLastEnumeratedActualProcessor >= HalpMpInfoTable.ProcessorCount) {
  654. //
  655. // Sorry, no more processors.
  656. //
  657. return STATUS_NOT_FOUND;
  658. }
  659. ++HalpLastEnumeratedActualProcessor;
  660. ProcessorNumber = HalpLastEnumeratedActualProcessor;
  661. //
  662. // Get the MP Table entry for this processor
  663. //
  664. ApPtr = HalpMpInfoTable.ProcessorEntryPtr;
  665. #if 0
  666. if (ProcessorNumber == 0) {
  667. //
  668. // Return the ID of the boot processor (BSP).
  669. //
  670. while (ApPtr->EntryType == ENTRY_PROCESSOR) {
  671. if ((ApPtr->CpuFlags & CPU_ENABLED) &&
  672. (ApPtr->CpuFlags & BSP_CPU)) {
  673. *ApicId = (UCHAR)ApPtr->LocalApicId;
  674. return STATUS_SUCCESS;
  675. }
  676. ++ApPtr;
  677. }
  678. //
  679. // Boot processor not found.
  680. //
  681. return STATUS_NOT_FOUND;
  682. }
  683. #endif
  684. //
  685. // Skip 'ProcessorNumber' enabled processors. The next enabled
  686. // processor entry (after those) will be the "next" processor.
  687. //
  688. // Note: The BSP may not be amongst the first 'ProcessorNumber'
  689. // processors so we must skip 'ProcessorNumber' - 1, and check
  690. // for the and skip the BSP.
  691. //
  692. --ProcessorNumber;
  693. while ((ProcessorNumber) && (ApPtr->EntryType == ENTRY_PROCESSOR)) {
  694. if ((ApPtr->CpuFlags & CPU_ENABLED) &&
  695. !(ApPtr->CpuFlags & BSP_CPU)) {
  696. //
  697. // Account for this entry (we have already started it) if this
  698. // processor is enabled and not the BSP (we decremented for the
  699. // BSP before entering the loop).
  700. //
  701. --ProcessorNumber;
  702. }
  703. ++ApPtr;
  704. }
  705. //
  706. // Find the first remaining enabled processor.
  707. //
  708. while(ApPtr->EntryType == ENTRY_PROCESSOR) {
  709. if ((ApPtr->CpuFlags & CPU_ENABLED) &&
  710. !(ApPtr->CpuFlags & BSP_CPU)) {
  711. *ApicId = (UCHAR)ApPtr->LocalApicId;
  712. return STATUS_SUCCESS;
  713. }
  714. ++ApPtr;
  715. }
  716. //
  717. // We did not find another processor.
  718. //
  719. return STATUS_NOT_FOUND;
  720. }
  721. NTSTATUS
  722. HalpGetApicIdByProcessorNumber(
  723. IN UCHAR Processor,
  724. IN OUT USHORT *ApicId
  725. )
  726. /*++
  727. Routine Description:
  728. This function returns an APIC ID for a given processor.
  729. It is intended this routine be able to produce the same
  730. APIC ID order as HalpGetNextProcessorApicId.
  731. Note: This won't actually work in the presence of skipped
  732. procesors.
  733. Arguments:
  734. Processor - The logical processor number that is
  735. associated with this APIC ID.
  736. ApicId - pointer to a value to fill in with the APIC ID.
  737. Return Value:
  738. status
  739. --*/
  740. {
  741. PPCMPPROCESSOR ApPtr;
  742. //
  743. // Get the MP Table entry for this processor
  744. //
  745. ApPtr = HalpMpInfoTable.ProcessorEntryPtr;
  746. if (Processor == 0) {
  747. //
  748. // Return the ID of the boot processor (BSP).
  749. //
  750. while (ApPtr->EntryType == ENTRY_PROCESSOR) {
  751. if ((ApPtr->CpuFlags & CPU_ENABLED) &&
  752. (ApPtr->CpuFlags & BSP_CPU)) {
  753. *ApicId = (UCHAR)ApPtr->LocalApicId;
  754. return STATUS_SUCCESS;
  755. }
  756. ++ApPtr;
  757. }
  758. //
  759. // Boot processor not found.
  760. //
  761. return STATUS_NOT_FOUND;
  762. }
  763. for ( ; TRUE ; ApPtr++) {
  764. if (ApPtr->EntryType != ENTRY_PROCESSOR) {
  765. //
  766. // Out of processor entries, fail.
  767. //
  768. return STATUS_NOT_FOUND;
  769. }
  770. if (ApPtr->CpuFlags & BSP_CPU) {
  771. //
  772. // BSP is processor 0 and is not considered in the
  773. // search for processors other than 0.
  774. //
  775. continue;
  776. }
  777. if (ApPtr->CpuFlags & CPU_ENABLED) {
  778. //
  779. // Count this processor.
  780. //
  781. Processor--;
  782. if (Processor == 0) {
  783. break;
  784. }
  785. }
  786. }
  787. ASSERT(ApPtr->EntryType == ENTRY_PROCESSOR);
  788. *ApicId = ApPtr->LocalApicId;
  789. return STATUS_SUCCESS;
  790. }
  791. BOOLEAN
  792. HalpInterruptsDescribedByMpsTable(
  793. IN UCHAR MpsBusNumber
  794. )
  795. {
  796. PPCMPINTI busInterrupt;
  797. PAGED_CODE();
  798. for (busInterrupt = HalpMpInfoTable.IntiEntryPtr;
  799. busInterrupt->EntryType == ENTRY_INTI;
  800. busInterrupt++) {
  801. //
  802. // The MPS spec requires that, if one interrupt
  803. // on a bus is described, all interrupts on that
  804. // bus must be described. So finding one match
  805. // is enough.
  806. //
  807. if (busInterrupt->SourceBusId == MpsBusNumber) {
  808. return TRUE;
  809. }
  810. }
  811. return FALSE;
  812. }
  813. NTSTATUS
  814. HalpPci2MpsBusNumber(
  815. IN UCHAR PciBusNumber,
  816. OUT UCHAR *MpsBusNumber
  817. )
  818. {
  819. PPCMPBUSTRANS busType;
  820. ULONG mpsBusNumber = 0;
  821. ULONG busNumber;
  822. PAGED_CODE();
  823. for (mpsBusNumber = 0;
  824. mpsBusNumber < 0x100;
  825. mpsBusNumber++) {
  826. if (HalpMPSBusId2NtBusId((UCHAR)mpsBusNumber,
  827. &busType,
  828. &busNumber)) {
  829. if ((busType->NtType == PCIBus) &&
  830. (PciBusNumber == (UCHAR)busNumber)) {
  831. *MpsBusNumber = (UCHAR)mpsBusNumber;
  832. return STATUS_SUCCESS;
  833. }
  834. }
  835. }
  836. return STATUS_NOT_FOUND;
  837. }
  838. VOID
  839. HalpEnableLocalNmiSources(
  840. VOID
  841. )
  842. /*++
  843. Routine Description:
  844. This routine parses the information from the MP table and
  845. enables any NMI sources in the local APIC of the processor
  846. that it is running on.
  847. Callers of this function must be holding HalpAccountingLock.
  848. Arguments:
  849. Return Value:
  850. --*/
  851. {
  852. PKPCR pPCR;
  853. UCHAR ThisCpu;
  854. UCHAR LocalApicId;
  855. PPCMPLINTI pEntry;
  856. ULONG NumEntries;
  857. pPCR = KeGetPcr();
  858. ThisCpu = pPCR->Prcb->Number;
  859. //
  860. // Enable local processor NMI source
  861. //
  862. LocalApicId = ((PHALPRCB)pPCR->Prcb->HalReserved)->PCMPApicID;
  863. NumEntries = HalpMpInfoTable.LintiCount;
  864. for (pEntry = HalpMpInfoTable.LintiEntryPtr;
  865. ((pEntry) && (NumEntries > 0));
  866. pEntry++, --NumEntries) {
  867. if ( ( (pEntry->DestLocalApicId == LocalApicId) ||
  868. (pEntry->DestLocalApicId == 0xff)) &&
  869. (pEntry->IntType == INT_TYPE_NMI) ) {
  870. //
  871. // Found local NMI source, enable it
  872. //
  873. if (pEntry->DestLocalApicInti == 0) {
  874. pLocalApic[LU_INT_VECTOR_0/4] = ( LEVEL_TRIGGERED |
  875. ACTIVE_HIGH | DELIVER_NMI | NMI_VECTOR);
  876. } else {
  877. pLocalApic[LU_INT_VECTOR_1/4] = ( LEVEL_TRIGGERED |
  878. ACTIVE_HIGH | DELIVER_NMI | NMI_VECTOR);
  879. }
  880. }
  881. }
  882. }