1 /* $Id: processor_mp.c,v 1.1 2004/12/03 20:10:44 gvg Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: hal/halx86/mp/processor_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 *****************************************************************/
17 #include <ddk/ntddk.h>
23 #include <internal/ntoskrnl.h>
24 #include <internal/i386/segment.h>
25 #include <internal/ke.h>
26 #include <internal/ps.h>
29 #include <internal/debug.h>
32 Address of area to be used for communication between Application
33 Processors (APs) and the BootStrap Processor (BSP)
35 #define COMMON_AREA 0x2000
39 typedef struct __attribute__((packed
)) _COMMON_AREA_INFO
41 ULONG Stack
; /* Location of AP stack */
42 ULONG Debug
[16]; /* For debugging */
43 } COMMON_AREA_INFO
, *PCOMMON_AREA_INFO
;
45 CPU_INFO CPUMap
[MAX_CPU
]; /* Map of all CPUs in the system */
46 ULONG CPUCount
; /* Total number of CPUs */
47 ULONG OnlineCPUs
; /* Bitmask of online CPUs */
49 UCHAR BUSMap
[MAX_BUS
]; /* Map of all buses in the system */
50 UCHAR PCIBUSMap
[MAX_BUS
]; /* Map of all PCI buses in the system */
52 IOAPIC_INFO IOAPICMap
[MAX_IOAPIC
]; /* Map of all I/O APICs in the system */
53 ULONG IOAPICCount
; /* Number of I/O APICs in the system */
55 MP_CONFIGURATION_INTSRC IRQMap
[MAX_IRQ_SOURCE
]; /* Map of all IRQs */
56 ULONG IRQVectorMap
[MAX_IRQ_SOURCE
]; /* IRQ to vector map */
57 ULONG IrqPinMap
[MAX_IRQ_SOURCE
]; /* IRQ to Pin map */
58 ULONG IrqApicMap
[MAX_IRQ_SOURCE
];
59 ULONG IRQCount
; /* Number of IRQs */
61 ULONG APICMode
; /* APIC mode at startup */
62 ULONG BootCPU
; /* Bootstrap processor */
63 PULONG BIOSBase
; /* Virtual address of BIOS data segment */
64 PULONG CommonBase
; /* Virtual address of common area */
66 extern CHAR
*APstart
, *APend
;
67 extern VOID (*APflush
)(VOID
);
69 extern VOID
MpsTimerInterrupt(VOID
);
70 extern VOID
MpsErrorInterrupt(VOID
);
71 extern VOID
MpsSpuriousInterrupt(VOID
);
72 extern VOID
MpsIpiInterrupt(VOID
);
74 #define CMOS_READ(address) ({ \
75 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
76 READ_PORT_UCHAR((PUCHAR)0x71)); \
79 #define CMOS_WRITE(address, value) ({ \
80 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
81 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
85 /* FUNCTIONS *****************************************************************/
87 /* Functions for handling 8259A PICs */
89 VOID
Disable8259AIrq(ULONG irq
)
95 tmp
= READ_PORT_UCHAR((PUCHAR
)0xA1);
96 tmp
|= (1 << (irq
- 8));
97 WRITE_PORT_UCHAR((PUCHAR
)0xA1, tmp
);
101 tmp
= READ_PORT_UCHAR((PUCHAR
)0x21);
103 WRITE_PORT_UCHAR((PUCHAR
)0x21, tmp
);
108 VOID
Enable8259AIrq(ULONG irq
)
114 tmp
= READ_PORT_UCHAR((PUCHAR
)0xA1);
115 tmp
&= ~(1 << (irq
- 8));
116 WRITE_PORT_UCHAR((PUCHAR
)0xA1, tmp
);
120 tmp
= READ_PORT_UCHAR((PUCHAR
)0x21);
122 WRITE_PORT_UCHAR((PUCHAR
)0x21, tmp
);
127 /* Functions for handling I/O APICs */
129 volatile ULONG
IOAPICRead(ULONG Apic
, ULONG Offset
)
133 Base
= (PULONG
)IOAPICMap
[Apic
].ApicAddress
;
135 return *((PULONG
)((ULONG
)Base
+ IOAPIC_IOWIN
));
138 VOID
IOAPICWrite(ULONG Apic
, ULONG Offset
, ULONG Value
)
142 Base
= (PULONG
)IOAPICMap
[Apic
].ApicAddress
;
144 *((PULONG
)((ULONG
)Base
+ IOAPIC_IOWIN
)) = Value
;
148 VOID
IOAPICClearPin(ULONG Apic
, ULONG Pin
)
150 IOAPIC_ROUTE_ENTRY Entry
;
152 DPRINT("IOAPICClearPin(Apic %d, Pin %d\n", Apic
, Pin
);
154 * Disable it in the IO-APIC irq-routing table
156 memset(&Entry
, 0, sizeof(Entry
));
159 IOAPICWrite(Apic
, IOAPIC_REDTBL
+ 2 * Pin
, *(((PULONG
)&Entry
) + 0));
160 IOAPICWrite(Apic
, IOAPIC_REDTBL
+ 1 + 2 * Pin
, *(((PULONG
)&Entry
) + 1));
163 static VOID
IOAPICClear(ULONG Apic
)
167 for (Pin
= 0; Pin
< /*IOAPICMap[Apic].EntryCount*/24; Pin
++)
169 IOAPICClearPin(Apic
, Pin
);
173 static VOID
IOAPICClearAll(VOID
)
177 for (Apic
= 0; Apic
< IOAPICCount
; Apic
++)
183 /* This is performance critical and should probably be done in assembler */
184 VOID
IOAPICMaskIrq(ULONG Irq
)
186 IOAPIC_ROUTE_ENTRY Entry
;
187 ULONG Apic
= IrqApicMap
[Irq
];
190 *((PULONG
)&Entry
) = IOAPICRead(Apic
, IOAPIC_REDTBL
+2*Irq
);
192 IOAPICWrite(Apic
, IOAPIC_REDTBL
+2*Irq
, *((PULONG
)&Entry
));
196 /* This is performance critical and should probably be done in assembler */
197 VOID
IOAPICUnmaskIrq(ULONG Irq
)
199 IOAPIC_ROUTE_ENTRY Entry
;
200 ULONG Apic
= IrqApicMap
[Irq
];
202 *((PULONG
)&Entry
) = IOAPICRead(Apic
, IOAPIC_REDTBL
+2*IrqPinMap
[Irq
]);
204 IOAPICWrite(Apic
, IOAPIC_REDTBL
+2*IrqPinMap
[Irq
], *((PULONG
)&Entry
));
214 * Set the IOAPIC ID to the value stored in the MPC table.
216 for (apic
= 0; apic
< IOAPICCount
; apic
++)
219 /* Read the register 0 value */
220 tmp
= IOAPICRead(apic
, IOAPIC_ID
);
222 old_id
= IOAPICMap
[apic
].ApicId
;
224 if (IOAPICMap
[apic
].ApicId
>= 0xf)
226 DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
227 apic
, IOAPICMap
[apic
].ApicId
);
228 DPRINT1("... fixing up to %d. (tell your hw vendor)\n",
230 IOAPICMap
[apic
].ApicId
= GET_IOAPIC_ID(tmp
);
234 * We need to adjust the IRQ routing table
237 if (old_id
!= IOAPICMap
[apic
].ApicId
)
239 for (i
= 0; i
< IRQCount
; i
++)
241 if (IRQMap
[i
].DstApicId
== old_id
)
243 IRQMap
[i
].DstApicId
= IOAPICMap
[apic
].ApicId
;
249 * Read the right value from the MPC table and
250 * write it into the ID register.
252 DPRINT("Changing IO-APIC physical APIC ID to %d\n",
253 IOAPICMap
[apic
].ApicId
);
255 tmp
&= ~IOAPIC_ID_MASK
;
256 tmp
|= SET_IOAPIC_ID(IOAPICMap
[apic
].ApicId
);
258 IOAPICWrite(apic
, IOAPIC_ID
, tmp
);
263 tmp
= IOAPICRead(apic
, 0);
264 if (GET_IOAPIC_ID(tmp
) != IOAPICMap
[apic
].ApicId
)
266 DPRINT1("Could not set I/O APIC ID!\n");
274 * EISA Edge/Level control register, ELCR
276 static ULONG
EISA_ELCR(ULONG irq
)
280 PUCHAR port
= (PUCHAR
)(0x4d0 + (irq
>> 3));
281 return (READ_PORT_UCHAR(port
) >> (irq
& 7)) & 1;
283 DPRINT("Broken MPtable reports ISA irq %d\n", irq
);
287 /* EISA interrupts are always polarity zero and can be edge or level
288 * trigger depending on the ELCR value. If an interrupt is listed as
289 * EISA conforming in the MP table, that means its trigger type must
290 * be read in from the ELCR */
292 #define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq))
293 #define default_EISA_polarity(idx) (0)
295 /* ISA interrupts are always polarity zero edge triggered,
296 * when listed as conforming in the MP table. */
298 #define default_ISA_trigger(idx) (0)
299 #define default_ISA_polarity(idx) (0)
301 /* PCI interrupts are always polarity one level triggered,
302 * when listed as conforming in the MP table. */
304 #define default_PCI_trigger(idx) (1)
305 #define default_PCI_polarity(idx) (1)
307 /* MCA interrupts are always polarity zero level triggered,
308 * when listed as conforming in the MP table. */
310 #define default_MCA_trigger(idx) (1)
311 #define default_MCA_polarity(idx) (0)
313 static ULONG
IRQPolarity(ULONG idx
)
315 ULONG bus
= IRQMap
[idx
].SrcBusId
;
319 * Determine IRQ line polarity (high active or low active):
321 switch (IRQMap
[idx
].IrqFlag
& 3)
323 case 0: /* conforms, ie. bus-type dependent polarity */
327 case MP_BUS_ISA
: /* ISA pin */
329 polarity
= default_ISA_polarity(idx
);
332 case MP_BUS_EISA
: /* EISA pin */
334 polarity
= default_EISA_polarity(idx
);
337 case MP_BUS_PCI
: /* PCI pin */
339 polarity
= default_PCI_polarity(idx
);
342 case MP_BUS_MCA
: /* MCA pin */
344 polarity
= default_MCA_polarity(idx
);
349 DPRINT("Broken BIOS!!\n");
356 case 1: /* high active */
361 case 2: /* reserved */
363 DPRINT("Broken BIOS!!\n");
367 case 3: /* low active */
372 default: /* invalid */
374 DPRINT("Broken BIOS!!\n");
382 static ULONG
IRQTrigger(ULONG idx
)
384 ULONG bus
= IRQMap
[idx
].SrcBusId
;
388 * Determine IRQ trigger mode (edge or level sensitive):
390 switch ((IRQMap
[idx
].IrqFlag
>> 2) & 3)
392 case 0: /* conforms, ie. bus-type dependent */
396 case MP_BUS_ISA
: /* ISA pin */
398 trigger
= default_ISA_trigger(idx
);
401 case MP_BUS_EISA
: /* EISA pin */
403 trigger
= default_EISA_trigger(idx
);
406 case MP_BUS_PCI
: /* PCI pin */
408 trigger
= default_PCI_trigger(idx
);
411 case MP_BUS_MCA
: /* MCA pin */
413 trigger
= default_MCA_trigger(idx
);
418 DPRINT("Broken BIOS!!\n");
430 case 2: /* reserved */
432 DPRINT("Broken BIOS!!\n");
441 default: /* invalid */
443 DPRINT("Broken BIOS!!\n");
452 static ULONG
Pin2Irq(ULONG idx
,
457 ULONG bus
= IRQMap
[idx
].SrcBusId
;
460 * Debugging check, we are in big trouble if this message pops up!
462 if (IRQMap
[idx
].DstApicInt
!= pin
) {
463 DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n");
468 case MP_BUS_ISA
: /* ISA pin */
472 irq
= IRQMap
[idx
].SrcBusIrq
;
475 case MP_BUS_PCI
: /* PCI pin */
478 * PCI IRQs are mapped in order
482 irq
+= IOAPICMap
[i
++].EntryCount
;
488 DPRINT("Unknown bus type %d.\n",bus
);
499 * Rough estimation of how many shared IRQs there are, can
500 * be changed anytime.
502 #define MAX_PLUS_SHARED_IRQS PIC_IRQS
503 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + PIC_IRQS)
506 * This is performance-critical, we want to do it O(1)
508 * the indexing order of this array favors 1:1 mappings
509 * between pins and IRQs.
512 static struct irq_pin_list
{
513 ULONG apic
, pin
, next
;
514 } irq_2_pin
[PIN_MAP_SIZE
];
517 * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
518 * shared ISA-space IRQs, so we have to support them. We are super
519 * fast in the common case, and fast for shared ISA-space IRQs.
521 static VOID
AddPinToIrq(ULONG irq
,
525 static ULONG first_free_entry
= PIC_IRQS
;
526 struct irq_pin_list
*entry
= irq_2_pin
+ irq
;
530 entry
= irq_2_pin
+ entry
->next
;
533 if (entry
->pin
!= -1)
535 entry
->next
= first_free_entry
;
536 entry
= irq_2_pin
+ entry
->next
;
537 if (++first_free_entry
>= PIN_MAP_SIZE
)
549 * Find the IRQ entry number of a certain pin.
551 static ULONG
IOAPICGetIrqEntry(ULONG apic
,
557 for (i
= 0; i
< IRQCount
; i
++)
559 if (IRQMap
[i
].IrqType
== type
&&
560 (IRQMap
[i
].DstApicId
== IOAPICMap
[apic
].ApicId
|| IRQMap
[i
].DstApicId
== MP_APIC_ALL
) &&
561 IRQMap
[i
].DstApicInt
== pin
)
570 static ULONG
AssignIrqVector(ULONG irq
)
573 static ULONG current_vector
= FIRST_DEVICE_VECTOR
, vector_offset
= 0;
576 /* There may already have been assigned a vector for this IRQ */
577 vector
= IRQVectorMap
[irq
];
583 if (current_vector
> FIRST_SYSTEM_VECTOR
) {
585 current_vector
= FIRST_DEVICE_VECTOR
+ vector_offset
;
586 } else if (current_vector
== FIRST_SYSTEM_VECTOR
) {
587 DPRINT1("Ran out of interrupt sources!");
591 vector
= current_vector
;
592 IRQVectorMap
[irq
] = vector
;
596 vector
= IRQ2VECTOR(irq
);
597 IRQVectorMap
[irq
] = vector
;
603 VOID
IOAPICSetupIrqs(VOID
)
605 IOAPIC_ROUTE_ENTRY entry
;
606 ULONG apic
, pin
, idx
, irq
, first_notcon
= 1, vector
;
608 DPRINT("Init IO_APIC IRQs\n");
610 for (apic
= 0; apic
< IOAPICCount
; apic
++)
612 for (pin
= 0; pin
< IOAPICMap
[apic
].EntryCount
; pin
++)
615 * add it to the IO-APIC irq-routing table
617 memset(&entry
,0,sizeof(entry
));
619 entry
.delivery_mode
= APIC_DM_LOWEST
;
620 entry
.dest_mode
= 1; /* logical delivery */
621 entry
.mask
= 1; /* disable IRQ */
625 * Some drivers are not able to deal with more than one cpu.
627 entry
.dest
.logical
.logical_dest
= OnlineCPUs
;
629 entry
.dest
.logical
.logical_dest
= 1 << 0;
631 idx
= IOAPICGetIrqEntry(apic
,pin
,INT_VECTORED
);
636 DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap
[apic
].ApicId
, pin
);
641 DPRINT(", %d-%d\n", IOAPICMap
[apic
].ApicId
, pin
);
646 entry
.trigger
= IRQTrigger(idx
);
647 entry
.polarity
= IRQPolarity(idx
);
652 entry
.mask
= 1; // disable
654 entry
.dest
.logical
.logical_dest
= OnlineCPUs
;
656 entry
.dest
.logical
.logical_dest
= 1 << 0;
660 irq
= Pin2Irq(idx
, apic
, pin
);
661 AddPinToIrq(irq
, apic
, pin
);
663 vector
= AssignIrqVector(irq
);
664 entry
.vector
= vector
;
666 DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector
, irq
);
674 if ((apic
== 0) && (irq
< 16))
676 Disable8259AIrq(irq
);
678 IOAPICWrite(apic
, IOAPIC_REDTBL
+2*pin
+1, *(((PULONG
)&entry
)+1));
679 IOAPICWrite(apic
, IOAPIC_REDTBL
+2*pin
, *(((PULONG
)&entry
)+0));
681 IrqPinMap
[irq
] = pin
;
682 IrqApicMap
[irq
] = apic
;
684 DPRINT("Vector %x, Pin %x, Irq %x\n", vector
, pin
, irq
);
690 static VOID
IOAPICEnable(VOID
)
694 for (i
= 0; i
< PIN_MAP_SIZE
; i
++)
696 irq_2_pin
[i
].pin
= -1;
697 irq_2_pin
[i
].next
= 0;
701 * The number of IO-APIC IRQ registers (== #pins):
703 for (i
= 0; i
< IOAPICCount
; i
++)
705 tmp
= IOAPICRead(i
, IOAPIC_VER
);
706 IOAPICMap
[i
].EntryCount
= GET_IOAPIC_MRE(tmp
) + 1;
710 * Do not trust the IO-APIC being empty at bootup
716 static VOID
IOAPICDisable(VOID
)
719 * Clear the IO-APIC before rebooting
727 static VOID
IOAPICSetup(VOID
)
736 VOID
IOAPICDump(VOID
)
739 ULONG reg0
, reg1
, reg2
=0;
741 DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount
);
742 for (i
= 0; i
< IOAPICCount
; i
++)
744 DbgPrint("Number of IO-APIC #%d registers: %d.\n",
746 IOAPICMap
[i
].EntryCount
);
750 * We are a bit conservative about what we expect. We have to
751 * know about every hardware change ASAP.
753 DbgPrint("Testing the IO APIC.......................\n");
755 for (apic
= 0; apic
< IOAPICCount
; apic
++)
757 reg0
= IOAPICRead(apic
, IOAPIC_ID
);
758 reg1
= IOAPICRead(apic
, IOAPIC_VER
);
759 if (GET_IOAPIC_VERSION(reg1
) >= 0x10)
761 reg2
= IOAPICRead(apic
, IOAPIC_ARB
);
765 DbgPrint("IO APIC #%d......\n", IOAPICMap
[apic
].ApicId
);
766 DbgPrint(".... register #00: %08X\n", reg0
);
767 DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0
));
768 if (reg0
& 0xF0FFFFFF)
770 DbgPrint(" WARNING: Unexpected IO-APIC\n");
773 DbgPrint(".... register #01: %08X\n", reg1
);
774 i
= GET_IOAPIC_MRE(reg1
);
776 DbgPrint("....... : max redirection entries: %04X\n", i
);
777 if ((i
!= 0x0f) && /* older (Neptune) boards */
778 (i
!= 0x17) && /* typical ISA+PCI boards */
779 (i
!= 0x1b) && /* Compaq Proliant boards */
780 (i
!= 0x1f) && /* dual Xeon boards */
781 (i
!= 0x22) && /* bigger Xeon boards */
785 DbgPrint(" WARNING: Unexpected IO-APIC\n");
788 i
= GET_IOAPIC_VERSION(reg1
);
789 DbgPrint("....... : IO APIC version: %04X\n", i
);
790 if ((i
!= 0x01) && /* 82489DX IO-APICs */
791 (i
!= 0x10) && /* oldest IO-APICs */
792 (i
!= 0x11) && /* Pentium/Pro IO-APICs */
793 (i
!= 0x13)) /* Xeon IO-APICs */
795 DbgPrint(" WARNING: Unexpected IO-APIC\n");
798 if (reg1
& 0xFF00FF00)
800 DbgPrint(" WARNING: Unexpected IO-APIC\n");
803 if (GET_IOAPIC_VERSION(reg1
) >= 0x10)
805 DbgPrint(".... register #02: %08X\n", reg2
);
806 DbgPrint("....... : arbitration: %02X\n",
807 GET_IOAPIC_ARB(reg2
));
808 if (reg2
& 0xF0FFFFFF)
810 DbgPrint(" WARNING: Unexpected IO-APIC\n");
814 DbgPrint(".... IRQ redirection table:\n");
815 DbgPrint(" NR Log Phy Mask Trig IRR Pol"
816 " Stat Dest Deli Vect: \n");
818 for (i
= 0; i
<= GET_IOAPIC_MRE(reg1
); i
++)
820 IOAPIC_ROUTE_ENTRY entry
;
822 *(((PULONG
)&entry
)+0) = IOAPICRead(apic
, 0x10+i
*2);
823 *(((PULONG
)&entry
)+1) = IOAPICRead(apic
, 0x11+i
*2);
825 DbgPrint(" %02x %03X %02X ",
827 entry
.dest
.logical
.logical_dest
,
828 entry
.dest
.physical
.physical_dest
);
830 DbgPrint("%C %C %1d %C %C %C %03X %02X\n",
831 (entry
.mask
== 0) ? 'U' : 'M', // Unmasked/masked
832 (entry
.trigger
== 0) ? 'E' : 'L', // Edge/level sensitive
834 (entry
.polarity
== 0) ? 'H' : 'L', // Active high/active low
835 (entry
.delivery_status
== 0) ? 'I' : 'S', // Idle / send pending
836 (entry
.dest_mode
== 0) ? 'P' : 'L', // Physical logical
841 DbgPrint("IRQ to pin mappings:\n");
842 for (i
= 0; i
< PIC_IRQS
; i
++)
844 struct irq_pin_list
*entry
= irq_2_pin
+ i
;
849 DbgPrint("IRQ%d ", i
);
852 DbgPrint("-> %d", entry
->pin
);
857 entry
= irq_2_pin
+ entry
->next
;
869 DbgPrint(".................................... done.\n");
874 /* Functions for handling local APICs */
876 ULONG
Read8254Timer(VOID
)
880 WRITE_PORT_UCHAR((PUCHAR
)0x43, 0x00);
881 Count
= READ_PORT_UCHAR((PUCHAR
)0x40);
882 Count
|= READ_PORT_UCHAR((PUCHAR
)0x40) << 8;
887 VOID
WaitFor8254Wraparound(VOID
)
889 ULONG CurCount
, PrevCount
= ~0;
892 CurCount
= Read8254Timer();
895 PrevCount
= CurCount
;
896 CurCount
= Read8254Timer();
897 Delta
= CurCount
- PrevCount
;
900 * This limit for delta seems arbitrary, but it isn't, it's
901 * slightly above the level of error a buggy Mercury/Neptune
902 * chipset timer can cause.
910 #define APIC_DIVISOR (16)
912 VOID
APICSetupLVTT(ULONG ClockTicks
)
916 tmp
= GET_APIC_VERSION(APICRead(APIC_VER
));
917 if (!APIC_INTEGRATED(tmp
))
919 tmp
= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV
) | APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
924 tmp
= APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
926 APICWrite(APIC_LVTT
, tmp
);
928 tmp
= APICRead(APIC_TDCR
);
929 tmp
&= ~(APIC_TDCR_1
| APIC_TIMER_BASE_DIV
);
931 APICWrite(APIC_TDCR
, tmp
);
932 APICWrite(APIC_ICRT
, ClockTicks
/ APIC_DIVISOR
);
936 VOID
APICCalibrateTimer(ULONG CPU
)
938 ULARGE_INTEGER t1
, t2
;
941 DPRINT("Calibrating APIC timer for CPU %d\n", CPU
);
943 APICSetupLVTT(1000000000);
946 * The timer chip counts down to zero. Let's wait
947 * for a wraparound to start exact measurement:
948 * (the current tick might have been already half done)
950 WaitFor8254Wraparound();
953 * We wrapped around just now. Let's start
955 ReadPentiumClock(&t1
);
956 tt1
= APICRead(APIC_CCRT
);
958 WaitFor8254Wraparound();
961 tt2
= APICRead(APIC_CCRT
);
962 ReadPentiumClock(&t2
);
964 CPUMap
[CPU
].BusSpeed
= (HZ
* (long)(tt1
- tt2
) * APIC_DIVISOR
);
965 CPUMap
[CPU
].CoreSpeed
= (HZ
* (t2
.QuadPart
- t1
.QuadPart
));
967 /* Setup timer for normal operation */
968 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
969 APICSetupLVTT((CPUMap
[CPU
].BusSpeed
/ 1000000) * 10000); // 10ms
970 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
972 DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
973 CPUMap
[CPU
].CoreSpeed
/1000000,
974 CPUMap
[CPU
].CoreSpeed
%1000000);
976 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
977 CPUMap
[CPU
].BusSpeed
/1000000,
978 CPUMap
[CPU
].BusSpeed
%1000000);
982 SetInterruptGate(ULONG index
, ULONG address
)
986 idt
= (IDT_DESCRIPTOR
*)((ULONG
)KeGetCurrentKPCR()->IDT
+ index
* sizeof(IDT_DESCRIPTOR
));
987 idt
->a
= (((ULONG
)address
)&0xffff) + (KERNEL_CS
<< 16);
988 idt
->b
= 0x8e00 + (((ULONG
)address
)&0xffff0000);
992 HalInitializeProcessor(ULONG ProcessorNumber
,
993 PVOID
/*PLOADER_PARAMETER_BLOCK*/ LoaderBlock
)
997 DPRINT("HalInitializeProcessor(%x %x)\n", ProcessorNumber
, LoaderBlock
);
1000 if (OnlineCPUs
& (1 << CPU
))
1005 if (ProcessorNumber
== 0)
1013 DPRINT("CPU %d says it is now booted.\n", CPU
);
1015 APICCalibrateTimer(CPU
);
1018 /* This processor is now booted */
1019 CPUMap
[CPU
].Flags
|= CPU_ENABLED
;
1020 OnlineCPUs
|= (1 << CPU
);
1022 /* Setup busy waiting */
1023 HalpCalibrateStallExecution();
1027 HalAllProcessorsStarted (VOID
)
1031 DPRINT("HalAllProcessorsStarted()\n");
1032 for (i
= 0; i
< 32; i
++)
1034 if (OnlineCPUs
& (1 << i
))
1039 if (CPUs
> CPUCount
)
1043 else if (CPUs
== CPUCount
)
1052 HalStartNextProcessor(ULONG Unknown1
,
1053 ULONG ProcessorStack
)
1055 PCOMMON_AREA_INFO Common
;
1057 ULONG DeliveryStatus
= 0;
1058 ULONG AcceptStatus
= 0;
1062 DPRINT("HalStartNextProcessor(%x %x)\n", Unknown1
, ProcessorStack
);
1064 for (CPU
= 0; CPU
< CPUCount
; CPU
++)
1066 if (!(OnlineCPUs
& (1<<CPU
)))
1072 if (CPU
>= CPUCount
)
1077 DPRINT1("Attempting to boot CPU %d\n", CPU
);
1081 APICSendIPI(CPU
, APIC_DM_INIT
|APIC_ICR0_LEVEL_ASSERT
);
1083 KeStallExecutionProcessor(200);
1087 APICSendIPI(CPU
, APIC_DM_INIT
|APIC_ICR0_LEVEL_DEASSERT
);
1089 if (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
1091 /* Clear APIC errors */
1092 APICWrite(APIC_ESR
, 0);
1093 tmp
= (APICRead(APIC_ESR
) & APIC_ESR_MASK
);
1096 Common
= (PCOMMON_AREA_INFO
)CommonBase
;
1098 /* Write the location of the AP stack */
1099 Common
->Stack
= (ULONG
)ProcessorStack
;
1101 DPRINT("CPU %d got stack at 0x%X\n", CPU
, Common
->Stack
);
1103 for (j
= 0; j
< 16; j
++)
1105 Common
->Debug
[j
] = 0;
1109 maxlvt
= APICGetMaxLVT();
1111 /* Is this a local APIC or an 82489DX? */
1112 StartupCount
= (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
)) ? 2 : 0;
1114 for (i
= 1; i
<= StartupCount
; i
++)
1116 /* It's a local APIC, so send STARTUP IPI */
1117 DPRINT("Sending startup signal %d\n", i
);
1119 APICWrite(APIC_ESR
, 0);
1122 APICSendIPI(CPU
, APIC_DM_STARTUP
| ((COMMON_AREA
+ PAGE_SIZE
) >> 12)|APIC_ICR0_LEVEL_DEASSERT
);
1124 /* Wait up to 10ms for IPI to be delivered */
1128 KeStallExecutionProcessor(10);
1130 /* Check Delivery Status */
1131 DeliveryStatus
= APICRead(APIC_ICR0
) & APIC_ICR0_DS
;
1134 } while ((DeliveryStatus
) && (j
< 1000));
1136 KeStallExecutionProcessor(200);
1139 * Due to the Pentium erratum 3AP.
1143 APICRead(APIC_SIVR
);
1144 APICWrite(APIC_ESR
, 0);
1147 AcceptStatus
= APICRead(APIC_ESR
) & APIC_ESR_MASK
;
1149 if (DeliveryStatus
|| AcceptStatus
)
1157 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", CPU
);
1162 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", CPU
);
1165 if (!(DeliveryStatus
|| AcceptStatus
))
1168 /* Wait no more than 5 seconds for processor to boot */
1169 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", CPU
);
1171 /* Wait no more than 5 seconds */
1172 for (j
= 0; j
< 50000; j
++)
1174 if (CPUMap
[CPU
].Flags
& CPU_ENABLED
)
1178 KeStallExecutionProcessor(100);
1182 if (CPUMap
[CPU
].Flags
& CPU_ENABLED
)
1184 DbgPrint("CPU %d is now running\n", CPU
);
1188 DbgPrint("Initialization of CPU %d failed\n", CPU
);
1192 DPRINT("Debug bytes are:\n");
1194 for (j
= 0; j
< 4; j
++)
1196 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1197 Common
->Debug
[j
*4+0],
1198 Common
->Debug
[j
*4+1],
1199 Common
->Debug
[j
*4+2],
1200 Common
->Debug
[j
*4+3]);
1208 ULONG
MPChecksum(PUCHAR Base
,
1211 * Checksum an MP configuration block
1223 PCHAR
HaliMPFamily(ULONG Family
,
1226 static CHAR str
[32];
1227 static PCHAR CPUs
[] =
1229 "80486DX", "80486DX",
1230 "80486SX", "80486DX/2 or 80487",
1231 "80486SL", "Intel5X2(tm)",
1232 "Unknown", "Unknown",
1236 return ("Pentium(tm) Pro");
1238 return ("Pentium(tm)");
1239 if (Family
== 0x0F && Model
== 0x0F)
1240 return("Special controller");
1241 if (Family
== 0x0F && Model
== 0x00)
1242 return("Pentium 4(tm)");
1243 if (Family
== 0x04 && Model
< 9)
1245 sprintf(str
, "Unknown CPU with family ID %ld and model ID %ld", Family
, Model
);
1249 static VOID
HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m
)
1253 if (!(m
->CpuFlags
& CPU_FLAG_ENABLED
))
1256 DPRINT("Processor #%d %s APIC version %d\n",
1258 HaliMPFamily((m
->FeatureFlags
& CPU_FAMILY_MASK
) >> 8,
1259 (m
->FeatureFlags
& CPU_MODEL_MASK
) >> 4),
1262 if (m
->FeatureFlags
& (1 << 0))
1263 DPRINT(" Floating point unit present.\n");
1264 if (m
->FeatureFlags
& (1 << 7))
1265 DPRINT(" Machine Exception supported.\n");
1266 if (m
->FeatureFlags
& (1 << 8))
1267 DPRINT(" 64 bit compare & exchange supported.\n");
1268 if (m
->FeatureFlags
& (1 << 9))
1269 DPRINT(" Internal APIC present.\n");
1270 if (m
->FeatureFlags
& (1 << 11))
1271 DPRINT(" SEP present.\n");
1272 if (m
->FeatureFlags
& (1 << 12))
1273 DPRINT(" MTRR present.\n");
1274 if (m
->FeatureFlags
& (1 << 13))
1275 DPRINT(" PGE present.\n");
1276 if (m
->FeatureFlags
& (1 << 14))
1277 DPRINT(" MCA present.\n");
1278 if (m
->FeatureFlags
& (1 << 15))
1279 DPRINT(" CMOV present.\n");
1280 if (m
->FeatureFlags
& (1 << 16))
1281 DPRINT(" PAT present.\n");
1282 if (m
->FeatureFlags
& (1 << 17))
1283 DPRINT(" PSE present.\n");
1284 if (m
->FeatureFlags
& (1 << 18))
1285 DPRINT(" PSN present.\n");
1286 if (m
->FeatureFlags
& (1 << 19))
1287 DPRINT(" Cache Line Flush Instruction present.\n");
1289 if (m
->FeatureFlags
& (1 << 21))
1290 DPRINT(" Debug Trace and EMON Store present.\n");
1291 if (m
->FeatureFlags
& (1 << 22))
1292 DPRINT(" ACPI Thermal Throttle Registers present.\n");
1293 if (m
->FeatureFlags
& (1 << 23))
1294 DPRINT(" MMX present.\n");
1295 if (m
->FeatureFlags
& (1 << 24))
1296 DPRINT(" FXSR present.\n");
1297 if (m
->FeatureFlags
& (1 << 25))
1298 DPRINT(" XMM present.\n");
1299 if (m
->FeatureFlags
& (1 << 26))
1300 DPRINT(" Willamette New Instructions present.\n");
1301 if (m
->FeatureFlags
& (1 << 27))
1302 DPRINT(" Self Snoop present.\n");
1304 if (m
->FeatureFlags
& (1 << 29))
1305 DPRINT(" Thermal Monitor present.\n");
1306 /* 30, 31 Reserved */
1308 CPUMap
[CPUCount
].APICId
= m
->ApicId
;
1310 CPUMap
[CPUCount
].Flags
= CPU_USABLE
;
1312 if (m
->CpuFlags
& CPU_FLAG_BSP
)
1314 DPRINT(" Bootup CPU\n");
1315 CPUMap
[CPUCount
].Flags
|= CPU_BSP
;
1316 BootCPU
= m
->ApicId
;
1319 if (m
->ApicId
> MAX_CPU
)
1321 DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m
->ApicId
, MAX_CPU
);
1324 ver
= m
->ApicVersion
;
1331 DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m
->ApicId
);
1334 CPUMap
[CPUCount
].APICVersion
= ver
;
1339 static VOID
HaliMPBusInfo(PMP_CONFIGURATION_BUS m
)
1341 static ULONG CurrentPCIBusId
= 0;
1344 memcpy(str
, m
->BusType
, 6);
1346 DPRINT("Bus #%d is %s\n", m
->BusId
, str
);
1348 if (strncmp(str
, BUSTYPE_ISA
, sizeof(BUSTYPE_ISA
)-1) == 0)
1350 BUSMap
[m
->BusId
] = MP_BUS_ISA
;
1352 else if (strncmp(str
, BUSTYPE_EISA
, sizeof(BUSTYPE_EISA
)-1) == 0)
1354 BUSMap
[m
->BusId
] = MP_BUS_EISA
;
1356 else if (strncmp(str
, BUSTYPE_PCI
, sizeof(BUSTYPE_PCI
)-1) == 0)
1358 BUSMap
[m
->BusId
] = MP_BUS_PCI
;
1359 PCIBUSMap
[m
->BusId
] = CurrentPCIBusId
;
1362 else if (strncmp(str
, BUSTYPE_MCA
, sizeof(BUSTYPE_MCA
)-1) == 0)
1364 BUSMap
[m
->BusId
] = MP_BUS_MCA
;
1368 DPRINT("Unknown bustype %s - ignoring\n", str
);
1372 static VOID
HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m
)
1374 if (!(m
->ApicFlags
& CPU_FLAG_ENABLED
))
1377 DPRINT("I/O APIC #%d Version %d at 0x%lX.\n",
1378 m
->ApicId
, m
->ApicVersion
, m
->ApicAddress
);
1379 if (IOAPICCount
> MAX_IOAPIC
)
1381 DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n",
1382 MAX_IOAPIC
, IOAPICCount
);
1383 DPRINT1("Recompile with bigger MAX_IOAPIC!.\n");
1386 IOAPICMap
[IOAPICCount
].ApicId
= m
->ApicId
;
1387 IOAPICMap
[IOAPICCount
].ApicVersion
= m
->ApicVersion
;
1388 IOAPICMap
[IOAPICCount
].ApicAddress
= m
->ApicAddress
;
1392 static VOID
HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m
)
1394 DPRINT("Int: type %d, pol %d, trig %d, bus %d,"
1395 " IRQ %02x, APIC ID %x, APIC INT %02x\n",
1396 m
->IrqType
, m
->IrqFlag
& 3,
1397 (m
->IrqFlag
>> 2) & 3, m
->SrcBusId
,
1398 m
->SrcBusIrq
, m
->DstApicId
, m
->DstApicInt
);
1399 if (IRQCount
> MAX_IRQ_SOURCE
)
1401 DPRINT1("Max # of irq sources exceeded!!\n");
1405 IRQMap
[IRQCount
] = *m
;
1409 static VOID
HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m
)
1411 DPRINT("Lint: type %d, pol %d, trig %d, bus %d,"
1412 " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
1413 m
->IrqType
, m
->IrqFlag
& 3,
1414 (m
->IrqFlag
>> 2) & 3, m
->SrcBusId
,
1415 m
->SrcBusIrq
, m
->DstApicId
, m
->DstApicLInt
);
1417 * Well it seems all SMP boards in existence
1418 * use ExtINT/LVT1 == LINT0 and
1419 * NMI/LVT2 == LINT1 - the following check
1420 * will show us if this assumptions is false.
1421 * Until then we do not have to add baggage.
1423 if ((m
->IrqType
== INT_EXTINT
) && (m
->DstApicLInt
!= 0))
1425 DPRINT1("Invalid MP table!\n");
1428 if ((m
->IrqType
== INT_NMI
) && (m
->DstApicLInt
!= 1))
1430 DPRINT1("Invalid MP table!\n");
1436 HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table
)
1439 Table = Pointer to MP configuration table
1445 if (Table
->Signature
!= MPC_SIGNATURE
)
1447 PUCHAR pc
= (PUCHAR
)&Table
->Signature
;
1449 DbgPrint("Bad MP configuration block signature: %c%c%c%c\n",
1450 pc
[0], pc
[1], pc
[2], pc
[3]);
1455 if (MPChecksum((PUCHAR
)Table
, Table
->Length
))
1457 DbgPrint("Bad MP configuration block checksum\n");
1462 if (Table
->Specification
< 0x04)
1464 DbgPrint("Bad MP configuration table version (%d)\n",
1465 Table
->Specification
);
1470 if (Table
->LocalAPICAddress
!= APIC_DEFAULT_BASE
)
1472 DbgPrint("APIC base address is at 0x%X. " \
1473 "I cannot handle non-standard adresses\n", Table
->LocalAPICAddress
);
1477 Entry
= (PUCHAR
)((PVOID
)Table
+ sizeof(MP_CONFIGURATION_TABLE
));
1479 while (Count
< (Table
->Length
- sizeof(MP_CONFIGURATION_TABLE
)))
1481 /* Switch on type */
1484 case MPCTE_PROCESSOR
:
1486 HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR
)Entry
);
1487 Entry
+= sizeof(MP_CONFIGURATION_PROCESSOR
);
1488 Count
+= sizeof(MP_CONFIGURATION_PROCESSOR
);
1493 HaliMPBusInfo((PMP_CONFIGURATION_BUS
)Entry
);
1494 Entry
+= sizeof(MP_CONFIGURATION_BUS
);
1495 Count
+= sizeof(MP_CONFIGURATION_BUS
);
1500 HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC
)Entry
);
1501 Entry
+= sizeof(MP_CONFIGURATION_IOAPIC
);
1502 Count
+= sizeof(MP_CONFIGURATION_IOAPIC
);
1507 HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC
)Entry
);
1508 Entry
+= sizeof(MP_CONFIGURATION_INTSRC
);
1509 Count
+= sizeof(MP_CONFIGURATION_INTSRC
);
1514 HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL
)Entry
);
1515 Entry
+= sizeof(MP_CONFIGURATION_INTLOCAL
);
1516 Count
+= sizeof(MP_CONFIGURATION_INTLOCAL
);
1520 DbgPrint("Unknown entry in MPC table\n");
1526 static VOID
HaliConstructDefaultIOIrqMPTable(ULONG Type
)
1528 MP_CONFIGURATION_INTSRC intsrc
;
1531 intsrc
.Type
= MPCTE_INTSRC
;
1532 intsrc
.IrqFlag
= 0; /* conforming */
1533 intsrc
.SrcBusId
= 0;
1534 intsrc
.DstApicId
= IOAPICMap
[0].ApicId
;
1536 intsrc
.IrqType
= INT_VECTORED
;
1537 for (i
= 0; i
< 16; i
++) {
1540 if (i
== 0 || i
== 13)
1541 continue; /* IRQ0 & IRQ13 not connected */
1545 continue; /* IRQ2 is never connected */
1548 intsrc
.SrcBusIrq
= i
;
1549 intsrc
.DstApicInt
= i
? i
: 2; /* IRQ0 to INTIN2 */
1550 HaliMPIntSrcInfo(&intsrc
);
1553 intsrc
.IrqType
= INT_EXTINT
;
1554 intsrc
.SrcBusIrq
= 0;
1555 intsrc
.DstApicInt
= 0; /* 8259A to INTIN0 */
1556 HaliMPIntSrcInfo(&intsrc
);
1559 static VOID
HaliConstructDefaultISAMPTable(ULONG Type
)
1561 MP_CONFIGURATION_PROCESSOR processor
;
1562 MP_CONFIGURATION_BUS bus
;
1563 MP_CONFIGURATION_IOAPIC ioapic
;
1564 MP_CONFIGURATION_INTLOCAL lintsrc
;
1565 ULONG linttypes
[2] = { INT_EXTINT
, INT_NMI
};
1569 * 2 CPUs, numbered 0 & 1.
1571 processor
.Type
= MPCTE_PROCESSOR
;
1572 /* Either an integrated APIC or a discrete 82489DX. */
1573 processor
.ApicVersion
= Type
> 4 ? 0x10 : 0x01;
1574 processor
.CpuFlags
= CPU_FLAG_ENABLED
| CPU_FLAG_BSP
;
1575 /* FIXME: Get this from the bootstrap processor */
1576 processor
.CpuSignature
= 0;
1577 processor
.FeatureFlags
= 0;
1578 processor
.Reserved
[0] = 0;
1579 processor
.Reserved
[1] = 0;
1580 for (i
= 0; i
< 2; i
++)
1582 processor
.ApicId
= i
;
1583 HaliMPProcessorInfo(&processor
);
1584 processor
.CpuFlags
&= ~CPU_FLAG_BSP
;
1587 bus
.Type
= MPCTE_BUS
;
1592 DPRINT("Unknown standard configuration %d\n", Type
);
1596 memcpy(bus
.BusType
, "ISA ", 6);
1601 memcpy(bus
.BusType
, "EISA ", 6);
1605 memcpy(bus
.BusType
, "MCA ", 6);
1607 HaliMPBusInfo(&bus
);
1610 bus
.Type
= MPCTE_BUS
;
1612 memcpy(bus
.BusType
, "PCI ", 6);
1613 HaliMPBusInfo(&bus
);
1616 ioapic
.Type
= MPCTE_IOAPIC
;
1618 ioapic
.ApicVersion
= Type
> 4 ? 0x10 : 0x01;
1619 ioapic
.ApicFlags
= MP_IOAPIC_USABLE
;
1620 ioapic
.ApicAddress
= IOAPIC_DEFAULT_BASE
;
1621 HaliMPIOApicInfo(&ioapic
);
1624 * We set up most of the low 16 IO-APIC pins according to MPS rules.
1626 HaliConstructDefaultIOIrqMPTable(Type
);
1628 lintsrc
.Type
= MPCTE_LINTSRC
;
1629 lintsrc
.IrqType
= 0;
1630 lintsrc
.IrqFlag
= 0; /* conforming */
1631 lintsrc
.SrcBusId
= 0;
1632 lintsrc
.SrcBusIrq
= 0;
1633 lintsrc
.DstApicId
= MP_APIC_ALL
;
1634 for (i
= 0; i
< 2; i
++)
1636 lintsrc
.IrqType
= linttypes
[i
];
1637 lintsrc
.DstApicLInt
= i
;
1638 HaliMPIntLocalInfo(&lintsrc
);
1644 HaliScanForMPConfigTable(ULONG Base
,
1648 Base = Base address of region
1649 Size = Length of region to check
1651 TRUE if a valid MP configuration table was found
1654 PULONG bp
= (PULONG
)Base
;
1655 MP_FLOATING_POINTER
* mpf
;
1659 if (*bp
== MPF_SIGNATURE
)
1661 DbgPrint("Found MPF signature at %x, checksum %x\n", bp
,
1662 MPChecksum((PUCHAR
)bp
, 16));
1663 if (MPChecksum((PUCHAR
)bp
, 16) == 0)
1665 mpf
= (MP_FLOATING_POINTER
*)bp
;
1667 DbgPrint("Intel MultiProcessor Specification v1.%d compliant system.\n",
1668 mpf
->Specification
);
1670 if (mpf
->Feature2
& FEATURE2_IMCRP
) {
1672 DPRINT("Running in IMCR and PIC compatibility mode.\n");
1675 DPRINT("Running in Virtual Wire compatibility mode.\n");
1678 switch (mpf
->Feature1
)
1681 /* Non standard configuration */
1687 DPRINT("EISA with no IRQ8 chaining\n");
1696 DPRINT("ISA and PCI\n");
1699 DPRINT("EISA and PCI\n");
1702 DPRINT("MCA and PCI\n");
1705 DbgPrint("Unknown standard configuration %d\n", mpf
->Feature1
);
1713 if ((mpf
->Feature1
== 0) && (mpf
->Address
)) {
1714 HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE
)mpf
->Address
);
1716 HaliConstructDefaultISAMPTable(mpf
->Feature1
);
1732 static BOOLEAN MPSInitialized
= FALSE
;
1735 /* Only initialize MP system once. Once called the first time,
1736 each subsequent call is part of the initialization sequence
1737 for an application processor. */
1739 DPRINT("HalpInitMPS()\n");
1747 MPSInitialized
= TRUE
;
1750 Scan the system memory for an MP configuration table
1751 1) Scan the first KB of system base memory
1752 2) Scan the last KB of system base memory
1753 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh
1754 4) Scan the Extended BIOS Data Area
1757 if (!HaliScanForMPConfigTable(0x0, 0x400))
1759 if (!HaliScanForMPConfigTable(0x9FC00, 0x400))
1761 if (!HaliScanForMPConfigTable(0xF0000, 0x10000))
1763 EBDA
= *((PUSHORT
)0x040E);
1765 if (!HaliScanForMPConfigTable((ULONG
)EBDA
, 0x1000))
1767 DbgPrint("No multiprocessor compliant system found.\n");
1774 /* Setup IRQ to vector translation map */
1775 memset(&IRQVectorMap
, 0, sizeof(IRQVectorMap
));
1777 /* Setup interrupt handlers */
1778 SetInterruptGate(LOCAL_TIMER_VECTOR
, (ULONG
)MpsTimerInterrupt
);
1779 SetInterruptGate(ERROR_VECTOR
, (ULONG
)MpsErrorInterrupt
);
1780 SetInterruptGate(SPURIOUS_VECTOR
, (ULONG
)MpsSpuriousInterrupt
);
1781 SetInterruptGate(IPI_VECTOR
, (ULONG
)MpsIpiInterrupt
);
1786 HaliReconfigurePciInterrupts(VOID
)
1790 for (i
= 0; i
< IRQCount
; i
++)
1792 if (BUSMap
[IRQMap
[i
].SrcBusId
] == MP_BUS_PCI
)
1794 DPRINT("%02x: IrqType %02x, IrqFlag %02x, SrcBusId %02x, SrcBusIrq %02x, DstApicId %02x, DstApicInt %02x\n",
1795 i
, IRQMap
[i
].IrqType
, IRQMap
[i
].IrqFlag
, IRQMap
[i
].SrcBusId
,
1796 IRQMap
[i
].SrcBusIrq
, IRQMap
[i
].DstApicId
, IRQMap
[i
].DstApicInt
);
1798 if(1 != HalSetBusDataByOffset(PCIConfiguration
, IRQMap
[i
].SrcBusId
, (IRQMap
[i
].SrcBusIrq
>> 2) & 0x1f, &IRQMap
[i
].DstApicInt
, 0x3c /*PCI_INTERRUPT_LINE*/, 1))