diff --git a/reactos/hal/halx86/generic/timer.c b/reactos/hal/halx86/generic/timer.c index 78a2a3d6554..4f41d35980e 100644 --- a/reactos/hal/halx86/generic/timer.c +++ b/reactos/hal/halx86/generic/timer.c @@ -165,7 +165,7 @@ static ULONG Read8254Timer(VOID) } -static VOID WaitFor8254Wraparound(VOID) +VOID WaitFor8254Wraparound(VOID) { ULONG CurCount, PrevCount = ~0; LONG Delta; diff --git a/reactos/hal/halx86/include/apic.h b/reactos/hal/halx86/include/apic.h index 89bba37b58d..b60d4df3153 100644 --- a/reactos/hal/halx86/include/apic.h +++ b/reactos/hal/halx86/include/apic.h @@ -145,7 +145,16 @@ #define APIC_INTEGRATED(version) (version & 0xF0) +typedef enum { + amPIC = 0, /* IMCR and PIC compatibility mode */ + amVWIRE /* Virtual Wire compatibility mode */ +} APIC_MODE; + +#ifdef CONFIG_SMP #define MAX_CPU 32 +#else +#define MAX_CPU 1 +#endif /* * Local APIC timer IRQ vector is on a different priority level, @@ -158,6 +167,11 @@ #define ERROR_VECTOR 0xFE #define SPURIOUS_VECTOR 0xFF /* Must be 0xXF */ +/* CPU flags */ +#define CPU_USABLE 0x01 /* 1 if the CPU is usable (ie. can be used) */ +#define CPU_ENABLED 0x02 /* 1 if the CPU is enabled */ +#define CPU_BSP 0x04 /* 1 if the CPU is the bootstrap processor */ +#define CPU_TSC 0x08 /* 1 if the CPU has a time stamp counter */ typedef struct _CPU_INFO { @@ -170,23 +184,26 @@ typedef struct _CPU_INFO UCHAR Padding[16-12]; /* Padding to 16-byte */ } CPU_INFO, *PCPU_INFO; +extern ULONG CPUCount; /* Total number of CPUs */ +extern ULONG BootCPU; /* Bootstrap processor */ +extern ULONG OnlineCPUs; /* Bitmask of online CPUs */ +extern CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */ /* Prototypes */ - -inline ULONG APICRead(ULONG Offset); inline VOID APICWrite(ULONG Offset, ULONG Value); +inline ULONG APICRead(ULONG Offset); VOID APICSendIPI(ULONG Target, ULONG Mode); - -ULONG APICGetMaxLVT(VOID); VOID APICSetup(VOID); VOID HaliInitBSP(VOID); VOID APICSyncArbIDs(VOID); inline VOID APICSendEOI(VOID); +VOID APICCalibrateTimer(ULONG CPU); +VOID HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack); static inline ULONG ThisCPU(VOID) { - return (APICRead(APIC_ID) & APIC_ID_MASK) >> 24; + return (APICRead(APIC_ID) & APIC_ID_MASK) >> 24; } diff --git a/reactos/hal/halx86/include/hal.h b/reactos/hal/halx86/include/hal.h index d8266191af3..87555082e4b 100644 --- a/reactos/hal/halx86/include/hal.h +++ b/reactos/hal/halx86/include/hal.h @@ -413,6 +413,8 @@ HalQueryDisplayOwnership(); #define Ki386EnableInterrupts() __asm__ __volatile__("sti\n\t") #define Ki386HaltProcessor() __asm__ __volatile__("hlt\n\t") #define Ki386RdTSC(x) __asm__ __volatile__("rdtsc\n\t" : "=A" (x.u.LowPart), "=d" (x.u.HighPart)); +#define Ki386Rdmsr(msr,val1,val2) __asm__ __volatile__("rdmsr" : "=a" (val1), "=d" (val2) : "c" (msr)) +#define Ki386Wrmsr(msr,val1,val2) __asm__ __volatile__("wrmsr" : /* no outputs */ : "c" (msr), "a" (val1), "d" (val2)) static inline BYTE Ki386ReadFsByte(ULONG offset) { diff --git a/reactos/hal/halx86/include/ioapic.h b/reactos/hal/halx86/include/ioapic.h new file mode 100644 index 00000000000..540f3411d14 --- /dev/null +++ b/reactos/hal/halx86/include/ioapic.h @@ -0,0 +1,101 @@ +/* + * + */ + +#ifndef __INTERNAL_HAL_IOAPIC_H +#define __INTERNAL_HAL_IOAPIC_H + +/* I/O APIC Register Address Map */ +#define IOAPIC_IOREGSEL 0x0000 /* I/O Register Select (index) (R/W) */ +#define IOAPIC_IOWIN 0x0010 /* I/O window (data) (R/W) */ + +#define IOAPIC_ID 0x0000 /* IO APIC ID (R/W) */ +#define IOAPIC_VER 0x0001 /* IO APIC Version (R) */ +#define IOAPIC_ARB 0x0002 /* IO APIC Arbitration ID (R) */ +#define IOAPIC_REDTBL 0x0010 /* Redirection Table (0-23 64-bit registers) (R/W) */ + +#define IOAPIC_ID_MASK (0xF << 24) +#define GET_IOAPIC_ID(x) (((x) & IOAPIC_ID_MASK) >> 24) +#define SET_IOAPIC_ID(x) ((x) << 24) + +#define IOAPIC_VER_MASK (0xFF) +#define GET_IOAPIC_VERSION(x) (((x) & IOAPIC_VER_MASK)) +#define IOAPIC_MRE_MASK (0xFF << 16) /* Maximum Redirection Entry */ +#define GET_IOAPIC_MRE(x) (((x) & IOAPIC_MRE_MASK) >> 16) + +#define IOAPIC_ARB_MASK (0xF << 24) +#define GET_IOAPIC_ARB(x) (((x) & IOAPIC_ARB_MASK) >> 24) + +#define IOAPIC_TBL_DELMOD (0x7 << 10) /* Delivery Mode (see APIC_DM_*) */ +#define IOAPIC_TBL_DM (0x1 << 11) /* Destination Mode */ +#define IOAPIC_TBL_DS (0x1 << 12) /* Delivery Status */ +#define IOAPIC_TBL_INTPOL (0x1 << 13) /* Interrupt Input Pin Polarity */ +#define IOAPIC_TBL_RIRR (0x1 << 14) /* Remote IRR */ +#define IOAPIC_TBL_TM (0x1 << 15) /* Trigger Mode */ +#define IOAPIC_TBL_IM (0x1 << 16) /* Interrupt Mask */ +#define IOAPIC_TBL_DF0 (0xF << 56) /* Destination Field (physical mode) */ +#define IOAPIC_TBL_DF1 (0xFF<< 56) /* Destination Field (logical mode) */ +#define IOAPIC_TBL_VECTOR (0xFF << 0) /* Vector (10h - FEh) */ + +typedef struct _IOAPIC_ROUTE_ENTRY { + ULONG vector : 8, + delivery_mode : 3, /* 000: FIXED + * 001: lowest priority + * 111: ExtINT + */ + dest_mode : 1, /* 0: physical, 1: logical */ + delivery_status : 1, + polarity : 1, + irr : 1, + trigger : 1, /* 0: edge, 1: level */ + mask : 1, /* 0: enabled, 1: disabled */ + __reserved_2 : 15; + + union { + struct { + ULONG __reserved_1 : 24, + physical_dest : 4, + __reserved_2 : 4; + } physical; + struct { + ULONG __reserved_1 : 24, + logical_dest : 8; + } logical; + } dest; +} __attribute__ ((packed)) IOAPIC_ROUTE_ENTRY, *PIOAPIC_ROUTE_ENTRY; + +typedef struct _IOAPIC_INFO +{ + ULONG ApicId; /* APIC ID */ + ULONG ApicVersion; /* APIC version */ + ULONG ApicAddress; /* APIC address */ + ULONG EntryCount; /* Number of redirection entries */ +} IOAPIC_INFO, *PIOAPIC_INFO; + +#define IOAPIC_DEFAULT_BASE 0xFEC00000 /* Default I/O APIC Base Register Address */ + +extern ULONG IRQCount; /* Number of IRQs */ +extern UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */ +extern UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */ +extern IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */ +extern ULONG IOAPICCount; /* Number of I/O APICs in the system */ +extern ULONG APICMode; /* APIC mode at startup */ +extern MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */ + +VOID IOAPICSetupIrqs(VOID); +VOID IOAPICEnable(VOID); +VOID IOAPICSetupIds(VOID); +VOID IOAPICMaskIrq(ULONG Irq); +VOID IOAPICUnmaskIrq(ULONG Irq); + +VOID HaliReconfigurePciInterrupts(VOID); + +/* For debugging */ +VOID IOAPICDump(VOID); + +#endif + + + +/* EOF */ + diff --git a/reactos/hal/halx86/include/mps.h b/reactos/hal/halx86/include/mps.h index f53b93580f5..b25a415df53 100644 --- a/reactos/hal/halx86/include/mps.h +++ b/reactos/hal/halx86/include/mps.h @@ -9,76 +9,6 @@ #define IRQL2TPR(irql) ((irql) >= IPI_LEVEL ? IPI_VECTOR : ((irql) >= PROFILE_LEVEL ? LOCAL_TIMER_VECTOR : ((irql) > DISPATCH_LEVEL ? IRQL2VECTOR(irql) : 0))) -#define IOAPIC_DEFAULT_BASE 0xFEC00000 /* Default I/O APIC Base Register Address */ - -/* I/O APIC Register Address Map */ -#define IOAPIC_IOREGSEL 0x0000 /* I/O Register Select (index) (R/W) */ -#define IOAPIC_IOWIN 0x0010 /* I/O window (data) (R/W) */ - -#define IOAPIC_ID 0x0000 /* IO APIC ID (R/W) */ -#define IOAPIC_VER 0x0001 /* IO APIC Version (R) */ -#define IOAPIC_ARB 0x0002 /* IO APIC Arbitration ID (R) */ -#define IOAPIC_REDTBL 0x0010 /* Redirection Table (0-23 64-bit registers) (R/W) */ - -#define IOAPIC_ID_MASK (0xF << 24) -#define GET_IOAPIC_ID(x) (((x) & IOAPIC_ID_MASK) >> 24) -#define SET_IOAPIC_ID(x) ((x) << 24) - -#define IOAPIC_VER_MASK (0xFF) -#define GET_IOAPIC_VERSION(x) (((x) & IOAPIC_VER_MASK)) -#define IOAPIC_MRE_MASK (0xFF << 16) /* Maximum Redirection Entry */ -#define GET_IOAPIC_MRE(x) (((x) & IOAPIC_MRE_MASK) >> 16) - -#define IOAPIC_ARB_MASK (0xF << 24) -#define GET_IOAPIC_ARB(x) (((x) & IOAPIC_ARB_MASK) >> 24) - -#define IOAPIC_TBL_DELMOD (0x7 << 10) /* Delivery Mode (see APIC_DM_*) */ -#define IOAPIC_TBL_DM (0x1 << 11) /* Destination Mode */ -#define IOAPIC_TBL_DS (0x1 << 12) /* Delivery Status */ -#define IOAPIC_TBL_INTPOL (0x1 << 13) /* Interrupt Input Pin Polarity */ -#define IOAPIC_TBL_RIRR (0x1 << 14) /* Remote IRR */ -#define IOAPIC_TBL_TM (0x1 << 15) /* Trigger Mode */ -#define IOAPIC_TBL_IM (0x1 << 16) /* Interrupt Mask */ -#define IOAPIC_TBL_DF0 (0xF << 56) /* Destination Field (physical mode) */ -#define IOAPIC_TBL_DF1 (0xFF<< 56) /* Destination Field (logical mode) */ -#define IOAPIC_TBL_VECTOR (0xFF << 0) /* Vector (10h - FEh) */ - -typedef struct _IOAPIC_ROUTE_ENTRY { - ULONG vector : 8, - delivery_mode : 3, /* 000: FIXED - * 001: lowest priority - * 111: ExtINT - */ - dest_mode : 1, /* 0: physical, 1: logical */ - delivery_status : 1, - polarity : 1, - irr : 1, - trigger : 1, /* 0: edge, 1: level */ - mask : 1, /* 0: enabled, 1: disabled */ - __reserved_2 : 15; - - union { struct { ULONG - __reserved_1 : 24, - physical_dest : 4, - __reserved_2 : 4; - } physical; - - struct { ULONG - __reserved_1 : 24, - logical_dest : 8; - } logical; - } dest; -} __attribute__ ((packed)) IOAPIC_ROUTE_ENTRY, *PIOAPIC_ROUTE_ENTRY; - -typedef struct _IOAPIC_INFO -{ - ULONG ApicId; /* APIC ID */ - ULONG ApicVersion; /* APIC version */ - ULONG ApicAddress; /* APIC address */ - ULONG EntryCount; /* Number of redirection entries */ -} IOAPIC_INFO, *PIOAPIC_INFO; - - #if 0 /* This values are defined in halirql.h */ @@ -148,12 +78,6 @@ typedef struct __attribute__((packed)) _MP_CONFIGURATION_PROCESSOR } __attribute__((packed)) MP_CONFIGURATION_PROCESSOR, *PMP_CONFIGURATION_PROCESSOR; -#define CPU_FLAG_ENABLED 1 /* Processor is available */ -#define CPU_FLAG_BSP 2 /* Processor is the bootstrap processor */ - -#define CPU_STEPPING_MASK 0x0F -#define CPU_MODEL_MASK 0xF0 -#define CPU_FAMILY_MASK 0xF00 typedef struct __attribute__((packed)) _MP_CONFIGURATION_BUS @@ -239,54 +163,20 @@ typedef struct __attribute__((packed)) _MP_CONFIGURATION_INTLOCAL } MP_CONFIGURATION_INTLOCAL, *PMP_CONFIGURATION_INTLOCAL; #define MP_APIC_ALL 0xFF - - -static inline VOID ReadPentiumClock(PULARGE_INTEGER Count) -{ - register ULONG nLow; - register ULONG nHigh; -#if defined(__GNUC__) - __asm__ __volatile__ ("rdtsc" : "=a" (nLow), "=d" (nHigh)); -#elif defined(_MSC_VER) - __asm rdtsc - __asm mov nLow, eax - __asm mov nHigh, edx -#else -#error Unknown compiler for inline assembler -#endif - - Count->u.LowPart = nLow; - Count->u.HighPart = nHigh; -} - - - - -/* CPU flags */ -#define CPU_USABLE 0x01 /* 1 if the CPU is usable (ie. can be used) */ -#define CPU_ENABLED 0x02 /* 1 if the CPU is enabled */ -#define CPU_BSP 0x04 /* 1 if the CPU is the bootstrap processor */ - - -typedef enum { - amPIC = 0, /* IMCR and PIC compatibility mode */ - amVWIRE /* Virtual Wire compatibility mode */ -} APIC_MODE; +#define CPU_FLAG_ENABLED 1 /* Processor is available */ +#define CPU_FLAG_BSP 2 /* Processor is the bootstrap processor */ +#define CPU_STEPPING_MASK 0x0F +#define CPU_MODEL_MASK 0xF0 +#define CPU_FAMILY_MASK 0xF00 #define PIC_IRQS 16 /* Prototypes */ VOID HalpInitMPS(VOID); -ULONG IOAPICRead(ULONG Apic, ULONG Offset); -VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value); -VOID IOAPICMaskIrq(ULONG Irq); -VOID IOAPICUnmaskIrq(ULONG Irq); -/* For debugging */ -VOID IOAPICDump(VOID); #endif /* __INCLUDE_HAL_MPS */ diff --git a/reactos/hal/halx86/mp/Makefile b/reactos/hal/halx86/mp/Makefile index 837237dfa0a..54c331e8ee3 100644 --- a/reactos/hal/halx86/mp/Makefile +++ b/reactos/hal/halx86/mp/Makefile @@ -61,7 +61,9 @@ GENERIC_OBJECTS = \ MP_OBJECTS = \ apic.o \ halinit_mp.o \ + ioapic.o \ ipi_mp.o \ + mpconfig.o \ mpsirql.o \ mpsboot.o \ mps.o \ diff --git a/reactos/hal/halx86/mp/apic.c b/reactos/hal/halx86/mp/apic.c index f87fe831e26..f6efcb40371 100644 --- a/reactos/hal/halx86/mp/apic.c +++ b/reactos/hal/halx86/mp/apic.c @@ -1,6 +1,6 @@ /* * ReactOS kernel - * Copyright (C) 2004 ReactOS Team + * Copyright (C) 2004, 2005 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +25,8 @@ * PROGRAMMER: */ +/* INCLUDE ***********************************************************************/ + #include #include @@ -36,22 +38,46 @@ #define NDEBUG #include -BOOLEAN VerifyLocalAPIC(VOID); -VOID APICCalibrateTimer(ULONG CPU); +/* GLOBALS ***********************************************************************/ -extern VOID MpsTimerInterrupt(VOID); -extern VOID MpsErrorInterrupt(VOID); -extern VOID MpsSpuriousInterrupt(VOID); -extern VOID MpsIpiInterrupt(VOID); +ULONG CPUCount; /* Total number of CPUs */ +ULONG BootCPU; /* Bootstrap processor */ +ULONG OnlineCPUs; /* Bitmask of online CPUs */ +CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */ -extern ULONG APICMode; /* APIC mode at startup */ -extern PULONG BIOSBase; /* Virtual address of BIOS data segment */ -extern PULONG CommonBase; /* Virtual address of common area */ -extern ULONG BootCPU; /* Bootstrap processor */ -extern ULONG OnlineCPUs; /* Bitmask of online CPUs */ +#ifdef CONFIG_SMP +PULONG BIOSBase; /* Virtual address of BIOS data segment */ +PULONG CommonBase; /* Virtual address of common area */ +#endif -extern CHAR *APstart, *APend; -extern VOID (*APflush)(VOID); +PULONG APICBase = (PULONG)APIC_DEFAULT_BASE; /* Virtual address of local APIC */ + +ULONG APICMode; /* APIC mode at startup */ + +/* For debugging */ +ULONG lastregr[MAX_CPU]; +ULONG lastvalr[MAX_CPU]; +ULONG lastregw[MAX_CPU]; +ULONG lastvalw[MAX_CPU]; + +#ifdef CONFIG_SMP +typedef struct __attribute__((packed)) _COMMON_AREA_INFO +{ + ULONG Stack; /* Location of AP stack */ + ULONG PageDirectory; /* Page directory for an AP */ + ULONG NtProcessStartup; /* Kernel entry point for an AP */ + ULONG PaeModeEnabled; /* PAE mode is enabled */ + ULONG Debug[16]; /* For debugging */ +} COMMON_AREA_INFO, *PCOMMON_AREA_INFO; +#endif + +CHAR *APstart, *APend; + +#define BIOS_AREA 0x0 +#define COMMON_AREA 0x2000 + +#define HZ (100) +#define APIC_DIVISOR (16) #define CMOS_READ(address) ({ \ WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \ @@ -63,19 +89,16 @@ extern VOID (*APflush)(VOID); WRITE_PORT_UCHAR((PUCHAR)0x71, value); \ }) -#define BIOS_AREA 0x0 -#define COMMON_AREA 0x2000 +extern PVOID IMPORTED MmSystemRangeStart; +/* FUNCTIONS *********************************************************************/ -extern CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */ - -PULONG APICBase = (PULONG)APIC_DEFAULT_BASE; /* Virtual address of local APIC */ - -/* For debugging */ -ULONG lastregr[MAX_CPU]; -ULONG lastvalr[MAX_CPU]; -ULONG lastregw[MAX_CPU]; -ULONG lastvalw[MAX_CPU]; +extern ULONG Read8254Timer(VOID); +extern VOID WaitFor8254Wraparound(VOID); +extern VOID MpsTimerInterrupt(VOID); +extern VOID MpsErrorInterrupt(VOID); +extern VOID MpsSpuriousInterrupt(VOID); +extern VOID MpsIpiInterrupt(VOID); ULONG APICGetMaxLVT(VOID) { @@ -152,7 +175,7 @@ VOID APICClear(VOID) } /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */ -VOID EnableSMPMode(VOID) +VOID EnableApicMode(VOID) { /* * Do not trust the local APIC being empty at bootup. @@ -203,63 +226,6 @@ VOID APICDisable(VOID) APICWrite(APIC_SIVR, tmp); } -VOID HaliInitBSP(VOID) -{ - PUSHORT ps; - static BOOLEAN BSPInitialized = FALSE; - - /* Only initialize the BSP once */ - if (BSPInitialized) - { - KEBUGCHECK(0); - return; - } - - BSPInitialized = TRUE; - - DPRINT("APIC is mapped at 0x%X\n", APICBase); - - if (VerifyLocalAPIC()) - { - DPRINT("APIC found\n"); - } - else - { - DPRINT("No APIC found\n"); - KEBUGCHECK(0); - } - - if (APICMode == amPIC) - { - EnableSMPMode(); - } - - APICSetup(); - - /* BIOS data segment */ - BIOSBase = (PULONG)BIOS_AREA; - - /* Area for communicating with the APs */ - CommonBase = (PULONG)COMMON_AREA; - - /* Copy bootstrap code to common area */ - memcpy((PVOID)((ULONG)CommonBase + PAGE_SIZE), - &APstart, - (ULONG)&APend - (ULONG)&APstart + 1); - - /* Set shutdown code */ - CMOS_WRITE(0xF, 0xA); - - /* Set warm reset vector */ - ps = (PUSHORT)((ULONG)BIOSBase + 0x467); - *ps = (COMMON_AREA + PAGE_SIZE) & 0xF; - - ps = (PUSHORT)((ULONG)BIOSBase + 0x469); - *ps = (COMMON_AREA + PAGE_SIZE) >> 4; - - /* Calibrate APIC timer */ - APICCalibrateTimer(BootCPU); -} inline ULONG _APICRead(ULONG Offset) { @@ -455,7 +421,6 @@ VOID APICDump(VOID) BOOLEAN VerifyLocalAPIC(VOID) { UINT reg0, reg1; - CHECKPOINT1; /* The version register is read-only in a real APIC */ reg0 = APICRead(APIC_VER); DPRINT1("Getting VERSION: %x\n", reg0); @@ -502,9 +467,23 @@ BOOLEAN VerifyLocalAPIC(VOID) return FALSE; } + ULONG l, h; + Ki386Rdmsr(0x1b /*MSR_IA32_APICBASE*/, l, h); + + if (!(l & /*MSR_IA32_APICBASE_ENABLE*/(1<<11))) + { + DPRINT1("Local APIC disabled by BIOS -- reenabling.\n"); + l &= ~/*MSR_IA32_APICBASE_BASE*/(1<<11); + l |= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000; + Ki386Wrmsr(0x1b/*MSR_IA32_APICBASE*/, l, h); + } + + + return TRUE; } +#ifdef CONFIG_SMP VOID APICSendIPI(ULONG Target, ULONG Mode) { ULONG tmp, i, flags; @@ -568,6 +547,7 @@ VOID APICSendIPI(ULONG Target, ULONG Mode) } Ki386RestoreFlags(flags); } +#endif VOID APICSetup(VOID) { @@ -651,7 +631,6 @@ VOID APICSetup(VOID) } APICWrite(APIC_LINT0, tmp); - /* * Only the BSP should see the LINT1 NMI signal, obviously. */ @@ -697,7 +676,7 @@ VOID APICSetup(VOID) DPRINT("ESR value after enabling vector: 0x%X\n", tmp); } } - +#ifdef CONFIG_SMP VOID APICSyncArbIDs(VOID) { ULONG i, tmp; @@ -720,6 +699,7 @@ VOID APICSyncArbIDs(VOID) DPRINT("Synchronizing Arb IDs.\n"); APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT); } +#endif VOID MpsErrorHandler(VOID) { @@ -769,12 +749,13 @@ VOID MpsSpuriousHandler(VOID) #endif } +#ifdef CONFIG_SMP VOID MpsIpiHandler(VOID) { KIRQL oldIrql; HalBeginSystemInterrupt(IPI_VECTOR, - VECTOR2IRQL(IPI_VECTOR), + IPI_LEVEL, &oldIrql); Ki386EnableInterrupts(); #if 0 @@ -791,6 +772,7 @@ VOID MpsIpiHandler(VOID) Ki386DisableInterrupts(); HalEndSystemInterrupt(oldIrql, 0); } +#endif VOID MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame, @@ -823,7 +805,7 @@ MpsTimerHandler(ULONG Vector, PKIRQ_TRAPFRAME Trapframe) static ULONG Count[MAX_CPU] = {0,}; #endif HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR, - VECTOR2IRQL(LOCAL_TIMER_VECTOR), + PROFILE_LEVEL, &oldIrql); Ki386EnableInterrupts(); @@ -850,4 +832,318 @@ MpsTimerHandler(ULONG Vector, PKIRQ_TRAPFRAME Trapframe) HalEndSystemInterrupt (oldIrql, 0); } +VOID APICSetupLVTT(ULONG ClockTicks) +{ + ULONG tmp; + + tmp = GET_APIC_VERSION(APICRead(APIC_VER)); + if (!APIC_INTEGRATED(tmp)) + { + tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;; + } + else + { + /* Periodic timer */ + tmp = APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;; + } + APICWrite(APIC_LVTT, tmp); + + tmp = APICRead(APIC_TDCR); + tmp &= ~(APIC_TDCR_1 | APIC_TIMER_BASE_DIV); + tmp |= APIC_TDCR_16; + APICWrite(APIC_TDCR, tmp); + APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR); +} + +VOID +APICCalibrateTimer(ULONG CPU) +{ + ULARGE_INTEGER t1, t2; + LONG tt1, tt2; + BOOLEAN TSCPresent; + + DPRINT("Calibrating APIC timer for CPU %d\n", CPU); + + APICSetupLVTT(1000000000); + + TSCPresent = KeGetCurrentKPCR()->PrcbData.FeatureBits & X86_FEATURE_TSC ? TRUE : FALSE; + + /* + * The timer chip counts down to zero. Let's wait + * for a wraparound to start exact measurement: + * (the current tick might have been already half done) + */ + WaitFor8254Wraparound(); + + /* + * We wrapped around just now. Let's start + */ + if (TSCPresent) + { + Ki386RdTSC(t1); + } + tt1 = APICRead(APIC_CCRT); + + WaitFor8254Wraparound(); + + + tt2 = APICRead(APIC_CCRT); + if (TSCPresent) + { + Ki386RdTSC(t2); + CPUMap[CPU].CoreSpeed = (HZ * (t2.QuadPart - t1.QuadPart)); + DPRINT("CPU clock speed is %ld.%04ld MHz.\n", + CPUMap[CPU].CoreSpeed/1000000, + CPUMap[CPU].CoreSpeed%1000000); + KeGetCurrentKPCR()->PrcbData.MHz = CPUMap[CPU].CoreSpeed/1000000; + } + + CPUMap[CPU].BusSpeed = (HZ * (long)(tt1 - tt2) * APIC_DIVISOR); + + /* Setup timer for normal operation */ +// APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns + APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 10000); // 10ms +// APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms + + DPRINT("Host bus clock speed is %ld.%04ld MHz.\n", + CPUMap[CPU].BusSpeed/1000000, + CPUMap[CPU].BusSpeed%1000000); +} + +VOID +SetInterruptGate(ULONG index, ULONG address) +{ + IDT_DESCRIPTOR *idt; + + idt = (IDT_DESCRIPTOR*)((ULONG)KeGetCurrentKPCR()->IDT + index * sizeof(IDT_DESCRIPTOR)); + idt->a = (((ULONG)address)&0xffff) + (KERNEL_CS << 16); + idt->b = 0x8e00 + (((ULONG)address)&0xffff0000); +} + +VOID HaliInitBSP(VOID) +{ +#ifdef CONFIG_SMP + PUSHORT ps; +#endif + + static BOOLEAN BSPInitialized = FALSE; + + /* Only initialize the BSP once */ + if (BSPInitialized) + { + KEBUGCHECK(0); + return; + } + + BSPInitialized = TRUE; + + /* Setup interrupt handlers */ + SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG)MpsTimerInterrupt); + SetInterruptGate(ERROR_VECTOR, (ULONG)MpsErrorInterrupt); + SetInterruptGate(SPURIOUS_VECTOR, (ULONG)MpsSpuriousInterrupt); +#ifdef CONFIG_SMP + SetInterruptGate(IPI_VECTOR, (ULONG)MpsIpiInterrupt); +#endif + DPRINT("APIC is mapped at 0x%X\n", APICBase); + + if (VerifyLocalAPIC()) + { + DPRINT("APIC found\n"); + } + else + { + DPRINT("No APIC found\n"); + KEBUGCHECK(0); + } + + if (APICMode == amPIC) + { + EnableApicMode(); + } + + APICSetup(); + +#ifdef CONFIG_SMP + /* BIOS data segment */ + BIOSBase = (PULONG)BIOS_AREA; + + /* Area for communicating with the APs */ + CommonBase = (PULONG)COMMON_AREA; + + /* Copy bootstrap code to common area */ + memcpy((PVOID)((ULONG)CommonBase + PAGE_SIZE), + &APstart, + (ULONG)&APend - (ULONG)&APstart + 1); + + /* Set shutdown code */ + CMOS_WRITE(0xF, 0xA); + + /* Set warm reset vector */ + ps = (PUSHORT)((ULONG)BIOSBase + 0x467); + *ps = (COMMON_AREA + PAGE_SIZE) & 0xF; + + ps = (PUSHORT)((ULONG)BIOSBase + 0x469); + *ps = (COMMON_AREA + PAGE_SIZE) >> 4; +#endif + + /* Calibrate APIC timer */ + APICCalibrateTimer(BootCPU); +} + +#ifdef CONFIG_SMP +VOID +HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack) +{ + ULONG tmp, maxlvt; + PCOMMON_AREA_INFO Common; + ULONG StartupCount; + ULONG i, j; + ULONG DeliveryStatus = 0; + ULONG AcceptStatus = 0; + + if (Cpu >= MAX_CPU || + Cpu >= CPUCount || + OnlineCPUs & (1 << Cpu)) + { + KEBUGCHECK(0); + } + DPRINT1("Attempting to boot CPU %d\n", Cpu); + + /* Send INIT IPI */ + + APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_ASSERT); + + KeStallExecutionProcessor(200); + + /* Deassert INIT */ + + APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_DEASSERT); + + if (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) + { + /* Clear APIC errors */ + APICWrite(APIC_ESR, 0); + tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK); + } + + Common = (PCOMMON_AREA_INFO)CommonBase; + + /* Write the location of the AP stack */ + Common->Stack = (ULONG)Stack; + /* Write the page directory page */ + Ke386GetPageTableDirectory(Common->PageDirectory); + /* Write the kernel entry point */ + Common->NtProcessStartup = (ULONG_PTR)RtlImageNtHeader(MmSystemRangeStart)->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)MmSystemRangeStart; + /* Write the state of the mae mode */ + Common->PaeModeEnabled = Ke386GetCr4() & X86_CR4_PAE ? 1 : 0; + + DPRINT1("%x %x %x %x\n", Common->Stack, Common->PageDirectory, Common->NtProcessStartup, Common->PaeModeEnabled); + + DPRINT("Cpu %d got stack at 0x%X\n", Cpu, Common->Stack); +#if 0 + for (j = 0; j < 16; j++) + { + Common->Debug[j] = 0; + } +#endif + + maxlvt = APICGetMaxLVT(); + + /* Is this a local APIC or an 82489DX? */ + StartupCount = (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) ? 2 : 0; + + for (i = 1; i <= StartupCount; i++) + { + /* It's a local APIC, so send STARTUP IPI */ + DPRINT("Sending startup signal %d\n", i); + /* Clear errors */ + APICWrite(APIC_ESR, 0); + APICRead(APIC_ESR); + + APICSendIPI(Cpu, APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12)|APIC_ICR0_LEVEL_DEASSERT); + + /* Wait up to 10ms for IPI to be delivered */ + j = 0; + do + { + KeStallExecutionProcessor(10); + + /* Check Delivery Status */ + DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS; + + j++; + } while ((DeliveryStatus) && (j < 1000)); + + KeStallExecutionProcessor(200); + + /* + * Due to the Pentium erratum 3AP. + */ + if (maxlvt > 3) + { + APICRead(APIC_SIVR); + APICWrite(APIC_ESR, 0); + } + + AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK; + + if (DeliveryStatus || AcceptStatus) + { + break; + } + } + + if (DeliveryStatus) + { + DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu); + } + + if (AcceptStatus) + { + DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu); + } + + if (!(DeliveryStatus || AcceptStatus)) + { + + /* Wait no more than 5 seconds for processor to boot */ + DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu); + + /* Wait no more than 5 seconds */ + for (j = 0; j < 50000; j++) + { + if (CPUMap[Cpu].Flags & CPU_ENABLED) + { + break; + } + KeStallExecutionProcessor(100); + } + } + + if (CPUMap[Cpu].Flags & CPU_ENABLED) + { + DbgPrint("CPU %d is now running\n", Cpu); + } + else + { + DbgPrint("Initialization of CPU %d failed\n", Cpu); + } + +#if 0 + DPRINT("Debug bytes are:\n"); + + for (j = 0; j < 4; j++) + { + DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n", + Common->Debug[j*4+0], + Common->Debug[j*4+1], + Common->Debug[j*4+2], + Common->Debug[j*4+3]); + } + +#endif +} + +#endif + /* EOF */ diff --git a/reactos/hal/halx86/mp/halinit_mp.c b/reactos/hal/halx86/mp/halinit_mp.c index 92c0b054d71..0501f5decea 100644 --- a/reactos/hal/halx86/mp/halinit_mp.c +++ b/reactos/hal/halx86/mp/halinit_mp.c @@ -20,10 +20,34 @@ /* FUNCTIONS ***************************************************************/ +extern BOOLEAN HaliFindSmpConfig(VOID); + +/***************************************************************************/ VOID HalpInitPhase0(VOID) + { - HalpInitMPS(); + static BOOLEAN MPSInitialized = FALSE; + + + /* Only initialize MP system once. Once called the first time, + each subsequent call is part of the initialization sequence + for an application processor. */ + + DPRINT("HalpInitPhase0()\n"); + + + if (MPSInitialized) + { + KEBUGCHECK(0); + } + + MPSInitialized = TRUE; + + if (!HaliFindSmpConfig()) + { + KEBUGCHECK(0); + } } /* EOF */ diff --git a/reactos/hal/halx86/mp/ioapic.c b/reactos/hal/halx86/mp/ioapic.c new file mode 100644 index 00000000000..9b0a6241ba3 --- /dev/null +++ b/reactos/hal/halx86/mp/ioapic.c @@ -0,0 +1,712 @@ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/generic/ioapic.c + * PURPOSE: + * PROGRAMMER: + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define NDEBUG +#include + +/* GLOBALS *****************************************************************/ + +MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */ +ULONG IRQCount = 0; /* Number of IRQs */ +ULONG IrqApicMap[MAX_IRQ_SOURCE]; + +UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */ +UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */ + +IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */ +ULONG IOAPICCount; /* Number of I/O APICs in the system */ + +ULONG IRQVectorMap[MAX_IRQ_SOURCE]; /* IRQ to vector map */ + +/* EISA interrupts are always polarity zero and can be edge or level + * trigger depending on the ELCR value. If an interrupt is listed as + * EISA conforming in the MP table, that means its trigger type must + * be read in from the ELCR */ + +#define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq)) +#define default_EISA_polarity(idx) (0) + +/* ISA interrupts are always polarity zero edge triggered, + * when listed as conforming in the MP table. */ + +#define default_ISA_trigger(idx) (0) +#define default_ISA_polarity(idx) (0) + +/* PCI interrupts are always polarity one level triggered, + * when listed as conforming in the MP table. */ + +#define default_PCI_trigger(idx) (1) +#define default_PCI_polarity(idx) (1) + +/* MCA interrupts are always polarity zero level triggered, + * when listed as conforming in the MP table. */ + +#define default_MCA_trigger(idx) (1) +#define default_MCA_polarity(idx) (0) + +/***************************************************************************/ + +extern VOID Disable8259AIrq(ULONG irq); +ULONG IOAPICRead(ULONG Apic, ULONG Offset); +VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value); + +/* FUNCTIONS ***************************************************************/ + +/* + * EISA Edge/Level control register, ELCR + */ +static ULONG EISA_ELCR(ULONG irq) +{ + if (irq < 16) + { + PUCHAR port = (PUCHAR)(0x4d0 + (irq >> 3)); + return (READ_PORT_UCHAR(port) >> (irq & 7)) & 1; + } + DPRINT("Broken MPtable reports ISA irq %d\n", irq); + return 0; +} + +static ULONG +IRQPolarity(ULONG idx) +{ + ULONG bus = IRQMap[idx].SrcBusId; + ULONG polarity; + + /* + * Determine IRQ line polarity (high active or low active): + */ + switch (IRQMap[idx].IrqFlag & 3) + { + case 0: /* conforms, ie. bus-type dependent polarity */ + { + switch (BUSMap[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + polarity = default_ISA_polarity(idx); + break; + + case MP_BUS_EISA: /* EISA pin */ + polarity = default_EISA_polarity(idx); + break; + + case MP_BUS_PCI: /* PCI pin */ + polarity = default_PCI_polarity(idx); + break; + + case MP_BUS_MCA: /* MCA pin */ + polarity = default_MCA_polarity(idx); + break; + + default: + DPRINT("Broken BIOS!!\n"); + polarity = 1; + } + } + break; + + case 1: /* high active */ + polarity = 0; + break; + + case 2: /* reserved */ + DPRINT("Broken BIOS!!\n"); + polarity = 1; + break; + + case 3: /* low active */ + polarity = 1; + break; + + default: /* invalid */ + DPRINT("Broken BIOS!!\n"); + polarity = 1; + } + return polarity; +} + +static ULONG +IRQTrigger(ULONG idx) +{ + ULONG bus = IRQMap[idx].SrcBusId; + ULONG trigger; + + /* + * Determine IRQ trigger mode (edge or level sensitive): + */ + switch ((IRQMap[idx].IrqFlag >> 2) & 3) + { + case 0: /* conforms, ie. bus-type dependent */ + { + switch (BUSMap[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + trigger = default_ISA_trigger(idx); + break; + + case MP_BUS_EISA: /* EISA pin */ + trigger = default_EISA_trigger(idx); + break; + + case MP_BUS_PCI: /* PCI pin */ + trigger = default_PCI_trigger(idx); + break; + + case MP_BUS_MCA: /* MCA pin */ + trigger = default_MCA_trigger(idx); + break; + + default: + DPRINT("Broken BIOS!!\n"); + trigger = 1; + } + } + break; + + case 1: /* edge */ + trigger = 0; + break; + + case 2: /* reserved */ + DPRINT("Broken BIOS!!\n"); + trigger = 1; + break; + + case 3: /* level */ + trigger = 1; + break; + + default: /* invalid */ + DPRINT("Broken BIOS!!\n"); + trigger = 0; + } + return trigger; +} + +static ULONG +Pin2Irq(ULONG idx, + ULONG apic, + ULONG pin) +{ + ULONG irq, i; + ULONG bus = IRQMap[idx].SrcBusId; + + /* + * Debugging check, we are in big trouble if this message pops up! + */ + if (IRQMap[idx].DstApicInt != pin) + { + DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n"); + } + + switch (BUSMap[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + case MP_BUS_EISA: + case MP_BUS_MCA: + irq = IRQMap[idx].SrcBusIrq; + break; + + case MP_BUS_PCI: /* PCI pin */ + /* + * PCI IRQs are mapped in order + */ + i = irq = 0; + while (i < apic) + { + irq += IOAPICMap[i++].EntryCount; + } + irq += pin; + break; + + default: + DPRINT("Unknown bus type %d.\n",bus); + irq = 0; + } + return irq; +} + +static ULONG +AssignIrqVector(ULONG irq) +{ +#if 0 + static ULONG current_vector = FIRST_DEVICE_VECTOR, vector_offset = 0; +#endif + ULONG vector; + /* There may already have been assigned a vector for this IRQ */ + vector = IRQVectorMap[irq]; + if (vector > 0) + { + return vector; + } +#if 0 + if (current_vector > FIRST_SYSTEM_VECTOR) + { + vector_offset++; + current_vector = FIRST_DEVICE_VECTOR + vector_offset; + } + else if (current_vector == FIRST_SYSTEM_VECTOR) + { + DPRINT1("Ran out of interrupt sources!"); + KEBUGCHECK(0); + } + + vector = current_vector; + IRQVectorMap[irq] = vector; + current_vector += 8; + return vector; +#else + vector = IRQ2VECTOR(irq); + IRQVectorMap[irq] = vector; + return vector; +#endif +} + +/* + * Find the IRQ entry number of a certain pin. + */ +static ULONG +IOAPICGetIrqEntry(ULONG apic, + ULONG pin, + ULONG type) +{ + ULONG i; + + for (i = 0; i < IRQCount; i++) + { + if (IRQMap[i].IrqType == type && + (IRQMap[i].DstApicId == IOAPICMap[apic].ApicId || IRQMap[i].DstApicId == MP_APIC_ALL) && + IRQMap[i].DstApicInt == pin) + { + return i; + } + } + return -1; +} + + +VOID +IOAPICSetupIrqs(VOID) +{ + IOAPIC_ROUTE_ENTRY entry; + ULONG apic, pin, idx, irq, first_notcon = 1, vector, trigger; + + DPRINT("Init IO_APIC IRQs\n"); + + /* Setup IRQ to vector translation map */ + memset(&IRQVectorMap, 0, sizeof(IRQVectorMap)); + + for (apic = 0; apic < IOAPICCount; apic++) + { + for (pin = 0; pin < IOAPICMap[apic].EntryCount; pin++) + { + /* + * add it to the IO-APIC irq-routing table + */ + memset(&entry,0,sizeof(entry)); + + entry.delivery_mode = (APIC_DM_LOWEST >> 8); + entry.dest_mode = 1; /* logical delivery */ + entry.mask = 1; /* disable IRQ */ + entry.dest.logical.logical_dest = 0; + + idx = IOAPICGetIrqEntry(apic,pin,INT_VECTORED); + if (idx == -1) + { + if (first_notcon) + { + DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap[apic].ApicId, pin); + first_notcon = 0; + } + else + { + DPRINT(", %d-%d\n", IOAPICMap[apic].ApicId, pin); + } + continue; + } + + trigger = IRQTrigger(idx); + entry.polarity = IRQPolarity(idx); + + if (trigger) + { + entry.trigger = 1; + } + + irq = Pin2Irq(idx, apic, pin); + + vector = AssignIrqVector(irq); + entry.vector = vector; + + DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector, irq); + + if (irq == 0) + { + /* Mask timer IRQ */ + entry.mask = 1; + } + + if ((apic == 0) && (irq < 16)) + { + Disable8259AIrq(irq); + } + IOAPICWrite(apic, IOAPIC_REDTBL+2*pin+1, *(((PULONG)&entry)+1)); + IOAPICWrite(apic, IOAPIC_REDTBL+2*pin, *(((PULONG)&entry)+0)); + + IrqApicMap[irq] = apic; + + DPRINT("Vector %x, Pin %x, Irq %x\n", vector, pin, irq); + } + } +} + +static VOID +IOAPICClearPin(ULONG Apic, ULONG Pin) +{ + IOAPIC_ROUTE_ENTRY Entry; + + DPRINT("IOAPICClearPin(Apic %d, Pin %d\n", Apic, Pin); + /* + * Disable it in the IO-APIC irq-routing table + */ + memset(&Entry, 0, sizeof(Entry)); + Entry.mask = 1; + + IOAPICWrite(Apic, IOAPIC_REDTBL + 2 * Pin, *(((PULONG)&Entry) + 0)); + IOAPICWrite(Apic, IOAPIC_REDTBL + 1 + 2 * Pin, *(((PULONG)&Entry) + 1)); +} + +static VOID +IOAPICClear(ULONG Apic) +{ + ULONG Pin; + + for (Pin = 0; Pin < /*IOAPICMap[Apic].EntryCount*/24; Pin++) + { + IOAPICClearPin(Apic, Pin); + } +} + +static VOID +IOAPICClearAll(VOID) +{ + ULONG Apic; + + for (Apic = 0; Apic < IOAPICCount; Apic++) + { + IOAPICClear(Apic); + } +} + +VOID +IOAPICEnable(VOID) +{ + ULONG i, tmp; + + /* Setup IRQ to vector translation map */ + memset(&IRQVectorMap, 0, sizeof(IRQVectorMap)); + + /* + * The number of IO-APIC IRQ registers (== #pins): + */ + for (i = 0; i < IOAPICCount; i++) + { + tmp = IOAPICRead(i, IOAPIC_VER); + IOAPICMap[i].EntryCount = GET_IOAPIC_MRE(tmp) + 1; + } + + /* + * Do not trust the IO-APIC being empty at bootup + */ + IOAPICClearAll(); +} + +VOID +IOAPICSetupIds(VOID) +{ + ULONG tmp, apic, i; + UCHAR old_id; + + /* + * Set the IOAPIC ID to the value stored in the MPC table. + */ + for (apic = 0; apic < IOAPICCount; apic++) + { + + /* Read the register 0 value */ + tmp = IOAPICRead(apic, IOAPIC_ID); + + old_id = IOAPICMap[apic].ApicId; + + if (IOAPICMap[apic].ApicId >= 0xf) + { + DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", + apic, IOAPICMap[apic].ApicId); + DPRINT1("... fixing up to %d. (tell your hw vendor)\n", + GET_IOAPIC_ID(tmp)); + IOAPICMap[apic].ApicId = GET_IOAPIC_ID(tmp); + } + + /* + * We need to adjust the IRQ routing table + * if the ID changed. + */ + if (old_id != IOAPICMap[apic].ApicId) + { + for (i = 0; i < IRQCount; i++) + { + if (IRQMap[i].DstApicId == old_id) + { + IRQMap[i].DstApicId = IOAPICMap[apic].ApicId; + } + } + } + + /* + * Read the right value from the MPC table and + * write it into the ID register. + */ + DPRINT("Changing IO-APIC physical APIC ID to %d\n", + IOAPICMap[apic].ApicId); + + tmp &= ~IOAPIC_ID_MASK; + tmp |= SET_IOAPIC_ID(IOAPICMap[apic].ApicId); + + IOAPICWrite(apic, IOAPIC_ID, tmp); + + /* + * Sanity check + */ + tmp = IOAPICRead(apic, 0); + if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId) + { + DPRINT1("Could not set I/O APIC ID!\n"); + KEBUGCHECK(0); + } + } +} + +/* This is performance critical and should probably be done in assembler */ +VOID IOAPICMaskIrq(ULONG Irq) +{ + IOAPIC_ROUTE_ENTRY Entry; + ULONG Apic = IrqApicMap[Irq]; + + *(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq); + *(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1); + Entry.dest.logical.logical_dest &= ~(1 << KeGetCurrentProcessorNumber()); + if (Entry.dest.logical.logical_dest == 0) + { + Entry.mask = 1; + } + IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1)); + IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0)); +} + +/* This is performance critical and should probably be done in assembler */ +VOID IOAPICUnmaskIrq(ULONG Irq) +{ + IOAPIC_ROUTE_ENTRY Entry; + ULONG Apic = IrqApicMap[Irq]; + + *(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq); + *(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1); + Entry.dest.logical.logical_dest |= 1 << KeGetCurrentProcessorNumber(); + Entry.mask = 0; + IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1)); + IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0)); +} + +VOID IOAPICDump(VOID) +{ + ULONG apic, i; + ULONG reg0, reg1, reg2=0; + + DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount); + for (i = 0; i < IOAPICCount; i++) + { + DbgPrint("Number of IO-APIC #%d registers: %d.\n", + IOAPICMap[i].ApicId, + IOAPICMap[i].EntryCount); + } + + /* + * We are a bit conservative about what we expect. We have to + * know about every hardware change ASAP. + */ + DbgPrint("Testing the IO APIC.......................\n"); + + for (apic = 0; apic < IOAPICCount; apic++) + { + reg0 = IOAPICRead(apic, IOAPIC_ID); + reg1 = IOAPICRead(apic, IOAPIC_VER); + if (GET_IOAPIC_VERSION(reg1) >= 0x10) + { + reg2 = IOAPICRead(apic, IOAPIC_ARB); + } + + DbgPrint("\n"); + DbgPrint("IO APIC #%d......\n", IOAPICMap[apic].ApicId); + DbgPrint(".... register #00: %08X\n", reg0); + DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0)); + if (reg0 & 0xF0FFFFFF) + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + + DbgPrint(".... register #01: %08X\n", reg1); + i = GET_IOAPIC_MRE(reg1); + + DbgPrint("....... : max redirection entries: %04X\n", i); + if ((i != 0x0f) && /* older (Neptune) boards */ + (i != 0x17) && /* typical ISA+PCI boards */ + (i != 0x1b) && /* Compaq Proliant boards */ + (i != 0x1f) && /* dual Xeon boards */ + (i != 0x22) && /* bigger Xeon boards */ + (i != 0x2E) && + (i != 0x3F)) + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + + i = GET_IOAPIC_VERSION(reg1); + DbgPrint("....... : IO APIC version: %04X\n", i); + if ((i != 0x01) && /* 82489DX IO-APICs */ + (i != 0x10) && /* oldest IO-APICs */ + (i != 0x11) && /* Pentium/Pro IO-APICs */ + (i != 0x13)) /* Xeon IO-APICs */ + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + + if (reg1 & 0xFF00FF00) + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + + if (GET_IOAPIC_VERSION(reg1) >= 0x10) + { + DbgPrint(".... register #02: %08X\n", reg2); + DbgPrint("....... : arbitration: %02X\n", + GET_IOAPIC_ARB(reg2)); + if (reg2 & 0xF0FFFFFF) + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + } + + DbgPrint(".... IRQ redirection table:\n"); + DbgPrint(" NR Log Phy Mask Trig IRR Pol" + " Stat Dest Deli Vect: \n"); + + for (i = 0; i <= GET_IOAPIC_MRE(reg1); i++) + { + IOAPIC_ROUTE_ENTRY entry; + + *(((PULONG)&entry)+0) = IOAPICRead(apic, 0x10+i*2); + *(((PULONG)&entry)+1) = IOAPICRead(apic, 0x11+i*2); + + DbgPrint(" %02x %03X %02X ", + i, + entry.dest.logical.logical_dest, + entry.dest.physical.physical_dest); + + DbgPrint("%C %C %1d %C %C %C %03X %02X\n", + (entry.mask == 0) ? 'U' : 'M', // Unmasked/masked + (entry.trigger == 0) ? 'E' : 'L', // Edge/level sensitive + entry.irr, + (entry.polarity == 0) ? 'H' : 'L', // Active high/active low + (entry.delivery_status == 0) ? 'I' : 'S', // Idle / send pending + (entry.dest_mode == 0) ? 'P' : 'L', // Physical logical + entry.delivery_mode, + entry.vector); + } + } + + DbgPrint(".................................... done.\n"); +} + +VOID +HaliReconfigurePciInterrupts(VOID) +{ + ULONG i; + + for (i = 0; i < IRQCount; i++) + { + if (BUSMap[IRQMap[i].SrcBusId] == MP_BUS_PCI) + { + DPRINT("%02x: IrqType %02x, IrqFlag %02x, SrcBusId %02x, SrcBusIrq %02x" + ", DstApicId %02x, DstApicInt %02x\n", + i, IRQMap[i].IrqType, IRQMap[i].IrqFlag, IRQMap[i].SrcBusId, + IRQMap[i].SrcBusIrq, IRQMap[i].DstApicId, IRQMap[i].DstApicInt); + + if(1 != HalSetBusDataByOffset(PCIConfiguration, + IRQMap[i].SrcBusId, + (IRQMap[i].SrcBusIrq >> 2) & 0x1f, + &IRQMap[i].DstApicInt, + 0x3c /*PCI_INTERRUPT_LINE*/, + 1)) + { + CHECKPOINT; + } + } + } +} + +VOID Disable8259AIrq(ULONG irq) +{ + ULONG tmp; + + if (irq >= 8) + { + tmp = READ_PORT_UCHAR((PUCHAR)0xA1); + tmp |= (1 << (irq - 8)); + WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp); + } + else + { + tmp = READ_PORT_UCHAR((PUCHAR)0x21); + tmp |= (1 << irq); + WRITE_PORT_UCHAR((PUCHAR)0x21, tmp); + } +} + +ULONG IOAPICRead(ULONG Apic, ULONG Offset) +{ + PULONG Base; + + Base = (PULONG)IOAPICMap[Apic].ApicAddress; + *Base = Offset; + return *((PULONG)((ULONG)Base + IOAPIC_IOWIN)); +} + +VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value) +{ + PULONG Base; + + Base = (PULONG)IOAPICMap[Apic].ApicAddress; + *Base = Offset; + *((PULONG)((ULONG)Base + IOAPIC_IOWIN)) = Value; +} + +/* EOF */ diff --git a/reactos/hal/halx86/mp/mpconfig.c b/reactos/hal/halx86/mp/mpconfig.c new file mode 100644 index 00000000000..e624887843c --- /dev/null +++ b/reactos/hal/halx86/mp/mpconfig.c @@ -0,0 +1,649 @@ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/generic/mpconfig.c + * PURPOSE: + * PROGRAMMER: + */ + +/* INCLUDES *****************************************************************/ + +#include +#include +#include +#include +#include +#include + +//#define NDEBUG +#include + +/* GLOBALS ******************************************************************/ + +MP_FLOATING_POINTER* Mpf = NULL; + +/* FUNCTIONS ****************************************************************/ + +static UCHAR +MPChecksum(PUCHAR Base, + ULONG Size) +/* + * Checksum an MP configuration block + */ +{ + UCHAR Sum = 0; + + while (Size--) + Sum += *Base++; + + return Sum; +} + +static VOID +HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m) +{ + DPRINT("Int: type %d, pol %d, trig %d, bus %d," + " IRQ %02x, APIC ID %x, APIC INT %02x\n", + m->IrqType, m->IrqFlag & 3, + (m->IrqFlag >> 2) & 3, m->SrcBusId, + m->SrcBusIrq, m->DstApicId, m->DstApicInt); + if (IRQCount > MAX_IRQ_SOURCE) + { + DPRINT1("Max # of irq sources exceeded!!\n"); + KEBUGCHECK(0); + } + + IRQMap[IRQCount] = *m; + IRQCount++; +} + +static PCHAR +HaliMPFamily(ULONG Family, + ULONG Model) +{ + static CHAR str[64]; + static PCHAR CPUs[] = + { + "80486DX", "80486DX", + "80486SX", "80486DX/2 or 80487", + "80486SL", "Intel5X2(tm)", + "Unknown", "Unknown", + "80486DX/4" + }; + if (Family == 0x6) + return ("Pentium(tm) Pro"); + if (Family == 0x5) + return ("Pentium(tm)"); + if (Family == 0x0F && Model == 0x0F) + return("Special controller"); + if (Family == 0x0F && Model == 0x00) + return("Pentium 4(tm)"); + if (Family == 0x04 && Model < 9) + return CPUs[Model]; + sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model); + return str; +} + + +static VOID +HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m) +{ + ULONG ver; + + if (!(m->CpuFlags & CPU_FLAG_ENABLED)) + return; + + DPRINT("Processor #%d %s APIC version %d\n", + m->ApicId, + HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8, + (m->FeatureFlags & CPU_MODEL_MASK) >> 4), + m->ApicVersion); + + if (m->FeatureFlags & (1 << 0)) + DPRINT(" Floating point unit present.\n"); + if (m->FeatureFlags & (1 << 7)) + DPRINT(" Machine Exception supported.\n"); + if (m->FeatureFlags & (1 << 8)) + DPRINT(" 64 bit compare & exchange supported.\n"); + if (m->FeatureFlags & (1 << 9)) + DPRINT(" Internal APIC present.\n"); + if (m->FeatureFlags & (1 << 11)) + DPRINT(" SEP present.\n"); + if (m->FeatureFlags & (1 << 12)) + DPRINT(" MTRR present.\n"); + if (m->FeatureFlags & (1 << 13)) + DPRINT(" PGE present.\n"); + if (m->FeatureFlags & (1 << 14)) + DPRINT(" MCA present.\n"); + if (m->FeatureFlags & (1 << 15)) + DPRINT(" CMOV present.\n"); + if (m->FeatureFlags & (1 << 16)) + DPRINT(" PAT present.\n"); + if (m->FeatureFlags & (1 << 17)) + DPRINT(" PSE present.\n"); + if (m->FeatureFlags & (1 << 18)) + DPRINT(" PSN present.\n"); + if (m->FeatureFlags & (1 << 19)) + DPRINT(" Cache Line Flush Instruction present.\n"); + /* 20 Reserved */ + if (m->FeatureFlags & (1 << 21)) + DPRINT(" Debug Trace and EMON Store present.\n"); + if (m->FeatureFlags & (1 << 22)) + DPRINT(" ACPI Thermal Throttle Registers present.\n"); + if (m->FeatureFlags & (1 << 23)) + DPRINT(" MMX present.\n"); + if (m->FeatureFlags & (1 << 24)) + DPRINT(" FXSR present.\n"); + if (m->FeatureFlags & (1 << 25)) + DPRINT(" XMM present.\n"); + if (m->FeatureFlags & (1 << 26)) + DPRINT(" Willamette New Instructions present.\n"); + if (m->FeatureFlags & (1 << 27)) + DPRINT(" Self Snoop present.\n"); + /* 28 Reserved */ + if (m->FeatureFlags & (1 << 29)) + DPRINT(" Thermal Monitor present.\n"); + /* 30, 31 Reserved */ + + CPUMap[CPUCount].APICId = m->ApicId; + + CPUMap[CPUCount].Flags = CPU_USABLE; + + if (m->CpuFlags & CPU_FLAG_BSP) + { + DPRINT(" Bootup CPU\n"); + CPUMap[CPUCount].Flags |= CPU_BSP; + BootCPU = m->ApicId; + } + + if (m->ApicId > MAX_CPU) + { + DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU); + return; + } + ver = m->ApicVersion; + + /* + * Validate version + */ + if (ver == 0x0) + { + DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId); + ver = 0x10; + } +// ApicVersion[m->ApicId] = Ver; +// BiosCpuApicId[CPUCount] = m->ApicId; + CPUMap[CPUCount].APICVersion = ver; + + CPUCount++; +} + +static VOID +HaliMPBusInfo(PMP_CONFIGURATION_BUS m) +{ + static ULONG CurrentPCIBusId = 0; + + DPRINT("Bus #%d is %.*s\n", m->BusId, 6, m->BusType); + + if (strncmp(m->BusType, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) + { + BUSMap[m->BusId] = MP_BUS_ISA; + } + else if (strncmp(m->BusType, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) + { + BUSMap[m->BusId] = MP_BUS_EISA; + } + else if (strncmp(m->BusType, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) + { + BUSMap[m->BusId] = MP_BUS_PCI; + PCIBUSMap[m->BusId] = CurrentPCIBusId; + CurrentPCIBusId++; + } + else if (strncmp(m->BusType, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) + { + BUSMap[m->BusId] = MP_BUS_MCA; + } + else + { + DPRINT("Unknown bustype %.*s - ignoring\n", 6, m->BusType); + } +} + +static VOID +HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m) +{ + if (!(m->ApicFlags & CPU_FLAG_ENABLED)) + return; + + DPRINT("I/O APIC #%d Version %d at 0x%lX.\n", + m->ApicId, m->ApicVersion, m->ApicAddress); + if (IOAPICCount > MAX_IOAPIC) + { + DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n", + MAX_IOAPIC, IOAPICCount); + DPRINT1("Recompile with bigger MAX_IOAPIC!.\n"); + KEBUGCHECK(0); + } + + IOAPICMap[IOAPICCount].ApicId = m->ApicId; + IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion; + IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress; + IOAPICCount++; +} + + +static VOID +HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m) +{ + DPRINT("Lint: type %d, pol %d, trig %d, bus %d," + " IRQ %02x, APIC ID %x, APIC LINT %02x\n", + m->IrqType, m->SrcBusIrq & 3, + (m->SrcBusIrq >> 2) & 3, m->SrcBusId, + m->SrcBusIrq, m->DstApicId, m->DstApicLInt); + /* + * Well it seems all SMP boards in existence + * use ExtINT/LVT1 == LINT0 and + * NMI/LVT2 == LINT1 - the following check + * will show us if this assumptions is false. + * Until then we do not have to add baggage. + */ + if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) + { + DPRINT1("Invalid MP table!\n"); + KEBUGCHECK(0); + } + if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) + { + DPRINT1("Invalid MP table!\n"); + KEBUGCHECK(0); + } +} + + +static BOOLEAN +HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table) +/* + PARAMETERS: + Table = Pointer to MP configuration table + */ +{ + PUCHAR Entry; + ULONG Count; + + if (Table->Signature != MPC_SIGNATURE) + { + PUCHAR pc = (PUCHAR)&Table->Signature; + + DPRINT1("Bad MP configuration block signature: %c%c%c%c\n", + pc[0], pc[1], pc[2], pc[3]); + KEBUGCHECK(0); + return FALSE; + } + + if (MPChecksum((PUCHAR)Table, Table->Length)) + { + DPRINT1("Bad MP configuration block checksum\n"); + KEBUGCHECK(0); + return FALSE; + } + + if (Table->Specification != 0x01 && Table->Specification != 0x04) + { + DPRINT1("Bad MP configuration table version (%d)\n", + Table->Specification); + KEBUGCHECK(0); + return FALSE; + } + + if (Table->LocalAPICAddress != APIC_DEFAULT_BASE) + { + DPRINT1("APIC base address is at 0x%X. I cannot handle non-standard adresses\n", + Table->LocalAPICAddress); + KEBUGCHECK(0); + return FALSE; + } + + DPRINT("Oem: %.*s, ProductId: %.*s\n", 8, Table->Oem, 12, Table->ProductId); + DPRINT("APIC at: %08x\n", Table->LocalAPICAddress); + + + Entry = (PUCHAR)((PVOID)Table + sizeof(MP_CONFIGURATION_TABLE)); + Count = 0; + while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE))) + { + /* Switch on type */ + switch (*Entry) + { + case MPCTE_PROCESSOR: + { + HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry); + Entry += sizeof(MP_CONFIGURATION_PROCESSOR); + Count += sizeof(MP_CONFIGURATION_PROCESSOR); + break; + } + case MPCTE_BUS: + { + HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry); + Entry += sizeof(MP_CONFIGURATION_BUS); + Count += sizeof(MP_CONFIGURATION_BUS); + break; + } + case MPCTE_IOAPIC: + { + HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry); + Entry += sizeof(MP_CONFIGURATION_IOAPIC); + Count += sizeof(MP_CONFIGURATION_IOAPIC); + break; + } + case MPCTE_INTSRC: + { + HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry); + Entry += sizeof(MP_CONFIGURATION_INTSRC); + Count += sizeof(MP_CONFIGURATION_INTSRC); + break; + } + case MPCTE_LINTSRC: + { + HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry); + Entry += sizeof(MP_CONFIGURATION_INTLOCAL); + Count += sizeof(MP_CONFIGURATION_INTLOCAL); + break; + } + default: + DPRINT1("Unknown entry in MPC table\n"); + KEBUGCHECK(0); + return FALSE; + } + } + return TRUE; +} + +static VOID +HaliConstructDefaultIOIrqMPTable(ULONG Type) +{ + MP_CONFIGURATION_INTSRC intsrc; + ULONG i; + + intsrc.Type = MPCTE_INTSRC; + intsrc.IrqFlag = 0; /* conforming */ + intsrc.SrcBusId = 0; + intsrc.DstApicId = IOAPICMap[0].ApicId; + + intsrc.IrqType = INT_VECTORED; + for (i = 0; i < 16; i++) { + switch (Type) { + case 2: + if (i == 0 || i == 13) + continue; /* IRQ0 & IRQ13 not connected */ + /* Fall through */ + default: + if (i == 2) + continue; /* IRQ2 is never connected */ + } + + intsrc.SrcBusIrq = i; + intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */ + HaliMPIntSrcInfo(&intsrc); + } + + intsrc.IrqType = INT_EXTINT; + intsrc.SrcBusIrq = 0; + intsrc.DstApicInt = 0; /* 8259A to INTIN0 */ + HaliMPIntSrcInfo(&intsrc); +} + +static VOID +HaliConstructDefaultISAMPTable(ULONG Type) +{ + MP_CONFIGURATION_PROCESSOR processor; + MP_CONFIGURATION_BUS bus; + MP_CONFIGURATION_IOAPIC ioapic; + MP_CONFIGURATION_INTLOCAL lintsrc; + ULONG linttypes[2] = { INT_EXTINT, INT_NMI }; + ULONG i; + + /* + * 2 CPUs, numbered 0 & 1. + */ + processor.Type = MPCTE_PROCESSOR; + /* Either an integrated APIC or a discrete 82489DX. */ + processor.ApicVersion = Type > 4 ? 0x10 : 0x01; + processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP; + /* FIXME: Get this from the bootstrap processor */ + processor.CpuSignature = 0; + processor.FeatureFlags = 0; + processor.Reserved[0] = 0; + processor.Reserved[1] = 0; + for (i = 0; i < 2; i++) + { + processor.ApicId = i; + HaliMPProcessorInfo(&processor); + processor.CpuFlags &= ~CPU_FLAG_BSP; + } + + bus.Type = MPCTE_BUS; + bus.BusId = 0; + switch (Type) + { + default: + DPRINT("Unknown standard configuration %d\n", Type); + /* Fall through */ + case 1: + case 5: + memcpy(bus.BusType, "ISA ", 6); + break; + case 2: + case 6: + case 3: + memcpy(bus.BusType, "EISA ", 6); + break; + case 4: + case 7: + memcpy(bus.BusType, "MCA ", 6); + } + HaliMPBusInfo(&bus); + if (Type > 4) + { + bus.Type = MPCTE_BUS; + bus.BusId = 1; + memcpy(bus.BusType, "PCI ", 6); + HaliMPBusInfo(&bus); + } + + ioapic.Type = MPCTE_IOAPIC; + ioapic.ApicId = 2; + ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01; + ioapic.ApicFlags = MP_IOAPIC_USABLE; + ioapic.ApicAddress = IOAPIC_DEFAULT_BASE; + HaliMPIOApicInfo(&ioapic); + + /* + * We set up most of the low 16 IO-APIC pins according to MPS rules. + */ + HaliConstructDefaultIOIrqMPTable(Type); + + lintsrc.Type = MPCTE_LINTSRC; + lintsrc.IrqType = 0; + lintsrc.IrqFlag = 0; /* conforming */ + lintsrc.SrcBusId = 0; + lintsrc.SrcBusIrq = 0; + lintsrc.DstApicId = MP_APIC_ALL; + for (i = 0; i < 2; i++) + { + lintsrc.IrqType = linttypes[i]; + lintsrc.DstApicLInt = i; + HaliMPIntLocalInfo(&lintsrc); + } +} + + +static BOOLEAN +HaliScanForMPConfigTable(ULONG Base, + ULONG Size) +{ +/* + PARAMETERS: + Base = Base address of region + Size = Length of region to check + RETURNS: + TRUE if a valid MP configuration table was found + */ + + PULONG bp = (PULONG)Base; + MP_FLOATING_POINTER* mpf; + UCHAR Checksum; + + while (Size > 0) + { + mpf = (MP_FLOATING_POINTER*)bp; + if (mpf->Signature == MPF_SIGNATURE) + { + Checksum = MPChecksum((PUCHAR)bp, 16); + DPRINT("Found MPF signature at %x, checksum %x\n", bp, Checksum); + if (Checksum == 0 && + mpf->Length == 1) + { + DPRINT("Intel MultiProcessor Specification v1.%d compliant system.\n", + mpf->Specification); + + if (mpf->Feature2 & FEATURE2_IMCRP) + { + DPRINT("Running in IMCR and PIC compatibility mode.\n"); + } + else + { + DPRINT("Running in Virtual Wire compatibility mode.\n"); + } + + + switch (mpf->Feature1) + { + case 0: + /* Non standard configuration */ + break; + case 1: + DPRINT("ISA\n"); + break; + case 2: + DPRINT("EISA with no IRQ8 chaining\n"); + break; + case 3: + DPRINT("EISA\n"); + break; + case 4: + DPRINT("MCA\n"); + break; + case 5: + DPRINT("ISA and PCI\n"); + break; + case 6: + DPRINT("EISA and PCI\n"); + break; + case 7: + DPRINT("MCA and PCI\n"); + break; + default: + DPRINT("Unknown standard configuration %d\n", mpf->Feature1); + return FALSE; + } + Mpf = mpf; + return TRUE; + } + } + bp += 4; + Size -= 16; + } + return FALSE; +} + +static BOOLEAN +HaliGetSmpConfig(VOID) +{ + if (Mpf == NULL) + { + return FALSE; + } + + if (Mpf->Feature2 & FEATURE2_IMCRP) + { + DPRINT("Running in IMCR and PIC compatibility mode.\n"); + APICMode = amPIC; + } + else + { + DPRINT("Running in Virtual Wire compatibility mode.\n"); + APICMode = amVWIRE; + } + + if (Mpf->Feature1 == 0 && Mpf->Address) + { + if(!HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)Mpf->Address)) + { + DPRINT("BIOS bug, MP table errors detected!...\n"); + DPRINT("... disabling SMP support. (tell your hw vendor)\n"); + return FALSE; + } + if (IRQCount == 0) + { + MP_CONFIGURATION_BUS bus; + + DPRINT("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); + + bus.BusId = 1; + memcpy(bus.BusType, "ISA ", 6); + HaliMPBusInfo(&bus); + HaliConstructDefaultIOIrqMPTable(bus.BusId); + } + + } + else if(Mpf->Feature1 != 0) + { + HaliConstructDefaultISAMPTable(Mpf->Feature1); + } + else + { + KEBUGCHECK(0); + } + return TRUE; +} + +BOOLEAN +HaliFindSmpConfig(VOID) +{ + /* + Scan the system memory for an MP configuration table + 1) Scan the first KB of system base memory + 2) Scan the last KB of system base memory + 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh + 4) Scan the first KB from the Extended BIOS Data Area + */ + + if (!HaliScanForMPConfigTable(0x0, 0x400)) + { + if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) + { + if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) + { + if (!HaliScanForMPConfigTable(*((PUSHORT)0x040E) << 4, 0x400)) + { + DPRINT("No multiprocessor compliant system found.\n"); + return FALSE; + } + } + } + } + + if (HaliGetSmpConfig()) + { + return TRUE; + } + else + { + DPRINT("No MP config table found\n"); + return FALSE; + } + +} + +/* EOF */ diff --git a/reactos/hal/halx86/mp/mpsirql.c b/reactos/hal/halx86/mp/mpsirql.c index 48be8270489..9c13f46a497 100644 --- a/reactos/hal/halx86/mp/mpsirql.c +++ b/reactos/hal/halx86/mp/mpsirql.c @@ -19,6 +19,7 @@ #include #include #include +#include #define NDEBUG #include diff --git a/reactos/hal/halx86/mp/processor_mp.c b/reactos/hal/halx86/mp/processor_mp.c index db82d9d8bc1..861647d6120 100644 --- a/reactos/hal/halx86/mp/processor_mp.c +++ b/reactos/hal/halx86/mp/processor_mp.c @@ -18,6 +18,8 @@ #include #include #include + +#include #include #include @@ -28,967 +30,10 @@ #define NDEBUG #include -/* - Address of area to be used for communication between Application - Processors (APs) and the BootStrap Processor (BSP) - */ -#define COMMON_AREA 0x2000 -#define BIOS_AREA 0x0 - -typedef struct __attribute__((packed)) _COMMON_AREA_INFO -{ - ULONG Stack; /* Location of AP stack */ - ULONG PageDirectory; /* Page directory for an AP */ - ULONG NtProcessStartup; /* Kernel entry point for an AP */ - ULONG PaeModeEnabled; /* PAE mode is enabled */ - ULONG Debug[16]; /* For debugging */ -} COMMON_AREA_INFO, *PCOMMON_AREA_INFO; - -CPU_INFO CPUMap[MAX_CPU]; /* Map of all CPUs in the system */ -ULONG CPUCount; /* Total number of CPUs */ -ULONG OnlineCPUs; /* Bitmask of online CPUs */ - -UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */ -UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */ - -IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */ -ULONG IOAPICCount; /* Number of I/O APICs in the system */ - -MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */ -ULONG IRQVectorMap[MAX_IRQ_SOURCE]; /* IRQ to vector map */ -ULONG IrqPinMap[MAX_IRQ_SOURCE]; /* IRQ to Pin map */ -ULONG IrqApicMap[MAX_IRQ_SOURCE]; -ULONG IRQCount; /* Number of IRQs */ - -ULONG APICMode; /* APIC mode at startup */ -ULONG BootCPU; /* Bootstrap processor */ -PULONG BIOSBase; /* Virtual address of BIOS data segment */ -PULONG CommonBase; /* Virtual address of common area */ - -extern CHAR *APstart, *APend; -extern VOID (*APflush)(VOID); - -extern VOID MpsTimerInterrupt(VOID); -extern VOID MpsErrorInterrupt(VOID); -extern VOID MpsSpuriousInterrupt(VOID); -extern VOID MpsIpiInterrupt(VOID); - -#define CMOS_READ(address) ({ \ - WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \ - READ_PORT_UCHAR((PUCHAR)0x71)); \ -}) - -#define CMOS_WRITE(address, value) ({ \ - WRITE_PORT_UCHAR((PUCHAR)0x70, address); \ - WRITE_PORT_UCHAR((PUCHAR)0x71, value); \ -}) - -extern PVOID IMPORTED MmSystemRangeStart; /* FUNCTIONS *****************************************************************/ -/* Functions for handling 8259A PICs */ - -VOID Disable8259AIrq(ULONG irq) -{ - ULONG tmp; - - if (irq >= 8) - { - tmp = READ_PORT_UCHAR((PUCHAR)0xA1); - tmp |= (1 << (irq - 8)); - WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp); - } - else - { - tmp = READ_PORT_UCHAR((PUCHAR)0x21); - tmp |= (1 << irq); - WRITE_PORT_UCHAR((PUCHAR)0x21, tmp); - } -} - - -VOID Enable8259AIrq(ULONG irq) -{ - ULONG tmp; - - if (irq >= 8) - { - tmp = READ_PORT_UCHAR((PUCHAR)0xA1); - tmp &= ~(1 << (irq - 8)); - WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp); - } - else - { - tmp = READ_PORT_UCHAR((PUCHAR)0x21); - tmp &= ~(1 << irq); - WRITE_PORT_UCHAR((PUCHAR)0x21, tmp); - } -} - - -/* Functions for handling I/O APICs */ - -ULONG IOAPICRead(ULONG Apic, ULONG Offset) -{ - PULONG Base; - - Base = (PULONG)IOAPICMap[Apic].ApicAddress; - *Base = Offset; - return *((PULONG)((ULONG)Base + IOAPIC_IOWIN)); -} - -VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value) -{ - PULONG Base; - - Base = (PULONG)IOAPICMap[Apic].ApicAddress; - *Base = Offset; - *((PULONG)((ULONG)Base + IOAPIC_IOWIN)) = Value; -} - - -VOID IOAPICClearPin(ULONG Apic, ULONG Pin) -{ - IOAPIC_ROUTE_ENTRY Entry; - - DPRINT("IOAPICClearPin(Apic %d, Pin %d\n", Apic, Pin); - /* - * Disable it in the IO-APIC irq-routing table - */ - memset(&Entry, 0, sizeof(Entry)); - Entry.mask = 1; - - IOAPICWrite(Apic, IOAPIC_REDTBL + 2 * Pin, *(((PULONG)&Entry) + 0)); - IOAPICWrite(Apic, IOAPIC_REDTBL + 1 + 2 * Pin, *(((PULONG)&Entry) + 1)); -} - -static VOID IOAPICClear(ULONG Apic) -{ - ULONG Pin; - - for (Pin = 0; Pin < /*IOAPICMap[Apic].EntryCount*/24; Pin++) - { - IOAPICClearPin(Apic, Pin); - } -} - -static VOID IOAPICClearAll(VOID) -{ - ULONG Apic; - - for (Apic = 0; Apic < IOAPICCount; Apic++) - { - IOAPICClear(Apic); - } -} - -/* This is performance critical and should probably be done in assembler */ -VOID IOAPICMaskIrq(ULONG Irq) -{ - IOAPIC_ROUTE_ENTRY Entry; - ULONG Apic = IrqApicMap[Irq]; - - *(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq); - *(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1); - Entry.dest.logical.logical_dest &= ~(1 << KeGetCurrentProcessorNumber()); - if (Entry.dest.logical.logical_dest == 0) - { - Entry.mask = 1; - } - IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1)); - IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0)); -} - - -/* This is performance critical and should probably be done in assembler */ -VOID IOAPICUnmaskIrq(ULONG Irq) -{ - IOAPIC_ROUTE_ENTRY Entry; - ULONG Apic = IrqApicMap[Irq]; - - *(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq); - *(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1); - Entry.dest.logical.logical_dest |= 1 << KeGetCurrentProcessorNumber(); - Entry.mask = 0; - IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1)); - IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0)); -} - -static VOID -IOAPICSetupIds(VOID) -{ - ULONG tmp, apic, i; - UCHAR old_id; - - /* - * Set the IOAPIC ID to the value stored in the MPC table. - */ - for (apic = 0; apic < IOAPICCount; apic++) - { - - /* Read the register 0 value */ - tmp = IOAPICRead(apic, IOAPIC_ID); - - old_id = IOAPICMap[apic].ApicId; - - if (IOAPICMap[apic].ApicId >= 0xf) - { - DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", - apic, IOAPICMap[apic].ApicId); - DPRINT1("... fixing up to %d. (tell your hw vendor)\n", - GET_IOAPIC_ID(tmp)); - IOAPICMap[apic].ApicId = GET_IOAPIC_ID(tmp); - } - - /* - * We need to adjust the IRQ routing table - * if the ID changed. - */ - if (old_id != IOAPICMap[apic].ApicId) - { - for (i = 0; i < IRQCount; i++) - { - if (IRQMap[i].DstApicId == old_id) - { - IRQMap[i].DstApicId = IOAPICMap[apic].ApicId; - } - } - } - - /* - * Read the right value from the MPC table and - * write it into the ID register. - */ - DPRINT("Changing IO-APIC physical APIC ID to %d\n", - IOAPICMap[apic].ApicId); - - tmp &= ~IOAPIC_ID_MASK; - tmp |= SET_IOAPIC_ID(IOAPICMap[apic].ApicId); - - IOAPICWrite(apic, IOAPIC_ID, tmp); - - /* - * Sanity check - */ - tmp = IOAPICRead(apic, 0); - if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId) - { - DPRINT1("Could not set I/O APIC ID!\n"); - KEBUGCHECK(0); - } - } -} - - -/* - * EISA Edge/Level control register, ELCR - */ -static ULONG EISA_ELCR(ULONG irq) -{ - if (irq < 16) - { - PUCHAR port = (PUCHAR)(0x4d0 + (irq >> 3)); - return (READ_PORT_UCHAR(port) >> (irq & 7)) & 1; - } - DPRINT("Broken MPtable reports ISA irq %d\n", irq); - return 0; -} - -/* EISA interrupts are always polarity zero and can be edge or level - * trigger depending on the ELCR value. If an interrupt is listed as - * EISA conforming in the MP table, that means its trigger type must - * be read in from the ELCR */ - -#define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq)) -#define default_EISA_polarity(idx) (0) - -/* ISA interrupts are always polarity zero edge triggered, - * when listed as conforming in the MP table. */ - -#define default_ISA_trigger(idx) (0) -#define default_ISA_polarity(idx) (0) - -/* PCI interrupts are always polarity one level triggered, - * when listed as conforming in the MP table. */ - -#define default_PCI_trigger(idx) (1) -#define default_PCI_polarity(idx) (1) - -/* MCA interrupts are always polarity zero level triggered, - * when listed as conforming in the MP table. */ - -#define default_MCA_trigger(idx) (1) -#define default_MCA_polarity(idx) (0) - -static ULONG IRQPolarity(ULONG idx) -{ - ULONG bus = IRQMap[idx].SrcBusId; - ULONG polarity; - - /* - * Determine IRQ line polarity (high active or low active): - */ - switch (IRQMap[idx].IrqFlag & 3) - { - case 0: /* conforms, ie. bus-type dependent polarity */ - { - switch (BUSMap[bus]) - { - case MP_BUS_ISA: /* ISA pin */ - { - polarity = default_ISA_polarity(idx); - break; - } - case MP_BUS_EISA: /* EISA pin */ - { - polarity = default_EISA_polarity(idx); - break; - } - case MP_BUS_PCI: /* PCI pin */ - { - polarity = default_PCI_polarity(idx); - break; - } - case MP_BUS_MCA: /* MCA pin */ - { - polarity = default_MCA_polarity(idx); - break; - } - default: - { - DPRINT("Broken BIOS!!\n"); - polarity = 1; - break; - } - } - break; - } - case 1: /* high active */ - { - polarity = 0; - break; - } - case 2: /* reserved */ - { - DPRINT("Broken BIOS!!\n"); - polarity = 1; - break; - } - case 3: /* low active */ - { - polarity = 1; - break; - } - default: /* invalid */ - { - DPRINT("Broken BIOS!!\n"); - polarity = 1; - break; - } - } - return polarity; -} - -static ULONG IRQTrigger(ULONG idx) -{ - ULONG bus = IRQMap[idx].SrcBusId; - ULONG trigger; - - /* - * Determine IRQ trigger mode (edge or level sensitive): - */ - switch ((IRQMap[idx].IrqFlag >> 2) & 3) - { - case 0: /* conforms, ie. bus-type dependent */ - { - switch (BUSMap[bus]) - { - case MP_BUS_ISA: /* ISA pin */ - { - trigger = default_ISA_trigger(idx); - break; - } - case MP_BUS_EISA: /* EISA pin */ - { - trigger = default_EISA_trigger(idx); - break; - } - case MP_BUS_PCI: /* PCI pin */ - { - trigger = default_PCI_trigger(idx); - break; - } - case MP_BUS_MCA: /* MCA pin */ - { - trigger = default_MCA_trigger(idx); - break; - } - default: - { - DPRINT("Broken BIOS!!\n"); - trigger = 1; - break; - } - } - break; - } - case 1: /* edge */ - { - trigger = 0; - break; - } - case 2: /* reserved */ - { - DPRINT("Broken BIOS!!\n"); - trigger = 1; - break; - } - case 3: /* level */ - { - trigger = 1; - break; - } - default: /* invalid */ - { - DPRINT("Broken BIOS!!\n"); - trigger = 0; - break; - } - } - return trigger; -} - - -static ULONG Pin2Irq(ULONG idx, - ULONG apic, - ULONG pin) -{ - ULONG irq, i; - ULONG bus = IRQMap[idx].SrcBusId; - - /* - * Debugging check, we are in big trouble if this message pops up! - */ - if (IRQMap[idx].DstApicInt != pin) { - DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n"); - } - - switch (BUSMap[bus]) - { - case MP_BUS_ISA: /* ISA pin */ - case MP_BUS_EISA: - case MP_BUS_MCA: - { - irq = IRQMap[idx].SrcBusIrq; - break; - } - case MP_BUS_PCI: /* PCI pin */ - { - /* - * PCI IRQs are mapped in order - */ - i = irq = 0; - while (i < apic) - irq += IOAPICMap[i++].EntryCount; - irq += pin; - break; - } - default: - { - DPRINT("Unknown bus type %d.\n",bus); - irq = 0; - break; - } - } - - return irq; -} - - -/* - * Rough estimation of how many shared IRQs there are, can - * be changed anytime. - */ -#define MAX_PLUS_SHARED_IRQS PIC_IRQS -#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + PIC_IRQS) - -/* - * This is performance-critical, we want to do it O(1) - * - * the indexing order of this array favors 1:1 mappings - * between pins and IRQs. - */ - -static struct irq_pin_list { - ULONG apic, pin, next; -} irq_2_pin[PIN_MAP_SIZE]; - -/* - * The common case is 1:1 IRQ<->pin mappings. Sometimes there are - * shared ISA-space IRQs, so we have to support them. We are super - * fast in the common case, and fast for shared ISA-space IRQs. - */ -static VOID AddPinToIrq(ULONG irq, - ULONG apic, - ULONG pin) -{ - static ULONG first_free_entry = PIC_IRQS; - struct irq_pin_list *entry = irq_2_pin + irq; - - while (entry->next) - { - entry = irq_2_pin + entry->next; - } - - if (entry->pin != -1) - { - entry->next = first_free_entry; - entry = irq_2_pin + entry->next; - if (++first_free_entry >= PIN_MAP_SIZE) - { - DPRINT1("Ohh no!"); - KEBUGCHECK(0); - } - } - entry->apic = apic; - entry->pin = pin; -} - - -/* - * Find the IRQ entry number of a certain pin. - */ -static ULONG IOAPICGetIrqEntry(ULONG apic, - ULONG pin, - ULONG type) -{ - ULONG i; - - for (i = 0; i < IRQCount; i++) - { - if (IRQMap[i].IrqType == type && - (IRQMap[i].DstApicId == IOAPICMap[apic].ApicId || IRQMap[i].DstApicId == MP_APIC_ALL) && - IRQMap[i].DstApicInt == pin) - { - return i; - } - } - return -1; -} - - -static ULONG AssignIrqVector(ULONG irq) -{ -#if 0 - static ULONG current_vector = FIRST_DEVICE_VECTOR, vector_offset = 0; -#endif - ULONG vector; - /* There may already have been assigned a vector for this IRQ */ - vector = IRQVectorMap[irq]; - if (vector > 0) - { - return vector; - } -#if 0 - if (current_vector > FIRST_SYSTEM_VECTOR) { - vector_offset++; - current_vector = FIRST_DEVICE_VECTOR + vector_offset; - } else if (current_vector == FIRST_SYSTEM_VECTOR) { - DPRINT1("Ran out of interrupt sources!"); - KEBUGCHECK(0); - } - - vector = current_vector; - IRQVectorMap[irq] = vector; - current_vector += 8; - return vector; -#else - vector = IRQ2VECTOR(irq); - IRQVectorMap[irq] = vector; - return vector; -#endif -} - - -VOID IOAPICSetupIrqs(VOID) -{ - IOAPIC_ROUTE_ENTRY entry; - ULONG apic, pin, idx, irq, first_notcon = 1, vector; - - DPRINT("Init IO_APIC IRQs\n"); - - for (apic = 0; apic < IOAPICCount; apic++) - { - for (pin = 0; pin < IOAPICMap[apic].EntryCount; pin++) - { - /* - * add it to the IO-APIC irq-routing table - */ - memset(&entry,0,sizeof(entry)); - - entry.delivery_mode = (APIC_DM_LOWEST >> 8); - entry.dest_mode = 1; /* logical delivery */ - entry.mask = 1; /* disable IRQ */ - entry.dest.logical.logical_dest = 0; - - idx = IOAPICGetIrqEntry(apic,pin,INT_VECTORED); - if (idx == -1) - { - if (first_notcon) - { - DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap[apic].ApicId, pin); - first_notcon = 0; - } - else - { - DPRINT(", %d-%d\n", IOAPICMap[apic].ApicId, pin); - } - continue; - } - - entry.trigger = IRQTrigger(idx); - entry.polarity = IRQPolarity(idx); - - if (entry.trigger) - { - entry.trigger = 1; - entry.mask = 1; // disable - entry.dest.logical.logical_dest = 0; - } - - irq = Pin2Irq(idx, apic, pin); - AddPinToIrq(irq, apic, pin); - - vector = AssignIrqVector(irq); - entry.vector = vector; - - DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector, irq); - - if (irq == 0) - { - /* Mask timer IRQ */ - entry.mask = 1; - } - - if ((apic == 0) && (irq < 16)) - { - Disable8259AIrq(irq); - } - IOAPICWrite(apic, IOAPIC_REDTBL+2*pin+1, *(((PULONG)&entry)+1)); - IOAPICWrite(apic, IOAPIC_REDTBL+2*pin, *(((PULONG)&entry)+0)); - - IrqPinMap[irq] = pin; - IrqApicMap[irq] = apic; - - DPRINT("Vector %x, Pin %x, Irq %x\n", vector, pin, irq); - } - } -} - - -static VOID IOAPICEnable(VOID) -{ - ULONG i, tmp; - - for (i = 0; i < PIN_MAP_SIZE; i++) - { - irq_2_pin[i].pin = -1; - irq_2_pin[i].next = 0; - } - - /* - * The number of IO-APIC IRQ registers (== #pins): - */ - for (i = 0; i < IOAPICCount; i++) - { - tmp = IOAPICRead(i, IOAPIC_VER); - IOAPICMap[i].EntryCount = GET_IOAPIC_MRE(tmp) + 1; - } - - /* - * Do not trust the IO-APIC being empty at bootup - */ - IOAPICClearAll(); -} - -#if 0 -static VOID IOAPICDisable(VOID) -{ - /* - * Clear the IO-APIC before rebooting - */ - IOAPICClearAll(); - APICDisable(); -} -#endif - - -static VOID IOAPICSetup(VOID) -{ - IOAPICEnable(); - IOAPICSetupIds(); - APICSyncArbIDs(); - IOAPICSetupIrqs(); -} - - -VOID IOAPICDump(VOID) -{ - ULONG apic, i; - ULONG reg0, reg1, reg2=0; - - DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount); - for (i = 0; i < IOAPICCount; i++) - { - DbgPrint("Number of IO-APIC #%d registers: %d.\n", - IOAPICMap[i].ApicId, - IOAPICMap[i].EntryCount); - } - - /* - * We are a bit conservative about what we expect. We have to - * know about every hardware change ASAP. - */ - DbgPrint("Testing the IO APIC.......................\n"); - - for (apic = 0; apic < IOAPICCount; apic++) - { - reg0 = IOAPICRead(apic, IOAPIC_ID); - reg1 = IOAPICRead(apic, IOAPIC_VER); - if (GET_IOAPIC_VERSION(reg1) >= 0x10) - { - reg2 = IOAPICRead(apic, IOAPIC_ARB); - } - - DbgPrint("\n"); - DbgPrint("IO APIC #%d......\n", IOAPICMap[apic].ApicId); - DbgPrint(".... register #00: %08X\n", reg0); - DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0)); - if (reg0 & 0xF0FFFFFF) - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - - DbgPrint(".... register #01: %08X\n", reg1); - i = GET_IOAPIC_MRE(reg1); - - DbgPrint("....... : max redirection entries: %04X\n", i); - if ((i != 0x0f) && /* older (Neptune) boards */ - (i != 0x17) && /* typical ISA+PCI boards */ - (i != 0x1b) && /* Compaq Proliant boards */ - (i != 0x1f) && /* dual Xeon boards */ - (i != 0x22) && /* bigger Xeon boards */ - (i != 0x2E) && - (i != 0x3F)) - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - - i = GET_IOAPIC_VERSION(reg1); - DbgPrint("....... : IO APIC version: %04X\n", i); - if ((i != 0x01) && /* 82489DX IO-APICs */ - (i != 0x10) && /* oldest IO-APICs */ - (i != 0x11) && /* Pentium/Pro IO-APICs */ - (i != 0x13)) /* Xeon IO-APICs */ - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - - if (reg1 & 0xFF00FF00) - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - - if (GET_IOAPIC_VERSION(reg1) >= 0x10) - { - DbgPrint(".... register #02: %08X\n", reg2); - DbgPrint("....... : arbitration: %02X\n", - GET_IOAPIC_ARB(reg2)); - if (reg2 & 0xF0FFFFFF) - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - } - - DbgPrint(".... IRQ redirection table:\n"); - DbgPrint(" NR Log Phy Mask Trig IRR Pol" - " Stat Dest Deli Vect: \n"); - - for (i = 0; i <= GET_IOAPIC_MRE(reg1); i++) - { - IOAPIC_ROUTE_ENTRY entry; - - *(((PULONG)&entry)+0) = IOAPICRead(apic, 0x10+i*2); - *(((PULONG)&entry)+1) = IOAPICRead(apic, 0x11+i*2); - - DbgPrint(" %02x %03X %02X ", - i, - entry.dest.logical.logical_dest, - entry.dest.physical.physical_dest); - - DbgPrint("%C %C %1d %C %C %C %03X %02X\n", - (entry.mask == 0) ? 'U' : 'M', // Unmasked/masked - (entry.trigger == 0) ? 'E' : 'L', // Edge/level sensitive - entry.irr, - (entry.polarity == 0) ? 'H' : 'L', // Active high/active low - (entry.delivery_status == 0) ? 'I' : 'S', // Idle / send pending - (entry.dest_mode == 0) ? 'P' : 'L', // Physical logical - entry.delivery_mode, - entry.vector); - } - } - DbgPrint("IRQ to pin mappings:\n"); - for (i = 0; i < PIC_IRQS; i++) - { - struct irq_pin_list *entry = irq_2_pin + i; - if (entry->pin < 0) - { - continue; - } - DbgPrint("IRQ%d ", i); - for (;;) - { - DbgPrint("-> %d", entry->pin); - if (!entry->next) - { - break; - } - entry = irq_2_pin + entry->next; - } - if (i % 2) - { - DbgPrint("\n"); - } - else - { - DbgPrint(" "); - } - } - - DbgPrint(".................................... done.\n"); -} - - - -/* Functions for handling local APICs */ - -ULONG Read8254Timer(VOID) -{ - ULONG Count; - - WRITE_PORT_UCHAR((PUCHAR)0x43, 0x00); - Count = READ_PORT_UCHAR((PUCHAR)0x40); - Count |= READ_PORT_UCHAR((PUCHAR)0x40) << 8; - - return Count; -} - -VOID WaitFor8254Wraparound(VOID) -{ - ULONG CurCount, PrevCount = ~0; - LONG Delta; - - CurCount = Read8254Timer(); - do - { - PrevCount = CurCount; - CurCount = Read8254Timer(); - Delta = CurCount - PrevCount; - - /* - * This limit for delta seems arbitrary, but it isn't, it's - * slightly above the level of error a buggy Mercury/Neptune - * chipset timer can cause. - */ - - } - while (Delta < 300); -} - -#define HZ (100) -#define APIC_DIVISOR (16) - -VOID APICSetupLVTT(ULONG ClockTicks) -{ - ULONG tmp; - - tmp = GET_APIC_VERSION(APICRead(APIC_VER)); - if (!APIC_INTEGRATED(tmp)) - { - tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;; - } - else - { - /* Periodic timer */ - tmp = APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;; - } - APICWrite(APIC_LVTT, tmp); - - tmp = APICRead(APIC_TDCR); - tmp &= ~(APIC_TDCR_1 | APIC_TIMER_BASE_DIV); - tmp |= APIC_TDCR_16; - APICWrite(APIC_TDCR, tmp); - APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR); -} - - -VOID APICCalibrateTimer(ULONG CPU) -{ - ULARGE_INTEGER t1, t2; - LONG tt1, tt2; - - DPRINT("Calibrating APIC timer for CPU %d\n", CPU); - - APICSetupLVTT(1000000000); - - /* - * The timer chip counts down to zero. Let's wait - * for a wraparound to start exact measurement: - * (the current tick might have been already half done) - */ - WaitFor8254Wraparound(); - - /* - * We wrapped around just now. Let's start - */ - ReadPentiumClock(&t1); - tt1 = APICRead(APIC_CCRT); - - WaitFor8254Wraparound(); - - - tt2 = APICRead(APIC_CCRT); - ReadPentiumClock(&t2); - - CPUMap[CPU].BusSpeed = (HZ * (long)(tt1 - tt2) * APIC_DIVISOR); - CPUMap[CPU].CoreSpeed = (HZ * (t2.QuadPart - t1.QuadPart)); - - /* Setup timer for normal operation */ -// APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns - APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 10000); // 10ms -// APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms - - DPRINT("CPU clock speed is %ld.%04ld MHz.\n", - CPUMap[CPU].CoreSpeed/1000000, - CPUMap[CPU].CoreSpeed%1000000); - - DPRINT("Host bus clock speed is %ld.%04ld MHz.\n", - CPUMap[CPU].BusSpeed/1000000, - CPUMap[CPU].BusSpeed%1000000); -} - -VOID -SetInterruptGate(ULONG index, ULONG address) -{ - IDT_DESCRIPTOR *idt; - - idt = (IDT_DESCRIPTOR*)((ULONG)KeGetCurrentKPCR()->IDT + index * sizeof(IDT_DESCRIPTOR)); - idt->a = (((ULONG)address)&0xffff) + (KERNEL_CS << 16); - idt->b = 0x8e00 + (((ULONG)address)&0xffff0000); -} - VOID STDCALL HalInitializeProcessor(ULONG ProcessorNumber, PVOID /*PLOADER_PARAMETER_BLOCK*/ LoaderBlock) @@ -1043,7 +88,15 @@ HalAllProcessorsStarted (VOID) } else if (CPUs == CPUCount) { - IOAPICSetup(); + + IOAPICEnable(); + IOAPICSetupIds(); + if (CPUCount > 1) + { + APICSyncArbIDs(); + } + IOAPICSetupIrqs(); + return TRUE; } return FALSE; @@ -1053,12 +106,7 @@ BOOLEAN STDCALL HalStartNextProcessor(ULONG Unknown1, ULONG ProcessorStack) { - PCOMMON_AREA_INFO Common; - ULONG StartupCount; - ULONG DeliveryStatus = 0; - ULONG AcceptStatus = 0; - ULONG CPU, i, j; - ULONG tmp, maxlvt; + ULONG CPU; DPRINT("HalStartNextProcessor(%x %x)\n", Unknown1, ProcessorStack); @@ -1077,741 +125,8 @@ HalStartNextProcessor(ULONG Unknown1, DPRINT1("Attempting to boot CPU %d\n", CPU); - /* Send INIT IPI */ - - APICSendIPI(CPU, APIC_DM_INIT|APIC_ICR0_LEVEL_ASSERT); - - KeStallExecutionProcessor(200); - - /* Deassert INIT */ - - APICSendIPI(CPU, APIC_DM_INIT|APIC_ICR0_LEVEL_DEASSERT); - - if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) - { - /* Clear APIC errors */ - APICWrite(APIC_ESR, 0); - tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK); - } - - Common = (PCOMMON_AREA_INFO)CommonBase; - - /* Write the location of the AP stack */ - Common->Stack = (ULONG)ProcessorStack; - /* Write the page directory page */ - Ke386GetPageTableDirectory(Common->PageDirectory); - /* Write the kernel entry point */ - Common->NtProcessStartup = (ULONG_PTR)RtlImageNtHeader(MmSystemRangeStart)->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)MmSystemRangeStart; - /* Write the state of the mae mode */ - Common->PaeModeEnabled = Ke386GetCr4() & X86_CR4_PAE ? 1 : 0; - - DPRINT1("%x %x %x %x\n", Common->Stack, Common->PageDirectory, Common->NtProcessStartup, Common->PaeModeEnabled); - - - DPRINT("CPU %d got stack at 0x%X\n", CPU, Common->Stack); -#if 0 - for (j = 0; j < 16; j++) - { - Common->Debug[j] = 0; - } -#endif - - maxlvt = APICGetMaxLVT(); - - /* Is this a local APIC or an 82489DX? */ - StartupCount = (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) ? 2 : 0; - - for (i = 1; i <= StartupCount; i++) - { - /* It's a local APIC, so send STARTUP IPI */ - DPRINT("Sending startup signal %d\n", i); - /* Clear errors */ - APICWrite(APIC_ESR, 0); - APICRead(APIC_ESR); - - APICSendIPI(CPU, APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12)|APIC_ICR0_LEVEL_DEASSERT); - - /* Wait up to 10ms for IPI to be delivered */ - j = 0; - do - { - KeStallExecutionProcessor(10); - - /* Check Delivery Status */ - DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS; - - j++; - } while ((DeliveryStatus) && (j < 1000)); - - KeStallExecutionProcessor(200); - - /* - * Due to the Pentium erratum 3AP. - */ - if (maxlvt > 3) - { - APICRead(APIC_SIVR); - APICWrite(APIC_ESR, 0); - } - - AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK; - - if (DeliveryStatus || AcceptStatus) - { - break; - } - } - - if (DeliveryStatus) - { - DPRINT("STARTUP IPI for CPU %d was never delivered.\n", CPU); - } - - if (AcceptStatus) - { - DPRINT("STARTUP IPI for CPU %d was never accepted.\n", CPU); - } - - if (!(DeliveryStatus || AcceptStatus)) - { - - /* Wait no more than 5 seconds for processor to boot */ - DPRINT("Waiting for 5 seconds for CPU %d to boot\n", CPU); - - /* Wait no more than 5 seconds */ - for (j = 0; j < 50000; j++) - { - if (CPUMap[CPU].Flags & CPU_ENABLED) - { - break; - } - KeStallExecutionProcessor(100); - } - } - - if (CPUMap[CPU].Flags & CPU_ENABLED) - { - DbgPrint("CPU %d is now running\n", CPU); - } - else - { - DbgPrint("Initialization of CPU %d failed\n", CPU); - } - -#if 0 - DPRINT("Debug bytes are:\n"); - - for (j = 0; j < 4; j++) - { - DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n", - Common->Debug[j*4+0], - Common->Debug[j*4+1], - Common->Debug[j*4+2], - Common->Debug[j*4+3]); - } -#endif + HaliStartApplicationProcessor(CPU, ProcessorStack); return TRUE; } - - -ULONG MPChecksum(PUCHAR Base, - ULONG Size) -/* - * Checksum an MP configuration block - */ -{ - ULONG Sum = 0; - - while (Size--) - Sum += *Base++; - - return((UCHAR)Sum); -} - - -PCHAR HaliMPFamily(ULONG Family, - ULONG Model) -{ - static CHAR str[64]; - static PCHAR CPUs[] = - { - "80486DX", "80486DX", - "80486SX", "80486DX/2 or 80487", - "80486SL", "Intel5X2(tm)", - "Unknown", "Unknown", - "80486DX/4" - }; - if (Family == 0x6) - return ("Pentium(tm) Pro"); - if (Family == 0x5) - return ("Pentium(tm)"); - if (Family == 0x0F && Model == 0x0F) - return("Special controller"); - if (Family == 0x0F && Model == 0x00) - return("Pentium 4(tm)"); - if (Family == 0x04 && Model < 9) - return CPUs[Model]; - sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model); - return str; -} - -static VOID HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m) -{ - ULONG ver; - - if (!(m->CpuFlags & CPU_FLAG_ENABLED)) - return; - - DPRINT("Processor #%d %s APIC version %d\n", - m->ApicId, - HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8, - (m->FeatureFlags & CPU_MODEL_MASK) >> 4), - m->ApicVersion); - - if (m->FeatureFlags & (1 << 0)) - DPRINT(" Floating point unit present.\n"); - if (m->FeatureFlags & (1 << 7)) - DPRINT(" Machine Exception supported.\n"); - if (m->FeatureFlags & (1 << 8)) - DPRINT(" 64 bit compare & exchange supported.\n"); - if (m->FeatureFlags & (1 << 9)) - DPRINT(" Internal APIC present.\n"); - if (m->FeatureFlags & (1 << 11)) - DPRINT(" SEP present.\n"); - if (m->FeatureFlags & (1 << 12)) - DPRINT(" MTRR present.\n"); - if (m->FeatureFlags & (1 << 13)) - DPRINT(" PGE present.\n"); - if (m->FeatureFlags & (1 << 14)) - DPRINT(" MCA present.\n"); - if (m->FeatureFlags & (1 << 15)) - DPRINT(" CMOV present.\n"); - if (m->FeatureFlags & (1 << 16)) - DPRINT(" PAT present.\n"); - if (m->FeatureFlags & (1 << 17)) - DPRINT(" PSE present.\n"); - if (m->FeatureFlags & (1 << 18)) - DPRINT(" PSN present.\n"); - if (m->FeatureFlags & (1 << 19)) - DPRINT(" Cache Line Flush Instruction present.\n"); - /* 20 Reserved */ - if (m->FeatureFlags & (1 << 21)) - DPRINT(" Debug Trace and EMON Store present.\n"); - if (m->FeatureFlags & (1 << 22)) - DPRINT(" ACPI Thermal Throttle Registers present.\n"); - if (m->FeatureFlags & (1 << 23)) - DPRINT(" MMX present.\n"); - if (m->FeatureFlags & (1 << 24)) - DPRINT(" FXSR present.\n"); - if (m->FeatureFlags & (1 << 25)) - DPRINT(" XMM present.\n"); - if (m->FeatureFlags & (1 << 26)) - DPRINT(" Willamette New Instructions present.\n"); - if (m->FeatureFlags & (1 << 27)) - DPRINT(" Self Snoop present.\n"); - /* 28 Reserved */ - if (m->FeatureFlags & (1 << 29)) - DPRINT(" Thermal Monitor present.\n"); - /* 30, 31 Reserved */ - - CPUMap[CPUCount].APICId = m->ApicId; - - CPUMap[CPUCount].Flags = CPU_USABLE; - - if (m->CpuFlags & CPU_FLAG_BSP) - { - DPRINT(" Bootup CPU\n"); - CPUMap[CPUCount].Flags |= CPU_BSP; - BootCPU = m->ApicId; - } - - if (m->ApicId > MAX_CPU) - { - DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU); - return; - } - ver = m->ApicVersion; - - /* - * Validate version - */ - if (ver == 0x0) - { - DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId); - ver = 0x10; - } - CPUMap[CPUCount].APICVersion = ver; - - CPUCount++; -} - -static VOID HaliMPBusInfo(PMP_CONFIGURATION_BUS m) -{ - static ULONG CurrentPCIBusId = 0; - CHAR str[7]; - - memcpy(str, m->BusType, 6); - str[6] = 0; - DPRINT("Bus #%d is %s\n", m->BusId, str); - - if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) - { - BUSMap[m->BusId] = MP_BUS_ISA; - } - else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) - { - BUSMap[m->BusId] = MP_BUS_EISA; - } - else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) - { - BUSMap[m->BusId] = MP_BUS_PCI; - PCIBUSMap[m->BusId] = CurrentPCIBusId; - CurrentPCIBusId++; - } - else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) - { - BUSMap[m->BusId] = MP_BUS_MCA; - } - else - { - DPRINT("Unknown bustype %s - ignoring\n", str); - } -} - -static VOID HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m) -{ - if (!(m->ApicFlags & CPU_FLAG_ENABLED)) - return; - - DPRINT("I/O APIC #%d Version %d at 0x%lX.\n", - m->ApicId, m->ApicVersion, m->ApicAddress); - if (IOAPICCount > MAX_IOAPIC) - { - DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n", - MAX_IOAPIC, IOAPICCount); - DPRINT1("Recompile with bigger MAX_IOAPIC!.\n"); - KEBUGCHECK(0); - } - IOAPICMap[IOAPICCount].ApicId = m->ApicId; - IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion; - IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress; - IOAPICCount++; -} - -static VOID HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m) -{ - DPRINT("Int: type %d, pol %d, trig %d, bus %d," - " IRQ %02x, APIC ID %x, APIC INT %02x\n", - m->IrqType, m->IrqFlag & 3, - (m->IrqFlag >> 2) & 3, m->SrcBusId, - m->SrcBusIrq, m->DstApicId, m->DstApicInt); - if (IRQCount > MAX_IRQ_SOURCE) - { - DPRINT1("Max # of irq sources exceeded!!\n"); - KEBUGCHECK(0); - } - - IRQMap[IRQCount] = *m; - IRQCount++; -} - -static VOID HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m) -{ - DPRINT("Lint: type %d, pol %d, trig %d, bus %d," - " IRQ %02x, APIC ID %x, APIC LINT %02x\n", - m->IrqType, m->IrqFlag & 3, - (m->IrqFlag >> 2) & 3, m->SrcBusId, - m->SrcBusIrq, m->DstApicId, m->DstApicLInt); - /* - * Well it seems all SMP boards in existence - * use ExtINT/LVT1 == LINT0 and - * NMI/LVT2 == LINT1 - the following check - * will show us if this assumptions is false. - * Until then we do not have to add baggage. - */ - if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) - { - DPRINT1("Invalid MP table!\n"); - KEBUGCHECK(0); - } - if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) - { - DPRINT1("Invalid MP table!\n"); - KEBUGCHECK(0); - } -} - -VOID -HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table) -/* - PARAMETERS: - Table = Pointer to MP configuration table - */ -{ - PUCHAR Entry; - ULONG Count; - - if (Table->Signature != MPC_SIGNATURE) - { - PUCHAR pc = (PUCHAR)&Table->Signature; - - DbgPrint("Bad MP configuration block signature: %c%c%c%c\n", - pc[0], pc[1], pc[2], pc[3]); - KEBUGCHECK(0); - return; - } - - if (MPChecksum((PUCHAR)Table, Table->Length)) - { - DbgPrint("Bad MP configuration block checksum\n"); - KEBUGCHECK(0); - return; - } - - if (Table->Specification < 0x04) - { - DbgPrint("Bad MP configuration table version (%d)\n", - Table->Specification); - KEBUGCHECK(0); - return; - } - - if (Table->LocalAPICAddress != APIC_DEFAULT_BASE) - { - DbgPrint("APIC base address is at 0x%X. " \ - "I cannot handle non-standard adresses\n", Table->LocalAPICAddress); - KEBUGCHECK(0); - } - - Entry = (PUCHAR)((PVOID)Table + sizeof(MP_CONFIGURATION_TABLE)); - Count = 0; - while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE))) - { - /* Switch on type */ - switch (*Entry) - { - case MPCTE_PROCESSOR: - { - HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry); - Entry += sizeof(MP_CONFIGURATION_PROCESSOR); - Count += sizeof(MP_CONFIGURATION_PROCESSOR); - break; - } - case MPCTE_BUS: - { - HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry); - Entry += sizeof(MP_CONFIGURATION_BUS); - Count += sizeof(MP_CONFIGURATION_BUS); - break; - } - case MPCTE_IOAPIC: - { - HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry); - Entry += sizeof(MP_CONFIGURATION_IOAPIC); - Count += sizeof(MP_CONFIGURATION_IOAPIC); - break; - } - case MPCTE_INTSRC: - { - HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry); - Entry += sizeof(MP_CONFIGURATION_INTSRC); - Count += sizeof(MP_CONFIGURATION_INTSRC); - break; - } - case MPCTE_LINTSRC: - { - HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry); - Entry += sizeof(MP_CONFIGURATION_INTLOCAL); - Count += sizeof(MP_CONFIGURATION_INTLOCAL); - break; - } - default: - DbgPrint("Unknown entry in MPC table\n"); - KEBUGCHECK(0); - } - } -} - -static VOID HaliConstructDefaultIOIrqMPTable(ULONG Type) -{ - MP_CONFIGURATION_INTSRC intsrc; - ULONG i; - - intsrc.Type = MPCTE_INTSRC; - intsrc.IrqFlag = 0; /* conforming */ - intsrc.SrcBusId = 0; - intsrc.DstApicId = IOAPICMap[0].ApicId; - - intsrc.IrqType = INT_VECTORED; - for (i = 0; i < 16; i++) { - switch (Type) { - case 2: - if (i == 0 || i == 13) - continue; /* IRQ0 & IRQ13 not connected */ - /* Fall through */ - default: - if (i == 2) - continue; /* IRQ2 is never connected */ - } - - intsrc.SrcBusIrq = i; - intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */ - HaliMPIntSrcInfo(&intsrc); - } - - intsrc.IrqType = INT_EXTINT; - intsrc.SrcBusIrq = 0; - intsrc.DstApicInt = 0; /* 8259A to INTIN0 */ - HaliMPIntSrcInfo(&intsrc); -} - -static VOID HaliConstructDefaultISAMPTable(ULONG Type) -{ - MP_CONFIGURATION_PROCESSOR processor; - MP_CONFIGURATION_BUS bus; - MP_CONFIGURATION_IOAPIC ioapic; - MP_CONFIGURATION_INTLOCAL lintsrc; - ULONG linttypes[2] = { INT_EXTINT, INT_NMI }; - ULONG i; - - /* - * 2 CPUs, numbered 0 & 1. - */ - processor.Type = MPCTE_PROCESSOR; - /* Either an integrated APIC or a discrete 82489DX. */ - processor.ApicVersion = Type > 4 ? 0x10 : 0x01; - processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP; - /* FIXME: Get this from the bootstrap processor */ - processor.CpuSignature = 0; - processor.FeatureFlags = 0; - processor.Reserved[0] = 0; - processor.Reserved[1] = 0; - for (i = 0; i < 2; i++) - { - processor.ApicId = i; - HaliMPProcessorInfo(&processor); - processor.CpuFlags &= ~CPU_FLAG_BSP; - } - - bus.Type = MPCTE_BUS; - bus.BusId = 0; - switch (Type) - { - default: - DPRINT("Unknown standard configuration %d\n", Type); - /* Fall through */ - case 1: - case 5: - memcpy(bus.BusType, "ISA ", 6); - break; - case 2: - case 6: - case 3: - memcpy(bus.BusType, "EISA ", 6); - break; - case 4: - case 7: - memcpy(bus.BusType, "MCA ", 6); - } - HaliMPBusInfo(&bus); - if (Type > 4) - { - bus.Type = MPCTE_BUS; - bus.BusId = 1; - memcpy(bus.BusType, "PCI ", 6); - HaliMPBusInfo(&bus); - } - - ioapic.Type = MPCTE_IOAPIC; - ioapic.ApicId = 2; - ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01; - ioapic.ApicFlags = MP_IOAPIC_USABLE; - ioapic.ApicAddress = IOAPIC_DEFAULT_BASE; - HaliMPIOApicInfo(&ioapic); - - /* - * We set up most of the low 16 IO-APIC pins according to MPS rules. - */ - HaliConstructDefaultIOIrqMPTable(Type); - - lintsrc.Type = MPCTE_LINTSRC; - lintsrc.IrqType = 0; - lintsrc.IrqFlag = 0; /* conforming */ - lintsrc.SrcBusId = 0; - lintsrc.SrcBusIrq = 0; - lintsrc.DstApicId = MP_APIC_ALL; - for (i = 0; i < 2; i++) - { - lintsrc.IrqType = linttypes[i]; - lintsrc.DstApicLInt = i; - HaliMPIntLocalInfo(&lintsrc); - } -} - - -BOOLEAN -HaliScanForMPConfigTable(ULONG Base, - ULONG Size) -/* - PARAMETERS: - Base = Base address of region - Size = Length of region to check - RETURNS: - TRUE if a valid MP configuration table was found - */ -{ - PULONG bp = (PULONG)Base; - MP_FLOATING_POINTER* mpf; - - while (Size > 0) - { - if (*bp == MPF_SIGNATURE) - { - DbgPrint("Found MPF signature at %x, checksum %x\n", bp, - MPChecksum((PUCHAR)bp, 16)); - if (MPChecksum((PUCHAR)bp, 16) == 0) - { - mpf = (MP_FLOATING_POINTER*)bp; - - DbgPrint("Intel MultiProcessor Specification v1.%d compliant system.\n", - mpf->Specification); - - if (mpf->Feature2 & FEATURE2_IMCRP) { - APICMode = amPIC; - DPRINT("Running in IMCR and PIC compatibility mode.\n"); - } else { - APICMode = amVWIRE; - DPRINT("Running in Virtual Wire compatibility mode.\n"); - } - - switch (mpf->Feature1) - { - case 0: - /* Non standard configuration */ - break; - case 1: - DPRINT("ISA\n"); - break; - case 2: - DPRINT("EISA with no IRQ8 chaining\n"); - break; - case 3: - DPRINT("EISA\n"); - break; - case 4: - DPRINT("MCA\n"); - break; - case 5: - DPRINT("ISA and PCI\n"); - break; - case 6: - DPRINT("EISA and PCI\n"); - break; - case 7: - DPRINT("MCA and PCI\n"); - break; - default: - DbgPrint("Unknown standard configuration %d\n", mpf->Feature1); - return FALSE; - } - - CPUCount = 0; - IOAPICCount = 0; - IRQCount = 0; - - if ((mpf->Feature1 == 0) && (mpf->Address)) { - HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)mpf->Address); - } else { - HaliConstructDefaultISAMPTable(mpf->Feature1); - } - - return TRUE; - } - } - bp += 4; - Size -= 16; - } - return FALSE; -} - -VOID -HalpInitMPS(VOID) -{ - USHORT EBDA; - static BOOLEAN MPSInitialized = FALSE; - - - /* Only initialize MP system once. Once called the first time, - each subsequent call is part of the initialization sequence - for an application processor. */ - - DPRINT("HalpInitMPS()\n"); - - - if (MPSInitialized) - { - KEBUGCHECK(0); - } - - MPSInitialized = TRUE; - - /* - Scan the system memory for an MP configuration table - 1) Scan the first KB of system base memory - 2) Scan the last KB of system base memory - 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh - 4) Scan the Extended BIOS Data Area - */ - - if (!HaliScanForMPConfigTable(0x0, 0x400)) - { - if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) - { - if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) - { - EBDA = *((PUSHORT)0x040E); - EBDA <<= 4; - if (!HaliScanForMPConfigTable((ULONG)EBDA, 0x1000)) - { - DbgPrint("No multiprocessor compliant system found.\n"); - KEBUGCHECK(0); - } - } - } - } - - /* Setup IRQ to vector translation map */ - memset(&IRQVectorMap, 0, sizeof(IRQVectorMap)); - - /* Setup interrupt handlers */ - SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG)MpsTimerInterrupt); - SetInterruptGate(ERROR_VECTOR, (ULONG)MpsErrorInterrupt); - SetInterruptGate(SPURIOUS_VECTOR, (ULONG)MpsSpuriousInterrupt); - SetInterruptGate(IPI_VECTOR, (ULONG)MpsIpiInterrupt); - -} - -VOID -HaliReconfigurePciInterrupts(VOID) -{ - ULONG i; - - for (i = 0; i < IRQCount; i++) - { - if (BUSMap[IRQMap[i].SrcBusId] == MP_BUS_PCI) - { - DPRINT("%02x: IrqType %02x, IrqFlag %02x, SrcBusId %02x, SrcBusIrq %02x, DstApicId %02x, DstApicInt %02x\n", - i, IRQMap[i].IrqType, IRQMap[i].IrqFlag, IRQMap[i].SrcBusId, - IRQMap[i].SrcBusIrq, IRQMap[i].DstApicId, IRQMap[i].DstApicInt); - - if(1 != HalSetBusDataByOffset(PCIConfiguration, IRQMap[i].SrcBusId, (IRQMap[i].SrcBusIrq >> 2) & 0x1f, &IRQMap[i].DstApicInt, 0x3c /*PCI_INTERRUPT_LINE*/, 1)) - { - CHECKPOINT; - } - } - } - -} - /* EOF */