Sync with trunk r43123
[reactos.git] / reactos / hal / halx86 / mp / apic.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2004, 2005 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: hal/halx86/apic.c
24 * PURPOSE:
25 * PROGRAMMER:
26 */
27
28 /* INCLUDE ***********************************************************************/
29
30 #include <hal.h>
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 */
33 #define NDEBUG
34 #include <debug.h>
35
36 /* GLOBALS ***********************************************************************/
37
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 */
42
43 #ifdef CONFIG_SMP
44 PULONG BIOSBase; /* Virtual address of BIOS data segment */
45 PULONG CommonBase; /* Virtual address of common area */
46 #endif
47
48 PULONG APICBase = (PULONG)APIC_DEFAULT_BASE; /* Virtual address of local APIC */
49
50 ULONG APICMode; /* APIC mode at startup */
51
52 /* For debugging */
53 ULONG lastregr[MAX_CPU];
54 ULONG lastvalr[MAX_CPU];
55 ULONG lastregw[MAX_CPU];
56 ULONG lastvalw[MAX_CPU];
57
58 #ifdef CONFIG_SMP
59 #include <pshpack1.h>
60 typedef struct _COMMON_AREA_INFO
61 {
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;
68 #include <poppack.h>
69 #endif
70
71 CHAR *APstart, *APend;
72
73 #define BIOS_AREA 0x0
74 #define COMMON_AREA 0x2000
75
76 #define HZ (100)
77 #define APIC_DIVISOR (16)
78
79 #define CMOS_READ(address) { \
80 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
81 READ_PORT_UCHAR((PUCHAR)0x71)); \
82 }
83
84 #define CMOS_WRITE(address, value) { \
85 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
86 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
87 }
88
89 extern ULONG_PTR KernelBase;
90
91 /* FUNCTIONS *********************************************************************/
92
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);
99
100 ULONG APICGetMaxLVT(VOID)
101 {
102 ULONG tmp, ver, maxlvt;
103
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;
108
109 return maxlvt;
110 }
111
112 VOID APICClear(VOID)
113 {
114 ULONG tmp, maxlvt;
115
116 maxlvt = APICGetMaxLVT();
117
118 /*
119 * Careful: we have to set masks only first to deassert
120 * any level-triggered sources.
121 */
122
123 if (maxlvt >= 3)
124 {
125 tmp = ERROR_VECTOR;
126 APICWrite(APIC_LVT3, tmp | APIC_LVT3_MASKED);
127 }
128
129 tmp = APICRead(APIC_LVTT);
130 APICWrite(APIC_LVTT, tmp | APIC_LVT_MASKED);
131
132 tmp = APICRead(APIC_LINT0);
133 APICWrite(APIC_LINT0, tmp | APIC_LVT_MASKED);
134
135 tmp = APICRead(APIC_LINT1);
136 APICWrite(APIC_LINT1, tmp | APIC_LVT_MASKED);
137
138 if (maxlvt >= 4)
139 {
140 tmp = APICRead(APIC_LVTPC);
141 APICWrite(APIC_LVTPC, tmp | APIC_LVT_MASKED);
142 }
143 #if 0
144 if (maxlvt >= 5)
145 {
146 tmp = APICRead(APIC_LVTTHMR);
147 APICWrite(APIC_LVTTHMR, tmp | APIC_LVT_MASKED);
148 }
149 #endif
150 /*
151 * Clean APIC state for other OSs:
152 */
153 APICWrite(APIC_LVTT, APIC_LVT_MASKED);
154 APICWrite(APIC_LINT0, APIC_LVT_MASKED);
155 APICWrite(APIC_LINT1, APIC_LVT_MASKED);
156
157 if (maxlvt >= 3)
158 {
159 APICWrite(APIC_LVT3, APIC_LVT3_MASKED);
160 }
161
162 if (maxlvt >= 4)
163 {
164 APICWrite(APIC_LVTPC, APIC_LVT_MASKED);
165 }
166 #if 0
167 if (maxlvt >= 5)
168 {
169 APICWrite(APIC_LVTTHMR, APIC_LVT_MASKED);
170 }
171 #endif
172 }
173
174 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */
175 VOID EnableApicMode(VOID)
176 {
177 /*
178 * Do not trust the local APIC being empty at bootup.
179 */
180 APICClear();
181
182 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
183 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x01);
184 }
185
186 /* Disable symetric I/O mode ie. go to PIC mode */
187 __inline VOID DisableSMPMode(VOID)
188 {
189 /*
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.
194 */
195 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
196 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x00);
197 }
198
199 VOID DumpESR(VOID)
200 {
201 ULONG tmp;
202
203 if (APICGetMaxLVT() > 3)
204 {
205 APICWrite(APIC_ESR, 0);
206 }
207 tmp = APICRead(APIC_ESR);
208 DbgPrint("ESR %08x\n", tmp);
209 }
210
211
212 VOID APICDisable(VOID)
213 {
214 ULONG tmp;
215
216 APICClear();
217
218 /*
219 * Disable APIC (implies clearing of registers for 82489DX!).
220 */
221 tmp = APICRead(APIC_SIVR);
222 tmp &= ~APIC_SIVR_ENABLE;
223 APICWrite(APIC_SIVR, tmp);
224 }
225
226 static VOID APICDumpBit(ULONG base)
227 {
228 ULONG v, i, j;
229
230 DbgPrint("0123456789abcdef0123456789abcdef\n");
231 for (i = 0; i < 8; i++)
232 {
233 v = APICRead(base + i*0x10);
234 for (j = 0; j < 32; j++)
235 {
236 if (v & (1<<j))
237 DbgPrint("1");
238 else
239 DbgPrint("0");
240 }
241 DbgPrint("\n");
242 }
243 }
244
245
246 VOID APICDump(VOID)
247 /*
248 * Dump the contents of the local APIC registers
249 */
250 {
251 ULONG v, ver, maxlvt;
252 ULONG r1, r2, w1, w2;
253 ULONG CPU = ThisCPU();
254
255
256 r1 = lastregr[CPU];
257 r2 = lastvalr[CPU];
258 w1 = lastregw[CPU];
259 w2 = lastvalw[CPU];
260
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();
268
269 v = APICRead(APIC_TPR);
270 DbgPrint("... TPR : %08x (%02x)", v, v & ~0);
271
272 if (APIC_INTEGRATED(ver))
273 {
274 /* !82489DX */
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);
279 }
280
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);
289
290 if (0)
291 {
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);
298 }
299
300 if (APIC_INTEGRATED(ver))
301 {
302 /* !82489DX */
303 if (maxlvt > 3)
304 {
305 /* Due to the Pentium erratum 3AP. */
306 APICWrite(APIC_ESR, 0);
307 }
308 v = APICRead(APIC_ESR);
309 DbgPrint("... ESR : %08x\n", v);
310 }
311
312 v = APICRead(APIC_ICR0);
313 DbgPrint("... ICR0 : %08x ! ", v);
314 v = APICRead(APIC_ICR1);
315 DbgPrint("... ICR1 : %08x ! ", v);
316
317 v = APICRead(APIC_LVTT);
318 DbgPrint("... LVTT : %08x\n", v);
319
320 if (maxlvt > 3)
321 {
322 /* PC is LVT#4. */
323 v = APICRead(APIC_LVTPC);
324 DbgPrint("... LVTPC : %08x ! ", v);
325 }
326 v = APICRead(APIC_LINT0);
327 DbgPrint("... LINT0 : %08x ! ", v);
328 v = APICRead(APIC_LINT1);
329 DbgPrint("... LINT1 : %08x\n", v);
330
331 if (maxlvt > 2)
332 {
333 v = APICRead(APIC_LVT3);
334 DbgPrint("... LVT3 : %08x\n", v);
335 }
336
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);
343 DbgPrint("\n");
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);
348 DbgPrint("\n");
349 }
350
351 BOOLEAN VerifyLocalAPIC(VOID)
352 {
353 SIZE_T reg0, reg1;
354 LARGE_INTEGER MsrValue;
355
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);
362
363 /*
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.
367 */
368
369 if (reg1 != reg0)
370 {
371 return FALSE;
372 }
373
374 /*
375 * Check if the version looks reasonably.
376 */
377 reg1 = GET_APIC_VERSION(reg0);
378 if (reg1 == 0x00 || reg1 == 0xff)
379 {
380 return FALSE;
381 }
382 reg1 = APICGetMaxLVT();
383 if (reg1 < 0x02 || reg1 == 0xff)
384 {
385 return FALSE;
386 }
387
388 /*
389 * The ID register is read/write in a real APIC.
390 */
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))
398 {
399 return FALSE;
400 }
401
402 MsrValue.QuadPart = __readmsr(0x1B /*MSR_IA32_APICBASE*/);
403
404 if (!(MsrValue.LowPart & /*MSR_IA32_APICBASE_ENABLE*/(1<<11)))
405 {
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);
410 }
411
412
413
414 return TRUE;
415 }
416
417 #ifdef CONFIG_SMP
418 VOID APICSendIPI(ULONG Target, ULONG Mode)
419 {
420 ULONG tmp, i, flags;
421
422 /* save flags and disable interrupts */
423 flags = __readeflags();
424 _disable();
425
426 /* Wait up to 100ms for the APIC to become ready */
427 for (i = 0; i < 10000; i++)
428 {
429 tmp = APICRead(APIC_ICR0);
430 /* Check Delivery Status */
431 if ((tmp & APIC_ICR0_DS) == 0)
432 break;
433 KeStallExecutionProcessor(10);
434 }
435
436 if (i == 10000)
437 {
438 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
439 }
440
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));
444
445 if (Target == APIC_TARGET_SELF)
446 {
447 Mode |= APIC_ICR0_DESTS_SELF;
448 }
449 else if (Target == APIC_TARGET_ALL)
450 {
451 Mode |= APIC_ICR0_DESTS_ALL;
452 }
453 else if (Target == APIC_TARGET_ALL_BUT_SELF)
454 {
455 Mode |= APIC_ICR0_DESTS_ALL_BUT_SELF;
456 }
457 else
458 {
459 Mode |= APIC_ICR0_DESTS_FIELD;
460 }
461
462 /* Now, fire off the IPI */
463 APICWrite(APIC_ICR0, Mode);
464
465 /* Wait up to 100ms for the APIC to become ready */
466 for (i = 0; i < 10000; i++)
467 {
468 tmp = APICRead(APIC_ICR0);
469 /* Check Delivery Status */
470 if ((tmp & APIC_ICR0_DS) == 0)
471 break;
472 KeStallExecutionProcessor(10);
473 }
474
475 if (i == 10000)
476 {
477 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
478 }
479 __writeeflags(flags);
480 }
481 #endif
482
483 VOID APICSetup(VOID)
484 {
485 ULONG CPU, tmp;
486
487 CPU = ThisCPU();
488
489 // APICDump();
490
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));
495
496 /*
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...
500 */
501
502 /*
503 * Put the APIC into flat delivery mode.
504 * Must be "all ones" explicitly for 82489DX.
505 */
506 APICWrite(APIC_DFR, 0xFFFFFFFF);
507
508 /*
509 * Set up the logical destination ID.
510 */
511 tmp = APICRead(APIC_LDR);
512 tmp &= ~APIC_LDR_MASK;
513 /*
514 * FIXME:
515 * This works only up to 8 CPU's
516 */
517 tmp |= (1 << (KeGetCurrentProcessorNumber() + 24));
518 APICWrite(APIC_LDR, tmp);
519
520
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);
526
527 /* Accept only higher interrupts */
528 APICWrite(APIC_TPR, 0xef);
529
530 /* Enable local APIC */
531 tmp = APICRead(APIC_SIVR);
532 tmp &= ~0xff;
533 tmp |= APIC_SIVR_ENABLE;
534
535 #if 0
536 tmp &= ~APIC_SIVR_FOCUS;
537 #else
538 tmp |= APIC_SIVR_FOCUS;
539 #endif
540
541 /* Set spurious interrupt vector */
542 tmp |= SPURIOUS_VECTOR;
543 APICWrite(APIC_SIVR, tmp);
544
545 /*
546 * Set up LVT0, LVT1:
547 *
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.
551 */
552 tmp = APICRead(APIC_LINT0) & APIC_LVT_MASKED;
553 if (CPU == BootCPU && (APICMode == amPIC || !tmp))
554 {
555 tmp = APIC_DM_EXTINT;
556 DPRINT1("enabled ExtINT on CPU#%d\n", CPU);
557 }
558 else
559 {
560 tmp = APIC_DM_EXTINT | APIC_LVT_MASKED;
561 DPRINT1("masked ExtINT on CPU#%d\n", CPU);
562 }
563 APICWrite(APIC_LINT0, tmp);
564
565 /*
566 * Only the BSP should see the LINT1 NMI signal, obviously.
567 */
568 if (CPU == BootCPU)
569 {
570 tmp = APIC_DM_NMI;
571 }
572 else
573 {
574 tmp = APIC_DM_NMI | APIC_LVT_MASKED;
575 }
576 if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion))
577 {
578 /* 82489DX */
579 tmp |= APIC_LVT_LEVEL_TRIGGER;
580 }
581 APICWrite(APIC_LINT1, tmp);
582
583 if (APIC_INTEGRATED(CPUMap[CPU].APICVersion))
584 {
585 /* !82489DX */
586 if (APICGetMaxLVT() > 3)
587 {
588 /* Due to the Pentium erratum 3AP */
589 APICWrite(APIC_ESR, 0);
590 }
591
592 tmp = APICRead(APIC_ESR);
593 DPRINT("ESR value before enabling vector: 0x%X\n", tmp);
594
595 /* Enable sending errors */
596 tmp = ERROR_VECTOR;
597 APICWrite(APIC_LVT3, tmp);
598
599 /*
600 * Spec says clear errors after enabling vector
601 */
602 if (APICGetMaxLVT() > 3)
603 {
604 APICWrite(APIC_ESR, 0);
605 }
606 tmp = APICRead(APIC_ESR);
607 DPRINT("ESR value after enabling vector: 0x%X\n", tmp);
608 }
609 }
610 #ifdef CONFIG_SMP
611 VOID APICSyncArbIDs(VOID)
612 {
613 ULONG i, tmp;
614
615 /* Wait up to 100ms for the APIC to become ready */
616 for (i = 0; i < 10000; i++)
617 {
618 tmp = APICRead(APIC_ICR0);
619 /* Check Delivery Status */
620 if ((tmp & APIC_ICR0_DS) == 0)
621 break;
622 KeStallExecutionProcessor(10);
623 }
624
625 if (i == 10000)
626 {
627 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
628 }
629
630 DPRINT("Synchronizing Arb IDs.\n");
631 APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT);
632 }
633 #endif
634
635 VOID MpsErrorHandler(VOID)
636 {
637 ULONG tmp1, tmp2;
638
639 APICDump();
640
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);
645
646 /*
647 * Acknowledge the interrupt
648 */
649 APICSendEOI();
650
651 /* Here is what the APIC error bits mean:
652 * 0: Send CS error
653 * 1: Receive CS error
654 * 2: Send accept error
655 * 3: Receive accept error
656 * 4: Reserved
657 * 5: Send illegal vector
658 * 6: Received illegal vector
659 * 7: Illegal register address
660 */
661 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
662 for (;;);
663 }
664
665 VOID MpsSpuriousHandler(VOID)
666 {
667 ULONG tmp;
668
669 DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU());
670
671 tmp = APICRead(APIC_ISR + ((SPURIOUS_VECTOR & ~0x1f) >> 1));
672 if (tmp & (1 << (SPURIOUS_VECTOR & 0x1f)))
673 {
674 APICSendEOI();
675 return;
676 }
677 #if 0
678 /* No need to send EOI here */
679 APICDump();
680 #endif
681 }
682
683 #ifdef CONFIG_SMP
684 VOID MpsIpiHandler(VOID)
685 {
686 KIRQL oldIrql;
687
688 HalBeginSystemInterrupt(IPI_LEVEL,
689 IPI_VECTOR,
690 &oldIrql);
691 _enable();
692 #if 0
693 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n",
694 __FILE__,__LINE__, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
695 #endif
696
697 KiIpiServiceRoutine(NULL, NULL);
698
699 #if 0
700 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber());
701 #endif
702
703 _disable();
704 HalEndSystemInterrupt(oldIrql, 0);
705 }
706 #endif
707
708 VOID
709 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
710 PKTRAP_FRAME TrapFrame)
711 {
712 #ifdef _M_AMD64
713 UNIMPLEMENTED;
714 #else
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;
730 #endif
731 }
732
733 VOID
734 MpsTimerHandler(ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
735 {
736 KIRQL oldIrql;
737 KTRAP_FRAME KernelTrapFrame;
738 #if 0
739 ULONG CPU;
740 static ULONG Count[MAX_CPU] = {0,};
741 #endif
742 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR,
743 PROFILE_LEVEL,
744 &oldIrql);
745 _enable();
746
747 #if 0
748 CPU = ThisCPU();
749 if ((Count[CPU] % 100) == 0)
750 {
751 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__, __LINE__, CPU, oldIrql,Trapframe->Eip, KeGetPcr());
752 }
753 Count[CPU]++;
754 #endif
755
756 /* FIXME: SMP is totally broken */
757 MpsIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
758 if (KeGetCurrentProcessorNumber() == 0)
759 {
760 //KeUpdateSystemTime(&KernelTrapFrame, oldIrql);
761 }
762 else
763 {
764 //KeUpdateRunTime(&KernelTrapFrame, oldIrql);
765 }
766
767 _disable();
768 HalEndSystemInterrupt (oldIrql, 0);
769 }
770
771 VOID APICSetupLVTT(ULONG ClockTicks)
772 {
773 ULONG tmp;
774
775 tmp = GET_APIC_VERSION(APICRead(APIC_VER));
776 if (!APIC_INTEGRATED(tmp))
777 {
778 tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;
779 }
780 else
781 {
782 /* Periodic timer */
783 tmp = APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;
784 }
785 APICWrite(APIC_LVTT, tmp);
786
787 tmp = APICRead(APIC_TDCR);
788 tmp &= ~(APIC_TDCR_1 | APIC_TIMER_BASE_DIV);
789 tmp |= APIC_TDCR_16;
790 APICWrite(APIC_TDCR, tmp);
791 APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR);
792 }
793
794 VOID
795 APICCalibrateTimer(ULONG CPU)
796 {
797 ULARGE_INTEGER t1, t2;
798 LONG tt1, tt2;
799 BOOLEAN TSCPresent;
800
801 DPRINT("Calibrating APIC timer for CPU %d\n", CPU);
802
803 APICSetupLVTT(1000000000);
804
805 TSCPresent = KeGetCurrentPrcb()->FeatureBits & KF_RDTSC ? TRUE : FALSE;
806
807 /*
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)
811 */
812 //WaitFor8254Wraparound();
813
814 /*
815 * We wrapped around just now. Let's start
816 */
817 if (TSCPresent)
818 {
819 t1.QuadPart = (LONGLONG)__rdtsc();
820 }
821 tt1 = APICRead(APIC_CCRT);
822
823 //WaitFor8254Wraparound();
824
825
826 tt2 = APICRead(APIC_CCRT);
827 if (TSCPresent)
828 {
829 t2.QuadPart = (LONGLONG)__rdtsc();
830 CPUMap[CPU].CoreSpeed = (HZ * (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;
835 }
836
837 CPUMap[CPU].BusSpeed = (HZ * (long)(tt1 - tt2) * APIC_DIVISOR);
838
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
843
844 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
845 CPUMap[CPU].BusSpeed/1000000,
846 CPUMap[CPU].BusSpeed%1000000);
847 }
848
849 VOID
850 SetInterruptGate(ULONG index, ULONG_PTR address)
851 {
852 #ifdef _M_AMD64
853 KIDTENTRY64 *idt;
854
855 idt = &KeGetPcr()->IdtBase[index];
856
857 idt->OffsetLow = address & 0xffff;
858 idt->Selector = KGDT_64_R0_CODE;
859 idt->IstIndex = 0;
860 idt->Reserved0 = 0;
861 idt->Type = 0x0e;
862 idt->Dpl = 0;
863 idt->Present = 1;
864 idt->OffsetMiddle = (address >> 16) & 0xffff;
865 idt->OffsetHigh = address >> 32;
866 idt->Reserved1 = 0;
867 idt->Alignment = 0;
868 #else
869 KIDTENTRY *idt;
870 KIDT_ACCESS Access;
871
872 /* Set the IDT Access Bits */
873 Access.Reserved = 0;
874 Access.Present = 1;
875 Access.Dpl = 0; /* Kernel-Mode */
876 Access.SystemSegmentFlag = 0;
877 Access.SegmentType = I386_INTERRUPT_GATE;
878
879 idt = (KIDTENTRY*)((ULONG)KeGetPcr()->IDT + index * sizeof(KIDTENTRY));
880 idt->Offset = address & 0xffff;
881 idt->Selector = KGDT_R0_CODE;
882 idt->Access = Access.Value;
883 idt->ExtendedOffset = address >> 16;
884 #endif
885 }
886
887 VOID HaliInitBSP(VOID)
888 {
889 #ifdef CONFIG_SMP
890 PUSHORT ps;
891 #endif
892
893 static BOOLEAN BSPInitialized = FALSE;
894
895 /* Only initialize the BSP once */
896 if (BSPInitialized)
897 {
898 ASSERT(FALSE);
899 return;
900 }
901
902 BSPInitialized = TRUE;
903
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);
908 #ifdef CONFIG_SMP
909 SetInterruptGate(IPI_VECTOR, (ULONG_PTR)MpsIpiInterrupt);
910 #endif
911 DPRINT1("APIC is mapped at 0x%p\n", (PVOID)APICBase);
912
913 if (VerifyLocalAPIC())
914 {
915 DPRINT("APIC found\n");
916 }
917 else
918 {
919 DPRINT1("No APIC found\n");
920 ASSERT(FALSE);
921 }
922
923 if (APICMode == amPIC)
924 {
925 EnableApicMode();
926 }
927
928 APICSetup();
929
930 #ifdef CONFIG_SMP
931 /* BIOS data segment */
932 BIOSBase = (PULONG)BIOS_AREA;
933
934 /* Area for communicating with the APs */
935 CommonBase = (PULONG)COMMON_AREA;
936
937 /* Copy bootstrap code to common area */
938 memcpy((PVOID)((ULONG_PTR)CommonBase + PAGE_SIZE),
939 &APstart,
940 (ULONG_PTR)&APend - (ULONG_PTR)&APstart + 1);
941
942 /* Set shutdown code */
943 CMOS_WRITE(0xF, 0xA);
944
945 /* Set warm reset vector */
946 ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x467);
947 *ps = (COMMON_AREA + PAGE_SIZE) & 0xF;
948
949 ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x469);
950 *ps = (COMMON_AREA + PAGE_SIZE) >> 4;
951 #endif
952
953 /* Calibrate APIC timer */
954 APICCalibrateTimer(BootCPU);
955 }
956
957 #ifdef CONFIG_SMP
958 VOID
959 HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack)
960 {
961 ULONG tmp, maxlvt;
962 PCOMMON_AREA_INFO Common;
963 ULONG StartupCount;
964 ULONG i, j;
965 ULONG DeliveryStatus = 0;
966 ULONG AcceptStatus = 0;
967
968 if (Cpu >= MAX_CPU ||
969 Cpu >= CPUCount ||
970 OnlineCPUs & (1 << Cpu))
971 {
972 ASSERT(FALSE);
973 }
974 DPRINT1("Attempting to boot CPU %d\n", Cpu);
975
976 /* Send INIT IPI */
977
978 APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_ASSERT);
979
980 KeStallExecutionProcessor(200);
981
982 /* Deassert INIT */
983
984 APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_DEASSERT);
985
986 if (APIC_INTEGRATED(CPUMap[Cpu].APICVersion))
987 {
988 /* Clear APIC errors */
989 APICWrite(APIC_ESR, 0);
990 tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK);
991 }
992
993 Common = (PCOMMON_AREA_INFO)CommonBase;
994
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;
1003
1004 DPRINT1("%x %x %x %x\n", Common->Stack, Common->PageDirectory, Common->NtProcessStartup, Common->PaeModeEnabled);
1005
1006 DPRINT("Cpu %d got stack at 0x%X\n", Cpu, Common->Stack);
1007 #if 0
1008 for (j = 0; j < 16; j++)
1009 {
1010 Common->Debug[j] = 0;
1011 }
1012 #endif
1013
1014 maxlvt = APICGetMaxLVT();
1015
1016 /* Is this a local APIC or an 82489DX? */
1017 StartupCount = (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) ? 2 : 0;
1018
1019 for (i = 1; i <= StartupCount; i++)
1020 {
1021 /* It's a local APIC, so send STARTUP IPI */
1022 DPRINT("Sending startup signal %d\n", i);
1023 /* Clear errors */
1024 APICWrite(APIC_ESR, 0);
1025 APICRead(APIC_ESR);
1026
1027 APICSendIPI(Cpu, APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12)|APIC_ICR0_LEVEL_DEASSERT);
1028
1029 /* Wait up to 10ms for IPI to be delivered */
1030 j = 0;
1031 do
1032 {
1033 KeStallExecutionProcessor(10);
1034
1035 /* Check Delivery Status */
1036 DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS;
1037
1038 j++;
1039 } while ((DeliveryStatus) && (j < 1000));
1040
1041 KeStallExecutionProcessor(200);
1042
1043 /*
1044 * Due to the Pentium erratum 3AP.
1045 */
1046 if (maxlvt > 3)
1047 {
1048 APICRead(APIC_SIVR);
1049 APICWrite(APIC_ESR, 0);
1050 }
1051
1052 AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK;
1053
1054 if (DeliveryStatus || AcceptStatus)
1055 {
1056 break;
1057 }
1058 }
1059
1060 if (DeliveryStatus)
1061 {
1062 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu);
1063 }
1064
1065 if (AcceptStatus)
1066 {
1067 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu);
1068 }
1069
1070 if (!(DeliveryStatus || AcceptStatus))
1071 {
1072
1073 /* Wait no more than 5 seconds for processor to boot */
1074 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu);
1075
1076 /* Wait no more than 5 seconds */
1077 for (j = 0; j < 50000; j++)
1078 {
1079 if (CPUMap[Cpu].Flags & CPU_ENABLED)
1080 {
1081 break;
1082 }
1083 KeStallExecutionProcessor(100);
1084 }
1085 }
1086
1087 if (CPUMap[Cpu].Flags & CPU_ENABLED)
1088 {
1089 DbgPrint("CPU %d is now running\n", Cpu);
1090 }
1091 else
1092 {
1093 DbgPrint("Initialization of CPU %d failed\n", Cpu);
1094 }
1095
1096 #if 0
1097 DPRINT("Debug bytes are:\n");
1098
1099 for (j = 0; j < 4; j++)
1100 {
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]);
1106 }
1107
1108 #endif
1109 }
1110
1111 #endif
1112
1113 /* EOF */