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 ***********************************************************************/
33 #include <internal/ntoskrnl.h>
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
];
58 typedef struct __attribute__((packed
)) _COMMON_AREA_INFO
60 ULONG Stack
; /* Location of AP stack */
61 ULONG PageDirectory
; /* Page directory for an AP */
62 ULONG NtProcessStartup
; /* Kernel entry point for an AP */
63 ULONG PaeModeEnabled
; /* PAE mode is enabled */
64 ULONG Debug
[16]; /* For debugging */
65 } COMMON_AREA_INFO
, *PCOMMON_AREA_INFO
;
68 CHAR
*APstart
, *APend
;
71 #define COMMON_AREA 0x2000
74 #define APIC_DIVISOR (16)
76 #define CMOS_READ(address) ({ \
77 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
78 READ_PORT_UCHAR((PUCHAR)0x71)); \
81 #define CMOS_WRITE(address, value) ({ \
82 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
83 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
86 /* FUNCTIONS *********************************************************************/
88 extern ULONG
Read8254Timer(VOID
);
89 extern VOID
WaitFor8254Wraparound(VOID
);
90 extern VOID
MpsTimerInterrupt(VOID
);
91 extern VOID
MpsErrorInterrupt(VOID
);
92 extern VOID
MpsSpuriousInterrupt(VOID
);
93 extern VOID
MpsIpiInterrupt(VOID
);
95 ULONG
APICGetMaxLVT(VOID
)
97 ULONG tmp
, ver
, maxlvt
;
99 tmp
= APICRead(APIC_VER
);
100 ver
= GET_APIC_VERSION(tmp
);
101 /* 82489DXs do not report # of LVT entries. */
102 maxlvt
= APIC_INTEGRATED(ver
) ? GET_APIC_MAXLVT(tmp
) : 2;
111 maxlvt
= APICGetMaxLVT();
114 * Careful: we have to set masks only first to deassert
115 * any level-triggered sources.
121 APICWrite(APIC_LVT3
, tmp
| APIC_LVT3_MASKED
);
124 tmp
= APICRead(APIC_LVTT
);
125 APICWrite(APIC_LVTT
, tmp
| APIC_LVT_MASKED
);
127 tmp
= APICRead(APIC_LINT0
);
128 APICWrite(APIC_LINT0
, tmp
| APIC_LVT_MASKED
);
130 tmp
= APICRead(APIC_LINT1
);
131 APICWrite(APIC_LINT1
, tmp
| APIC_LVT_MASKED
);
135 tmp
= APICRead(APIC_LVTPC
);
136 APICWrite(APIC_LVTPC
, tmp
| APIC_LVT_MASKED
);
141 tmp
= APICRead(APIC_LVTTHMR
);
142 APICWrite(APIC_LVTTHMR
, tmp
| APIC_LVT_MASKED
);
146 * Clean APIC state for other OSs:
148 APICWrite(APIC_LVTT
, APIC_LVT_MASKED
);
149 APICWrite(APIC_LINT0
, APIC_LVT_MASKED
);
150 APICWrite(APIC_LINT1
, APIC_LVT_MASKED
);
154 APICWrite(APIC_LVT3
, APIC_LVT3_MASKED
);
159 APICWrite(APIC_LVTPC
, APIC_LVT_MASKED
);
164 APICWrite(APIC_LVTTHMR
, APIC_LVT_MASKED
);
169 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */
170 VOID
EnableApicMode(VOID
)
173 * Do not trust the local APIC being empty at bootup.
177 WRITE_PORT_UCHAR((PUCHAR
)0x22, 0x70);
178 WRITE_PORT_UCHAR((PUCHAR
)0x23, 0x01);
181 /* Disable symetric I/O mode ie. go to PIC mode */
182 inline VOID
DisableSMPMode(VOID
)
185 * Put the board back into PIC mode (has an effect
186 * only on certain older boards). Note that APIC
187 * interrupts, including IPIs, won't work beyond
188 * this point! The only exception are INIT IPIs.
190 WRITE_PORT_UCHAR((PUCHAR
)0x22, 0x70);
191 WRITE_PORT_UCHAR((PUCHAR
)0x23, 0x00);
198 if (APICGetMaxLVT() > 3)
200 APICWrite(APIC_ESR
, 0);
202 tmp
= APICRead(APIC_ESR
);
203 DbgPrint("ESR %08x\n", tmp
);
207 VOID
APICDisable(VOID
)
214 * Disable APIC (implies clearing of registers for 82489DX!).
216 tmp
= APICRead(APIC_SIVR
);
217 tmp
&= ~APIC_SIVR_ENABLE
;
218 APICWrite(APIC_SIVR
, tmp
);
222 inline ULONG
_APICRead(ULONG Offset
)
226 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
231 inline VOID
APICWrite(ULONG Offset
,
236 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
241 inline VOID
APICWrite(ULONG Offset
,
245 ULONG CPU
= (_APICRead(APIC_ID
) & APIC_ID_MASK
) >> 24;
247 lastregw
[CPU
] = Offset
;
248 lastvalw
[CPU
] = Value
;
250 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
258 inline ULONG
APICRead(ULONG Offset
)
262 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
266 inline ULONG
APICRead(ULONG Offset
)
269 ULONG CPU
= (_APICRead(APIC_ID
) & APIC_ID_MASK
) >> 24;
271 lastregr
[CPU
] = Offset
;
274 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
277 return lastvalr
[CPU
];
281 inline VOID
APICSendEOI(VOID
)
284 APICWrite(APIC_EOI
, 0);
287 static VOID
APICDumpBit(ULONG base
)
291 DbgPrint("0123456789abcdef0123456789abcdef\n");
292 for (i
= 0; i
< 8; i
++)
294 v
= APICRead(base
+ i
*0x10);
295 for (j
= 0; j
< 32; j
++)
309 * Dump the contents of the local APIC registers
312 ULONG v
, ver
, maxlvt
;
313 ULONG r1
, r2
, w1
, w2
;
314 ULONG CPU
= ThisCPU();;
323 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
324 v
= APICRead(APIC_ID
);
325 DbgPrint("... ID : %08x (%01x) ", v
, GET_APIC_ID(v
));
326 v
= APICRead(APIC_VER
);
327 DbgPrint("... VERSION: %08x\n", v
);
328 ver
= GET_APIC_VERSION(v
);
329 maxlvt
= APICGetMaxLVT();
331 v
= APICRead(APIC_TPR
);
332 DbgPrint("... TPR : %08x (%02x)", v
, v
& ~0);
334 if (APIC_INTEGRATED(ver
))
337 v
= APICRead(APIC_APR
);
338 DbgPrint("... APR : %08x (%02x)\n", v
, v
& ~0);
339 v
= APICRead(APIC_PPR
);
340 DbgPrint("... PPR : %08x\n", v
);
343 v
= APICRead(APIC_EOI
);
344 DbgPrint("... EOI : %08x ! ", v
);
345 v
= APICRead(APIC_LDR
);
346 DbgPrint("... LDR : %08x\n", v
);
347 v
= APICRead(APIC_DFR
);
348 DbgPrint("... DFR : %08x ! ", v
);
349 v
= APICRead(APIC_SIVR
);
350 DbgPrint("... SIVR : %08x\n", v
);
354 DbgPrint("... ISR field:\n");
355 APICDumpBit(APIC_ISR
);
356 DbgPrint("... TMR field:\n");
357 APICDumpBit(APIC_TMR
);
358 DbgPrint("... IRR field:\n");
359 APICDumpBit(APIC_IRR
);
362 if (APIC_INTEGRATED(ver
))
367 /* Due to the Pentium erratum 3AP. */
368 APICWrite(APIC_ESR
, 0);
370 v
= APICRead(APIC_ESR
);
371 DbgPrint("... ESR : %08x\n", v
);
374 v
= APICRead(APIC_ICR0
);
375 DbgPrint("... ICR0 : %08x ! ", v
);
376 v
= APICRead(APIC_ICR1
);
377 DbgPrint("... ICR1 : %08x ! ", v
);
379 v
= APICRead(APIC_LVTT
);
380 DbgPrint("... LVTT : %08x\n", v
);
385 v
= APICRead(APIC_LVTPC
);
386 DbgPrint("... LVTPC : %08x ! ", v
);
388 v
= APICRead(APIC_LINT0
);
389 DbgPrint("... LINT0 : %08x ! ", v
);
390 v
= APICRead(APIC_LINT1
);
391 DbgPrint("... LINT1 : %08x\n", v
);
395 v
= APICRead(APIC_LVT3
);
396 DbgPrint("... LVT3 : %08x\n", v
);
399 v
= APICRead(APIC_ICRT
);
400 DbgPrint("... ICRT : %08x ! ", v
);
401 v
= APICRead(APIC_CCRT
);
402 DbgPrint("... CCCT : %08x ! ", v
);
403 v
= APICRead(APIC_TDCR
);
404 DbgPrint("... TDCR : %08x\n", v
);
406 DbgPrint("Last register read (offset): 0x%08X\n", r1
);
407 DbgPrint("Last register read (value): 0x%08X\n", r2
);
408 DbgPrint("Last register written (offset): 0x%08X\n", w1
);
409 DbgPrint("Last register written (value): 0x%08X\n", w2
);
413 BOOLEAN
VerifyLocalAPIC(VOID
)
416 /* The version register is read-only in a real APIC */
417 reg0
= APICRead(APIC_VER
);
418 DPRINT1("Getting VERSION: %x\n", reg0
);
419 APICWrite(APIC_VER
, reg0
^ APIC_VER_MASK
);
420 reg1
= APICRead(APIC_VER
);
421 DPRINT1("Getting VERSION: %x\n", reg1
);
424 * The two version reads above should print the same
425 * numbers. If the second one is different, then we
426 * poke at a non-APIC.
435 * Check if the version looks reasonably.
437 reg1
= GET_APIC_VERSION(reg0
);
438 if (reg1
== 0x00 || reg1
== 0xff)
442 reg1
= APICGetMaxLVT();
443 if (reg1
< 0x02 || reg1
== 0xff)
449 * The ID register is read/write in a real APIC.
451 reg0
= APICRead(APIC_ID
);
452 DPRINT1("Getting ID: %x\n", reg0
);
453 APICWrite(APIC_ID
, reg0
^ APIC_ID_MASK
);
454 reg1
= APICRead(APIC_ID
);
455 DPRINT1("Getting ID: %x\n", reg1
);
456 APICWrite(APIC_ID
, reg0
);
457 if (reg1
!= (reg0
^ APIC_ID_MASK
))
463 Ki386Rdmsr(0x1b /*MSR_IA32_APICBASE*/, l
, h
);
465 if (!(l
& /*MSR_IA32_APICBASE_ENABLE*/(1<<11)))
467 DPRINT1("Local APIC disabled by BIOS -- reenabling.\n");
468 l
&= ~/*MSR_IA32_APICBASE_BASE*/(1<<11);
469 l
|= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000;
470 Ki386Wrmsr(0x1b/*MSR_IA32_APICBASE*/, l
, h
);
479 VOID
APICSendIPI(ULONG Target
, ULONG Mode
)
483 /* save flags and disable interrupts */
484 Ki386SaveFlags(flags
);
485 Ki386DisableInterrupts();
487 /* Wait up to 100ms for the APIC to become ready */
488 for (i
= 0; i
< 10000; i
++)
490 tmp
= APICRead(APIC_ICR0
);
491 /* Check Delivery Status */
492 if ((tmp
& APIC_ICR0_DS
) == 0)
494 KeStallExecutionProcessor(10);
499 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
502 /* Setup the APIC to deliver the IPI */
503 DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target
), Target
);
504 APICWrite(APIC_ICR1
, SET_APIC_DEST_FIELD(Target
));
506 if (Target
== APIC_TARGET_SELF
)
508 Mode
|= APIC_ICR0_DESTS_SELF
;
510 else if (Target
== APIC_TARGET_ALL
)
512 Mode
|= APIC_ICR0_DESTS_ALL
;
514 else if (Target
== APIC_TARGET_ALL_BUT_SELF
)
516 Mode
|= APIC_ICR0_DESTS_ALL_BUT_SELF
;
520 Mode
|= APIC_ICR0_DESTS_FIELD
;
523 /* Now, fire off the IPI */
524 APICWrite(APIC_ICR0
, Mode
);
526 /* Wait up to 100ms for the APIC to become ready */
527 for (i
= 0; i
< 10000; i
++)
529 tmp
= APICRead(APIC_ICR0
);
530 /* Check Delivery Status */
531 if ((tmp
& APIC_ICR0_DS
) == 0)
533 KeStallExecutionProcessor(10);
538 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
540 Ki386RestoreFlags(flags
);
552 DPRINT1("CPU%d:\n", CPU
);
553 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
554 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
555 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
558 * Intel recommends to set DFR, LDR and TPR before enabling
559 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
560 * document number 292116). So here it goes...
564 * Put the APIC into flat delivery mode.
565 * Must be "all ones" explicitly for 82489DX.
567 APICWrite(APIC_DFR
, 0xFFFFFFFF);
570 * Set up the logical destination ID.
572 tmp
= APICRead(APIC_LDR
);
573 tmp
&= ~APIC_LDR_MASK
;
576 * This works only up to 8 CPU's
578 tmp
|= (1 << (KeGetCurrentProcessorNumber() + 24));
579 APICWrite(APIC_LDR
, tmp
);
582 DPRINT1("CPU%d:\n", CPU
);
583 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
584 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
585 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
586 DPRINT1("%d\n", CPUMap
[CPU
].APICId
);
588 /* Accept only higher interrupts */
589 APICWrite(APIC_TPR
, 0xef);
591 /* Enable local APIC */
592 tmp
= APICRead(APIC_SIVR
);
594 tmp
|= APIC_SIVR_ENABLE
;
597 tmp
&= ~APIC_SIVR_FOCUS
;
599 tmp
|= APIC_SIVR_FOCUS
;
602 /* Set spurious interrupt vector */
603 tmp
|= SPURIOUS_VECTOR
;
604 APICWrite(APIC_SIVR
, tmp
);
609 * set up through-local-APIC on the BP's LINT0. This is not
610 * strictly necessery in pure symmetric-IO mode, but sometimes
611 * we delegate interrupts to the 8259A.
613 tmp
= APICRead(APIC_LINT0
) & APIC_LVT_MASKED
;
614 if (CPU
== BootCPU
&& (APICMode
== amPIC
|| !tmp
))
616 tmp
= APIC_DM_EXTINT
;
617 DPRINT1("enabled ExtINT on CPU#%d\n", CPU
);
621 tmp
= APIC_DM_EXTINT
| APIC_LVT_MASKED
;
622 DPRINT1("masked ExtINT on CPU#%d\n", CPU
);
624 APICWrite(APIC_LINT0
, tmp
);
627 * Only the BSP should see the LINT1 NMI signal, obviously.
635 tmp
= APIC_DM_NMI
| APIC_LVT_MASKED
;
637 if (!APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
640 tmp
|= APIC_LVT_LEVEL_TRIGGER
;
642 APICWrite(APIC_LINT1
, tmp
);
644 if (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
647 if (APICGetMaxLVT() > 3)
649 /* Due to the Pentium erratum 3AP */
650 APICWrite(APIC_ESR
, 0);
653 tmp
= APICRead(APIC_ESR
);
654 DPRINT("ESR value before enabling vector: 0x%X\n", tmp
);
656 /* Enable sending errors */
658 APICWrite(APIC_LVT3
, tmp
);
661 * Spec says clear errors after enabling vector
663 if (APICGetMaxLVT() > 3)
665 APICWrite(APIC_ESR
, 0);
667 tmp
= APICRead(APIC_ESR
);
668 DPRINT("ESR value after enabling vector: 0x%X\n", tmp
);
672 VOID
APICSyncArbIDs(VOID
)
676 /* Wait up to 100ms for the APIC to become ready */
677 for (i
= 0; i
< 10000; i
++)
679 tmp
= APICRead(APIC_ICR0
);
680 /* Check Delivery Status */
681 if ((tmp
& APIC_ICR0_DS
) == 0)
683 KeStallExecutionProcessor(10);
688 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
691 DPRINT("Synchronizing Arb IDs.\n");
692 APICWrite(APIC_ICR0
, APIC_ICR0_DESTS_ALL
| APIC_ICR0_LEVEL
| APIC_DM_INIT
);
696 VOID
MpsErrorHandler(VOID
)
702 tmp1
= APICRead(APIC_ESR
);
703 APICWrite(APIC_ESR
, 0);
704 tmp2
= APICRead(APIC_ESR
);
705 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
708 * Acknowledge the interrupt
712 /* Here is what the APIC error bits mean:
714 * 1: Receive CS error
715 * 2: Send accept error
716 * 3: Receive accept error
718 * 5: Send illegal vector
719 * 6: Received illegal vector
720 * 7: Illegal register address
722 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
726 VOID
MpsSpuriousHandler(VOID
)
730 DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU());
732 tmp
= APICRead(APIC_ISR
+ ((SPURIOUS_VECTOR
& ~0x1f) >> 1));
733 if (tmp
& (1 << (SPURIOUS_VECTOR
& 0x1f)))
739 /* No need to send EOI here */
745 VOID
MpsIpiHandler(VOID
)
749 HalBeginSystemInterrupt(IPI_VECTOR
,
752 Ki386EnableInterrupts();
754 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n",
755 __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
758 KiIpiServiceRoutine(NULL
, NULL
);
761 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber());
764 Ki386DisableInterrupts();
765 HalEndSystemInterrupt(oldIrql
, 0);
770 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
771 PKTRAP_FRAME TrapFrame
)
773 TrapFrame
->Gs
= (USHORT
)IrqTrapFrame
->Gs
;
774 TrapFrame
->Fs
= (USHORT
)IrqTrapFrame
->Fs
;
775 TrapFrame
->Es
= (USHORT
)IrqTrapFrame
->Es
;
776 TrapFrame
->Ds
= (USHORT
)IrqTrapFrame
->Ds
;
777 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
778 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
779 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
780 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
781 TrapFrame
->Esp
= IrqTrapFrame
->Esp
;
782 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
783 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
784 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
785 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
786 TrapFrame
->Cs
= IrqTrapFrame
->Cs
;
787 TrapFrame
->Eflags
= IrqTrapFrame
->Eflags
;
791 MpsTimerHandler(ULONG Vector
, PKIRQ_TRAPFRAME Trapframe
)
794 KTRAP_FRAME KernelTrapFrame
;
797 static ULONG Count
[MAX_CPU
] = {0,};
799 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR
,
802 Ki386EnableInterrupts();
806 if ((Count
[CPU
] % 100) == 0)
808 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__
, __LINE__
, CPU
, oldIrql
,Trapframe
->Eip
, KeGetCurrentKPCR());
813 MpsIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
814 if (KeGetCurrentProcessorNumber() == 0)
816 KeUpdateSystemTime(&KernelTrapFrame
, oldIrql
);
820 KeUpdateRunTime(&KernelTrapFrame
, oldIrql
);
823 Ki386DisableInterrupts();
824 HalEndSystemInterrupt (oldIrql
, 0);
827 VOID
APICSetupLVTT(ULONG ClockTicks
)
831 tmp
= GET_APIC_VERSION(APICRead(APIC_VER
));
832 if (!APIC_INTEGRATED(tmp
))
834 tmp
= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV
) | APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
839 tmp
= APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
841 APICWrite(APIC_LVTT
, tmp
);
843 tmp
= APICRead(APIC_TDCR
);
844 tmp
&= ~(APIC_TDCR_1
| APIC_TIMER_BASE_DIV
);
846 APICWrite(APIC_TDCR
, tmp
);
847 APICWrite(APIC_ICRT
, ClockTicks
/ APIC_DIVISOR
);
851 APICCalibrateTimer(ULONG CPU
)
853 ULARGE_INTEGER t1
, t2
;
857 DPRINT("Calibrating APIC timer for CPU %d\n", CPU
);
859 APICSetupLVTT(1000000000);
861 TSCPresent
= ((PKIPCR
)KeGetCurrentKPCR())->PrcbData
.FeatureBits
& X86_FEATURE_TSC
? TRUE
: FALSE
;
864 * The timer chip counts down to zero. Let's wait
865 * for a wraparound to start exact measurement:
866 * (the current tick might have been already half done)
868 WaitFor8254Wraparound();
871 * We wrapped around just now. Let's start
877 tt1
= APICRead(APIC_CCRT
);
879 WaitFor8254Wraparound();
882 tt2
= APICRead(APIC_CCRT
);
886 CPUMap
[CPU
].CoreSpeed
= (HZ
* (t2
.QuadPart
- t1
.QuadPart
));
887 DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
888 CPUMap
[CPU
].CoreSpeed
/1000000,
889 CPUMap
[CPU
].CoreSpeed
%1000000);
890 ((PKIPCR
)KeGetCurrentKPCR())->PrcbData
.MHz
= CPUMap
[CPU
].CoreSpeed
/1000000;
893 CPUMap
[CPU
].BusSpeed
= (HZ
* (long)(tt1
- tt2
) * APIC_DIVISOR
);
895 /* Setup timer for normal operation */
896 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
897 APICSetupLVTT((CPUMap
[CPU
].BusSpeed
/ 1000000) * 10000); // 10ms
898 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
900 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
901 CPUMap
[CPU
].BusSpeed
/1000000,
902 CPUMap
[CPU
].BusSpeed
%1000000);
906 SetInterruptGate(ULONG index
, ULONG address
)
911 /* Set the IDT Access Bits */
914 Access
.Dpl
= 0; /* Kernel-Mode */
915 Access
.SystemSegmentFlag
= 0;
916 Access
.SegmentType
= I386_INTERRUPT_GATE
;
918 idt
= (KIDTENTRY
*)((ULONG
)KeGetCurrentKPCR()->IDT
+ index
* sizeof(KIDTENTRY
));
919 idt
->Offset
= address
& 0xffff;
920 idt
->Selector
= KERNEL_CS
;
921 idt
->Access
= Access
.Value
;
922 idt
->ExtendedOffset
= address
>> 16;
925 VOID
HaliInitBSP(VOID
)
931 static BOOLEAN BSPInitialized
= FALSE
;
933 /* Only initialize the BSP once */
940 BSPInitialized
= TRUE
;
942 /* Setup interrupt handlers */
943 SetInterruptGate(LOCAL_TIMER_VECTOR
, (ULONG
)MpsTimerInterrupt
);
944 SetInterruptGate(ERROR_VECTOR
, (ULONG
)MpsErrorInterrupt
);
945 SetInterruptGate(SPURIOUS_VECTOR
, (ULONG
)MpsSpuriousInterrupt
);
947 SetInterruptGate(IPI_VECTOR
, (ULONG
)MpsIpiInterrupt
);
949 DPRINT("APIC is mapped at 0x%X\n", APICBase
);
951 if (VerifyLocalAPIC())
953 DPRINT("APIC found\n");
957 DPRINT("No APIC found\n");
961 if (APICMode
== amPIC
)
969 /* BIOS data segment */
970 BIOSBase
= (PULONG
)BIOS_AREA
;
972 /* Area for communicating with the APs */
973 CommonBase
= (PULONG
)COMMON_AREA
;
975 /* Copy bootstrap code to common area */
976 memcpy((PVOID
)((ULONG
)CommonBase
+ PAGE_SIZE
),
978 (ULONG
)&APend
- (ULONG
)&APstart
+ 1);
980 /* Set shutdown code */
981 CMOS_WRITE(0xF, 0xA);
983 /* Set warm reset vector */
984 ps
= (PUSHORT
)((ULONG
)BIOSBase
+ 0x467);
985 *ps
= (COMMON_AREA
+ PAGE_SIZE
) & 0xF;
987 ps
= (PUSHORT
)((ULONG
)BIOSBase
+ 0x469);
988 *ps
= (COMMON_AREA
+ PAGE_SIZE
) >> 4;
991 /* Calibrate APIC timer */
992 APICCalibrateTimer(BootCPU
);
997 HaliStartApplicationProcessor(ULONG Cpu
, ULONG Stack
)
1000 PCOMMON_AREA_INFO Common
;
1003 ULONG DeliveryStatus
= 0;
1004 ULONG AcceptStatus
= 0;
1006 if (Cpu
>= MAX_CPU
||
1008 OnlineCPUs
& (1 << Cpu
))
1012 DPRINT1("Attempting to boot CPU %d\n", Cpu
);
1016 APICSendIPI(Cpu
, APIC_DM_INIT
|APIC_ICR0_LEVEL_ASSERT
);
1018 KeStallExecutionProcessor(200);
1022 APICSendIPI(Cpu
, APIC_DM_INIT
|APIC_ICR0_LEVEL_DEASSERT
);
1024 if (APIC_INTEGRATED(CPUMap
[Cpu
].APICVersion
))
1026 /* Clear APIC errors */
1027 APICWrite(APIC_ESR
, 0);
1028 tmp
= (APICRead(APIC_ESR
) & APIC_ESR_MASK
);
1031 Common
= (PCOMMON_AREA_INFO
)CommonBase
;
1033 /* Write the location of the AP stack */
1034 Common
->Stack
= (ULONG
)Stack
;
1035 /* Write the page directory page */
1036 Ke386GetPageTableDirectory(Common
->PageDirectory
);
1037 /* Write the kernel entry point */
1038 Common
->NtProcessStartup
= (ULONG_PTR
)RtlImageNtHeader(MmSystemRangeStart
)->OptionalHeader
.AddressOfEntryPoint
+ (ULONG_PTR
)MmSystemRangeStart
;
1039 /* Write the state of the mae mode */
1040 Common
->PaeModeEnabled
= Ke386GetCr4() & X86_CR4_PAE
? 1 : 0;
1042 DPRINT1("%x %x %x %x\n", Common
->Stack
, Common
->PageDirectory
, Common
->NtProcessStartup
, Common
->PaeModeEnabled
);
1044 DPRINT("Cpu %d got stack at 0x%X\n", Cpu
, Common
->Stack
);
1046 for (j
= 0; j
< 16; j
++)
1048 Common
->Debug
[j
] = 0;
1052 maxlvt
= APICGetMaxLVT();
1054 /* Is this a local APIC or an 82489DX? */
1055 StartupCount
= (APIC_INTEGRATED(CPUMap
[Cpu
].APICVersion
)) ? 2 : 0;
1057 for (i
= 1; i
<= StartupCount
; i
++)
1059 /* It's a local APIC, so send STARTUP IPI */
1060 DPRINT("Sending startup signal %d\n", i
);
1062 APICWrite(APIC_ESR
, 0);
1065 APICSendIPI(Cpu
, APIC_DM_STARTUP
| ((COMMON_AREA
+ PAGE_SIZE
) >> 12)|APIC_ICR0_LEVEL_DEASSERT
);
1067 /* Wait up to 10ms for IPI to be delivered */
1071 KeStallExecutionProcessor(10);
1073 /* Check Delivery Status */
1074 DeliveryStatus
= APICRead(APIC_ICR0
) & APIC_ICR0_DS
;
1077 } while ((DeliveryStatus
) && (j
< 1000));
1079 KeStallExecutionProcessor(200);
1082 * Due to the Pentium erratum 3AP.
1086 APICRead(APIC_SIVR
);
1087 APICWrite(APIC_ESR
, 0);
1090 AcceptStatus
= APICRead(APIC_ESR
) & APIC_ESR_MASK
;
1092 if (DeliveryStatus
|| AcceptStatus
)
1100 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu
);
1105 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu
);
1108 if (!(DeliveryStatus
|| AcceptStatus
))
1111 /* Wait no more than 5 seconds for processor to boot */
1112 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu
);
1114 /* Wait no more than 5 seconds */
1115 for (j
= 0; j
< 50000; j
++)
1117 if (CPUMap
[Cpu
].Flags
& CPU_ENABLED
)
1121 KeStallExecutionProcessor(100);
1125 if (CPUMap
[Cpu
].Flags
& CPU_ENABLED
)
1127 DbgPrint("CPU %d is now running\n", Cpu
);
1131 DbgPrint("Initialization of CPU %d failed\n", Cpu
);
1135 DPRINT("Debug bytes are:\n");
1137 for (j
= 0; j
< 4; j
++)
1139 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1140 Common
->Debug
[j
*4+0],
1141 Common
->Debug
[j
*4+1],
1142 Common
->Debug
[j
*4+2],
1143 Common
->Debug
[j
*4+3]);