Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3814 lines
79 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
amd64.h
Abstract:
This module contains the AMD64 hardware specific header file.
Author:
David N. Cutler (davec) 3-May-2000
Revision History:
--*/
#ifndef __amd64_
#define __amd64_
#if !(defined(_NTDRIVER_) || defined(_NTDDK_) || defined(_NTIFS_) || defined(_NTHAL_) || defined(_NTOSP_)) && !defined(_BLDR_)
#define ExRaiseException RtlRaiseException
#define ExRaiseStatus RtlRaiseStatus
#endif
// begin_ntddk begin_wdm begin_nthal begin_ntndis begin_ntosp
#if defined(_M_AMD64) && !defined(RC_INVOKED) && !defined(MIDL_PASS)
//
// Define intrinsic function to do in's and out's.
//
#ifdef __cplusplus
extern "C" {
#endif
UCHAR
__inbyte (
IN USHORT Port
);
USHORT
__inword (
IN USHORT Port
);
ULONG
__indword (
IN USHORT Port
);
VOID
__outbyte (
IN USHORT Port,
IN UCHAR Data
);
VOID
__outword (
IN USHORT Port,
IN USHORT Data
);
VOID
__outdword (
IN USHORT Port,
IN ULONG Data
);
VOID
__inbytestring (
IN USHORT Port,
IN PUCHAR Buffer,
IN ULONG Count
);
VOID
__inwordstring (
IN USHORT Port,
IN PUSHORT Buffer,
IN ULONG Count
);
VOID
__indwordstring (
IN USHORT Port,
IN PULONG Buffer,
IN ULONG Count
);
VOID
__outbytestring (
IN USHORT Port,
IN PUCHAR Buffer,
IN ULONG Count
);
VOID
__outwordstring (
IN USHORT Port,
IN PUSHORT Buffer,
IN ULONG Count
);
VOID
__outdwordstring (
IN USHORT Port,
IN PULONG Buffer,
IN ULONG Count
);
#ifdef __cplusplus
}
#endif
#pragma intrinsic(__inbyte)
#pragma intrinsic(__inword)
#pragma intrinsic(__indword)
#pragma intrinsic(__outbyte)
#pragma intrinsic(__outword)
#pragma intrinsic(__outdword)
#pragma intrinsic(__inbytestring)
#pragma intrinsic(__inwordstring)
#pragma intrinsic(__indwordstring)
#pragma intrinsic(__outbytestring)
#pragma intrinsic(__outwordstring)
#pragma intrinsic(__outdwordstring)
//
// Interlocked intrinsic functions.
//
#define InterlockedAnd _InterlockedAnd
#define InterlockedOr _InterlockedOr
#define InterlockedXor _InterlockedXor
#define InterlockedIncrement _InterlockedIncrement
#define InterlockedIncrementAcquire InterlockedIncrement
#define InterlockedIncrementRelease InterlockedIncrement
#define InterlockedDecrement _InterlockedDecrement
#define InterlockedDecrementAcquire InterlockedDecrement
#define InterlockedDecrementRelease InterlockedDecrement
#define InterlockedAdd _InterlockedAdd
#define InterlockedExchange _InterlockedExchange
#define InterlockedExchangeAdd _InterlockedExchangeAdd
#define InterlockedCompareExchange _InterlockedCompareExchange
#define InterlockedCompareExchangeAcquire InterlockedCompareExchange
#define InterlockedCompareExchangeRelease InterlockedCompareExchange
#define InterlockedAnd64 _InterlockedAnd64
#define InterlockedOr64 _InterlockedOr64
#define InterlockedXor64 _InterlockedXor64
#define InterlockedIncrement64 _InterlockedIncrement64
#define InterlockedDecrement64 _InterlockedDecrement64
#define InterlockedAdd64 _InterlockedAdd64
#define InterlockedExchange64 _InterlockedExchange64
#define InterlockedExchangeAcquire64 InterlockedExchange64
#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64
#define InterlockedCompareExchange64 _InterlockedCompareExchange64
#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64
#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64
#define InterlockedExchangePointer _InterlockedExchangePointer
#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer
#ifdef __cplusplus
extern "C" {
#endif
LONG
InterlockedAnd (
IN OUT LONG volatile *Destination,
IN LONG Value
);
LONG
InterlockedOr (
IN OUT LONG volatile *Destination,
IN LONG Value
);
LONG
InterlockedXor (
IN OUT LONG volatile *Destination,
IN LONG Value
);
LONG64
InterlockedAnd64 (
IN OUT LONG64 volatile *Destination,
IN LONG64 Value
);
LONG64
InterlockedOr64 (
IN OUT LONG64 volatile *Destination,
IN LONG64 Value
);
LONG64
InterlockedXor64 (
IN OUT LONG64 volatile *Destination,
IN LONG64 Value
);
LONG
InterlockedIncrement(
IN OUT LONG volatile *Addend
);
LONG
InterlockedDecrement(
IN OUT LONG volatile *Addend
);
LONG
InterlockedExchange(
IN OUT LONG volatile *Target,
IN LONG Value
);
LONG
InterlockedExchangeAdd(
IN OUT LONG volatile *Addend,
IN LONG Value
);
#if !defined(_X86AMD64_)
__forceinline
LONG
InterlockedAdd(
IN OUT LONG volatile *Addend,
IN LONG Value
)
{
return InterlockedExchangeAdd(Addend, Value) + Value;
}
#endif
LONG
InterlockedCompareExchange (
IN OUT LONG volatile *Destination,
IN LONG ExChange,
IN LONG Comperand
);
LONG64
InterlockedIncrement64(
IN OUT LONG64 volatile *Addend
);
LONG64
InterlockedDecrement64(
IN OUT LONG64 volatile *Addend
);
LONG64
InterlockedExchange64(
IN OUT LONG64 volatile *Target,
IN LONG64 Value
);
LONG64
InterlockedExchangeAdd64(
IN OUT LONG64 volatile *Addend,
IN LONG64 Value
);
#if !defined(_X86AMD64_)
__forceinline
LONG64
InterlockedAdd64(
IN OUT LONG64 volatile *Addend,
IN LONG64 Value
)
{
return InterlockedExchangeAdd64(Addend, Value) + Value;
}
#endif
LONG64
InterlockedCompareExchange64 (
IN OUT LONG64 volatile *Destination,
IN LONG64 ExChange,
IN LONG64 Comperand
);
PVOID
InterlockedCompareExchangePointer (
IN OUT PVOID volatile *Destination,
IN PVOID Exchange,
IN PVOID Comperand
);
PVOID
InterlockedExchangePointer(
IN OUT PVOID volatile *Target,
IN PVOID Value
);
#pragma intrinsic(_InterlockedAnd)
#pragma intrinsic(_InterlockedOr)
#pragma intrinsic(_InterlockedXor)
#pragma intrinsic(_InterlockedIncrement)
#pragma intrinsic(_InterlockedDecrement)
#pragma intrinsic(_InterlockedExchange)
#pragma intrinsic(_InterlockedExchangeAdd)
#pragma intrinsic(_InterlockedCompareExchange)
#pragma intrinsic(_InterlockedAnd64)
#pragma intrinsic(_InterlockedOr64)
#pragma intrinsic(_InterlockedXor64)
#pragma intrinsic(_InterlockedIncrement64)
#pragma intrinsic(_InterlockedDecrement64)
#pragma intrinsic(_InterlockedExchange64)
#pragma intrinsic(_InterlockedExchangeAdd64)
#pragma intrinsic(_InterlockedCompareExchange64)
#pragma intrinsic(_InterlockedExchangePointer)
#pragma intrinsic(_InterlockedCompareExchangePointer)
#ifdef __cplusplus
}
#endif
#endif // defined(_M_AMD64) && !defined(RC_INVOKED) && !defined(MIDL_PASS)
#if defined(_AMD64_)
//
// Types to use to contain PFNs and their counts.
//
typedef ULONG PFN_COUNT;
typedef LONG64 SPFN_NUMBER, *PSPFN_NUMBER;
typedef ULONG64 PFN_NUMBER, *PPFN_NUMBER;
//
// Define maximum size of flush multiple TB request.
//
#define FLUSH_MULTIPLE_MAXIMUM 32
//
// Indicate that the AMD64 compiler supports the allocate pragmas.
//
#define ALLOC_PRAGMA 1
#define ALLOC_DATA_PRAGMA 1
// end_ntddk end_nthal end_ntndis end_wdm end_ntosp
//
// Length on interrupt object dispatch code in longwords.
// (shielint) Reserve 9*4 space for ABIOS stack mapping. If NO
// ABIOS support the size of DISPATCH_LENGTH should be 74.
//
// begin_nthal
#define NORMAL_DISPATCH_LENGTH 106 // ntddk wdm
#define DISPATCH_LENGTH NORMAL_DISPATCH_LENGTH // ntddk wdm
// ntddk wdm
// begin_ntosp
//
// Define constants for bits in CR0.
//
#define CR0_PE 0x00000001 // protection enable
#define CR0_MP 0x00000002 // math present
#define CR0_EM 0x00000004 // emulate math coprocessor
#define CR0_TS 0x00000008 // task switched
#define CR0_ET 0x00000010 // extension type (80387)
#define CR0_NE 0x00000020 // numeric error
#define CR0_WP 0x00010000 // write protect
#define CR0_AM 0x00040000 // alignment mask
#define CR0_NW 0x20000000 // not write-through
#define CR0_CD 0x40000000 // cache disable
#define CR0_PG 0x80000000 // paging
//
// Define functions to read and write CR0.
//
#ifdef __cplusplus
extern "C" {
#endif
#define ReadCR0() __readcr0()
ULONG64
__readcr0 (
VOID
);
#define WriteCR0(Data) __writecr0(Data)
VOID
__writecr0 (
IN ULONG64 Data
);
#pragma intrinsic(__readcr0)
#pragma intrinsic(__writecr0)
//
// Define functions to read and write CR3.
//
#define ReadCR3() __readcr3()
ULONG64
__readcr3 (
VOID
);
#define WriteCR3(Data) __writecr3(Data)
VOID
__writecr3 (
IN ULONG64 Data
);
#pragma intrinsic(__readcr3)
#pragma intrinsic(__writecr3)
//
// Define constants for bits in CR4.
//
#define CR4_VME 0x00000001 // V86 mode extensions
#define CR4_PVI 0x00000002 // Protected mode virtual interrupts
#define CR4_TSD 0x00000004 // Time stamp disable
#define CR4_DE 0x00000008 // Debugging Extensions
#define CR4_PSE 0x00000010 // Page size extensions
#define CR4_PAE 0x00000020 // Physical address extensions
#define CR4_MCE 0x00000040 // Machine check enable
#define CR4_PGE 0x00000080 // Page global enable
#define CR4_FXSR 0x00000200 // FXSR used by OS
#define CR4_XMMEXCPT 0x00000400 // XMMI used by OS
//
// Define functions to read and write CR4.
//
#define ReadCR4() __readcr4()
ULONG64
__readcr4 (
VOID
);
#define WriteCR4(Data) __writecr4(Data)
VOID
__writecr4 (
IN ULONG64 Data
);
#pragma intrinsic(__readcr4)
#pragma intrinsic(__writecr4)
//
// Define functions to read and write CR8.
//
// CR8 is the APIC TPR register.
//
#define ReadCR8() __readcr8()
ULONG64
__readcr8 (
VOID
);
#define WriteCR8(Data) __writecr8(Data)
VOID
__writecr8 (
IN ULONG64 Data
);
#pragma intrinsic(__readcr8)
#pragma intrinsic(__writecr8)
#ifdef __cplusplus
}
#endif
// end_nthal end_ntosp
//
// External references to the code labels.
//
extern ULONG KiInterruptTemplate[NORMAL_DISPATCH_LENGTH];
// begin_ntddk begin_wdm begin_nthal begin_ntosp
//
// Interrupt Request Level definitions
//
#define PASSIVE_LEVEL 0 // Passive release level
#define LOW_LEVEL 0 // Lowest interrupt level
#define APC_LEVEL 1 // APC interrupt level
#define DISPATCH_LEVEL 2 // Dispatcher level
#define CLOCK_LEVEL 13 // Interval clock level
#define IPI_LEVEL 14 // Interprocessor interrupt level
#define POWER_LEVEL 14 // Power failure level
#define PROFILE_LEVEL 15 // timer used for profiling.
#define HIGH_LEVEL 15 // Highest interrupt level
// end_ntddk end_wdm end_ntosp
#if defined(NT_UP)
// synchronization level (UP)
#define SYNCH_LEVEL DISPATCH_LEVEL
#else
// synchronization level (MP)
#define SYNCH_LEVEL (IPI_LEVEL-2) // ntddk wdm ntosp
#endif
#define IRQL_VECTOR_OFFSET 2 // offset from IRQL to vector / 16
#define KiSynchIrql SYNCH_LEVEL // enable portable code
//
// Machine type definitions
//
#define MACHINE_TYPE_ISA 0
#define MACHINE_TYPE_EISA 1
#define MACHINE_TYPE_MCA 2
// end_nthal
//
// The previous values and the following are or'ed in KeI386MachineType.
//
#define MACHINE_TYPE_PC_AT_COMPATIBLE 0x00000000
#define MACHINE_TYPE_PC_9800_COMPATIBLE 0x00000100
#define MACHINE_TYPE_FMR_COMPATIBLE 0x00000200
extern ULONG KeI386MachineType;
// begin_nthal
//
// Define constants used in selector tests.
//
// N.B. MODE_MASK and MODE_BIT assumes that all code runs at either ring-0
// or ring-3 and is used to test the mode. RPL_MASK is used for merging
// or extracting RPL values.
//
#define MODE_BIT 0
#define MODE_MASK 1 // ntosp
#define RPL_MASK 3
//
// Startup count value for KeStallExecution. This value is used
// until KiInitializeStallExecution can compute the real one.
// Pick a value long enough for very fast processors.
//
#define INITIAL_STALL_COUNT 100
// end_nthal
//
// begin_nthal
//
// Macro to extract the high word of a long offset
//
#define HIGHWORD(l) \
((USHORT)(((ULONG)(l)>>16) & 0xffff))
//
// Macro to extract the low word of a long offset
//
#define LOWWORD(l) \
((USHORT)((ULONG)l & 0x0000ffff))
//
// Macro to combine two USHORT offsets into a long offset
//
#if !defined(MAKEULONG)
#define MAKEULONG(x, y) \
(((((ULONG)(x))<<16) & 0xffff0000) | \
((ULONG)(y) & 0xffff))
#endif
// end_nthal
//
// Request a software interrupt.
//
#define KiRequestSoftwareInterrupt(RequestIrql) \
HalRequestSoftwareInterrupt( RequestIrql )
// begin_ntddk begin_wdm begin_nthal begin_ntndis begin_ntosp
//
// I/O space read and write macros.
//
// The READ/WRITE_REGISTER_* calls manipulate I/O registers in MEMORY space.
//
// The READ/WRITE_PORT_* calls manipulate I/O registers in PORT space.
//
__forceinline
UCHAR
READ_REGISTER_UCHAR (
volatile UCHAR *Register
)
{
return *Register;
}
__forceinline
USHORT
READ_REGISTER_USHORT (
volatile USHORT *Register
)
{
return *Register;
}
__forceinline
ULONG
READ_REGISTER_ULONG (
volatile ULONG *Register
)
{
return *Register;
}
__forceinline
VOID
READ_REGISTER_BUFFER_UCHAR (
PUCHAR Register,
PUCHAR Buffer,
ULONG Count
)
{
__movsb(Buffer, Register, Count);
return;
}
__forceinline
VOID
READ_REGISTER_BUFFER_USHORT (
PUSHORT Register,
PUSHORT Buffer,
ULONG Count
)
{
__movsw(Buffer, Register, Count);
return;
}
__forceinline
VOID
READ_REGISTER_BUFFER_ULONG (
PULONG Register,
PULONG Buffer,
ULONG Count
)
{
__movsd(Buffer, Register, Count);
return;
}
__forceinline
VOID
WRITE_REGISTER_UCHAR (
PUCHAR Register,
UCHAR Value
)
{
*Register = Value;
StoreFence();
return;
}
__forceinline
VOID
WRITE_REGISTER_USHORT (
PUSHORT Register,
USHORT Value
)
{
*Register = Value;
StoreFence();
return;
}
__forceinline
VOID
WRITE_REGISTER_ULONG (
PULONG Register,
ULONG Value
)
{
*Register = Value;
StoreFence();
return;
}
__forceinline
VOID
WRITE_REGISTER_BUFFER_UCHAR (
PUCHAR Register,
PUCHAR Buffer,
ULONG Count
)
{
__movsb(Register, Buffer, Count);
StoreFence();
return;
}
__forceinline
VOID
WRITE_REGISTER_BUFFER_USHORT (
PUSHORT Register,
PUSHORT Buffer,
ULONG Count
)
{
__movsw(Register, Buffer, Count);
StoreFence();
return;
}
__forceinline
VOID
WRITE_REGISTER_BUFFER_ULONG (
PULONG Register,
PULONG Buffer,
ULONG Count
)
{
__movsd(Register, Buffer, Count);
StoreFence();
return;
}
__forceinline
UCHAR
READ_PORT_UCHAR (
PUCHAR Port
)
{
return __inbyte((USHORT)((ULONG64)Port));
}
__forceinline
USHORT
READ_PORT_USHORT (
PUSHORT Port
)
{
return __inword((USHORT)((ULONG64)Port));
}
__forceinline
ULONG
READ_PORT_ULONG (
PULONG Port
)
{
return __indword((USHORT)((ULONG64)Port));
}
__forceinline
VOID
READ_PORT_BUFFER_UCHAR (
PUCHAR Port,
PUCHAR Buffer,
ULONG Count
)
{
__inbytestring((USHORT)((ULONG64)Port), Buffer, Count);
return;
}
__forceinline
VOID
READ_PORT_BUFFER_USHORT (
PUSHORT Port,
PUSHORT Buffer,
ULONG Count
)
{
__inwordstring((USHORT)((ULONG64)Port), Buffer, Count);
return;
}
__forceinline
VOID
READ_PORT_BUFFER_ULONG (
PULONG Port,
PULONG Buffer,
ULONG Count
)
{
__indwordstring((USHORT)((ULONG64)Port), Buffer, Count);
return;
}
__forceinline
VOID
WRITE_PORT_UCHAR (
PUCHAR Port,
UCHAR Value
)
{
__outbyte((USHORT)((ULONG64)Port), Value);
return;
}
__forceinline
VOID
WRITE_PORT_USHORT (
PUSHORT Port,
USHORT Value
)
{
__outword((USHORT)((ULONG64)Port), Value);
return;
}
__forceinline
VOID
WRITE_PORT_ULONG (
PULONG Port,
ULONG Value
)
{
__outdword((USHORT)((ULONG64)Port), Value);
return;
}
__forceinline
VOID
WRITE_PORT_BUFFER_UCHAR (
PUCHAR Port,
PUCHAR Buffer,
ULONG Count
)
{
__outbytestring((USHORT)((ULONG64)Port), Buffer, Count);
return;
}
__forceinline
VOID
WRITE_PORT_BUFFER_USHORT (
PUSHORT Port,
PUSHORT Buffer,
ULONG Count
)
{
__outwordstring((USHORT)((ULONG64)Port), Buffer, Count);
return;
}
__forceinline
VOID
WRITE_PORT_BUFFER_ULONG (
PULONG Port,
PULONG Buffer,
ULONG Count
)
{
__outdwordstring((USHORT)((ULONG64)Port), Buffer, Count);
return;
}
// end_ntndis
//
// Get data cache fill size.
//
#if PRAGMA_DEPRECATED_DDK
#pragma deprecated(KeGetDcacheFillSize) // Use GetDmaAlignment
#endif
#define KeGetDcacheFillSize() 1L
// end_ntddk end_wdm end_nthal end_ntosp
//
// Fill TB entry and flush single TB entry.
//
#define KeFillEntryTb(Virtual) \
InvalidatePage(Virtual);
#if !defined(_NTHAL_) && !defined(RC_INVOKED) && !defined(MIDL_PASS)
__forceinline
VOID
KeFlushCurrentTb (
VOID
)
{
ULONG64 Cr4;
Cr4 = ReadCR4();
WriteCR4(Cr4 & ~CR4_PGE);
WriteCR4(Cr4);
return;
}
__forceinline
VOID
KiFlushProcessTb (
VOID
)
{
ULONG64 Cr3;
Cr3 = ReadCR3();
WriteCR3(Cr3);
return;
}
#else
// begin_nthal
NTKERNELAPI
VOID
KeFlushCurrentTb (
VOID
);
// end_nthal
#endif
#define KiFlushSingleTb(Virtual) InvalidatePage(Virtual)
//
// Data cache, instruction cache, I/O buffer, and write buffer flush routine
// prototypes.
//
// AMD64 has transparent caches, so these are noops.
#define KeSweepDcache(AllProcessors)
#define KeSweepCurrentDcache()
#define KeSweepIcache(AllProcessors)
#define KeSweepCurrentIcache()
#define KeSweepIcacheRange(AllProcessors, BaseAddress, Length)
// begin_ntddk begin_wdm begin_nthal begin_ntndis begin_ntosp
#define KeFlushIoBuffers(Mdl, ReadOperation, DmaOperation)
// end_ntddk end_wdm end_ntndis end_ntosp
#define KeYieldProcessor()
// end_nthal
//
// Define executive macros for acquiring and releasing executive spinlocks.
// These macros can ONLY be used by executive components and NOT by drivers.
// Drivers MUST use the kernel interfaces since they must be MP enabled on
// all systems.
//
#if defined(NT_UP) && !DBG && !defined(_NTDDK_) && !defined(_NTIFS_)
#if !defined(_NTDRIVER_)
#define ExAcquireSpinLock(Lock, OldIrql) (*OldIrql) = KeRaiseIrqlToDpcLevel();
#define ExReleaseSpinLock(Lock, OldIrql) KeLowerIrql((OldIrql))
#else
#define ExAcquireSpinLock(Lock, OldIrql) KeAcquireSpinLock((Lock), (OldIrql))
#define ExReleaseSpinLock(Lock, OldIrql) KeReleaseSpinLock((Lock), (OldIrql))
#endif
#define ExAcquireSpinLockAtDpcLevel(Lock)
#define ExReleaseSpinLockFromDpcLevel(Lock)
#else
// begin_wdm begin_ntddk begin_ntosp
#define ExAcquireSpinLock(Lock, OldIrql) KeAcquireSpinLock((Lock), (OldIrql))
#define ExReleaseSpinLock(Lock, OldIrql) KeReleaseSpinLock((Lock), (OldIrql))
#define ExAcquireSpinLockAtDpcLevel(Lock) KeAcquireSpinLockAtDpcLevel(Lock)
#define ExReleaseSpinLockFromDpcLevel(Lock) KeReleaseSpinLockFromDpcLevel(Lock)
// end_wdm end_ntddk end_ntosp
#endif
// begin_nthal
//
// The acquire and release fast lock macros disable and enable interrupts
// on UP nondebug systems. On MP or debug systems, the spinlock routines
// are used.
//
// N.B. Extreme caution should be observed when using these routines.
//
#if defined(_M_AMD64) && !defined(USER_MODE_CODE)
VOID
_disable (
VOID
);
VOID
_enable (
VOID
);
#pragma warning(push)
#pragma warning(disable:4164)
#pragma intrinsic(_disable)
#pragma intrinsic(_enable)
#pragma warning(pop)
#endif
// end_nthal
#if defined(NT_UP) && !DBG && !defined(USER_MODE_CODE)
#define ExAcquireFastLock(Lock, OldIrql) _disable()
#else
#define ExAcquireFastLock(Lock, OldIrql) \
ExAcquireSpinLock(Lock, OldIrql)
#endif
#if defined(NT_UP) && !DBG && !defined(USER_MODE_CODE)
#define ExReleaseFastLock(Lock, OldIrql) _enable()
#else
#define ExReleaseFastLock(Lock, OldIrql) \
ExReleaseSpinLock(Lock, OldIrql)
#endif
//
// The following function prototypes must be in this module so that the
// above macros can call them directly.
//
// begin_nthal
#if defined(NT_UP)
#define KiAcquireSpinLock(SpinLock)
#define KiReleaseSpinLock(SpinLock)
#else
#define KiAcquireSpinLock(SpinLock) KeAcquireSpinLockAtDpcLevel(SpinLock)
#define KiReleaseSpinLock(SpinLock) KeReleaseSpinLockFromDpcLevel(SpinLock)
#endif // defined(NT_UP)
// end_nthal
//
// Define query tick count macro.
//
// begin_ntddk begin_nthal begin_ntosp begin_wdm
#define KI_USER_SHARED_DATA 0xFFFFF78000000000UI64
#define SharedUserData ((KUSER_SHARED_DATA * const)KI_USER_SHARED_DATA)
#define SharedInterruptTime (KI_USER_SHARED_DATA + 0x8)
#define SharedSystemTime (KI_USER_SHARED_DATA + 0x14)
#define SharedTickCount (KI_USER_SHARED_DATA + 0x320)
#define KeQueryInterruptTime() *((volatile ULONG64 *)(SharedInterruptTime))
#define KeQuerySystemTime(CurrentCount) \
*((PULONG64)(CurrentCount)) = *((volatile ULONG64 *)(SharedSystemTime))
#define KeQueryTickCount(CurrentCount) \
*((PULONG64)(CurrentCount)) = *((volatile ULONG64 *)(SharedTickCount))
// end_ntddk end_nthal end_ntosp end_wdm
C_ASSERT((FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime) & 7) == 0);
C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime) == 0x8);
C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemTime) == 0x14);
C_ASSERT((FIELD_OFFSET(KUSER_SHARED_DATA, TickCount) & 7) == 0);
C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCount) == 0x320);
//
// Define query interrupt time macro.
//
C_ASSERT((FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime) & 7) == 0);
#define KiQueryInterruptTime(CurrentTime) \
((PLARGE_INTEGER)(CurrentTime))->QuadPart = *(PLONG64)(&SharedUserData->InterruptTime)
// begin_nthal begin_ntosp
//
// AMD64 hardware structures
//
// A Page Table Entry on an AMD64 has the following definition.
//
#define _HARDWARE_PTE_WORKING_SET_BITS 11
typedef struct _HARDWARE_PTE {
ULONG64 Valid : 1;
ULONG64 Write : 1; // UP version
ULONG64 Owner : 1;
ULONG64 WriteThrough : 1;
ULONG64 CacheDisable : 1;
ULONG64 Accessed : 1;
ULONG64 Dirty : 1;
ULONG64 LargePage : 1;
ULONG64 Global : 1;
ULONG64 CopyOnWrite : 1; // software field
ULONG64 Prototype : 1; // software field
ULONG64 reserved0 : 1; // software field
ULONG64 PageFrameNumber : 28;
ULONG64 reserved1 : 24 - (_HARDWARE_PTE_WORKING_SET_BITS+1);
ULONG64 SoftwareWsIndex : _HARDWARE_PTE_WORKING_SET_BITS;
ULONG64 NoExecute : 1;
} HARDWARE_PTE, *PHARDWARE_PTE;
//
// Define macro to initialize directory table base.
//
#define INITIALIZE_DIRECTORY_TABLE_BASE(dirbase,pfn) \
*((PULONG64)(dirbase)) = (((ULONG64)(pfn)) << PAGE_SHIFT)
//
// Define Global Descriptor Table (GDT) entry structure and constants.
//
// Define descriptor type codes.
//
#define TYPE_CODE 0x1A // 11010 = code, read only
#define TYPE_DATA 0x12 // 10010 = data, read and write
#define TYPE_TSS64 0x09 // 01001 = task state segment
//
// Define descriptor privilege levels for user and system.
//
#define DPL_USER 3
#define DPL_SYSTEM 0
//
// Define limit granularity.
//
#define GRANULARITY_BYTE 0
#define GRANULARITY_PAGE 1
#define SELECTOR_TABLE_INDEX 0x04
typedef union _KGDTENTRY64 {
struct {
USHORT LimitLow;
USHORT BaseLow;
union {
struct {
UCHAR BaseMiddle;
UCHAR Flags1;
UCHAR Flags2;
UCHAR BaseHigh;
} Bytes;
struct {
ULONG BaseMiddle : 8;
ULONG Type : 5;
ULONG Dpl : 2;
ULONG Present : 1;
ULONG LimitHigh : 4;
ULONG System : 1;
ULONG LongMode : 1;
ULONG DefaultBig : 1;
ULONG Granularity : 1;
ULONG BaseHigh : 8;
} Bits;
};
ULONG BaseUpper;
ULONG MustBeZero;
};
ULONG64 Alignment;
} KGDTENTRY64, *PKGDTENTRY64;
//
// Define Interrupt Descriptor Table (IDT) entry structure and constants.
//
typedef union _KIDTENTRY64 {
struct {
USHORT OffsetLow;
USHORT Selector;
USHORT IstIndex : 3;
USHORT Reserved0 : 5;
USHORT Type : 5;
USHORT Dpl : 2;
USHORT Present : 1;
USHORT OffsetMiddle;
ULONG OffsetHigh;
ULONG Reserved1;
};
ULONG64 Alignment;
} KIDTENTRY64, *PKIDTENTRY64;
//
// Define two union definitions used for parsing addresses into the
// component fields required by a GDT.
//
typedef union _KGDT_BASE {
struct {
USHORT BaseLow;
UCHAR BaseMiddle;
UCHAR BaseHigh;
ULONG BaseUpper;
};
ULONG64 Base;
} KGDT_BASE, *PKGDT_BASE;
C_ASSERT(sizeof(KGDT_BASE) == sizeof(ULONG64));
typedef union _KGDT_LIMIT {
struct {
USHORT LimitLow;
USHORT LimitHigh : 4;
USHORT MustBeZero : 12;
};
ULONG Limit;
} KGDT_LIMIT, *PKGDT_LIMIT;
C_ASSERT(sizeof(KGDT_LIMIT) == sizeof(ULONG));
//
// Define Task State Segment (TSS) structure and constants.
//
// Task switches are not supported by the AMD64, but a task state segment
// must be present to define the kernel stack pointer and I/O map base.
//
// N.B. This structure is misaligned as per the AMD64 specification.
//
// N.B. The size of TSS must be <= 0xDFFF.
//
#pragma pack(push, 4)
typedef struct _KTSS64 {
ULONG Reserved0;
ULONG64 Rsp0;
ULONG64 Rsp1;
ULONG64 Rsp2;
//
// Element 0 of the Ist is reserved
//
ULONG64 Ist[8];
ULONG64 Reserved1;
USHORT IoMapBase;
} KTSS64, *PKTSS64;
#pragma pack(pop)
C_ASSERT((sizeof(KTSS64) % sizeof(PVOID)) == 0);
#define TSS_IST_RESERVED 0
#define TSS_IST_PANIC 1
#define TSS_IST_MCA 2
#define IO_ACCESS_MAP_NONE FALSE
#define KiComputeIopmOffset(Enable) (sizeof(KTSS64))
// begin_windbgkd
#if defined(_AMD64_)
//
// Define pseudo descriptor structures for both 64- and 32-bit mode.
//
typedef struct _KDESCRIPTOR {
USHORT Pad[3];
USHORT Limit;
PVOID Base;
} KDESCRIPTOR, *PKDESCRIPTOR;
typedef struct _KDESCRIPTOR32 {
USHORT Pad[3];
USHORT Limit;
ULONG Base;
} KDESCRIPTOR32, *PKDESCRIPTOR32;
//
// Define special kernel registers and the initial MXCSR value.
//
typedef struct _KSPECIAL_REGISTERS {
ULONG64 Cr0;
ULONG64 Cr2;
ULONG64 Cr3;
ULONG64 Cr4;
ULONG64 KernelDr0;
ULONG64 KernelDr1;
ULONG64 KernelDr2;
ULONG64 KernelDr3;
ULONG64 KernelDr6;
ULONG64 KernelDr7;
KDESCRIPTOR Gdtr;
KDESCRIPTOR Idtr;
USHORT Tr;
USHORT Ldtr;
ULONG MxCsr;
ULONG64 DebugControl;
ULONG64 LastBranchToRip;
ULONG64 LastBranchFromRip;
ULONG64 LastExceptionToRip;
ULONG64 LastExceptionFromRip;
ULONG64 Cr8;
ULONG64 MsrGsBase;
ULONG64 MsrGsSwap;
ULONG64 MsrStar;
ULONG64 MsrLStar;
ULONG64 MsrCStar;
ULONG64 MsrSyscallMask;
} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS;
//
// Define processor state structure.
//
typedef struct _KPROCESSOR_STATE {
KSPECIAL_REGISTERS SpecialRegisters;
CONTEXT ContextFrame;
} KPROCESSOR_STATE, *PKPROCESSOR_STATE;
#endif // _AMD64_
// end_windbgkd
//
// DPC data structure definition.
//
typedef struct _KDPC_DATA {
LIST_ENTRY DpcListHead;
KSPIN_LOCK DpcLock;
volatile ULONG DpcQueueDepth;
ULONG DpcCount;
} KDPC_DATA, *PKDPC_DATA;
//
// Processor Control Block (PRCB)
//
#define PRCB_MAJOR_VERSION 1
#define PRCB_MINOR_VERSION 1
#define PRCB_BUILD_DEBUG 0x1
#define PRCB_BUILD_UNIPROCESSOR 0x2
typedef struct _KPRCB {
//
// Start of the architecturally defined section of the PRCB. This section
// may be directly addressed by vendor/platform specific HAL code and will
// not change from version to version of NT.
//
USHORT MinorVersion;
USHORT MajorVersion;
CCHAR Number;
CCHAR Reserved;
USHORT BuildType;
struct _KTHREAD *CurrentThread;
struct _KTHREAD *NextThread;
struct _KTHREAD *IdleThread;
KAFFINITY SetMember;
KAFFINITY NotSetMember;
KSPIN_LOCK PrcbLock;
KPROCESSOR_STATE ProcessorState;
CCHAR CpuType;
CCHAR CpuID;
USHORT CpuStep;
ULONG PrcbPad00;
ULONG64 HalReserved[8];
UCHAR PrcbPad0[104];
//
// End of the architecturally defined section of the PRCB.
//
// end_nthal end_ntosp
//
// Numbered queued spin locks - 128-byte aligned.
//
KSPIN_LOCK_QUEUE LockQueue[16];
UCHAR PrcbPad1[16];
//
// Nonpaged per processor lookaside lists - 128-byte aligned.
//
PP_LOOKASIDE_LIST PPLookasideList[16];
//
// Nonpaged per processor small pool lookaside lists - 128-byte aligned.
//
PP_LOOKASIDE_LIST PPNPagedLookasideList[POOL_SMALL_LISTS];
//
// Paged per processor small pool lookaside lists.
//
PP_LOOKASIDE_LIST PPPagedLookasideList[POOL_SMALL_LISTS];
//
// MP interprocessor request packet barrier - 128-byte aligned.
//
volatile KAFFINITY PacketBarrier;
UCHAR PrcbPad2[120];
//
// MP interprocessor request packet and summary - 128-byte aligned.
//
volatile PVOID CurrentPacket[3];
volatile KAFFINITY TargetSet;
volatile PKIPI_WORKER WorkerRoutine;
volatile ULONG IpiFrozen;
UCHAR PrcbPad3[84];
//
// MP interprocessor request summary and packet address - 128-byte aligned.
//
// N.B. Request summary includes the request summary mask as well as the
// request packet. The address occupies the upper 48-bits and the mask
// the lower 16-bits
//
#define IPI_PACKET_SHIFT 16
volatile LONG64 RequestSummary;
UCHAR PrcbPad4[120];
//
// DPC listhead, counts, and batching parameters - 128-byte aligned.
//
KDPC_DATA DpcData[2];
PVOID DpcStack;
PVOID SavedRsp;
ULONG MaximumDpcQueueDepth;
ULONG DpcRequestRate;
ULONG MinimumDpcRate;
volatile BOOLEAN DpcInterruptRequested;
volatile BOOLEAN DpcThreadRequested;
//
// N.B. the following two fields must be on a word boundary.
//
volatile BOOLEAN DpcRoutineActive;
volatile BOOLEAN DpcThreadActive;
union {
volatile ULONG64 TimerHand;
volatile ULONG64 TimerRequest;
};
ULONG64 PrcbPad40;
ULONG DpcLastCount;
BOOLEAN ThreadDpcEnable;
volatile BOOLEAN QuantumEnd;
UCHAR PrcbPad50;
volatile BOOLEAN IdleSchedule;
LONG DpcSetEventRequest;
UCHAR PrcbPad5[4];
//
// DPC thread and generic call DPC - 128-byte aligned
//
PVOID DpcThread;
KEVENT DpcEvent;
KDPC CallDpc;
SINGLE_LIST_ENTRY DeferredReadyListHead;
ULONG64 PrcbPad7[3];
//
// Per-processor ready summary and ready queues - 128-byte aligned.
//
// N.B. Ready summary is in the first cache line as the queue for priority
// zero is never used.
//
LIST_ENTRY WaitListHead;
ULONG ReadySummary;
ULONG SelectNextLast;
LIST_ENTRY DispatcherReadyListHead[MAXIMUM_PRIORITY];
//
// Miscellaneous counters.
//
ULONG InterruptCount;
ULONG KernelTime;
ULONG UserTime;
ULONG DpcTime;
ULONG InterruptTime;
ULONG AdjustDpcThreshold;
ULONG PageColor;
BOOLEAN SkipTick;
KIRQL DebuggerSavedIRQL;
UCHAR PollSlot;
UCHAR PrcbPad8[1];
struct _KNODE * ParentNode;
KAFFINITY MultiThreadProcessorSet;
ULONG ThreadStartCount[2];
ULONG DebugDpcTime;
UCHAR PrcbPad9[44];
//
// Performance counters - 128-byte aligned.
//
// Cache manager performance counters.
//
ULONG CcFastReadNoWait;
ULONG CcFastReadWait;
ULONG CcFastReadNotPossible;
ULONG CcCopyReadNoWait;
ULONG CcCopyReadWait;
ULONG CcCopyReadNoWaitMiss;
//
// Kernel performance counters.
//
ULONG KeAlignmentFixupCount;
ULONG SpareCounter0;
ULONG KeDcacheFlushCount;
ULONG KeExceptionDispatchCount;
ULONG KeFirstLevelTbFills;
ULONG KeFloatingEmulationCount;
ULONG KeIcacheFlushCount;
ULONG KeSecondLevelTbFills;
ULONG KeSystemCalls;
ULONG SpareCounter1;
//
// I/O IRP float.
//
LONG LookasideIrpFloat;
//
// Processor information.
//
UCHAR VendorString[13];
UCHAR InitialApicId;
UCHAR LogicalProcessorsPerPhysicalProcessor;
ULONG MHz;
ULONG FeatureBits;
LARGE_INTEGER UpdateSignature;
//
// Processors power state
//
PROCESSOR_POWER_STATE PowerState;
// begin_nthal begin_ntosp
} KPRCB, *PKPRCB, *RESTRICTED_POINTER PRKPRCB;
// end_nthal end_ntosp
#if !defined(_X86AMD64_)
C_ASSERT(((FIELD_OFFSET(KPRCB, LockQueue) + 16) & (128 - 1)) == 0);
C_ASSERT((FIELD_OFFSET(KPRCB, PPLookasideList) & (128 - 1)) == 0);
C_ASSERT((FIELD_OFFSET(KPRCB, PPNPagedLookasideList) & (128 - 1)) == 0);
C_ASSERT((FIELD_OFFSET(KPRCB, PacketBarrier) & (128 - 1)) == 0);
C_ASSERT((FIELD_OFFSET(KPRCB, RequestSummary) & (128 - 1)) == 0);
C_ASSERT((FIELD_OFFSET(KPRCB, DpcData) & (128 - 1)) == 0);
C_ASSERT(((FIELD_OFFSET(KPRCB, DpcRoutineActive)) & (1)) == 0);
C_ASSERT((FIELD_OFFSET(KPRCB, DpcThread) & (128 - 1)) == 0);
C_ASSERT((FIELD_OFFSET(KPRCB, WaitListHead) & (128 - 1)) == 0);
C_ASSERT((FIELD_OFFSET(KPRCB, CcFastReadNoWait) & (128 - 1)) == 0);
#endif
// begin_nthal begin_ntosp begin_ntddk
//
// Processor Control Region Structure Definition
//
#define PCR_MINOR_VERSION 1
#define PCR_MAJOR_VERSION 1
typedef struct _KPCR {
//
// Start of the architecturally defined section of the PCR. This section
// may be directly addressed by vendor/platform specific HAL code and will
// not change from version to version of NT.
//
// Certain fields in the TIB are not used in kernel mode. These include the
// exception list, stack base, stack limit, subsystem TIB, fiber data, and
// the arbitrary user pointer. Therefore, these fields are overlaid with
// other data to get better cache locality.
union {
NT_TIB NtTib;
struct {
union _KGDTENTRY64 *GdtBase;
struct _KTSS64 *TssBase;
PVOID PerfGlobalGroupMask;
struct _KPCR *Self;
ULONG ContextSwitches;
ULONG NotUsed;
KAFFINITY SetMember;
PVOID Used_Self;
};
};
struct _KPRCB *CurrentPrcb;
ULONG64 SavedRcx;
ULONG64 SavedR11;
KIRQL Irql;
UCHAR SecondLevelCacheAssociativity;
UCHAR Number;
UCHAR Fill0;
ULONG Irr;
ULONG IrrActive;
ULONG Idr;
USHORT MajorVersion;
USHORT MinorVersion;
ULONG StallScaleFactor;
union _KIDTENTRY64 *IdtBase;
PVOID Unused1;
PVOID Unused2;
// end_ntddk end_ntosp
ULONG KernelReserved[15];
ULONG SecondLevelCacheSize;
ULONG HalReserved[16];
ULONG MxCsr;
PVOID KdVersionBlock;
PVOID Unused3;
//
// End of the architecturally defined section of the PCR.
//
// end_nthal
//
ULONG PcrAlign1[24];
KPRCB Prcb;
// begin_nthal begin_ntddk begin_ntosp
} KPCR, *PKPCR;
// end_nthal end_ntddk end_ntosp
#if !defined (_X86AMD64_)
C_ASSERT(FIELD_OFFSET(KPCR, NtTib.ExceptionList) == FIELD_OFFSET(KPCR, GdtBase));
C_ASSERT(FIELD_OFFSET(KPCR, NtTib.StackBase) == FIELD_OFFSET(KPCR, TssBase));
C_ASSERT(FIELD_OFFSET(KPCR, NtTib.StackLimit) == FIELD_OFFSET(KPCR, PerfGlobalGroupMask));
C_ASSERT(FIELD_OFFSET(KPCR, NtTib.SubSystemTib) == FIELD_OFFSET(KPCR, Self));
C_ASSERT(FIELD_OFFSET(KPCR, NtTib.FiberData) == FIELD_OFFSET(KPCR, ContextSwitches));
C_ASSERT(FIELD_OFFSET(KPCR, NtTib.ArbitraryUserPointer) == FIELD_OFFSET(KPCR, SetMember));
C_ASSERT(FIELD_OFFSET(KPCR, NtTib.Self) == FIELD_OFFSET(KPCR, Used_Self));
C_ASSERT((FIELD_OFFSET(KPCR, Prcb) & (128 - 1)) == 0);
//
// The offset of the DebuggerDataBlock must not change.
//
C_ASSERT(FIELD_OFFSET(KPCR, KdVersionBlock) == 0x108);
#endif
__forceinline
ULONG
KeGetContextSwitches (
PKPRCB Prcb
)
{
PKPCR Pcr;
Pcr = CONTAINING_RECORD(Prcb, KPCR, Prcb);
return Pcr->ContextSwitches;
}
VOID
KeRestoreLegacyFloatingPointState (
PLEGACY_SAVE_AREA NpxFrame
);
VOID
KeSaveLegacyFloatingPointState (
PLEGACY_SAVE_AREA NpxFrame
);
// begin_nthal begin_ntosp
//
// Define legacy floating status word bit masks.
//
#define FSW_INVALID_OPERATION 0x1
#define FSW_DENORMAL 0x2
#define FSW_ZERO_DIVIDE 0x4
#define FSW_OVERFLOW 0x8
#define FSW_UNDERFLOW 0x10
#define FSW_PRECISION 0x20
#define FSW_STACK_FAULT 0x40
#define FSW_CONDITION_CODE_0 0x100
#define FSW_CONDITION_CODE_1 0x200
#define FSW_CONDITION_CODE_2 0x400
#define FSW_CONDITION_CODE_3 0x4000
#define FSW_ERROR_MASK (FSW_INVALID_OPERATION | FSW_DENORMAL | \
FSW_ZERO_DIVIDE | FSW_OVERFLOW | FSW_UNDERFLOW | \
FSW_PRECISION)
//
// Define legacy floating states.
//
#define LEGACY_STATE_UNUSED 0
#define LEGACY_STATE_SCRUB 1
#define LEGACY_STATE_SWITCH 2
//
// Define MxCsr floating control/status word bit masks.
//
// No flush to zero, round to nearest, and all exception masked.
//
#define XSW_INVALID_OPERATION 0x1
#define XSW_DENORMAL 0x2
#define XSW_ZERO_DIVIDE 0x4
#define XSW_OVERFLOW 0x8
#define XSW_UNDERFLOW 0x10
#define XSW_PRECISION 0x20
#define XSW_ERROR_MASK (XSW_INVALID_OPERATION | XSW_DENORMAL | \
XSW_ZERO_DIVIDE | XSW_OVERFLOW | XSW_UNDERFLOW | \
XSW_PRECISION)
#define XSW_ERROR_SHIFT 7
#define XCW_INVALID_OPERATION 0x80
#define XCW_DENORMAL 0x100
#define XCW_ZERO_DIVIDE 0x200
#define XCW_OVERFLOW 0x400
#define XCW_UNDERFLOW 0x800
#define XCW_PRECISION 0x1000
#define XCW_ROUND_CONTROL 0x6000
#define XCW_FLUSH_ZERO 0x8000
//
// Define EFLAG bit masks and shift offsets.
//
#define EFLAGS_CF_MASK 0x00000001 // carry flag
#define EFLAGS_PF_MASK 0x00000004 // parity flag
#define EFALGS_AF_MASK 0x00000010 // auxiliary carry flag
#define EFLAGS_ZF_MASK 0x00000040 // zero flag
#define EFLAGS_SF_MASK 0x00000080 // sign flag
#define EFLAGS_TF_MASK 0x00000100 // trap flag
#define EFLAGS_IF_MASK 0x00000200 // interrupt flag
#define EFLAGS_DF_MASK 0x00000400 // direction flag
#define EFLAGS_OF_MASK 0x00000800 // overflow flag
#define EFLAGS_IOPL_MASK 0x00003000 // I/O privilege level
#define EFLAGS_NT_MASK 0x00004000 // nested task
#define EFLAGS_RF_MASK 0x00010000 // resume flag
#define EFLAGS_VM_MASK 0x00020000 // virtual 8086 mode
#define EFLAGS_AC_MASK 0x00040000 // alignment check
#define EFLAGS_VIF_MASK 0x00080000 // virtual interrupt flag
#define EFLAGS_VIP_MASK 0x00100000 // virtual interrupt pending
#define EFLAGS_ID_MASK 0x00200000 // identification flag
#define EFLAGS_TF_SHIFT 8 // trap
#define EFLAGS_IF_SHIFT 9 // interrupt enable
// end_nthal
//
// Define sanitize EFLAGS macro.
//
// If kernel mode, then
// caller can specify Carry, Parity, AuxCarry, Zero, Sign, Trap,
// Interrupt, Direction, Overflow, and identification.
//
// If user mode, then
// caller can specify Carry, Parity, AuxCarry, Zero, Sign, Trap,
// Direction, Overflow, and force Interrupt on.
//
#define EFLAGS_KERNEL_SANITIZE 0x00210fd5L
#define EFLAGS_USER_SANITIZE 0x00010dd5L
#define SANITIZE_EFLAGS(eFlags, mode) ( \
((mode) == KernelMode ? \
((eFlags) & EFLAGS_KERNEL_SANITIZE) : \
(((eFlags) & EFLAGS_USER_SANITIZE) | EFLAGS_IF_MASK)))
//
// Define sanitize debug register macros.
//
// Define control register settable bits and active mask.
//
#define DR7_LEGAL 0xffff0155
#define DR7_ACTIVE 0x00000055
//
// Define macro to sanitize the debug control register.
//
#define SANITIZE_DR7(Dr7, mode) ((Dr7 & DR7_LEGAL));
//
// Define macro to santitize debug address registers.
//
#define SANITIZE_DRADDR(DrReg, mode) \
((mode) == KernelMode ? \
(DrReg) : \
(((PVOID)(DrReg) <= MM_HIGHEST_USER_ADDRESS) ? (DrReg) : 0)) \
//
// Define macro to clear reserved bits from MXCSR.
//
#define SANITIZE_MXCSR(_mxcsr_) ((_mxcsr_) & 0xffbf)
//
// Define macro to clear reserved bits for legacy FP control word.
//
#define SANITIZE_FCW(_fcw_) ((_fcw_) & 0x1f37)
// begin_nthal begin_ntddk
//
// Exception frame
//
// This frame is established when handling an exception. It provides a place
// to save all nonvolatile registers. The volatile registers will already
// have been saved in a trap frame.
//
// N.B. The exception frame has a built in exception record capable of
// storing information for four parameter values. This exception
// record is used exclusively within the trap handling code.
//
#define EXCEPTION_AREA_SIZE 64
typedef struct _KEXCEPTION_FRAME {
//
// Home address for the parameter registers.
//
ULONG64 P1Home;
ULONG64 P2Home;
ULONG64 P3Home;
ULONG64 P4Home;
ULONG64 P5;
//
// Kernel callout initial stack value.
//
ULONG64 InitialStack;
//
// Saved nonvolatile floating registers.
//
M128 Xmm6;
M128 Xmm7;
M128 Xmm8;
M128 Xmm9;
M128 Xmm10;
M128 Xmm11;
M128 Xmm12;
M128 Xmm13;
M128 Xmm14;
M128 Xmm15;
//
// Kernel callout frame variables.
//
ULONG64 TrapFrame;
ULONG64 CallbackStack;
ULONG64 OutputBuffer;
ULONG64 OutputLength;
//
// Exception record for exceptions.
//
UCHAR ExceptionRecord[EXCEPTION_AREA_SIZE];
//
// Saved nonvolatile register - not always saved.
//
ULONG64 Fill1;
ULONG64 Rbp;
//
// Saved nonvolatile registers.
//
ULONG64 Rbx;
ULONG64 Rdi;
ULONG64 Rsi;
ULONG64 R12;
ULONG64 R13;
ULONG64 R14;
ULONG64 R15;
//
// EFLAGS and return address.
//
ULONG64 Return;
} KEXCEPTION_FRAME, *PKEXCEPTION_FRAME;
// end_ntddk
#define KEXCEPTION_FRAME_LENGTH sizeof(KEXCEPTION_FRAME)
C_ASSERT((sizeof(KEXCEPTION_FRAME) & STACK_ROUND) == 0);
#define EXCEPTION_RECORD_LENGTH \
((sizeof(EXCEPTION_RECORD) + STACK_ROUND) & ~STACK_ROUND)
#if !defined(_X86AMD64_)
C_ASSERT(EXCEPTION_AREA_SIZE == (FIELD_OFFSET(EXCEPTION_RECORD, ExceptionInformation) + (4 * sizeof(ULONG_PTR))));
#endif
//
// Machine Frame
//
// This frame is established by code that trampolines to user mode (e.g. user
// APC, user callback, dispatch user exception, etc.). The purpose of this
// frame is to allow unwinding through these callbacks if an exception occurs.
//
// N.B. This frame is identical to the frame that is pushed for a trap without
// an error code and is identical to the hardware part of a trap frame.
//
typedef struct _MACHINE_FRAME {
ULONG64 Rip;
USHORT SegCs;
USHORT Fill1[3];
ULONG EFlags;
ULONG Fill2;
ULONG64 Rsp;
USHORT SegSs;
USHORT Fill3[3];
} MACHINE_FRAME, *PMACHINE_FRAME;
#define MACHINE_FRAME_LENGTH sizeof(MACHINE_FRAME)
C_ASSERT((sizeof(MACHINE_FRAME) & STACK_ROUND) == 8);
//
// Switch Frame
//
// This frame is established by the code that switches context from one
// thread to the next and is used by the thread initialization code to
// construct a stack that will start the execution of a thread in the
// thread start up code.
//
typedef struct _KSWITCH_FRAME {
ULONG64 P1Home;
ULONG64 P2Home;
ULONG64 P3Home;
ULONG64 P4Home;
ULONG64 P5Home;
ULONG MxCsr;
KIRQL ApcBypass;
UCHAR Fill1[3];
ULONG64 Rbp;
ULONG64 Return;
} KSWITCH_FRAME, *PKSWITCH_FRAME;
#define KSWITCH_FRAME_LENGTH sizeof(KSWITCH_FRAME)
C_ASSERT((sizeof(KSWITCH_FRAME) & STACK_ROUND) == 0);
//
// Start system thread frame.
//
// This frame is established by the AMD64 specific thread initialization
// code. It is used to store the initial context for starting a system
// thread.
//
typedef struct _KSTART_FRAME {
ULONG64 P1Home;
ULONG64 P2Home;
ULONG64 P3Home;
ULONG64 Return;
} KSTART_FRAME, *PKSTART_FRAME;
#define KSTART_FRAME_LENGTH sizeof(KSTART_FRAME)
C_ASSERT((sizeof(KSTART_FRAME) & STACK_ROUND) == 0);
// begin_ntddk
//
// Trap frame
//
// This frame is established when handling a trap. It provides a place to
// save all volatile registers. The nonvolatile registers are saved in an
// exception frame or through the normal C calling conventions for saved
// registers.
//
typedef struct _KTRAP_FRAME {
//
// Home address for the parameter registers.
//
ULONG64 P1Home;
ULONG64 P2Home;
ULONG64 P3Home;
ULONG64 P4Home;
ULONG64 P5;
//
// Previous processor mode (system services only) and previous IRQL
// (interrupts only).
//
KPROCESSOR_MODE PreviousMode;
KIRQL PreviousIrql;
//
// Page fault load/store indicator.
//
UCHAR FaultIndicator;
UCHAR Fill0;
//
// Floating point state.
//
ULONG MxCsr;
//
// Volatile registers.
//
// N.B. These registers are only saved on exceptions and interrupts. They
// are not saved for system calls.
//
ULONG64 Rax;
ULONG64 Rcx;
ULONG64 Rdx;
ULONG64 R8;
ULONG64 R9;
ULONG64 R10;
ULONG64 R11;
ULONG64 Spare0;
//
// Volatile floating registers.
//
// N.B. These registers are only saved on exceptions and interrupts. They
// are not saved for system calls.
//
M128 Xmm0;
M128 Xmm1;
M128 Xmm2;
M128 Xmm3;
M128 Xmm4;
M128 Xmm5;
//
// Page fault address.
//
ULONG64 FaultAddress;
//
// Debug registers.
//
ULONG64 Dr0;
ULONG64 Dr1;
ULONG64 Dr2;
ULONG64 Dr3;
ULONG64 Dr6;
ULONG64 Dr7;
//
// Special debug registers.
//
ULONG64 DebugControl;
ULONG64 LastBranchToRip;
ULONG64 LastBranchFromRip;
ULONG64 LastExceptionToRip;
ULONG64 LastExceptionFromRip;
//
// Segment registers
//
USHORT SegDs;
USHORT SegEs;
USHORT SegFs;
USHORT SegGs;
//
// Previous trap frame address.
//
ULONG64 TrapFrame;
//
// Saved nonvolatile registers RBX, RDI and RSI. These registers are only
// saved in system service trap frames.
//
ULONG64 Rbx;
ULONG64 Rdi;
ULONG64 Rsi;
//
// Saved nonvolatile register RBP. This register is used as a frame
// pointer during trap processing and is saved in all trap frames.
//
ULONG64 Rbp;
//
// Information pushed by hardware.
//
// N.B. The error code is not always pushed by hardware. For those cases
// where it is not pushed by hardware a dummy error code is allocated
// on the stack.
//
ULONG64 ErrorCode;
ULONG64 Rip;
USHORT SegCs;
USHORT Fill1[3];
ULONG EFlags;
ULONG Fill2;
ULONG64 Rsp;
USHORT SegSs;
USHORT Fill3[3];
} KTRAP_FRAME, *PKTRAP_FRAME;
// end_ntddk
#define KTRAP_FRAME_LENGTH sizeof(KTRAP_FRAME)
C_ASSERT((sizeof(KTRAP_FRAME) & STACK_ROUND) == 0);
//
// IPI, profile, update run time, and update system time interrupt routines.
//
NTKERNELAPI
VOID
KeIpiInterrupt (
IN PKTRAP_FRAME TrapFrame
);
NTKERNELAPI
VOID
KeProfileInterruptWithSource (
IN PKTRAP_FRAME TrapFrame,
IN KPROFILE_SOURCE ProfileSource
);
NTKERNELAPI
VOID
KeUpdateRunTime (
IN PKTRAP_FRAME TrapFrame
);
NTKERNELAPI
VOID
KeUpdateSystemTime (
IN PKTRAP_FRAME TrapFrame,
IN ULONG64 Increment
);
// end_nthal
//
// The frame saved by the call out to user mode code is defined here to allow
// the kernel debugger to trace the entire kernel stack when user mode callouts
// are active.
//
// N.B. The kernel callout frame is the same as an exception frame.
//
typedef KEXCEPTION_FRAME KCALLOUT_FRAME;
typedef PKEXCEPTION_FRAME PKCALLOUT_FRAME;
typedef struct _UCALLOUT_FRAME {
ULONG64 P1Home;
ULONG64 P2Home;
ULONG64 P3Home;
ULONG64 P4Home;
PVOID Buffer;
ULONG Length;
ULONG ApiNumber;
MACHINE_FRAME MachineFrame;
} UCALLOUT_FRAME, *PUCALLOUT_FRAME;
#define UCALLOUT_FRAME_LENGTH sizeof(UCALLOUT_FRAME)
C_ASSERT((sizeof(UCALLOUT_FRAME) & STACK_ROUND) == 8);
// begin_ntddk begin_wdm
//
// The nonvolatile floating state
//
typedef struct _KFLOATING_SAVE {
ULONG MxCsr;
} KFLOATING_SAVE, *PKFLOATING_SAVE;
// end_ntddk end_wdm end_ntosp
//
// Define profile values.
//
#define DEFAULT_PROFILE_INTERVAL 39063
//
// The minimum acceptable profiling interval is set to 1221 which is the
// fast RTC clock rate we can get. If this
// value is too small, the system will run very slowly.
//
#define MINIMUM_PROFILE_INTERVAL 1221
// begin_ntddk begin_wdm begin_nthal begin_ntndis begin_ntosp
//
// AMD64 Specific portions of mm component.
//
// Define the page size for the AMD64 as 4096 (0x1000).
//
#define PAGE_SIZE 0x1000
//
// Define the number of trailing zeroes in a page aligned virtual address.
// This is used as the shift count when shifting virtual addresses to
// virtual page numbers.
//
#define PAGE_SHIFT 12L
// end_ntndis end_wdm
#define PXE_BASE 0xFFFFF6FB7DBED000UI64
#define PXE_SELFMAP 0xFFFFF6FB7DBEDF68UI64
#define PPE_BASE 0xFFFFF6FB7DA00000UI64
#define PDE_BASE 0xFFFFF6FB40000000UI64
#define PTE_BASE 0xFFFFF68000000000UI64
#define PXE_TOP 0xFFFFF6FB7DBEDFFFUI64
#define PPE_TOP 0xFFFFF6FB7DBFFFFFUI64
#define PDE_TOP 0xFFFFF6FB7FFFFFFFUI64
#define PTE_TOP 0xFFFFF6FFFFFFFFFFUI64
#define PDE_KTBASE_AMD64 PPE_BASE
#define PTI_SHIFT 12
#define PDI_SHIFT 21
#define PPI_SHIFT 30
#define PXI_SHIFT 39
#define PTE_PER_PAGE 512
#define PDE_PER_PAGE 512
#define PPE_PER_PAGE 512
#define PXE_PER_PAGE 512
#define PTI_MASK_AMD64 (PTE_PER_PAGE - 1)
#define PDI_MASK_AMD64 (PDE_PER_PAGE - 1)
#define PPI_MASK (PPE_PER_PAGE - 1)
#define PXI_MASK (PXE_PER_PAGE - 1)
//
// Define the highest user address and user probe address.
//
// end_ntddk end_nthal end_ntosp
#if defined(_NTDRIVER_) || defined(_NTDDK_) || defined(_NTIFS_) || defined(_NTHAL_)
// begin_ntddk begin_nthal begin_ntosp
extern PVOID *MmHighestUserAddress;
extern PVOID *MmSystemRangeStart;
extern ULONG64 *MmUserProbeAddress;
#define MM_HIGHEST_USER_ADDRESS *MmHighestUserAddress
#define MM_SYSTEM_RANGE_START *MmSystemRangeStart
#define MM_USER_PROBE_ADDRESS *MmUserProbeAddress
// end_ntddk end_nthal end_ntosp
#else
extern PVOID MmHighestUserAddress;
extern PVOID MmSystemRangeStart;
extern ULONG64 MmUserProbeAddress;
#define MM_HIGHEST_USER_ADDRESS MmHighestUserAddress
#define MM_SYSTEM_RANGE_START MmSystemRangeStart
#define MM_USER_PROBE_ADDRESS MmUserProbeAddress
#define MI_HIGHEST_USER_ADDRESS (PVOID) (ULONG_PTR)((0x80000000000 - 0x10000 - 1)) // highest user address
#define MI_SYSTEM_RANGE_START (PVOID)(0xFFFF080000000000) // start of system space
#define MI_USER_PROBE_ADDRESS ((ULONG_PTR)(0x80000000000UI64 - 0x10000)) // starting address of guard page
#endif
// begin_nthal
//
// 4MB at the top of VA space is reserved for the HAL's use.
//
#define HAL_VA_START 0xFFFFFFFFFFC00000UI64
#define HAL_VA_SIZE (4 * 1024 * 1024)
// end_nthal
// begin_ntddk begin_nthal begin_ntosp
//
// The lowest user address reserves the low 64k.
//
#define MM_LOWEST_USER_ADDRESS (PVOID)0x10000
//
// The lowest address for system space.
//
#define MM_LOWEST_SYSTEM_ADDRESS (PVOID)0xFFFF080000000000
// begin_wdm
#define MmGetProcedureAddress(Address) (Address)
#define MmLockPagableCodeSection(Address) MmLockPagableDataSection(Address)
// end_ntddk end_wdm end_ntosp
//
// Define virtual base and alternate virtual base of kernel.
//
#define KSEG0_BASE 0xFFFFF80000000000UI64
//
// Generate kernel segment physical address.
//
#define KSEG_ADDRESS(PAGE) ((PVOID)(KSEG0_BASE | ((ULONG_PTR)(PAGE) << PAGE_SHIFT)))
// begin_ntddk begin_ntosp
//
// Intrinsic functions
//
// begin_wdm
#if defined(_M_AMD64) && !defined(RC_INVOKED) && !defined(MIDL_PASS)
// end_wdm
//
// The following routines are provided for backward compatibility with old
// code. They are no longer the preferred way to accomplish these functions.
//
#if PRAGMA_DEPRECATED_DDK
#pragma deprecated(ExInterlockedIncrementLong) // Use InterlockedIncrement
#pragma deprecated(ExInterlockedDecrementLong) // Use InterlockedDecrement
#pragma deprecated(ExInterlockedExchangeUlong) // Use InterlockedExchange
#endif
#define RESULT_ZERO 0
#define RESULT_NEGATIVE 1
#define RESULT_POSITIVE 2
typedef enum _INTERLOCKED_RESULT {
ResultNegative = RESULT_NEGATIVE,
ResultZero = RESULT_ZERO,
ResultPositive = RESULT_POSITIVE
} INTERLOCKED_RESULT;
#define ExInterlockedDecrementLong(Addend, Lock) \
_ExInterlockedDecrementLong(Addend)
__forceinline
LONG
_ExInterlockedDecrementLong (
IN OUT PLONG Addend
)
{
LONG Result;
Result = InterlockedDecrement(Addend);
if (Result < 0) {
return ResultNegative;
} else if (Result > 0) {
return ResultPositive;
} else {
return ResultZero;
}
}
#define ExInterlockedIncrementLong(Addend, Lock) \
_ExInterlockedIncrementLong(Addend)
__forceinline
LONG
_ExInterlockedIncrementLong (
IN OUT PLONG Addend
)
{
LONG Result;
Result = InterlockedIncrement(Addend);
if (Result < 0) {
return ResultNegative;
} else if (Result > 0) {
return ResultPositive;
} else {
return ResultZero;
}
}
#define ExInterlockedExchangeUlong(Target, Value, Lock) \
_ExInterlockedExchangeUlong(Target, Value)
__forceinline
_ExInterlockedExchangeUlong (
IN OUT PULONG Target,
IN ULONG Value
)
{
return (ULONG)InterlockedExchange((PLONG)Target, (LONG)Value);
}
// begin_wdm
#endif // defined(_M_AMD64) && !defined(RC_INVOKED) && !defined(MIDL_PASS)
// end_wdm end_ntddk end_nthal end_ntosp
// begin_ntosp begin_nthal begin_ntddk begin_wdm
#if !defined(MIDL_PASS) && defined(_M_AMD64)
//
// AMD646 function prototype definitions
//
// end_wdm
// end_ntddk end_ntosp
//
// Get address of current processor block.
//
__forceinline
PKPCR
KeGetPcr (
VOID
)
{
return (PKPCR)__readgsqword(FIELD_OFFSET(KPCR, Self));
}
// begin_ntosp
//
// Get address of current processor block.
//
__forceinline
PKPRCB
KeGetCurrentPrcb (
VOID
)
{
return (PKPRCB)__readgsqword(FIELD_OFFSET(KPCR, CurrentPrcb));
}
// begin_ntddk
//
// Get the current processor number
//
__forceinline
ULONG
KeGetCurrentProcessorNumber (
VOID
)
{
return (ULONG)__readgsbyte(FIELD_OFFSET(KPCR, Number));
}
// end_nthal end_ntddk end_ntosp
//
// Get address of current kernel thread object.
//
// WARNING: This inline macro can not be used for device drivers or HALs
// they must call the kernel function KeGetCurrentThread.
//
__forceinline
struct _KTHREAD *
KeGetCurrentThread (
VOID
)
{
return (struct _KTHREAD *)__readgsqword(FIELD_OFFSET(KPCR, Prcb.CurrentThread));
}
//
// If processor executing a DPC.
//
// WARNING: This inline macro is always MP enabled because filesystems
// utilize it
//
__forceinline
ULONG
KeIsExecutingDpc (
VOID
)
{
return (__readgsword(FIELD_OFFSET(KPCR, Prcb.DpcRoutineActive)) != 0);
}
// begin_nthal begin_ntddk begin_ntosp
// begin_wdm
#endif // !defined(MIDL_PASS) && defined(_M_AMD64)
// end_nthal end_ntddk end_wdm end_ntosp
// begin_ntddk begin_nthal begin_ntndis begin_wdm begin_ntosp
//++
//
//
// VOID
// KeMemoryBarrier (
// VOID
// )
//
// VOID
// KeMemoryBarrierWithoutFence (
// VOID
// )
//
//
// Routine Description:
//
// These functions order memory accesses as seen by other processors.
//
// Arguments:
//
// None.
//
// Return Value:
//
// None.
//
//--
#if !defined(_CROSS_PLATFORM_)
#ifdef __cplusplus
extern "C" {
#endif
VOID
_ReadWriteBarrier (
VOID
);
#pragma intrinsic(_ReadWriteBarrier)
#ifdef __cplusplus
}
#endif
#define KeMemoryBarrier() _ReadWriteBarrier()
#define KeMemoryBarrierWithoutFence() _ReadWriteBarrier()
#else
#define KeMemoryBarrier()
#define KeMemoryBarrierWithoutFence()
#endif
// end_ntddk end_nthal end_ntndis end_wdm end_ntosp
// begin_nthal
//
// Define inline functions to get and set the handler address in and IDT
// entry.
//
typedef union _KIDT_HANDLER_ADDRESS {
struct {
USHORT OffsetLow;
USHORT OffsetMiddle;
ULONG OffsetHigh;
};
ULONG64 Address;
} KIDT_HANDLER_ADDRESS, *PKIDT_HANDLER_ADDRESS;
#define KiGetIdtFromVector(Vector) \
&KeGetPcr()->IdtBase[HalVectorToIDTEntry(Vector)]
#define KeGetIdtHandlerAddress(Vector,Addr) { \
KIDT_HANDLER_ADDRESS Handler; \
PKIDTENTRY64 Idt; \
\
Idt = KiGetIdtFromVector(Vector); \
Handler.OffsetLow = Idt->OffsetLow; \
Handler.OffsetMiddle = Idt->OffsetMiddle; \
Handler.OffsetHigh = Idt->OffsetHigh; \
*(Addr) = (PVOID)(Handler.Address); \
}
#define KeSetIdtHandlerAddress(Vector,Addr) { \
KIDT_HANDLER_ADDRESS Handler; \
PKIDTENTRY64 Idt; \
\
Idt = KiGetIdtFromVector(Vector); \
Handler.Address = (ULONG64)(Addr); \
Idt->OffsetLow = Handler.OffsetLow; \
Idt->OffsetMiddle = Handler.OffsetMiddle; \
Idt->OffsetHigh = Handler.OffsetHigh; \
}
// end_nthal
//++
//
// BOOLEAN
// KiIsThreadNumericStateSaved(
// IN PKTHREAD Address
// )
//
//--
#define KiIsThreadNumericStateSaved(a) TRUE
//++
//
// VOID
// KiRundownThread(
// IN PKTHREAD Address
// )
//
//--
#define KiRundownThread(a)
//
// functions specific to structure
//
VOID
KiSetIRR (
IN ULONG SWInterruptMask
);
// begin_ntddk begin_wdm begin_ntosp
NTKERNELAPI
NTSTATUS
KeSaveFloatingPointState (
OUT PKFLOATING_SAVE SaveArea
);
NTKERNELAPI
NTSTATUS
KeRestoreFloatingPointState (
IN PKFLOATING_SAVE SaveArea
);
// end_ntddk end_wdm end_ntosp
// begin_nthal begin_ntddk begin_wdm begin_ntndis begin_ntosp
#endif // defined(_AMD64_)
// end_nthal end_ntddk end_wdm end_ntndis end_ntosp
//
// Architecture specific kernel functions.
//
// begin_ntosp
//
// Platform specific kernel fucntions to raise and lower IRQL.
//
// These functions are imported for ntddk, ntifs, and wdm. They are
// inlined for nthal, ntosp, and the system.
//
#if defined(_NTDRIVER_) || defined(_NTDDK_) || defined(_NTIFS_) || defined(_WDMDDK_)
// begin_ntddk begin_wdm
#if defined(_AMD64_)
NTKERNELAPI
KIRQL
KeGetCurrentIrql (
VOID
);
NTKERNELAPI
VOID
KeLowerIrql (
IN KIRQL NewIrql
);
#define KeRaiseIrql(a,b) *(b) = KfRaiseIrql(a)
NTKERNELAPI
KIRQL
KfRaiseIrql (
IN KIRQL NewIrql
);
// end_wdm
NTKERNELAPI
KIRQL
KeRaiseIrqlToDpcLevel (
VOID
);
NTKERNELAPI
KIRQL
KeRaiseIrqlToSynchLevel (
VOID
);
// begin_wdm
#endif // defined(_AMD64_)
// end_ntddk end_wdm
#else
// begin_nthal
#if defined(_AMD64_) && !defined(MIDL_PASS)
__forceinline
KIRQL
KeGetCurrentIrql (
VOID
)
/*++
Routine Description:
This function return the current IRQL.
Arguments:
None.
Return Value:
The current IRQL is returned as the function value.
--*/
{
return (KIRQL)ReadCR8();
}
__forceinline
VOID
KeLowerIrql (
IN KIRQL NewIrql
)
/*++
Routine Description:
This function lowers the IRQL to the specified value.
Arguments:
NewIrql - Supplies the new IRQL value.
Return Value:
None.
--*/
{
ASSERT(KeGetCurrentIrql() >= NewIrql);
WriteCR8(NewIrql);
return;
}
#define KeRaiseIrql(a,b) *(b) = KfRaiseIrql(a)
__forceinline
KIRQL
KfRaiseIrql (
IN KIRQL NewIrql
)
/*++
Routine Description:
This function raises the current IRQL to the specified value and returns
the previous IRQL.
Arguments:
NewIrql (cl) - Supplies the new IRQL value.
Return Value:
The previous IRQL is retured as the function value.
--*/
{
KIRQL OldIrql;
OldIrql = KeGetCurrentIrql();
ASSERT(OldIrql <= NewIrql);
WriteCR8(NewIrql);
return OldIrql;
}
__forceinline
KIRQL
KeRaiseIrqlToDpcLevel (
VOID
)
/*++
Routine Description:
This function raises the current IRQL to DPC_LEVEL and returns the
previous IRQL.
Arguments:
None.
Return Value:
The previous IRQL is retured as the function value.
--*/
{
KIRQL OldIrql;
OldIrql = KeGetCurrentIrql();
ASSERT(OldIrql <= DISPATCH_LEVEL);
WriteCR8(DISPATCH_LEVEL);
return OldIrql;
}
__forceinline
KIRQL
KeRaiseIrqlToSynchLevel (
VOID
)
/*++
Routine Description:
This function raises the current IRQL to SYNCH_LEVEL and returns the
previous IRQL.
Arguments:
Return Value:
The previous IRQL is retured as the function value.
--*/
{
KIRQL OldIrql;
OldIrql = KeGetCurrentIrql();
ASSERT(OldIrql <= SYNCH_LEVEL);
WriteCR8(SYNCH_LEVEL);
return OldIrql;
}
#endif // defined(_AMD64_) && !defined(MIDL_PASS)
// end_nthal
#endif // defined(_NTDRIVER_) || defined(_NTDDK_) || defined(_NTIFS_) || defined(_WDMDDK_)
// end_ntosp
//
// misc routines
//
VOID
KeOptimizeProcessorControlState (
VOID
);
// begin_nthal
#if defined(_AMD64_)
//
// Structure to aid in booting secondary processors
//
#pragma pack(push,2)
typedef struct _FAR_JMP_16 {
UCHAR OpCode; // = 0xe9
USHORT Offset;
} FAR_JMP_16;
typedef struct _FAR_TARGET_32 {
ULONG Offset;
USHORT Selector;
} FAR_TARGET_32;
typedef struct _PSEUDO_DESCRIPTOR_32 {
USHORT Limit;
ULONG Base;
} PSEUDO_DESCRIPTOR_32;
#pragma pack(pop)
#define PSB_GDT32_NULL 0 * 16
#define PSB_GDT32_CODE64 1 * 16
#define PSB_GDT32_DATA32 2 * 16
#define PSB_GDT32_CODE32 3 * 16
#define PSB_GDT32_MAX 3
typedef struct _PROCESSOR_START_BLOCK *PPROCESSOR_START_BLOCK;
typedef struct _PROCESSOR_START_BLOCK {
//
// The block starts with a jmp instruction to the end of the block
//
FAR_JMP_16 Jmp;
//
// Completion flag is set to non-zero when the target processor has
// started
//
ULONG CompletionFlag;
//
// Pseudo descriptors for GDT and IDT.
//
PSEUDO_DESCRIPTOR_32 Gdt32;
PSEUDO_DESCRIPTOR_32 Idt32;
//
// The temporary 32-bit GDT itself resides here.
//
KGDTENTRY64 Gdt[PSB_GDT32_MAX + 1];
//
// Physical address of the 64-bit top-level identity-mapped page table.
//
ULONG64 TiledCr3;
//
// Far jump target from Rm to Pm code
//
FAR_TARGET_32 PmTarget;
//
// Far jump target from Pm to Lm code
//
FAR_TARGET_32 LmIdentityTarget;
//
// Address of LmTarget
//
PVOID LmTarget;
//
// Linear address of this structure
//
PPROCESSOR_START_BLOCK SelfMap;
//
// Contents of the PAT msr
//
ULONG64 MsrPat;
//
// Initial processor state for the processor to be started
//
KPROCESSOR_STATE ProcessorState;
} PROCESSOR_START_BLOCK;
//
// AMD64 functions for special instructions
//
typedef struct _CPU_INFO {
ULONG Eax;
ULONG Ebx;
ULONG Ecx;
ULONG Edx;
} CPU_INFO, *PCPU_INFO;
VOID
KiCpuId (
ULONG Function,
PCPU_INFO CpuInfo
);
//
// Define read/write MSR functions and register definitions.
//
#define MSR_TSC 0x10 // time stamp counter
#define MSR_PAT 0x277 // page attributes table
#define MSR_MCG_CAP 0x179 // machine check capabilities
#define MSR_MCG_STATUS 0x17a // machine check status
#define MSR_MCG_CTL 0x17b // machine check control
#define MSR_MC0_CTL 0x400 // machine check control, status,
#define MSR_MC0_STATUS 0x401 // address, and miscellaneous
#define MSR_MC0_ADDR 0x402 // registers for machine check
#define MSR_MC0_MISC 0x403 // sources
#define MSR_EFER 0xc0000080 // extended function enable register
#define MSR_STAR 0xc0000081 // system call selectors
#define MSR_LSTAR 0xc0000082 // system call 64-bit entry
#define MSR_CSTAR 0xc0000083 // system call 32-bit entry
#define MSR_SYSCALL_MASK 0xc0000084 // system call flags mask
#define MSR_FS_BASE 0xc0000100 // fs long mode base address register
#define MSR_GS_BASE 0xc0000101 // gs long mode base address register
#define MSR_GS_SWAP 0xc0000102 // gs long mode swap GS base register
#define MSR_PERF_EVT_SEL0 0xc0010000 // performance event select registers
#define MSR_PERF_EVT_SEL1 0xc0010001 //
#define MSR_PERF_EVT_SEL2 0xc0010002 //
#define MSR_PERF_EVT_SEL3 0xc0010003 //
#define MSR_PERF_CTR0 0xc0010004 // performance counter registers
#define MSR_PERF_CTR1 0xc0010005 //
#define MSR_PERF_CTR2 0xc0010006 //
#define MSR_PERF_CTR3 0xc0010007 //
//
// Flags within MSR_EFER
//
#define MSR_SCE 0x00000001 // system call enable
#define MSR_LME 0x00000100 // long mode enable
#define MSR_LMA 0x00000400 // long mode active
#define MSR_NXE 0x00000800 // no execute enable
//
// Page attributes table.
//
#define PAT_TYPE_STRONG_UC 0 // uncacheable/strongly ordered
#define PAT_TYPE_USWC 1 // write combining/weakly ordered
#define PAT_TYPE_WT 4 // write through
#define PAT_TYPE_WP 5 // write protected
#define PAT_TYPE_WB 6 // write back
#define PAT_TYPE_WEAK_UC 7 // uncacheable/weakly ordered
//
// Page attributes table structure.
//
typedef union _PAT_ATTRIBUTES {
struct {
UCHAR Pat[8];
} hw;
ULONG64 QuadPart;
} PAT_ATTRIBUTES, *PPAT_ATTRIBUTES;
#define ReadMSR(Msr) __readmsr(Msr)
ULONG64
__readmsr (
IN ULONG Msr
);
#define WriteMSR(Msr, Data) __writemsr(Msr, Data)
VOID
__writemsr (
IN ULONG Msr,
IN ULONG64 Value
);
#define InvalidatePage(Page) __invlpg(Page)
VOID
__invlpg (
IN PVOID Page
);
#define WritebackInvalidate() __wbinvd()
VOID
__wbinvd (
VOID
);
#pragma intrinsic(__readmsr)
#pragma intrinsic(__writemsr)
#pragma intrinsic(__invlpg)
#pragma intrinsic(__wbinvd)
#endif // _AMD64_
// end_nthal
#if !(defined(_NTDRIVER_) || defined(_NTDDK_) || defined(_NTIFS_) || defined(_NTHAL_) || defined(_NTOSP_) || defined(_WDMDDK_))
__forceinline
VOID
KxAcquireSpinLock (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function acquires a spin lock at the current IRQL.
Arguments:
SpinLock - Supplies a pointer to an spin lock.
Return Value:
None.
--*/
{
//
// Acquire the specified spin lock at the current IRQL.
//
#if !defined(NT_UP)
#if DBG
LONG64 Thread;
Thread = (LONG64)KeGetCurrentThread() + 1;
while (InterlockedCompareExchange64((PLONG64)SpinLock,
Thread,
0) != 0) {
#else
while (InterlockedBitTestAndSet64((LONG64 *)SpinLock, 0)) {
#endif // DBG
do {
KeMemoryBarrierWithoutFence();
} while (BitTest64((LONG64 *)SpinLock, 0));
}
#else
UNREFERENCED_PARAMETER(SpinLock);
#endif // !defined(NT_UP)
return;
}
__forceinline
BOOLEAN
KxTryToAcquireSpinLock (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function attempts acquires a spin lock at the current IRQL. If
the spinlock is already owned, then FALSE is returned. Otherwise,
TRUE is returned.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
Return Value:
If the spin lock is acquired a value TRUE is returned. Otherwise, FALSE
is returned as the function value.
--*/
{
//
// Try to acquire the specified spin lock at the current IRQL.
//
#if !defined(NT_UP)
KeMemoryBarrierWithoutFence();
if (!BitTest64((LONG64 *)SpinLock, 0)) {
#if DBG
LONG64 Thread;
Thread = (LONG64)KeGetCurrentThread() + 1;
return InterlockedCompareExchange64((PLONG64)SpinLock,
Thread,
0) == 0 ? TRUE : FALSE;
#else
return !InterlockedBitTestAndSet64((LONG64 *)SpinLock, 0);
#endif // DBG
} else {
return FALSE;
}
#else
UNREFERENCED_PARAMETER(SpinLock);
return TRUE;
#endif // !defined(NT_UP)
}
__forceinline
KIRQL
KeAcquireSpinLockRaiseToDpc (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function raises IRQL to DISPATCH_LEVEL and acquires the specified
spin lock.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
Return Value:
The previous IRQL is returned.
--*/
{
KIRQL OldIrql;
//
// Raise IRQL to DISPATCH_LEVEL and acquire the specified spin lock.
//
OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
KxAcquireSpinLock(SpinLock);
return OldIrql;
}
__forceinline
KIRQL
KeAcquireSpinLockRaiseToSynch (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function raises IRQL to SYNCH_LEVEL and acquires the specified
spin lock.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
Return Value:
The previous IRQL is returned as the function value.
--*/
{
KIRQL OldIrql;
//
// Raise IRQL to SYNCH_LEVEL and acquire the specified spin lock.
//
OldIrql = KfRaiseIrql(SYNCH_LEVEL);
KxAcquireSpinLock(SpinLock);
return OldIrql;
}
__forceinline
VOID
KeAcquireSpinLockAtDpcLevel (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function acquires a spin lock at the current IRQL.
Arguments:
SpinLock - Supplies a pointer to an spin lock.
Return Value:
None.
--*/
{
//
// Acquired the specified spin lock at the current IRQL.
//
KxAcquireSpinLock(SpinLock);
return;
}
__forceinline
VOID
KxReleaseSpinLock (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function releases the specified spin lock at the current IRQL.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
Return Value:
None.
--*/
{
#if !defined(NT_UP)
#if DBG
ASSERT(*(volatile LONG64 *)SpinLock == (LONG64)KeGetCurrentThread() + 1);
#endif // DBG
KeMemoryBarrierWithoutFence();
*(volatile LONG64 *)SpinLock = 0;
#else
UNREFERENCED_PARAMETER(SpinLock);
#endif // !defined(NT_UP)
return;
}
__forceinline
VOID
KeReleaseSpinLock (
IN PKSPIN_LOCK SpinLock,
IN KIRQL OldIrql
)
/*++
Routine Description:
This function releases the specified spin lock and lowers IRQL to a
previous value.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
OldIrql - Supplies the previous IRQL value.
Return Value:
None.
--*/
{
KxReleaseSpinLock(SpinLock);
KeLowerIrql(OldIrql);
return;
}
__forceinline
VOID
KeReleaseSpinLockFromDpcLevel (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function releases a spin lock at the current IRQL.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
Return Value:
None.
--*/
{
KxReleaseSpinLock(SpinLock);
return;
}
__forceinline
BOOLEAN
KeTestSpinLock (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function tests a spin lock to determine if it is currently owned.
If the spinlock is already owned, then FALSE is returned. Otherwise,
TRUE is returned.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
Return Value:
If the spin lock is currently owned, then a value of FALSE is returned.
Otherwise, a value of TRUE is returned.
--*/
{
KeMemoryBarrierWithoutFence();
return !BitTest64((LONG64 *)SpinLock, 0);
}
__forceinline
BOOLEAN
KeTryToAcquireSpinLock (
IN PKSPIN_LOCK SpinLock,
OUT PKIRQL OldIrql
)
/*++
Routine Description:
This function raises IRQL to DISPATCH level and attempts to acquire a
spin lock. If the spin lock is already owned, then IRQL is restored to
its previous value and FALSE is returned. Otherwise, the spin lock is
acquired and TRUE is returned.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
OldIrql - Supplies a pointer to a variable that receives the old IRQL.
Return Value:
If the spin lock is acquired a value TRUE is returned. Otherwise, FALSE
is returned.
--*/
{
//
// Raise IRQL to DISPATCH level and attempt to acquire the specified
// spin lock.
//
*OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
if (KxTryToAcquireSpinLock(SpinLock) == FALSE) {
KeLowerIrql(*OldIrql);
return FALSE;
}
return TRUE;
}
__forceinline
BOOLEAN
KeTryToAcquireSpinLockAtDpcLevel (
IN PKSPIN_LOCK SpinLock
)
/*++
Routine Description:
This function attempts acquires a spin lock at the current IRQL. If
the spinlock is already owned, then FALSE is returned. Otherwise,
TRUE is returned.
Arguments:
SpinLock - Supplies a pointer to a spin lock.
Return Value:
If the spin lock is acquired a value TRUE is returned. Otherwise, FALSE
is returned as the function value.
--*/
{
//
// Try to acquire the specified spin lock at the current IRQL.
//
return KxTryToAcquireSpinLock(SpinLock);
}
#endif
//
// Define software feature bit definitions.
//
#define KF_V86_VIS 0x00000001
#define KF_RDTSC 0x00000002
#define KF_CR4 0x00000004
#define KF_CMOV 0x00000008
#define KF_GLOBAL_PAGE 0x00000010
#define KF_LARGE_PAGE 0x00000020
#define KF_MTRR 0x00000040
#define KF_CMPXCHG8B 0x00000080
#define KF_MMX 0x00000100
#define KF_WORKING_PTE 0x00000200
#define KF_PAT 0x00000400
#define KF_FXSR 0x00000800
#define KF_FAST_SYSCALL 0x00001000
#define KF_XMMI 0x00002000
#define KF_3DNOW 0x00004000
#define KF_AMDK6MTRR 0x00008000
#define KF_XMMI64 0x00010000
#define KF_DTS 0x00020000
#define KF_SMT 0x00040000
//
// Define required software feature bits.
//
#define KF_REQUIRED (KF_RDTSC | KF_CR4 | KF_CMOV | KF_GLOBAL_PAGE | \
KF_LARGE_PAGE | KF_CMPXCHG8B | KF_MMX | KF_WORKING_PTE | \
KF_PAT | KF_FXSR | KF_FAST_SYSCALL | KF_XMMI | KF_XMMI64)
//
// Define hardware feature bits definitions.
//
#define HF_FPU 0x00000001 // FPU is on chip
#define HF_VME 0x00000002 // virtual 8086 mode enhancement
#define HF_DE 0x00000004 // debugging extension
#define HF_PSE 0x00000008 // page size extension
#define HF_TSC 0x00000010 // time stamp counter
#define HF_MSR 0x00000020 // rdmsr and wrmsr support
#define HF_PAE 0x00000040 // physical address extension
#define HF_MCE 0x00000080 // machine check exception
#define HF_CXS 0x00000100 // cmpxchg8b instruction supported
#define HF_APIC 0x00000200 // APIC on chip
#define HF_UNUSED0 0x00000400 // unused bit
#define HF_SYSCALL 0x00000800 // fast system call
#define HF_MTRR 0x00001000 // memory type range registers
#define HF_PGE 0x00002000 // global page TB support
#define HF_MCA 0x00004000 // machine check architecture
#define HF_CMOV 0x00008000 // cmov instruction supported
#define HF_PAT 0x00010000 // physical attributes table
#define HF_UNUSED1 0x00020000 // unused bit
#define HF_UNUSED2 0x00040000 // unused bit
#define HF_UNUSED3 0x00080000 // unused bit
#define HF_NOEXECUTE 0x00100000 // no execute protection
#define HF_UNUSED5 0x00200000 // unused bit
#define HF_UNUSED6 0x00400000 // unused bit
#define HF_MMX 0x00800000 // MMX technology supported
#define HF_FXSR 0x01000000 // fxsr instruction supported
#define HF_XMMI 0x02000000 // xmm (SSE) registers supported
#define HF_XMMI64 0x04000000 // xmm (SSE2) registers supported
//
// Define required hardware feature bits.
//
#define HF_REQUIRED (HF_FPU | HF_DE | HF_PSE | HF_TSC | HF_MSR | \
HF_PAE | HF_MCE | HF_CXS | HF_APIC | HF_SYSCALL | \
HF_PGE | HF_MCA | HF_CMOV | HF_PAT | HF_MMX | \
HF_FXSR | HF_XMMI | HF_XMMI64)
//
// Define extended hardware feature bit definitions.
//
#define XHF_3DNOW 0x80000000 // 3DNOW supported
#endif // __amd64_