Source code of Windows XP (NT5)
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.

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