/*
* ReactOS kernel
- * Copyright (C) 2004 ReactOS Team
+ * Copyright (C) 2004, 2005 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* PROGRAMMER:
*/
-#include <ddk/ntddk.h>
-#include <internal/i386/ps.h>
+/* INCLUDE ***********************************************************************/
#include <hal.h>
-#include <halirq.h>
-#include <mps.h>
-#include <apic.h>
-
+#include <halfuncs.h> /* Not in PCH because only used for MP HAL */
+#include <rtlfuncs.h> /* Not in PCH because only used for MP HAL */
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
-BOOLEAN VerifyLocalAPIC(VOID);
-VOID APICCalibrateTimer(ULONG CPU);
+/* GLOBALS ***********************************************************************/
-extern VOID MpsTimerInterrupt(VOID);
-extern VOID MpsErrorInterrupt(VOID);
-extern VOID MpsSpuriousInterrupt(VOID);
-extern VOID MpsIpiInterrupt(VOID);
+ULONG CPUCount; /* Total number of CPUs */
+ULONG BootCPU; /* Bootstrap processor */
+ULONG OnlineCPUs; /* Bitmask of online CPUs */
+CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */
+
+#ifdef CONFIG_SMP
+PULONG BIOSBase; /* Virtual address of BIOS data segment */
+PULONG CommonBase; /* Virtual address of common area */
+#endif
+
+PULONG APICBase = (PULONG)APIC_DEFAULT_BASE; /* Virtual address of local APIC */
-extern ULONG APICMode; /* APIC mode at startup */
-extern PULONG BIOSBase; /* Virtual address of BIOS data segment */
-extern PULONG CommonBase; /* Virtual address of common area */
-extern ULONG BootCPU; /* Bootstrap processor */
-extern ULONG OnlineCPUs; /* Bitmask of online CPUs */
+ULONG APICMode; /* APIC mode at startup */
+
+/* For debugging */
+ULONG lastregr[MAX_CPU];
+ULONG lastvalr[MAX_CPU];
+ULONG lastregw[MAX_CPU];
+ULONG lastvalw[MAX_CPU];
+
+#ifdef CONFIG_SMP
+#include <pshpack1.h>
+typedef struct _COMMON_AREA_INFO
+{
+ ULONG Stack; /* Location of AP stack */
+ ULONG PageDirectory; /* Page directory for an AP */
+ ULONG NtProcessStartup; /* Kernel entry point for an AP */
+ ULONG PaeModeEnabled; /* PAE mode is enabled */
+ ULONG Debug[16]; /* For debugging */
+} COMMON_AREA_INFO, *PCOMMON_AREA_INFO;
+#include <poppack.h>
+#endif
-extern CHAR *APstart, *APend;
-extern VOID (*APflush)(VOID);
+CHAR *APstart, *APend;
-#define CMOS_READ(address) ({ \
+#define BIOS_AREA 0x0
+#define COMMON_AREA 0x2000
+
+#define HZ (100)
+#define APIC_DIVISOR (16)
+
+#define CMOS_READ(address) { \
WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
READ_PORT_UCHAR((PUCHAR)0x71)); \
-})
+}
-#define CMOS_WRITE(address, value) ({ \
+#define CMOS_WRITE(address, value) { \
WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
-})
-
-#define BIOS_AREA 0x0
-#define COMMON_AREA 0x2000
-
+}
-extern CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */
+extern ULONG_PTR KernelBase;
-PULONG APICBase = (PULONG)APIC_DEFAULT_BASE; /* Virtual address of local APIC */
+/* FUNCTIONS *********************************************************************/
-/* For debugging */
-ULONG lastregr[MAX_CPU];
-ULONG lastvalr[MAX_CPU];
-ULONG lastregw[MAX_CPU];
-ULONG lastvalw[MAX_CPU];
+extern ULONG Read8254Timer(VOID);
+extern VOID WaitFor8254Wraparound(VOID);
+extern VOID MpsTimerInterrupt(VOID);
+extern VOID MpsErrorInterrupt(VOID);
+extern VOID MpsSpuriousInterrupt(VOID);
+extern VOID MpsIpiInterrupt(VOID);
ULONG APICGetMaxLVT(VOID)
{
}
/* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */
-VOID EnableSMPMode(VOID)
+VOID EnableApicMode(VOID)
{
/*
* Do not trust the local APIC being empty at bootup.
}
/* Disable symetric I/O mode ie. go to PIC mode */
-inline VOID DisableSMPMode(VOID)
+__inline VOID DisableSMPMode(VOID)
{
/*
* Put the board back into PIC mode (has an effect
APICWrite(APIC_SIVR, tmp);
}
-VOID HaliInitBSP(VOID)
-{
- PUSHORT ps;
- static BOOLEAN BSPInitialized = FALSE;
-
- /* Only initialize the BSP once */
- if (BSPInitialized)
- {
- KEBUGCHECK(0);
- return;
- }
-
- BSPInitialized = TRUE;
-
- DPRINT("APIC is mapped at 0x%X\n", APICBase);
-
- if (VerifyLocalAPIC())
- {
- DPRINT("APIC found\n");
- }
- else
- {
- DPRINT("No APIC found\n");
- KEBUGCHECK(0);
- }
-
- if (APICMode == amPIC)
- {
- EnableSMPMode();
- }
-
- APICSetup();
-
- /* BIOS data segment */
- BIOSBase = (PULONG)BIOS_AREA;
-
- /* Area for communicating with the APs */
- CommonBase = (PULONG)COMMON_AREA;
-
- /* Copy bootstrap code to common area */
- memcpy((PVOID)((ULONG)CommonBase + PAGE_SIZE),
- &APstart,
- (ULONG)&APend - (ULONG)&APstart + 1);
-
- /* Set shutdown code */
- CMOS_WRITE(0xF, 0xA);
-
- /* Set warm reset vector */
- ps = (PUSHORT)((ULONG)BIOSBase + 0x467);
- *ps = (COMMON_AREA + PAGE_SIZE) & 0xF;
-
- ps = (PUSHORT)((ULONG)BIOSBase + 0x469);
- *ps = (COMMON_AREA + PAGE_SIZE) >> 4;
-
- /* Calibrate APIC timer */
- APICCalibrateTimer(BootCPU);
-}
-
-inline ULONG _APICRead(ULONG Offset)
-{
- PULONG p;
-
- p = (PULONG)((ULONG)APICBase + Offset);
- return *p;
-}
-
-#if 0
-inline VOID APICWrite(ULONG Offset,
- ULONG Value)
-{
- PULONG p;
-
- p = (PULONG)((ULONG)APICBase + Offset);
-
- *p = Value;
-}
-#else
-inline VOID APICWrite(ULONG Offset,
- ULONG Value)
-{
- PULONG p;
- ULONG CPU = (_APICRead(APIC_ID) & APIC_ID_MASK) >> 24;
-
- lastregw[CPU] = Offset;
- lastvalw[CPU] = Value;
-
- p = (PULONG)((ULONG)APICBase + Offset);
-
- *p = Value;
-}
-#endif
-
-
-#if 0
-inline ULONG APICRead(ULONG Offset)
-{
- PULONG p;
-
- p = (PULONG)((ULONG)APICBase + Offset);
- return *p;
-}
-#else
-inline ULONG APICRead(ULONG Offset)
-{
- PULONG p;
- ULONG CPU = (_APICRead(APIC_ID) & APIC_ID_MASK) >> 24;
-
- lastregr[CPU] = Offset;
- lastvalr[CPU] = 0;
-
- p = (PULONG)((ULONG)APICBase + Offset);
-
- lastvalr[CPU] = *p;
- return lastvalr[CPU];
-}
-#endif
-
-inline VOID APICSendEOI(VOID)
-{
- // Send the EOI
- APICWrite(APIC_EOI, 0);
-}
-
static VOID APICDumpBit(ULONG base)
{
ULONG v, i, j;
{
ULONG v, ver, maxlvt;
ULONG r1, r2, w1, w2;
- ULONG CPU = ThisCPU();;
-
+ ULONG CPU = ThisCPU();
r1 = lastregr[CPU];
BOOLEAN VerifyLocalAPIC(VOID)
{
- UINT reg0, reg1;
- CHECKPOINT1;
+ SIZE_T reg0, reg1;
+ ULONG l = 0, h = 0;
/* The version register is read-only in a real APIC */
reg0 = APICRead(APIC_VER);
DPRINT1("Getting VERSION: %x\n", reg0);
return FALSE;
}
+ Ke386Rdmsr(0x1b /*MSR_IA32_APICBASE*/, l, h);
+
+ if (!(l & /*MSR_IA32_APICBASE_ENABLE*/(1<<11)))
+ {
+ DPRINT1("Local APIC disabled by BIOS -- reenabling.\n");
+ l &= ~/*MSR_IA32_APICBASE_BASE*/(1<<11);
+ l |= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000;
+ Ke386Wrmsr(0x1b/*MSR_IA32_APICBASE*/, l, h);
+ }
+
+
+
return TRUE;
}
+#ifdef CONFIG_SMP
VOID APICSendIPI(ULONG Target, ULONG Mode)
{
- ULONG tmp, i, flags;
+ ULONG tmp, i, flags = 0;
/* save flags and disable interrupts */
- Ki386SaveFlags(flags);
- Ki386DisableInterrupts();
+ Ke386SaveFlags(flags);
+ _disable();
/* Wait up to 100ms for the APIC to become ready */
for (i = 0; i < 10000; i++)
{
DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
}
- Ki386RestoreFlags(flags);
+ Ke386RestoreFlags(flags);
}
+#endif
VOID APICSetup(VOID)
{
}
APICWrite(APIC_LINT0, tmp);
-
/*
* Only the BSP should see the LINT1 NMI signal, obviously.
*/
DPRINT("ESR value after enabling vector: 0x%X\n", tmp);
}
}
-
+#ifdef CONFIG_SMP
VOID APICSyncArbIDs(VOID)
{
ULONG i, tmp;
DPRINT("Synchronizing Arb IDs.\n");
APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT);
}
+#endif
VOID MpsErrorHandler(VOID)
{
{
ULONG tmp;
- DPRINT1("Spurious interrupt on CPU(%d)\n", ThisCPU());
+ DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU());
tmp = APICRead(APIC_ISR + ((SPURIOUS_VECTOR & ~0x1f) >> 1));
if (tmp & (1 << (SPURIOUS_VECTOR & 0x1f)))
#endif
}
+#ifdef CONFIG_SMP
VOID MpsIpiHandler(VOID)
{
KIRQL oldIrql;
- HalBeginSystemInterrupt(IPI_VECTOR,
- VECTOR2IRQL(IPI_VECTOR),
+ HalBeginSystemInterrupt(IPI_LEVEL,
+ IPI_VECTOR,
&oldIrql);
- Ki386EnableInterrupts();
+ _enable();
#if 0
DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n",
__FILE__,__LINE__, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber());
#endif
- Ki386DisableInterrupts();
+ _disable();
HalEndSystemInterrupt(oldIrql, 0);
}
+#endif
VOID
MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
PKTRAP_FRAME TrapFrame)
{
- TrapFrame->Gs = (USHORT)IrqTrapFrame->Gs;
- TrapFrame->Fs = (USHORT)IrqTrapFrame->Fs;
- TrapFrame->Es = (USHORT)IrqTrapFrame->Es;
- TrapFrame->Ds = (USHORT)IrqTrapFrame->Ds;
+#ifdef _M_AMD64
+ UNIMPLEMENTED;
+#else
+ TrapFrame->SegGs = (USHORT)IrqTrapFrame->Gs;
+ TrapFrame->SegFs = (USHORT)IrqTrapFrame->Fs;
+ TrapFrame->SegEs = (USHORT)IrqTrapFrame->Es;
+ TrapFrame->SegDs = (USHORT)IrqTrapFrame->Ds;
TrapFrame->Eax = IrqTrapFrame->Eax;
TrapFrame->Ecx = IrqTrapFrame->Ecx;
TrapFrame->Edx = IrqTrapFrame->Edx;
TrapFrame->Ebx = IrqTrapFrame->Ebx;
- TrapFrame->Esp = IrqTrapFrame->Esp;
+ TrapFrame->HardwareEsp = IrqTrapFrame->Esp;
TrapFrame->Ebp = IrqTrapFrame->Ebp;
TrapFrame->Esi = IrqTrapFrame->Esi;
TrapFrame->Edi = IrqTrapFrame->Edi;
TrapFrame->Eip = IrqTrapFrame->Eip;
- TrapFrame->Cs = IrqTrapFrame->Cs;
- TrapFrame->Eflags = IrqTrapFrame->Eflags;
+ TrapFrame->SegCs = IrqTrapFrame->Cs;
+ TrapFrame->EFlags = IrqTrapFrame->Eflags;
+#endif
}
VOID
static ULONG Count[MAX_CPU] = {0,};
#endif
HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR,
- VECTOR2IRQL(LOCAL_TIMER_VECTOR),
+ PROFILE_LEVEL,
&oldIrql);
- Ki386EnableInterrupts();
+ _enable();
#if 0
CPU = ThisCPU();
if ((Count[CPU] % 100) == 0)
{
- DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__, __LINE__, CPU, oldIrql,Trapframe->Eip, KeGetCurrentKPCR());
+ DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__, __LINE__, CPU, oldIrql,Trapframe->Eip, KeGetPcr());
}
Count[CPU]++;
#endif
+ /* FIXME: SMP is totally broken */
MpsIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
if (KeGetCurrentProcessorNumber() == 0)
{
- KeUpdateSystemTime(&KernelTrapFrame, oldIrql);
+ //KeUpdateSystemTime(&KernelTrapFrame, oldIrql);
}
else
{
- KeUpdateRunTime(&KernelTrapFrame, oldIrql);
+ //KeUpdateRunTime(&KernelTrapFrame, oldIrql);
}
- Ki386DisableInterrupts();
+ _disable();
HalEndSystemInterrupt (oldIrql, 0);
}
+VOID APICSetupLVTT(ULONG ClockTicks)
+{
+ ULONG tmp;
+
+ tmp = GET_APIC_VERSION(APICRead(APIC_VER));
+ if (!APIC_INTEGRATED(tmp))
+ {
+ tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;
+ }
+ else
+ {
+ /* Periodic timer */
+ tmp = APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;
+ }
+ APICWrite(APIC_LVTT, tmp);
+
+ tmp = APICRead(APIC_TDCR);
+ tmp &= ~(APIC_TDCR_1 | APIC_TIMER_BASE_DIV);
+ tmp |= APIC_TDCR_16;
+ APICWrite(APIC_TDCR, tmp);
+ APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR);
+}
+
+VOID
+APICCalibrateTimer(ULONG CPU)
+{
+ ULARGE_INTEGER t1, t2;
+ LONG tt1, tt2;
+ BOOLEAN TSCPresent;
+
+ DPRINT("Calibrating APIC timer for CPU %d\n", CPU);
+
+ APICSetupLVTT(1000000000);
+
+ TSCPresent = KeGetCurrentPrcb()->FeatureBits & KF_RDTSC ? TRUE : FALSE;
+
+ /*
+ * The timer chip counts down to zero. Let's wait
+ * for a wraparound to start exact measurement:
+ * (the current tick might have been already half done)
+ */
+ //WaitFor8254Wraparound();
+
+ /*
+ * We wrapped around just now. Let's start
+ */
+ if (TSCPresent)
+ {
+ t1.QuadPart = (LONGLONG)__rdtsc();
+ }
+ tt1 = APICRead(APIC_CCRT);
+
+ //WaitFor8254Wraparound();
+
+
+ tt2 = APICRead(APIC_CCRT);
+ if (TSCPresent)
+ {
+ t2.QuadPart = (LONGLONG)__rdtsc();
+ CPUMap[CPU].CoreSpeed = (HZ * (t2.QuadPart - t1.QuadPart));
+ DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
+ CPUMap[CPU].CoreSpeed/1000000,
+ CPUMap[CPU].CoreSpeed%1000000);
+ KeGetCurrentPrcb()->MHz = CPUMap[CPU].CoreSpeed/1000000;
+ }
+
+ CPUMap[CPU].BusSpeed = (HZ * (long)(tt1 - tt2) * APIC_DIVISOR);
+
+ /* Setup timer for normal operation */
+// APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
+ APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 10000); // 10ms
+// APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
+
+ DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
+ CPUMap[CPU].BusSpeed/1000000,
+ CPUMap[CPU].BusSpeed%1000000);
+}
+
+VOID
+SetInterruptGate(ULONG index, ULONG_PTR address)
+{
+#ifdef _M_AMD64
+ KIDTENTRY64 *idt;
+
+ idt = &KeGetPcr()->IdtBase[index];
+
+ idt->OffsetLow = address & 0xffff;
+ idt->Selector = KGDT_64_R0_CODE;
+ idt->IstIndex = 0;
+ idt->Reserved0 = 0;
+ idt->Type = 0x0e;
+ idt->Dpl = 0;
+ idt->Present = 1;
+ idt->OffsetMiddle = (address >> 16) & 0xffff;
+ idt->OffsetHigh = address >> 32;
+ idt->Reserved1 = 0;
+ idt->Alignment = 0;
+#else
+ KIDTENTRY *idt;
+ KIDT_ACCESS Access;
+
+ /* Set the IDT Access Bits */
+ Access.Reserved = 0;
+ Access.Present = 1;
+ Access.Dpl = 0; /* Kernel-Mode */
+ Access.SystemSegmentFlag = 0;
+ Access.SegmentType = I386_INTERRUPT_GATE;
+
+ idt = (KIDTENTRY*)((ULONG)KeGetPcr()->IDT + index * sizeof(KIDTENTRY));
+ idt->Offset = address & 0xffff;
+ idt->Selector = KGDT_R0_CODE;
+ idt->Access = Access.Value;
+ idt->ExtendedOffset = address >> 16;
+#endif
+}
+
+VOID HaliInitBSP(VOID)
+{
+#ifdef CONFIG_SMP
+ PUSHORT ps;
+#endif
+
+ static BOOLEAN BSPInitialized = FALSE;
+
+ /* Only initialize the BSP once */
+ if (BSPInitialized)
+ {
+ ASSERT(FALSE);
+ return;
+ }
+
+ BSPInitialized = TRUE;
+
+ /* Setup interrupt handlers */
+ SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG_PTR)MpsTimerInterrupt);
+ SetInterruptGate(ERROR_VECTOR, (ULONG_PTR)MpsErrorInterrupt);
+ SetInterruptGate(SPURIOUS_VECTOR, (ULONG_PTR)MpsSpuriousInterrupt);
+#ifdef CONFIG_SMP
+ SetInterruptGate(IPI_VECTOR, (ULONG_PTR)MpsIpiInterrupt);
+#endif
+ DPRINT1("APIC is mapped at 0x%p\n", (PVOID)APICBase);
+
+ if (VerifyLocalAPIC())
+ {
+ DPRINT("APIC found\n");
+ }
+ else
+ {
+ DPRINT1("No APIC found\n");
+ ASSERT(FALSE);
+ }
+
+ if (APICMode == amPIC)
+ {
+ EnableApicMode();
+ }
+
+ APICSetup();
+
+#ifdef CONFIG_SMP
+ /* BIOS data segment */
+ BIOSBase = (PULONG)BIOS_AREA;
+
+ /* Area for communicating with the APs */
+ CommonBase = (PULONG)COMMON_AREA;
+
+ /* Copy bootstrap code to common area */
+ memcpy((PVOID)((ULONG_PTR)CommonBase + PAGE_SIZE),
+ &APstart,
+ (ULONG_PTR)&APend - (ULONG_PTR)&APstart + 1);
+
+ /* Set shutdown code */
+ CMOS_WRITE(0xF, 0xA);
+
+ /* Set warm reset vector */
+ ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x467);
+ *ps = (COMMON_AREA + PAGE_SIZE) & 0xF;
+
+ ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x469);
+ *ps = (COMMON_AREA + PAGE_SIZE) >> 4;
+#endif
+
+ /* Calibrate APIC timer */
+ APICCalibrateTimer(BootCPU);
+}
+
+#ifdef CONFIG_SMP
+VOID
+HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack)
+{
+ ULONG tmp, maxlvt;
+ PCOMMON_AREA_INFO Common;
+ ULONG StartupCount;
+ ULONG i, j;
+ ULONG DeliveryStatus = 0;
+ ULONG AcceptStatus = 0;
+
+ if (Cpu >= MAX_CPU ||
+ Cpu >= CPUCount ||
+ OnlineCPUs & (1 << Cpu))
+ {
+ ASSERT(FALSE);
+ }
+ DPRINT1("Attempting to boot CPU %d\n", Cpu);
+
+ /* Send INIT IPI */
+
+ APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_ASSERT);
+
+ KeStallExecutionProcessor(200);
+
+ /* Deassert INIT */
+
+ APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_DEASSERT);
+
+ if (APIC_INTEGRATED(CPUMap[Cpu].APICVersion))
+ {
+ /* Clear APIC errors */
+ APICWrite(APIC_ESR, 0);
+ tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK);
+ }
+
+ Common = (PCOMMON_AREA_INFO)CommonBase;
+
+ /* Write the location of the AP stack */
+ Common->Stack = (ULONG)Stack;
+ /* Write the page directory page */
+ Common->PageDirectory = __readcr3();
+ /* Write the kernel entry point */
+ Common->NtProcessStartup = (ULONG_PTR)RtlImageNtHeader((PVOID)KernelBase)->OptionalHeader.AddressOfEntryPoint + KernelBase;
+ /* Write the state of the mae mode */
+ Common->PaeModeEnabled = __readcr4() & CR4_PAE ? 1 : 0;
+
+ DPRINT1("%x %x %x %x\n", Common->Stack, Common->PageDirectory, Common->NtProcessStartup, Common->PaeModeEnabled);
+
+ DPRINT("Cpu %d got stack at 0x%X\n", Cpu, Common->Stack);
+#if 0
+ for (j = 0; j < 16; j++)
+ {
+ Common->Debug[j] = 0;
+ }
+#endif
+
+ maxlvt = APICGetMaxLVT();
+
+ /* Is this a local APIC or an 82489DX? */
+ StartupCount = (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) ? 2 : 0;
+
+ for (i = 1; i <= StartupCount; i++)
+ {
+ /* It's a local APIC, so send STARTUP IPI */
+ DPRINT("Sending startup signal %d\n", i);
+ /* Clear errors */
+ APICWrite(APIC_ESR, 0);
+ APICRead(APIC_ESR);
+
+ APICSendIPI(Cpu, APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12)|APIC_ICR0_LEVEL_DEASSERT);
+
+ /* Wait up to 10ms for IPI to be delivered */
+ j = 0;
+ do
+ {
+ KeStallExecutionProcessor(10);
+
+ /* Check Delivery Status */
+ DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS;
+
+ j++;
+ } while ((DeliveryStatus) && (j < 1000));
+
+ KeStallExecutionProcessor(200);
+
+ /*
+ * Due to the Pentium erratum 3AP.
+ */
+ if (maxlvt > 3)
+ {
+ APICRead(APIC_SIVR);
+ APICWrite(APIC_ESR, 0);
+ }
+
+ AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK;
+
+ if (DeliveryStatus || AcceptStatus)
+ {
+ break;
+ }
+ }
+
+ if (DeliveryStatus)
+ {
+ DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu);
+ }
+
+ if (AcceptStatus)
+ {
+ DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu);
+ }
+
+ if (!(DeliveryStatus || AcceptStatus))
+ {
+
+ /* Wait no more than 5 seconds for processor to boot */
+ DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu);
+
+ /* Wait no more than 5 seconds */
+ for (j = 0; j < 50000; j++)
+ {
+ if (CPUMap[Cpu].Flags & CPU_ENABLED)
+ {
+ break;
+ }
+ KeStallExecutionProcessor(100);
+ }
+ }
+
+ if (CPUMap[Cpu].Flags & CPU_ENABLED)
+ {
+ DbgPrint("CPU %d is now running\n", Cpu);
+ }
+ else
+ {
+ DbgPrint("Initialization of CPU %d failed\n", Cpu);
+ }
+
+#if 0
+ DPRINT("Debug bytes are:\n");
+
+ for (j = 0; j < 4; j++)
+ {
+ DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
+ Common->Debug[j*4+0],
+ Common->Debug[j*4+1],
+ Common->Debug[j*4+2],
+ Common->Debug[j*4+3]);
+ }
+
+#endif
+}
+
+#endif
+
/* EOF */