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