mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
Split some of the halmp files according its functions.
svn path=/trunk/; revision=13868
This commit is contained in:
parent
63981fc041
commit
8399d9c123
12 changed files with 1917 additions and 1908 deletions
|
@ -165,7 +165,7 @@ static ULONG Read8254Timer(VOID)
|
|||
}
|
||||
|
||||
|
||||
static VOID WaitFor8254Wraparound(VOID)
|
||||
VOID WaitFor8254Wraparound(VOID)
|
||||
{
|
||||
ULONG CurCount, PrevCount = ~0;
|
||||
LONG Delta;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
101
reactos/hal/halx86/include/ioapic.h
Normal file
101
reactos/hal/halx86/include/ioapic.h
Normal file
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 <ddk/ntddk.h>
|
||||
#include <internal/i386/ps.h>
|
||||
|
||||
|
@ -36,22 +38,46 @@
|
|||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
712
reactos/hal/halx86/mp/ioapic.c
Normal file
712
reactos/hal/halx86/mp/ioapic.c
Normal file
|
@ -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 <ddk/ntddk.h>
|
||||
#include <hal.h>
|
||||
|
||||
#include <mps.h>
|
||||
#include <halirq.h>
|
||||
#include <apic.h>
|
||||
#include <ioapic.h>
|
||||
|
||||
#include <internal/ntoskrnl.h>
|
||||
#include <internal/i386/segment.h>
|
||||
#include <internal/ke.h>
|
||||
#include <internal/ps.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* 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 */
|
649
reactos/hal/halx86/mp/mpconfig.c
Normal file
649
reactos/hal/halx86/mp/mpconfig.c
Normal file
|
@ -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 <ddk/ntddk.h>
|
||||
#include <ntos/types.h>
|
||||
#include <hal.h>
|
||||
#include <mps.h>
|
||||
#include <apic.h>
|
||||
#include <ioapic.h>
|
||||
|
||||
//#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* 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 */
|
|
@ -19,6 +19,7 @@
|
|||
#include <hal.h>
|
||||
#include <mps.h>
|
||||
#include <apic.h>
|
||||
#include <ioapic.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue