3 * Copyright (C) 2004, 2005 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: hal/halx86/apic.c
28 /* INCLUDE ***********************************************************************/
31 #include <halfuncs.h> /* Not in PCH because only used for MP HAL */
32 #include <rtlfuncs.h> /* Not in PCH because only used for MP HAL */
36 /* GLOBALS ***********************************************************************/
38 ULONG CPUCount
; /* Total number of CPUs */
39 ULONG BootCPU
; /* Bootstrap processor */
40 ULONG OnlineCPUs
; /* Bitmask of online CPUs */
41 CPU_INFO CPUMap
[MAX_CPU
]; /* Map of all CPUs in the system */
44 PULONG BIOSBase
; /* Virtual address of BIOS data segment */
45 PULONG CommonBase
; /* Virtual address of common area */
48 PULONG APICBase
= (PULONG
)APIC_DEFAULT_BASE
; /* Virtual address of local APIC */
50 ULONG APICMode
; /* APIC mode at startup */
53 ULONG lastregr
[MAX_CPU
];
54 ULONG lastvalr
[MAX_CPU
];
55 ULONG lastregw
[MAX_CPU
];
56 ULONG lastvalw
[MAX_CPU
];
60 typedef struct _COMMON_AREA_INFO
62 ULONG Stack
; /* Location of AP stack */
63 ULONG PageDirectory
; /* Page directory for an AP */
64 ULONG NtProcessStartup
; /* Kernel entry point for an AP */
65 ULONG PaeModeEnabled
; /* PAE mode is enabled */
66 ULONG Debug
[16]; /* For debugging */
67 } COMMON_AREA_INFO
, *PCOMMON_AREA_INFO
;
71 extern CHAR
*APstart
, *APend
;
74 #define COMMON_AREA 0x2000
77 #define APIC_DIVISOR (16)
79 #define CMOS_READ(address) { \
80 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
81 READ_PORT_UCHAR((PUCHAR)0x71)); \
84 #define CMOS_WRITE(address, value) { \
85 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
86 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
89 extern ULONG_PTR KernelBase
;
91 /* FUNCTIONS *********************************************************************/
93 extern ULONG
Read8254Timer(VOID
);
94 extern VOID
WaitFor8254Wraparound(VOID
);
95 extern VOID
MpsTimerInterrupt(VOID
);
96 extern VOID
MpsErrorInterrupt(VOID
);
97 extern VOID
MpsSpuriousInterrupt(VOID
);
98 extern VOID
MpsIpiInterrupt(VOID
);
100 ULONG
APICGetMaxLVT(VOID
)
102 ULONG tmp
, ver
, maxlvt
;
104 tmp
= APICRead(APIC_VER
);
105 ver
= GET_APIC_VERSION(tmp
);
106 /* 82489DXs do not report # of LVT entries. */
107 maxlvt
= APIC_INTEGRATED(ver
) ? GET_APIC_MAXLVT(tmp
) : 2;
116 maxlvt
= APICGetMaxLVT();
119 * Careful: we have to set masks only first to deassert
120 * any level-triggered sources.
126 APICWrite(APIC_LVT3
, tmp
| APIC_LVT3_MASKED
);
129 tmp
= APICRead(APIC_LVTT
);
130 APICWrite(APIC_LVTT
, tmp
| APIC_LVT_MASKED
);
132 tmp
= APICRead(APIC_LINT0
);
133 APICWrite(APIC_LINT0
, tmp
| APIC_LVT_MASKED
);
135 tmp
= APICRead(APIC_LINT1
);
136 APICWrite(APIC_LINT1
, tmp
| APIC_LVT_MASKED
);
140 tmp
= APICRead(APIC_LVTPC
);
141 APICWrite(APIC_LVTPC
, tmp
| APIC_LVT_MASKED
);
146 tmp
= APICRead(APIC_LVTTHMR
);
147 APICWrite(APIC_LVTTHMR
, tmp
| APIC_LVT_MASKED
);
151 * Clean APIC state for other OSs:
153 APICWrite(APIC_LVTT
, APIC_LVT_MASKED
);
154 APICWrite(APIC_LINT0
, APIC_LVT_MASKED
);
155 APICWrite(APIC_LINT1
, APIC_LVT_MASKED
);
159 APICWrite(APIC_LVT3
, APIC_LVT3_MASKED
);
164 APICWrite(APIC_LVTPC
, APIC_LVT_MASKED
);
169 APICWrite(APIC_LVTTHMR
, APIC_LVT_MASKED
);
174 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */
175 VOID
EnableApicMode(VOID
)
178 * Do not trust the local APIC being empty at bootup.
182 WRITE_PORT_UCHAR((PUCHAR
)0x22, 0x70);
183 WRITE_PORT_UCHAR((PUCHAR
)0x23, 0x01);
186 /* Disable symetric I/O mode ie. go to PIC mode */
187 __inline VOID
DisableSMPMode(VOID
)
190 * Put the board back into PIC mode (has an effect
191 * only on certain older boards). Note that APIC
192 * interrupts, including IPIs, won't work beyond
193 * this point! The only exception are INIT IPIs.
195 WRITE_PORT_UCHAR((PUCHAR
)0x22, 0x70);
196 WRITE_PORT_UCHAR((PUCHAR
)0x23, 0x00);
203 if (APICGetMaxLVT() > 3)
205 APICWrite(APIC_ESR
, 0);
207 tmp
= APICRead(APIC_ESR
);
208 DbgPrint("ESR %08x\n", tmp
);
212 VOID
APICDisable(VOID
)
219 * Disable APIC (implies clearing of registers for 82489DX!).
221 tmp
= APICRead(APIC_SIVR
);
222 tmp
&= ~APIC_SIVR_ENABLE
;
223 APICWrite(APIC_SIVR
, tmp
);
226 static VOID
APICDumpBit(ULONG base
)
230 DbgPrint("0123456789abcdef0123456789abcdef\n");
231 for (i
= 0; i
< 8; i
++)
233 v
= APICRead(base
+ i
*0x10);
234 for (j
= 0; j
< 32; j
++)
248 * Dump the contents of the local APIC registers
251 ULONG v
, ver
, maxlvt
;
252 ULONG r1
, r2
, w1
, w2
;
253 ULONG CPU
= ThisCPU();
261 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
262 v
= APICRead(APIC_ID
);
263 DbgPrint("... ID : %08x (%01x) ", v
, GET_APIC_ID(v
));
264 v
= APICRead(APIC_VER
);
265 DbgPrint("... VERSION: %08x\n", v
);
266 ver
= GET_APIC_VERSION(v
);
267 maxlvt
= APICGetMaxLVT();
269 v
= APICRead(APIC_TPR
);
270 DbgPrint("... TPR : %08x (%02x)", v
, v
& ~0);
272 if (APIC_INTEGRATED(ver
))
275 v
= APICRead(APIC_APR
);
276 DbgPrint("... APR : %08x (%02x)\n", v
, v
& ~0);
277 v
= APICRead(APIC_PPR
);
278 DbgPrint("... PPR : %08x\n", v
);
281 v
= APICRead(APIC_EOI
);
282 DbgPrint("... EOI : %08x ! ", v
);
283 v
= APICRead(APIC_LDR
);
284 DbgPrint("... LDR : %08x\n", v
);
285 v
= APICRead(APIC_DFR
);
286 DbgPrint("... DFR : %08x ! ", v
);
287 v
= APICRead(APIC_SIVR
);
288 DbgPrint("... SIVR : %08x\n", v
);
292 DbgPrint("... ISR field:\n");
293 APICDumpBit(APIC_ISR
);
294 DbgPrint("... TMR field:\n");
295 APICDumpBit(APIC_TMR
);
296 DbgPrint("... IRR field:\n");
297 APICDumpBit(APIC_IRR
);
300 if (APIC_INTEGRATED(ver
))
305 /* Due to the Pentium erratum 3AP. */
306 APICWrite(APIC_ESR
, 0);
308 v
= APICRead(APIC_ESR
);
309 DbgPrint("... ESR : %08x\n", v
);
312 v
= APICRead(APIC_ICR0
);
313 DbgPrint("... ICR0 : %08x ! ", v
);
314 v
= APICRead(APIC_ICR1
);
315 DbgPrint("... ICR1 : %08x ! ", v
);
317 v
= APICRead(APIC_LVTT
);
318 DbgPrint("... LVTT : %08x\n", v
);
323 v
= APICRead(APIC_LVTPC
);
324 DbgPrint("... LVTPC : %08x ! ", v
);
326 v
= APICRead(APIC_LINT0
);
327 DbgPrint("... LINT0 : %08x ! ", v
);
328 v
= APICRead(APIC_LINT1
);
329 DbgPrint("... LINT1 : %08x\n", v
);
333 v
= APICRead(APIC_LVT3
);
334 DbgPrint("... LVT3 : %08x\n", v
);
337 v
= APICRead(APIC_ICRT
);
338 DbgPrint("... ICRT : %08x ! ", v
);
339 v
= APICRead(APIC_CCRT
);
340 DbgPrint("... CCCT : %08x ! ", v
);
341 v
= APICRead(APIC_TDCR
);
342 DbgPrint("... TDCR : %08x\n", v
);
344 DbgPrint("Last register read (offset): 0x%08X\n", r1
);
345 DbgPrint("Last register read (value): 0x%08X\n", r2
);
346 DbgPrint("Last register written (offset): 0x%08X\n", w1
);
347 DbgPrint("Last register written (value): 0x%08X\n", w2
);
351 BOOLEAN
VerifyLocalAPIC(VOID
)
354 LARGE_INTEGER MsrValue
;
356 /* The version register is read-only in a real APIC */
357 reg0
= APICRead(APIC_VER
);
358 DPRINT1("Getting VERSION: %x\n", reg0
);
359 APICWrite(APIC_VER
, reg0
^ APIC_VER_MASK
);
360 reg1
= APICRead(APIC_VER
);
361 DPRINT1("Getting VERSION: %x\n", reg1
);
364 * The two version reads above should print the same
365 * numbers. If the second one is different, then we
366 * poke at a non-APIC.
375 * Check if the version looks reasonably.
377 reg1
= GET_APIC_VERSION(reg0
);
378 if (reg1
== 0x00 || reg1
== 0xff)
382 reg1
= APICGetMaxLVT();
383 if (reg1
< 0x02 || reg1
== 0xff)
389 * The ID register is read/write in a real APIC.
391 reg0
= APICRead(APIC_ID
);
392 DPRINT1("Getting ID: %x\n", reg0
);
393 APICWrite(APIC_ID
, reg0
^ APIC_ID_MASK
);
394 reg1
= APICRead(APIC_ID
);
395 DPRINT1("Getting ID: %x\n", reg1
);
396 APICWrite(APIC_ID
, reg0
);
397 if (reg1
!= (reg0
^ APIC_ID_MASK
))
402 MsrValue
.QuadPart
= __readmsr(0x1B /*MSR_IA32_APICBASE*/);
404 if (!(MsrValue
.LowPart
& /*MSR_IA32_APICBASE_ENABLE*/(1<<11)))
406 DPRINT1("Local APIC disabled by BIOS -- reenabling.\n");
407 MsrValue
.LowPart
&= ~/*MSR_IA32_APICBASE_BASE*/(1<<11);
408 MsrValue
.LowPart
|= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000;
409 __writemsr(0x1B /*MSR_IA32_APICBASE*/, MsrValue
.HighPart
);
418 VOID
APICSendIPI(ULONG Target
, ULONG Mode
)
422 /* save flags and disable interrupts */
423 flags
= __readeflags();
426 /* Wait up to 100ms for the APIC to become ready */
427 for (i
= 0; i
< 10000; i
++)
429 tmp
= APICRead(APIC_ICR0
);
430 /* Check Delivery Status */
431 if ((tmp
& APIC_ICR0_DS
) == 0)
433 KeStallExecutionProcessor(10);
438 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
441 /* Setup the APIC to deliver the IPI */
442 DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target
), Target
);
443 APICWrite(APIC_ICR1
, SET_APIC_DEST_FIELD(Target
));
445 if (Target
== APIC_TARGET_SELF
)
447 Mode
|= APIC_ICR0_DESTS_SELF
;
449 else if (Target
== APIC_TARGET_ALL
)
451 Mode
|= APIC_ICR0_DESTS_ALL
;
453 else if (Target
== APIC_TARGET_ALL_BUT_SELF
)
455 Mode
|= APIC_ICR0_DESTS_ALL_BUT_SELF
;
459 Mode
|= APIC_ICR0_DESTS_FIELD
;
462 /* Now, fire off the IPI */
463 APICWrite(APIC_ICR0
, Mode
);
465 /* Wait up to 100ms for the APIC to become ready */
466 for (i
= 0; i
< 10000; i
++)
468 tmp
= APICRead(APIC_ICR0
);
469 /* Check Delivery Status */
470 if ((tmp
& APIC_ICR0_DS
) == 0)
472 KeStallExecutionProcessor(10);
477 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
479 __writeeflags(flags
);
491 DPRINT1("CPU%d:\n", CPU
);
492 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
493 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
494 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
497 * Intel recommends to set DFR, LDR and TPR before enabling
498 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
499 * document number 292116). So here it goes...
503 * Put the APIC into flat delivery mode.
504 * Must be "all ones" explicitly for 82489DX.
506 APICWrite(APIC_DFR
, 0xFFFFFFFF);
509 * Set up the logical destination ID.
511 tmp
= APICRead(APIC_LDR
);
512 tmp
&= ~APIC_LDR_MASK
;
515 * This works only up to 8 CPU's
517 tmp
|= (1 << (KeGetCurrentProcessorNumber() + 24));
518 APICWrite(APIC_LDR
, tmp
);
521 DPRINT1("CPU%d:\n", CPU
);
522 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
523 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
524 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
525 DPRINT1("%d\n", CPUMap
[CPU
].APICId
);
527 /* Accept only higher interrupts */
528 APICWrite(APIC_TPR
, 0xef);
530 /* Enable local APIC */
531 tmp
= APICRead(APIC_SIVR
);
533 tmp
|= APIC_SIVR_ENABLE
;
536 tmp
&= ~APIC_SIVR_FOCUS
;
538 tmp
|= APIC_SIVR_FOCUS
;
541 /* Set spurious interrupt vector */
542 tmp
|= SPURIOUS_VECTOR
;
543 APICWrite(APIC_SIVR
, tmp
);
548 * set up through-local-APIC on the BP's LINT0. This is not
549 * strictly necessery in pure symmetric-IO mode, but sometimes
550 * we delegate interrupts to the 8259A.
552 tmp
= APICRead(APIC_LINT0
) & APIC_LVT_MASKED
;
553 if (CPU
== BootCPU
&& (APICMode
== amPIC
|| !tmp
))
555 tmp
= APIC_DM_EXTINT
;
556 DPRINT1("enabled ExtINT on CPU#%d\n", CPU
);
560 tmp
= APIC_DM_EXTINT
| APIC_LVT_MASKED
;
561 DPRINT1("masked ExtINT on CPU#%d\n", CPU
);
563 APICWrite(APIC_LINT0
, tmp
);
566 * Only the BSP should see the LINT1 NMI signal, obviously.
574 tmp
= APIC_DM_NMI
| APIC_LVT_MASKED
;
576 if (!APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
579 tmp
|= APIC_LVT_LEVEL_TRIGGER
;
581 APICWrite(APIC_LINT1
, tmp
);
583 if (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
586 if (APICGetMaxLVT() > 3)
588 /* Due to the Pentium erratum 3AP */
589 APICWrite(APIC_ESR
, 0);
592 tmp
= APICRead(APIC_ESR
);
593 DPRINT("ESR value before enabling vector: 0x%X\n", tmp
);
595 /* Enable sending errors */
597 APICWrite(APIC_LVT3
, tmp
);
600 * Spec says clear errors after enabling vector
602 if (APICGetMaxLVT() > 3)
604 APICWrite(APIC_ESR
, 0);
606 tmp
= APICRead(APIC_ESR
);
607 DPRINT("ESR value after enabling vector: 0x%X\n", tmp
);
611 VOID
APICSyncArbIDs(VOID
)
615 /* Wait up to 100ms for the APIC to become ready */
616 for (i
= 0; i
< 10000; i
++)
618 tmp
= APICRead(APIC_ICR0
);
619 /* Check Delivery Status */
620 if ((tmp
& APIC_ICR0_DS
) == 0)
622 KeStallExecutionProcessor(10);
627 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
630 DPRINT("Synchronizing Arb IDs.\n");
631 APICWrite(APIC_ICR0
, APIC_ICR0_DESTS_ALL
| APIC_ICR0_LEVEL
| APIC_DM_INIT
);
635 VOID
MpsErrorHandler(VOID
)
641 tmp1
= APICRead(APIC_ESR
);
642 APICWrite(APIC_ESR
, 0);
643 tmp2
= APICRead(APIC_ESR
);
644 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
647 * Acknowledge the interrupt
651 /* Here is what the APIC error bits mean:
653 * 1: Receive CS error
654 * 2: Send accept error
655 * 3: Receive accept error
657 * 5: Send illegal vector
658 * 6: Received illegal vector
659 * 7: Illegal register address
661 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
665 VOID
MpsSpuriousHandler(VOID
)
669 DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU());
671 tmp
= APICRead(APIC_ISR
+ ((SPURIOUS_VECTOR
& ~0x1f) >> 1));
672 if (tmp
& (1 << (SPURIOUS_VECTOR
& 0x1f)))
678 /* No need to send EOI here */
684 VOID
MpsIpiHandler(VOID
)
688 HalBeginSystemInterrupt(IPI_LEVEL
,
693 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n",
694 __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
697 KiIpiServiceRoutine(NULL
, NULL
);
700 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber());
704 HalEndSystemInterrupt(oldIrql
, 0);
709 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
710 PKTRAP_FRAME TrapFrame
)
715 TrapFrame
->SegGs
= (USHORT
)IrqTrapFrame
->Gs
;
716 TrapFrame
->SegFs
= (USHORT
)IrqTrapFrame
->Fs
;
717 TrapFrame
->SegEs
= (USHORT
)IrqTrapFrame
->Es
;
718 TrapFrame
->SegDs
= (USHORT
)IrqTrapFrame
->Ds
;
719 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
720 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
721 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
722 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
723 TrapFrame
->HardwareEsp
= IrqTrapFrame
->Esp
;
724 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
725 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
726 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
727 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
728 TrapFrame
->SegCs
= IrqTrapFrame
->Cs
;
729 TrapFrame
->EFlags
= IrqTrapFrame
->Eflags
;
734 MpsTimerHandler(ULONG Vector
, PKIRQ_TRAPFRAME Trapframe
)
737 KTRAP_FRAME KernelTrapFrame
;
740 static ULONG Count
[MAX_CPU
] = {0,};
742 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR
,
749 if ((Count
[CPU
] % 100) == 0)
751 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__
, __LINE__
, CPU
, oldIrql
,Trapframe
->Eip
, KeGetPcr());
756 /* FIXME: SMP is totally broken */
757 MpsIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
758 if (KeGetCurrentProcessorNumber() == 0)
760 //KeUpdateSystemTime(&KernelTrapFrame, oldIrql);
764 //KeUpdateRunTime(&KernelTrapFrame, oldIrql);
768 HalEndSystemInterrupt (oldIrql
, 0);
771 VOID
APICSetupLVTT(ULONG ClockTicks
)
775 tmp
= GET_APIC_VERSION(APICRead(APIC_VER
));
776 if (!APIC_INTEGRATED(tmp
))
778 tmp
= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV
) | APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;
783 tmp
= APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;
785 APICWrite(APIC_LVTT
, tmp
);
787 tmp
= APICRead(APIC_TDCR
);
788 tmp
&= ~(APIC_TDCR_1
| APIC_TIMER_BASE_DIV
);
790 APICWrite(APIC_TDCR
, tmp
);
791 APICWrite(APIC_ICRT
, ClockTicks
/ APIC_DIVISOR
);
795 APICCalibrateTimer(ULONG CPU
)
797 ULARGE_INTEGER t1
, t2
;
801 DPRINT("Calibrating APIC timer for CPU %d\n", CPU
);
803 APICSetupLVTT(1000000000);
805 TSCPresent
= KeGetCurrentPrcb()->FeatureBits
& KF_RDTSC
? TRUE
: FALSE
;
808 * The timer chip counts down to zero. Let's wait
809 * for a wraparound to start exact measurement:
810 * (the current tick might have been already half done)
812 //WaitFor8254Wraparound();
815 * We wrapped around just now. Let's start
819 t1
.QuadPart
= (LONGLONG
)__rdtsc();
821 tt1
= APICRead(APIC_CCRT
);
823 //WaitFor8254Wraparound();
826 tt2
= APICRead(APIC_CCRT
);
829 t2
.QuadPart
= (LONGLONG
)__rdtsc();
830 CPUMap
[CPU
].CoreSpeed
= (HZ
* (ULONG
)(t2
.QuadPart
- t1
.QuadPart
));
831 DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
832 CPUMap
[CPU
].CoreSpeed
/1000000,
833 CPUMap
[CPU
].CoreSpeed
%1000000);
834 KeGetCurrentPrcb()->MHz
= CPUMap
[CPU
].CoreSpeed
/1000000;
837 CPUMap
[CPU
].BusSpeed
= (HZ
* (long)(tt1
- tt2
) * APIC_DIVISOR
);
839 /* Setup timer for normal operation */
840 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
841 APICSetupLVTT((CPUMap
[CPU
].BusSpeed
/ 1000000) * 10000); // 10ms
842 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
844 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
845 CPUMap
[CPU
].BusSpeed
/1000000,
846 CPUMap
[CPU
].BusSpeed
%1000000);
850 SetInterruptGate(ULONG index
, ULONG_PTR address
)
855 idt
= &KeGetPcr()->IdtBase
[index
];
857 idt
->OffsetLow
= address
& 0xffff;
858 idt
->Selector
= KGDT_64_R0_CODE
;
864 idt
->OffsetMiddle
= (address
>> 16) & 0xffff;
865 idt
->OffsetHigh
= address
>> 32;
872 /* Set the IDT Access Bits */
875 Access
.Dpl
= 0; /* Kernel-Mode */
876 Access
.SystemSegmentFlag
= 0;
877 Access
.SegmentType
= I386_INTERRUPT_GATE
;
879 idt
= (KIDTENTRY
*)((ULONG
)KeGetPcr()->IDT
+ index
* sizeof(KIDTENTRY
));
880 idt
->Offset
= (USHORT
)(address
& 0xffff);
881 idt
->Selector
= KGDT_R0_CODE
;
882 idt
->Access
= Access
.Value
;
883 idt
->ExtendedOffset
= (USHORT
)(address
>> 16);
887 VOID
HaliInitBSP(VOID
)
893 static BOOLEAN BSPInitialized
= FALSE
;
895 /* Only initialize the BSP once */
902 BSPInitialized
= TRUE
;
904 /* Setup interrupt handlers */
905 SetInterruptGate(LOCAL_TIMER_VECTOR
, (ULONG_PTR
)MpsTimerInterrupt
);
906 SetInterruptGate(ERROR_VECTOR
, (ULONG_PTR
)MpsErrorInterrupt
);
907 SetInterruptGate(SPURIOUS_VECTOR
, (ULONG_PTR
)MpsSpuriousInterrupt
);
909 SetInterruptGate(IPI_VECTOR
, (ULONG_PTR
)MpsIpiInterrupt
);
911 DPRINT1("APIC is mapped at 0x%p\n", (PVOID
)APICBase
);
913 if (VerifyLocalAPIC())
915 DPRINT("APIC found\n");
919 DPRINT1("No APIC found\n");
923 if (APICMode
== amPIC
)
931 /* BIOS data segment */
932 BIOSBase
= (PULONG
)BIOS_AREA
;
934 /* Area for communicating with the APs */
935 CommonBase
= (PULONG
)COMMON_AREA
;
937 /* Copy bootstrap code to common area */
938 memcpy((PVOID
)((ULONG_PTR
)CommonBase
+ PAGE_SIZE
),
940 (ULONG_PTR
)&APend
- (ULONG_PTR
)&APstart
+ 1);
942 /* Set shutdown code */
943 CMOS_WRITE(0xF, 0xA);
945 /* Set warm reset vector */
946 ps
= (PUSHORT
)((ULONG_PTR
)BIOSBase
+ 0x467);
947 *ps
= (COMMON_AREA
+ PAGE_SIZE
) & 0xF;
949 ps
= (PUSHORT
)((ULONG_PTR
)BIOSBase
+ 0x469);
950 *ps
= (COMMON_AREA
+ PAGE_SIZE
) >> 4;
953 /* Calibrate APIC timer */
954 APICCalibrateTimer(BootCPU
);
959 HaliStartApplicationProcessor(ULONG Cpu
, ULONG Stack
)
962 PCOMMON_AREA_INFO Common
;
965 ULONG DeliveryStatus
= 0;
966 ULONG AcceptStatus
= 0;
968 if (Cpu
>= MAX_CPU
||
970 OnlineCPUs
& (1 << Cpu
))
974 DPRINT1("Attempting to boot CPU %d\n", Cpu
);
978 APICSendIPI(Cpu
, APIC_DM_INIT
|APIC_ICR0_LEVEL_ASSERT
);
980 KeStallExecutionProcessor(200);
984 APICSendIPI(Cpu
, APIC_DM_INIT
|APIC_ICR0_LEVEL_DEASSERT
);
986 if (APIC_INTEGRATED(CPUMap
[Cpu
].APICVersion
))
988 /* Clear APIC errors */
989 APICWrite(APIC_ESR
, 0);
990 tmp
= (APICRead(APIC_ESR
) & APIC_ESR_MASK
);
993 Common
= (PCOMMON_AREA_INFO
)CommonBase
;
995 /* Write the location of the AP stack */
996 Common
->Stack
= (ULONG
)Stack
;
997 /* Write the page directory page */
998 Common
->PageDirectory
= __readcr3();
999 /* Write the kernel entry point */
1000 Common
->NtProcessStartup
= (ULONG_PTR
)RtlImageNtHeader((PVOID
)KernelBase
)->OptionalHeader
.AddressOfEntryPoint
+ KernelBase
;
1001 /* Write the state of the mae mode */
1002 Common
->PaeModeEnabled
= __readcr4() & CR4_PAE
? 1 : 0;
1004 DPRINT1("%x %x %x %x\n", Common
->Stack
, Common
->PageDirectory
, Common
->NtProcessStartup
, Common
->PaeModeEnabled
);
1006 DPRINT("Cpu %d got stack at 0x%X\n", Cpu
, Common
->Stack
);
1008 for (j
= 0; j
< 16; j
++)
1010 Common
->Debug
[j
] = 0;
1014 maxlvt
= APICGetMaxLVT();
1016 /* Is this a local APIC or an 82489DX? */
1017 StartupCount
= (APIC_INTEGRATED(CPUMap
[Cpu
].APICVersion
)) ? 2 : 0;
1019 for (i
= 1; i
<= StartupCount
; i
++)
1021 /* It's a local APIC, so send STARTUP IPI */
1022 DPRINT("Sending startup signal %d\n", i
);
1024 APICWrite(APIC_ESR
, 0);
1027 APICSendIPI(Cpu
, APIC_DM_STARTUP
| ((COMMON_AREA
+ PAGE_SIZE
) >> 12)|APIC_ICR0_LEVEL_DEASSERT
);
1029 /* Wait up to 10ms for IPI to be delivered */
1033 KeStallExecutionProcessor(10);
1035 /* Check Delivery Status */
1036 DeliveryStatus
= APICRead(APIC_ICR0
) & APIC_ICR0_DS
;
1039 } while ((DeliveryStatus
) && (j
< 1000));
1041 KeStallExecutionProcessor(200);
1044 * Due to the Pentium erratum 3AP.
1048 APICRead(APIC_SIVR
);
1049 APICWrite(APIC_ESR
, 0);
1052 AcceptStatus
= APICRead(APIC_ESR
) & APIC_ESR_MASK
;
1054 if (DeliveryStatus
|| AcceptStatus
)
1062 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu
);
1067 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu
);
1070 if (!(DeliveryStatus
|| AcceptStatus
))
1073 /* Wait no more than 5 seconds for processor to boot */
1074 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu
);
1076 /* Wait no more than 5 seconds */
1077 for (j
= 0; j
< 50000; j
++)
1079 if (CPUMap
[Cpu
].Flags
& CPU_ENABLED
)
1083 KeStallExecutionProcessor(100);
1087 if (CPUMap
[Cpu
].Flags
& CPU_ENABLED
)
1089 DbgPrint("CPU %d is now running\n", Cpu
);
1093 DbgPrint("Initialization of CPU %d failed\n", Cpu
);
1097 DPRINT("Debug bytes are:\n");
1099 for (j
= 0; j
< 4; j
++)
1101 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1102 Common
->Debug
[j
*4+0],
1103 Common
->Debug
[j
*4+1],
1104 Common
->Debug
[j
*4+2],
1105 Common
->Debug
[j
*4+3]);