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 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
);
227 __inline ULONG
_APICRead(ULONG Offset
)
231 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
236 __inline VOID
APICWrite(ULONG Offset
,
241 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
246 __inline VOID
APICWrite(ULONG Offset
,
250 ULONG CPU
= (_APICRead(APIC_ID
) & APIC_ID_MASK
) >> 24;
252 lastregw
[CPU
] = Offset
;
253 lastvalw
[CPU
] = Value
;
255 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
263 __inline ULONG
APICRead(ULONG Offset
)
267 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
271 __inline ULONG
APICRead(ULONG Offset
)
274 ULONG CPU
= (_APICRead(APIC_ID
) & APIC_ID_MASK
) >> 24;
276 lastregr
[CPU
] = Offset
;
279 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
282 return lastvalr
[CPU
];
286 __inline VOID
APICSendEOI(VOID
)
289 APICWrite(APIC_EOI
, 0);
292 static VOID
APICDumpBit(ULONG base
)
296 DbgPrint("0123456789abcdef0123456789abcdef\n");
297 for (i
= 0; i
< 8; i
++)
299 v
= APICRead(base
+ i
*0x10);
300 for (j
= 0; j
< 32; j
++)
314 * Dump the contents of the local APIC registers
317 ULONG v
, ver
, maxlvt
;
318 ULONG r1
, r2
, w1
, w2
;
319 ULONG CPU
= ThisCPU();;
328 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
329 v
= APICRead(APIC_ID
);
330 DbgPrint("... ID : %08x (%01x) ", v
, GET_APIC_ID(v
));
331 v
= APICRead(APIC_VER
);
332 DbgPrint("... VERSION: %08x\n", v
);
333 ver
= GET_APIC_VERSION(v
);
334 maxlvt
= APICGetMaxLVT();
336 v
= APICRead(APIC_TPR
);
337 DbgPrint("... TPR : %08x (%02x)", v
, v
& ~0);
339 if (APIC_INTEGRATED(ver
))
342 v
= APICRead(APIC_APR
);
343 DbgPrint("... APR : %08x (%02x)\n", v
, v
& ~0);
344 v
= APICRead(APIC_PPR
);
345 DbgPrint("... PPR : %08x\n", v
);
348 v
= APICRead(APIC_EOI
);
349 DbgPrint("... EOI : %08x ! ", v
);
350 v
= APICRead(APIC_LDR
);
351 DbgPrint("... LDR : %08x\n", v
);
352 v
= APICRead(APIC_DFR
);
353 DbgPrint("... DFR : %08x ! ", v
);
354 v
= APICRead(APIC_SIVR
);
355 DbgPrint("... SIVR : %08x\n", v
);
359 DbgPrint("... ISR field:\n");
360 APICDumpBit(APIC_ISR
);
361 DbgPrint("... TMR field:\n");
362 APICDumpBit(APIC_TMR
);
363 DbgPrint("... IRR field:\n");
364 APICDumpBit(APIC_IRR
);
367 if (APIC_INTEGRATED(ver
))
372 /* Due to the Pentium erratum 3AP. */
373 APICWrite(APIC_ESR
, 0);
375 v
= APICRead(APIC_ESR
);
376 DbgPrint("... ESR : %08x\n", v
);
379 v
= APICRead(APIC_ICR0
);
380 DbgPrint("... ICR0 : %08x ! ", v
);
381 v
= APICRead(APIC_ICR1
);
382 DbgPrint("... ICR1 : %08x ! ", v
);
384 v
= APICRead(APIC_LVTT
);
385 DbgPrint("... LVTT : %08x\n", v
);
390 v
= APICRead(APIC_LVTPC
);
391 DbgPrint("... LVTPC : %08x ! ", v
);
393 v
= APICRead(APIC_LINT0
);
394 DbgPrint("... LINT0 : %08x ! ", v
);
395 v
= APICRead(APIC_LINT1
);
396 DbgPrint("... LINT1 : %08x\n", v
);
400 v
= APICRead(APIC_LVT3
);
401 DbgPrint("... LVT3 : %08x\n", v
);
404 v
= APICRead(APIC_ICRT
);
405 DbgPrint("... ICRT : %08x ! ", v
);
406 v
= APICRead(APIC_CCRT
);
407 DbgPrint("... CCCT : %08x ! ", v
);
408 v
= APICRead(APIC_TDCR
);
409 DbgPrint("... TDCR : %08x\n", v
);
411 DbgPrint("Last register read (offset): 0x%08X\n", r1
);
412 DbgPrint("Last register read (value): 0x%08X\n", r2
);
413 DbgPrint("Last register written (offset): 0x%08X\n", w1
);
414 DbgPrint("Last register written (value): 0x%08X\n", w2
);
418 BOOLEAN
VerifyLocalAPIC(VOID
)
422 /* The version register is read-only in a real APIC */
423 reg0
= APICRead(APIC_VER
);
424 DPRINT1("Getting VERSION: %x\n", reg0
);
425 APICWrite(APIC_VER
, reg0
^ APIC_VER_MASK
);
426 reg1
= APICRead(APIC_VER
);
427 DPRINT1("Getting VERSION: %x\n", reg1
);
430 * The two version reads above should print the same
431 * numbers. If the second one is different, then we
432 * poke at a non-APIC.
441 * Check if the version looks reasonably.
443 reg1
= GET_APIC_VERSION(reg0
);
444 if (reg1
== 0x00 || reg1
== 0xff)
448 reg1
= APICGetMaxLVT();
449 if (reg1
< 0x02 || reg1
== 0xff)
455 * The ID register is read/write in a real APIC.
457 reg0
= APICRead(APIC_ID
);
458 DPRINT1("Getting ID: %x\n", reg0
);
459 APICWrite(APIC_ID
, reg0
^ APIC_ID_MASK
);
460 reg1
= APICRead(APIC_ID
);
461 DPRINT1("Getting ID: %x\n", reg1
);
462 APICWrite(APIC_ID
, reg0
);
463 if (reg1
!= (reg0
^ APIC_ID_MASK
))
468 Ki386Rdmsr(0x1b /*MSR_IA32_APICBASE*/, l
, h
);
470 if (!(l
& /*MSR_IA32_APICBASE_ENABLE*/(1<<11)))
472 DPRINT1("Local APIC disabled by BIOS -- reenabling.\n");
473 l
&= ~/*MSR_IA32_APICBASE_BASE*/(1<<11);
474 l
|= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000;
475 Ki386Wrmsr(0x1b/*MSR_IA32_APICBASE*/, l
, h
);
484 VOID
APICSendIPI(ULONG Target
, ULONG Mode
)
488 /* save flags and disable interrupts */
489 Ki386SaveFlags(flags
);
490 Ki386DisableInterrupts();
492 /* Wait up to 100ms for the APIC to become ready */
493 for (i
= 0; i
< 10000; i
++)
495 tmp
= APICRead(APIC_ICR0
);
496 /* Check Delivery Status */
497 if ((tmp
& APIC_ICR0_DS
) == 0)
499 KeStallExecutionProcessor(10);
504 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
507 /* Setup the APIC to deliver the IPI */
508 DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target
), Target
);
509 APICWrite(APIC_ICR1
, SET_APIC_DEST_FIELD(Target
));
511 if (Target
== APIC_TARGET_SELF
)
513 Mode
|= APIC_ICR0_DESTS_SELF
;
515 else if (Target
== APIC_TARGET_ALL
)
517 Mode
|= APIC_ICR0_DESTS_ALL
;
519 else if (Target
== APIC_TARGET_ALL_BUT_SELF
)
521 Mode
|= APIC_ICR0_DESTS_ALL_BUT_SELF
;
525 Mode
|= APIC_ICR0_DESTS_FIELD
;
528 /* Now, fire off the IPI */
529 APICWrite(APIC_ICR0
, Mode
);
531 /* Wait up to 100ms for the APIC to become ready */
532 for (i
= 0; i
< 10000; i
++)
534 tmp
= APICRead(APIC_ICR0
);
535 /* Check Delivery Status */
536 if ((tmp
& APIC_ICR0_DS
) == 0)
538 KeStallExecutionProcessor(10);
543 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
545 Ki386RestoreFlags(flags
);
557 DPRINT1("CPU%d:\n", CPU
);
558 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
559 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
560 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
563 * Intel recommends to set DFR, LDR and TPR before enabling
564 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
565 * document number 292116). So here it goes...
569 * Put the APIC into flat delivery mode.
570 * Must be "all ones" explicitly for 82489DX.
572 APICWrite(APIC_DFR
, 0xFFFFFFFF);
575 * Set up the logical destination ID.
577 tmp
= APICRead(APIC_LDR
);
578 tmp
&= ~APIC_LDR_MASK
;
581 * This works only up to 8 CPU's
583 tmp
|= (1 << (KeGetCurrentProcessorNumber() + 24));
584 APICWrite(APIC_LDR
, tmp
);
587 DPRINT1("CPU%d:\n", CPU
);
588 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
589 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
590 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
591 DPRINT1("%d\n", CPUMap
[CPU
].APICId
);
593 /* Accept only higher interrupts */
594 APICWrite(APIC_TPR
, 0xef);
596 /* Enable local APIC */
597 tmp
= APICRead(APIC_SIVR
);
599 tmp
|= APIC_SIVR_ENABLE
;
602 tmp
&= ~APIC_SIVR_FOCUS
;
604 tmp
|= APIC_SIVR_FOCUS
;
607 /* Set spurious interrupt vector */
608 tmp
|= SPURIOUS_VECTOR
;
609 APICWrite(APIC_SIVR
, tmp
);
614 * set up through-local-APIC on the BP's LINT0. This is not
615 * strictly necessery in pure symmetric-IO mode, but sometimes
616 * we delegate interrupts to the 8259A.
618 tmp
= APICRead(APIC_LINT0
) & APIC_LVT_MASKED
;
619 if (CPU
== BootCPU
&& (APICMode
== amPIC
|| !tmp
))
621 tmp
= APIC_DM_EXTINT
;
622 DPRINT1("enabled ExtINT on CPU#%d\n", CPU
);
626 tmp
= APIC_DM_EXTINT
| APIC_LVT_MASKED
;
627 DPRINT1("masked ExtINT on CPU#%d\n", CPU
);
629 APICWrite(APIC_LINT0
, tmp
);
632 * Only the BSP should see the LINT1 NMI signal, obviously.
640 tmp
= APIC_DM_NMI
| APIC_LVT_MASKED
;
642 if (!APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
645 tmp
|= APIC_LVT_LEVEL_TRIGGER
;
647 APICWrite(APIC_LINT1
, tmp
);
649 if (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
652 if (APICGetMaxLVT() > 3)
654 /* Due to the Pentium erratum 3AP */
655 APICWrite(APIC_ESR
, 0);
658 tmp
= APICRead(APIC_ESR
);
659 DPRINT("ESR value before enabling vector: 0x%X\n", tmp
);
661 /* Enable sending errors */
663 APICWrite(APIC_LVT3
, tmp
);
666 * Spec says clear errors after enabling vector
668 if (APICGetMaxLVT() > 3)
670 APICWrite(APIC_ESR
, 0);
672 tmp
= APICRead(APIC_ESR
);
673 DPRINT("ESR value after enabling vector: 0x%X\n", tmp
);
677 VOID
APICSyncArbIDs(VOID
)
681 /* Wait up to 100ms for the APIC to become ready */
682 for (i
= 0; i
< 10000; i
++)
684 tmp
= APICRead(APIC_ICR0
);
685 /* Check Delivery Status */
686 if ((tmp
& APIC_ICR0_DS
) == 0)
688 KeStallExecutionProcessor(10);
693 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
696 DPRINT("Synchronizing Arb IDs.\n");
697 APICWrite(APIC_ICR0
, APIC_ICR0_DESTS_ALL
| APIC_ICR0_LEVEL
| APIC_DM_INIT
);
701 VOID
MpsErrorHandler(VOID
)
707 tmp1
= APICRead(APIC_ESR
);
708 APICWrite(APIC_ESR
, 0);
709 tmp2
= APICRead(APIC_ESR
);
710 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
713 * Acknowledge the interrupt
717 /* Here is what the APIC error bits mean:
719 * 1: Receive CS error
720 * 2: Send accept error
721 * 3: Receive accept error
723 * 5: Send illegal vector
724 * 6: Received illegal vector
725 * 7: Illegal register address
727 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
731 VOID
MpsSpuriousHandler(VOID
)
735 DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU());
737 tmp
= APICRead(APIC_ISR
+ ((SPURIOUS_VECTOR
& ~0x1f) >> 1));
738 if (tmp
& (1 << (SPURIOUS_VECTOR
& 0x1f)))
744 /* No need to send EOI here */
750 VOID
MpsIpiHandler(VOID
)
754 HalBeginSystemInterrupt(IPI_LEVEL
,
757 Ki386EnableInterrupts();
759 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n",
760 __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
763 KiIpiServiceRoutine(NULL
, NULL
);
766 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber());
769 Ki386DisableInterrupts();
770 HalEndSystemInterrupt(oldIrql
, 0);
775 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
776 PKTRAP_FRAME TrapFrame
)
778 TrapFrame
->SegGs
= (USHORT
)IrqTrapFrame
->Gs
;
779 TrapFrame
->SegFs
= (USHORT
)IrqTrapFrame
->Fs
;
780 TrapFrame
->SegEs
= (USHORT
)IrqTrapFrame
->Es
;
781 TrapFrame
->SegDs
= (USHORT
)IrqTrapFrame
->Ds
;
782 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
783 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
784 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
785 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
786 TrapFrame
->HardwareEsp
= IrqTrapFrame
->Esp
;
787 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
788 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
789 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
790 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
791 TrapFrame
->SegCs
= IrqTrapFrame
->Cs
;
792 TrapFrame
->EFlags
= IrqTrapFrame
->Eflags
;
796 MpsTimerHandler(ULONG Vector
, PKIRQ_TRAPFRAME Trapframe
)
799 KTRAP_FRAME KernelTrapFrame
;
802 static ULONG Count
[MAX_CPU
] = {0,};
804 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR
,
807 Ki386EnableInterrupts();
811 if ((Count
[CPU
] % 100) == 0)
813 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__
, __LINE__
, CPU
, oldIrql
,Trapframe
->Eip
, KeGetPcr());
818 MpsIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
819 if (KeGetCurrentProcessorNumber() == 0)
821 KeUpdateSystemTime(&KernelTrapFrame
, oldIrql
);
825 KeUpdateRunTime(&KernelTrapFrame
, oldIrql
);
828 Ki386DisableInterrupts();
829 HalEndSystemInterrupt (oldIrql
, 0);
832 VOID
APICSetupLVTT(ULONG ClockTicks
)
836 tmp
= GET_APIC_VERSION(APICRead(APIC_VER
));
837 if (!APIC_INTEGRATED(tmp
))
839 tmp
= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV
) | APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
844 tmp
= APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
846 APICWrite(APIC_LVTT
, tmp
);
848 tmp
= APICRead(APIC_TDCR
);
849 tmp
&= ~(APIC_TDCR_1
| APIC_TIMER_BASE_DIV
);
851 APICWrite(APIC_TDCR
, tmp
);
852 APICWrite(APIC_ICRT
, ClockTicks
/ APIC_DIVISOR
);
856 APICCalibrateTimer(ULONG CPU
)
858 ULARGE_INTEGER t1
, t2
;
862 DPRINT("Calibrating APIC timer for CPU %d\n", CPU
);
864 APICSetupLVTT(1000000000);
866 TSCPresent
= ((PKIPCR
)KeGetPcr())->PrcbData
.FeatureBits
& KF_RDTSC
? TRUE
: FALSE
;
869 * The timer chip counts down to zero. Let's wait
870 * for a wraparound to start exact measurement:
871 * (the current tick might have been already half done)
873 WaitFor8254Wraparound();
876 * We wrapped around just now. Let's start
882 tt1
= APICRead(APIC_CCRT
);
884 WaitFor8254Wraparound();
887 tt2
= APICRead(APIC_CCRT
);
891 CPUMap
[CPU
].CoreSpeed
= (HZ
* (t2
.QuadPart
- t1
.QuadPart
));
892 DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
893 CPUMap
[CPU
].CoreSpeed
/1000000,
894 CPUMap
[CPU
].CoreSpeed
%1000000);
895 ((PKIPCR
)KeGetPcr())->PrcbData
.MHz
= CPUMap
[CPU
].CoreSpeed
/1000000;
898 CPUMap
[CPU
].BusSpeed
= (HZ
* (long)(tt1
- tt2
) * APIC_DIVISOR
);
900 /* Setup timer for normal operation */
901 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
902 APICSetupLVTT((CPUMap
[CPU
].BusSpeed
/ 1000000) * 10000); // 10ms
903 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
905 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
906 CPUMap
[CPU
].BusSpeed
/1000000,
907 CPUMap
[CPU
].BusSpeed
%1000000);
911 SetInterruptGate(ULONG index
, ULONG address
)
916 /* Set the IDT Access Bits */
919 Access
.Dpl
= 0; /* Kernel-Mode */
920 Access
.SystemSegmentFlag
= 0;
921 Access
.SegmentType
= I386_INTERRUPT_GATE
;
923 idt
= (KIDTENTRY
*)((ULONG
)KeGetPcr()->IDT
+ index
* sizeof(KIDTENTRY
));
924 idt
->Offset
= address
& 0xffff;
925 idt
->Selector
= KGDT_R0_CODE
;
926 idt
->Access
= Access
.Value
;
927 idt
->ExtendedOffset
= address
>> 16;
930 VOID
HaliInitBSP(VOID
)
936 static BOOLEAN BSPInitialized
= FALSE
;
938 /* Only initialize the BSP once */
945 BSPInitialized
= TRUE
;
947 /* Setup interrupt handlers */
948 SetInterruptGate(LOCAL_TIMER_VECTOR
, (ULONG
)MpsTimerInterrupt
);
949 SetInterruptGate(ERROR_VECTOR
, (ULONG
)MpsErrorInterrupt
);
950 SetInterruptGate(SPURIOUS_VECTOR
, (ULONG
)MpsSpuriousInterrupt
);
952 SetInterruptGate(IPI_VECTOR
, (ULONG
)MpsIpiInterrupt
);
954 DPRINT("APIC is mapped at 0x%X\n", APICBase
);
956 if (VerifyLocalAPIC())
958 DPRINT("APIC found\n");
962 DPRINT("No APIC found\n");
966 if (APICMode
== amPIC
)
974 /* BIOS data segment */
975 BIOSBase
= (PULONG
)BIOS_AREA
;
977 /* Area for communicating with the APs */
978 CommonBase
= (PULONG
)COMMON_AREA
;
980 /* Copy bootstrap code to common area */
981 memcpy((PVOID
)((ULONG
)CommonBase
+ PAGE_SIZE
),
983 (ULONG
)&APend
- (ULONG
)&APstart
+ 1);
985 /* Set shutdown code */
986 CMOS_WRITE(0xF, 0xA);
988 /* Set warm reset vector */
989 ps
= (PUSHORT
)((ULONG
)BIOSBase
+ 0x467);
990 *ps
= (COMMON_AREA
+ PAGE_SIZE
) & 0xF;
992 ps
= (PUSHORT
)((ULONG
)BIOSBase
+ 0x469);
993 *ps
= (COMMON_AREA
+ PAGE_SIZE
) >> 4;
996 /* Calibrate APIC timer */
997 APICCalibrateTimer(BootCPU
);
1002 HaliStartApplicationProcessor(ULONG Cpu
, ULONG Stack
)
1005 PCOMMON_AREA_INFO Common
;
1008 ULONG DeliveryStatus
= 0;
1009 ULONG AcceptStatus
= 0;
1011 if (Cpu
>= MAX_CPU
||
1013 OnlineCPUs
& (1 << Cpu
))
1017 DPRINT1("Attempting to boot CPU %d\n", Cpu
);
1021 APICSendIPI(Cpu
, APIC_DM_INIT
|APIC_ICR0_LEVEL_ASSERT
);
1023 KeStallExecutionProcessor(200);
1027 APICSendIPI(Cpu
, APIC_DM_INIT
|APIC_ICR0_LEVEL_DEASSERT
);
1029 if (APIC_INTEGRATED(CPUMap
[Cpu
].APICVersion
))
1031 /* Clear APIC errors */
1032 APICWrite(APIC_ESR
, 0);
1033 tmp
= (APICRead(APIC_ESR
) & APIC_ESR_MASK
);
1036 Common
= (PCOMMON_AREA_INFO
)CommonBase
;
1038 /* Write the location of the AP stack */
1039 Common
->Stack
= (ULONG
)Stack
;
1040 /* Write the page directory page */
1041 Common
->PageDirectory
= __readcr3();
1042 /* Write the kernel entry point */
1043 Common
->NtProcessStartup
= (ULONG_PTR
)RtlImageNtHeader((PVOID
)KernelBase
)->OptionalHeader
.AddressOfEntryPoint
+ KernelBase
;
1044 /* Write the state of the mae mode */
1045 Common
->PaeModeEnabled
= __readcr4() & CR4_PAE
? 1 : 0;
1047 DPRINT1("%x %x %x %x\n", Common
->Stack
, Common
->PageDirectory
, Common
->NtProcessStartup
, Common
->PaeModeEnabled
);
1049 DPRINT("Cpu %d got stack at 0x%X\n", Cpu
, Common
->Stack
);
1051 for (j
= 0; j
< 16; j
++)
1053 Common
->Debug
[j
] = 0;
1057 maxlvt
= APICGetMaxLVT();
1059 /* Is this a local APIC or an 82489DX? */
1060 StartupCount
= (APIC_INTEGRATED(CPUMap
[Cpu
].APICVersion
)) ? 2 : 0;
1062 for (i
= 1; i
<= StartupCount
; i
++)
1064 /* It's a local APIC, so send STARTUP IPI */
1065 DPRINT("Sending startup signal %d\n", i
);
1067 APICWrite(APIC_ESR
, 0);
1070 APICSendIPI(Cpu
, APIC_DM_STARTUP
| ((COMMON_AREA
+ PAGE_SIZE
) >> 12)|APIC_ICR0_LEVEL_DEASSERT
);
1072 /* Wait up to 10ms for IPI to be delivered */
1076 KeStallExecutionProcessor(10);
1078 /* Check Delivery Status */
1079 DeliveryStatus
= APICRead(APIC_ICR0
) & APIC_ICR0_DS
;
1082 } while ((DeliveryStatus
) && (j
< 1000));
1084 KeStallExecutionProcessor(200);
1087 * Due to the Pentium erratum 3AP.
1091 APICRead(APIC_SIVR
);
1092 APICWrite(APIC_ESR
, 0);
1095 AcceptStatus
= APICRead(APIC_ESR
) & APIC_ESR_MASK
;
1097 if (DeliveryStatus
|| AcceptStatus
)
1105 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu
);
1110 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu
);
1113 if (!(DeliveryStatus
|| AcceptStatus
))
1116 /* Wait no more than 5 seconds for processor to boot */
1117 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu
);
1119 /* Wait no more than 5 seconds */
1120 for (j
= 0; j
< 50000; j
++)
1122 if (CPUMap
[Cpu
].Flags
& CPU_ENABLED
)
1126 KeStallExecutionProcessor(100);
1130 if (CPUMap
[Cpu
].Flags
& CPU_ENABLED
)
1132 DbgPrint("CPU %d is now running\n", Cpu
);
1136 DbgPrint("Initialization of CPU %d failed\n", Cpu
);
1140 DPRINT("Debug bytes are:\n");
1142 for (j
= 0; j
< 4; j
++)
1144 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1145 Common
->Debug
[j
*4+0],
1146 Common
->Debug
[j
*4+1],
1147 Common
->Debug
[j
*4+2],
1148 Common
->Debug
[j
*4+3]);