update for HEAD-2003021201
[reactos.git] / hal / halx86 / mp.c
1 /* $Id$
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 PsDispatchThread ???
1397   //PsDispatchThread(THREAD_STATE_READY);
1398
1399   // KeGetCurrentThread is linked into hal from ntoskrnl, so can 
1400   //    PsDispatchThread be exported from ntoskrnl also ???
1401
1402
1403 #if 0
1404   /*
1405    * Lower irq level
1406    */
1407   KeLowerIrql(OldIrql);
1408 #endif
1409 }
1410
1411
1412 VOID MpsErrorHandler(
1413   VOID)
1414 {
1415   ULONG tmp1, tmp2;
1416
1417   APICDump();
1418
1419   tmp1 = APICRead(APIC_ESR);
1420         APICWrite(APIC_ESR, 0);
1421         tmp2 = APICRead(APIC_ESR);
1422
1423   /*
1424    * Acknowledge the interrupt
1425    */
1426   APICSendEOI();
1427
1428         /* Here is what the APIC error bits mean:
1429            0: Send CS error
1430            1: Receive CS error
1431            2: Send accept error
1432            3: Receive accept error
1433            4: Reserved
1434            5: Send illegal vector
1435            6: Received illegal vector
1436            7: Illegal register address
1437         */
1438         DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
1439   for (;;);
1440 }
1441
1442
1443 VOID MpsSpuriousHandler(
1444   VOID)
1445 {
1446   DPRINT1("Spurious interrupt on CPU(%d)\n", ThisCPU());
1447
1448         /*
1449    * Acknowledge the interrupt
1450    */
1451   APICSendEOI();
1452   APICDump();
1453   for (;;);
1454 }
1455
1456
1457 VOID APICSetup(
1458   VOID)
1459 {
1460   ULONG CPU, tmp;
1461
1462   CPU = ThisCPU();
1463
1464   /*
1465          * Intel recommends to set DFR, LDR and TPR before enabling
1466          * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
1467          * document number 292116).  So here it goes...
1468          */
1469
1470         /*
1471          * Put the APIC into flat delivery mode.
1472          * Must be "all ones" explicitly for 82489DX.
1473          */
1474         APICWrite(APIC_DFR, 0xFFFFFFFF);
1475
1476   /*
1477          * Set up the logical destination ID.
1478          */
1479         tmp = APICRead(APIC_LDR);
1480         tmp &= ~APIC_LDR_MASK;
1481         tmp |= (1 << (CPU + 24));
1482         APICWrite(APIC_LDR, tmp);
1483
1484         /* Accept all interrupts */
1485         tmp = (APICRead(APIC_TPR) & ~APIC_TPR_PRI);
1486         APICWrite(APIC_TPR, tmp);
1487
1488         /* Enable local APIC */
1489         tmp = APICRead(APIC_SIVR) | APIC_SIVR_ENABLE | APIC_SIVR_FOCUS; // No focus processor
1490
1491   /* Set spurious interrupt vector */
1492         tmp |= SPURIOUS_VECTOR;
1493
1494         APICWrite(APIC_SIVR, tmp);
1495
1496   /*
1497    * Only the BP should see the LINT1 NMI signal, obviously.
1498    */
1499   if (CPU == 0)
1500                 tmp = APIC_DM_NMI;
1501         else
1502                 tmp = APIC_DM_NMI | APIC_LVT_MASKED;
1503         if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion)) /* 82489DX */
1504                 tmp |= APIC_LVT_LEVEL_TRIGGER;
1505         APICWrite(APIC_LINT1, tmp);
1506
1507         if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) { /* !82489DX */
1508     if (CPUMap[CPU].MaxLVT > 3) {               /* Due to the Pentium erratum 3AP */
1509                         APICWrite(APIC_ESR, 0);
1510     }
1511
1512     tmp = APICRead(APIC_ESR);
1513     DPRINT("ESR value before enabling vector: 0x%X\n", tmp);
1514
1515     /* Enable sending errors */
1516           tmp = ERROR_VECTOR;
1517           APICWrite(APIC_LVT3, tmp);
1518
1519     /*
1520      * Spec says clear errors after enabling vector
1521      */
1522     if (CPUMap[CPU].MaxLVT > 3)
1523       APICWrite(APIC_ESR, 0);
1524     tmp = APICRead(APIC_ESR);
1525     DPRINT("ESR value after enabling vector: 0x%X\n", tmp);
1526         }
1527 }
1528
1529 VOID
1530 HaliInitBSP(
1531    VOID)
1532 {
1533         PUSHORT ps;
1534
1535         /* Only initialize the BSP once */
1536         if (BSPInitialized)
1537                 return;
1538
1539         BSPInitialized = TRUE;
1540
1541         DPRINT("APIC is mapped at 0x%X\n", APICBase);
1542
1543         if (VerifyLocalAPIC()) {
1544                 DPRINT("APIC found\n");
1545         } else {
1546                 DPRINT1("No APIC found\n");
1547                 KeBugCheck(0);
1548         }
1549
1550   CPUMap[BootCPU].MaxLVT = APICGetMaxLVT();
1551
1552   SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG)MpsTimerInterrupt);
1553   SetInterruptGate(ERROR_VECTOR, (ULONG)MpsErrorInterrupt);
1554   SetInterruptGate(SPURIOUS_VECTOR, (ULONG)MpsSpuriousInterrupt);
1555
1556   if (APICMode == amPIC) {
1557     EnableSMPMode();
1558   }
1559
1560   APICSetup();
1561
1562         /* BIOS data segment */
1563         BIOSBase = (PULONG)BIOS_AREA;
1564
1565         /* Area for communicating with the APs */
1566         CommonBase = (PULONG)COMMON_AREA;
1567
1568   /* Copy bootstrap code to common area */
1569         memcpy((PVOID)((ULONG)CommonBase + PAGE_SIZE),
1570                     &APstart,
1571                     (ULONG)&APend - (ULONG)&APstart + 1);
1572
1573         /* Set shutdown code */
1574         CMOS_WRITE(0xF, 0xA);
1575
1576         /* Set warm reset vector */
1577         ps = (PUSHORT)((ULONG)BIOSBase + 0x467);
1578         *ps = (COMMON_AREA + PAGE_SIZE) & 0xF;
1579
1580         ps = (PUSHORT)((ULONG)BIOSBase + 0x469);
1581         *ps = (COMMON_AREA + PAGE_SIZE) >> 4;
1582
1583   /* Calibrate APIC timer */
1584         APICCalibrateTimer(0);
1585
1586   /* The boot processor is online */
1587   OnlineCPUs = (1 << 0);
1588 }
1589
1590 #endif /* MP */
1591
1592 VOID
1593 STDCALL
1594 HalInitializeProcessor (
1595   ULONG ProcessorNumber,
1596   PVOID ProcessorStack)
1597 {
1598
1599 #ifdef MP
1600
1601    PCOMMON_AREA_INFO Common;
1602    ULONG StartupCount;
1603    ULONG DeliveryStatus;
1604    ULONG AcceptStatus;
1605          ULONG CPU, i, j;
1606          ULONG tmp, maxlvt;
1607
1608    if (ProcessorNumber == 0) {
1609        /* Boot processor is already initialized */
1610        NextCPU = 1;
1611        return;
1612    }
1613
1614    if (NextCPU < CPUCount) {
1615       CPU = NextCPU;
1616
1617       DPRINT("Attempting to boot CPU %d\n", CPU);
1618
1619             /* Send INIT IPI */
1620             APICSendIPI(CPUMap[CPU].APICId, APIC_DM_INIT, 0, APIC_ICR0_LEVEL_ASSERT);
1621
1622             APICSleep(200);
1623
1624             /* Deassert INIT */
1625       APICSendIPI(CPUMap[CPU].APICId, APIC_DM_INIT, 0, APIC_ICR0_LEVEL_DEASSERT);
1626
1627       if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) {
1628                            /* Clear APIC errors */
1629          APICWrite(APIC_ESR, 0);
1630          tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK);
1631       }
1632
1633       Common = (PCOMMON_AREA_INFO)CommonBase;
1634
1635       /* Write the location of the AP stack */
1636       Common->Stack = (ULONG)ProcessorStack;
1637
1638       DPRINT("CPU %d got stack at 0x%X\n", CPU, Common->Stack);
1639 #if 0
1640       for (j = 0; j < 16; j++) {
1641          Common->Debug[j] = 0;
1642       }
1643 #endif
1644
1645       maxlvt = APICGetMaxLVT();
1646
1647                   /* Is this a local APIC or an 82489DX? */
1648       StartupCount = (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) ? 2 : 0;
1649
1650                   for (i = 1; i <= StartupCount; i++)
1651                   {
1652          /* It's a local APIC, so send STARTUP IPI */
1653          DPRINT("Sending startup signal %d\n", i);
1654          /* Clear errors */
1655          APICWrite(APIC_ESR, 0);
1656          APICRead(APIC_ESR);
1657
1658          APICSendIPI(CPUMap[CPU].APICId,
1659             0,
1660             APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12),
1661             APIC_ICR0_LEVEL_DEASSERT);
1662
1663          /* Wait up to 10ms for IPI to be delivered */
1664          j = 0;
1665          do {
1666             APICSleep(10);
1667
1668             /* Check Delivery Status */
1669             DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS;
1670
1671             j++;
1672          } while ((DeliveryStatus) && (j < 1000));
1673
1674          APICSleep(200);
1675
1676                      /*
1677                       * Due to the Pentium erratum 3AP.
1678                       */
1679                      if (maxlvt > 3) {
1680                              APICRead(APIC_SIVR);
1681                              APICWrite(APIC_ESR, 0);
1682                      }
1683
1684          AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK;
1685
1686          if (DeliveryStatus || AcceptStatus) {
1687             break;
1688          }
1689       }
1690
1691       if (DeliveryStatus) {
1692          DPRINT("STARTUP IPI for CPU %d was never delivered.\n", CPU);
1693       }
1694
1695       if (AcceptStatus) {
1696          DPRINT("STARTUP IPI for CPU %d was never accepted.\n", CPU);
1697       }
1698
1699       if (!(DeliveryStatus || AcceptStatus)) {
1700
1701          /* Wait no more than 5 seconds for processor to boot */
1702          DPRINT("Waiting for 5 seconds for CPU %d to boot\n", CPU);
1703
1704          /* Wait no more than 5 seconds */
1705          for (j = 0; j < 50000; j++) {
1706
1707             if (CPUMap[CPU].Flags & CPU_ENABLED)
1708                break;
1709
1710             APICSleep(100);
1711          }
1712       }
1713
1714       if (CPUMap[CPU].Flags & CPU_ENABLED) {
1715          DbgPrint("CPU %d is now running\n", CPU);
1716       } else {
1717          DbgPrint("Initialization of CPU %d failed\n", CPU);
1718       }
1719
1720 #if 0
1721       DPRINT("Debug bytes are:\n");
1722
1723       for (j = 0; j < 4; j++) {
1724          DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1725             Common->Debug[j*4+0],
1726             Common->Debug[j*4+1],
1727             Common->Debug[j*4+2],
1728             Common->Debug[j*4+3]);
1729       }
1730 #endif
1731       NextCPU++;
1732    }
1733
1734 #endif /* MP */
1735
1736 }
1737
1738 BOOLEAN
1739 STDCALL
1740 HalAllProcessorsStarted (
1741         VOID
1742         )
1743 {
1744
1745 #ifdef MP
1746
1747   return (NextCPU >= CPUCount);
1748
1749 #else /* MP */
1750
1751         if (BSPInitialized) {
1752                 return TRUE;
1753         } else {
1754                 BSPInitialized = TRUE;
1755                 return FALSE;
1756         }
1757
1758 #endif /* MP */
1759
1760 }
1761
1762 BOOLEAN
1763 STDCALL
1764 HalStartNextProcessor (
1765         ULONG   Unknown1,
1766         ULONG   Unknown2
1767         )
1768 {
1769 #ifdef MP
1770
1771   /* Display the APIC registers for debugging */
1772   switch (Unknown1) {
1773   case 0:
1774     APICDump();
1775     break;
1776   case 1:
1777     IOAPICDump();
1778   }
1779   for(;;);
1780
1781   return (NextCPU >= CPUCount);
1782
1783 #endif /* MP */
1784
1785   return FALSE;
1786 }
1787
1788
1789 #ifdef MP
1790
1791 ULONG MPChecksum(
1792    PUCHAR Base,
1793    ULONG Size)
1794 /*
1795  *      Checksum an MP configuration block
1796  */
1797 {
1798    ULONG Sum = 0;
1799
1800    while (Size--)
1801       Sum += *Base++;
1802
1803    return((UCHAR)Sum);
1804 }
1805
1806
1807 PCHAR HaliMPFamily(
1808    ULONG Family,
1809    ULONG Model)
1810 {
1811    static CHAR str[32];
1812    static PCHAR CPUs[] =
1813    {
1814       "80486DX", "80486DX",
1815       "80486SX", "80486DX/2 or 80487",
1816       "80486SL", "Intel5X2(tm)",
1817       "Unknown", "Unknown",
1818       "80486DX/4"
1819    };
1820    if (Family == 0x6)
1821       return ("Pentium(tm) Pro");
1822    if (Family == 0x5)
1823       return ("Pentium(tm)");
1824    if (Family == 0x0F && Model == 0x0F)
1825       return("Special controller");
1826    if (Family == 0x0F && Model == 0x00)
1827       return("Pentium 4(tm)");
1828    if (Family == 0x04 && Model < 9)
1829       return CPUs[Model];
1830    sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model);
1831    return str;
1832 }
1833
1834
1835 static VOID HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m)
1836 {
1837   ULONG ver;
1838
1839   if (!(m->CpuFlags & CPU_FLAG_ENABLED))
1840     return;
1841
1842   DPRINT("Processor #%d %s APIC version %d\n",
1843     m->ApicId,
1844     HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8,
1845       (m->FeatureFlags & CPU_MODEL_MASK) >> 4),
1846       m->ApicVersion);
1847
1848   if (m->FeatureFlags & (1 << 0))
1849     DPRINT("    Floating point unit present.\n");
1850   if (m->FeatureFlags & (1 << 7))
1851     DPRINT("    Machine Exception supported.\n");
1852   if (m->FeatureFlags & (1 << 8))
1853     DPRINT("    64 bit compare & exchange supported.\n");
1854   if (m->FeatureFlags & (1 << 9))
1855     DPRINT("    Internal APIC present.\n");
1856   if (m->FeatureFlags & (1 << 11))
1857     DPRINT("    SEP present.\n");
1858   if (m->FeatureFlags & (1 << 12))
1859     DPRINT("    MTRR present.\n");
1860   if (m->FeatureFlags & (1 << 13))
1861     DPRINT("    PGE  present.\n");
1862   if (m->FeatureFlags & (1 << 14))
1863     DPRINT("    MCA  present.\n");
1864   if (m->FeatureFlags & (1 << 15))
1865     DPRINT("    CMOV  present.\n");
1866   if (m->FeatureFlags & (1 << 16))
1867     DPRINT("    PAT  present.\n");
1868   if (m->FeatureFlags & (1 << 17))
1869     DPRINT("    PSE  present.\n");
1870   if (m->FeatureFlags & (1 << 18))
1871     DPRINT("    PSN  present.\n");
1872   if (m->FeatureFlags & (1 << 19))
1873     DPRINT("    Cache Line Flush Instruction present.\n");
1874   /* 20 Reserved */
1875   if (m->FeatureFlags & (1 << 21))
1876     DPRINT("    Debug Trace and EMON Store present.\n");
1877   if (m->FeatureFlags & (1 << 22))
1878     DPRINT("    ACPI Thermal Throttle Registers present.\n");
1879   if (m->FeatureFlags & (1 << 23))
1880     DPRINT("    MMX  present.\n");
1881   if (m->FeatureFlags & (1 << 24))
1882     DPRINT("    FXSR  present.\n");
1883   if (m->FeatureFlags & (1 << 25))
1884     DPRINT("    XMM  present.\n");
1885   if (m->FeatureFlags & (1 << 26))
1886     DPRINT("    Willamette New Instructions present.\n");
1887   if (m->FeatureFlags & (1 << 27))
1888     DPRINT("    Self Snoop present.\n");
1889   /* 28 Reserved */
1890   if (m->FeatureFlags & (1 << 29))
1891     DPRINT("    Thermal Monitor present.\n");
1892   /* 30, 31 Reserved */
1893
1894   CPUMap[CPUCount].APICId = m->ApicId;
1895
1896   CPUMap[CPUCount].Flags = CPU_USABLE;
1897
1898   if (m->CpuFlags & CPU_FLAG_BSP) {
1899     DPRINT("    Bootup CPU\n");
1900     CPUMap[CPUCount].Flags |= CPU_BSP;
1901     BootCPU = m->ApicId;
1902   }
1903
1904   if (m->ApicId > MAX_CPU) {
1905     DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU);
1906     return;
1907   }
1908   ver = m->ApicVersion;
1909
1910   /*
1911   * Validate version
1912   */
1913   if (ver == 0x0) {
1914     DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId);
1915     ver = 0x10;
1916   }
1917   CPUMap[CPUCount].APICVersion = ver;
1918   
1919   CPUCount++;
1920 }
1921
1922 static VOID HaliMPBusInfo(PMP_CONFIGURATION_BUS m)
1923 {
1924   static ULONG CurrentPCIBusId = 0;
1925         CHAR str[7];
1926
1927         memcpy(str, m->BusType, 6);
1928         str[6] = 0;
1929         DPRINT("Bus #%d is %s\n", m->BusId, str);
1930
1931         if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) {
1932                 BUSMap[m->BusId] = MP_BUS_ISA;
1933         } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) {
1934                 BUSMap[m->BusId] = MP_BUS_EISA;
1935         } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) {
1936                 BUSMap[m->BusId] = MP_BUS_PCI;
1937                 PCIBUSMap[m->BusId] = CurrentPCIBusId;
1938                 CurrentPCIBusId++;
1939         } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) {
1940                 BUSMap[m->BusId] = MP_BUS_MCA;
1941         } else {
1942                 DPRINT("Unknown bustype %s - ignoring\n", str);
1943         }
1944 }
1945
1946 static VOID HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m)
1947 {
1948   if (!(m->ApicFlags & CPU_FLAG_ENABLED))
1949     return;
1950
1951   DPRINT("I/O APIC #%d Version %d at 0x%lX.\n",
1952     m->ApicId, m->ApicVersion, m->ApicAddress);
1953   if (IOAPICCount > MAX_IOAPIC) {
1954     DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n",
1955       MAX_IOAPIC, IOAPICCount);
1956     DPRINT1("Recompile with bigger MAX_IOAPIC!.\n");
1957     KeBugCheck(0);
1958   }
1959   IOAPICMap[IOAPICCount].ApicId = m->ApicId;
1960   IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion;
1961   IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress;
1962   IOAPICCount++;
1963 }
1964
1965 static VOID HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m)
1966 {
1967   DPRINT("Int: type %d, pol %d, trig %d, bus %d,"
1968     " IRQ %02x, APIC ID %x, APIC INT %02x\n",
1969     m->IrqType, m->IrqFlag & 3,
1970     (m->IrqFlag >> 2) & 3, m->SrcBusId,
1971     m->SrcBusIrq, m->DstApicId, m->DstApicInt);
1972   if (IRQCount > MAX_IRQ_SOURCE) {
1973     DPRINT1("Max # of irq sources exceeded!!\n");
1974     KeBugCheck(0);
1975   }
1976
1977   IRQMap[IRQCount] = *m;
1978   IRQCount++;
1979 }
1980
1981 static VOID HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m)
1982 {
1983   DPRINT("Lint: type %d, pol %d, trig %d, bus %d,"
1984     " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
1985     m->IrqType, m->IrqFlag & 3,
1986     (m->IrqFlag >> 2) & 3, m->SrcBusId,
1987     m->SrcBusIrq, m->DstApicId, m->DstApicLInt);
1988   /*
1989    * Well it seems all SMP boards in existence
1990    * use ExtINT/LVT1 == LINT0 and
1991    * NMI/LVT2 == LINT1 - the following check
1992    * will show us if this assumptions is false.
1993    * Until then we do not have to add baggage.
1994    */
1995   if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) {
1996     DPRINT1("Invalid MP table!\n");
1997     KeBugCheck(0);
1998   }
1999   if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) {
2000     DPRINT1("Invalid MP table!\n");
2001     KeBugCheck(0);
2002   }
2003 }
2004
2005
2006 VOID
2007 HaliReadMPConfigTable(
2008    PMP_CONFIGURATION_TABLE Table)
2009 /*
2010    PARAMETERS:
2011       Table = Pointer to MP configuration table
2012  */
2013 {
2014    PUCHAR Entry;
2015    ULONG Count;
2016
2017    if (Table->Signature != MPC_SIGNATURE)
2018      {
2019        PUCHAR pc = (PUCHAR)&Table->Signature;
2020        
2021        DbgPrint("Bad MP configuration block signature: %c%c%c%c\n", 
2022                 pc[0], pc[1], pc[2], pc[3]);
2023        KeBugCheck(0);
2024        return;
2025      }
2026
2027    if (MPChecksum((PUCHAR)Table, Table->Length))
2028      {
2029        DbgPrint("Bad MP configuration block checksum\n");
2030        KeBugCheck(0);
2031        return;
2032      }
2033
2034    if (Table->Specification < 0x04)
2035      {
2036        DbgPrint("Bad MP configuration table version (%d)\n",
2037                 Table->Specification);
2038        KeBugCheck(0);
2039        return;
2040      }
2041
2042    APICBase = (PULONG)Table->LocalAPICAddress;
2043    if (APICBase != (PULONG)APIC_DEFAULT_BASE)
2044      {
2045        DbgPrint("APIC base address is at 0x%X. " \
2046                 "I cannot handle non-standard adresses\n", APICBase);
2047        KeBugCheck(0);
2048      }
2049
2050    Entry = (PUCHAR)((PVOID)Table + sizeof(MP_CONFIGURATION_TABLE));
2051    Count = 0;
2052    while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE)))
2053    {
2054      /* Switch on type */
2055      switch (*Entry)
2056        {
2057        case MPCTE_PROCESSOR:
2058          {
2059            HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry);
2060            Entry += sizeof(MP_CONFIGURATION_PROCESSOR);
2061            Count += sizeof(MP_CONFIGURATION_PROCESSOR);
2062            break;
2063          }
2064        case MPCTE_BUS:
2065          {
2066            HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry);
2067            Entry += sizeof(MP_CONFIGURATION_BUS);
2068            Count += sizeof(MP_CONFIGURATION_BUS);
2069            break;
2070          }
2071        case MPCTE_IOAPIC:
2072          {
2073            HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry);
2074            Entry += sizeof(MP_CONFIGURATION_IOAPIC);
2075            Count += sizeof(MP_CONFIGURATION_IOAPIC);
2076            break;
2077          }
2078        case MPCTE_INTSRC:
2079          {
2080            HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry);
2081            Entry += sizeof(MP_CONFIGURATION_INTSRC);
2082            Count += sizeof(MP_CONFIGURATION_INTSRC);
2083            break;
2084          }
2085        case MPCTE_LINTSRC:
2086          {
2087            HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry);
2088            Entry += sizeof(MP_CONFIGURATION_INTLOCAL);
2089            Count += sizeof(MP_CONFIGURATION_INTLOCAL);
2090            break;
2091          }
2092        default:
2093          DbgPrint("Unknown entry in MPC table\n");
2094          KeBugCheck(0);
2095        }
2096    }
2097 }
2098
2099
2100 static VOID HaliConstructDefaultIOIrqMPTable(
2101   ULONG Type)
2102 {
2103         MP_CONFIGURATION_INTSRC intsrc;
2104         ULONG i;
2105
2106         intsrc.Type = MPCTE_INTSRC;
2107         intsrc.IrqFlag = 0;                     /* conforming */
2108         intsrc.SrcBusId = 0;
2109         intsrc.DstApicId = IOAPICMap[0].ApicId;
2110
2111         intsrc.IrqType = INT_VECTORED;
2112         for (i = 0; i < 16; i++) {
2113                 switch (Type) {
2114                 case 2:
2115                         if (i == 0 || i == 13)
2116                                 continue;       /* IRQ0 & IRQ13 not connected */
2117                         /* Fall through */
2118                 default:
2119                         if (i == 2)
2120                                 continue;       /* IRQ2 is never connected */
2121                 }
2122
2123                 intsrc.SrcBusIrq = i;
2124                 intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */
2125                 HaliMPIntSrcInfo(&intsrc);
2126         }
2127
2128         intsrc.IrqType = INT_EXTINT;
2129         intsrc.SrcBusIrq = 0;
2130         intsrc.DstApicInt = 0; /* 8259A to INTIN0 */
2131         HaliMPIntSrcInfo(&intsrc);
2132 }
2133
2134
2135 static VOID HaliConstructDefaultISAMPTable(
2136   ULONG Type)
2137 {
2138         MP_CONFIGURATION_PROCESSOR processor;
2139         MP_CONFIGURATION_BUS bus;
2140         MP_CONFIGURATION_IOAPIC ioapic;
2141         MP_CONFIGURATION_INTLOCAL lintsrc;
2142         ULONG linttypes[2] = { INT_EXTINT, INT_NMI };
2143         ULONG i;
2144
2145   APICBase = (PULONG)APIC_DEFAULT_BASE;
2146
2147   /*
2148    * 2 CPUs, numbered 0 & 1.
2149    */
2150   processor.Type = MPCTE_PROCESSOR;
2151         /* Either an integrated APIC or a discrete 82489DX. */
2152   processor.ApicVersion = Type > 4 ? 0x10 : 0x01;
2153   processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP;
2154   /* FIXME: Get this from the bootstrap processor */
2155   processor.CpuSignature = 0;
2156   processor.FeatureFlags = 0;
2157   processor.Reserved[0] = 0;
2158   processor.Reserved[1] = 0;
2159   for (i = 0; i < 2; i++) {
2160     processor.ApicId = i;
2161     HaliMPProcessorInfo(&processor);
2162     processor.CpuFlags &= ~CPU_FLAG_BSP;
2163   }
2164
2165   bus.Type = MPCTE_BUS;
2166   bus.BusId = 0;
2167   switch (Type) {
2168     default:
2169     DPRINT("Unknown standard configuration %d\n", Type);
2170       /* Fall through */
2171     case 1:
2172     case 5:
2173       memcpy(bus.BusType, "ISA   ", 6);
2174       break;
2175     case 2:
2176     case 6:
2177     case 3:
2178       memcpy(bus.BusType, "EISA  ", 6);
2179       break;
2180     case 4:
2181     case 7:
2182       memcpy(bus.BusType, "MCA   ", 6);
2183   }
2184   HaliMPBusInfo(&bus);
2185   if (Type > 4) {
2186     bus.Type = MPCTE_BUS;
2187     bus.BusId = 1;
2188     memcpy(bus.BusType, "PCI   ", 6);
2189     HaliMPBusInfo(&bus);
2190   }
2191
2192   ioapic.Type = MPCTE_IOAPIC;
2193   ioapic.ApicId = 2;
2194   ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01;
2195   ioapic.ApicFlags = MP_IOAPIC_USABLE;
2196   ioapic.ApicAddress = IOAPIC_DEFAULT_BASE;
2197   HaliMPIOApicInfo(&ioapic);
2198
2199   /*
2200    * We set up most of the low 16 IO-APIC pins according to MPS rules.
2201    */
2202   HaliConstructDefaultIOIrqMPTable(Type);
2203
2204   lintsrc.Type = MPCTE_LINTSRC;
2205   lintsrc.IrqType = 0;
2206   lintsrc.IrqFlag = 0;  /* conforming */
2207   lintsrc.SrcBusId = 0;
2208   lintsrc.SrcBusIrq = 0;
2209   lintsrc.DstApicId = MP_APIC_ALL;
2210   for (i = 0; i < 2; i++) {
2211     lintsrc.IrqType = linttypes[i];
2212     lintsrc.DstApicLInt = i;
2213     HaliMPIntLocalInfo(&lintsrc);
2214   }
2215 }
2216
2217 BOOLEAN
2218 HaliScanForMPConfigTable(
2219    ULONG Base,
2220    ULONG Size)
2221 /*
2222    PARAMETERS:
2223       Base = Base address of region
2224       Size = Length of region to check
2225    RETURNS:
2226       TRUE if a valid MP configuration table was found
2227  */
2228 {
2229          PULONG bp = (PULONG)Base;
2230          MP_FLOATING_POINTER* mpf;
2231
2232    while (Size > 0)
2233    {
2234       if (*bp == MPF_SIGNATURE)
2235       {
2236         DbgPrint("Found MPF signature at %x, checksum %x\n", bp,
2237                  MPChecksum((PUCHAR)bp, 16));
2238          if (MPChecksum((PUCHAR)bp, 16) == 0)
2239          {
2240             mpf = (MP_FLOATING_POINTER*)bp;
2241
2242             DbgPrint("Intel MultiProcessor Specification v1.%d compliant system.\n",
2243               mpf->Specification);
2244
2245             if (mpf->Feature2 & FEATURE2_IMCRP) {
2246                APICMode = amPIC;
2247                DPRINT("Running in IMCR and PIC compatibility mode.\n")
2248             } else {
2249                APICMode = amVWIRE;
2250                DPRINT("Running in Virtual Wire compatibility mode.\n");
2251                                     }
2252
2253             switch (mpf->Feature1)
2254             {
2255                case 0:
2256                   /* Non standard configuration */
2257                   break;
2258                case 1:
2259                   DPRINT("ISA\n");
2260                   break;
2261                case 2:
2262                   DPRINT("EISA with no IRQ8 chaining\n");
2263                   break;
2264                case 3:
2265                   DPRINT("EISA\n");
2266                   break;
2267                case 4:
2268                   DPRINT("MCA\n");
2269                   break;
2270                case 5:
2271                   DPRINT("ISA and PCI\n");
2272                   break;
2273                case 6:
2274                   DPRINT("EISA and PCI\n");
2275                   break;
2276                case 7:
2277                   DPRINT("MCA and PCI\n");
2278                   break;
2279                default:
2280                   DbgPrint("Unknown standard configuration %d\n", mpf->Feature1);
2281                   return FALSE;
2282             }
2283
2284             CPUCount = 0;
2285             IOAPICCount = 0;
2286             IRQCount = 0;
2287
2288             if ((mpf->Feature1 == 0) && (mpf->Address)) {
2289               HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)mpf->Address);
2290             } else {
2291               HaliConstructDefaultISAMPTable(mpf->Feature1);
2292             }
2293
2294             return TRUE;
2295          }
2296       }
2297       bp += 4;
2298       Size -= 16;
2299    }
2300    return FALSE;
2301 }
2302
2303
2304 VOID
2305 HalpInitMPS(
2306    VOID)
2307 {
2308    USHORT EBDA;
2309    ULONG CPU;
2310
2311    /* Only initialize MP system once. Once called the first time,
2312       each subsequent call is part of the initialization sequence
2313                         for an application processor. */
2314   if (MPSInitialized) {
2315     CPU = ThisCPU();
2316
2317     DPRINT("CPU %d says it is now booted.\n", CPU);
2318
2319     APICSetup();
2320     APICCalibrateTimer(CPU);
2321
2322     /* This processor is now booted */
2323     CPUMap[CPU].Flags |= CPU_ENABLED;
2324     OnlineCPUs |= (1 << CPU);
2325
2326     return;
2327   }
2328
2329   MPSInitialized = TRUE;
2330
2331   /*
2332      Scan the system memory for an MP configuration table
2333        1) Scan the first KB of system base memory
2334        2) Scan the last KB of system base memory
2335        3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh
2336        4) Scan the Extended BIOS Data Area
2337    */
2338
2339   if (!HaliScanForMPConfigTable(0x0, 0x400)) {
2340     if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) {
2341       if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) {
2342         EBDA = *((PUSHORT)0x040E);
2343         EBDA <<= 4;
2344         if (!HaliScanForMPConfigTable((ULONG)EBDA, 0x1000)) {
2345           DbgPrint("No multiprocessor compliant system found.\n");
2346           KeBugCheck(0);
2347         }
2348       }
2349     }
2350   }
2351
2352   /* Setup IRQ to vector translation map */
2353   memset(&IRQVectorMap, sizeof(IRQVectorMap), 0);
2354
2355   /* Initialize the bootstrap processor */
2356   HaliInitBSP();
2357
2358   /* Setup I/O APIC */
2359   IOAPICSetup();
2360
2361   /* Setup busy waiting */
2362   HalpCalibrateStallExecution();
2363
2364   /* We can now enable interrupts */
2365   __asm__ __volatile__ ("sti\n\t");
2366
2367   NextCPU = 0;
2368 }
2369
2370 #endif /* MP */
2371
2372 /* EOF */