Windows-Server-2003/base/hals/inc/ntapic.inc

863 lines
20 KiB
PHP

;/*++
;
;Module Name:
;
; ntapic.inc
;
;Abstract:
;
; This header file is intended to be included by any HAL
; that uses APICs.
;
;Author:
;
; Ron Mosgrove (Intel)
;
;Environment:
;
; Kernel mode only.
;
;Revision History:
;
; Separated out from pcmp_nt.inc -- 6-2-98 (jakeo)
;
;
if 0 ; Begin C only code */
#if !defined(_NTAPIC_INC_)
#define _NTAPIC_INC_ 1
//#define DEBUGGING 1
#ifndef DBGMSG
#ifdef DEBUGGING
extern CHAR Cbuf[];
#define DBGMSG(x) DbgPrint(x);
#else
#define DBGMSG(x)
#endif
#endif
//
// To allow the user to specify command line options to the HAL.
//
#define USER_SETABLE_OPTIONS
// #define BUILD_FOR_OLD_IDW
//
// Default BusType
//
#ifndef MCA
#define DEFAULT_PC_BUS Eisa
#else
#define DEFAULT_PC_BUS MicroChannel
#endif
//
// Well known virtual address of local processor apic
//
#if defined(_WIN64)
#define LOCALAPIC 0xfffffffffffe0000
#else
#define LOCALAPIC 0xfffe0000
#endif
#define pLocalApic ((ULONG volatile *) LOCALAPIC)
#define LOCAL_APIC(x) (*((ULONG volatile *)&pLocalApic[(x)/sizeof(ULONG)]))
//
// Additional CpuFlags Bits used by NT in PC+MP Table
//
#define CPU_NT_STARTED 0x40 // CPU Has Been Started
#define CPU_NT_RUNNING 0x80 // CPU is Runing NT
#define MAX_PROCESSORS 32
#define MAX_CLUSTERS 15
#define MAX_IOAPICS 64
//
// This OS specific structure holds useful MP information. This information
// is obtained from the PC+MP table and stored here for convenience.
//
typedef struct HalpMpInfo {
ULONG ApicVersion; // 82489Dx or Not
ULONG ProcessorCount; // Number of Enabled Processors
ULONG NtProcessors; // Number of Running Processors
ULONG BusCount; // Number of buses in system
ULONG IOApicCount; // Number of Io Apics in system
ULONG IntiCount; // Number of Io Apic interrupt input entries
ULONG LintiCount; // Number of Local Apic interrupt input entries
ULONG IMCRPresent; // Indicates if the IMCR is present
ULONG LocalApicBase; // Base of local APIC
PULONG IoApicBase[MAX_IOAPICS]; // The virtual addresses of the IoApics
ULONG IoApicPhys[MAX_IOAPICS]; // The physical addresses of the IoApics
#ifdef ACPI_HAL
ULONG IoApicIntiBase[MAX_IOAPICS]; // The 'number' of the first INTI -- only used for ACPI
#else
PPCMPPROCESSOR ProcessorEntryPtr; // Ptr to 1st PC+MP processor entry
PPCMPBUS BusEntryPtr; // Ptr to 1st PC+MP bus entry
PPCMPIOAPIC IoApicEntryPtr; // Ptr to 1st PC+MP IoApic entry
PPCMPINTI IntiEntryPtr; // Ptr to 1st PC+MP Inti entry
PPCMPLINTI LintiEntryPtr; // Ptr to 1st PC+MP Linti entry
PMPS_EXTENTRY ExtensionTable; // Ptr to 1st extension table entry
PMPS_EXTENTRY EndOfExtensionTable;
#endif
} MP_INFO, *PMP_INFO;
typedef struct {
PUCHAR PcMpType;
BOOLEAN PhysicalInstance;
UCHAR Level;
INTERFACE_TYPE NtType;
PINSTALL_BUS_HANDLER NewInstance;
BUS_DATA_TYPE NtConfig;
ULONG BusExtensionSize;
} PCMPBUSTRANS, *PPCMPBUSTRANS;
#define CFG_MUST_BE 0x02
#define CFG_ERROR 0x80
#define CFG_HIGH 0x01
#define CFG_LOW 0x00
#define CFG_EDGE 0x00
#define CFG_LEVEL 0x01
#define CFG_MB_EDGE (CFG_MUST_BE | CFG_EDGE)
#define CFG_MB_LEVEL (CFG_MUST_BE | CFG_LEVEL)
#define CFG_ERR_EDGE (CFG_ERROR | CFG_EDGE)
#define CFG_ERR_LEVEL (CFG_ERROR | CFG_LEVEL)
#define CFG_ERR_MB_EDGE (CFG_ERROR | CFG_MUST_BE | CFG_EDGE)
#define CFG_ERR_MB_LEVEL (CFG_ERROR | CFG_MUST_BE | CFG_LEVEL)
#define CFG_TYPE(a) (a & 1)
typedef union _INTERRUPT_DEST {
union _Cluster {
struct _Hw {
UCHAR DestId:4;
UCHAR ClusterId:4;
} Hw;
UCHAR AsUchar;
} Cluster;
UCHAR LogicalId;
} INTERRUPT_DEST, *PINTERRUPT_DEST;
#if defined(_X86_)
//
// The kernel leaves some space (64 byte) of the PCR for the HAL to use
// as it needs. Currently this space is used for some efficiency in
// some of the MP specific code and is highly implementation-dependent.
//
typedef struct _HALPCR {
UCHAR PcrNumber; // Processor's number
UCHAR ShortDpc; // Short circut dpc interrupt
UCHAR DpcPending; // Dpc interrupt pending
UCHAR Reserved; // force dword alignment
//
// The next three dwords are used to manipulate the APIC counter
//
ULONG ApicClockFreqHz; // Counter Freq in Hertz
ULONG ApicClockFreqKhz; // Counter Freq in Khertz (rounded)
ULONG ProfileCountDown; // Current Countdown Interval
ULONGLONG TSCHz; // Time stamp counter hertz
ULONG PerfCounterLow; // PerProcessor Counter
ULONG PerfCounterHigh;
} HALPCR, *PHALPCR;
#elif defined(_AMD64_)
typedef struct _HALPCR {
ULONG64 PerfCounter;
ULONG64 TSCHz; // time stamp counter frequency
ULONG ProfileCountDown; // current profile countdown interval
ULONG ApicClockFreqHz; // counter frequency
ULONG StallScaleFactor;
ULONG ApicId; // APIC Id assigned this processor
} HALPCR, *PHALPCR;
C_ASSERT(sizeof(HALPCR) <= RTL_FIELD_SIZE(KPCR,HalReserved));
#else
#error "Platform not supported"
#endif
//
// The kernel leaves some space (64 byte) of the PCRB for the HAL to use
// as it needs. Currently this space is used for some efficiency in
// some of the MP specific code and is highly implementation-dependent.
//
typedef struct {
UCHAR PCMPApicID;
UCHAR na[3];
} HALPRCB, *PHALPRCB;
#if defined(_AMD64_)
#define ZERO_VECTOR 0x00 // IRQL 0 placeholder
#define APC_VECTOR 0x1f // IRQL 1 APC
#define DPC_VECTOR 0x2f // IRQL 2 DPC
#define APIC_SPURIOUS_VECTOR 0x3f // IRQL 3 Spurious handler
#define APIC_REBOOT_VECTOR 0x50 // IRQL 5 Vector used to reboot
#define APIC_GENERIC_VECTOR 0xC1 // IRQL 12 broadcast function call
#define APIC_CLOCK_VECTOR 0xD1 // IRQL 13 APIC INTI0 - CLOCK2_LEVEL
#define APIC_SYNCH_VECTOR 0xD1 // IRQL 13 IPI_LEVEL-1
#define APIC_IPI_VECTOR 0xE1 // IRQL 14 APIC IPI
#define APIC_FAULT_VECTOR 0xE3 // IRQL 14
#define POWERFAIL_VECTOR 0xEF // IRQL 14 reserved. not used
#define APIC_PROFILE_VECTOR 0xFD // IRQL 15
#define APIC_PERF_VECTOR 0xFE // IRQL 15
#define NMI_VECTOR 0xFF // IRQL 15
//
// The APIC hard-wires the four low-order bits of the spurious interrupt
// vector to 1.
//
C_ASSERT((APIC_SPURIOUS_VECTOR & 0x0f) == 0x0f);
#else
//
// interrupt vector definitions for C
//
#define ZERO_VECTOR 0x00 // IRQL 00 placeholder
#define APIC_SPURIOUS_VECTOR 0x1f // IRQL Spurious handler
#define APC_VECTOR 0x3D // IRQL 01 APC
#define DPC_VECTOR 0x41 // IRQL 02 DPC
#define APIC_REBOOT_VECTOR 0x50 // IRQL Vector used to reboot
#define APIC_GENERIC_VECTOR 0xC1 // IRQL 27 broadcast function call
#define APIC_CLOCK_VECTOR 0xD1 // IRQL 28 APIC INTI0 - CLOCK2_LEVEL
//
// If MP, define APIC_SYNCH_LEVEL as SYNCH_LEVEL, otherwise define
// to be the same as DPC_LEVEL.
//
#if (SYNCH_LEVEL != DISPATCH_LEVEL)
#define APIC_SYNCH_VECTOR 0xC1 // IRQL 28 IPI_LEVEL-1
#else
#define APIC_SYNCH_VECTOR DPC_VECTOR // IRQL 02 if UNIPROCESSOR
#endif
#define APIC_IPI_VECTOR 0xE1 // IRQL 29 APIC IPI
#define APIC_FAULT_VECTOR 0xE3 //
#define POWERFAIL_VECTOR 0xEF // IRQL 30 reserved. not used
#define APIC_PROFILE_VECTOR 0xFD // IRQL 31
#define APIC_PERF_VECTOR 0xFE // IRQL 31
#define NMI_VECTOR 0xFF // IRQL 31
#endif
//
// 8259/ISP interrupt controller register addresses
//
#define PIC1_PORT0 0x20
#define PIC1_PORT1 0x21
#define PIC2_PORT0 0xA0
#define PIC2_PORT1 0xA1
#define PIC_SLAVE_IRQ 2
#define RTC_IRQ 8
#define PIC1_ELCR_PORT 0x04D0 // ISP edge/level control registers
#define PIC2_ELCR_PORT 0x04D1
#define PIC1_SPURIOUS_VECTOR 0x37
//
// Defines for HalpFeatureBits
//
extern ULONG HalpFeatureBits;
//
//
//
#if defined(_AMD64_) && defined(NT_UP)
#define HalpAcquireHighLevelLock(lock) HalpDisableInterrupts()
#define HalpReleaseHighLevelLock(lock,irql) HalpRestoreInterrupts(irql)
#else
ULONG FASTCALL HalpAcquireHighLevelLock(PKSPIN_LOCK);
VOID FASTCALL HalpReleaseHighLevelLock(PKSPIN_LOCK, ULONG);
#endif
extern KSPIN_LOCK HalpAccountingLock;
extern KAFFINITY HalpActiveProcessors;
//
// Prototypes
//
#define MAX_INTI (MAX_IOAPICS*32) // Max interrupt inputs from APICs
#define MAX_SOURCE_IRQS MAX_INTI // Max different interrupts supported
//
// HalVectorToIDTEntry(vector) is defined in i386.h, because the kernel needs
// it.
#define MAX_NODES MAX_PROCESSORS
#define HalpVectorToNode(vector) ((vector)>>8)
#define HalpVector(node, idtentry) ((node)<<8|(idtentry))
extern struct HalpMpInfo HalpMpInfoTable;
extern UCHAR HalpMaxProcsPerCluster;
extern BOOLEAN HalpELCRChecked;
extern USHORT HalpGlobal8259Mask;
extern USHORT HalpVectorToINTI[];
extern UCHAR HalpInitLevel[4][4];
extern UCHAR HalpDevPolarity[4][2];
extern UCHAR HalpDevLevel[2][4];
//
// Initialized from MPS table
//
typedef struct _INTI_INFO {
UCHAR Type:4;
UCHAR Level:2;
UCHAR Polarity:2;
UCHAR Destinations;
USHORT Entry;
} INTI_INFO, *PINTI_INFO;
extern INTI_INFO HalpIntiInfo[];
extern USHORT HalpMaxApicInti[];
extern PCMPBUSTRANS HalpTypeTranslation[];
extern ULONG HalpIpiClock;
#define BusIrq2Id(bus,no,irq) \
((bus << 16) | (no << 8) | irq)
#define Id2BusIrq(id) \
(id & 0xff)
VOID
HalpInitIntiInfo (
VOID
);
ULONG
HalpGetIoApicId(
ULONG ApicNo
);
VOID
HalpSet8259Mask(
IN USHORT Mask
);
VOID
HalpInitializeLocalUnit (
VOID
);
VOID
HalpInitializeIOUnits (
VOID
);
VOID
HalpRestoreIoApicRedirTable (
VOID
);
VOID
HalpEnableNMI (
VOID
);
VOID
HalpEnableLocalNmiSources(
VOID
);
VOID
HalpSet8259Mask(
IN USHORT Mask
);
BOOLEAN
HalpGetApicInterruptDesc (
IN INTERFACE_TYPE BusType,
IN ULONG BusNumber,
IN ULONG BusInterruptLevel,
OUT PUSHORT PcMpInti
);
VOID
HalpCheckELCR (
VOID
);
VOID
HalpGenericCall (
VOID (*Fnc)(ULONG_PTR),
ULONG Context,
KAFFINITY Processors
);
VOID
HalpPollForBroadcast (
VOID
);
ULONG
FASTCALL
HalpWaitForPending (
IN ULONG Count,
IN volatile ULONG *LuICR
);
//
// Warning 4131 is "uses old-style declarator"
//
#pragma warning(disable:4131)
//
// Warning 4218 is "nonstandard extension used"
//
#pragma warning(disable:4218)
HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpPerfInterrupt);
VOID
HalpEnablePerfInterupt (
ULONG_PTR Context
);
VOID
HalpEnableNMI (
VOID
);
NTSTATUS
HalpSetSystemInformation (
IN HAL_SET_INFORMATION_CLASS InformationClass,
IN ULONG BufferSize,
IN PVOID Buffer
);
ULONG
HalpInti2BusInterruptLevel(
ULONG Inti
);
VOID
HalpUnMapIOApics(
VOID
);
VOID
HalpInitializeIOUnits (
VOID
);
VOID
HalpPostSleepMP(
IN LONG NumberProcessors,
IN volatile PLONG Number
);
VOID
HalpSetRedirEntry (
IN USHORT InterruptInput,
IN ULONG Entry,
IN ULONG Destination
);
VOID
HalpGetRedirEntry (
IN USHORT InterruptInput,
IN PULONG Entry,
IN PULONG Destination
);
/*++
HalpStallWhileApicBusy (
VOID
)
Routine Description:
This routine waits until the local apic has completed sending
an IPI.
Parameters:
None.
Return Value:
None.
--*/
#define HalpStallWhileApicBusy() \
while ((LOCAL_APIC(LU_INT_CMD_LOW) & DELIVERY_PENDING) != 0) { }
#if defined(_AMD64_)
#define HalpGetHalPcr(pcr) ((PHALPCR)(pcr->HalReserved))
#define HalpGetCurrentHalPcr() HalpGetHalPcr(KeGetPcr())
#endif
#endif // _NTAPIC_INC_
/*
endif
;
; Begin assembly part of the definitions
;
;
; Well known virtual address of local processor apic
;
LOCALAPIC equ 0fffe0000h
APIC equ ds:[LOCALAPIC]
DEBUGGING equ 0
if DEBUGGING
IRQL_METRICS equ 0
endif
;
; To allow the user to specify command line options to the HAL.
;
USER_SETABLE_OPTIONS equ 1
MAX_PROCESSORS equ 32
MAX_NODES equ MAX_PROCESSORS
MAX_IOAPICS equ 64
;
; This OS specific structure holds useful MP information. This information
; is obtained from the PC+MP table and stored here for convenience.
;
HalpMpInfo struc
ApicVersion dd 0 ; 82489Dx or Not
ProcessorCount dd 0 ; Number of Enabled Processors
NtProcessors dd 0 ; Number of Running Processors
BusCount dd 0 ; Number of buses in system
IOApicCount dd 0 ; Number of Io Apics in system
IntiCount dd 0 ; Num of Io Apic interrupt inputs
LintiCount dd 0 ; Num of Local Apic interrupt inputs
IMCRPresent dd 0 ; Indicates if the IMCR is present
LocalApicBase dd 0 ; Base of local apic
IoApicBase dd MAX_IOAPICS dup (0) ; Virtual addresses of IoApics
IoApicPhys dd MAX_IOAPICS dup (0) ; Physical addresses of IoApics
ifdef ACPI_HAL
IoApicIntiBase dd MAX_IOAPICS dup (0) ; ACPI only. First GSIV.
else
ProcessorEntryPtr dd 0 ; Ptr to 1st PC+MP processor entry
BusEntryPtr dd 0 ; Ptr to 1st PC+MP bus entry
IoApicEntryPtr dd 0 ; Ptr to 1st PC+MP IoApic entry
IntiEntryPtr dd 0 ; Ptr to 1st PC+MP Inti entry
LintiEntryPtr dd 0 ; Ptr to 1st PC+MP Linti entry
ExtensionTable dd 0 ; Ptr to 1st extension table entry
EndExtensionTable dd 0 ; Ptr to 1st extension table entry
endif
HalpMpInfo ends
;
; interrupt vector definitions for assembler
;
ZERO_VECTOR equ 000h ; IRQL 00 placeholder
APIC_SPURIOUS_VECTOR equ 01fh ; Vector used for spurious handler
APC_VECTOR equ 03Dh ; IRQL 01 APC
DPC_VECTOR equ 041h ; IRQL 02 DPC
APIC_REBOOT_VECTOR equ 050h ; Vector used to reboot
DEVICE_LEVEL1 equ 051h
DEVICE_LEVEL2 equ 061h
DEVICE_LEVEL3 equ 071h
DEVICE_LEVEL4 equ 081h
DEVICE_LEVEL5 equ 091h
DEVICE_LEVEL6 equ 0A1h
DEVICE_LEVEL7 equ 0B1h
APIC_GENERIC_VECTOR equ 0C1h ; IRQL 27 broadcast function call
APIC_CLOCK_VECTOR equ 0D1h ; IRQL 28 APIC INTI0 - CLOCK2_LEVEL
if SYNCH_LEVEL-DISPATCH_LEVEL
APIC_SYNCH_VECTOR equ 0C1h ; IRQL 28 IPI_LEVEL-1
else
APIC_SYNCH_VECTOR equ DPC_VECTOR
endif
APIC_IPI_VECTOR equ 0E1h ; IRQL 29 APIC IPI
APIC_FAULT_VECTOR equ 0E3h ;
POWERFAIL_VECTOR equ 0EFh ; IRQL 30 reserved
APIC_PROFILE_VECTOR equ 0FDh ; IRQL 27
APIC_PERF_VECTOR equ 0FEh ; IRQL 27
NMI_VECTOR equ 0FFh ; IRQL 31
HAL_PROFILE_LEVEL equ HIGH_LEVEL
;
; 8259/ISP interrupt controller register addresses
;
PIC1_PORT0 equ 020H
PIC1_PORT1 equ 021H
PIC2_PORT0 equ 0A0H
PIC2_PORT1 equ 0A1H
PIC1_ELCR_PORT equ 04D0H ; ISP edge/level control registers
PIC2_ELCR_PORT equ 04D1H
;
; Initialization control words for the PICs
;
ICW1_ICW4_NEEDED equ 01H
ICW1_CASCADE equ 00H
ICW1_INTERVAL8 equ 00H
ICW1_LEVEL_TRIG equ 08H
ICW1_EDGE_TRIG equ 00H
ICW1_ICW equ 10H
ICW4_8086_MODE equ 001H
ICW4_AUTO_EOI equ 002H
ICW4_NORM_EOI equ 000H
ICW4_NON_BUF_MODE equ 000H
ICW4_SPEC_FULLY_NESTED equ 010H
ICW4_NOT_SPEC_FULLY_NESTED equ 000H
PIC_SLAVE_IRQ equ 2
PIC1_BASE equ 30H
PIC2_BASE equ 38H
PIC_CLOCK_VECTOR equ 30H
PIC_DMA_VECTOR equ 3DH
PIC1_SPURIOUS_VECTOR equ 37H
PIC2_SPURIOUS_VECTOR equ 3FH
;
; Operation control words for the PICs
;
OCW2_NON_SPECIFIC_EOI equ 020H
OCW2_SPECIFIC_EOI equ 060H
OCW3_READ_ISR equ 0BH
OCW3_READ_IRR equ 0AH
OCW3_READ_POLLED equ 0CH
;
; A couple of definitions that shouldn't change on a Compatible
;
TimerPicInti equ 0
DmaPic2Inti equ 5
SlavePicInti equ 2
DmaPicInti equ 13 ; DMA input relative to 0
cr equ 0ah
lf equ 0dh
;
; The kernel leaves some space (64 byte) of the PCR for the HAL to use
; as it needs. Currently this space is used for some efficiency in
; some of the MP specific code and is highly implementation-dependent.
;
PcrE struc
PcrNumber db 0 ; Processor's number
ShortDpc db 0 ; Short circut dpc interrupt
DpcPending db 0 ; Dpc interrupt pending
db 0 ; force dword alignment
;
; The next three dwords are used to manipulate the APIC counter
;
ApicClockFreqHz dd 0 ; Counter Freq in Hertz
ApicClockFreqKhz dd 0 ; Counter Freq in Khertz (rounded)
ProfileCountDown dd 0 ; Current Countdown Interval
TSCHz dq 0 ; Time stamp counter hertz
PerfCounterLow dd 0 ; PerProcessor Counter
PerfCounterHigh dd 0 ;
; ProfileCountLast dd 0
OEMPcr db size OEMPcr dup(?)
PcrE ends
PrcbE struc
PrcbPCMPApicID db 0 ; Processor's PCMP ApicID
db 3 dup (0) ; force dword alignment
PrcbE ends
MsrTSC equ 10h
;++
;
; STALL_WHILE_APIC_BUSY
;
; Wait for the APIC DELIVERY_PENDING bit to be clear
;
;--
STALL_WHILE_APIC_BUSY macro
local a, b
if 0
push eax
mov eax, 5000h
a: test dword ptr APIC[LU_INT_CMD_LOW],DELIVERY_PENDING
jz short b
dec eax
jnz short a
int 3
jmp short a
b: pop eax
else
a: test dword ptr APIC[LU_INT_CMD_LOW],DELIVERY_PENDING
jnz short a
endif
endm
;++
;
; APICFIX
;
; Macro Description:
;
; For internal testing use
;
; Arguments:
;
; None
;
;--
APICFIX macro reg1
; inc dword ptr PCR[PcKernel] ; Count # of times patched
endm
;++
;
; CHECKTPR
;
; Macro Description:
;
; For internal testing use
;
; Arguments:
;
; None
;
;--
CHECKTPR macro reg1, reg2
if DBG
cmp reg1, reg2
je short @f
int 3
@@:
endif
endm
;++
;
; IODELAY
;
; Macro Description:
;
; This macro delays the CPU just a little so the PIC has time to settle
; between IO port accesses. Current mechanism is to read an APIC local
; unit register (eax is saved). Note that PUSHF/POPF is worth 10 clocks.
;
; Arguments:
;
; None
;
;--
IODELAY macro
pushf
popf
jmp $+2
endm
;++
;
; SET_8259_MASK
;
; Macro Description:
;
; This macro sets the 8259 PIC interrupt mask register with the mask
; passed from eax register. Bits 7:0 are the mask for the master PIC
; and bits 15:8 are the mask for the slave PIC.
;
; Arguments:
;
; (eax) = mask for setting 8259 PIC interrupt mask register
;
;--
SET_8259_MASK macro
out PIC1_PORT1, al ; set master 8259 mask
shr eax, 8 ; shift slave 8259 mask to al
out PIC2_PORT1, al ; set slave 8259 mask
endm
;*/