Commented out call to PsDispatchThread(THREAD_STATE_RUNNABLE) in order to get MP...
[reactos.git] / reactos / hal / halx86 / mp.c
1 /* $Id: mp.c,v 1.5 2002/12/09 18:42:41 robd Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/hal/x86/mp.c
6 * PURPOSE: Intel MultiProcessor specification support
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * NOTES: Parts adapted from linux SMP code
10 * UPDATE HISTORY:
11 * 22/05/1998 DW Created
12 * 12/04/2001 CSH Added MultiProcessor specification support
13 */
14
15 /* INCLUDES *****************************************************************/
16
17 #include <ddk/ntddk.h>
18 #include <roscfg.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 #ifdef MP
24
25 #include <hal.h>
26 #include <mps.h>
27
28 #include <internal/ntoskrnl.h>
29 #include <internal/i386/segment.h>
30 #include <internal/ke.h>
31 #include <internal/ps.h>
32
33 /*
34 Address of area to be used for communication between Application
35 Processors (APs) and the BootStrap Processor (BSP)
36 */
37 #define COMMON_AREA 0x2000
38
39 #define BIOS_AREA 0x0
40
41 typedef struct __attribute__((packed)) _COMMON_AREA_INFO
42 {
43 ULONG Stack; /* Location of AP stack */
44 ULONG Debug[16]; /* For debugging */
45 } COMMON_AREA_INFO, *PCOMMON_AREA_INFO;
46
47 CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */
48 ULONG CPUCount; /* Total number of CPUs */
49 ULONG OnlineCPUs; /* Bitmask of online CPUs */
50
51 UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */
52 UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */
53
54 IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */
55 ULONG IOAPICCount; /* Number of I/O APICs in the system */
56
57 MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */
58 ULONG IRQVectorMap[MAX_IRQ_SOURCE]; /* IRQ to vector map */
59 ULONG IRQCount; /* Number of IRQs */
60
61 ULONG APICMode; /* APIC mode at startup */
62 ULONG BootCPU; /* Bootstrap processor */
63 ULONG NextCPU; /* Next CPU to start */
64 PULONG BIOSBase; /* Virtual address of BIOS data segment */
65 PULONG APICBase; /* Virtual address of local APIC */
66 PULONG CommonBase; /* Virtual address of common area */
67
68 extern CHAR *APstart, *APend;
69 extern VOID (*APflush)(VOID);
70
71 extern VOID MpsTimerInterrupt(VOID);
72 extern VOID MpsErrorInterrupt(VOID);
73 extern VOID MpsSpuriousInterrupt(VOID);
74
75 #define CMOS_READ(address) ({ \
76 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
77 READ_PORT_UCHAR((PUCHAR)0x71)); \
78 })
79
80 #define CMOS_WRITE(address, value) ({ \
81 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
82 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
83 })
84
85 BOOLEAN MPSInitialized = FALSE; /* Is the MP system initialized? */
86
87 VOID APICDisable(VOID);
88 static VOID APICSyncArbIDs(VOID);
89
90 /* For debugging */
91 ULONG lastregr = 0;
92 ULONG lastvalr = 0;
93 ULONG lastregw = 0;
94 ULONG lastvalw = 0;
95
96 #endif /* MP */
97
98
99 BOOLEAN BSPInitialized = FALSE; /* Is the BSP initialized? */
100
101
102 /* FUNCTIONS *****************************************************************/
103
104 #ifdef MP
105
106 /* Functions for handling 8259A PICs */
107
108 VOID Disable8259AIrq(
109 ULONG irq)
110 {
111 ULONG tmp;
112
113 if (irq & 8) {
114 tmp = READ_PORT_UCHAR((PUCHAR)0xA1);
115 tmp |= (1 << irq);
116 WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp);
117 } else {
118 tmp = READ_PORT_UCHAR((PUCHAR)0x21);
119 tmp |= (1 << irq);
120 WRITE_PORT_UCHAR((PUCHAR)0x21, tmp);
121 }
122 }
123
124
125 VOID Enable8259AIrq(
126 ULONG irq)
127 {
128 ULONG tmp;
129
130 if (irq & 8) {
131 tmp = READ_PORT_UCHAR((PUCHAR)0xA1);
132 tmp &= ~(1 << irq);
133 WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp);
134 } else {
135 tmp = READ_PORT_UCHAR((PUCHAR)0x21);
136 tmp &= ~(1 << irq);
137 WRITE_PORT_UCHAR((PUCHAR)0x21, tmp);
138 }
139 }
140
141
142 /* Functions for handling I/O APICs */
143
144 volatile ULONG IOAPICRead(
145 ULONG Apic,
146 ULONG Offset)
147 {
148 PULONG Base;
149
150 Base = (PULONG)IOAPICMap[Apic].ApicAddress;
151
152 *Base = Offset;
153 return *((PULONG)((ULONG)Base + IOAPIC_IOWIN));
154 }
155
156
157 VOID IOAPICWrite(
158 ULONG Apic,
159 ULONG Offset,
160 ULONG Value)
161 {
162 PULONG Base;
163
164 Base = (PULONG)IOAPICMap[Apic].ApicAddress;
165
166 *Base = Offset;
167 *((PULONG)((ULONG)Base + IOAPIC_IOWIN)) = Value;
168 }
169
170
171 VOID IOAPICClearPin(
172 ULONG Apic,
173 ULONG Pin)
174 {
175 IOAPIC_ROUTE_ENTRY Entry;
176
177 /*
178 * Disable it in the IO-APIC irq-routing table
179 */
180 memset(&Entry, 0, sizeof(Entry));
181 Entry.mask = 1;
182 IOAPICWrite(Apic, IOAPIC_REDTBL + 2 * Pin, *(((PULONG)&Entry) + 0));
183 IOAPICWrite(Apic, IOAPIC_REDTBL + 1 + 2 * Pin, *(((PULONG)&Entry) + 1));
184 }
185
186 static VOID IOAPICClear(
187 ULONG Apic)
188 {
189 ULONG Pin;
190
191 for (Pin = 0; Pin < IOAPICMap[Apic].EntryCount; Pin++)
192 IOAPICClearPin(Apic, Pin);
193 }
194
195 static VOID IOAPICClearAll(
196 VOID)
197 {
198 ULONG Apic;
199
200 for (Apic = 0; Apic < IOAPICCount; Apic++)
201 IOAPICClear(Apic);
202 }
203
204 /* This is performance critical and should probably be done in assembler */
205 VOID IOAPICMaskIrq(
206 ULONG Apic,
207 ULONG Irq)
208 {
209 IOAPIC_ROUTE_ENTRY Entry;
210
211 *((PULONG)&Entry) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq);
212 Entry.mask = 1;
213 IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *((PULONG)&Entry));
214 }
215
216
217 /* This is performance critical and should probably be done in assembler */
218 VOID IOAPICUnmaskIrq(
219 ULONG Apic,
220 ULONG Irq)
221 {
222 IOAPIC_ROUTE_ENTRY Entry;
223
224 *((PULONG)&Entry) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq);
225 Entry.mask = 0;
226 IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *((PULONG)&Entry));
227 }
228
229 static VOID
230 IOAPICSetupIds(VOID)
231 {
232 ULONG tmp, apic, i;
233 UCHAR old_id;
234
235 /*
236 * Set the IOAPIC ID to the value stored in the MPC table.
237 */
238 for (apic = 0; apic < IOAPICCount; apic++) {
239
240 /* Read the register 0 value */
241 tmp = IOAPICRead(apic, IOAPIC_ID);
242
243 old_id = IOAPICMap[apic].ApicId;
244
245 if (IOAPICMap[apic].ApicId >= 0xf) {
246 DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
247 apic, IOAPICMap[apic].ApicId);
248 DPRINT1("... fixing up to %d. (tell your hw vendor)\n",
249 GET_IOAPIC_ID(tmp));
250 IOAPICMap[apic].ApicId = GET_IOAPIC_ID(tmp);
251 }
252
253 /*
254 * We need to adjust the IRQ routing table
255 * if the ID changed.
256 */
257 if (old_id != IOAPICMap[apic].ApicId)
258 for (i = 0; i < IRQCount; i++)
259 if (IRQMap[i].DstApicId == old_id)
260 IRQMap[i].DstApicId = IOAPICMap[apic].ApicId;
261
262 /*
263 * Read the right value from the MPC table and
264 * write it into the ID register.
265 */
266 DPRINT("Changing IO-APIC physical APIC ID to %d\n",
267 IOAPICMap[apic].ApicId);
268
269 tmp &= ~IOAPIC_ID_MASK;
270 tmp |= SET_IOAPIC_ID(IOAPICMap[apic].ApicId);
271
272 IOAPICWrite(apic, IOAPIC_ID, tmp);
273
274 /*
275 * Sanity check
276 */
277 tmp = IOAPICRead(apic, 0);
278 if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId) {
279 DPRINT1("Could not set I/O APIC ID!\n");
280 KeBugCheck(0);
281 }
282 }
283 }
284
285
286 /*
287 * EISA Edge/Level control register, ELCR
288 */
289 static ULONG EISA_ELCR(
290 ULONG irq)
291 {
292 if (irq < 16) {
293 PUCHAR port = (PUCHAR)(0x4d0 + (irq >> 3));
294 return (READ_PORT_UCHAR(port) >> (irq & 7)) & 1;
295 }
296 DPRINT("Broken MPtable reports ISA irq %d\n", irq);
297 return 0;
298 }
299
300 /* EISA interrupts are always polarity zero and can be edge or level
301 * trigger depending on the ELCR value. If an interrupt is listed as
302 * EISA conforming in the MP table, that means its trigger type must
303 * be read in from the ELCR */
304
305 #define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq))
306 #define default_EISA_polarity(idx) (0)
307
308 /* ISA interrupts are always polarity zero edge triggered,
309 * when listed as conforming in the MP table. */
310
311 #define default_ISA_trigger(idx) (0)
312 #define default_ISA_polarity(idx) (0)
313
314 /* PCI interrupts are always polarity one level triggered,
315 * when listed as conforming in the MP table. */
316
317 #define default_PCI_trigger(idx) (1)
318 #define default_PCI_polarity(idx) (1)
319
320 /* MCA interrupts are always polarity zero level triggered,
321 * when listed as conforming in the MP table. */
322
323 #define default_MCA_trigger(idx) (1)
324 #define default_MCA_polarity(idx) (0)
325
326 static ULONG IRQPolarity(
327 ULONG idx)
328 {
329 ULONG bus = IRQMap[idx].SrcBusId;
330 ULONG polarity;
331
332 /*
333 * Determine IRQ line polarity (high active or low active):
334 */
335 switch (IRQMap[idx].IrqFlag & 3)
336 {
337 case 0: /* conforms, ie. bus-type dependent polarity */
338 {
339 switch (BUSMap[bus])
340 {
341 case MP_BUS_ISA: /* ISA pin */
342 {
343 polarity = default_ISA_polarity(idx);
344 break;
345 }
346 case MP_BUS_EISA: /* EISA pin */
347 {
348 polarity = default_EISA_polarity(idx);
349 break;
350 }
351 case MP_BUS_PCI: /* PCI pin */
352 {
353 polarity = default_PCI_polarity(idx);
354 break;
355 }
356 case MP_BUS_MCA: /* MCA pin */
357 {
358 polarity = default_MCA_polarity(idx);
359 break;
360 }
361 default:
362 {
363 DPRINT("Broken BIOS!!\n");
364 polarity = 1;
365 break;
366 }
367 }
368 break;
369 }
370 case 1: /* high active */
371 {
372 polarity = 0;
373 break;
374 }
375 case 2: /* reserved */
376 {
377 DPRINT("Broken BIOS!!\n");
378 polarity = 1;
379 break;
380 }
381 case 3: /* low active */
382 {
383 polarity = 1;
384 break;
385 }
386 default: /* invalid */
387 {
388 DPRINT("Broken BIOS!!\n");
389 polarity = 1;
390 break;
391 }
392 }
393 return polarity;
394 }
395
396 static ULONG IRQTrigger(
397 ULONG idx)
398 {
399 ULONG bus = IRQMap[idx].SrcBusId;
400 ULONG trigger;
401
402 /*
403 * Determine IRQ trigger mode (edge or level sensitive):
404 */
405 switch ((IRQMap[idx].IrqFlag >> 2) & 3)
406 {
407 case 0: /* conforms, ie. bus-type dependent */
408 {
409 switch (BUSMap[bus])
410 {
411 case MP_BUS_ISA: /* ISA pin */
412 {
413 trigger = default_ISA_trigger(idx);
414 break;
415 }
416 case MP_BUS_EISA: /* EISA pin */
417 {
418 trigger = default_EISA_trigger(idx);
419 break;
420 }
421 case MP_BUS_PCI: /* PCI pin */
422 {
423 trigger = default_PCI_trigger(idx);
424 break;
425 }
426 case MP_BUS_MCA: /* MCA pin */
427 {
428 trigger = default_MCA_trigger(idx);
429 break;
430 }
431 default:
432 {
433 DPRINT("Broken BIOS!!\n");
434 trigger = 1;
435 break;
436 }
437 }
438 break;
439 }
440 case 1: /* edge */
441 {
442 trigger = 0;
443 break;
444 }
445 case 2: /* reserved */
446 {
447 DPRINT("Broken BIOS!!\n");
448 trigger = 1;
449 break;
450 }
451 case 3: /* level */
452 {
453 trigger = 1;
454 break;
455 }
456 default: /* invalid */
457 {
458 DPRINT("Broken BIOS!!\n");
459 trigger = 0;
460 break;
461 }
462 }
463 return trigger;
464 }
465
466
467 static ULONG Pin2Irq(
468 ULONG idx,
469 ULONG apic,
470 ULONG pin)
471 {
472 ULONG irq, i;
473 ULONG bus = IRQMap[idx].SrcBusId;
474
475 /*
476 * Debugging check, we are in big trouble if this message pops up!
477 */
478 if (IRQMap[idx].DstApicInt != pin) {
479 DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n");
480 }
481
482 switch (BUSMap[bus])
483 {
484 case MP_BUS_ISA: /* ISA pin */
485 case MP_BUS_EISA:
486 case MP_BUS_MCA:
487 {
488 irq = IRQMap[idx].SrcBusIrq;
489 break;
490 }
491 case MP_BUS_PCI: /* PCI pin */
492 {
493 /*
494 * PCI IRQs are mapped in order
495 */
496 i = irq = 0;
497 while (i < apic)
498 irq += IOAPICMap[i++].EntryCount;
499 irq += pin;
500 break;
501 }
502 default:
503 {
504 DPRINT("Unknown bus type %d.\n",bus);
505 irq = 0;
506 break;
507 }
508 }
509
510 return irq;
511 }
512
513
514 /*
515 * Rough estimation of how many shared IRQs there are, can
516 * be changed anytime.
517 */
518 #define MAX_PLUS_SHARED_IRQS PIC_IRQS
519 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + PIC_IRQS)
520
521 /*
522 * This is performance-critical, we want to do it O(1)
523 *
524 * the indexing order of this array favors 1:1 mappings
525 * between pins and IRQs.
526 */
527
528 static struct irq_pin_list {
529 ULONG apic, pin, next;
530 } irq_2_pin[PIN_MAP_SIZE];
531
532 /*
533 * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
534 * shared ISA-space IRQs, so we have to support them. We are super
535 * fast in the common case, and fast for shared ISA-space IRQs.
536 */
537 static VOID AddPinToIrq(
538 ULONG irq,
539 ULONG apic,
540 ULONG pin)
541 {
542 static ULONG first_free_entry = PIC_IRQS;
543 struct irq_pin_list *entry = irq_2_pin + irq;
544
545 while (entry->next)
546 entry = irq_2_pin + entry->next;
547
548 if (entry->pin != -1) {
549 entry->next = first_free_entry;
550 entry = irq_2_pin + entry->next;
551 if (++first_free_entry >= PIN_MAP_SIZE) {
552 DPRINT1("Ohh no!");
553 KeBugCheck(0);
554 }
555 }
556 entry->apic = apic;
557 entry->pin = pin;
558 }
559
560
561 /*
562 * Find the IRQ entry number of a certain pin.
563 */
564 static ULONG IOAPICGetIrqEntry(
565 ULONG apic,
566 ULONG pin,
567 ULONG type)
568 {
569 ULONG i;
570
571 for (i = 0; i < IRQCount; i++)
572 if (IRQMap[i].IrqType == type &&
573 (IRQMap[i].DstApicId == IOAPICMap[apic].ApicId ||
574 IRQMap[i].DstApicId == MP_APIC_ALL) &&
575 IRQMap[i].DstApicInt == pin)
576 return i;
577
578 return -1;
579 }
580
581
582 static ULONG AssignIrqVector(
583 ULONG irq)
584 {
585 static ULONG current_vector = FIRST_DEVICE_VECTOR, vector_offset = 0;
586 ULONG vector;
587
588 /* There may already have been assigned a vector for this IRQ */
589 vector = IRQVectorMap[irq];
590 if (vector > 0)
591 return vector;
592
593 current_vector += 8;
594 if (current_vector > FIRST_SYSTEM_VECTOR) {
595 vector_offset++;
596 current_vector = FIRST_DEVICE_VECTOR + vector_offset;
597 } else if (current_vector == FIRST_SYSTEM_VECTOR) {
598 DPRINT1("Ran out of interrupt sources!");
599 KeBugCheck(0);
600 }
601
602 IRQVectorMap[irq] = current_vector;
603 return current_vector;
604 }
605
606
607 VOID IOAPICSetupIrqs(
608 VOID)
609 {
610 IOAPIC_ROUTE_ENTRY entry;
611 ULONG apic, pin, idx, irq, first_notcon = 1, vector;
612
613 DPRINT("Init IO_APIC IRQs\n");
614
615 for (apic = 0; apic < IOAPICCount; apic++) {
616 for (pin = 0; pin < IOAPICMap[apic].EntryCount; pin++) {
617
618 /*
619 * add it to the IO-APIC irq-routing table
620 */
621 memset(&entry,0,sizeof(entry));
622
623 entry.delivery_mode = APIC_DM_LOWEST;
624 entry.dest_mode = 1; /* logical delivery */
625 entry.mask = 0; /* enable IRQ */
626 entry.dest.logical.logical_dest = OnlineCPUs;
627
628 idx = IOAPICGetIrqEntry(apic,pin,INT_VECTORED);
629 if (idx == -1) {
630 if (first_notcon) {
631 DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap[apic].ApicId, pin);
632 first_notcon = 0;
633 } else {
634 DPRINT(", %d-%d\n", IOAPICMap[apic].ApicId, pin);
635 }
636 continue;
637 }
638
639 entry.trigger = IRQTrigger(idx);
640 entry.polarity = IRQPolarity(idx);
641
642 if (entry.trigger) {
643 entry.trigger = 1;
644 entry.mask = 1;
645 entry.dest.logical.logical_dest = OnlineCPUs;
646 }
647
648 irq = Pin2Irq(idx, apic, pin);
649 AddPinToIrq(irq, apic, pin);
650
651 vector = AssignIrqVector(irq);
652 entry.vector = vector;
653
654 if (irq == 0)
655 {
656 /* Mask timer IRQ */
657 entry.mask = 1;
658 }
659
660 if ((apic == 0) && (irq < 16))
661 Disable8259AIrq(irq);
662
663 IOAPICWrite(apic, IOAPIC_REDTBL+2*pin+1, *(((PULONG)&entry)+1));
664 IOAPICWrite(apic, IOAPIC_REDTBL+2*pin, *(((PULONG)&entry)+0));
665 }
666 }
667 }
668
669
670 static VOID IOAPICEnable(
671 VOID)
672 {
673 ULONG i, tmp;
674
675 for (i = 0; i < PIN_MAP_SIZE; i++) {
676 irq_2_pin[i].pin = -1;
677 irq_2_pin[i].next = 0;
678 }
679
680 /*
681 * The number of IO-APIC IRQ registers (== #pins):
682 */
683 for (i = 0; i < IOAPICCount; i++) {
684 tmp = IOAPICRead(i, IOAPIC_VER);
685 IOAPICMap[i].EntryCount = GET_IOAPIC_MRE(tmp) + 1;
686 }
687
688 /*
689 * Do not trust the IO-APIC being empty at bootup
690 */
691 IOAPICClearAll();
692 }
693
694 #if 0
695 static VOID IOAPICDisable(
696 VOID)
697 {
698 /*
699 * Clear the IO-APIC before rebooting
700 */
701 IOAPICClearAll();
702
703 APICDisable();
704 }
705 #endif
706
707
708 static VOID IOAPICSetup(
709 VOID)
710 {
711 IOAPICEnable();
712 IOAPICSetupIds();
713 if (0) {
714 // FIXME: This causes application processors to not boot if asked to
715 APICSyncArbIDs();
716 }
717 IOAPICSetupIrqs();
718 }
719
720
721 VOID IOAPICDump(VOID)
722 {
723 ULONG apic, i;
724 ULONG reg0, reg1, reg2;
725
726 DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount);
727 for (i = 0; i < IOAPICCount; i++) {
728 DbgPrint("Number of IO-APIC #%d registers: %d.\n",
729 IOAPICMap[i].ApicId,
730 IOAPICMap[i].EntryCount);
731 }
732
733 /*
734 * We are a bit conservative about what we expect. We have to
735 * know about every hardware change ASAP.
736 */
737 DbgPrint("Testing the IO APIC.......................\n");
738
739 for (apic = 0; apic < IOAPICCount; apic++) {
740
741 reg0 = IOAPICRead(apic, IOAPIC_ID);
742 reg1 = IOAPICRead(apic, IOAPIC_VER);
743 if (GET_IOAPIC_VERSION(reg1) >= 0x10) {
744 reg2 = IOAPICRead(apic, IOAPIC_ARB);
745 }
746
747 DbgPrint("\n");
748 DbgPrint("IO APIC #%d......\n", IOAPICMap[apic].ApicId);
749 DbgPrint(".... register #00: %08X\n", reg0);
750 DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0));
751 if (reg0 & 0xF0FFFFFF) {
752 DbgPrint(" WARNING: Unexpected IO-APIC\n");
753 }
754
755 DbgPrint(".... register #01: %08X\n", reg1);
756 i = GET_IOAPIC_MRE(reg1);
757
758 DbgPrint("....... : max redirection entries: %04X\n", i);
759 if ((i != 0x0f) && /* older (Neptune) boards */
760 (i != 0x17) && /* typical ISA+PCI boards */
761 (i != 0x1b) && /* Compaq Proliant boards */
762 (i != 0x1f) && /* dual Xeon boards */
763 (i != 0x22) && /* bigger Xeon boards */
764 (i != 0x2E) &&
765 (i != 0x3F)) {
766 DbgPrint(" WARNING: Unexpected IO-APIC\n");
767 }
768
769 i = GET_IOAPIC_VERSION(reg1);
770 DbgPrint("....... : IO APIC version: %04X\n", i);
771 if ((i != 0x01) && /* 82489DX IO-APICs */
772 (i != 0x10) && /* oldest IO-APICs */
773 (i != 0x11) && /* Pentium/Pro IO-APICs */
774 (i != 0x13)) { /* Xeon IO-APICs */
775 DbgPrint(" WARNING: Unexpected IO-APIC\n");
776 }
777
778 if (reg1 & 0xFF00FF00) {
779 DbgPrint(" WARNING: Unexpected IO-APIC\n");
780 }
781
782 if (GET_IOAPIC_VERSION(reg1) >= 0x10) {
783 DbgPrint(".... register #02: %08X\n", reg2);
784 DbgPrint("....... : arbitration: %02X\n",
785 GET_IOAPIC_ARB(reg2));
786 if (reg2 & 0xF0FFFFFF) {
787 DbgPrint(" WARNING: Unexpected IO-APIC\n");
788 }
789 }
790
791 DbgPrint(".... IRQ redirection table:\n");
792 DbgPrint(" NR Log Phy Mask Trig IRR Pol"
793 " Stat Dest Deli Vect: \n");
794
795 for (i = 0; i <= GET_IOAPIC_MRE(reg1); i++) {
796 IOAPIC_ROUTE_ENTRY entry;
797
798 *(((PULONG)&entry)+0) = IOAPICRead(apic, 0x10+i*2);
799 *(((PULONG)&entry)+1) = IOAPICRead(apic, 0x11+i*2);
800
801 DbgPrint(" %02x %03X %02X ",
802 i,
803 entry.dest.logical.logical_dest,
804 entry.dest.physical.physical_dest
805 );
806
807 DbgPrint("%C %C %1d %C %C %C %03X %02X\n",
808 (entry.mask == 0) ? 'U' : 'M', // Unmasked/masked
809 (entry.trigger == 0) ? 'E' : 'L', // Edge/level sensitive
810 entry.irr,
811 (entry.polarity == 0) ? 'H' : 'L', // Active high/active low
812 (entry.delivery_status == 0) ? 'I' : 'S', // Idle / send pending
813 (entry.dest_mode == 0) ? 'P' : 'L', // Physical logical
814 entry.delivery_mode,
815 entry.vector
816 );
817 }
818 }
819 DbgPrint("IRQ to pin mappings:\n");
820 for (i = 0; i < PIC_IRQS; i++) {
821 struct irq_pin_list *entry = irq_2_pin + i;
822 if (entry->pin < 0)
823 continue;
824 DbgPrint("IRQ%d ", i);
825 for (;;) {
826 DbgPrint("-> %d", entry->pin);
827 if (!entry->next)
828 break;
829 entry = irq_2_pin + entry->next;
830 }
831 if (i % 2) {
832 DbgPrint("\n");
833 } else {
834 DbgPrint(" ");
835 }
836 }
837
838 DbgPrint(".................................... done.\n");
839 }
840
841
842
843 /* Functions for handling local APICs */
844
845 #if 0
846 volatile inline ULONG APICRead(
847 ULONG Offset)
848 {
849 PULONG p;
850
851 p = (PULONG)((ULONG)APICBase + Offset);
852 return *p;
853 }
854 #else
855 volatile inline ULONG APICRead(
856 ULONG Offset)
857 {
858 PULONG p;
859
860 lastregr = Offset;
861 lastvalr = 0;
862
863 //DPRINT1("R(0x%X)", Offset);
864 p = (PULONG)((ULONG)APICBase + Offset);
865 lastvalr = *p;
866 //DPRINT1("(0x%08X)\n", *p);
867
868 return lastvalr;
869 }
870 #endif
871
872 #if 0
873 inline VOID APICWrite(
874 ULONG Offset,
875 ULONG Value)
876 {
877 PULONG p;
878
879 p = (PULONG)((ULONG)APICBase + Offset);
880
881 *p = Value;
882 }
883 #else
884 inline VOID APICWrite(
885 ULONG Offset,
886 ULONG Value)
887 {
888 PULONG p;
889
890 lastregw = Offset;
891 lastvalw = Value;
892
893 //DPRINT1("W(0x%X, 0x%08X)\n", Offset, Value);
894 p = (PULONG)((ULONG)APICBase + Offset);
895
896 *p = Value;
897 }
898 #endif
899
900
901 inline VOID APICSendEOI(VOID)
902 {
903 // Dummy read
904 APICRead(APIC_SIVR);
905 // Send the EOI
906 APICWrite(APIC_EOI, 0);
907 }
908
909
910 VOID DumpESR(VOID)
911 {
912 ULONG tmp;
913
914 if (CPUMap[ThisCPU()].MaxLVT > 3)
915 APICWrite(APIC_ESR, 0);
916 tmp = APICRead(APIC_ESR);
917 DbgPrint("ESR %08x\n", tmp);
918 }
919
920
921 ULONG APICGetMaxLVT(VOID)
922 {
923 ULONG tmp, ver, maxlvt;
924
925 tmp = APICRead(APIC_VER);
926 ver = GET_APIC_VERSION(tmp);
927 /* 82489DXs do not report # of LVT entries. */
928 maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(tmp) : 2;
929
930 return maxlvt;
931 }
932
933
934 static VOID APICClear(
935 VOID)
936 {
937 ULONG tmp, maxlvt;
938
939 maxlvt = CPUMap[ThisCPU()].MaxLVT;
940
941 /*
942 * Careful: we have to set masks only first to deassert
943 * any level-triggered sources.
944 */
945 tmp = APICRead(APIC_LVTT);
946 APICWrite(APIC_LVTT, tmp | APIC_LVT_MASKED);
947
948 tmp = APICRead(APIC_LINT0);
949 APICWrite(APIC_LINT0, tmp | APIC_LVT_MASKED);
950
951 tmp = APICRead(APIC_LINT1);
952 APICWrite(APIC_LINT1, tmp | APIC_LVT_MASKED);
953
954 if (maxlvt >= 3) {
955 tmp = APICRead(APIC_LVT3);
956 APICWrite(APIC_LVT3, tmp | APIC_LVT3_MASKED);
957 }
958
959 if (maxlvt >= 4) {
960 tmp = APICRead(APIC_LVTPC);
961 APICWrite(APIC_LVTPC, tmp | APIC_LVT_MASKED);
962 }
963
964 /*
965 * Clean APIC state for other OSs:
966 */
967 APICRead(APIC_SIVR); // Dummy read
968 APICWrite(APIC_LVTT, APIC_LVT_MASKED);
969
970 APICRead(APIC_SIVR); // Dummy read
971 APICWrite(APIC_LINT0, APIC_LVT_MASKED);
972
973 APICRead(APIC_SIVR); // Dummy read
974 APICWrite(APIC_LINT1, APIC_LVT_MASKED);
975
976 if (maxlvt >= 3) {
977 APICRead(APIC_SIVR); // Dummy read
978 APICWrite(APIC_LVT3, APIC_LVT3_MASKED);
979 }
980
981 if (maxlvt >= 4) {
982 APICRead(APIC_SIVR); // Dummy read
983 APICWrite(APIC_LVTPC, APIC_LVT_MASKED);
984 }
985 }
986
987 /* Enable symetric I/O mode ie. connect the BSP's
988 local APIC to INT and NMI lines */
989 inline VOID EnableSMPMode(
990 VOID)
991 {
992 /*
993 * Do not trust the local APIC being empty at bootup.
994 */
995 APICClear();
996
997 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
998 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x01);
999 }
1000
1001
1002 /* Disable symetric I/O mode ie. go to PIC mode */
1003 inline VOID DisableSMPMode(
1004 VOID)
1005 {
1006 /*
1007 * Put the board back into PIC mode (has an effect
1008 * only on certain older boards). Note that APIC
1009 * interrupts, including IPIs, won't work beyond
1010 * this point! The only exception are INIT IPIs.
1011 */
1012 WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
1013 WRITE_PORT_UCHAR((PUCHAR)0x23, 0x00);
1014 }
1015
1016
1017 VOID APICDisable(
1018 VOID)
1019 {
1020 ULONG tmp;
1021
1022 APICClear();
1023
1024 /*
1025 * Disable APIC (implies clearing of registers for 82489DX!).
1026 */
1027 tmp = APICRead(APIC_SIVR);
1028 tmp &= ~APIC_SIVR_ENABLE;
1029 APICWrite(APIC_SIVR, tmp);
1030 }
1031
1032
1033 inline ULONG ThisCPU(
1034 VOID)
1035 {
1036 return (APICRead(APIC_ID) & APIC_ID_MASK) >> 24;
1037 }
1038
1039
1040 static VOID APICDumpBit(ULONG base)
1041 {
1042 ULONG v, i, j;
1043
1044 DbgPrint("0123456789abcdef0123456789abcdef\n");
1045 for (i = 0; i < 8; i++) {
1046 APICRead(base + i*0x10);
1047 for (j = 0; j < 32; j++) {
1048 if (v & (1<<j))
1049 DbgPrint("1");
1050 else
1051 DbgPrint("0");
1052 }
1053 DbgPrint("\n");
1054 }
1055 }
1056
1057
1058 VOID APICDump(VOID)
1059 /*
1060 * Dump the contents of the local APIC registers
1061 */
1062 {
1063 ULONG v, ver, maxlvt;
1064 ULONG r1, r2, w1, w2;
1065
1066 r1 = lastregr;
1067 r2 = lastvalr;
1068 w1 = lastregw;
1069 w2 = lastvalw;
1070
1071 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
1072 v = APICRead(APIC_ID);
1073 DbgPrint("... ID : %08x (%01x) ", v, GET_APIC_ID(v));
1074 v = APICRead(APIC_VER);
1075 DbgPrint("... VERSION: %08x\n", v);
1076 ver = GET_APIC_VERSION(v);
1077 maxlvt = CPUMap[ThisCPU()].MaxLVT;
1078
1079 v = APICRead(APIC_TPR);
1080 DbgPrint("... TPR : %08x (%02x)", v, v & ~0);
1081
1082 if (APIC_INTEGRATED(ver)) { /* !82489DX */
1083 v = APICRead(APIC_APR);
1084 DbgPrint("... APR : %08x (%02x)\n", v, v & ~0);
1085 v = APICRead(APIC_PPR);
1086 DbgPrint("... PPR : %08x\n", v);
1087 }
1088
1089 v = APICRead(APIC_EOI);
1090 DbgPrint("... EOI : %08x ! ", v);
1091 v = APICRead(APIC_LDR);
1092 DbgPrint("... LDR : %08x\n", v);
1093 v = APICRead(APIC_DFR);
1094 DbgPrint("... DFR : %08x ! ", v);
1095 v = APICRead(APIC_SIVR);
1096 DbgPrint("... SIVR : %08x\n", v);
1097
1098 if (0)
1099 {
1100 DbgPrint("... ISR field:\n");
1101 APICDumpBit(APIC_ISR);
1102 DbgPrint("... TMR field:\n");
1103 APICDumpBit(APIC_TMR);
1104 DbgPrint("... IRR field:\n");
1105 APICDumpBit(APIC_IRR);
1106 }
1107
1108 if (APIC_INTEGRATED(ver)) { /* !82489DX */
1109 if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
1110 APICWrite(APIC_ESR, 0);
1111 v = APICRead(APIC_ESR);
1112 DbgPrint("... ESR : %08x\n", v);
1113 }
1114
1115 v = APICRead(APIC_ICR0);
1116 DbgPrint("... ICR0 : %08x ! ", v);
1117 v = APICRead(APIC_ICR1);
1118 DbgPrint("... ICR1 : %08x ! ", v);
1119
1120 v = APICRead(APIC_LVTT);
1121 DbgPrint("... LVTT : %08x\n", v);
1122
1123 if (maxlvt > 3) { /* PC is LVT#4. */
1124 v = APICRead(APIC_LVTPC);
1125 DbgPrint("... LVTPC : %08x ! ", v);
1126 }
1127 v = APICRead(APIC_LINT0);
1128 DbgPrint("... LINT0 : %08x ! ", v);
1129 v = APICRead(APIC_LINT1);
1130 DbgPrint("... LINT1 : %08x\n", v);
1131
1132 if (maxlvt > 2) {
1133 v = APICRead(APIC_LVT3);
1134 DbgPrint("... LVT3 : %08x\n", v);
1135 }
1136
1137 v = APICRead(APIC_ICRT);
1138 DbgPrint("... ICRT : %08x ! ", v);
1139 v = APICRead(APIC_CCRT);
1140 DbgPrint("... CCCT : %08x ! ", v);
1141 v = APICRead(APIC_TDCR);
1142 DbgPrint("... TDCR : %08x\n", v);
1143 DbgPrint("\n");
1144 DbgPrint("Last register read (offset): 0x%08X\n", r1);
1145 DbgPrint("Last register read (value): 0x%08X\n", r2);
1146 DbgPrint("Last register written (offset): 0x%08X\n", w1);
1147 DbgPrint("Last register written (value): 0x%08X\n", w2);
1148 DbgPrint("\n");
1149 }
1150
1151
1152 ULONG Read8254Timer(VOID)
1153 {
1154 ULONG Count;
1155
1156 WRITE_PORT_UCHAR((PUCHAR)0x43, 0x00);
1157 Count = READ_PORT_UCHAR((PUCHAR)0x40);
1158 Count |= READ_PORT_UCHAR((PUCHAR)0x40) << 8;
1159
1160 return Count;
1161 }
1162
1163
1164 VOID WaitFor8254Wraparound(VOID)
1165 {
1166 ULONG CurCount, PrevCount = ~0;
1167 LONG Delta;
1168
1169 CurCount = Read8254Timer();
1170
1171 do {
1172 PrevCount = CurCount;
1173 CurCount = Read8254Timer();
1174 Delta = CurCount - PrevCount;
1175
1176 /*
1177 * This limit for delta seems arbitrary, but it isn't, it's
1178 * slightly above the level of error a buggy Mercury/Neptune
1179 * chipset timer can cause.
1180 */
1181
1182 } while (Delta < 300);
1183 }
1184
1185 #define HZ (100)
1186 #define APIC_DIVISOR (16)
1187
1188 VOID APICSetupLVTT(
1189 ULONG ClockTicks)
1190 {
1191 ULONG tmp;
1192
1193 /* Periodic timer */
1194 tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
1195 APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;
1196 APICWrite(APIC_LVTT, tmp);
1197
1198 tmp = APICRead(APIC_TDCR);
1199 tmp &= ~(APIC_TDCR_1 | APIC_TDCR_TMBASE | APIC_TDCR_16);
1200 APICWrite(APIC_TDCR, tmp);
1201 APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR);
1202 }
1203
1204
1205 VOID APICCalibrateTimer(
1206 ULONG CPU)
1207 {
1208 ULARGE_INTEGER t1, t2;
1209 LONG tt1, tt2;
1210
1211 DPRINT("Calibrating APIC timer...\n");
1212
1213 APICSetupLVTT(~0);
1214
1215 /*
1216 * The timer chip counts down to zero. Let's wait
1217 * for a wraparound to start exact measurement:
1218 * (the current tick might have been already half done)
1219 */
1220 WaitFor8254Wraparound();
1221
1222 /*
1223 * We wrapped around just now. Let's start
1224 */
1225 ReadPentiumClock(&t1);
1226 tt1 = APICRead(APIC_CCRT);
1227
1228 WaitFor8254Wraparound();
1229
1230 tt2 = APICRead(APIC_CCRT);
1231 ReadPentiumClock(&t2);
1232
1233 CPUMap[CPU].BusSpeed = (HZ * (tt2 - tt1) * APIC_DIVISOR);
1234 CPUMap[CPU].CoreSpeed = (HZ * (t2.QuadPart - t1.QuadPart));
1235
1236 /* Setup timer for normal operation */
1237 //APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
1238 APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 15000); // 15ms
1239 //APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
1240
1241 DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
1242 CPUMap[CPU].CoreSpeed/1000000,
1243 CPUMap[CPU].CoreSpeed%1000000);
1244
1245 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
1246 CPUMap[CPU].BusSpeed/1000000,
1247 CPUMap[CPU].BusSpeed%1000000);
1248 }
1249
1250
1251 static VOID APICSleep(
1252 ULONG Count)
1253 /*
1254 PARAMETERS:
1255 Count = Number of microseconds to busy wait
1256 */
1257 {
1258 KeStallExecutionProcessor(Count);
1259 }
1260
1261
1262 static VOID APICSyncArbIDs(
1263 VOID)
1264 {
1265 ULONG i, tmp;
1266
1267 /* Wait up to 100ms for the APIC to become ready */
1268 for (i = 0; i < 10000; i++) {
1269 tmp = APICRead(APIC_ICR0);
1270 /* Check Delivery Status */
1271 if ((tmp & APIC_ICR0_DS) == 0)
1272 break;
1273 APICSleep(10);
1274 }
1275
1276 if (i == 10000) {
1277 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
1278 }
1279
1280 DPRINT("Synchronizing Arb IDs.\n");
1281 APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT);
1282 }
1283
1284
1285 VOID APICSendIPI(
1286 ULONG Target,
1287 ULONG DeliveryMode,
1288 ULONG IntNum,
1289 ULONG Level)
1290 {
1291 ULONG tmp, i, flags;
1292
1293 pushfl(flags);
1294 __asm__ ("\n\tcli\n\t");
1295
1296 /* Wait up to 100ms for the APIC to become ready */
1297 for (i = 0; i < 10000; i++) {
1298 tmp = APICRead(APIC_ICR0);
1299 /* Check Delivery Status */
1300 if ((tmp & APIC_ICR0_DS) == 0)
1301 break;
1302 APICSleep(10);
1303 }
1304
1305 if (i == 10000) {
1306 DPRINT("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
1307 }
1308
1309 /* Setup the APIC to deliver the IPI */
1310 tmp = APICRead(APIC_ICR1);
1311 tmp &= 0x00FFFFFF;
1312 APICWrite(APIC_ICR1, tmp | SET_APIC_DEST_FIELD(Target));
1313
1314 tmp = APICRead(APIC_ICR0);
1315 tmp &= ~(APIC_ICR0_LEVEL | APIC_ICR0_DESTM | APIC_ICR0_DM | APIC_ICR0_VECTOR);
1316 tmp |= (DeliveryMode | IntNum | Level);
1317
1318 if (Target == APIC_TARGET_SELF) {
1319 tmp |= APIC_ICR0_DESTS_SELF;
1320 } else if (Target == APIC_TARGET_ALL) {
1321 tmp |= APIC_ICR0_DESTS_ALL;
1322 } else if (Target == APIC_TARGET_ALL_BUT_SELF) {
1323 tmp |= APIC_ICR0_DESTS_ALL_BUT_SELF;
1324 } else {
1325 tmp |= APIC_ICR0_DESTS_FIELD;
1326 }
1327
1328 /* Now, fire off the IPI */
1329 APICWrite(APIC_ICR0, tmp);
1330
1331 popfl(flags);
1332 }
1333
1334
1335 BOOLEAN VerifyLocalAPIC(
1336 VOID)
1337 {
1338 UINT reg0, reg1;
1339
1340 /* The version register is read-only in a real APIC */
1341 reg0 = APICRead(APIC_VER);
1342 APICWrite(APIC_VER, reg0 ^ APIC_VER_MASK);
1343 reg1 = APICRead(APIC_VER);
1344
1345 if (reg1 != reg0)
1346 return FALSE;
1347
1348 /* The ID register is read/write in a real APIC */
1349 reg0 = APICRead(APIC_ID);
1350 APICWrite(APIC_ID, reg0 ^ APIC_ID_MASK);
1351 reg1 = APICRead(APIC_ID);
1352 APICWrite(APIC_ID, reg0);
1353 if (reg1 != (reg0 ^ APIC_ID_MASK))
1354 return FALSE;
1355
1356 return TRUE;
1357 }
1358
1359
1360 static VOID SetInterruptGate(
1361 ULONG index,
1362 ULONG address)
1363 {
1364 IDT_DESCRIPTOR *idt;
1365
1366 idt = (IDT_DESCRIPTOR*)((ULONG)KeGetCurrentKPCR()->IDT + index * sizeof(IDT_DESCRIPTOR));
1367 idt->a = (((ULONG)address)&0xffff) + (KERNEL_CS << 16);
1368 idt->b = 0x8f00 + (((ULONG)address)&0xffff0000);
1369 }
1370
1371
1372 VOID MpsTimerHandler(
1373 VOID)
1374 {
1375 #if 0
1376 KIRQL OldIrql;
1377 #endif
1378
1379 DPRINT("T1");
1380
1381 /*
1382 * Acknowledge the interrupt
1383 */
1384 APICSendEOI();
1385 #if 0
1386 /*
1387 * Notify the rest of the kernel of the raised irq level
1388 */
1389 OldIrql = KeRaiseIrqlToSynchLevel();
1390 #endif
1391 __asm__("sti\n\t");
1392
1393 /*
1394 * Call the dispatcher
1395 */
1396 // TODO FIXME - What happened to definition for THREAD_STATE_RUNNABLE ???
1397 // TODO FIXME - What happened to definition for PsDispatchThread ???
1398 //PsDispatchThread(THREAD_STATE_RUNNABLE);
1399
1400 #if 0
1401 /*
1402 * Lower irq level
1403 */
1404 KeLowerIrql(OldIrql);
1405 #endif
1406 }
1407
1408
1409 VOID MpsErrorHandler(
1410 VOID)
1411 {
1412 ULONG tmp1, tmp2;
1413
1414 APICDump();
1415
1416 tmp1 = APICRead(APIC_ESR);
1417 APICWrite(APIC_ESR, 0);
1418 tmp2 = APICRead(APIC_ESR);
1419
1420 /*
1421 * Acknowledge the interrupt
1422 */
1423 APICSendEOI();
1424
1425 /* Here is what the APIC error bits mean:
1426 0: Send CS error
1427 1: Receive CS error
1428 2: Send accept error
1429 3: Receive accept error
1430 4: Reserved
1431 5: Send illegal vector
1432 6: Received illegal vector
1433 7: Illegal register address
1434 */
1435 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
1436 for (;;);
1437 }
1438
1439
1440 VOID MpsSpuriousHandler(
1441 VOID)
1442 {
1443 DPRINT1("Spurious interrupt on CPU(%d)\n", ThisCPU());
1444
1445 /*
1446 * Acknowledge the interrupt
1447 */
1448 APICSendEOI();
1449 APICDump();
1450 for (;;);
1451 }
1452
1453
1454 VOID APICSetup(
1455 VOID)
1456 {
1457 ULONG CPU, tmp;
1458
1459 CPU = ThisCPU();
1460
1461 /*
1462 * Intel recommends to set DFR, LDR and TPR before enabling
1463 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
1464 * document number 292116). So here it goes...
1465 */
1466
1467 /*
1468 * Put the APIC into flat delivery mode.
1469 * Must be "all ones" explicitly for 82489DX.
1470 */
1471 APICWrite(APIC_DFR, 0xFFFFFFFF);
1472
1473 /*
1474 * Set up the logical destination ID.
1475 */
1476 tmp = APICRead(APIC_LDR);
1477 tmp &= ~APIC_LDR_MASK;
1478 tmp |= (1 << (CPU + 24));
1479 APICWrite(APIC_LDR, tmp);
1480
1481 /* Accept all interrupts */
1482 tmp = (APICRead(APIC_TPR) & ~APIC_TPR_PRI);
1483 APICWrite(APIC_TPR, tmp);
1484
1485 /* Enable local APIC */
1486 tmp = APICRead(APIC_SIVR) | APIC_SIVR_ENABLE | APIC_SIVR_FOCUS; // No focus processor
1487
1488 /* Set spurious interrupt vector */
1489 tmp |= SPURIOUS_VECTOR;
1490
1491 APICWrite(APIC_SIVR, tmp);
1492
1493 /*
1494 * Only the BP should see the LINT1 NMI signal, obviously.
1495 */
1496 if (CPU == 0)
1497 tmp = APIC_DM_NMI;
1498 else
1499 tmp = APIC_DM_NMI | APIC_LVT_MASKED;
1500 if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion)) /* 82489DX */
1501 tmp |= APIC_LVT_LEVEL_TRIGGER;
1502 APICWrite(APIC_LINT1, tmp);
1503
1504 if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) { /* !82489DX */
1505 if (CPUMap[CPU].MaxLVT > 3) { /* Due to the Pentium erratum 3AP */
1506 APICWrite(APIC_ESR, 0);
1507 }
1508
1509 tmp = APICRead(APIC_ESR);
1510 DPRINT("ESR value before enabling vector: 0x%X\n", tmp);
1511
1512 /* Enable sending errors */
1513 tmp = ERROR_VECTOR;
1514 APICWrite(APIC_LVT3, tmp);
1515
1516 /*
1517 * Spec says clear errors after enabling vector
1518 */
1519 if (CPUMap[CPU].MaxLVT > 3)
1520 APICWrite(APIC_ESR, 0);
1521 tmp = APICRead(APIC_ESR);
1522 DPRINT("ESR value after enabling vector: 0x%X\n", tmp);
1523 }
1524 }
1525
1526 VOID
1527 HaliInitBSP(
1528 VOID)
1529 {
1530 PUSHORT ps;
1531
1532 /* Only initialize the BSP once */
1533 if (BSPInitialized)
1534 return;
1535
1536 BSPInitialized = TRUE;
1537
1538 DPRINT("APIC is mapped at 0x%X\n", APICBase);
1539
1540 if (VerifyLocalAPIC()) {
1541 DPRINT("APIC found\n");
1542 } else {
1543 DPRINT1("No APIC found\n");
1544 KeBugCheck(0);
1545 }
1546
1547 CPUMap[BootCPU].MaxLVT = APICGetMaxLVT();
1548
1549 SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG)MpsTimerInterrupt);
1550 SetInterruptGate(ERROR_VECTOR, (ULONG)MpsErrorInterrupt);
1551 SetInterruptGate(SPURIOUS_VECTOR, (ULONG)MpsSpuriousInterrupt);
1552
1553 if (APICMode == amPIC) {
1554 EnableSMPMode();
1555 }
1556
1557 APICSetup();
1558
1559 /* BIOS data segment */
1560 BIOSBase = (PULONG)BIOS_AREA;
1561
1562 /* Area for communicating with the APs */
1563 CommonBase = (PULONG)COMMON_AREA;
1564
1565 /* Copy bootstrap code to common area */
1566 memcpy((PVOID)((ULONG)CommonBase + PAGE_SIZE),
1567 &APstart,
1568 (ULONG)&APend - (ULONG)&APstart + 1);
1569
1570 /* Set shutdown code */
1571 CMOS_WRITE(0xF, 0xA);
1572
1573 /* Set warm reset vector */
1574 ps = (PUSHORT)((ULONG)BIOSBase + 0x467);
1575 *ps = (COMMON_AREA + PAGE_SIZE) & 0xF;
1576
1577 ps = (PUSHORT)((ULONG)BIOSBase + 0x469);
1578 *ps = (COMMON_AREA + PAGE_SIZE) >> 4;
1579
1580 /* Calibrate APIC timer */
1581 APICCalibrateTimer(0);
1582
1583 /* The boot processor is online */
1584 OnlineCPUs = (1 << 0);
1585 }
1586
1587 #endif /* MP */
1588
1589 VOID
1590 STDCALL
1591 HalInitializeProcessor (
1592 ULONG ProcessorNumber,
1593 PVOID ProcessorStack)
1594 {
1595
1596 #ifdef MP
1597
1598 PCOMMON_AREA_INFO Common;
1599 ULONG StartupCount;
1600 ULONG DeliveryStatus;
1601 ULONG AcceptStatus;
1602 ULONG CPU, i, j;
1603 ULONG tmp, maxlvt;
1604
1605 if (ProcessorNumber == 0) {
1606 /* Boot processor is already initialized */
1607 NextCPU = 1;
1608 return;
1609 }
1610
1611 if (NextCPU < CPUCount) {
1612 CPU = NextCPU;
1613
1614 DPRINT("Attempting to boot CPU %d\n", CPU);
1615
1616 /* Send INIT IPI */
1617 APICSendIPI(CPUMap[CPU].APICId, APIC_DM_INIT, 0, APIC_ICR0_LEVEL_ASSERT);
1618
1619 APICSleep(200);
1620
1621 /* Deassert INIT */
1622 APICSendIPI(CPUMap[CPU].APICId, APIC_DM_INIT, 0, APIC_ICR0_LEVEL_DEASSERT);
1623
1624 if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) {
1625 /* Clear APIC errors */
1626 APICWrite(APIC_ESR, 0);
1627 tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK);
1628 }
1629
1630 Common = (PCOMMON_AREA_INFO)CommonBase;
1631
1632 /* Write the location of the AP stack */
1633 Common->Stack = (ULONG)ProcessorStack;
1634
1635 DPRINT("CPU %d got stack at 0x%X\n", CPU, Common->Stack);
1636 #if 0
1637 for (j = 0; j < 16; j++) {
1638 Common->Debug[j] = 0;
1639 }
1640 #endif
1641
1642 maxlvt = APICGetMaxLVT();
1643
1644 /* Is this a local APIC or an 82489DX? */
1645 StartupCount = (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) ? 2 : 0;
1646
1647 for (i = 1; i <= StartupCount; i++)
1648 {
1649 /* It's a local APIC, so send STARTUP IPI */
1650 DPRINT("Sending startup signal %d\n", i);
1651 /* Clear errors */
1652 APICWrite(APIC_ESR, 0);
1653 APICRead(APIC_ESR);
1654
1655 APICSendIPI(CPUMap[CPU].APICId,
1656 0,
1657 APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12),
1658 APIC_ICR0_LEVEL_DEASSERT);
1659
1660 /* Wait up to 10ms for IPI to be delivered */
1661 j = 0;
1662 do {
1663 APICSleep(10);
1664
1665 /* Check Delivery Status */
1666 DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS;
1667
1668 j++;
1669 } while ((DeliveryStatus) && (j < 1000));
1670
1671 APICSleep(200);
1672
1673 /*
1674 * Due to the Pentium erratum 3AP.
1675 */
1676 if (maxlvt > 3) {
1677 APICRead(APIC_SIVR);
1678 APICWrite(APIC_ESR, 0);
1679 }
1680
1681 AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK;
1682
1683 if (DeliveryStatus || AcceptStatus) {
1684 break;
1685 }
1686 }
1687
1688 if (DeliveryStatus) {
1689 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", CPU);
1690 }
1691
1692 if (AcceptStatus) {
1693 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", CPU);
1694 }
1695
1696 if (!(DeliveryStatus || AcceptStatus)) {
1697
1698 /* Wait no more than 5 seconds for processor to boot */
1699 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", CPU);
1700
1701 /* Wait no more than 5 seconds */
1702 for (j = 0; j < 50000; j++) {
1703
1704 if (CPUMap[CPU].Flags & CPU_ENABLED)
1705 break;
1706
1707 APICSleep(100);
1708 }
1709 }
1710
1711 if (CPUMap[CPU].Flags & CPU_ENABLED) {
1712 DbgPrint("CPU %d is now running\n", CPU);
1713 } else {
1714 DbgPrint("Initialization of CPU %d failed\n", CPU);
1715 }
1716
1717 #if 0
1718 DPRINT("Debug bytes are:\n");
1719
1720 for (j = 0; j < 4; j++) {
1721 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1722 Common->Debug[j*4+0],
1723 Common->Debug[j*4+1],
1724 Common->Debug[j*4+2],
1725 Common->Debug[j*4+3]);
1726 }
1727 #endif
1728 NextCPU++;
1729 }
1730
1731 #endif /* MP */
1732
1733 }
1734
1735 BOOLEAN
1736 STDCALL
1737 HalAllProcessorsStarted (
1738 VOID
1739 )
1740 {
1741
1742 #ifdef MP
1743
1744 return (NextCPU >= CPUCount);
1745
1746 #else /* MP */
1747
1748 if (BSPInitialized) {
1749 return TRUE;
1750 } else {
1751 BSPInitialized = TRUE;
1752 return FALSE;
1753 }
1754
1755 #endif /* MP */
1756
1757 }
1758
1759 BOOLEAN
1760 STDCALL
1761 HalStartNextProcessor (
1762 ULONG Unknown1,
1763 ULONG Unknown2
1764 )
1765 {
1766 #ifdef MP
1767
1768 /* Display the APIC registers for debugging */
1769 switch (Unknown1) {
1770 case 0:
1771 APICDump();
1772 break;
1773 case 1:
1774 IOAPICDump();
1775 }
1776 for(;;);
1777
1778 return (NextCPU >= CPUCount);
1779
1780 #endif /* MP */
1781
1782 return FALSE;
1783 }
1784
1785
1786 #ifdef MP
1787
1788 ULONG MPChecksum(
1789 PUCHAR Base,
1790 ULONG Size)
1791 /*
1792 * Checksum an MP configuration block
1793 */
1794 {
1795 ULONG Sum = 0;
1796
1797 while (Size--)
1798 Sum += *Base++;
1799
1800 return((UCHAR)Sum);
1801 }
1802
1803
1804 PCHAR HaliMPFamily(
1805 ULONG Family,
1806 ULONG Model)
1807 {
1808 static CHAR str[32];
1809 static PCHAR CPUs[] =
1810 {
1811 "80486DX", "80486DX",
1812 "80486SX", "80486DX/2 or 80487",
1813 "80486SL", "Intel5X2(tm)",
1814 "Unknown", "Unknown",
1815 "80486DX/4"
1816 };
1817 if (Family == 0x6)
1818 return ("Pentium(tm) Pro");
1819 if (Family == 0x5)
1820 return ("Pentium(tm)");
1821 if (Family == 0x0F && Model == 0x0F)
1822 return("Special controller");
1823 if (Family == 0x0F && Model == 0x00)
1824 return("Pentium 4(tm)");
1825 if (Family == 0x04 && Model < 9)
1826 return CPUs[Model];
1827 sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model);
1828 return str;
1829 }
1830
1831
1832 static VOID HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m)
1833 {
1834 ULONG ver;
1835
1836 if (!(m->CpuFlags & CPU_FLAG_ENABLED))
1837 return;
1838
1839 DPRINT("Processor #%d %s APIC version %d\n",
1840 m->ApicId,
1841 HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8,
1842 (m->FeatureFlags & CPU_MODEL_MASK) >> 4),
1843 m->ApicVersion);
1844
1845 if (m->FeatureFlags & (1 << 0))
1846 DPRINT(" Floating point unit present.\n");
1847 if (m->FeatureFlags & (1 << 7))
1848 DPRINT(" Machine Exception supported.\n");
1849 if (m->FeatureFlags & (1 << 8))
1850 DPRINT(" 64 bit compare & exchange supported.\n");
1851 if (m->FeatureFlags & (1 << 9))
1852 DPRINT(" Internal APIC present.\n");
1853 if (m->FeatureFlags & (1 << 11))
1854 DPRINT(" SEP present.\n");
1855 if (m->FeatureFlags & (1 << 12))
1856 DPRINT(" MTRR present.\n");
1857 if (m->FeatureFlags & (1 << 13))
1858 DPRINT(" PGE present.\n");
1859 if (m->FeatureFlags & (1 << 14))
1860 DPRINT(" MCA present.\n");
1861 if (m->FeatureFlags & (1 << 15))
1862 DPRINT(" CMOV present.\n");
1863 if (m->FeatureFlags & (1 << 16))
1864 DPRINT(" PAT present.\n");
1865 if (m->FeatureFlags & (1 << 17))
1866 DPRINT(" PSE present.\n");
1867 if (m->FeatureFlags & (1 << 18))
1868 DPRINT(" PSN present.\n");
1869 if (m->FeatureFlags & (1 << 19))
1870 DPRINT(" Cache Line Flush Instruction present.\n");
1871 /* 20 Reserved */
1872 if (m->FeatureFlags & (1 << 21))
1873 DPRINT(" Debug Trace and EMON Store present.\n");
1874 if (m->FeatureFlags & (1 << 22))
1875 DPRINT(" ACPI Thermal Throttle Registers present.\n");
1876 if (m->FeatureFlags & (1 << 23))
1877 DPRINT(" MMX present.\n");
1878 if (m->FeatureFlags & (1 << 24))
1879 DPRINT(" FXSR present.\n");
1880 if (m->FeatureFlags & (1 << 25))
1881 DPRINT(" XMM present.\n");
1882 if (m->FeatureFlags & (1 << 26))
1883 DPRINT(" Willamette New Instructions present.\n");
1884 if (m->FeatureFlags & (1 << 27))
1885 DPRINT(" Self Snoop present.\n");
1886 /* 28 Reserved */
1887 if (m->FeatureFlags & (1 << 29))
1888 DPRINT(" Thermal Monitor present.\n");
1889 /* 30, 31 Reserved */
1890
1891 CPUMap[CPUCount].APICId = m->ApicId;
1892
1893 CPUMap[CPUCount].Flags = CPU_USABLE;
1894
1895 if (m->CpuFlags & CPU_FLAG_BSP) {
1896 DPRINT(" Bootup CPU\n");
1897 CPUMap[CPUCount].Flags |= CPU_BSP;
1898 BootCPU = m->ApicId;
1899 }
1900
1901 if (m->ApicId > MAX_CPU) {
1902 DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU);
1903 return;
1904 }
1905 ver = m->ApicVersion;
1906
1907 /*
1908 * Validate version
1909 */
1910 if (ver == 0x0) {
1911 DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId);
1912 ver = 0x10;
1913 }
1914 CPUMap[CPUCount].APICVersion = ver;
1915
1916 CPUCount++;
1917 }
1918
1919 static VOID HaliMPBusInfo(PMP_CONFIGURATION_BUS m)
1920 {
1921 static ULONG CurrentPCIBusId = 0;
1922 CHAR str[7];
1923
1924 memcpy(str, m->BusType, 6);
1925 str[6] = 0;
1926 DPRINT("Bus #%d is %s\n", m->BusId, str);
1927
1928 if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) {
1929 BUSMap[m->BusId] = MP_BUS_ISA;
1930 } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) {
1931 BUSMap[m->BusId] = MP_BUS_EISA;
1932 } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) {
1933 BUSMap[m->BusId] = MP_BUS_PCI;
1934 PCIBUSMap[m->BusId] = CurrentPCIBusId;
1935 CurrentPCIBusId++;
1936 } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) {
1937 BUSMap[m->BusId] = MP_BUS_MCA;
1938 } else {
1939 DPRINT("Unknown bustype %s - ignoring\n", str);
1940 }
1941 }
1942
1943 static VOID HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m)
1944 {
1945 if (!(m->ApicFlags & CPU_FLAG_ENABLED))
1946 return;
1947
1948 DPRINT("I/O APIC #%d Version %d at 0x%lX.\n",
1949 m->ApicId, m->ApicVersion, m->ApicAddress);
1950 if (IOAPICCount > MAX_IOAPIC) {
1951 DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n",
1952 MAX_IOAPIC, IOAPICCount);
1953 DPRINT1("Recompile with bigger MAX_IOAPIC!.\n");
1954 KeBugCheck(0);
1955 }
1956 IOAPICMap[IOAPICCount].ApicId = m->ApicId;
1957 IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion;
1958 IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress;
1959 IOAPICCount++;
1960 }
1961
1962 static VOID HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m)
1963 {
1964 DPRINT("Int: type %d, pol %d, trig %d, bus %d,"
1965 " IRQ %02x, APIC ID %x, APIC INT %02x\n",
1966 m->IrqType, m->IrqFlag & 3,
1967 (m->IrqFlag >> 2) & 3, m->SrcBusId,
1968 m->SrcBusIrq, m->DstApicId, m->DstApicInt);
1969 if (IRQCount > MAX_IRQ_SOURCE) {
1970 DPRINT1("Max # of irq sources exceeded!!\n");
1971 KeBugCheck(0);
1972 }
1973
1974 IRQMap[IRQCount] = *m;
1975 IRQCount++;
1976 }
1977
1978 static VOID HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m)
1979 {
1980 DPRINT("Lint: type %d, pol %d, trig %d, bus %d,"
1981 " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
1982 m->IrqType, m->IrqFlag & 3,
1983 (m->IrqFlag >> 2) & 3, m->SrcBusId,
1984 m->SrcBusIrq, m->DstApicId, m->DstApicLInt);
1985 /*
1986 * Well it seems all SMP boards in existence
1987 * use ExtINT/LVT1 == LINT0 and
1988 * NMI/LVT2 == LINT1 - the following check
1989 * will show us if this assumptions is false.
1990 * Until then we do not have to add baggage.
1991 */
1992 if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) {
1993 DPRINT1("Invalid MP table!\n");
1994 KeBugCheck(0);
1995 }
1996 if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) {
1997 DPRINT1("Invalid MP table!\n");
1998 KeBugCheck(0);
1999 }
2000 }
2001
2002
2003 VOID
2004 HaliReadMPConfigTable(
2005 PMP_CONFIGURATION_TABLE Table)
2006 /*
2007 PARAMETERS:
2008 Table = Pointer to MP configuration table
2009 */
2010 {
2011 PUCHAR Entry;
2012 ULONG Count;
2013
2014 if (Table->Signature != MPC_SIGNATURE)
2015 {
2016 PUCHAR pc = (PUCHAR)&Table->Signature;
2017
2018 DbgPrint("Bad MP configuration block signature: %c%c%c%c\n",
2019 pc[0], pc[1], pc[2], pc[3]);
2020 KeBugCheck(0);
2021 return;
2022 }
2023
2024 if (MPChecksum((PUCHAR)Table, Table->Length))
2025 {
2026 DbgPrint("Bad MP configuration block checksum\n");
2027 KeBugCheck(0);
2028 return;
2029 }
2030
2031 if (Table->Specification < 0x04)
2032 {
2033 DbgPrint("Bad MP configuration table version (%d)\n",
2034 Table->Specification);
2035 KeBugCheck(0);
2036 return;
2037 }
2038
2039 APICBase = (PULONG)Table->LocalAPICAddress;
2040 if (APICBase != (PULONG)APIC_DEFAULT_BASE)
2041 {
2042 DbgPrint("APIC base address is at 0x%X. " \
2043 "I cannot handle non-standard adresses\n", APICBase);
2044 KeBugCheck(0);
2045 }
2046
2047 Entry = (PUCHAR)((PVOID)Table + sizeof(MP_CONFIGURATION_TABLE));
2048 Count = 0;
2049 while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE)))
2050 {
2051 /* Switch on type */
2052 switch (*Entry)
2053 {
2054 case MPCTE_PROCESSOR:
2055 {
2056 HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry);
2057 Entry += sizeof(MP_CONFIGURATION_PROCESSOR);
2058 Count += sizeof(MP_CONFIGURATION_PROCESSOR);
2059 break;
2060 }
2061 case MPCTE_BUS:
2062 {
2063 HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry);
2064 Entry += sizeof(MP_CONFIGURATION_BUS);
2065 Count += sizeof(MP_CONFIGURATION_BUS);
2066 break;
2067 }
2068 case MPCTE_IOAPIC:
2069 {
2070 HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry);
2071 Entry += sizeof(MP_CONFIGURATION_IOAPIC);
2072 Count += sizeof(MP_CONFIGURATION_IOAPIC);
2073 break;
2074 }
2075 case MPCTE_INTSRC:
2076 {
2077 HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry);
2078 Entry += sizeof(MP_CONFIGURATION_INTSRC);
2079 Count += sizeof(MP_CONFIGURATION_INTSRC);
2080 break;
2081 }
2082 case MPCTE_LINTSRC:
2083 {
2084 HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry);
2085 Entry += sizeof(MP_CONFIGURATION_INTLOCAL);
2086 Count += sizeof(MP_CONFIGURATION_INTLOCAL);
2087 break;
2088 }
2089 default:
2090 DbgPrint("Unknown entry in MPC table\n");
2091 KeBugCheck(0);
2092 }
2093 }
2094 }
2095
2096
2097 static VOID HaliConstructDefaultIOIrqMPTable(
2098 ULONG Type)
2099 {
2100 MP_CONFIGURATION_INTSRC intsrc;
2101 ULONG i;
2102
2103 intsrc.Type = MPCTE_INTSRC;
2104 intsrc.IrqFlag = 0; /* conforming */
2105 intsrc.SrcBusId = 0;
2106 intsrc.DstApicId = IOAPICMap[0].ApicId;
2107
2108 intsrc.IrqType = INT_VECTORED;
2109 for (i = 0; i < 16; i++) {
2110 switch (Type) {
2111 case 2:
2112 if (i == 0 || i == 13)
2113 continue; /* IRQ0 & IRQ13 not connected */
2114 /* Fall through */
2115 default:
2116 if (i == 2)
2117 continue; /* IRQ2 is never connected */
2118 }
2119
2120 intsrc.SrcBusIrq = i;
2121 intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */
2122 HaliMPIntSrcInfo(&intsrc);
2123 }
2124
2125 intsrc.IrqType = INT_EXTINT;
2126 intsrc.SrcBusIrq = 0;
2127 intsrc.DstApicInt = 0; /* 8259A to INTIN0 */
2128 HaliMPIntSrcInfo(&intsrc);
2129 }
2130
2131
2132 static VOID HaliConstructDefaultISAMPTable(
2133 ULONG Type)
2134 {
2135 MP_CONFIGURATION_PROCESSOR processor;
2136 MP_CONFIGURATION_BUS bus;
2137 MP_CONFIGURATION_IOAPIC ioapic;
2138 MP_CONFIGURATION_INTLOCAL lintsrc;
2139 ULONG linttypes[2] = { INT_EXTINT, INT_NMI };
2140 ULONG i;
2141
2142 APICBase = (PULONG)APIC_DEFAULT_BASE;
2143
2144 /*
2145 * 2 CPUs, numbered 0 & 1.
2146 */
2147 processor.Type = MPCTE_PROCESSOR;
2148 /* Either an integrated APIC or a discrete 82489DX. */
2149 processor.ApicVersion = Type > 4 ? 0x10 : 0x01;
2150 processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP;
2151 /* FIXME: Get this from the bootstrap processor */
2152 processor.CpuSignature = 0;
2153 processor.FeatureFlags = 0;
2154 processor.Reserved[0] = 0;
2155 processor.Reserved[1] = 0;
2156 for (i = 0; i < 2; i++) {
2157 processor.ApicId = i;
2158 HaliMPProcessorInfo(&processor);
2159 processor.CpuFlags &= ~CPU_FLAG_BSP;
2160 }
2161
2162 bus.Type = MPCTE_BUS;
2163 bus.BusId = 0;
2164 switch (Type) {
2165 default:
2166 DPRINT("Unknown standard configuration %d\n", Type);
2167 /* Fall through */
2168 case 1:
2169 case 5:
2170 memcpy(bus.BusType, "ISA ", 6);
2171 break;
2172 case 2:
2173 case 6:
2174 case 3:
2175 memcpy(bus.BusType, "EISA ", 6);
2176 break;
2177 case 4:
2178 case 7:
2179 memcpy(bus.BusType, "MCA ", 6);
2180 }
2181 HaliMPBusInfo(&bus);
2182 if (Type > 4) {
2183 bus.Type = MPCTE_BUS;
2184 bus.BusId = 1;
2185 memcpy(bus.BusType, "PCI ", 6);
2186 HaliMPBusInfo(&bus);
2187 }
2188
2189 ioapic.Type = MPCTE_IOAPIC;
2190 ioapic.ApicId = 2;
2191 ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01;
2192 ioapic.ApicFlags = MP_IOAPIC_USABLE;
2193 ioapic.ApicAddress = IOAPIC_DEFAULT_BASE;
2194 HaliMPIOApicInfo(&ioapic);
2195
2196 /*
2197 * We set up most of the low 16 IO-APIC pins according to MPS rules.
2198 */
2199 HaliConstructDefaultIOIrqMPTable(Type);
2200
2201 lintsrc.Type = MPCTE_LINTSRC;
2202 lintsrc.IrqType = 0;
2203 lintsrc.IrqFlag = 0; /* conforming */
2204 lintsrc.SrcBusId = 0;
2205 lintsrc.SrcBusIrq = 0;
2206 lintsrc.DstApicId = MP_APIC_ALL;
2207 for (i = 0; i < 2; i++) {
2208 lintsrc.IrqType = linttypes[i];
2209 lintsrc.DstApicLInt = i;
2210 HaliMPIntLocalInfo(&lintsrc);
2211 }
2212 }
2213
2214 BOOLEAN
2215 HaliScanForMPConfigTable(
2216 ULONG Base,
2217 ULONG Size)
2218 /*
2219 PARAMETERS:
2220 Base = Base address of region
2221 Size = Length of region to check
2222 RETURNS:
2223 TRUE if a valid MP configuration table was found
2224 */
2225 {
2226 PULONG bp = (PULONG)Base;
2227 MP_FLOATING_POINTER* mpf;
2228
2229 while (Size > 0)
2230 {
2231 if (*bp == MPF_SIGNATURE)
2232 {
2233 DbgPrint("Found MPF signature at %x, checksum %x\n", bp,
2234 MPChecksum((PUCHAR)bp, 16));
2235 if (MPChecksum((PUCHAR)bp, 16) == 0)
2236 {
2237 mpf = (MP_FLOATING_POINTER*)bp;
2238
2239 DbgPrint("Intel MultiProcessor Specification v1.%d compliant system.\n",
2240 mpf->Specification);
2241
2242 if (mpf->Feature2 & FEATURE2_IMCRP) {
2243 APICMode = amPIC;
2244 DPRINT("Running in IMCR and PIC compatibility mode.\n")
2245 } else {
2246 APICMode = amVWIRE;
2247 DPRINT("Running in Virtual Wire compatibility mode.\n");
2248 }
2249
2250 switch (mpf->Feature1)
2251 {
2252 case 0:
2253 /* Non standard configuration */
2254 break;
2255 case 1:
2256 DPRINT("ISA\n");
2257 break;
2258 case 2:
2259 DPRINT("EISA with no IRQ8 chaining\n");
2260 break;
2261 case 3:
2262 DPRINT("EISA\n");
2263 break;
2264 case 4:
2265 DPRINT("MCA\n");
2266 break;
2267 case 5:
2268 DPRINT("ISA and PCI\n");
2269 break;
2270 case 6:
2271 DPRINT("EISA and PCI\n");
2272 break;
2273 case 7:
2274 DPRINT("MCA and PCI\n");
2275 break;
2276 default:
2277 DbgPrint("Unknown standard configuration %d\n", mpf->Feature1);
2278 return FALSE;
2279 }
2280
2281 CPUCount = 0;
2282 IOAPICCount = 0;
2283 IRQCount = 0;
2284
2285 if ((mpf->Feature1 == 0) && (mpf->Address)) {
2286 HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)mpf->Address);
2287 } else {
2288 HaliConstructDefaultISAMPTable(mpf->Feature1);
2289 }
2290
2291 return TRUE;
2292 }
2293 }
2294 bp += 4;
2295 Size -= 16;
2296 }
2297 return FALSE;
2298 }
2299
2300
2301 VOID
2302 HalpInitMPS(
2303 VOID)
2304 {
2305 USHORT EBDA;
2306 ULONG CPU;
2307
2308 /* Only initialize MP system once. Once called the first time,
2309 each subsequent call is part of the initialization sequence
2310 for an application processor. */
2311 if (MPSInitialized) {
2312 CPU = ThisCPU();
2313
2314 DPRINT("CPU %d says it is now booted.\n", CPU);
2315
2316 APICSetup();
2317 APICCalibrateTimer(CPU);
2318
2319 /* This processor is now booted */
2320 CPUMap[CPU].Flags |= CPU_ENABLED;
2321 OnlineCPUs |= (1 << CPU);
2322
2323 return;
2324 }
2325
2326 MPSInitialized = TRUE;
2327
2328 /*
2329 Scan the system memory for an MP configuration table
2330 1) Scan the first KB of system base memory
2331 2) Scan the last KB of system base memory
2332 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh
2333 4) Scan the Extended BIOS Data Area
2334 */
2335
2336 if (!HaliScanForMPConfigTable(0x0, 0x400)) {
2337 if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) {
2338 if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) {
2339 EBDA = *((PUSHORT)0x040E);
2340 EBDA <<= 4;
2341 if (!HaliScanForMPConfigTable((ULONG)EBDA, 0x1000)) {
2342 DbgPrint("No multiprocessor compliant system found.\n");
2343 KeBugCheck(0);
2344 }
2345 }
2346 }
2347 }
2348
2349 /* Setup IRQ to vector translation map */
2350 memset(&IRQVectorMap, sizeof(IRQVectorMap), 0);
2351
2352 /* Initialize the bootstrap processor */
2353 HaliInitBSP();
2354
2355 /* Setup I/O APIC */
2356 IOAPICSetup();
2357
2358 /* Setup busy waiting */
2359 HalpCalibrateStallExecution();
2360
2361 /* We can now enable interrupts */
2362 __asm__ __volatile__ ("sti\n\t");
2363
2364 NextCPU = 0;
2365 }
2366
2367 #endif /* MP */
2368
2369 /* EOF */