mirror of https://github.com/tongzx/nt5src
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
946 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
Copyright (c) 1992 Intel Corporation
|
|
All rights reserved
|
|
|
|
INTEL CORPORATION PROPRIETARY INFORMATION
|
|
|
|
This software is supplied to Microsoft under the terms
|
|
of a license agreement with Intel Corporation and may not be
|
|
copied nor disclosed except in accordance with the terms
|
|
of that agreement.
|
|
|
|
Module Name:
|
|
|
|
mpsproc.c
|
|
|
|
Abstract:
|
|
|
|
PC+MP Start Next Processor c code.
|
|
|
|
This module implements the initialization of the system dependent
|
|
functions that define the Hardware Architecture Layer (HAL) for a
|
|
PC+MP System
|
|
|
|
Author:
|
|
|
|
Ken Reneris (kenr) 22-Jan-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
Ron Mosgrove (Intel) - Modified to support the PC+MP
|
|
Jake Oshins (jakeo) - Modified for ACPI MP machines 22-Dec-1997
|
|
|
|
--*/
|
|
|
|
#if !defined(_HALPAE_)
|
|
#define _HALPAE_
|
|
#endif
|
|
|
|
#include "halp.h"
|
|
#include "apic.inc"
|
|
#include "pcmp_nt.inc"
|
|
#include "stdio.h"
|
|
#ifdef ACPI_HAL
|
|
#include "acpitabl.h"
|
|
#endif
|
|
|
|
#ifdef DEBUGGING
|
|
|
|
void
|
|
HalpDisplayString(
|
|
IN PVOID String
|
|
);
|
|
|
|
#endif // DEBUGGING
|
|
|
|
#if defined(ACPI_HAL)
|
|
#if !defined(NT_UP)
|
|
const UCHAR HalName[] = "ACPI 1.0 - APIC platform MP";
|
|
#define HalName L"ACPI 1.0 - APIC platform MP"
|
|
WCHAR HalHardwareIdString[] = L"acpiapic_mp\0";
|
|
#else
|
|
const UCHAR HalName[] = "ACPI 1.0 - APIC platform UP";
|
|
#define HalName L"ACPI 1.0 - APIC platform UP"
|
|
WCHAR MpHalHardwareIdString[] = L"acpiapic_mp\0";
|
|
WCHAR HalHardwareIdString[] = L"acpiapic_up\0";
|
|
#endif
|
|
#else
|
|
#if !defined(NT_UP)
|
|
const UCHAR HalName[] = "MPS 1.4 - APIC platform";
|
|
#define HalName L"MPS 1.4 - APIC platform"
|
|
WCHAR HalHardwareIdString[] = L"mps_mp\0";
|
|
#else
|
|
const UCHAR HalName[] = "UP MPS 1.4 - APIC platform";
|
|
#define HalName L"UP MPS 1.4 - APIC platform"
|
|
WCHAR MpHalHardwareIdString[] = L"mps_mp\0";
|
|
WCHAR HalHardwareIdString[] = L"mps_up\0";
|
|
#endif
|
|
#endif
|
|
|
|
#if !defined(NT_UP)
|
|
ULONG
|
|
HalpStartProcessor (
|
|
IN PVOID InitCodePhysAddr,
|
|
IN ULONG ProcessorNumber
|
|
);
|
|
#endif
|
|
|
|
VOID
|
|
HalpBiosDisplayReset (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpInitMP (
|
|
IN ULONG Phase,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
VOID
|
|
HalpInitOtherBuses (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpInitializePciBus (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpInitializePciStubs (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpInheritBusAddressMapInfo (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpInitBusAddressMapInfo (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpResetThisProcessor (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpApicRebootService(
|
|
VOID
|
|
);
|
|
|
|
#ifdef ACPI_HAL
|
|
VOID
|
|
HalpInitMpInfo (
|
|
IN PMAPIC ApicTable,
|
|
IN ULONG Phase
|
|
);
|
|
extern PMAPIC HalpApicTable;
|
|
#endif
|
|
|
|
extern VOID (*HalpRebootNow)(VOID);
|
|
|
|
|
|
volatile ULONG HalpProcessorsNotHalted = 0;
|
|
|
|
#define LOW_MEMORY 0x000100000
|
|
|
|
//
|
|
// From hal386.inc
|
|
//
|
|
|
|
#define IDT_NMI_VECTOR 2
|
|
#define D_INT032 0x8E00
|
|
#define KGDT_R0_CODE 0x8
|
|
|
|
//
|
|
// Defines to let us diddle the CMOS clock and the keyboard
|
|
//
|
|
|
|
#define CMOS_CTRL (PUCHAR )0x70
|
|
#define CMOS_DATA (PUCHAR )0x71
|
|
|
|
|
|
#define RESET 0xfe
|
|
#define KEYBPORT (PUCHAR )0x64
|
|
|
|
extern USHORT HalpGlobal8259Mask;
|
|
extern PKPCR HalpProcessorPCR[];
|
|
extern struct HalpMpInfo HalpMpInfoTable;
|
|
|
|
extern ULONG HalpIpiClock;
|
|
extern PVOID HalpLowStubPhysicalAddress; // pointer to low memory bootup stub
|
|
extern PUCHAR HalpLowStub; // pointer to low memory bootup stub
|
|
|
|
PUCHAR Halp1stPhysicalPageVaddr; // pointer to physical memory 0:0
|
|
PUSHORT MppProcessorAvail; // pointer to processavail flag
|
|
ULONG HalpDontStartProcessors = 0;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,HalpInitMP)
|
|
#pragma alloc_text(INIT,HalAllProcessorsStarted)
|
|
#pragma alloc_text(INIT,HalReportResourceUsage)
|
|
#pragma alloc_text(INIT,HalpInitOtherBuses)
|
|
#if !defined(NT_UP)
|
|
#pragma alloc_text(PAGELK,HalpStartProcessor)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
VOID
|
|
HalpInitMP (
|
|
IN ULONG Phase,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Allows MP initialization from HalInitSystem.
|
|
|
|
Arguments:
|
|
Same as HalInitSystem
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PKPCR pPCR;
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
|
|
|
|
pPCR = KeGetPcr();
|
|
|
|
//
|
|
// Increment a count of the number of processors
|
|
// running NT, This could be different from the
|
|
// number of enabled processors, if one or more
|
|
// of the processor failed to start.
|
|
//
|
|
if (Phase == 1)
|
|
HalpMpInfoTable.NtProcessors++;
|
|
#ifdef DEBUGGING
|
|
sprintf(Cbuf, "HalpInitMP: Number of Processors = 0x%x\n",
|
|
HalpMpInfoTable.NtProcessors);
|
|
|
|
HalpDisplayString(Cbuf);
|
|
#endif
|
|
|
|
if (Phase == 0) {
|
|
|
|
#if defined(NT_UP)
|
|
|
|
//
|
|
// On UP build - done
|
|
//
|
|
|
|
return ;
|
|
#endif
|
|
|
|
//
|
|
// Map the 1st Physical page of memory
|
|
//
|
|
physicalAddress.QuadPart = 0;
|
|
Halp1stPhysicalPageVaddr = HalpMapPhysicalMemory (physicalAddress, 1);
|
|
|
|
//
|
|
// Allocate some low memory for processor bootup stub
|
|
//
|
|
|
|
HalpLowStubPhysicalAddress = (PVOID)HalpAllocPhysicalMemory (LoaderBlock,
|
|
LOW_MEMORY, 1, FALSE);
|
|
|
|
if (!HalpLowStubPhysicalAddress) {
|
|
//
|
|
// Can't get memory
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint("HAL: can't allocate memory to start processors\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
physicalAddress.QuadPart = (ULONGLONG)HalpLowStubPhysicalAddress;
|
|
HalpLowStub = (PCHAR) HalpMapPhysicalMemory (physicalAddress, 1);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Phase 1 for another processor
|
|
//
|
|
if (pPCR->Prcb->Number != 0) {
|
|
HalpIpiClock = 0xff;
|
|
}
|
|
|
|
#ifdef ACPI_HAL
|
|
HalpInitMpInfo(HalpApicTable, Phase);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
HalAllProcessorsStarted (
|
|
VOID
|
|
)
|
|
{
|
|
if (KeGetPcr()->Number == 0) {
|
|
|
|
if (HalpFeatureBits & HAL_PERF_EVENTS) {
|
|
|
|
//
|
|
// Enable local perf events on each processor
|
|
//
|
|
|
|
HalpGenericCall (
|
|
HalpEnablePerfInterupt,
|
|
(ULONG) NULL,
|
|
HalpActiveProcessors
|
|
);
|
|
|
|
}
|
|
|
|
if (HalpFeatureBits & HAL_NO_SPECULATION) {
|
|
|
|
//
|
|
// Processor doesn't perform speculative execeution,
|
|
// remove fences in critical code paths
|
|
//
|
|
|
|
HalpRemoveFences ();
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
HalpInitOtherBuses (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
//
|
|
// Registry is now intialized, see if there are any PCI buses
|
|
//
|
|
}
|
|
|
|
VOID
|
|
HalReportResourceUsage (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
The registery is now enabled - time to report resources which are
|
|
used by the HAL.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING UHalName;
|
|
INTERFACE_TYPE interfacetype;
|
|
|
|
//
|
|
// Initialize phase 2
|
|
//
|
|
|
|
HalInitSystemPhase2 ();
|
|
|
|
//
|
|
// Turn on MCA support if present
|
|
//
|
|
|
|
HalpMcaInit();
|
|
|
|
//
|
|
// Registry is now intialized, see if there are any PCI buses
|
|
//
|
|
|
|
HalpInitializePciBus ();
|
|
HalpInitializePciStubs ();
|
|
|
|
#ifndef ACPI_HAL // ACPI HALs don't deal with address maps
|
|
//
|
|
// Update supported address info with MPS bus address map
|
|
//
|
|
|
|
HalpInitBusAddressMapInfo ();
|
|
|
|
//
|
|
// Inherit any bus address mappings from MPS hierarchy descriptors
|
|
//
|
|
|
|
HalpInheritBusAddressMapInfo ();
|
|
|
|
#endif
|
|
//
|
|
// Set type
|
|
//
|
|
|
|
switch (HalpBusType) {
|
|
case MACHINE_TYPE_ISA: interfacetype = Isa; break;
|
|
case MACHINE_TYPE_EISA: interfacetype = Eisa; break;
|
|
case MACHINE_TYPE_MCA: interfacetype = MicroChannel; break;
|
|
default: interfacetype = PCIBus; break;
|
|
}
|
|
|
|
//
|
|
// Report HALs resource usage
|
|
//
|
|
|
|
RtlInitUnicodeString (&UHalName, HalName);
|
|
|
|
HalpReportResourceUsage (
|
|
&UHalName, // descriptive name
|
|
interfacetype
|
|
);
|
|
|
|
#ifndef ACPI_HAL // ACPI HALs don't deal with address maps
|
|
//
|
|
// Register hibernate support
|
|
//
|
|
HalpRegisterHibernate();
|
|
#endif
|
|
|
|
HalpRegisterPciDebuggingDeviceInfo();
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpResetAllProcessors (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure is called by the HalpReboot routine. It is called in
|
|
response to a system reset request.
|
|
|
|
This routine generates a reboot request via the APIC's ICR.
|
|
|
|
This routine will NOT return.
|
|
|
|
--*/
|
|
{
|
|
ULONG j;
|
|
PKGDTENTRY GdtPtr;
|
|
ULONG TssAddr;
|
|
PKPRCB Prcb;
|
|
|
|
#ifndef NT_UP
|
|
HalpProcessorsNotHalted = HalpMpInfoTable.NtProcessors;
|
|
#else
|
|
//
|
|
// Only this processor needs to be halted
|
|
//
|
|
HalpProcessorsNotHalted = 1;
|
|
#endif
|
|
|
|
//
|
|
// Set all processors NMI handlers
|
|
//
|
|
|
|
for (j = 0; j < HalpMpInfoTable.NtProcessors; ++j) {
|
|
GdtPtr = &HalpProcessorPCR[j]->
|
|
GDT[HalpProcessorPCR[j]->IDT[IDT_NMI_VECTOR].Selector >> 3];
|
|
TssAddr = (((GdtPtr->HighWord.Bits.BaseHi << 8) +
|
|
GdtPtr->HighWord.Bits.BaseMid) << 16) + GdtPtr->BaseLow;
|
|
((PKTSS)TssAddr)->Eip = (ULONG)HalpApicRebootService;
|
|
}
|
|
|
|
if (HalpProcessorsNotHalted > 1) {
|
|
|
|
//
|
|
// Wait for the ICR to become free
|
|
//
|
|
|
|
if (HalpWaitForPending (0xFFFF, pLocalApic + LU_INT_CMD_LOW/4)) {
|
|
|
|
//
|
|
// For P54c or better processors, reboot by sending all processors
|
|
// NMIs. For pentiums we send interrupts, since there are some
|
|
// pentium MP machines where the NMIs method does not work.
|
|
//
|
|
// The NMI method is better.
|
|
//
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
j = Prcb->CpuType << 16 | (Prcb->CpuStep & 0xff00);
|
|
if (j > 0x50100) {
|
|
|
|
//
|
|
// Get other processors attention with an NMI
|
|
//
|
|
|
|
j = HalpActiveProcessors & ~Prcb->SetMember;
|
|
j = j << DESTINATION_SHIFT;
|
|
pLocalApic[LU_INT_CMD_HIGH/4] = j;
|
|
pLocalApic[LU_INT_CMD_LOW/4] = (ICR_USE_DEST_FIELD | LOGICAL_DESTINATION | DELIVER_NMI);
|
|
|
|
//
|
|
// Wait 5ms and see if any processors took the NMI. If not,
|
|
// go do it the old way.
|
|
//
|
|
|
|
KeStallExecutionProcessor(5000);
|
|
if (HalpProcessorsNotHalted != HalpMpInfoTable.NtProcessors) {
|
|
|
|
//
|
|
// Reboot local
|
|
//
|
|
|
|
HalpApicRebootService();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Signal other processors which also may be waiting to
|
|
// reboot the machine, that it's time to go
|
|
//
|
|
|
|
HalpRebootNow = HalpResetThisProcessor;
|
|
|
|
//
|
|
// Send a reboot interrupt
|
|
//
|
|
|
|
pLocalApic[LU_INT_CMD_LOW/4] = (ICR_ALL_INCL_SELF | APIC_REBOOT_VECTOR);
|
|
|
|
//
|
|
// we're done - set TPR to zero so the reboot interrupt will happen
|
|
//
|
|
|
|
pLocalApic[LU_TPR/4] = 0;
|
|
_asm sti ;
|
|
for (; ;) ;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Reset the old fashion way
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(KEYBPORT, RESET);
|
|
}
|
|
|
|
VOID
|
|
HalpResetThisProcessor (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure is called by the HalpReboot routine.
|
|
It is called in response to a system reset request.
|
|
|
|
This routine is called by the reboot ISR (linked to
|
|
APIC_REBOOT_VECTOR). The HalpResetAllProcessors
|
|
generates the reboot request via the APIC's ICR.
|
|
|
|
The function of this routine is to perform any processor
|
|
specific shutdown code needed and then reset the system
|
|
(on the BSP==P0 only).
|
|
|
|
This routine will NOT return.
|
|
|
|
--*/
|
|
{
|
|
PUSHORT Magic;
|
|
ULONG ThisProcessor = 0;
|
|
ULONG i, j, max, RedirEntry;
|
|
ULONG AllProcessorsHalted;
|
|
struct ApicIoUnit *IoUnitPtr;
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
|
|
ThisProcessor = KeGetPcr()->Prcb->Number;
|
|
|
|
//
|
|
// Do whatever is needed to this processor to restore
|
|
// system to a bootable state
|
|
//
|
|
|
|
pLocalApic[LU_TPR/4] = 0xff;
|
|
pLocalApic[LU_TIMER_VECTOR/4] =
|
|
(APIC_SPURIOUS_VECTOR |PERIODIC_TIMER | INTERRUPT_MASKED);
|
|
pLocalApic[LU_INT_VECTOR_0/4] =
|
|
(APIC_SPURIOUS_VECTOR | INTERRUPT_MASKED);
|
|
pLocalApic[LU_INT_VECTOR_1/4] =
|
|
( LEVEL_TRIGGERED | ACTIVE_HIGH | DELIVER_NMI |
|
|
INTERRUPT_MASKED | NMI_VECTOR);
|
|
if (HalpMpInfoTable.ApicVersion != APIC_82489DX) {
|
|
pLocalApic[LU_FAULT_VECTOR/4] =
|
|
APIC_FAULT_VECTOR | INTERRUPT_MASKED;
|
|
}
|
|
|
|
if (ThisProcessor == 0) {
|
|
_asm {
|
|
lock dec HalpProcessorsNotHalted
|
|
}
|
|
//
|
|
// we are running on the BSP, wait for everyone to
|
|
// complete the re-initialization code above
|
|
//
|
|
AllProcessorsHalted = 0;
|
|
while(!AllProcessorsHalted) {
|
|
_asm {
|
|
lock and HalpProcessorsNotHalted,0xffffffff
|
|
jnz EveryOneNotDone
|
|
inc AllProcessorsHalted
|
|
EveryOneNotDone:
|
|
} // asm block
|
|
} // NOT AllProcessorsHalted
|
|
|
|
KeStallExecutionProcessor(100);
|
|
|
|
//
|
|
// Write the Shutdown reason code, so the BIOS knows
|
|
// this is a reboot
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(CMOS_CTRL, 0x0f); // CMOS Addr 0f
|
|
|
|
WRITE_PORT_UCHAR(CMOS_DATA, 0x00); // Reason Code Reset
|
|
|
|
physicalAddress.QuadPart = 0;
|
|
Magic = HalpMapPhysicalMemory(physicalAddress, 1);
|
|
Magic[0x472 / sizeof(USHORT)] = 0x1234; // warm boot
|
|
|
|
//
|
|
// If required, disable APIC mode
|
|
//
|
|
|
|
if (HalpMpInfoTable.IMCRPresent)
|
|
{
|
|
_asm {
|
|
mov al, ImcrPort
|
|
out ImcrRegPortAddr, al
|
|
}
|
|
|
|
KeStallExecutionProcessor(100);
|
|
_asm {
|
|
mov al, ImcrDisableApic
|
|
out ImcrDataPortAddr, al
|
|
}
|
|
}
|
|
|
|
KeStallExecutionProcessor(100);
|
|
|
|
for (j=0; j<HalpMpInfoTable.IOApicCount; j++) {
|
|
IoUnitPtr = (struct ApicIoUnit *) HalpMpInfoTable.IoApicBase[j];
|
|
|
|
//
|
|
// Disable all interrupts on IO Unit
|
|
//
|
|
|
|
IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
|
|
max = ((IoUnitPtr->RegisterWindow >> 16) & 0xff) * 2;
|
|
for (i=0; i <= max; i += 2) {
|
|
IoUnitPtr->RegisterSelect = IO_REDIR_00_LOW + i;
|
|
IoUnitPtr->RegisterWindow |= INT_VECTOR_MASK | INTERRUPT_MASKED;
|
|
|
|
//
|
|
// Clear any set Remote IRR bits by programming the entry to
|
|
// edge and then back to level. Otherwise there will be
|
|
// no further interrupts from this source.
|
|
//
|
|
|
|
IoUnitPtr->RegisterSelect = IO_REDIR_00_LOW + i;
|
|
RedirEntry = IoUnitPtr->RegisterWindow;
|
|
if ( (RedirEntry & LEVEL_TRIGGERED) && (RedirEntry & REMOTE_IRR)) {
|
|
RedirEntry &= ~LEVEL_TRIGGERED;
|
|
IoUnitPtr->RegisterWindow = RedirEntry;
|
|
RedirEntry = IoUnitPtr->RegisterWindow;
|
|
RedirEntry |= LEVEL_TRIGGERED;
|
|
IoUnitPtr->RegisterWindow = RedirEntry;
|
|
}
|
|
}
|
|
} // for all Io Apics
|
|
|
|
//
|
|
// Disable the Local Apic
|
|
//
|
|
pLocalApic[LU_SPURIOUS_VECTOR/4] =
|
|
(APIC_SPURIOUS_VECTOR | LU_UNIT_DISABLED);
|
|
|
|
|
|
KeStallExecutionProcessor(100);
|
|
|
|
_asm {
|
|
cli
|
|
};
|
|
|
|
//
|
|
// Enable Pic interrupts
|
|
//
|
|
HalpGlobal8259Mask = 0;
|
|
HalpSet8259Mask ((USHORT) HalpGlobal8259Mask);
|
|
|
|
KeStallExecutionProcessor(1000);
|
|
|
|
//
|
|
// Finally, reset the system through
|
|
// the keyboard controller
|
|
//
|
|
WRITE_PORT_UCHAR(KEYBPORT, RESET);
|
|
|
|
} else {
|
|
//
|
|
// We're running on a processor other than the BSP
|
|
//
|
|
|
|
//
|
|
// Disable the Local Apic
|
|
//
|
|
|
|
pLocalApic[LU_SPURIOUS_VECTOR/4] =
|
|
(APIC_SPURIOUS_VECTOR | LU_UNIT_DISABLED);
|
|
|
|
KeStallExecutionProcessor(100);
|
|
|
|
//
|
|
// Now we are done, tell the BSP
|
|
//
|
|
|
|
_asm {
|
|
lock dec HalpProcessorsNotHalted
|
|
}
|
|
} // Not BSP
|
|
|
|
|
|
//
|
|
// Everyone stops here until reset
|
|
//
|
|
_asm {
|
|
cli
|
|
StayHalted:
|
|
hlt
|
|
jmp StayHalted
|
|
}
|
|
}
|
|
|
|
#if !defined(NT_UP)
|
|
ULONG
|
|
HalpStartProcessor (
|
|
IN PVOID InitCodePhysAddr,
|
|
IN ULONG ProcessorNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Actually Start the Processor in question. This routine
|
|
assumes the init code is setup and ready to run. The real
|
|
mode init code must begin on a page boundry.
|
|
|
|
NOTE: This assumes the BSP is entry 0 in the MP table.
|
|
|
|
This routine cannot fail.
|
|
|
|
Arguments:
|
|
InitCodePhysAddr - execution address of init code
|
|
|
|
Return Value:
|
|
0 - Something prevented us from issuing the reset.
|
|
|
|
n - Processor's PCMP Local APICID + 1
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
UCHAR ApicID;
|
|
PVULONG LuDestAddress = (PVULONG) (LOCALAPIC + LU_INT_CMD_HIGH);
|
|
PVULONG LuICR = (PVULONG) (LOCALAPIC + LU_INT_CMD_LOW);
|
|
#define DEFAULT_DELAY 100
|
|
ULONG DelayCount = DEFAULT_DELAY;
|
|
ULONG ICRCommand,i;
|
|
|
|
ASSERT((((ULONG) InitCodePhysAddr) & 0xfff00fff) == 0);
|
|
|
|
if (ProcessorNumber >= HalpMpInfoTable.ProcessorCount) {
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// Get the APIC ID of the processor to start.
|
|
//
|
|
|
|
status = HalpGetNextProcessorApicId(ProcessorNumber,
|
|
&ApicID);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
#ifdef DEBUGGING
|
|
HalpDisplayString("HAL: HalpStartProcessor: No Processor Available\n");
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
if (HalpDontStartProcessors)
|
|
return ApicID+1;
|
|
|
|
//
|
|
// Make sure we can get to the Apic Bus
|
|
//
|
|
|
|
KeStallExecutionProcessor(200);
|
|
if (HalpWaitForPending (DEFAULT_DELAY, LuICR) == 0) {
|
|
//
|
|
// We couldn't find a processor to start
|
|
//
|
|
#ifdef DEBUGGING
|
|
HalpDisplayString("HAL: HalpStartProcessor: can't access APIC Bus\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
// For a P54 C/CM system, it is possible that the BSP is the P54CM and the
|
|
// P54C is the Application processor. The P54C needs an INIT (reset)
|
|
// to restart, so we issue a reset regardless of whether we a 82489DX
|
|
// or an integrated APIC.
|
|
|
|
//
|
|
// This system is based on the original 82489DX's.
|
|
// These devices do not support the Startup IPI's.
|
|
// The mechanism used is the ASSERT/DEASSERT INIT
|
|
// feature of the local APIC. This resets the
|
|
// processor.
|
|
//
|
|
|
|
#ifdef DEBUGGING
|
|
sprintf(Cbuf, "HAL: HalpStartProcessor: Reset IPI to ApicId %d (0x%x)\n",
|
|
ApicID,((ULONG) ApicID) << DESTINATION_SHIFT );
|
|
HalpDisplayString(Cbuf);
|
|
#endif
|
|
|
|
//
|
|
// We use a Physical Destination
|
|
//
|
|
|
|
*LuDestAddress = ((ULONG) ApicID) << DESTINATION_SHIFT;
|
|
|
|
//
|
|
// Now Assert reset and drop it
|
|
//
|
|
|
|
*LuICR = LU_RESET_ASSERT;
|
|
KeStallExecutionProcessor(10);
|
|
*LuICR = LU_RESET_DEASSERT;
|
|
KeStallExecutionProcessor(200);
|
|
|
|
if (HalpMpInfoTable.ApicVersion == APIC_82489DX) {
|
|
return ApicID+1;
|
|
}
|
|
|
|
//
|
|
// Set the Startup Address as a vector and combine with the
|
|
// ICR bits
|
|
//
|
|
ICRCommand = (((ULONG) InitCodePhysAddr & 0x000ff000) >> 12)
|
|
| LU_STARTUP_IPI;
|
|
|
|
#ifdef DEBUGGING
|
|
sprintf(Cbuf, "HAL: HalpStartProcessor: Startup IPI (0x%x) to ApicId %d (0x%x)\n",
|
|
ICRCommand, ApicID, ((ULONG) ApicID) << DESTINATION_SHIFT );
|
|
HalpDisplayString(Cbuf);
|
|
#endif
|
|
|
|
//
|
|
// Set the Address of the APIC again, this may not be needed
|
|
// but it can't hurt.
|
|
//
|
|
*LuDestAddress = (ApicID << DESTINATION_SHIFT);
|
|
//
|
|
// Issue the request
|
|
//
|
|
*LuICR = ICRCommand;
|
|
KeStallExecutionProcessor(200);
|
|
|
|
//
|
|
// Repeat the Startup IPI. This is because the second processor may
|
|
// have been issued an INIT request. This is generated by some BIOSs.
|
|
//
|
|
// On older processors (286) BIOS's use a mechanism called triple
|
|
// fault reset to transition from protected mode to real mode.
|
|
// This mechanism causes the processor to generate a shutdown cycle.
|
|
// The shutdown is typically issued by the BIOS building an invalid
|
|
// IDT and then generating an interrupt. Newer processors have an
|
|
// INIT line that the chipset jerks when it sees a shutdown cycle
|
|
// issued by the processor. The Phoenix BIOS, for example, has
|
|
// integrated support for triple fault reset as part of their POST
|
|
// (Power On Self Test) code.
|
|
//
|
|
// When the P54CM powers on it is held in a tight microcode loop
|
|
// waiting for a Startup IPI to be issued and queuing other requests.
|
|
// When the POST code executes the triple fault reset test the INIT
|
|
// cycle is queued by the processor. Later, when a Startup IPI is
|
|
// issued to the CM, the CM starts and immediately gets a INIT cycle.
|
|
// The effect from a software standpoint is that the processor is
|
|
// never started.
|
|
//
|
|
// The work around implemented here is to issue two Startup IPI's.
|
|
// The first allows the INIT to be processed and the second performs
|
|
// the actual startup.
|
|
//
|
|
|
|
//
|
|
// Make sure we can get to the Apic Bus
|
|
//
|
|
|
|
|
|
if (HalpWaitForPending (DEFAULT_DELAY, LuICR) == 0) {
|
|
//
|
|
// We're toast, can't gain access to the APIC Bus
|
|
//
|
|
#ifdef DEBUGGING
|
|
HalpDisplayString("HAL: HalpStartProcessor: can't access APIC Bus\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Allow Time for any Init request to be processed
|
|
//
|
|
KeStallExecutionProcessor(100);
|
|
|
|
//
|
|
// Set the Address of the APIC again, this may not be needed
|
|
// but it can't hurt.
|
|
//
|
|
*LuDestAddress = (ApicID << DESTINATION_SHIFT);
|
|
//
|
|
// Issue the request
|
|
//
|
|
*LuICR = ICRCommand;
|
|
|
|
KeStallExecutionProcessor(200);
|
|
return ApicID+1;
|
|
}
|
|
#endif // !NT_UP
|
|
|
|
|
|
ULONG
|
|
FASTCALL
|
|
HalSystemVectorDispatchEntry (
|
|
IN ULONG Vector,
|
|
OUT PKINTERRUPT_ROUTINE **FlatDispatch,
|
|
OUT PKINTERRUPT_ROUTINE *NoConnection
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|