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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: hal/halx86/mp/apic.c
27 /* INCLUDE ***********************************************************************/
30 #include <halfuncs.h> /* Not in PCH because only used for MP HAL */
31 #include <rtlfuncs.h> /* Not in PCH because only used for MP HAL */
35 /* GLOBALS ***********************************************************************/
37 ULONG CPUCount
; /* Total number of CPUs */
38 ULONG BootCPU
; /* Bootstrap processor */
39 ULONG OnlineCPUs
; /* Bitmask of online CPUs */
40 CPU_INFO CPUMap
[MAX_CPU
]; /* Map of all CPUs in the system */
43 PULONG BIOSBase
; /* Virtual address of BIOS data segment */
44 PULONG CommonBase
; /* Virtual address of common area */
47 PULONG APICBase
= (PULONG
)APIC_DEFAULT_BASE
; /* Virtual address of local APIC */
49 ULONG APICMode
; /* APIC mode at startup */
52 ULONG lastregr
[MAX_CPU
];
53 ULONG lastvalr
[MAX_CPU
];
54 ULONG lastregw
[MAX_CPU
];
55 ULONG lastvalw
[MAX_CPU
];
59 typedef struct _COMMON_AREA_INFO
61 ULONG Stack
; /* Location of AP stack */
62 ULONG PageDirectory
; /* Page directory for an AP */
63 ULONG NtProcessStartup
; /* Kernel entry point for an AP */
64 ULONG PaeModeEnabled
; /* PAE mode is enabled */
65 ULONG Debug
[16]; /* For debugging */
66 } COMMON_AREA_INFO
, *PCOMMON_AREA_INFO
;
70 extern CHAR
*APstart
, *APend
;
73 #define COMMON_AREA 0x2000
76 #define APIC_DIVISOR (16)
78 #define CMOS_READ(address) { \
79 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
80 READ_PORT_UCHAR((PUCHAR)0x71)); \
83 #define CMOS_WRITE(address, value) { \
84 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
85 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
88 extern ULONG_PTR KernelBase
;
90 /* FUNCTIONS *********************************************************************/
92 extern ULONG
Read8254Timer(VOID
);
93 extern VOID
WaitFor8254Wraparound(VOID
);
94 extern VOID
MpsTimerInterrupt(VOID
);
95 extern VOID
MpsErrorInterrupt(VOID
);
96 extern VOID
MpsSpuriousInterrupt(VOID
);
97 extern VOID
MpsIpiInterrupt(VOID
);
99 ULONG
APICGetMaxLVT(VOID
)
101 ULONG tmp
, ver
, maxlvt
;
103 tmp
= APICRead(APIC_VER
);
104 ver
= GET_APIC_VERSION(tmp
);
105 /* 82489DXs do not report # of LVT entries. */
106 maxlvt
= APIC_INTEGRATED(ver
) ? GET_APIC_MAXLVT(tmp
) : 2;
115 maxlvt
= APICGetMaxLVT();
118 * Careful: we have to set masks only first to deassert
119 * any level-triggered sources.
125 APICWrite(APIC_LVT3
, tmp
| APIC_LVT3_MASKED
);
128 tmp
= APICRead(APIC_LVTT
);
129 APICWrite(APIC_LVTT
, tmp
| APIC_LVT_MASKED
);
131 tmp
= APICRead(APIC_LINT0
);
132 APICWrite(APIC_LINT0
, tmp
| APIC_LVT_MASKED
);
134 tmp
= APICRead(APIC_LINT1
);
135 APICWrite(APIC_LINT1
, tmp
| APIC_LVT_MASKED
);
139 tmp
= APICRead(APIC_LVTPC
);
140 APICWrite(APIC_LVTPC
, tmp
| APIC_LVT_MASKED
);
145 tmp
= APICRead(APIC_LVTTHMR
);
146 APICWrite(APIC_LVTTHMR
, tmp
| APIC_LVT_MASKED
);
150 * Clean APIC state for other OSs:
152 APICWrite(APIC_LVTT
, APIC_LVT_MASKED
);
153 APICWrite(APIC_LINT0
, APIC_LVT_MASKED
);
154 APICWrite(APIC_LINT1
, APIC_LVT_MASKED
);
158 APICWrite(APIC_LVT3
, APIC_LVT3_MASKED
);
163 APICWrite(APIC_LVTPC
, APIC_LVT_MASKED
);
168 APICWrite(APIC_LVTTHMR
, APIC_LVT_MASKED
);
173 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */
174 VOID
EnableApicMode(VOID
)
177 * Do not trust the local APIC being empty at bootup.
181 WRITE_PORT_UCHAR((PUCHAR
)0x22, 0x70);
182 WRITE_PORT_UCHAR((PUCHAR
)0x23, 0x01);
185 /* Disable symetric I/O mode ie. go to PIC mode */
186 __inline VOID
DisableSMPMode(VOID
)
189 * Put the board back into PIC mode (has an effect
190 * only on certain older boards). Note that APIC
191 * interrupts, including IPIs, won't work beyond
192 * this point! The only exception are INIT IPIs.
194 WRITE_PORT_UCHAR((PUCHAR
)0x22, 0x70);
195 WRITE_PORT_UCHAR((PUCHAR
)0x23, 0x00);
202 if (APICGetMaxLVT() > 3)
204 APICWrite(APIC_ESR
, 0);
206 tmp
= APICRead(APIC_ESR
);
207 DbgPrint("ESR %08x\n", tmp
);
211 VOID
APICDisable(VOID
)
218 * Disable APIC (implies clearing of registers for 82489DX!).
220 tmp
= APICRead(APIC_SIVR
);
221 tmp
&= ~APIC_SIVR_ENABLE
;
222 APICWrite(APIC_SIVR
, tmp
);
225 static VOID
APICDumpBit(ULONG base
)
229 DbgPrint("0123456789abcdef0123456789abcdef\n");
230 for (i
= 0; i
< 8; i
++)
232 v
= APICRead(base
+ i
*0x10);
233 for (j
= 0; j
< 32; j
++)
247 * Dump the contents of the local APIC registers
250 ULONG v
, ver
, maxlvt
;
251 ULONG r1
, r2
, w1
, w2
;
252 ULONG CPU
= ThisCPU();
260 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
261 v
= APICRead(APIC_ID
);
262 DbgPrint("... ID : %08x (%01x) ", v
, GET_APIC_ID(v
));
263 v
= APICRead(APIC_VER
);
264 DbgPrint("... VERSION: %08x\n", v
);
265 ver
= GET_APIC_VERSION(v
);
266 maxlvt
= APICGetMaxLVT();
268 v
= APICRead(APIC_TPR
);
269 DbgPrint("... TPR : %08x (%02x)", v
, v
& ~0);
271 if (APIC_INTEGRATED(ver
))
274 v
= APICRead(APIC_APR
);
275 DbgPrint("... APR : %08x (%02x)\n", v
, v
& ~0);
276 v
= APICRead(APIC_PPR
);
277 DbgPrint("... PPR : %08x\n", v
);
280 v
= APICRead(APIC_EOI
);
281 DbgPrint("... EOI : %08x ! ", v
);
282 v
= APICRead(APIC_LDR
);
283 DbgPrint("... LDR : %08x\n", v
);
284 v
= APICRead(APIC_DFR
);
285 DbgPrint("... DFR : %08x ! ", v
);
286 v
= APICRead(APIC_SIVR
);
287 DbgPrint("... SIVR : %08x\n", v
);
291 DbgPrint("... ISR field:\n");
292 APICDumpBit(APIC_ISR
);
293 DbgPrint("... TMR field:\n");
294 APICDumpBit(APIC_TMR
);
295 DbgPrint("... IRR field:\n");
296 APICDumpBit(APIC_IRR
);
299 if (APIC_INTEGRATED(ver
))
304 /* Due to the Pentium erratum 3AP. */
305 APICWrite(APIC_ESR
, 0);
307 v
= APICRead(APIC_ESR
);
308 DbgPrint("... ESR : %08x\n", v
);
311 v
= APICRead(APIC_ICR0
);
312 DbgPrint("... ICR0 : %08x ! ", v
);
313 v
= APICRead(APIC_ICR1
);
314 DbgPrint("... ICR1 : %08x ! ", v
);
316 v
= APICRead(APIC_LVTT
);
317 DbgPrint("... LVTT : %08x\n", v
);
322 v
= APICRead(APIC_LVTPC
);
323 DbgPrint("... LVTPC : %08x ! ", v
);
325 v
= APICRead(APIC_LINT0
);
326 DbgPrint("... LINT0 : %08x ! ", v
);
327 v
= APICRead(APIC_LINT1
);
328 DbgPrint("... LINT1 : %08x\n", v
);
332 v
= APICRead(APIC_LVT3
);
333 DbgPrint("... LVT3 : %08x\n", v
);
336 v
= APICRead(APIC_ICRT
);
337 DbgPrint("... ICRT : %08x ! ", v
);
338 v
= APICRead(APIC_CCRT
);
339 DbgPrint("... CCCT : %08x ! ", v
);
340 v
= APICRead(APIC_TDCR
);
341 DbgPrint("... TDCR : %08x\n", v
);
343 DbgPrint("Last register read (offset): 0x%08X\n", r1
);
344 DbgPrint("Last register read (value): 0x%08X\n", r2
);
345 DbgPrint("Last register written (offset): 0x%08X\n", w1
);
346 DbgPrint("Last register written (value): 0x%08X\n", w2
);
350 BOOLEAN
VerifyLocalAPIC(VOID
)
353 LARGE_INTEGER MsrValue
;
355 /* The version register is read-only in a real APIC */
356 reg0
= APICRead(APIC_VER
);
357 DPRINT1("Getting VERSION: %x\n", reg0
);
358 APICWrite(APIC_VER
, reg0
^ APIC_VER_MASK
);
359 reg1
= APICRead(APIC_VER
);
360 DPRINT1("Getting VERSION: %x\n", reg1
);
363 * The two version reads above should print the same
364 * numbers. If the second one is different, then we
365 * poke at a non-APIC.
374 * Check if the version looks reasonably.
376 reg1
= GET_APIC_VERSION(reg0
);
377 if (reg1
== 0x00 || reg1
== 0xff)
381 reg1
= APICGetMaxLVT();
382 if (reg1
< 0x02 || reg1
== 0xff)
388 * The ID register is read/write in a real APIC.
390 reg0
= APICRead(APIC_ID
);
391 DPRINT1("Getting ID: %x\n", reg0
);
392 APICWrite(APIC_ID
, reg0
^ APIC_ID_MASK
);
393 reg1
= APICRead(APIC_ID
);
394 DPRINT1("Getting ID: %x\n", reg1
);
395 APICWrite(APIC_ID
, reg0
);
396 if (reg1
!= (reg0
^ APIC_ID_MASK
))
401 MsrValue
.QuadPart
= __readmsr(0x1B /*MSR_IA32_APICBASE*/);
403 if (!(MsrValue
.LowPart
& /*MSR_IA32_APICBASE_ENABLE*/(1<<11)))
405 DPRINT1("Local APIC disabled by BIOS -- reenabling.\n");
406 MsrValue
.LowPart
&= ~/*MSR_IA32_APICBASE_BASE*/(1<<11);
407 MsrValue
.LowPart
|= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000;
408 __writemsr(0x1B /*MSR_IA32_APICBASE*/, MsrValue
.HighPart
);
417 VOID
APICSendIPI(ULONG Target
, ULONG Mode
)
421 /* save flags and disable interrupts */
422 flags
= __readeflags();
425 /* Wait up to 100ms for the APIC to become ready */
426 for (i
= 0; i
< 10000; i
++)
428 tmp
= APICRead(APIC_ICR0
);
429 /* Check Delivery Status */
430 if ((tmp
& APIC_ICR0_DS
) == 0)
432 KeStallExecutionProcessor(10);
437 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
440 /* Setup the APIC to deliver the IPI */
441 DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target
), Target
);
442 APICWrite(APIC_ICR1
, SET_APIC_DEST_FIELD(Target
));
444 if (Target
== APIC_TARGET_SELF
)
446 Mode
|= APIC_ICR0_DESTS_SELF
;
448 else if (Target
== APIC_TARGET_ALL
)
450 Mode
|= APIC_ICR0_DESTS_ALL
;
452 else if (Target
== APIC_TARGET_ALL_BUT_SELF
)
454 Mode
|= APIC_ICR0_DESTS_ALL_BUT_SELF
;
458 Mode
|= APIC_ICR0_DESTS_FIELD
;
461 /* Now, fire off the IPI */
462 APICWrite(APIC_ICR0
, Mode
);
464 /* Wait up to 100ms for the APIC to become ready */
465 for (i
= 0; i
< 10000; i
++)
467 tmp
= APICRead(APIC_ICR0
);
468 /* Check Delivery Status */
469 if ((tmp
& APIC_ICR0_DS
) == 0)
471 KeStallExecutionProcessor(10);
476 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
478 __writeeflags(flags
);
490 DPRINT1("CPU%d:\n", CPU
);
491 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
492 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
493 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
496 * Intel recommends to set DFR, LDR and TPR before enabling
497 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
498 * document number 292116). So here it goes...
502 * Put the APIC into flat delivery mode.
503 * Must be "all ones" explicitly for 82489DX.
505 APICWrite(APIC_DFR
, 0xFFFFFFFF);
508 * Set up the logical destination ID.
510 tmp
= APICRead(APIC_LDR
);
511 tmp
&= ~APIC_LDR_MASK
;
514 * This works only up to 8 CPU's
516 tmp
|= (1 << (KeGetCurrentProcessorNumber() + 24));
517 APICWrite(APIC_LDR
, tmp
);
520 DPRINT1("CPU%d:\n", CPU
);
521 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
522 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
523 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
524 DPRINT1("%d\n", CPUMap
[CPU
].APICId
);
526 /* Accept only higher interrupts */
527 APICWrite(APIC_TPR
, 0xef);
529 /* Enable local APIC */
530 tmp
= APICRead(APIC_SIVR
);
532 tmp
|= APIC_SIVR_ENABLE
;
535 tmp
&= ~APIC_SIVR_FOCUS
;
537 tmp
|= APIC_SIVR_FOCUS
;
540 /* Set spurious interrupt vector */
541 tmp
|= SPURIOUS_VECTOR
;
542 APICWrite(APIC_SIVR
, tmp
);
547 * set up through-local-APIC on the BP's LINT0. This is not
548 * strictly necessery in pure symmetric-IO mode, but sometimes
549 * we delegate interrupts to the 8259A.
551 tmp
= APICRead(APIC_LINT0
) & APIC_LVT_MASKED
;
552 if (CPU
== BootCPU
&& (APICMode
== amPIC
|| !tmp
))
554 tmp
= APIC_DM_EXTINT
;
555 DPRINT1("enabled ExtINT on CPU#%d\n", CPU
);
559 tmp
= APIC_DM_EXTINT
| APIC_LVT_MASKED
;
560 DPRINT1("masked ExtINT on CPU#%d\n", CPU
);
562 APICWrite(APIC_LINT0
, tmp
);
565 * Only the BSP should see the LINT1 NMI signal, obviously.
573 tmp
= APIC_DM_NMI
| APIC_LVT_MASKED
;
575 if (!APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
578 tmp
|= APIC_LVT_LEVEL_TRIGGER
;
580 APICWrite(APIC_LINT1
, tmp
);
582 if (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
585 if (APICGetMaxLVT() > 3)
587 /* Due to the Pentium erratum 3AP */
588 APICWrite(APIC_ESR
, 0);
591 tmp
= APICRead(APIC_ESR
);
592 DPRINT("ESR value before enabling vector: 0x%X\n", tmp
);
594 /* Enable sending errors */
596 APICWrite(APIC_LVT3
, tmp
);
599 * Spec says clear errors after enabling vector
601 if (APICGetMaxLVT() > 3)
603 APICWrite(APIC_ESR
, 0);
605 tmp
= APICRead(APIC_ESR
);
606 DPRINT("ESR value after enabling vector: 0x%X\n", tmp
);
610 VOID
APICSyncArbIDs(VOID
)
614 /* Wait up to 100ms for the APIC to become ready */
615 for (i
= 0; i
< 10000; i
++)
617 tmp
= APICRead(APIC_ICR0
);
618 /* Check Delivery Status */
619 if ((tmp
& APIC_ICR0_DS
) == 0)
621 KeStallExecutionProcessor(10);
626 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
629 DPRINT("Synchronizing Arb IDs.\n");
630 APICWrite(APIC_ICR0
, APIC_ICR0_DESTS_ALL
| APIC_ICR0_LEVEL
| APIC_DM_INIT
);
634 VOID
MpsErrorHandler(VOID
)
640 tmp1
= APICRead(APIC_ESR
);
641 APICWrite(APIC_ESR
, 0);
642 tmp2
= APICRead(APIC_ESR
);
643 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
646 * Acknowledge the interrupt
650 /* Here is what the APIC error bits mean:
652 * 1: Receive CS error
653 * 2: Send accept error
654 * 3: Receive accept error
656 * 5: Send illegal vector
657 * 6: Received illegal vector
658 * 7: Illegal register address
660 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
664 VOID
MpsSpuriousHandler(VOID
)
668 DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU());
670 tmp
= APICRead(APIC_ISR
+ ((SPURIOUS_VECTOR
& ~0x1f) >> 1));
671 if (tmp
& (1 << (SPURIOUS_VECTOR
& 0x1f)))
677 /* No need to send EOI here */
683 VOID
MpsIpiHandler(VOID
)
687 HalBeginSystemInterrupt(IPI_LEVEL
,
692 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n",
693 __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
696 KiIpiServiceRoutine(NULL
, NULL
);
699 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber());
703 HalEndSystemInterrupt(oldIrql
, 0);
708 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
709 PKTRAP_FRAME TrapFrame
)
714 TrapFrame
->SegGs
= (USHORT
)IrqTrapFrame
->Gs
;
715 TrapFrame
->SegFs
= (USHORT
)IrqTrapFrame
->Fs
;
716 TrapFrame
->SegEs
= (USHORT
)IrqTrapFrame
->Es
;
717 TrapFrame
->SegDs
= (USHORT
)IrqTrapFrame
->Ds
;
718 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
719 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
720 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
721 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
722 TrapFrame
->HardwareEsp
= IrqTrapFrame
->Esp
;
723 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
724 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
725 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
726 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
727 TrapFrame
->SegCs
= IrqTrapFrame
->Cs
;
728 TrapFrame
->EFlags
= IrqTrapFrame
->Eflags
;
733 MpsTimerHandler(ULONG Vector
, PKIRQ_TRAPFRAME Trapframe
)
736 KTRAP_FRAME KernelTrapFrame
;
739 static ULONG Count
[MAX_CPU
] = {0,};
741 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR
,
748 if ((Count
[CPU
] % 100) == 0)
750 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__
, __LINE__
, CPU
, oldIrql
,Trapframe
->Eip
, KeGetPcr());
755 /* FIXME: SMP is totally broken */
756 MpsIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
757 if (KeGetCurrentProcessorNumber() == 0)
759 //KeUpdateSystemTime(&KernelTrapFrame, oldIrql);
763 //KeUpdateRunTime(&KernelTrapFrame, oldIrql);
767 HalEndSystemInterrupt (oldIrql
, 0);
770 VOID
APICSetupLVTT(ULONG ClockTicks
)
774 tmp
= GET_APIC_VERSION(APICRead(APIC_VER
));
775 if (!APIC_INTEGRATED(tmp
))
777 tmp
= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV
) | APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;
782 tmp
= APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;
784 APICWrite(APIC_LVTT
, tmp
);
786 tmp
= APICRead(APIC_TDCR
);
787 tmp
&= ~(APIC_TDCR_1
| APIC_TIMER_BASE_DIV
);
789 APICWrite(APIC_TDCR
, tmp
);
790 APICWrite(APIC_ICRT
, ClockTicks
/ APIC_DIVISOR
);
794 APICCalibrateTimer(ULONG CPU
)
796 ULARGE_INTEGER t1
, t2
;
800 DPRINT("Calibrating APIC timer for CPU %d\n", CPU
);
802 APICSetupLVTT(1000000000);
804 TSCPresent
= KeGetCurrentPrcb()->FeatureBits
& KF_RDTSC
? TRUE
: FALSE
;
807 * The timer chip counts down to zero. Let's wait
808 * for a wraparound to start exact measurement:
809 * (the current tick might have been already half done)
811 //WaitFor8254Wraparound();
814 * We wrapped around just now. Let's start
818 t1
.QuadPart
= (LONGLONG
)__rdtsc();
820 tt1
= APICRead(APIC_CCRT
);
822 //WaitFor8254Wraparound();
825 tt2
= APICRead(APIC_CCRT
);
828 t2
.QuadPart
= (LONGLONG
)__rdtsc();
829 CPUMap
[CPU
].CoreSpeed
= (HZ
* (ULONG
)(t2
.QuadPart
- t1
.QuadPart
));
830 DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
831 CPUMap
[CPU
].CoreSpeed
/1000000,
832 CPUMap
[CPU
].CoreSpeed
%1000000);
833 KeGetCurrentPrcb()->MHz
= CPUMap
[CPU
].CoreSpeed
/1000000;
836 CPUMap
[CPU
].BusSpeed
= (HZ
* (long)(tt1
- tt2
) * APIC_DIVISOR
);
838 /* Setup timer for normal operation */
839 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
840 APICSetupLVTT((CPUMap
[CPU
].BusSpeed
/ 1000000) * 10000); // 10ms
841 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
843 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
844 CPUMap
[CPU
].BusSpeed
/1000000,
845 CPUMap
[CPU
].BusSpeed
%1000000);
849 SetInterruptGate(ULONG index
, ULONG_PTR address
)
854 idt
= &KeGetPcr()->IdtBase
[index
];
856 idt
->OffsetLow
= address
& 0xffff;
857 idt
->Selector
= KGDT_64_R0_CODE
;
863 idt
->OffsetMiddle
= (address
>> 16) & 0xffff;
864 idt
->OffsetHigh
= address
>> 32;
871 /* Set the IDT Access Bits */
874 Access
.Dpl
= 0; /* Kernel-Mode */
875 Access
.SystemSegmentFlag
= 0;
876 Access
.SegmentType
= I386_INTERRUPT_GATE
;
878 idt
= (KIDTENTRY
*)((ULONG
)KeGetPcr()->IDT
+ index
* sizeof(KIDTENTRY
));
879 idt
->Offset
= (USHORT
)(address
& 0xffff);
880 idt
->Selector
= KGDT_R0_CODE
;
881 idt
->Access
= Access
.Value
;
882 idt
->ExtendedOffset
= (USHORT
)(address
>> 16);
886 VOID
HaliInitBSP(VOID
)
892 static BOOLEAN BSPInitialized
= FALSE
;
894 /* Only initialize the BSP once */
901 BSPInitialized
= TRUE
;
903 /* Setup interrupt handlers */
904 SetInterruptGate(LOCAL_TIMER_VECTOR
, (ULONG_PTR
)MpsTimerInterrupt
);
905 SetInterruptGate(ERROR_VECTOR
, (ULONG_PTR
)MpsErrorInterrupt
);
906 SetInterruptGate(SPURIOUS_VECTOR
, (ULONG_PTR
)MpsSpuriousInterrupt
);
908 SetInterruptGate(IPI_VECTOR
, (ULONG_PTR
)MpsIpiInterrupt
);
910 DPRINT("APIC is mapped at 0x%X\n", APICBase
);
912 if (VerifyLocalAPIC())
914 DPRINT("APIC found\n");
918 DPRINT("No APIC found\n");
922 if (APICMode
== amPIC
)
930 /* BIOS data segment */
931 BIOSBase
= (PULONG
)BIOS_AREA
;
933 /* Area for communicating with the APs */
934 CommonBase
= (PULONG
)COMMON_AREA
;
936 /* Copy bootstrap code to common area */
937 memcpy((PVOID
)((ULONG_PTR
)CommonBase
+ PAGE_SIZE
),
939 (ULONG_PTR
)&APend
- (ULONG_PTR
)&APstart
+ 1);
941 /* Set shutdown code */
942 CMOS_WRITE(0xF, 0xA);
944 /* Set warm reset vector */
945 ps
= (PUSHORT
)((ULONG_PTR
)BIOSBase
+ 0x467);
946 *ps
= (COMMON_AREA
+ PAGE_SIZE
) & 0xF;
948 ps
= (PUSHORT
)((ULONG_PTR
)BIOSBase
+ 0x469);
949 *ps
= (COMMON_AREA
+ PAGE_SIZE
) >> 4;
952 /* Calibrate APIC timer */
953 APICCalibrateTimer(BootCPU
);
958 HaliStartApplicationProcessor(ULONG Cpu
, ULONG Stack
)
961 PCOMMON_AREA_INFO Common
;
964 ULONG DeliveryStatus
= 0;
965 ULONG AcceptStatus
= 0;
967 if (Cpu
>= MAX_CPU
||
969 OnlineCPUs
& (1 << Cpu
))
973 DPRINT1("Attempting to boot CPU %d\n", Cpu
);
977 APICSendIPI(Cpu
, APIC_DM_INIT
|APIC_ICR0_LEVEL_ASSERT
);
979 KeStallExecutionProcessor(200);
983 APICSendIPI(Cpu
, APIC_DM_INIT
|APIC_ICR0_LEVEL_DEASSERT
);
985 if (APIC_INTEGRATED(CPUMap
[Cpu
].APICVersion
))
987 /* Clear APIC errors */
988 APICWrite(APIC_ESR
, 0);
989 tmp
= (APICRead(APIC_ESR
) & APIC_ESR_MASK
);
992 Common
= (PCOMMON_AREA_INFO
)CommonBase
;
994 /* Write the location of the AP stack */
995 Common
->Stack
= (ULONG
)Stack
;
996 /* Write the page directory page */
997 Common
->PageDirectory
= __readcr3();
998 /* Write the kernel entry point */
999 Common
->NtProcessStartup
= (ULONG_PTR
)RtlImageNtHeader((PVOID
)KernelBase
)->OptionalHeader
.AddressOfEntryPoint
+ KernelBase
;
1000 /* Write the state of the mae mode */
1001 Common
->PaeModeEnabled
= __readcr4() & CR4_PAE
? 1 : 0;
1003 DPRINT1("%x %x %x %x\n", Common
->Stack
, Common
->PageDirectory
, Common
->NtProcessStartup
, Common
->PaeModeEnabled
);
1005 DPRINT("Cpu %d got stack at 0x%X\n", Cpu
, Common
->Stack
);
1007 for (j
= 0; j
< 16; j
++)
1009 Common
->Debug
[j
] = 0;
1013 maxlvt
= APICGetMaxLVT();
1015 /* Is this a local APIC or an 82489DX? */
1016 StartupCount
= (APIC_INTEGRATED(CPUMap
[Cpu
].APICVersion
)) ? 2 : 0;
1018 for (i
= 1; i
<= StartupCount
; i
++)
1020 /* It's a local APIC, so send STARTUP IPI */
1021 DPRINT("Sending startup signal %d\n", i
);
1023 APICWrite(APIC_ESR
, 0);
1026 APICSendIPI(Cpu
, APIC_DM_STARTUP
| ((COMMON_AREA
+ PAGE_SIZE
) >> 12)|APIC_ICR0_LEVEL_DEASSERT
);
1028 /* Wait up to 10ms for IPI to be delivered */
1032 KeStallExecutionProcessor(10);
1034 /* Check Delivery Status */
1035 DeliveryStatus
= APICRead(APIC_ICR0
) & APIC_ICR0_DS
;
1038 } while ((DeliveryStatus
) && (j
< 1000));
1040 KeStallExecutionProcessor(200);
1043 * Due to the Pentium erratum 3AP.
1047 APICRead(APIC_SIVR
);
1048 APICWrite(APIC_ESR
, 0);
1051 AcceptStatus
= APICRead(APIC_ESR
) & APIC_ESR_MASK
;
1053 if (DeliveryStatus
|| AcceptStatus
)
1061 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu
);
1066 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu
);
1069 if (!(DeliveryStatus
|| AcceptStatus
))
1072 /* Wait no more than 5 seconds for processor to boot */
1073 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu
);
1075 /* Wait no more than 5 seconds */
1076 for (j
= 0; j
< 50000; j
++)
1078 if (CPUMap
[Cpu
].Flags
& CPU_ENABLED
)
1082 KeStallExecutionProcessor(100);
1086 if (CPUMap
[Cpu
].Flags
& CPU_ENABLED
)
1088 DbgPrint("CPU %d is now running\n", Cpu
);
1092 DbgPrint("Initialization of CPU %d failed\n", Cpu
);
1096 DPRINT("Debug bytes are:\n");
1098 for (j
= 0; j
< 4; j
++)
1100 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1101 Common
->Debug
[j
*4+0],
1102 Common
->Debug
[j
*4+1],
1103 Common
->Debug
[j
*4+2],
1104 Common
->Debug
[j
*4+3]);
1115 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
1117 /* Set up a fake INT Stack */
1118 TrapFrame
->EFlags
= __readeflags();
1119 TrapFrame
->SegCs
= KGDT_R0_CODE
;
1120 TrapFrame
->Eip
= TrapFrame
->Eax
;
1122 /* Build the trap frame */
1123 KiEnterInterruptTrap(TrapFrame
);
1128 /* Exit the interrupt */
1129 KiEoiHelper(TrapFrame
);