1 /* $Id: mp.c,v 1.12 2004/11/28 01:30:01 hbirr Exp $
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
11 * 22/05/1998 DW Created
12 * 12/04/2001 CSH Added MultiProcessor specification support
15 /* INCLUDES *****************************************************************/
18 #include <ddk/ntddk.h>
28 #include <internal/ntoskrnl.h>
29 #include <internal/i386/segment.h>
30 #include <internal/ke.h>
31 #include <internal/ps.h>
36 #include <internal/debug.h>
42 Address of area to be used for communication between Application
43 Processors (APs) and the BootStrap Processor (BSP)
45 #define COMMON_AREA 0x2000
49 typedef struct __attribute__((packed
)) _COMMON_AREA_INFO
51 ULONG Stack
; /* Location of AP stack */
52 ULONG Debug
[16]; /* For debugging */
53 } COMMON_AREA_INFO
, *PCOMMON_AREA_INFO
;
55 CPU_INFO CPUMap
[MAX_CPU
]; /* Map of all CPUs in the system */
56 ULONG CPUCount
; /* Total number of CPUs */
57 ULONG OnlineCPUs
; /* Bitmask of online CPUs */
59 UCHAR BUSMap
[MAX_BUS
]; /* Map of all buses in the system */
60 UCHAR PCIBUSMap
[MAX_BUS
]; /* Map of all PCI buses in the system */
62 IOAPIC_INFO IOAPICMap
[MAX_IOAPIC
]; /* Map of all I/O APICs in the system */
63 ULONG IOAPICCount
; /* Number of I/O APICs in the system */
65 MP_CONFIGURATION_INTSRC IRQMap
[MAX_IRQ_SOURCE
]; /* Map of all IRQs */
66 ULONG IRQVectorMap
[MAX_IRQ_SOURCE
]; /* IRQ to vector map */
67 ULONG IrqPinMap
[MAX_IRQ_SOURCE
]; /* IRQ to Pin map */
68 ULONG IrqApicMap
[MAX_IRQ_SOURCE
];
69 ULONG IRQCount
; /* Number of IRQs */
71 ULONG APICMode
; /* APIC mode at startup */
72 ULONG BootCPU
; /* Bootstrap processor */
73 PULONG BIOSBase
; /* Virtual address of BIOS data segment */
74 PULONG CommonBase
; /* Virtual address of common area */
76 extern CHAR
*APstart
, *APend
;
77 extern VOID (*APflush
)(VOID
);
79 extern VOID
MpsTimerInterrupt(VOID
);
80 extern VOID
MpsErrorInterrupt(VOID
);
81 extern VOID
MpsSpuriousInterrupt(VOID
);
82 extern VOID
MpsIpiInterrupt(VOID
);
84 #define CMOS_READ(address) ({ \
85 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
86 READ_PORT_UCHAR((PUCHAR)0x71)); \
89 #define CMOS_WRITE(address, value) ({ \
90 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
91 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
98 /* FUNCTIONS *****************************************************************/
102 /* Functions for handling 8259A PICs */
104 VOID
Disable8259AIrq(ULONG irq
)
110 tmp
= READ_PORT_UCHAR((PUCHAR
)0xA1);
111 tmp
|= (1 << (irq
- 8));
112 WRITE_PORT_UCHAR((PUCHAR
)0xA1, tmp
);
116 tmp
= READ_PORT_UCHAR((PUCHAR
)0x21);
118 WRITE_PORT_UCHAR((PUCHAR
)0x21, tmp
);
123 VOID
Enable8259AIrq(ULONG irq
)
129 tmp
= READ_PORT_UCHAR((PUCHAR
)0xA1);
130 tmp
&= ~(1 << (irq
- 8));
131 WRITE_PORT_UCHAR((PUCHAR
)0xA1, tmp
);
135 tmp
= READ_PORT_UCHAR((PUCHAR
)0x21);
137 WRITE_PORT_UCHAR((PUCHAR
)0x21, tmp
);
142 /* Functions for handling I/O APICs */
144 volatile ULONG
IOAPICRead(ULONG Apic
, ULONG Offset
)
148 Base
= (PULONG
)IOAPICMap
[Apic
].ApicAddress
;
150 return *((PULONG
)((ULONG
)Base
+ IOAPIC_IOWIN
));
153 VOID
IOAPICWrite(ULONG Apic
, ULONG Offset
, ULONG Value
)
157 Base
= (PULONG
)IOAPICMap
[Apic
].ApicAddress
;
159 *((PULONG
)((ULONG
)Base
+ IOAPIC_IOWIN
)) = Value
;
163 VOID
IOAPICClearPin(ULONG Apic
, ULONG Pin
)
165 IOAPIC_ROUTE_ENTRY Entry
;
167 DPRINT("IOAPICClearPin(Apic %d, Pin %d\n", Apic
, Pin
);
169 * Disable it in the IO-APIC irq-routing table
171 memset(&Entry
, 0, sizeof(Entry
));
174 IOAPICWrite(Apic
, IOAPIC_REDTBL
+ 2 * Pin
, *(((PULONG
)&Entry
) + 0));
175 IOAPICWrite(Apic
, IOAPIC_REDTBL
+ 1 + 2 * Pin
, *(((PULONG
)&Entry
) + 1));
178 static VOID
IOAPICClear(ULONG Apic
)
182 for (Pin
= 0; Pin
< /*IOAPICMap[Apic].EntryCount*/24; Pin
++)
184 IOAPICClearPin(Apic
, Pin
);
188 static VOID
IOAPICClearAll(VOID
)
192 for (Apic
= 0; Apic
< IOAPICCount
; Apic
++)
198 /* This is performance critical and should probably be done in assembler */
199 VOID
IOAPICMaskIrq(ULONG Irq
)
201 IOAPIC_ROUTE_ENTRY Entry
;
202 ULONG Apic
= IrqApicMap
[Irq
];
205 *((PULONG
)&Entry
) = IOAPICRead(Apic
, IOAPIC_REDTBL
+2*Irq
);
207 IOAPICWrite(Apic
, IOAPIC_REDTBL
+2*Irq
, *((PULONG
)&Entry
));
211 /* This is performance critical and should probably be done in assembler */
212 VOID
IOAPICUnmaskIrq(ULONG Irq
)
214 IOAPIC_ROUTE_ENTRY Entry
;
215 ULONG Apic
= IrqApicMap
[Irq
];
217 *((PULONG
)&Entry
) = IOAPICRead(Apic
, IOAPIC_REDTBL
+2*IrqPinMap
[Irq
]);
219 IOAPICWrite(Apic
, IOAPIC_REDTBL
+2*IrqPinMap
[Irq
], *((PULONG
)&Entry
));
229 * Set the IOAPIC ID to the value stored in the MPC table.
231 for (apic
= 0; apic
< IOAPICCount
; apic
++)
234 /* Read the register 0 value */
235 tmp
= IOAPICRead(apic
, IOAPIC_ID
);
237 old_id
= IOAPICMap
[apic
].ApicId
;
239 if (IOAPICMap
[apic
].ApicId
>= 0xf)
241 DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
242 apic
, IOAPICMap
[apic
].ApicId
);
243 DPRINT1("... fixing up to %d. (tell your hw vendor)\n",
245 IOAPICMap
[apic
].ApicId
= GET_IOAPIC_ID(tmp
);
249 * We need to adjust the IRQ routing table
252 if (old_id
!= IOAPICMap
[apic
].ApicId
)
254 for (i
= 0; i
< IRQCount
; i
++)
256 if (IRQMap
[i
].DstApicId
== old_id
)
258 IRQMap
[i
].DstApicId
= IOAPICMap
[apic
].ApicId
;
264 * Read the right value from the MPC table and
265 * write it into the ID register.
267 DPRINT("Changing IO-APIC physical APIC ID to %d\n",
268 IOAPICMap
[apic
].ApicId
);
270 tmp
&= ~IOAPIC_ID_MASK
;
271 tmp
|= SET_IOAPIC_ID(IOAPICMap
[apic
].ApicId
);
273 IOAPICWrite(apic
, IOAPIC_ID
, tmp
);
278 tmp
= IOAPICRead(apic
, 0);
279 if (GET_IOAPIC_ID(tmp
) != IOAPICMap
[apic
].ApicId
)
281 DPRINT1("Could not set I/O APIC ID!\n");
289 * EISA Edge/Level control register, ELCR
291 static ULONG
EISA_ELCR(ULONG irq
)
295 PUCHAR port
= (PUCHAR
)(0x4d0 + (irq
>> 3));
296 return (READ_PORT_UCHAR(port
) >> (irq
& 7)) & 1;
298 DPRINT("Broken MPtable reports ISA irq %d\n", irq
);
302 /* EISA interrupts are always polarity zero and can be edge or level
303 * trigger depending on the ELCR value. If an interrupt is listed as
304 * EISA conforming in the MP table, that means its trigger type must
305 * be read in from the ELCR */
307 #define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq))
308 #define default_EISA_polarity(idx) (0)
310 /* ISA interrupts are always polarity zero edge triggered,
311 * when listed as conforming in the MP table. */
313 #define default_ISA_trigger(idx) (0)
314 #define default_ISA_polarity(idx) (0)
316 /* PCI interrupts are always polarity one level triggered,
317 * when listed as conforming in the MP table. */
319 #define default_PCI_trigger(idx) (1)
320 #define default_PCI_polarity(idx) (1)
322 /* MCA interrupts are always polarity zero level triggered,
323 * when listed as conforming in the MP table. */
325 #define default_MCA_trigger(idx) (1)
326 #define default_MCA_polarity(idx) (0)
328 static ULONG
IRQPolarity(ULONG idx
)
330 ULONG bus
= IRQMap
[idx
].SrcBusId
;
334 * Determine IRQ line polarity (high active or low active):
336 switch (IRQMap
[idx
].IrqFlag
& 3)
338 case 0: /* conforms, ie. bus-type dependent polarity */
342 case MP_BUS_ISA
: /* ISA pin */
344 polarity
= default_ISA_polarity(idx
);
347 case MP_BUS_EISA
: /* EISA pin */
349 polarity
= default_EISA_polarity(idx
);
352 case MP_BUS_PCI
: /* PCI pin */
354 polarity
= default_PCI_polarity(idx
);
357 case MP_BUS_MCA
: /* MCA pin */
359 polarity
= default_MCA_polarity(idx
);
364 DPRINT("Broken BIOS!!\n");
371 case 1: /* high active */
376 case 2: /* reserved */
378 DPRINT("Broken BIOS!!\n");
382 case 3: /* low active */
387 default: /* invalid */
389 DPRINT("Broken BIOS!!\n");
397 static ULONG
IRQTrigger(ULONG idx
)
399 ULONG bus
= IRQMap
[idx
].SrcBusId
;
403 * Determine IRQ trigger mode (edge or level sensitive):
405 switch ((IRQMap
[idx
].IrqFlag
>> 2) & 3)
407 case 0: /* conforms, ie. bus-type dependent */
411 case MP_BUS_ISA
: /* ISA pin */
413 trigger
= default_ISA_trigger(idx
);
416 case MP_BUS_EISA
: /* EISA pin */
418 trigger
= default_EISA_trigger(idx
);
421 case MP_BUS_PCI
: /* PCI pin */
423 trigger
= default_PCI_trigger(idx
);
426 case MP_BUS_MCA
: /* MCA pin */
428 trigger
= default_MCA_trigger(idx
);
433 DPRINT("Broken BIOS!!\n");
445 case 2: /* reserved */
447 DPRINT("Broken BIOS!!\n");
456 default: /* invalid */
458 DPRINT("Broken BIOS!!\n");
467 static ULONG
Pin2Irq(ULONG idx
,
472 ULONG bus
= IRQMap
[idx
].SrcBusId
;
475 * Debugging check, we are in big trouble if this message pops up!
477 if (IRQMap
[idx
].DstApicInt
!= pin
) {
478 DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n");
483 case MP_BUS_ISA
: /* ISA pin */
487 irq
= IRQMap
[idx
].SrcBusIrq
;
490 case MP_BUS_PCI
: /* PCI pin */
493 * PCI IRQs are mapped in order
497 irq
+= IOAPICMap
[i
++].EntryCount
;
503 DPRINT("Unknown bus type %d.\n",bus
);
514 * Rough estimation of how many shared IRQs there are, can
515 * be changed anytime.
517 #define MAX_PLUS_SHARED_IRQS PIC_IRQS
518 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + PIC_IRQS)
521 * This is performance-critical, we want to do it O(1)
523 * the indexing order of this array favors 1:1 mappings
524 * between pins and IRQs.
527 static struct irq_pin_list
{
528 ULONG apic
, pin
, next
;
529 } irq_2_pin
[PIN_MAP_SIZE
];
532 * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
533 * shared ISA-space IRQs, so we have to support them. We are super
534 * fast in the common case, and fast for shared ISA-space IRQs.
536 static VOID
AddPinToIrq(ULONG irq
,
540 static ULONG first_free_entry
= PIC_IRQS
;
541 struct irq_pin_list
*entry
= irq_2_pin
+ irq
;
545 entry
= irq_2_pin
+ entry
->next
;
548 if (entry
->pin
!= -1)
550 entry
->next
= first_free_entry
;
551 entry
= irq_2_pin
+ entry
->next
;
552 if (++first_free_entry
>= PIN_MAP_SIZE
)
564 * Find the IRQ entry number of a certain pin.
566 static ULONG
IOAPICGetIrqEntry(ULONG apic
,
572 for (i
= 0; i
< IRQCount
; i
++)
574 if (IRQMap
[i
].IrqType
== type
&&
575 (IRQMap
[i
].DstApicId
== IOAPICMap
[apic
].ApicId
|| IRQMap
[i
].DstApicId
== MP_APIC_ALL
) &&
576 IRQMap
[i
].DstApicInt
== pin
)
585 static ULONG
AssignIrqVector(ULONG irq
)
588 static ULONG current_vector
= FIRST_DEVICE_VECTOR
, vector_offset
= 0;
591 /* There may already have been assigned a vector for this IRQ */
592 vector
= IRQVectorMap
[irq
];
598 if (current_vector
> FIRST_SYSTEM_VECTOR
) {
600 current_vector
= FIRST_DEVICE_VECTOR
+ vector_offset
;
601 } else if (current_vector
== FIRST_SYSTEM_VECTOR
) {
602 DPRINT1("Ran out of interrupt sources!");
606 vector
= current_vector
;
607 IRQVectorMap
[irq
] = vector
;
611 vector
= IRQ2VECTOR(irq
);
612 IRQVectorMap
[irq
] = vector
;
618 VOID
IOAPICSetupIrqs(VOID
)
620 IOAPIC_ROUTE_ENTRY entry
;
621 ULONG apic
, pin
, idx
, irq
, first_notcon
= 1, vector
;
623 DPRINT("Init IO_APIC IRQs\n");
625 for (apic
= 0; apic
< IOAPICCount
; apic
++)
627 for (pin
= 0; pin
< IOAPICMap
[apic
].EntryCount
; pin
++)
630 * add it to the IO-APIC irq-routing table
632 memset(&entry
,0,sizeof(entry
));
634 entry
.delivery_mode
= APIC_DM_LOWEST
;
635 entry
.dest_mode
= 1; /* logical delivery */
636 entry
.mask
= 1; /* disable IRQ */
640 * Some drivers are not able to deal with more than one cpu.
642 entry
.dest
.logical
.logical_dest
= OnlineCPUs
;
644 entry
.dest
.logical
.logical_dest
= 1 << 0;
646 idx
= IOAPICGetIrqEntry(apic
,pin
,INT_VECTORED
);
651 DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap
[apic
].ApicId
, pin
);
656 DPRINT(", %d-%d\n", IOAPICMap
[apic
].ApicId
, pin
);
661 entry
.trigger
= IRQTrigger(idx
);
662 entry
.polarity
= IRQPolarity(idx
);
667 entry
.mask
= 1; // disable
669 entry
.dest
.logical
.logical_dest
= OnlineCPUs
;
671 entry
.dest
.logical
.logical_dest
= 1 << 0;
675 irq
= Pin2Irq(idx
, apic
, pin
);
676 AddPinToIrq(irq
, apic
, pin
);
678 vector
= AssignIrqVector(irq
);
679 entry
.vector
= vector
;
681 DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector
, irq
);
689 if ((apic
== 0) && (irq
< 16))
691 Disable8259AIrq(irq
);
693 IOAPICWrite(apic
, IOAPIC_REDTBL
+2*pin
+1, *(((PULONG
)&entry
)+1));
694 IOAPICWrite(apic
, IOAPIC_REDTBL
+2*pin
, *(((PULONG
)&entry
)+0));
696 IrqPinMap
[irq
] = pin
;
697 IrqApicMap
[irq
] = apic
;
699 DPRINT("Vector %x, Pin %x, Irq %x\n", vector
, pin
, irq
);
705 static VOID
IOAPICEnable(VOID
)
709 for (i
= 0; i
< PIN_MAP_SIZE
; i
++)
711 irq_2_pin
[i
].pin
= -1;
712 irq_2_pin
[i
].next
= 0;
716 * The number of IO-APIC IRQ registers (== #pins):
718 for (i
= 0; i
< IOAPICCount
; i
++)
720 tmp
= IOAPICRead(i
, IOAPIC_VER
);
721 IOAPICMap
[i
].EntryCount
= GET_IOAPIC_MRE(tmp
) + 1;
725 * Do not trust the IO-APIC being empty at bootup
731 static VOID
IOAPICDisable(VOID
)
734 * Clear the IO-APIC before rebooting
742 static VOID
IOAPICSetup(VOID
)
751 VOID
IOAPICDump(VOID
)
754 ULONG reg0
, reg1
, reg2
=0;
756 DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount
);
757 for (i
= 0; i
< IOAPICCount
; i
++)
759 DbgPrint("Number of IO-APIC #%d registers: %d.\n",
761 IOAPICMap
[i
].EntryCount
);
765 * We are a bit conservative about what we expect. We have to
766 * know about every hardware change ASAP.
768 DbgPrint("Testing the IO APIC.......................\n");
770 for (apic
= 0; apic
< IOAPICCount
; apic
++)
772 reg0
= IOAPICRead(apic
, IOAPIC_ID
);
773 reg1
= IOAPICRead(apic
, IOAPIC_VER
);
774 if (GET_IOAPIC_VERSION(reg1
) >= 0x10)
776 reg2
= IOAPICRead(apic
, IOAPIC_ARB
);
780 DbgPrint("IO APIC #%d......\n", IOAPICMap
[apic
].ApicId
);
781 DbgPrint(".... register #00: %08X\n", reg0
);
782 DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0
));
783 if (reg0
& 0xF0FFFFFF)
785 DbgPrint(" WARNING: Unexpected IO-APIC\n");
788 DbgPrint(".... register #01: %08X\n", reg1
);
789 i
= GET_IOAPIC_MRE(reg1
);
791 DbgPrint("....... : max redirection entries: %04X\n", i
);
792 if ((i
!= 0x0f) && /* older (Neptune) boards */
793 (i
!= 0x17) && /* typical ISA+PCI boards */
794 (i
!= 0x1b) && /* Compaq Proliant boards */
795 (i
!= 0x1f) && /* dual Xeon boards */
796 (i
!= 0x22) && /* bigger Xeon boards */
800 DbgPrint(" WARNING: Unexpected IO-APIC\n");
803 i
= GET_IOAPIC_VERSION(reg1
);
804 DbgPrint("....... : IO APIC version: %04X\n", i
);
805 if ((i
!= 0x01) && /* 82489DX IO-APICs */
806 (i
!= 0x10) && /* oldest IO-APICs */
807 (i
!= 0x11) && /* Pentium/Pro IO-APICs */
808 (i
!= 0x13)) /* Xeon IO-APICs */
810 DbgPrint(" WARNING: Unexpected IO-APIC\n");
813 if (reg1
& 0xFF00FF00)
815 DbgPrint(" WARNING: Unexpected IO-APIC\n");
818 if (GET_IOAPIC_VERSION(reg1
) >= 0x10)
820 DbgPrint(".... register #02: %08X\n", reg2
);
821 DbgPrint("....... : arbitration: %02X\n",
822 GET_IOAPIC_ARB(reg2
));
823 if (reg2
& 0xF0FFFFFF)
825 DbgPrint(" WARNING: Unexpected IO-APIC\n");
829 DbgPrint(".... IRQ redirection table:\n");
830 DbgPrint(" NR Log Phy Mask Trig IRR Pol"
831 " Stat Dest Deli Vect: \n");
833 for (i
= 0; i
<= GET_IOAPIC_MRE(reg1
); i
++)
835 IOAPIC_ROUTE_ENTRY entry
;
837 *(((PULONG
)&entry
)+0) = IOAPICRead(apic
, 0x10+i
*2);
838 *(((PULONG
)&entry
)+1) = IOAPICRead(apic
, 0x11+i
*2);
840 DbgPrint(" %02x %03X %02X ",
842 entry
.dest
.logical
.logical_dest
,
843 entry
.dest
.physical
.physical_dest
);
845 DbgPrint("%C %C %1d %C %C %C %03X %02X\n",
846 (entry
.mask
== 0) ? 'U' : 'M', // Unmasked/masked
847 (entry
.trigger
== 0) ? 'E' : 'L', // Edge/level sensitive
849 (entry
.polarity
== 0) ? 'H' : 'L', // Active high/active low
850 (entry
.delivery_status
== 0) ? 'I' : 'S', // Idle / send pending
851 (entry
.dest_mode
== 0) ? 'P' : 'L', // Physical logical
856 DbgPrint("IRQ to pin mappings:\n");
857 for (i
= 0; i
< PIC_IRQS
; i
++)
859 struct irq_pin_list
*entry
= irq_2_pin
+ i
;
864 DbgPrint("IRQ%d ", i
);
867 DbgPrint("-> %d", entry
->pin
);
872 entry
= irq_2_pin
+ entry
->next
;
884 DbgPrint(".................................... done.\n");
889 /* Functions for handling local APICs */
891 ULONG
Read8254Timer(VOID
)
895 WRITE_PORT_UCHAR((PUCHAR
)0x43, 0x00);
896 Count
= READ_PORT_UCHAR((PUCHAR
)0x40);
897 Count
|= READ_PORT_UCHAR((PUCHAR
)0x40) << 8;
902 VOID
WaitFor8254Wraparound(VOID
)
904 ULONG CurCount
, PrevCount
= ~0;
907 CurCount
= Read8254Timer();
910 PrevCount
= CurCount
;
911 CurCount
= Read8254Timer();
912 Delta
= CurCount
- PrevCount
;
915 * This limit for delta seems arbitrary, but it isn't, it's
916 * slightly above the level of error a buggy Mercury/Neptune
917 * chipset timer can cause.
925 #define APIC_DIVISOR (16)
927 VOID
APICSetupLVTT(ULONG ClockTicks
)
931 tmp
= GET_APIC_VERSION(APICRead(APIC_VER
));
932 if (!APIC_INTEGRATED(tmp
))
934 tmp
= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV
) | APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
939 tmp
= APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
941 APICWrite(APIC_LVTT
, tmp
);
943 tmp
= APICRead(APIC_TDCR
);
944 tmp
&= ~(APIC_TDCR_1
| APIC_TIMER_BASE_DIV
);
946 APICWrite(APIC_TDCR
, tmp
);
947 APICWrite(APIC_ICRT
, ClockTicks
/ APIC_DIVISOR
);
951 VOID
APICCalibrateTimer(ULONG CPU
)
953 ULARGE_INTEGER t1
, t2
;
956 DPRINT("Calibrating APIC timer for CPU %d\n", CPU
);
958 APICSetupLVTT(1000000000);
961 * The timer chip counts down to zero. Let's wait
962 * for a wraparound to start exact measurement:
963 * (the current tick might have been already half done)
965 WaitFor8254Wraparound();
968 * We wrapped around just now. Let's start
970 ReadPentiumClock(&t1
);
971 tt1
= APICRead(APIC_CCRT
);
973 WaitFor8254Wraparound();
976 tt2
= APICRead(APIC_CCRT
);
977 ReadPentiumClock(&t2
);
979 CPUMap
[CPU
].BusSpeed
= (HZ
* (long)(tt1
- tt2
) * APIC_DIVISOR
);
980 CPUMap
[CPU
].CoreSpeed
= (HZ
* (t2
.QuadPart
- t1
.QuadPart
));
982 /* Setup timer for normal operation */
983 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
984 APICSetupLVTT((CPUMap
[CPU
].BusSpeed
/ 1000000) * 10000); // 10ms
985 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
987 DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
988 CPUMap
[CPU
].CoreSpeed
/1000000,
989 CPUMap
[CPU
].CoreSpeed
%1000000);
991 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
992 CPUMap
[CPU
].BusSpeed
/1000000,
993 CPUMap
[CPU
].BusSpeed
%1000000);
997 SetInterruptGate(ULONG index
, ULONG address
)
1001 idt
= (IDT_DESCRIPTOR
*)((ULONG
)KeGetCurrentKPCR()->IDT
+ index
* sizeof(IDT_DESCRIPTOR
));
1002 idt
->a
= (((ULONG
)address
)&0xffff) + (KERNEL_CS
<< 16);
1003 idt
->b
= 0x8e00 + (((ULONG
)address
)&0xffff0000);
1009 HalInitializeProcessor(ULONG ProcessorNumber
,
1010 PVOID
/*PLOADER_PARAMETER_BLOCK*/ LoaderBlock
)
1016 DPRINT("HalInitializeProcessor(%x %x)\n", ProcessorNumber
, LoaderBlock
);
1020 if (OnlineCPUs
& (1 << CPU
))
1025 if (ProcessorNumber
== 0)
1033 DPRINT("CPU %d says it is now booted.\n", CPU
);
1035 APICCalibrateTimer(CPU
);
1038 /* This processor is now booted */
1039 CPUMap
[CPU
].Flags
|= CPU_ENABLED
;
1040 OnlineCPUs
|= (1 << CPU
);
1042 /* Setup busy waiting */
1043 HalpCalibrateStallExecution();
1048 HalAllProcessorsStarted (VOID
)
1050 DPRINT("HalAllProcessorsStarted()\n");
1055 for (i
= 0; i
< 32; i
++)
1057 if (OnlineCPUs
& (1 << i
))
1062 if (CPUs
> CPUCount
)
1066 else if (CPUs
== CPUCount
)
1081 HalStartNextProcessor(ULONG Unknown1
,
1082 ULONG ProcessorStack
)
1085 PCOMMON_AREA_INFO Common
;
1087 ULONG DeliveryStatus
= 0;
1088 ULONG AcceptStatus
= 0;
1092 DPRINT("HalStartNextProcessor(%x %x)\n", Unknown1
, ProcessorStack
);
1094 for (CPU
= 0; CPU
< CPUCount
; CPU
++)
1096 if (!(OnlineCPUs
& (1<<CPU
)))
1102 if (CPU
>= CPUCount
)
1107 DPRINT1("Attempting to boot CPU %d\n", CPU
);
1111 APICSendIPI(CPU
, APIC_DM_INIT
|APIC_ICR0_LEVEL_ASSERT
);
1113 KeStallExecutionProcessor(200);
1117 APICSendIPI(CPU
, APIC_DM_INIT
|APIC_ICR0_LEVEL_DEASSERT
);
1119 if (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
1121 /* Clear APIC errors */
1122 APICWrite(APIC_ESR
, 0);
1123 tmp
= (APICRead(APIC_ESR
) & APIC_ESR_MASK
);
1126 Common
= (PCOMMON_AREA_INFO
)CommonBase
;
1128 /* Write the location of the AP stack */
1129 Common
->Stack
= (ULONG
)ProcessorStack
;
1131 DPRINT("CPU %d got stack at 0x%X\n", CPU
, Common
->Stack
);
1133 for (j
= 0; j
< 16; j
++)
1135 Common
->Debug
[j
] = 0;
1139 maxlvt
= APICGetMaxLVT();
1141 /* Is this a local APIC or an 82489DX? */
1142 StartupCount
= (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
)) ? 2 : 0;
1144 for (i
= 1; i
<= StartupCount
; i
++)
1146 /* It's a local APIC, so send STARTUP IPI */
1147 DPRINT("Sending startup signal %d\n", i
);
1149 APICWrite(APIC_ESR
, 0);
1152 APICSendIPI(CPU
, APIC_DM_STARTUP
| ((COMMON_AREA
+ PAGE_SIZE
) >> 12)|APIC_ICR0_LEVEL_DEASSERT
);
1154 /* Wait up to 10ms for IPI to be delivered */
1158 KeStallExecutionProcessor(10);
1160 /* Check Delivery Status */
1161 DeliveryStatus
= APICRead(APIC_ICR0
) & APIC_ICR0_DS
;
1164 } while ((DeliveryStatus
) && (j
< 1000));
1166 KeStallExecutionProcessor(200);
1169 * Due to the Pentium erratum 3AP.
1173 APICRead(APIC_SIVR
);
1174 APICWrite(APIC_ESR
, 0);
1177 AcceptStatus
= APICRead(APIC_ESR
) & APIC_ESR_MASK
;
1179 if (DeliveryStatus
|| AcceptStatus
)
1187 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", CPU
);
1192 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", CPU
);
1195 if (!(DeliveryStatus
|| AcceptStatus
))
1198 /* Wait no more than 5 seconds for processor to boot */
1199 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", CPU
);
1201 /* Wait no more than 5 seconds */
1202 for (j
= 0; j
< 50000; j
++)
1204 if (CPUMap
[CPU
].Flags
& CPU_ENABLED
)
1208 KeStallExecutionProcessor(100);
1212 if (CPUMap
[CPU
].Flags
& CPU_ENABLED
)
1214 DbgPrint("CPU %d is now running\n", CPU
);
1218 DbgPrint("Initialization of CPU %d failed\n", CPU
);
1222 DPRINT("Debug bytes are:\n");
1224 for (j
= 0; j
< 4; j
++)
1226 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1227 Common
->Debug
[j
*4+0],
1228 Common
->Debug
[j
*4+1],
1229 Common
->Debug
[j
*4+2],
1230 Common
->Debug
[j
*4+3]);
1241 ULONG
MPChecksum(PUCHAR Base
,
1244 * Checksum an MP configuration block
1256 PCHAR
HaliMPFamily(ULONG Family
,
1259 static CHAR str
[32];
1260 static PCHAR CPUs
[] =
1262 "80486DX", "80486DX",
1263 "80486SX", "80486DX/2 or 80487",
1264 "80486SL", "Intel5X2(tm)",
1265 "Unknown", "Unknown",
1269 return ("Pentium(tm) Pro");
1271 return ("Pentium(tm)");
1272 if (Family
== 0x0F && Model
== 0x0F)
1273 return("Special controller");
1274 if (Family
== 0x0F && Model
== 0x00)
1275 return("Pentium 4(tm)");
1276 if (Family
== 0x04 && Model
< 9)
1278 sprintf(str
, "Unknown CPU with family ID %ld and model ID %ld", Family
, Model
);
1282 static VOID
HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m
)
1286 if (!(m
->CpuFlags
& CPU_FLAG_ENABLED
))
1289 DPRINT("Processor #%d %s APIC version %d\n",
1291 HaliMPFamily((m
->FeatureFlags
& CPU_FAMILY_MASK
) >> 8,
1292 (m
->FeatureFlags
& CPU_MODEL_MASK
) >> 4),
1295 if (m
->FeatureFlags
& (1 << 0))
1296 DPRINT(" Floating point unit present.\n");
1297 if (m
->FeatureFlags
& (1 << 7))
1298 DPRINT(" Machine Exception supported.\n");
1299 if (m
->FeatureFlags
& (1 << 8))
1300 DPRINT(" 64 bit compare & exchange supported.\n");
1301 if (m
->FeatureFlags
& (1 << 9))
1302 DPRINT(" Internal APIC present.\n");
1303 if (m
->FeatureFlags
& (1 << 11))
1304 DPRINT(" SEP present.\n");
1305 if (m
->FeatureFlags
& (1 << 12))
1306 DPRINT(" MTRR present.\n");
1307 if (m
->FeatureFlags
& (1 << 13))
1308 DPRINT(" PGE present.\n");
1309 if (m
->FeatureFlags
& (1 << 14))
1310 DPRINT(" MCA present.\n");
1311 if (m
->FeatureFlags
& (1 << 15))
1312 DPRINT(" CMOV present.\n");
1313 if (m
->FeatureFlags
& (1 << 16))
1314 DPRINT(" PAT present.\n");
1315 if (m
->FeatureFlags
& (1 << 17))
1316 DPRINT(" PSE present.\n");
1317 if (m
->FeatureFlags
& (1 << 18))
1318 DPRINT(" PSN present.\n");
1319 if (m
->FeatureFlags
& (1 << 19))
1320 DPRINT(" Cache Line Flush Instruction present.\n");
1322 if (m
->FeatureFlags
& (1 << 21))
1323 DPRINT(" Debug Trace and EMON Store present.\n");
1324 if (m
->FeatureFlags
& (1 << 22))
1325 DPRINT(" ACPI Thermal Throttle Registers present.\n");
1326 if (m
->FeatureFlags
& (1 << 23))
1327 DPRINT(" MMX present.\n");
1328 if (m
->FeatureFlags
& (1 << 24))
1329 DPRINT(" FXSR present.\n");
1330 if (m
->FeatureFlags
& (1 << 25))
1331 DPRINT(" XMM present.\n");
1332 if (m
->FeatureFlags
& (1 << 26))
1333 DPRINT(" Willamette New Instructions present.\n");
1334 if (m
->FeatureFlags
& (1 << 27))
1335 DPRINT(" Self Snoop present.\n");
1337 if (m
->FeatureFlags
& (1 << 29))
1338 DPRINT(" Thermal Monitor present.\n");
1339 /* 30, 31 Reserved */
1341 CPUMap
[CPUCount
].APICId
= m
->ApicId
;
1343 CPUMap
[CPUCount
].Flags
= CPU_USABLE
;
1345 if (m
->CpuFlags
& CPU_FLAG_BSP
)
1347 DPRINT(" Bootup CPU\n");
1348 CPUMap
[CPUCount
].Flags
|= CPU_BSP
;
1349 BootCPU
= m
->ApicId
;
1352 if (m
->ApicId
> MAX_CPU
)
1354 DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m
->ApicId
, MAX_CPU
);
1357 ver
= m
->ApicVersion
;
1364 DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m
->ApicId
);
1367 CPUMap
[CPUCount
].APICVersion
= ver
;
1372 static VOID
HaliMPBusInfo(PMP_CONFIGURATION_BUS m
)
1374 static ULONG CurrentPCIBusId
= 0;
1377 memcpy(str
, m
->BusType
, 6);
1379 DPRINT("Bus #%d is %s\n", m
->BusId
, str
);
1381 if (strncmp(str
, BUSTYPE_ISA
, sizeof(BUSTYPE_ISA
)-1) == 0)
1383 BUSMap
[m
->BusId
] = MP_BUS_ISA
;
1385 else if (strncmp(str
, BUSTYPE_EISA
, sizeof(BUSTYPE_EISA
)-1) == 0)
1387 BUSMap
[m
->BusId
] = MP_BUS_EISA
;
1389 else if (strncmp(str
, BUSTYPE_PCI
, sizeof(BUSTYPE_PCI
)-1) == 0)
1391 BUSMap
[m
->BusId
] = MP_BUS_PCI
;
1392 PCIBUSMap
[m
->BusId
] = CurrentPCIBusId
;
1395 else if (strncmp(str
, BUSTYPE_MCA
, sizeof(BUSTYPE_MCA
)-1) == 0)
1397 BUSMap
[m
->BusId
] = MP_BUS_MCA
;
1401 DPRINT("Unknown bustype %s - ignoring\n", str
);
1405 static VOID
HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m
)
1407 if (!(m
->ApicFlags
& CPU_FLAG_ENABLED
))
1410 DPRINT("I/O APIC #%d Version %d at 0x%lX.\n",
1411 m
->ApicId
, m
->ApicVersion
, m
->ApicAddress
);
1412 if (IOAPICCount
> MAX_IOAPIC
)
1414 DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n",
1415 MAX_IOAPIC
, IOAPICCount
);
1416 DPRINT1("Recompile with bigger MAX_IOAPIC!.\n");
1419 IOAPICMap
[IOAPICCount
].ApicId
= m
->ApicId
;
1420 IOAPICMap
[IOAPICCount
].ApicVersion
= m
->ApicVersion
;
1421 IOAPICMap
[IOAPICCount
].ApicAddress
= m
->ApicAddress
;
1425 static VOID
HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m
)
1427 DPRINT("Int: type %d, pol %d, trig %d, bus %d,"
1428 " IRQ %02x, APIC ID %x, APIC INT %02x\n",
1429 m
->IrqType
, m
->IrqFlag
& 3,
1430 (m
->IrqFlag
>> 2) & 3, m
->SrcBusId
,
1431 m
->SrcBusIrq
, m
->DstApicId
, m
->DstApicInt
);
1432 if (IRQCount
> MAX_IRQ_SOURCE
)
1434 DPRINT1("Max # of irq sources exceeded!!\n");
1438 IRQMap
[IRQCount
] = *m
;
1442 static VOID
HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m
)
1444 DPRINT("Lint: type %d, pol %d, trig %d, bus %d,"
1445 " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
1446 m
->IrqType
, m
->IrqFlag
& 3,
1447 (m
->IrqFlag
>> 2) & 3, m
->SrcBusId
,
1448 m
->SrcBusIrq
, m
->DstApicId
, m
->DstApicLInt
);
1450 * Well it seems all SMP boards in existence
1451 * use ExtINT/LVT1 == LINT0 and
1452 * NMI/LVT2 == LINT1 - the following check
1453 * will show us if this assumptions is false.
1454 * Until then we do not have to add baggage.
1456 if ((m
->IrqType
== INT_EXTINT
) && (m
->DstApicLInt
!= 0))
1458 DPRINT1("Invalid MP table!\n");
1461 if ((m
->IrqType
== INT_NMI
) && (m
->DstApicLInt
!= 1))
1463 DPRINT1("Invalid MP table!\n");
1469 HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table
)
1472 Table = Pointer to MP configuration table
1478 if (Table
->Signature
!= MPC_SIGNATURE
)
1480 PUCHAR pc
= (PUCHAR
)&Table
->Signature
;
1482 DbgPrint("Bad MP configuration block signature: %c%c%c%c\n",
1483 pc
[0], pc
[1], pc
[2], pc
[3]);
1488 if (MPChecksum((PUCHAR
)Table
, Table
->Length
))
1490 DbgPrint("Bad MP configuration block checksum\n");
1495 if (Table
->Specification
< 0x04)
1497 DbgPrint("Bad MP configuration table version (%d)\n",
1498 Table
->Specification
);
1503 if (Table
->LocalAPICAddress
!= APIC_DEFAULT_BASE
)
1505 DbgPrint("APIC base address is at 0x%X. " \
1506 "I cannot handle non-standard adresses\n", Table
->LocalAPICAddress
);
1510 Entry
= (PUCHAR
)((PVOID
)Table
+ sizeof(MP_CONFIGURATION_TABLE
));
1512 while (Count
< (Table
->Length
- sizeof(MP_CONFIGURATION_TABLE
)))
1514 /* Switch on type */
1517 case MPCTE_PROCESSOR
:
1519 HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR
)Entry
);
1520 Entry
+= sizeof(MP_CONFIGURATION_PROCESSOR
);
1521 Count
+= sizeof(MP_CONFIGURATION_PROCESSOR
);
1526 HaliMPBusInfo((PMP_CONFIGURATION_BUS
)Entry
);
1527 Entry
+= sizeof(MP_CONFIGURATION_BUS
);
1528 Count
+= sizeof(MP_CONFIGURATION_BUS
);
1533 HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC
)Entry
);
1534 Entry
+= sizeof(MP_CONFIGURATION_IOAPIC
);
1535 Count
+= sizeof(MP_CONFIGURATION_IOAPIC
);
1540 HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC
)Entry
);
1541 Entry
+= sizeof(MP_CONFIGURATION_INTSRC
);
1542 Count
+= sizeof(MP_CONFIGURATION_INTSRC
);
1547 HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL
)Entry
);
1548 Entry
+= sizeof(MP_CONFIGURATION_INTLOCAL
);
1549 Count
+= sizeof(MP_CONFIGURATION_INTLOCAL
);
1553 DbgPrint("Unknown entry in MPC table\n");
1559 static VOID
HaliConstructDefaultIOIrqMPTable(ULONG Type
)
1561 MP_CONFIGURATION_INTSRC intsrc
;
1564 intsrc
.Type
= MPCTE_INTSRC
;
1565 intsrc
.IrqFlag
= 0; /* conforming */
1566 intsrc
.SrcBusId
= 0;
1567 intsrc
.DstApicId
= IOAPICMap
[0].ApicId
;
1569 intsrc
.IrqType
= INT_VECTORED
;
1570 for (i
= 0; i
< 16; i
++) {
1573 if (i
== 0 || i
== 13)
1574 continue; /* IRQ0 & IRQ13 not connected */
1578 continue; /* IRQ2 is never connected */
1581 intsrc
.SrcBusIrq
= i
;
1582 intsrc
.DstApicInt
= i
? i
: 2; /* IRQ0 to INTIN2 */
1583 HaliMPIntSrcInfo(&intsrc
);
1586 intsrc
.IrqType
= INT_EXTINT
;
1587 intsrc
.SrcBusIrq
= 0;
1588 intsrc
.DstApicInt
= 0; /* 8259A to INTIN0 */
1589 HaliMPIntSrcInfo(&intsrc
);
1592 static VOID
HaliConstructDefaultISAMPTable(ULONG Type
)
1594 MP_CONFIGURATION_PROCESSOR processor
;
1595 MP_CONFIGURATION_BUS bus
;
1596 MP_CONFIGURATION_IOAPIC ioapic
;
1597 MP_CONFIGURATION_INTLOCAL lintsrc
;
1598 ULONG linttypes
[2] = { INT_EXTINT
, INT_NMI
};
1602 * 2 CPUs, numbered 0 & 1.
1604 processor
.Type
= MPCTE_PROCESSOR
;
1605 /* Either an integrated APIC or a discrete 82489DX. */
1606 processor
.ApicVersion
= Type
> 4 ? 0x10 : 0x01;
1607 processor
.CpuFlags
= CPU_FLAG_ENABLED
| CPU_FLAG_BSP
;
1608 /* FIXME: Get this from the bootstrap processor */
1609 processor
.CpuSignature
= 0;
1610 processor
.FeatureFlags
= 0;
1611 processor
.Reserved
[0] = 0;
1612 processor
.Reserved
[1] = 0;
1613 for (i
= 0; i
< 2; i
++)
1615 processor
.ApicId
= i
;
1616 HaliMPProcessorInfo(&processor
);
1617 processor
.CpuFlags
&= ~CPU_FLAG_BSP
;
1620 bus
.Type
= MPCTE_BUS
;
1625 DPRINT("Unknown standard configuration %d\n", Type
);
1629 memcpy(bus
.BusType
, "ISA ", 6);
1634 memcpy(bus
.BusType
, "EISA ", 6);
1638 memcpy(bus
.BusType
, "MCA ", 6);
1640 HaliMPBusInfo(&bus
);
1643 bus
.Type
= MPCTE_BUS
;
1645 memcpy(bus
.BusType
, "PCI ", 6);
1646 HaliMPBusInfo(&bus
);
1649 ioapic
.Type
= MPCTE_IOAPIC
;
1651 ioapic
.ApicVersion
= Type
> 4 ? 0x10 : 0x01;
1652 ioapic
.ApicFlags
= MP_IOAPIC_USABLE
;
1653 ioapic
.ApicAddress
= IOAPIC_DEFAULT_BASE
;
1654 HaliMPIOApicInfo(&ioapic
);
1657 * We set up most of the low 16 IO-APIC pins according to MPS rules.
1659 HaliConstructDefaultIOIrqMPTable(Type
);
1661 lintsrc
.Type
= MPCTE_LINTSRC
;
1662 lintsrc
.IrqType
= 0;
1663 lintsrc
.IrqFlag
= 0; /* conforming */
1664 lintsrc
.SrcBusId
= 0;
1665 lintsrc
.SrcBusIrq
= 0;
1666 lintsrc
.DstApicId
= MP_APIC_ALL
;
1667 for (i
= 0; i
< 2; i
++)
1669 lintsrc
.IrqType
= linttypes
[i
];
1670 lintsrc
.DstApicLInt
= i
;
1671 HaliMPIntLocalInfo(&lintsrc
);
1677 HaliScanForMPConfigTable(ULONG Base
,
1681 Base = Base address of region
1682 Size = Length of region to check
1684 TRUE if a valid MP configuration table was found
1687 PULONG bp
= (PULONG
)Base
;
1688 MP_FLOATING_POINTER
* mpf
;
1692 if (*bp
== MPF_SIGNATURE
)
1694 DbgPrint("Found MPF signature at %x, checksum %x\n", bp
,
1695 MPChecksum((PUCHAR
)bp
, 16));
1696 if (MPChecksum((PUCHAR
)bp
, 16) == 0)
1698 mpf
= (MP_FLOATING_POINTER
*)bp
;
1700 DbgPrint("Intel MultiProcessor Specification v1.%d compliant system.\n",
1701 mpf
->Specification
);
1703 if (mpf
->Feature2
& FEATURE2_IMCRP
) {
1705 DPRINT("Running in IMCR and PIC compatibility mode.\n");
1708 DPRINT("Running in Virtual Wire compatibility mode.\n");
1711 switch (mpf
->Feature1
)
1714 /* Non standard configuration */
1720 DPRINT("EISA with no IRQ8 chaining\n");
1729 DPRINT("ISA and PCI\n");
1732 DPRINT("EISA and PCI\n");
1735 DPRINT("MCA and PCI\n");
1738 DbgPrint("Unknown standard configuration %d\n", mpf
->Feature1
);
1746 if ((mpf
->Feature1
== 0) && (mpf
->Address
)) {
1747 HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE
)mpf
->Address
);
1749 HaliConstructDefaultISAMPTable(mpf
->Feature1
);
1765 static BOOLEAN MPSInitialized
= FALSE
;
1768 /* Only initialize MP system once. Once called the first time,
1769 each subsequent call is part of the initialization sequence
1770 for an application processor. */
1772 DPRINT("HalpInitMPS()\n");
1780 MPSInitialized
= TRUE
;
1783 Scan the system memory for an MP configuration table
1784 1) Scan the first KB of system base memory
1785 2) Scan the last KB of system base memory
1786 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh
1787 4) Scan the Extended BIOS Data Area
1790 if (!HaliScanForMPConfigTable(0x0, 0x400))
1792 if (!HaliScanForMPConfigTable(0x9FC00, 0x400))
1794 if (!HaliScanForMPConfigTable(0xF0000, 0x10000))
1796 EBDA
= *((PUSHORT
)0x040E);
1798 if (!HaliScanForMPConfigTable((ULONG
)EBDA
, 0x1000))
1800 DbgPrint("No multiprocessor compliant system found.\n");
1807 /* Setup IRQ to vector translation map */
1808 memset(&IRQVectorMap
, 0, sizeof(IRQVectorMap
));
1810 /* Setup interrupt handlers */
1811 SetInterruptGate(LOCAL_TIMER_VECTOR
, (ULONG
)MpsTimerInterrupt
);
1812 SetInterruptGate(ERROR_VECTOR
, (ULONG
)MpsErrorInterrupt
);
1813 SetInterruptGate(SPURIOUS_VECTOR
, (ULONG
)MpsSpuriousInterrupt
);
1814 SetInterruptGate(IPI_VECTOR
, (ULONG
)MpsIpiInterrupt
);
1819 HaliReconfigurePciInterrupts(VOID
)
1823 for (i
= 0; i
< IRQCount
; i
++)
1825 if (BUSMap
[IRQMap
[i
].SrcBusId
] == MP_BUS_PCI
)
1827 DPRINT("%02x: IrqType %02x, IrqFlag %02x, SrcBusId %02x, SrcBusIrq %02x, DstApicId %02x, DstApicInt %02x\n",
1828 i
, IRQMap
[i
].IrqType
, IRQMap
[i
].IrqFlag
, IRQMap
[i
].SrcBusId
,
1829 IRQMap
[i
].SrcBusIrq
, IRQMap
[i
].DstApicId
, IRQMap
[i
].DstApicInt
);
1831 if(1 != HalSetBusDataByOffset(PCIConfiguration
, IRQMap
[i
].SrcBusId
, (IRQMap
[i
].SrcBusIrq
>> 2) & 0x1f, &IRQMap
[i
].DstApicInt
, 0x3c /*PCI_INTERRUPT_LINE*/, 1))