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.

962 lines
24 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1992 Intel Corporation
  4. All rights reserved
  5. INTEL CORPORATION PROPRIETARY INFORMATION
  6. This software is supplied to Microsoft under the terms
  7. of a license agreement with Intel Corporation and may not be
  8. copied nor disclosed except in accordance with the terms
  9. of that agreement.
  10. Module Name:
  11. mpsproc.c
  12. Abstract:
  13. PC+MP Start Next Processor c code.
  14. This module implements the initialization of the system dependent
  15. functions that define the Hardware Architecture Layer (HAL) for a
  16. PC+MP System
  17. Author:
  18. Ken Reneris (kenr) 22-Jan-1991
  19. Environment:
  20. Kernel mode only.
  21. Revision History:
  22. Ron Mosgrove (Intel) - Modified to support the PC+MP
  23. Jake Oshins (jakeo) - Modified for ACPI MP machines 22-Dec-1997
  24. --*/
  25. #if !defined(_HALPAE_)
  26. #define _HALPAE_
  27. #endif
  28. #include "halp.h"
  29. #include "apic.inc"
  30. #include "pcmp_nt.inc"
  31. #include "stdio.h"
  32. #ifdef ACPI_HAL
  33. #include "acpitabl.h"
  34. #endif
  35. #ifdef DEBUGGING
  36. void
  37. HalpDisplayString(
  38. IN PVOID String
  39. );
  40. #endif // DEBUGGING
  41. #if defined(ACPI_HAL)
  42. const ULONG HalDisableFirmwareMapper = 1;
  43. #if !defined(NT_UP)
  44. const UCHAR HalName[] = "ACPI 1.0 - APIC platform MP";
  45. #define HalName L"ACPI 1.0 - APIC platform MP"
  46. WCHAR HalHardwareIdString[] = L"acpiapic_mp\0";
  47. #else
  48. const UCHAR HalName[] = "ACPI 1.0 - APIC platform UP";
  49. #define HalName L"ACPI 1.0 - APIC platform UP"
  50. WCHAR MpHalHardwareIdString[] = L"acpiapic_mp\0";
  51. WCHAR HalHardwareIdString[] = L"acpiapic_up\0";
  52. #endif
  53. #else
  54. const ULONG HalDisableFirmwareMapper = 0;
  55. #if !defined(NT_UP)
  56. const UCHAR HalName[] = "MPS 1.4 - APIC platform";
  57. #define HalName L"MPS 1.4 - APIC platform"
  58. WCHAR HalHardwareIdString[] = L"mps_mp\0";
  59. #else
  60. const UCHAR HalName[] = "UP MPS 1.4 - APIC platform";
  61. #define HalName L"UP MPS 1.4 - APIC platform"
  62. WCHAR MpHalHardwareIdString[] = L"mps_mp\0";
  63. WCHAR HalHardwareIdString[] = L"mps_up\0";
  64. #endif
  65. #endif
  66. #if !defined(NT_UP)
  67. ULONG
  68. HalpStartProcessor (
  69. IN PVOID InitCodePhysAddr,
  70. IN ULONG ProcessorNumber
  71. );
  72. #endif
  73. VOID
  74. HalpInitMP (
  75. IN ULONG Phase,
  76. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  77. );
  78. VOID
  79. HalpInitOtherBuses (
  80. VOID
  81. );
  82. VOID
  83. HalpInitializePciBus (
  84. VOID
  85. );
  86. VOID
  87. HalpInitializePciStubs (
  88. VOID
  89. );
  90. VOID
  91. HalpInheritBusAddressMapInfo (
  92. VOID
  93. );
  94. VOID
  95. HalpInitBusAddressMapInfo (
  96. VOID
  97. );
  98. VOID
  99. HalpResetThisProcessor (
  100. VOID
  101. );
  102. HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpApicRebootService);
  103. #ifdef ACPI_HAL
  104. VOID
  105. HalpInitMpInfo (
  106. IN PMAPIC ApicTable,
  107. IN ULONG Phase
  108. );
  109. extern PMAPIC HalpApicTable;
  110. #endif
  111. extern VOID (*HalpRebootNow)(VOID);
  112. extern volatile ULONG HalpNMIInProgress;
  113. volatile ULONG HalpProcessorsNotHalted = 0;
  114. #define LOW_MEMORY 0x000100000
  115. //
  116. // From hal386.inc
  117. //
  118. #define IDT_NMI_VECTOR 2
  119. #define D_INT032 0x8E00
  120. #if !defined(KGDT_R0_CODE)
  121. #define KGDT_R0_CODE 0x8
  122. #endif
  123. //
  124. // Defines to let us diddle the CMOS clock and the keyboard
  125. //
  126. #define CMOS_CTRL (PUCHAR )0x70
  127. #define CMOS_DATA (PUCHAR )0x71
  128. #define RESET 0xfe
  129. #define KEYBPORT (PUCHAR )0x64
  130. extern USHORT HalpGlobal8259Mask;
  131. extern PKPCR HalpProcessorPCR[];
  132. extern struct HalpMpInfo HalpMpInfoTable;
  133. extern ULONG HalpIpiClock;
  134. extern PVOID HalpLowStubPhysicalAddress; // pointer to low memory bootup stub
  135. extern PUCHAR HalpLowStub; // pointer to low memory bootup stub
  136. PUCHAR Halp1stPhysicalPageVaddr; // pointer to physical memory 0:0
  137. PUSHORT MppProcessorAvail; // pointer to processavail flag
  138. ULONG HalpDontStartProcessors = 0;
  139. #ifdef ALLOC_PRAGMA
  140. #pragma alloc_text(INIT,HalpInitMP)
  141. #pragma alloc_text(INIT,HalAllProcessorsStarted)
  142. #pragma alloc_text(INIT,HalReportResourceUsage)
  143. #pragma alloc_text(INIT,HalpInitOtherBuses)
  144. #if !defined(NT_UP)
  145. #pragma alloc_text(PAGELK,HalpStartProcessor)
  146. #endif
  147. #endif
  148. VOID
  149. HalpInitMP (
  150. IN ULONG Phase,
  151. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  152. )
  153. /*++
  154. Routine Description:
  155. Allows MP initialization from HalInitSystem.
  156. Arguments:
  157. Same as HalInitSystem
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. PKPCR pPCR;
  163. PHYSICAL_ADDRESS physicalAddress;
  164. pPCR = KeGetPcr();
  165. //
  166. // Increment a count of the number of processors
  167. // running NT, This could be different from the
  168. // number of enabled processors, if one or more
  169. // of the processor failed to start.
  170. //
  171. if (Phase == 1)
  172. HalpMpInfoTable.NtProcessors++;
  173. #ifdef DEBUGGING
  174. sprintf(Cbuf, "HalpInitMP: Number of Processors = 0x%x\n",
  175. HalpMpInfoTable.NtProcessors);
  176. HalpDisplayString(Cbuf);
  177. #endif
  178. if (Phase == 0) {
  179. #if defined(NT_UP)
  180. //
  181. // On UP build - done
  182. //
  183. return ;
  184. #endif
  185. //
  186. // Map the 1st Physical page of memory
  187. //
  188. physicalAddress.QuadPart = 0;
  189. Halp1stPhysicalPageVaddr = HalpMapPhysicalMemoryWriteThrough (physicalAddress, 1);
  190. //
  191. // Allocate some low memory for processor bootup stub
  192. //
  193. HalpLowStubPhysicalAddress =
  194. UlongToPtr(HalpAllocPhysicalMemory (LoaderBlock,
  195. LOW_MEMORY, 1, FALSE));
  196. if (!HalpLowStubPhysicalAddress) {
  197. //
  198. // Can't get memory
  199. //
  200. #if DBG
  201. DbgPrint("HAL: can't allocate memory to start processors\n");
  202. #endif
  203. return;
  204. }
  205. physicalAddress.QuadPart = (ULONGLONG)HalpLowStubPhysicalAddress;
  206. HalpLowStub = (PCHAR) HalpMapPhysicalMemory (physicalAddress, 1);
  207. } else {
  208. //
  209. // Phase 1 for another processor
  210. //
  211. if (CurrentPrcb(pPCR)->Number != 0) {
  212. HalpIpiClock = 0xff;
  213. }
  214. #ifdef ACPI_HAL
  215. HalpInitMpInfo(HalpApicTable, Phase);
  216. #endif
  217. }
  218. }
  219. BOOLEAN
  220. HalAllProcessorsStarted (
  221. VOID
  222. )
  223. {
  224. if (KeGetPcr()->Number == 0) {
  225. if (HalpFeatureBits & HAL_PERF_EVENTS) {
  226. //
  227. // Enable local perf events on each processor
  228. //
  229. HalpGenericCall (
  230. HalpEnablePerfInterupt,
  231. 0,
  232. HalpActiveProcessors
  233. );
  234. }
  235. #if !defined(_AMD64_)
  236. if (HalpFeatureBits & HAL_NO_SPECULATION) {
  237. //
  238. // Processor doesn't perform speculative execeution,
  239. // remove fences in critical code paths
  240. //
  241. HalpRemoveFences ();
  242. }
  243. #endif
  244. }
  245. return TRUE;
  246. }
  247. VOID
  248. HalpInitOtherBuses (
  249. VOID
  250. )
  251. {
  252. //
  253. // Registry is now intialized, see if there are any PCI buses
  254. //
  255. }
  256. VOID
  257. HalReportResourceUsage (
  258. VOID
  259. )
  260. /*++
  261. Routine Description:
  262. The registery is now enabled - time to report resources which are
  263. used by the HAL.
  264. Arguments:
  265. Return Value:
  266. --*/
  267. {
  268. UNICODE_STRING UHalName;
  269. INTERFACE_TYPE interfacetype;
  270. //
  271. // Initialize phase 2
  272. //
  273. HalInitSystemPhase2 ();
  274. //
  275. // Turn on MCA support if present
  276. //
  277. HalpMcaInit();
  278. //
  279. // Registry is now intialized, see if there are any PCI buses
  280. //
  281. HalpInitializePciBus ();
  282. HalpInitializePciStubs ();
  283. #ifndef ACPI_HAL // ACPI HALs don't deal with address maps
  284. //
  285. // Update supported address info with MPS bus address map
  286. //
  287. HalpInitBusAddressMapInfo ();
  288. //
  289. // Inherit any bus address mappings from MPS hierarchy descriptors
  290. //
  291. HalpInheritBusAddressMapInfo ();
  292. #endif
  293. //
  294. // Set type
  295. //
  296. switch (HalpBusType) {
  297. case MACHINE_TYPE_ISA: interfacetype = Isa; break;
  298. case MACHINE_TYPE_EISA: interfacetype = Eisa; break;
  299. case MACHINE_TYPE_MCA: interfacetype = MicroChannel; break;
  300. default: interfacetype = PCIBus; break;
  301. }
  302. //
  303. // Report HALs resource usage
  304. //
  305. RtlInitUnicodeString (&UHalName, HalName);
  306. HalpReportResourceUsage (
  307. &UHalName, // descriptive name
  308. interfacetype
  309. );
  310. #ifndef ACPI_HAL // ACPI HALs don't deal with address maps
  311. //
  312. // Register hibernate support
  313. //
  314. HalpRegisterHibernate();
  315. #endif
  316. HalpRegisterPciDebuggingDeviceInfo();
  317. }
  318. VOID
  319. HalpResetAllProcessors (
  320. VOID
  321. )
  322. /*++
  323. Routine Description:
  324. This procedure is called by the HalpReboot routine. It is called in
  325. response to a system reset request.
  326. This routine generates a reboot request via the APIC's ICR.
  327. This routine will NOT return.
  328. --*/
  329. {
  330. ULONG_PTR j;
  331. PKGDTENTRY GdtPtr;
  332. ULONG TssAddr;
  333. PKPRCB Prcb;
  334. #if defined(_AMD64_)
  335. PKIDTENTRY64 idtEntry;
  336. KIDT_HANDLER_ADDRESS handler;
  337. handler.Address = (ULONG64)HalpApicRebootService;
  338. #endif
  339. if (HalpNMIInProgress) {
  340. //
  341. // If we are in an NMI then none of the code below is going to work so just reset the old fashion way
  342. //
  343. HalpWriteResetCommand();
  344. }
  345. #ifndef NT_UP
  346. HalpProcessorsNotHalted = HalpMpInfoTable.NtProcessors;
  347. #else
  348. //
  349. // Only this processor needs to be halted
  350. //
  351. HalpProcessorsNotHalted = 1;
  352. #endif
  353. //
  354. // Set all processors NMI handlers
  355. //
  356. for (j = 0; j < HalpMpInfoTable.NtProcessors; ++j) {
  357. #if defined(_AMD64_)
  358. idtEntry = &HalpProcessorPCR[j]->IdtBase[IDT_NMI_VECTOR];
  359. idtEntry->OffsetLow = handler.OffsetLow;
  360. idtEntry->OffsetMiddle = handler.OffsetMiddle;
  361. idtEntry->OffsetHigh = handler.OffsetHigh;
  362. #else
  363. GdtPtr = &HalpProcessorPCR[j]->
  364. GDT[HalpProcessorPCR[j]->IDT[IDT_NMI_VECTOR].Selector >> 3];
  365. TssAddr = (((GdtPtr->HighWord.Bits.BaseHi << 8) +
  366. GdtPtr->HighWord.Bits.BaseMid) << 16) + GdtPtr->BaseLow;
  367. ((PKTSS)TssAddr)->Eip = (ULONG)HalpApicRebootService;
  368. #endif
  369. }
  370. if (HalpProcessorsNotHalted > 1) {
  371. //
  372. // Wait for the ICR to become free
  373. //
  374. if (HalpWaitForPending (0xFFFF, pLocalApic + LU_INT_CMD_LOW/4)) {
  375. //
  376. // For P54c or better processors, reboot by sending all processors
  377. // NMIs. For pentiums we send interrupts, since there are some
  378. // pentium MP machines where the NMIs method does not work.
  379. //
  380. // The NMI method is better.
  381. //
  382. Prcb = KeGetCurrentPrcb();
  383. j = Prcb->CpuType << 16 | (Prcb->CpuStep & 0xff00);
  384. if (j > 0x50100) {
  385. //
  386. // Get other processors attention with an NMI
  387. //
  388. // BUGBUG if we're in cluster mode?
  389. //
  390. j = HalpActiveProcessors & ~Prcb->SetMember;
  391. j = j << DESTINATION_SHIFT;
  392. pLocalApic[LU_INT_CMD_HIGH/4] = (ULONG)j;
  393. pLocalApic[LU_INT_CMD_LOW/4] = (ICR_USE_DEST_FIELD | LOGICAL_DESTINATION | DELIVER_NMI);
  394. //
  395. // Wait 5ms and see if any processors took the NMI. If not,
  396. // go do it the old way.
  397. //
  398. KeStallExecutionProcessor(5000);
  399. if (HalpProcessorsNotHalted != HalpMpInfoTable.NtProcessors) {
  400. //
  401. // Reboot local
  402. //
  403. #if defined(_AMD64_)
  404. HalpApicRebootService(NULL,NULL);
  405. #else
  406. HalpApicRebootService();
  407. #endif
  408. }
  409. }
  410. //
  411. // Signal other processors which also may be waiting to
  412. // reboot the machine, that it's time to go
  413. //
  414. HalpRebootNow = HalpResetThisProcessor;
  415. //
  416. // Send a reboot interrupt
  417. //
  418. pLocalApic[LU_INT_CMD_LOW/4] = (ICR_ALL_INCL_SELF | APIC_REBOOT_VECTOR);
  419. //
  420. // we're done - set TPR to zero so the reboot interrupt will happen
  421. //
  422. pLocalApic[LU_TPR/4] = 0;
  423. HalpEnableInterrupts();
  424. for (; ;) ;
  425. }
  426. }
  427. //
  428. // Reset the old fashion way
  429. //
  430. HalpWriteResetCommand();
  431. }
  432. VOID
  433. HalpResetThisProcessor (
  434. VOID
  435. )
  436. /*++
  437. Routine Description:
  438. This procedure is called by the HalpReboot routine.
  439. It is called in response to a system reset request.
  440. This routine is called by the reboot ISR (linked to
  441. APIC_REBOOT_VECTOR). The HalpResetAllProcessors
  442. generates the reboot request via the APIC's ICR.
  443. The function of this routine is to perform any processor
  444. specific shutdown code needed and then reset the system
  445. (on the BSP==P0 only).
  446. This routine will NOT return.
  447. --*/
  448. {
  449. PUSHORT Magic;
  450. ULONG ThisProcessor = 0;
  451. ULONG i, j, max, RedirEntry;
  452. struct ApicIoUnit *IoUnitPtr;
  453. PHYSICAL_ADDRESS physicalAddress;
  454. ThisProcessor = CurrentPrcb(KeGetPcr())->Number;
  455. //
  456. // Do whatever is needed to this processor to restore
  457. // system to a bootable state
  458. //
  459. pLocalApic[LU_TPR/4] = 0xff;
  460. pLocalApic[LU_TIMER_VECTOR/4] =
  461. (APIC_SPURIOUS_VECTOR |PERIODIC_TIMER | INTERRUPT_MASKED);
  462. pLocalApic[LU_INT_VECTOR_0/4] =
  463. (APIC_SPURIOUS_VECTOR | INTERRUPT_MASKED);
  464. pLocalApic[LU_INT_VECTOR_1/4] =
  465. ( LEVEL_TRIGGERED | ACTIVE_HIGH | DELIVER_NMI |
  466. INTERRUPT_MASKED | NMI_VECTOR);
  467. if (HalpMpInfoTable.ApicVersion != APIC_82489DX) {
  468. pLocalApic[LU_FAULT_VECTOR/4] =
  469. APIC_FAULT_VECTOR | INTERRUPT_MASKED;
  470. }
  471. if (ThisProcessor == 0) {
  472. InterlockedDecrement(&HalpProcessorsNotHalted);
  473. //
  474. // we are running on the BSP, wait for everyone to
  475. // complete the re-initialization code above
  476. //
  477. while (InterlockedAnd(&HalpProcessorsNotHalted,0xffffffff) != 0) {
  478. ;
  479. }
  480. KeStallExecutionProcessor(100);
  481. //
  482. // Write the Shutdown reason code, so the BIOS knows
  483. // this is a reboot
  484. //
  485. WRITE_PORT_UCHAR(CMOS_CTRL, 0x0f); // CMOS Addr 0f
  486. WRITE_PORT_UCHAR(CMOS_DATA, 0x00); // Reason Code Reset
  487. physicalAddress.QuadPart = 0;
  488. Magic = HalpMapPhysicalMemoryWriteThrough(physicalAddress, 1);
  489. Magic[0x472 / sizeof(USHORT)] = 0x1234; // warm boot
  490. //
  491. // If required, disable APIC mode
  492. //
  493. if (HalpMpInfoTable.IMCRPresent)
  494. {
  495. WRITE_PORT_UCHAR(UlongToPtr(ImcrRegPortAddr),ImcrPort);
  496. KeStallExecutionProcessor(100);
  497. WRITE_PORT_UCHAR(UlongToPtr(ImcrDataPortAddr),ImcrDisableApic);
  498. }
  499. KeStallExecutionProcessor(100);
  500. for (j=0; j<HalpMpInfoTable.IOApicCount; j++) {
  501. IoUnitPtr = (struct ApicIoUnit *) HalpMpInfoTable.IoApicBase[j];
  502. //
  503. // Disable all interrupts on IO Unit
  504. //
  505. IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
  506. max = ((IoUnitPtr->RegisterWindow >> 16) & 0xff) * 2;
  507. for (i=0; i <= max; i += 2) {
  508. IoUnitPtr->RegisterSelect = IO_REDIR_00_LOW + i;
  509. IoUnitPtr->RegisterWindow |= INT_VECTOR_MASK | INTERRUPT_MASKED;
  510. //
  511. // Clear any set Remote IRR bits by programming the entry to
  512. // edge and then back to level. Otherwise there will be
  513. // no further interrupts from this source.
  514. //
  515. IoUnitPtr->RegisterSelect = IO_REDIR_00_LOW + i;
  516. RedirEntry = IoUnitPtr->RegisterWindow;
  517. if ( (RedirEntry & LEVEL_TRIGGERED) && (RedirEntry & REMOTE_IRR)) {
  518. RedirEntry &= ~LEVEL_TRIGGERED;
  519. IoUnitPtr->RegisterWindow = RedirEntry;
  520. RedirEntry = IoUnitPtr->RegisterWindow;
  521. RedirEntry |= LEVEL_TRIGGERED;
  522. IoUnitPtr->RegisterWindow = RedirEntry;
  523. }
  524. }
  525. } // for all Io Apics
  526. //
  527. // Disable the Local Apic
  528. //
  529. pLocalApic[LU_SPURIOUS_VECTOR/4] =
  530. (APIC_SPURIOUS_VECTOR | LU_UNIT_DISABLED);
  531. KeStallExecutionProcessor(100);
  532. HalpDisableInterrupts();
  533. //
  534. // Enable Pic interrupts
  535. //
  536. HalpGlobal8259Mask = 0;
  537. HalpSet8259Mask ((USHORT) HalpGlobal8259Mask);
  538. KeStallExecutionProcessor(1000);
  539. //
  540. // Finally, reset the system.
  541. //
  542. HalpWriteResetCommand();
  543. } else {
  544. //
  545. // We're running on a processor other than the BSP
  546. //
  547. //
  548. // Disable the Local Apic
  549. //
  550. pLocalApic[LU_SPURIOUS_VECTOR/4] =
  551. (APIC_SPURIOUS_VECTOR | LU_UNIT_DISABLED);
  552. KeStallExecutionProcessor(100);
  553. //
  554. // Now we are done, tell the BSP
  555. //
  556. InterlockedDecrement(&HalpProcessorsNotHalted);
  557. } // Not BSP
  558. //
  559. // Everyone stops here until reset
  560. //
  561. HalpDisableInterrupts();
  562. while (TRUE) {
  563. HalpHalt();
  564. }
  565. }
  566. #if !defined(NT_UP)
  567. ULONG
  568. HalpStartProcessor (
  569. IN PVOID InitCodePhysAddr,
  570. IN ULONG ProcessorNumber
  571. )
  572. /*++
  573. Routine Description:
  574. Actually Start the Processor in question. This routine
  575. assumes the init code is setup and ready to run. The real
  576. mode init code must begin on a page boundry.
  577. NOTE: This assumes the BSP is entry 0 in the MP table.
  578. This routine cannot fail.
  579. Arguments:
  580. InitCodePhysAddr - execution address of init code
  581. Return Value:
  582. 0 - Something prevented us from issuing the reset.
  583. n - Processor's PCMP Local APICID + 1
  584. --*/
  585. {
  586. NTSTATUS status;
  587. UCHAR ApicID;
  588. PVULONG LuDestAddress = (PVULONG) (LOCALAPIC + LU_INT_CMD_HIGH);
  589. PVULONG LuICR = (PVULONG) (LOCALAPIC + LU_INT_CMD_LOW);
  590. #define DEFAULT_DELAY 100
  591. ULONG DelayCount = DEFAULT_DELAY;
  592. ULONG ICRCommand,i;
  593. ASSERT((((ULONG_PTR) InitCodePhysAddr) & 0xfff00fff) == 0);
  594. if (ProcessorNumber >= HalpMpInfoTable.ProcessorCount) {
  595. return(0);
  596. }
  597. //
  598. // Get the APIC ID of the processor to start.
  599. //
  600. status = HalpGetNextProcessorApicId(ProcessorNumber,
  601. &ApicID);
  602. if (!NT_SUCCESS(status)) {
  603. #ifdef DEBUGGING
  604. HalpDisplayString("HAL: HalpStartProcessor: No Processor Available\n");
  605. #endif
  606. return(0);
  607. }
  608. if (HalpDontStartProcessors)
  609. return ApicID+1;
  610. //
  611. // Make sure we can get to the Apic Bus
  612. //
  613. KeStallExecutionProcessor(200);
  614. if (HalpWaitForPending (DEFAULT_DELAY, LuICR) == 0) {
  615. //
  616. // We couldn't find a processor to start
  617. //
  618. #ifdef DEBUGGING
  619. HalpDisplayString("HAL: HalpStartProcessor: can't access APIC Bus\n");
  620. #endif
  621. return 0;
  622. }
  623. // For a P54 C/CM system, it is possible that the BSP is the P54CM and the
  624. // P54C is the Application processor. The P54C needs an INIT (reset)
  625. // to restart, so we issue a reset regardless of whether we a 82489DX
  626. // or an integrated APIC.
  627. //
  628. // This system is based on the original 82489DX's.
  629. // These devices do not support the Startup IPI's.
  630. // The mechanism used is the ASSERT/DEASSERT INIT
  631. // feature of the local APIC. This resets the
  632. // processor.
  633. //
  634. #ifdef DEBUGGING
  635. sprintf(Cbuf, "HAL: HalpStartProcessor: Reset IPI to ApicId %d (0x%x)\n",
  636. ApicID,((ULONG) ApicID) << DESTINATION_SHIFT );
  637. HalpDisplayString(Cbuf);
  638. #endif
  639. //
  640. // We use a Physical Destination
  641. //
  642. *LuDestAddress = ((ULONG) ApicID) << DESTINATION_SHIFT;
  643. //
  644. // Now Assert reset and drop it
  645. //
  646. *LuICR = LU_RESET_ASSERT;
  647. KeStallExecutionProcessor(10);
  648. *LuICR = LU_RESET_DEASSERT;
  649. KeStallExecutionProcessor(200);
  650. if (HalpMpInfoTable.ApicVersion == APIC_82489DX) {
  651. return ApicID+1;
  652. }
  653. //
  654. // Set the Startup Address as a vector and combine with the
  655. // ICR bits
  656. //
  657. ICRCommand = (ULONG)((((ULONG_PTR) InitCodePhysAddr & 0x000ff000) >> 12)
  658. | LU_STARTUP_IPI);
  659. #ifdef DEBUGGING
  660. sprintf(Cbuf, "HAL: HalpStartProcessor: Startup IPI (0x%x) to ApicId %d (0x%x)\n",
  661. ICRCommand, ApicID, ((ULONG) ApicID) << DESTINATION_SHIFT );
  662. HalpDisplayString(Cbuf);
  663. #endif
  664. //
  665. // Set the Address of the APIC again, this may not be needed
  666. // but it can't hurt.
  667. //
  668. *LuDestAddress = (ApicID << DESTINATION_SHIFT);
  669. //
  670. // Issue the request
  671. //
  672. *LuICR = ICRCommand;
  673. KeStallExecutionProcessor(200);
  674. //
  675. // Repeat the Startup IPI. This is because the second processor may
  676. // have been issued an INIT request. This is generated by some BIOSs.
  677. //
  678. // On older processors (286) BIOS's use a mechanism called triple
  679. // fault reset to transition from protected mode to real mode.
  680. // This mechanism causes the processor to generate a shutdown cycle.
  681. // The shutdown is typically issued by the BIOS building an invalid
  682. // IDT and then generating an interrupt. Newer processors have an
  683. // INIT line that the chipset jerks when it sees a shutdown cycle
  684. // issued by the processor. The Phoenix BIOS, for example, has
  685. // integrated support for triple fault reset as part of their POST
  686. // (Power On Self Test) code.
  687. //
  688. // When the P54CM powers on it is held in a tight microcode loop
  689. // waiting for a Startup IPI to be issued and queuing other requests.
  690. // When the POST code executes the triple fault reset test the INIT
  691. // cycle is queued by the processor. Later, when a Startup IPI is
  692. // issued to the CM, the CM starts and immediately gets a INIT cycle.
  693. // The effect from a software standpoint is that the processor is
  694. // never started.
  695. //
  696. // The work around implemented here is to issue two Startup IPI's.
  697. // The first allows the INIT to be processed and the second performs
  698. // the actual startup.
  699. //
  700. //
  701. // Make sure we can get to the Apic Bus
  702. //
  703. if (HalpWaitForPending (DEFAULT_DELAY, LuICR) == 0) {
  704. //
  705. // We're toast, can't gain access to the APIC Bus
  706. //
  707. #ifdef DEBUGGING
  708. HalpDisplayString("HAL: HalpStartProcessor: can't access APIC Bus\n");
  709. #endif
  710. return 0;
  711. }
  712. //
  713. // Allow Time for any Init request to be processed
  714. //
  715. KeStallExecutionProcessor(100);
  716. //
  717. // Set the Address of the APIC again, this may not be needed
  718. // but it can't hurt.
  719. //
  720. *LuDestAddress = (ApicID << DESTINATION_SHIFT);
  721. //
  722. // Issue the request
  723. //
  724. *LuICR = ICRCommand;
  725. KeStallExecutionProcessor(200);
  726. return ApicID+1;
  727. }
  728. #endif // !NT_UP
  729. ULONG
  730. FASTCALL
  731. HalSystemVectorDispatchEntry (
  732. IN ULONG Vector,
  733. OUT PKINTERRUPT_ROUTINE **FlatDispatch,
  734. OUT PKINTERRUPT_ROUTINE *NoConnection
  735. )
  736. {
  737. return FALSE;
  738. }