Reorganise HAL so multiple HAL versions can be built in parallel
[reactos.git] / reactos / hal / halx86 / mp / apic.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2004 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: apic.c,v 1.1 2004/12/03 20:10:44 gvg Exp $
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 <ddk/ntddk.h>
29 #include <internal/i386/ps.h>
30
31 #include <hal.h>
32 #include <halirq.h>
33 #include <mps.h>
34 #include <apic.h>
35
36 #define NDEBUG
37 #include <internal/debug.h>
38
39 BOOLEAN VerifyLocalAPIC(VOID);
40 VOID APICCalibrateTimer(ULONG CPU);
41
42 extern VOID MpsTimerInterrupt(VOID);
43 extern VOID MpsErrorInterrupt(VOID);
44 extern VOID MpsSpuriousInterrupt(VOID);
45 extern VOID MpsIpiInterrupt(VOID);
46
47 extern ULONG APICMode; /* APIC mode at startup */
48 extern PULONG BIOSBase; /* Virtual address of BIOS data segment */
49 extern PULONG CommonBase; /* Virtual address of common area */
50 extern ULONG BootCPU; /* Bootstrap processor */
51 extern ULONG OnlineCPUs; /* Bitmask of online CPUs */
52
53 extern CHAR *APstart, *APend;
54 extern VOID (*APflush)(VOID);
55
56 #define CMOS_READ(address) ({ \
57 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
58 READ_PORT_UCHAR((PUCHAR)0x71)); \
59 })
60
61 #define CMOS_WRITE(address, value) ({ \
62 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
63 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
64 })
65
66 #define BIOS_AREA 0x0
67 #define COMMON_AREA 0x2000
68
69
70 extern CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */
71
72 PULONG APICBase = (PULONG)APIC_DEFAULT_BASE; /* Virtual address of local APIC */
73
74 /* For debugging */
75 ULONG lastregr[MAX_CPU];
76 ULONG lastvalr[MAX_CPU];
77 ULONG lastregw[MAX_CPU];
78 ULONG lastvalw[MAX_CPU];
79
80 ULONG APICGetMaxLVT(VOID)
81 {
82 ULONG tmp, ver, maxlvt;
83
84 tmp = APICRead(APIC_VER);
85 ver = GET_APIC_VERSION(tmp);
86 /* 82489DXs do not report # of LVT entries. */
87 maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(tmp) : 2;
88
89 return maxlvt;
90 }
91
92 VOID APICClear(VOID)
93 {
94 ULONG tmp, maxlvt;
95
96 maxlvt = APICGetMaxLVT();
97
98 /*
99 * Careful: we have to set masks only first to deassert
100 * any level-triggered sources.
101 */
102
103 if (maxlvt >= 3)
104 {
105 tmp = ERROR_VECTOR;
106 APICWrite(APIC_LVT3, tmp | APIC_LVT3_MASKED);
107 }
108
109 tmp = APICRead(APIC_LVTT);
110 APICWrite(APIC_LVTT, tmp | APIC_LVT_MASKED);
111
112 tmp = APICRead(APIC_LINT0);
113 APICWrite(APIC_LINT0, tmp | APIC_LVT_MASKED);
114
115 tmp = APICRead(APIC_LINT1);
116 APICWrite(APIC_LINT1, tmp | APIC_LVT_MASKED);
117
118 if (maxlvt >= 4)
119 {
120 tmp = APICRead(APIC_LVTPC);
121 APICWrite(APIC_LVTPC, tmp | APIC_LVT_MASKED);
122 }
123 #if 0
124 if (maxlvt >= 5)
125 {
126 tmp = APICRead(APIC_LVTTHMR);
127 APICWrite(APIC_LVTTHMR, tmp | APIC_LVT_MASKED);
128 }
129 #endif
130 /*
131 * Clean APIC state for other OSs:
132 */
133 APICWrite(APIC_LVTT, APIC_LVT_MASKED);
134 APICWrite(APIC_LINT0, APIC_LVT_MASKED);
135 APICWrite(APIC_LINT1, APIC_LVT_MASKED);
136
137 if (maxlvt >= 3)
138 {
139 APICWrite(APIC_LVT3, APIC_LVT3_MASKED);
140 }
141
142 if (maxlvt >= 4)
143 {
144 APICWrite(APIC_LVTPC, APIC_LVT_MASKED);
145 }
146 #if 0
147 if (maxlvt >= 5)
148 {
149 APICWrite(APIC_LVTTHMR, APIC_LVT_MASKED);
150 }
151 #endif
152 }
153
154 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */
155 VOID EnableSMPMode(VOID)
156 {
157 /*
158 * Do not trust the local APIC being empty at bootup.
159 */
160 APICClear();
161
162 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
163 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x01);
164 }
165
166 /* Disable symetric I/O mode ie. go to PIC mode */
167 inline VOID DisableSMPMode(VOID)
168 {
169 /*
170 * Put the board back into PIC mode (has an effect
171 * only on certain older boards). Note that APIC
172 * interrupts, including IPIs, won't work beyond
173 * this point! The only exception are INIT IPIs.
174 */
175 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
176 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x00);
177 }
178
179 VOID DumpESR(VOID)
180 {
181 ULONG tmp;
182
183 if (APICGetMaxLVT() > 3)
184 {
185 APICWrite(APIC_ESR, 0);
186 }
187 tmp = APICRead(APIC_ESR);
188 DbgPrint("ESR %08x\n", tmp);
189 }
190
191
192 VOID APICDisable(VOID)
193 {
194 ULONG tmp;
195
196 APICClear();
197
198 /*
199 * Disable APIC (implies clearing of registers for 82489DX!).
200 */
201 tmp = APICRead(APIC_SIVR);
202 tmp &= ~APIC_SIVR_ENABLE;
203 APICWrite(APIC_SIVR, tmp);
204 }
205
206 VOID HaliInitBSP(VOID)
207 {
208 PUSHORT ps;
209 static BOOLEAN BSPInitialized = FALSE;
210
211 /* Only initialize the BSP once */
212 if (BSPInitialized)
213 {
214 KEBUGCHECK(0);
215 return;
216 }
217
218 BSPInitialized = TRUE;
219
220 DPRINT("APIC is mapped at 0x%X\n", APICBase);
221
222 if (VerifyLocalAPIC())
223 {
224 DPRINT("APIC found\n");
225 }
226 else
227 {
228 DPRINT("No APIC found\n");
229 KEBUGCHECK(0);
230 }
231
232 if (APICMode == amPIC)
233 {
234 EnableSMPMode();
235 }
236
237 APICSetup();
238
239 /* BIOS data segment */
240 BIOSBase = (PULONG)BIOS_AREA;
241
242 /* Area for communicating with the APs */
243 CommonBase = (PULONG)COMMON_AREA;
244
245 /* Copy bootstrap code to common area */
246 memcpy((PVOID)((ULONG)CommonBase + PAGE_SIZE),
247 &APstart,
248 (ULONG)&APend - (ULONG)&APstart + 1);
249
250 /* Set shutdown code */
251 CMOS_WRITE(0xF, 0xA);
252
253 /* Set warm reset vector */
254 ps = (PUSHORT)((ULONG)BIOSBase + 0x467);
255 *ps = (COMMON_AREA + PAGE_SIZE) & 0xF;
256
257 ps = (PUSHORT)((ULONG)BIOSBase + 0x469);
258 *ps = (COMMON_AREA + PAGE_SIZE) >> 4;
259
260 /* Calibrate APIC timer */
261 APICCalibrateTimer(BootCPU);
262 }
263
264 volatile inline ULONG _APICRead(ULONG Offset)
265 {
266 PULONG p;
267
268 p = (PULONG)((ULONG)APICBase + Offset);
269 return *p;
270 }
271
272 #if 0
273 inline VOID APICWrite(ULONG Offset,
274 ULONG Value)
275 {
276 PULONG p;
277
278 p = (PULONG)((ULONG)APICBase + Offset);
279
280 *p = Value;
281 }
282 #else
283 inline VOID APICWrite(ULONG Offset,
284 ULONG Value)
285 {
286 PULONG p;
287 ULONG CPU = (_APICRead(APIC_ID) & APIC_ID_MASK) >> 24;
288
289 lastregw[CPU] = Offset;
290 lastvalw[CPU] = Value;
291
292 p = (PULONG)((ULONG)APICBase + Offset);
293
294 *p = Value;
295 }
296 #endif
297
298
299 #if 0
300 volatile inline ULONG APICRead(ULONG Offset)
301 {
302 PULONG p;
303
304 p = (PULONG)((ULONG)APICBase + Offset);
305 return *p;
306 }
307 #else
308 volatile inline ULONG APICRead(ULONG Offset)
309 {
310 PULONG p;
311 ULONG CPU = (_APICRead(APIC_ID) & APIC_ID_MASK) >> 24;
312
313 lastregr[CPU] = Offset;
314 lastvalr[CPU] = 0;
315
316 p = (PULONG)((ULONG)APICBase + Offset);
317
318 lastvalr[CPU] = *p;
319 return lastvalr[CPU];
320 }
321 #endif
322
323 inline VOID APICSendEOI(VOID)
324 {
325 // Send the EOI
326 APICWrite(APIC_EOI, 0);
327 }
328
329 static VOID APICDumpBit(ULONG base)
330 {
331 ULONG v, i, j;
332
333 DbgPrint("0123456789abcdef0123456789abcdef\n");
334 for (i = 0; i < 8; i++)
335 {
336 v = APICRead(base + i*0x10);
337 for (j = 0; j < 32; j++)
338 {
339 if (v & (1<<j))
340 DbgPrint("1");
341 else
342 DbgPrint("0");
343 }
344 DbgPrint("\n");
345 }
346 }
347
348
349 VOID APICDump(VOID)
350 /*
351 * Dump the contents of the local APIC registers
352 */
353 {
354 ULONG v, ver, maxlvt;
355 ULONG r1, r2, w1, w2;
356 ULONG CPU = ThisCPU();;
357
358
359
360 r1 = lastregr[CPU];
361 r2 = lastvalr[CPU];
362 w1 = lastregw[CPU];
363 w2 = lastvalw[CPU];
364
365 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
366 v = APICRead(APIC_ID);
367 DbgPrint("... ID : %08x (%01x) ", v, GET_APIC_ID(v));
368 v = APICRead(APIC_VER);
369 DbgPrint("... VERSION: %08x\n", v);
370 ver = GET_APIC_VERSION(v);
371 maxlvt = APICGetMaxLVT();
372
373 v = APICRead(APIC_TPR);
374 DbgPrint("... TPR : %08x (%02x)", v, v & ~0);
375
376 if (APIC_INTEGRATED(ver))
377 {
378 /* !82489DX */
379 v = APICRead(APIC_APR);
380 DbgPrint("... APR : %08x (%02x)\n", v, v & ~0);
381 v = APICRead(APIC_PPR);
382 DbgPrint("... PPR : %08x\n", v);
383 }
384
385 v = APICRead(APIC_EOI);
386 DbgPrint("... EOI : %08x ! ", v);
387 v = APICRead(APIC_LDR);
388 DbgPrint("... LDR : %08x\n", v);
389 v = APICRead(APIC_DFR);
390 DbgPrint("... DFR : %08x ! ", v);
391 v = APICRead(APIC_SIVR);
392 DbgPrint("... SIVR : %08x\n", v);
393
394 if (0)
395 {
396 DbgPrint("... ISR field:\n");
397 APICDumpBit(APIC_ISR);
398 DbgPrint("... TMR field:\n");
399 APICDumpBit(APIC_TMR);
400 DbgPrint("... IRR field:\n");
401 APICDumpBit(APIC_IRR);
402 }
403
404 if (APIC_INTEGRATED(ver))
405 {
406 /* !82489DX */
407 if (maxlvt > 3)
408 {
409 /* Due to the Pentium erratum 3AP. */
410 APICWrite(APIC_ESR, 0);
411 }
412 v = APICRead(APIC_ESR);
413 DbgPrint("... ESR : %08x\n", v);
414 }
415
416 v = APICRead(APIC_ICR0);
417 DbgPrint("... ICR0 : %08x ! ", v);
418 v = APICRead(APIC_ICR1);
419 DbgPrint("... ICR1 : %08x ! ", v);
420
421 v = APICRead(APIC_LVTT);
422 DbgPrint("... LVTT : %08x\n", v);
423
424 if (maxlvt > 3)
425 {
426 /* PC is LVT#4. */
427 v = APICRead(APIC_LVTPC);
428 DbgPrint("... LVTPC : %08x ! ", v);
429 }
430 v = APICRead(APIC_LINT0);
431 DbgPrint("... LINT0 : %08x ! ", v);
432 v = APICRead(APIC_LINT1);
433 DbgPrint("... LINT1 : %08x\n", v);
434
435 if (maxlvt > 2)
436 {
437 v = APICRead(APIC_LVT3);
438 DbgPrint("... LVT3 : %08x\n", v);
439 }
440
441 v = APICRead(APIC_ICRT);
442 DbgPrint("... ICRT : %08x ! ", v);
443 v = APICRead(APIC_CCRT);
444 DbgPrint("... CCCT : %08x ! ", v);
445 v = APICRead(APIC_TDCR);
446 DbgPrint("... TDCR : %08x\n", v);
447 DbgPrint("\n");
448 DbgPrint("Last register read (offset): 0x%08X\n", r1);
449 DbgPrint("Last register read (value): 0x%08X\n", r2);
450 DbgPrint("Last register written (offset): 0x%08X\n", w1);
451 DbgPrint("Last register written (value): 0x%08X\n", w2);
452 DbgPrint("\n");
453 }
454
455 BOOLEAN VerifyLocalAPIC(VOID)
456 {
457 UINT reg0, reg1;
458 CHECKPOINT1;
459 /* The version register is read-only in a real APIC */
460 reg0 = APICRead(APIC_VER);
461 DPRINT1("Getting VERSION: %x\n", reg0);
462 APICWrite(APIC_VER, reg0 ^ APIC_VER_MASK);
463 reg1 = APICRead(APIC_VER);
464 DPRINT1("Getting VERSION: %x\n", reg1);
465
466 /*
467 * The two version reads above should print the same
468 * numbers. If the second one is different, then we
469 * poke at a non-APIC.
470 */
471
472 if (reg1 != reg0)
473 {
474 return FALSE;
475 }
476
477 /*
478 * Check if the version looks reasonably.
479 */
480 reg1 = GET_APIC_VERSION(reg0);
481 if (reg1 == 0x00 || reg1 == 0xff)
482 {
483 return FALSE;
484 }
485 reg1 = APICGetMaxLVT();
486 if (reg1 < 0x02 || reg1 == 0xff)
487 {
488 return FALSE;
489 }
490
491 /*
492 * The ID register is read/write in a real APIC.
493 */
494 reg0 = APICRead(APIC_ID);
495 DPRINT1("Getting ID: %x\n", reg0);
496 APICWrite(APIC_ID, reg0 ^ APIC_ID_MASK);
497 reg1 = APICRead(APIC_ID);
498 DPRINT1("Getting ID: %x\n", reg1);
499 APICWrite(APIC_ID, reg0);
500 if (reg1 != (reg0 ^ APIC_ID_MASK))
501 {
502 return FALSE;
503 }
504
505 return TRUE;
506 }
507
508 VOID APICSendIPI(ULONG Target, ULONG Mode)
509 {
510 ULONG tmp, i, flags;
511
512 /* save flags and disable interrupts */
513 Ki386SaveFlags(flags);
514 Ki386DisableInterrupts();
515
516 /* Wait up to 100ms for the APIC to become ready */
517 for (i = 0; i < 10000; i++)
518 {
519 tmp = APICRead(APIC_ICR0);
520 /* Check Delivery Status */
521 if ((tmp & APIC_ICR0_DS) == 0)
522 break;
523 KeStallExecutionProcessor(10);
524 }
525
526 if (i == 10000)
527 {
528 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
529 }
530
531 /* Setup the APIC to deliver the IPI */
532 DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target), Target);
533 APICWrite(APIC_ICR1, SET_APIC_DEST_FIELD(Target));
534
535 if (Target == APIC_TARGET_SELF)
536 {
537 Mode |= APIC_ICR0_DESTS_SELF;
538 }
539 else if (Target == APIC_TARGET_ALL)
540 {
541 Mode |= APIC_ICR0_DESTS_ALL;
542 }
543 else if (Target == APIC_TARGET_ALL_BUT_SELF)
544 {
545 Mode |= APIC_ICR0_DESTS_ALL_BUT_SELF;
546 }
547 else
548 {
549 Mode |= APIC_ICR0_DESTS_FIELD;
550 }
551
552 /* Now, fire off the IPI */
553 APICWrite(APIC_ICR0, Mode);
554
555 /* Wait up to 100ms for the APIC to become ready */
556 for (i = 0; i < 10000; i++)
557 {
558 tmp = APICRead(APIC_ICR0);
559 /* Check Delivery Status */
560 if ((tmp & APIC_ICR0_DS) == 0)
561 break;
562 KeStallExecutionProcessor(10);
563 }
564
565 if (i == 10000)
566 {
567 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
568 }
569 Ki386RestoreFlags(flags);
570 }
571
572 VOID APICSetup(VOID)
573 {
574 ULONG CPU, tmp;
575
576 CPU = ThisCPU();
577
578 // APICDump();
579
580 DPRINT1("CPU%d:\n", CPU);
581 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID)));
582 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR)));
583 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR));
584
585 /*
586 * Intel recommends to set DFR, LDR and TPR before enabling
587 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
588 * document number 292116). So here it goes...
589 */
590
591 /*
592 * Put the APIC into flat delivery mode.
593 * Must be "all ones" explicitly for 82489DX.
594 */
595 APICWrite(APIC_DFR, 0xFFFFFFFF);
596
597 /*
598 * Set up the logical destination ID.
599 */
600 tmp = APICRead(APIC_LDR);
601 tmp &= ~APIC_LDR_MASK;
602 /*
603 * FIXME:
604 * This works only up to 8 CPU's
605 */
606 tmp |= (1 << (KeGetCurrentProcessorNumber() + 24));
607 APICWrite(APIC_LDR, tmp);
608
609
610 DPRINT1("CPU%d:\n", CPU);
611 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID)));
612 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR)));
613 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR));
614 DPRINT1("%d\n", CPUMap[CPU].APICId);
615
616 /* Accept only higher interrupts */
617 APICWrite(APIC_TPR, 0xef);
618
619 /* Enable local APIC */
620 tmp = APICRead(APIC_SIVR);
621 tmp &= ~0xff;
622 tmp |= APIC_SIVR_ENABLE;
623
624 #if 0
625 tmp &= ~APIC_SIVR_FOCUS;
626 #else
627 tmp |= APIC_SIVR_FOCUS;
628 #endif
629
630 /* Set spurious interrupt vector */
631 tmp |= SPURIOUS_VECTOR;
632 APICWrite(APIC_SIVR, tmp);
633
634 /*
635 * Set up LVT0, LVT1:
636 *
637 * set up through-local-APIC on the BP's LINT0. This is not
638 * strictly necessery in pure symmetric-IO mode, but sometimes
639 * we delegate interrupts to the 8259A.
640 */
641 tmp = APICRead(APIC_LINT0) & APIC_LVT_MASKED;
642 if (CPU == BootCPU && (APICMode == amPIC || !tmp))
643 {
644 tmp = APIC_DM_EXTINT;
645 DPRINT1("enabled ExtINT on CPU#%d\n", CPU);
646 }
647 else
648 {
649 tmp = APIC_DM_EXTINT | APIC_LVT_MASKED;
650 DPRINT1("masked ExtINT on CPU#%d\n", CPU);
651 }
652 APICWrite(APIC_LINT0, tmp);
653
654
655 /*
656 * Only the BSP should see the LINT1 NMI signal, obviously.
657 */
658 if (CPU == BootCPU)
659 {
660 tmp = APIC_DM_NMI;
661 }
662 else
663 {
664 tmp = APIC_DM_NMI | APIC_LVT_MASKED;
665 }
666 if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion))
667 {
668 /* 82489DX */
669 tmp |= APIC_LVT_LEVEL_TRIGGER;
670 }
671 APICWrite(APIC_LINT1, tmp);
672
673 if (APIC_INTEGRATED(CPUMap[CPU].APICVersion))
674 {
675 /* !82489DX */
676 if (APICGetMaxLVT() > 3)
677 {
678 /* Due to the Pentium erratum 3AP */
679 APICWrite(APIC_ESR, 0);
680 }
681
682 tmp = APICRead(APIC_ESR);
683 DPRINT("ESR value before enabling vector: 0x%X\n", tmp);
684
685 /* Enable sending errors */
686 tmp = ERROR_VECTOR;
687 APICWrite(APIC_LVT3, tmp);
688
689 /*
690 * Spec says clear errors after enabling vector
691 */
692 if (APICGetMaxLVT() > 3)
693 {
694 APICWrite(APIC_ESR, 0);
695 }
696 tmp = APICRead(APIC_ESR);
697 DPRINT("ESR value after enabling vector: 0x%X\n", tmp);
698 }
699 }
700
701 VOID APICSyncArbIDs(VOID)
702 {
703 ULONG i, tmp;
704
705 /* Wait up to 100ms for the APIC to become ready */
706 for (i = 0; i < 10000; i++)
707 {
708 tmp = APICRead(APIC_ICR0);
709 /* Check Delivery Status */
710 if ((tmp & APIC_ICR0_DS) == 0)
711 break;
712 KeStallExecutionProcessor(10);
713 }
714
715 if (i == 10000)
716 {
717 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
718 }
719
720 DPRINT("Synchronizing Arb IDs.\n");
721 APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT);
722 }
723
724 VOID MpsErrorHandler(VOID)
725 {
726 ULONG tmp1, tmp2;
727
728 APICDump();
729
730 tmp1 = APICRead(APIC_ESR);
731 APICWrite(APIC_ESR, 0);
732 tmp2 = APICRead(APIC_ESR);
733 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
734
735 /*
736 * Acknowledge the interrupt
737 */
738 APICSendEOI();
739
740 /* Here is what the APIC error bits mean:
741 * 0: Send CS error
742 * 1: Receive CS error
743 * 2: Send accept error
744 * 3: Receive accept error
745 * 4: Reserved
746 * 5: Send illegal vector
747 * 6: Received illegal vector
748 * 7: Illegal register address
749 */
750 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
751 for (;;);
752 }
753
754 VOID MpsSpuriousHandler(VOID)
755 {
756 ULONG tmp;
757
758 DPRINT1("Spurious interrupt on CPU(%d)\n", ThisCPU());
759
760 tmp = APICRead(APIC_ISR + ((SPURIOUS_VECTOR & ~0x1f) >> 1));
761 if (tmp & (1 << (SPURIOUS_VECTOR & 0x1f)))
762 {
763 APICSendEOI();
764 return;
765 }
766 #if 0
767 /* No need to send EOI here */
768 APICDump();
769 #endif
770 }
771
772 VOID MpsIpiHandler(VOID)
773 {
774 KIRQL oldIrql;
775
776 HalBeginSystemInterrupt(IPI_VECTOR,
777 VECTOR2IRQL(IPI_VECTOR),
778 &oldIrql);
779 Ki386EnableInterrupts();
780 #if 0
781 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n",
782 __FILE__,__LINE__, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
783 #endif
784
785 KiIpiServiceRoutine(NULL, NULL);
786
787 #if 0
788 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber());
789 #endif
790
791 Ki386DisableInterrupts();
792 HalEndSystemInterrupt(oldIrql, 0);
793 }
794
795 VOID
796 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
797 PKTRAP_FRAME TrapFrame)
798 {
799 TrapFrame->Gs = (USHORT)IrqTrapFrame->Gs;
800 TrapFrame->Fs = (USHORT)IrqTrapFrame->Fs;
801 TrapFrame->Es = (USHORT)IrqTrapFrame->Es;
802 TrapFrame->Ds = (USHORT)IrqTrapFrame->Ds;
803 TrapFrame->Eax = IrqTrapFrame->Eax;
804 TrapFrame->Ecx = IrqTrapFrame->Ecx;
805 TrapFrame->Edx = IrqTrapFrame->Edx;
806 TrapFrame->Ebx = IrqTrapFrame->Ebx;
807 TrapFrame->Esp = IrqTrapFrame->Esp;
808 TrapFrame->Ebp = IrqTrapFrame->Ebp;
809 TrapFrame->Esi = IrqTrapFrame->Esi;
810 TrapFrame->Edi = IrqTrapFrame->Edi;
811 TrapFrame->Eip = IrqTrapFrame->Eip;
812 TrapFrame->Cs = IrqTrapFrame->Cs;
813 TrapFrame->Eflags = IrqTrapFrame->Eflags;
814 }
815
816 VOID
817 MpsTimerHandler(ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
818 {
819 KIRQL oldIrql;
820 KTRAP_FRAME KernelTrapFrame;
821 #if 0
822 ULONG CPU;
823 static ULONG Count[MAX_CPU] = {0,};
824 #endif
825 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR,
826 VECTOR2IRQL(LOCAL_TIMER_VECTOR),
827 &oldIrql);
828 Ki386EnableInterrupts();
829
830 #if 0
831 CPU = ThisCPU();
832 if ((Count[CPU] % 100) == 0)
833 {
834 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__, __LINE__, CPU, oldIrql,Trapframe->Eip, KeGetCurrentKPCR());
835 }
836 Count[CPU]++;
837 #endif
838
839 MpsIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
840 if (KeGetCurrentProcessorNumber() == 0)
841 {
842 KeUpdateSystemTime(&KernelTrapFrame, oldIrql);
843 }
844 else
845 {
846 KeUpdateRunTime(&KernelTrapFrame, oldIrql);
847 }
848
849 Ki386DisableInterrupts();
850 HalEndSystemInterrupt (oldIrql, 0);
851 }
852
853 /* EOF */