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 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
];
189 *(((PULONG
)&Entry
)+0) = IOAPICRead(Apic
, IOAPIC_REDTBL
+2*Irq
);
190 *(((PULONG
)&Entry
)+1) = IOAPICRead(Apic
, IOAPIC_REDTBL
+2*Irq
+1);
191 Entry
.dest
.logical
.logical_dest
&= ~(1 << KeGetCurrentProcessorNumber());
192 if (Entry
.dest
.logical
.logical_dest
== 0)
196 IOAPICWrite(Apic
, IOAPIC_REDTBL
+2*Irq
+1, *(((PULONG
)&Entry
)+1));
197 IOAPICWrite(Apic
, IOAPIC_REDTBL
+2*Irq
, *(((PULONG
)&Entry
)+0));
201 /* This is performance critical and should probably be done in assembler */
202 VOID
IOAPICUnmaskIrq(ULONG Irq
)
204 IOAPIC_ROUTE_ENTRY Entry
;
205 ULONG Apic
= IrqApicMap
[Irq
];
207 *(((PULONG
)&Entry
)+0) = IOAPICRead(Apic
, IOAPIC_REDTBL
+2*Irq
);
208 *(((PULONG
)&Entry
)+1) = IOAPICRead(Apic
, IOAPIC_REDTBL
+2*Irq
+1);
209 Entry
.dest
.logical
.logical_dest
|= 1 << KeGetCurrentProcessorNumber();
211 IOAPICWrite(Apic
, IOAPIC_REDTBL
+2*Irq
+1, *(((PULONG
)&Entry
)+1));
212 IOAPICWrite(Apic
, IOAPIC_REDTBL
+2*Irq
, *(((PULONG
)&Entry
)+0));
222 * Set the IOAPIC ID to the value stored in the MPC table.
224 for (apic
= 0; apic
< IOAPICCount
; apic
++)
227 /* Read the register 0 value */
228 tmp
= IOAPICRead(apic
, IOAPIC_ID
);
230 old_id
= IOAPICMap
[apic
].ApicId
;
232 if (IOAPICMap
[apic
].ApicId
>= 0xf)
234 DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
235 apic
, IOAPICMap
[apic
].ApicId
);
236 DPRINT1("... fixing up to %d. (tell your hw vendor)\n",
238 IOAPICMap
[apic
].ApicId
= GET_IOAPIC_ID(tmp
);
242 * We need to adjust the IRQ routing table
245 if (old_id
!= IOAPICMap
[apic
].ApicId
)
247 for (i
= 0; i
< IRQCount
; i
++)
249 if (IRQMap
[i
].DstApicId
== old_id
)
251 IRQMap
[i
].DstApicId
= IOAPICMap
[apic
].ApicId
;
257 * Read the right value from the MPC table and
258 * write it into the ID register.
260 DPRINT("Changing IO-APIC physical APIC ID to %d\n",
261 IOAPICMap
[apic
].ApicId
);
263 tmp
&= ~IOAPIC_ID_MASK
;
264 tmp
|= SET_IOAPIC_ID(IOAPICMap
[apic
].ApicId
);
266 IOAPICWrite(apic
, IOAPIC_ID
, tmp
);
271 tmp
= IOAPICRead(apic
, 0);
272 if (GET_IOAPIC_ID(tmp
) != IOAPICMap
[apic
].ApicId
)
274 DPRINT1("Could not set I/O APIC ID!\n");
282 * EISA Edge/Level control register, ELCR
284 static ULONG
EISA_ELCR(ULONG irq
)
288 PUCHAR port
= (PUCHAR
)(0x4d0 + (irq
>> 3));
289 return (READ_PORT_UCHAR(port
) >> (irq
& 7)) & 1;
291 DPRINT("Broken MPtable reports ISA irq %d\n", irq
);
295 /* EISA interrupts are always polarity zero and can be edge or level
296 * trigger depending on the ELCR value. If an interrupt is listed as
297 * EISA conforming in the MP table, that means its trigger type must
298 * be read in from the ELCR */
300 #define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq))
301 #define default_EISA_polarity(idx) (0)
303 /* ISA interrupts are always polarity zero edge triggered,
304 * when listed as conforming in the MP table. */
306 #define default_ISA_trigger(idx) (0)
307 #define default_ISA_polarity(idx) (0)
309 /* PCI interrupts are always polarity one level triggered,
310 * when listed as conforming in the MP table. */
312 #define default_PCI_trigger(idx) (1)
313 #define default_PCI_polarity(idx) (1)
315 /* MCA interrupts are always polarity zero level triggered,
316 * when listed as conforming in the MP table. */
318 #define default_MCA_trigger(idx) (1)
319 #define default_MCA_polarity(idx) (0)
321 static ULONG
IRQPolarity(ULONG idx
)
323 ULONG bus
= IRQMap
[idx
].SrcBusId
;
327 * Determine IRQ line polarity (high active or low active):
329 switch (IRQMap
[idx
].IrqFlag
& 3)
331 case 0: /* conforms, ie. bus-type dependent polarity */
335 case MP_BUS_ISA
: /* ISA pin */
337 polarity
= default_ISA_polarity(idx
);
340 case MP_BUS_EISA
: /* EISA pin */
342 polarity
= default_EISA_polarity(idx
);
345 case MP_BUS_PCI
: /* PCI pin */
347 polarity
= default_PCI_polarity(idx
);
350 case MP_BUS_MCA
: /* MCA pin */
352 polarity
= default_MCA_polarity(idx
);
357 DPRINT("Broken BIOS!!\n");
364 case 1: /* high active */
369 case 2: /* reserved */
371 DPRINT("Broken BIOS!!\n");
375 case 3: /* low active */
380 default: /* invalid */
382 DPRINT("Broken BIOS!!\n");
390 static ULONG
IRQTrigger(ULONG idx
)
392 ULONG bus
= IRQMap
[idx
].SrcBusId
;
396 * Determine IRQ trigger mode (edge or level sensitive):
398 switch ((IRQMap
[idx
].IrqFlag
>> 2) & 3)
400 case 0: /* conforms, ie. bus-type dependent */
404 case MP_BUS_ISA
: /* ISA pin */
406 trigger
= default_ISA_trigger(idx
);
409 case MP_BUS_EISA
: /* EISA pin */
411 trigger
= default_EISA_trigger(idx
);
414 case MP_BUS_PCI
: /* PCI pin */
416 trigger
= default_PCI_trigger(idx
);
419 case MP_BUS_MCA
: /* MCA pin */
421 trigger
= default_MCA_trigger(idx
);
426 DPRINT("Broken BIOS!!\n");
438 case 2: /* reserved */
440 DPRINT("Broken BIOS!!\n");
449 default: /* invalid */
451 DPRINT("Broken BIOS!!\n");
460 static ULONG
Pin2Irq(ULONG idx
,
465 ULONG bus
= IRQMap
[idx
].SrcBusId
;
468 * Debugging check, we are in big trouble if this message pops up!
470 if (IRQMap
[idx
].DstApicInt
!= pin
) {
471 DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n");
476 case MP_BUS_ISA
: /* ISA pin */
480 irq
= IRQMap
[idx
].SrcBusIrq
;
483 case MP_BUS_PCI
: /* PCI pin */
486 * PCI IRQs are mapped in order
490 irq
+= IOAPICMap
[i
++].EntryCount
;
496 DPRINT("Unknown bus type %d.\n",bus
);
507 * Rough estimation of how many shared IRQs there are, can
508 * be changed anytime.
510 #define MAX_PLUS_SHARED_IRQS PIC_IRQS
511 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + PIC_IRQS)
514 * This is performance-critical, we want to do it O(1)
516 * the indexing order of this array favors 1:1 mappings
517 * between pins and IRQs.
520 static struct irq_pin_list
{
521 ULONG apic
, pin
, next
;
522 } irq_2_pin
[PIN_MAP_SIZE
];
525 * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
526 * shared ISA-space IRQs, so we have to support them. We are super
527 * fast in the common case, and fast for shared ISA-space IRQs.
529 static VOID
AddPinToIrq(ULONG irq
,
533 static ULONG first_free_entry
= PIC_IRQS
;
534 struct irq_pin_list
*entry
= irq_2_pin
+ irq
;
538 entry
= irq_2_pin
+ entry
->next
;
541 if (entry
->pin
!= -1)
543 entry
->next
= first_free_entry
;
544 entry
= irq_2_pin
+ entry
->next
;
545 if (++first_free_entry
>= PIN_MAP_SIZE
)
557 * Find the IRQ entry number of a certain pin.
559 static ULONG
IOAPICGetIrqEntry(ULONG apic
,
565 for (i
= 0; i
< IRQCount
; i
++)
567 if (IRQMap
[i
].IrqType
== type
&&
568 (IRQMap
[i
].DstApicId
== IOAPICMap
[apic
].ApicId
|| IRQMap
[i
].DstApicId
== MP_APIC_ALL
) &&
569 IRQMap
[i
].DstApicInt
== pin
)
578 static ULONG
AssignIrqVector(ULONG irq
)
581 static ULONG current_vector
= FIRST_DEVICE_VECTOR
, vector_offset
= 0;
584 /* There may already have been assigned a vector for this IRQ */
585 vector
= IRQVectorMap
[irq
];
591 if (current_vector
> FIRST_SYSTEM_VECTOR
) {
593 current_vector
= FIRST_DEVICE_VECTOR
+ vector_offset
;
594 } else if (current_vector
== FIRST_SYSTEM_VECTOR
) {
595 DPRINT1("Ran out of interrupt sources!");
599 vector
= current_vector
;
600 IRQVectorMap
[irq
] = vector
;
604 vector
= IRQ2VECTOR(irq
);
605 IRQVectorMap
[irq
] = vector
;
611 VOID
IOAPICSetupIrqs(VOID
)
613 IOAPIC_ROUTE_ENTRY entry
;
614 ULONG apic
, pin
, idx
, irq
, first_notcon
= 1, vector
;
616 DPRINT("Init IO_APIC IRQs\n");
618 for (apic
= 0; apic
< IOAPICCount
; apic
++)
620 for (pin
= 0; pin
< IOAPICMap
[apic
].EntryCount
; pin
++)
623 * add it to the IO-APIC irq-routing table
625 memset(&entry
,0,sizeof(entry
));
627 entry
.delivery_mode
= (APIC_DM_LOWEST
>> 8);
628 entry
.dest_mode
= 1; /* logical delivery */
629 entry
.mask
= 1; /* disable IRQ */
630 entry
.dest
.logical
.logical_dest
= 0;
632 idx
= IOAPICGetIrqEntry(apic
,pin
,INT_VECTORED
);
637 DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap
[apic
].ApicId
, pin
);
642 DPRINT(", %d-%d\n", IOAPICMap
[apic
].ApicId
, pin
);
647 entry
.trigger
= IRQTrigger(idx
);
648 entry
.polarity
= IRQPolarity(idx
);
653 entry
.mask
= 1; // disable
654 entry
.dest
.logical
.logical_dest
= 0;
657 irq
= Pin2Irq(idx
, apic
, pin
);
658 AddPinToIrq(irq
, apic
, pin
);
660 vector
= AssignIrqVector(irq
);
661 entry
.vector
= vector
;
663 DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector
, irq
);
671 if ((apic
== 0) && (irq
< 16))
673 Disable8259AIrq(irq
);
675 IOAPICWrite(apic
, IOAPIC_REDTBL
+2*pin
+1, *(((PULONG
)&entry
)+1));
676 IOAPICWrite(apic
, IOAPIC_REDTBL
+2*pin
, *(((PULONG
)&entry
)+0));
678 IrqPinMap
[irq
] = pin
;
679 IrqApicMap
[irq
] = apic
;
681 DPRINT("Vector %x, Pin %x, Irq %x\n", vector
, pin
, irq
);
687 static VOID
IOAPICEnable(VOID
)
691 for (i
= 0; i
< PIN_MAP_SIZE
; i
++)
693 irq_2_pin
[i
].pin
= -1;
694 irq_2_pin
[i
].next
= 0;
698 * The number of IO-APIC IRQ registers (== #pins):
700 for (i
= 0; i
< IOAPICCount
; i
++)
702 tmp
= IOAPICRead(i
, IOAPIC_VER
);
703 IOAPICMap
[i
].EntryCount
= GET_IOAPIC_MRE(tmp
) + 1;
707 * Do not trust the IO-APIC being empty at bootup
713 static VOID
IOAPICDisable(VOID
)
716 * Clear the IO-APIC before rebooting
724 static VOID
IOAPICSetup(VOID
)
733 VOID
IOAPICDump(VOID
)
736 ULONG reg0
, reg1
, reg2
=0;
738 DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount
);
739 for (i
= 0; i
< IOAPICCount
; i
++)
741 DbgPrint("Number of IO-APIC #%d registers: %d.\n",
743 IOAPICMap
[i
].EntryCount
);
747 * We are a bit conservative about what we expect. We have to
748 * know about every hardware change ASAP.
750 DbgPrint("Testing the IO APIC.......................\n");
752 for (apic
= 0; apic
< IOAPICCount
; apic
++)
754 reg0
= IOAPICRead(apic
, IOAPIC_ID
);
755 reg1
= IOAPICRead(apic
, IOAPIC_VER
);
756 if (GET_IOAPIC_VERSION(reg1
) >= 0x10)
758 reg2
= IOAPICRead(apic
, IOAPIC_ARB
);
762 DbgPrint("IO APIC #%d......\n", IOAPICMap
[apic
].ApicId
);
763 DbgPrint(".... register #00: %08X\n", reg0
);
764 DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0
));
765 if (reg0
& 0xF0FFFFFF)
767 DbgPrint(" WARNING: Unexpected IO-APIC\n");
770 DbgPrint(".... register #01: %08X\n", reg1
);
771 i
= GET_IOAPIC_MRE(reg1
);
773 DbgPrint("....... : max redirection entries: %04X\n", i
);
774 if ((i
!= 0x0f) && /* older (Neptune) boards */
775 (i
!= 0x17) && /* typical ISA+PCI boards */
776 (i
!= 0x1b) && /* Compaq Proliant boards */
777 (i
!= 0x1f) && /* dual Xeon boards */
778 (i
!= 0x22) && /* bigger Xeon boards */
782 DbgPrint(" WARNING: Unexpected IO-APIC\n");
785 i
= GET_IOAPIC_VERSION(reg1
);
786 DbgPrint("....... : IO APIC version: %04X\n", i
);
787 if ((i
!= 0x01) && /* 82489DX IO-APICs */
788 (i
!= 0x10) && /* oldest IO-APICs */
789 (i
!= 0x11) && /* Pentium/Pro IO-APICs */
790 (i
!= 0x13)) /* Xeon IO-APICs */
792 DbgPrint(" WARNING: Unexpected IO-APIC\n");
795 if (reg1
& 0xFF00FF00)
797 DbgPrint(" WARNING: Unexpected IO-APIC\n");
800 if (GET_IOAPIC_VERSION(reg1
) >= 0x10)
802 DbgPrint(".... register #02: %08X\n", reg2
);
803 DbgPrint("....... : arbitration: %02X\n",
804 GET_IOAPIC_ARB(reg2
));
805 if (reg2
& 0xF0FFFFFF)
807 DbgPrint(" WARNING: Unexpected IO-APIC\n");
811 DbgPrint(".... IRQ redirection table:\n");
812 DbgPrint(" NR Log Phy Mask Trig IRR Pol"
813 " Stat Dest Deli Vect: \n");
815 for (i
= 0; i
<= GET_IOAPIC_MRE(reg1
); i
++)
817 IOAPIC_ROUTE_ENTRY entry
;
819 *(((PULONG
)&entry
)+0) = IOAPICRead(apic
, 0x10+i
*2);
820 *(((PULONG
)&entry
)+1) = IOAPICRead(apic
, 0x11+i
*2);
822 DbgPrint(" %02x %03X %02X ",
824 entry
.dest
.logical
.logical_dest
,
825 entry
.dest
.physical
.physical_dest
);
827 DbgPrint("%C %C %1d %C %C %C %03X %02X\n",
828 (entry
.mask
== 0) ? 'U' : 'M', // Unmasked/masked
829 (entry
.trigger
== 0) ? 'E' : 'L', // Edge/level sensitive
831 (entry
.polarity
== 0) ? 'H' : 'L', // Active high/active low
832 (entry
.delivery_status
== 0) ? 'I' : 'S', // Idle / send pending
833 (entry
.dest_mode
== 0) ? 'P' : 'L', // Physical logical
838 DbgPrint("IRQ to pin mappings:\n");
839 for (i
= 0; i
< PIC_IRQS
; i
++)
841 struct irq_pin_list
*entry
= irq_2_pin
+ i
;
846 DbgPrint("IRQ%d ", i
);
849 DbgPrint("-> %d", entry
->pin
);
854 entry
= irq_2_pin
+ entry
->next
;
866 DbgPrint(".................................... done.\n");
871 /* Functions for handling local APICs */
873 ULONG
Read8254Timer(VOID
)
877 WRITE_PORT_UCHAR((PUCHAR
)0x43, 0x00);
878 Count
= READ_PORT_UCHAR((PUCHAR
)0x40);
879 Count
|= READ_PORT_UCHAR((PUCHAR
)0x40) << 8;
884 VOID
WaitFor8254Wraparound(VOID
)
886 ULONG CurCount
, PrevCount
= ~0;
889 CurCount
= Read8254Timer();
892 PrevCount
= CurCount
;
893 CurCount
= Read8254Timer();
894 Delta
= CurCount
- PrevCount
;
897 * This limit for delta seems arbitrary, but it isn't, it's
898 * slightly above the level of error a buggy Mercury/Neptune
899 * chipset timer can cause.
907 #define APIC_DIVISOR (16)
909 VOID
APICSetupLVTT(ULONG ClockTicks
)
913 tmp
= GET_APIC_VERSION(APICRead(APIC_VER
));
914 if (!APIC_INTEGRATED(tmp
))
916 tmp
= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV
) | APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
921 tmp
= APIC_LVT_PERIODIC
| LOCAL_TIMER_VECTOR
;;
923 APICWrite(APIC_LVTT
, tmp
);
925 tmp
= APICRead(APIC_TDCR
);
926 tmp
&= ~(APIC_TDCR_1
| APIC_TIMER_BASE_DIV
);
928 APICWrite(APIC_TDCR
, tmp
);
929 APICWrite(APIC_ICRT
, ClockTicks
/ APIC_DIVISOR
);
933 VOID
APICCalibrateTimer(ULONG CPU
)
935 ULARGE_INTEGER t1
, t2
;
938 DPRINT("Calibrating APIC timer for CPU %d\n", CPU
);
940 APICSetupLVTT(1000000000);
943 * The timer chip counts down to zero. Let's wait
944 * for a wraparound to start exact measurement:
945 * (the current tick might have been already half done)
947 WaitFor8254Wraparound();
950 * We wrapped around just now. Let's start
952 ReadPentiumClock(&t1
);
953 tt1
= APICRead(APIC_CCRT
);
955 WaitFor8254Wraparound();
958 tt2
= APICRead(APIC_CCRT
);
959 ReadPentiumClock(&t2
);
961 CPUMap
[CPU
].BusSpeed
= (HZ
* (long)(tt1
- tt2
) * APIC_DIVISOR
);
962 CPUMap
[CPU
].CoreSpeed
= (HZ
* (t2
.QuadPart
- t1
.QuadPart
));
964 /* Setup timer for normal operation */
965 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
966 APICSetupLVTT((CPUMap
[CPU
].BusSpeed
/ 1000000) * 10000); // 10ms
967 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
969 DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
970 CPUMap
[CPU
].CoreSpeed
/1000000,
971 CPUMap
[CPU
].CoreSpeed
%1000000);
973 DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
974 CPUMap
[CPU
].BusSpeed
/1000000,
975 CPUMap
[CPU
].BusSpeed
%1000000);
979 SetInterruptGate(ULONG index
, ULONG address
)
983 idt
= (IDT_DESCRIPTOR
*)((ULONG
)KeGetCurrentKPCR()->IDT
+ index
* sizeof(IDT_DESCRIPTOR
));
984 idt
->a
= (((ULONG
)address
)&0xffff) + (KERNEL_CS
<< 16);
985 idt
->b
= 0x8e00 + (((ULONG
)address
)&0xffff0000);
989 HalInitializeProcessor(ULONG ProcessorNumber
,
990 PVOID
/*PLOADER_PARAMETER_BLOCK*/ LoaderBlock
)
994 DPRINT("HalInitializeProcessor(%x %x)\n", ProcessorNumber
, LoaderBlock
);
997 if (OnlineCPUs
& (1 << CPU
))
1002 if (ProcessorNumber
== 0)
1010 DPRINT("CPU %d says it is now booted.\n", CPU
);
1012 APICCalibrateTimer(CPU
);
1015 /* This processor is now booted */
1016 CPUMap
[CPU
].Flags
|= CPU_ENABLED
;
1017 OnlineCPUs
|= (1 << CPU
);
1019 /* Setup busy waiting */
1020 HalpCalibrateStallExecution();
1024 HalAllProcessorsStarted (VOID
)
1028 DPRINT("HalAllProcessorsStarted()\n");
1029 for (i
= 0; i
< 32; i
++)
1031 if (OnlineCPUs
& (1 << i
))
1036 if (CPUs
> CPUCount
)
1040 else if (CPUs
== CPUCount
)
1049 HalStartNextProcessor(ULONG Unknown1
,
1050 ULONG ProcessorStack
)
1052 PCOMMON_AREA_INFO Common
;
1054 ULONG DeliveryStatus
= 0;
1055 ULONG AcceptStatus
= 0;
1059 DPRINT("HalStartNextProcessor(%x %x)\n", Unknown1
, ProcessorStack
);
1061 for (CPU
= 0; CPU
< CPUCount
; CPU
++)
1063 if (!(OnlineCPUs
& (1<<CPU
)))
1069 if (CPU
>= CPUCount
)
1074 DPRINT1("Attempting to boot CPU %d\n", CPU
);
1078 APICSendIPI(CPU
, APIC_DM_INIT
|APIC_ICR0_LEVEL_ASSERT
);
1080 KeStallExecutionProcessor(200);
1084 APICSendIPI(CPU
, APIC_DM_INIT
|APIC_ICR0_LEVEL_DEASSERT
);
1086 if (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
1088 /* Clear APIC errors */
1089 APICWrite(APIC_ESR
, 0);
1090 tmp
= (APICRead(APIC_ESR
) & APIC_ESR_MASK
);
1093 Common
= (PCOMMON_AREA_INFO
)CommonBase
;
1095 /* Write the location of the AP stack */
1096 Common
->Stack
= (ULONG
)ProcessorStack
;
1098 DPRINT("CPU %d got stack at 0x%X\n", CPU
, Common
->Stack
);
1100 for (j
= 0; j
< 16; j
++)
1102 Common
->Debug
[j
] = 0;
1106 maxlvt
= APICGetMaxLVT();
1108 /* Is this a local APIC or an 82489DX? */
1109 StartupCount
= (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
)) ? 2 : 0;
1111 for (i
= 1; i
<= StartupCount
; i
++)
1113 /* It's a local APIC, so send STARTUP IPI */
1114 DPRINT("Sending startup signal %d\n", i
);
1116 APICWrite(APIC_ESR
, 0);
1119 APICSendIPI(CPU
, APIC_DM_STARTUP
| ((COMMON_AREA
+ PAGE_SIZE
) >> 12)|APIC_ICR0_LEVEL_DEASSERT
);
1121 /* Wait up to 10ms for IPI to be delivered */
1125 KeStallExecutionProcessor(10);
1127 /* Check Delivery Status */
1128 DeliveryStatus
= APICRead(APIC_ICR0
) & APIC_ICR0_DS
;
1131 } while ((DeliveryStatus
) && (j
< 1000));
1133 KeStallExecutionProcessor(200);
1136 * Due to the Pentium erratum 3AP.
1140 APICRead(APIC_SIVR
);
1141 APICWrite(APIC_ESR
, 0);
1144 AcceptStatus
= APICRead(APIC_ESR
) & APIC_ESR_MASK
;
1146 if (DeliveryStatus
|| AcceptStatus
)
1154 DPRINT("STARTUP IPI for CPU %d was never delivered.\n", CPU
);
1159 DPRINT("STARTUP IPI for CPU %d was never accepted.\n", CPU
);
1162 if (!(DeliveryStatus
|| AcceptStatus
))
1165 /* Wait no more than 5 seconds for processor to boot */
1166 DPRINT("Waiting for 5 seconds for CPU %d to boot\n", CPU
);
1168 /* Wait no more than 5 seconds */
1169 for (j
= 0; j
< 50000; j
++)
1171 if (CPUMap
[CPU
].Flags
& CPU_ENABLED
)
1175 KeStallExecutionProcessor(100);
1179 if (CPUMap
[CPU
].Flags
& CPU_ENABLED
)
1181 DbgPrint("CPU %d is now running\n", CPU
);
1185 DbgPrint("Initialization of CPU %d failed\n", CPU
);
1189 DPRINT("Debug bytes are:\n");
1191 for (j
= 0; j
< 4; j
++)
1193 DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
1194 Common
->Debug
[j
*4+0],
1195 Common
->Debug
[j
*4+1],
1196 Common
->Debug
[j
*4+2],
1197 Common
->Debug
[j
*4+3]);
1205 ULONG
MPChecksum(PUCHAR Base
,
1208 * Checksum an MP configuration block
1220 PCHAR
HaliMPFamily(ULONG Family
,
1223 static CHAR str
[32];
1224 static PCHAR CPUs
[] =
1226 "80486DX", "80486DX",
1227 "80486SX", "80486DX/2 or 80487",
1228 "80486SL", "Intel5X2(tm)",
1229 "Unknown", "Unknown",
1233 return ("Pentium(tm) Pro");
1235 return ("Pentium(tm)");
1236 if (Family
== 0x0F && Model
== 0x0F)
1237 return("Special controller");
1238 if (Family
== 0x0F && Model
== 0x00)
1239 return("Pentium 4(tm)");
1240 if (Family
== 0x04 && Model
< 9)
1242 sprintf(str
, "Unknown CPU with family ID %ld and model ID %ld", Family
, Model
);
1246 static VOID
HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m
)
1250 if (!(m
->CpuFlags
& CPU_FLAG_ENABLED
))
1253 DPRINT("Processor #%d %s APIC version %d\n",
1255 HaliMPFamily((m
->FeatureFlags
& CPU_FAMILY_MASK
) >> 8,
1256 (m
->FeatureFlags
& CPU_MODEL_MASK
) >> 4),
1259 if (m
->FeatureFlags
& (1 << 0))
1260 DPRINT(" Floating point unit present.\n");
1261 if (m
->FeatureFlags
& (1 << 7))
1262 DPRINT(" Machine Exception supported.\n");
1263 if (m
->FeatureFlags
& (1 << 8))
1264 DPRINT(" 64 bit compare & exchange supported.\n");
1265 if (m
->FeatureFlags
& (1 << 9))
1266 DPRINT(" Internal APIC present.\n");
1267 if (m
->FeatureFlags
& (1 << 11))
1268 DPRINT(" SEP present.\n");
1269 if (m
->FeatureFlags
& (1 << 12))
1270 DPRINT(" MTRR present.\n");
1271 if (m
->FeatureFlags
& (1 << 13))
1272 DPRINT(" PGE present.\n");
1273 if (m
->FeatureFlags
& (1 << 14))
1274 DPRINT(" MCA present.\n");
1275 if (m
->FeatureFlags
& (1 << 15))
1276 DPRINT(" CMOV present.\n");
1277 if (m
->FeatureFlags
& (1 << 16))
1278 DPRINT(" PAT present.\n");
1279 if (m
->FeatureFlags
& (1 << 17))
1280 DPRINT(" PSE present.\n");
1281 if (m
->FeatureFlags
& (1 << 18))
1282 DPRINT(" PSN present.\n");
1283 if (m
->FeatureFlags
& (1 << 19))
1284 DPRINT(" Cache Line Flush Instruction present.\n");
1286 if (m
->FeatureFlags
& (1 << 21))
1287 DPRINT(" Debug Trace and EMON Store present.\n");
1288 if (m
->FeatureFlags
& (1 << 22))
1289 DPRINT(" ACPI Thermal Throttle Registers present.\n");
1290 if (m
->FeatureFlags
& (1 << 23))
1291 DPRINT(" MMX present.\n");
1292 if (m
->FeatureFlags
& (1 << 24))
1293 DPRINT(" FXSR present.\n");
1294 if (m
->FeatureFlags
& (1 << 25))
1295 DPRINT(" XMM present.\n");
1296 if (m
->FeatureFlags
& (1 << 26))
1297 DPRINT(" Willamette New Instructions present.\n");
1298 if (m
->FeatureFlags
& (1 << 27))
1299 DPRINT(" Self Snoop present.\n");
1301 if (m
->FeatureFlags
& (1 << 29))
1302 DPRINT(" Thermal Monitor present.\n");
1303 /* 30, 31 Reserved */
1305 CPUMap
[CPUCount
].APICId
= m
->ApicId
;
1307 CPUMap
[CPUCount
].Flags
= CPU_USABLE
;
1309 if (m
->CpuFlags
& CPU_FLAG_BSP
)
1311 DPRINT(" Bootup CPU\n");
1312 CPUMap
[CPUCount
].Flags
|= CPU_BSP
;
1313 BootCPU
= m
->ApicId
;
1316 if (m
->ApicId
> MAX_CPU
)
1318 DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m
->ApicId
, MAX_CPU
);
1321 ver
= m
->ApicVersion
;
1328 DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m
->ApicId
);
1331 CPUMap
[CPUCount
].APICVersion
= ver
;
1336 static VOID
HaliMPBusInfo(PMP_CONFIGURATION_BUS m
)
1338 static ULONG CurrentPCIBusId
= 0;
1341 memcpy(str
, m
->BusType
, 6);
1343 DPRINT("Bus #%d is %s\n", m
->BusId
, str
);
1345 if (strncmp(str
, BUSTYPE_ISA
, sizeof(BUSTYPE_ISA
)-1) == 0)
1347 BUSMap
[m
->BusId
] = MP_BUS_ISA
;
1349 else if (strncmp(str
, BUSTYPE_EISA
, sizeof(BUSTYPE_EISA
)-1) == 0)
1351 BUSMap
[m
->BusId
] = MP_BUS_EISA
;
1353 else if (strncmp(str
, BUSTYPE_PCI
, sizeof(BUSTYPE_PCI
)-1) == 0)
1355 BUSMap
[m
->BusId
] = MP_BUS_PCI
;
1356 PCIBUSMap
[m
->BusId
] = CurrentPCIBusId
;
1359 else if (strncmp(str
, BUSTYPE_MCA
, sizeof(BUSTYPE_MCA
)-1) == 0)
1361 BUSMap
[m
->BusId
] = MP_BUS_MCA
;
1365 DPRINT("Unknown bustype %s - ignoring\n", str
);
1369 static VOID
HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m
)
1371 if (!(m
->ApicFlags
& CPU_FLAG_ENABLED
))
1374 DPRINT("I/O APIC #%d Version %d at 0x%lX.\n",
1375 m
->ApicId
, m
->ApicVersion
, m
->ApicAddress
);
1376 if (IOAPICCount
> MAX_IOAPIC
)
1378 DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n",
1379 MAX_IOAPIC
, IOAPICCount
);
1380 DPRINT1("Recompile with bigger MAX_IOAPIC!.\n");
1383 IOAPICMap
[IOAPICCount
].ApicId
= m
->ApicId
;
1384 IOAPICMap
[IOAPICCount
].ApicVersion
= m
->ApicVersion
;
1385 IOAPICMap
[IOAPICCount
].ApicAddress
= m
->ApicAddress
;
1389 static VOID
HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m
)
1391 DPRINT("Int: type %d, pol %d, trig %d, bus %d,"
1392 " IRQ %02x, APIC ID %x, APIC INT %02x\n",
1393 m
->IrqType
, m
->IrqFlag
& 3,
1394 (m
->IrqFlag
>> 2) & 3, m
->SrcBusId
,
1395 m
->SrcBusIrq
, m
->DstApicId
, m
->DstApicInt
);
1396 if (IRQCount
> MAX_IRQ_SOURCE
)
1398 DPRINT1("Max # of irq sources exceeded!!\n");
1402 IRQMap
[IRQCount
] = *m
;
1406 static VOID
HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m
)
1408 DPRINT("Lint: type %d, pol %d, trig %d, bus %d,"
1409 " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
1410 m
->IrqType
, m
->IrqFlag
& 3,
1411 (m
->IrqFlag
>> 2) & 3, m
->SrcBusId
,
1412 m
->SrcBusIrq
, m
->DstApicId
, m
->DstApicLInt
);
1414 * Well it seems all SMP boards in existence
1415 * use ExtINT/LVT1 == LINT0 and
1416 * NMI/LVT2 == LINT1 - the following check
1417 * will show us if this assumptions is false.
1418 * Until then we do not have to add baggage.
1420 if ((m
->IrqType
== INT_EXTINT
) && (m
->DstApicLInt
!= 0))
1422 DPRINT1("Invalid MP table!\n");
1425 if ((m
->IrqType
== INT_NMI
) && (m
->DstApicLInt
!= 1))
1427 DPRINT1("Invalid MP table!\n");
1433 HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table
)
1436 Table = Pointer to MP configuration table
1442 if (Table
->Signature
!= MPC_SIGNATURE
)
1444 PUCHAR pc
= (PUCHAR
)&Table
->Signature
;
1446 DbgPrint("Bad MP configuration block signature: %c%c%c%c\n",
1447 pc
[0], pc
[1], pc
[2], pc
[3]);
1452 if (MPChecksum((PUCHAR
)Table
, Table
->Length
))
1454 DbgPrint("Bad MP configuration block checksum\n");
1459 if (Table
->Specification
< 0x04)
1461 DbgPrint("Bad MP configuration table version (%d)\n",
1462 Table
->Specification
);
1467 if (Table
->LocalAPICAddress
!= APIC_DEFAULT_BASE
)
1469 DbgPrint("APIC base address is at 0x%X. " \
1470 "I cannot handle non-standard adresses\n", Table
->LocalAPICAddress
);
1474 Entry
= (PUCHAR
)((PVOID
)Table
+ sizeof(MP_CONFIGURATION_TABLE
));
1476 while (Count
< (Table
->Length
- sizeof(MP_CONFIGURATION_TABLE
)))
1478 /* Switch on type */
1481 case MPCTE_PROCESSOR
:
1483 HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR
)Entry
);
1484 Entry
+= sizeof(MP_CONFIGURATION_PROCESSOR
);
1485 Count
+= sizeof(MP_CONFIGURATION_PROCESSOR
);
1490 HaliMPBusInfo((PMP_CONFIGURATION_BUS
)Entry
);
1491 Entry
+= sizeof(MP_CONFIGURATION_BUS
);
1492 Count
+= sizeof(MP_CONFIGURATION_BUS
);
1497 HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC
)Entry
);
1498 Entry
+= sizeof(MP_CONFIGURATION_IOAPIC
);
1499 Count
+= sizeof(MP_CONFIGURATION_IOAPIC
);
1504 HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC
)Entry
);
1505 Entry
+= sizeof(MP_CONFIGURATION_INTSRC
);
1506 Count
+= sizeof(MP_CONFIGURATION_INTSRC
);
1511 HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL
)Entry
);
1512 Entry
+= sizeof(MP_CONFIGURATION_INTLOCAL
);
1513 Count
+= sizeof(MP_CONFIGURATION_INTLOCAL
);
1517 DbgPrint("Unknown entry in MPC table\n");
1523 static VOID
HaliConstructDefaultIOIrqMPTable(ULONG Type
)
1525 MP_CONFIGURATION_INTSRC intsrc
;
1528 intsrc
.Type
= MPCTE_INTSRC
;
1529 intsrc
.IrqFlag
= 0; /* conforming */
1530 intsrc
.SrcBusId
= 0;
1531 intsrc
.DstApicId
= IOAPICMap
[0].ApicId
;
1533 intsrc
.IrqType
= INT_VECTORED
;
1534 for (i
= 0; i
< 16; i
++) {
1537 if (i
== 0 || i
== 13)
1538 continue; /* IRQ0 & IRQ13 not connected */
1542 continue; /* IRQ2 is never connected */
1545 intsrc
.SrcBusIrq
= i
;
1546 intsrc
.DstApicInt
= i
? i
: 2; /* IRQ0 to INTIN2 */
1547 HaliMPIntSrcInfo(&intsrc
);
1550 intsrc
.IrqType
= INT_EXTINT
;
1551 intsrc
.SrcBusIrq
= 0;
1552 intsrc
.DstApicInt
= 0; /* 8259A to INTIN0 */
1553 HaliMPIntSrcInfo(&intsrc
);
1556 static VOID
HaliConstructDefaultISAMPTable(ULONG Type
)
1558 MP_CONFIGURATION_PROCESSOR processor
;
1559 MP_CONFIGURATION_BUS bus
;
1560 MP_CONFIGURATION_IOAPIC ioapic
;
1561 MP_CONFIGURATION_INTLOCAL lintsrc
;
1562 ULONG linttypes
[2] = { INT_EXTINT
, INT_NMI
};
1566 * 2 CPUs, numbered 0 & 1.
1568 processor
.Type
= MPCTE_PROCESSOR
;
1569 /* Either an integrated APIC or a discrete 82489DX. */
1570 processor
.ApicVersion
= Type
> 4 ? 0x10 : 0x01;
1571 processor
.CpuFlags
= CPU_FLAG_ENABLED
| CPU_FLAG_BSP
;
1572 /* FIXME: Get this from the bootstrap processor */
1573 processor
.CpuSignature
= 0;
1574 processor
.FeatureFlags
= 0;
1575 processor
.Reserved
[0] = 0;
1576 processor
.Reserved
[1] = 0;
1577 for (i
= 0; i
< 2; i
++)
1579 processor
.ApicId
= i
;
1580 HaliMPProcessorInfo(&processor
);
1581 processor
.CpuFlags
&= ~CPU_FLAG_BSP
;
1584 bus
.Type
= MPCTE_BUS
;
1589 DPRINT("Unknown standard configuration %d\n", Type
);
1593 memcpy(bus
.BusType
, "ISA ", 6);
1598 memcpy(bus
.BusType
, "EISA ", 6);
1602 memcpy(bus
.BusType
, "MCA ", 6);
1604 HaliMPBusInfo(&bus
);
1607 bus
.Type
= MPCTE_BUS
;
1609 memcpy(bus
.BusType
, "PCI ", 6);
1610 HaliMPBusInfo(&bus
);
1613 ioapic
.Type
= MPCTE_IOAPIC
;
1615 ioapic
.ApicVersion
= Type
> 4 ? 0x10 : 0x01;
1616 ioapic
.ApicFlags
= MP_IOAPIC_USABLE
;
1617 ioapic
.ApicAddress
= IOAPIC_DEFAULT_BASE
;
1618 HaliMPIOApicInfo(&ioapic
);
1621 * We set up most of the low 16 IO-APIC pins according to MPS rules.
1623 HaliConstructDefaultIOIrqMPTable(Type
);
1625 lintsrc
.Type
= MPCTE_LINTSRC
;
1626 lintsrc
.IrqType
= 0;
1627 lintsrc
.IrqFlag
= 0; /* conforming */
1628 lintsrc
.SrcBusId
= 0;
1629 lintsrc
.SrcBusIrq
= 0;
1630 lintsrc
.DstApicId
= MP_APIC_ALL
;
1631 for (i
= 0; i
< 2; i
++)
1633 lintsrc
.IrqType
= linttypes
[i
];
1634 lintsrc
.DstApicLInt
= i
;
1635 HaliMPIntLocalInfo(&lintsrc
);
1641 HaliScanForMPConfigTable(ULONG Base
,
1645 Base = Base address of region
1646 Size = Length of region to check
1648 TRUE if a valid MP configuration table was found
1651 PULONG bp
= (PULONG
)Base
;
1652 MP_FLOATING_POINTER
* mpf
;
1656 if (*bp
== MPF_SIGNATURE
)
1658 DbgPrint("Found MPF signature at %x, checksum %x\n", bp
,
1659 MPChecksum((PUCHAR
)bp
, 16));
1660 if (MPChecksum((PUCHAR
)bp
, 16) == 0)
1662 mpf
= (MP_FLOATING_POINTER
*)bp
;
1664 DbgPrint("Intel MultiProcessor Specification v1.%d compliant system.\n",
1665 mpf
->Specification
);
1667 if (mpf
->Feature2
& FEATURE2_IMCRP
) {
1669 DPRINT("Running in IMCR and PIC compatibility mode.\n");
1672 DPRINT("Running in Virtual Wire compatibility mode.\n");
1675 switch (mpf
->Feature1
)
1678 /* Non standard configuration */
1684 DPRINT("EISA with no IRQ8 chaining\n");
1693 DPRINT("ISA and PCI\n");
1696 DPRINT("EISA and PCI\n");
1699 DPRINT("MCA and PCI\n");
1702 DbgPrint("Unknown standard configuration %d\n", mpf
->Feature1
);
1710 if ((mpf
->Feature1
== 0) && (mpf
->Address
)) {
1711 HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE
)mpf
->Address
);
1713 HaliConstructDefaultISAMPTable(mpf
->Feature1
);
1729 static BOOLEAN MPSInitialized
= FALSE
;
1732 /* Only initialize MP system once. Once called the first time,
1733 each subsequent call is part of the initialization sequence
1734 for an application processor. */
1736 DPRINT("HalpInitMPS()\n");
1744 MPSInitialized
= TRUE
;
1747 Scan the system memory for an MP configuration table
1748 1) Scan the first KB of system base memory
1749 2) Scan the last KB of system base memory
1750 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh
1751 4) Scan the Extended BIOS Data Area
1754 if (!HaliScanForMPConfigTable(0x0, 0x400))
1756 if (!HaliScanForMPConfigTable(0x9FC00, 0x400))
1758 if (!HaliScanForMPConfigTable(0xF0000, 0x10000))
1760 EBDA
= *((PUSHORT
)0x040E);
1762 if (!HaliScanForMPConfigTable((ULONG
)EBDA
, 0x1000))
1764 DbgPrint("No multiprocessor compliant system found.\n");
1771 /* Setup IRQ to vector translation map */
1772 memset(&IRQVectorMap
, 0, sizeof(IRQVectorMap
));
1774 /* Setup interrupt handlers */
1775 SetInterruptGate(LOCAL_TIMER_VECTOR
, (ULONG
)MpsTimerInterrupt
);
1776 SetInterruptGate(ERROR_VECTOR
, (ULONG
)MpsErrorInterrupt
);
1777 SetInterruptGate(SPURIOUS_VECTOR
, (ULONG
)MpsSpuriousInterrupt
);
1778 SetInterruptGate(IPI_VECTOR
, (ULONG
)MpsIpiInterrupt
);
1783 HaliReconfigurePciInterrupts(VOID
)
1787 for (i
= 0; i
< IRQCount
; i
++)
1789 if (BUSMap
[IRQMap
[i
].SrcBusId
] == MP_BUS_PCI
)
1791 DPRINT("%02x: IrqType %02x, IrqFlag %02x, SrcBusId %02x, SrcBusIrq %02x, DstApicId %02x, DstApicInt %02x\n",
1792 i
, IRQMap
[i
].IrqType
, IRQMap
[i
].IrqFlag
, IRQMap
[i
].SrcBusId
,
1793 IRQMap
[i
].SrcBusIrq
, IRQMap
[i
].DstApicId
, IRQMap
[i
].DstApicInt
);
1795 if(1 != HalSetBusDataByOffset(PCIConfiguration
, IRQMap
[i
].SrcBusId
, (IRQMap
[i
].SrcBusIrq
>> 2) & 0x1f, &IRQMap
[i
].DstApicInt
, 0x3c /*PCI_INTERRUPT_LINE*/, 1))