/*++ BUILD Version: 0014    // Increment this if a change has global effects

Copyright (c) 1989  Microsoft Corporation

Module Name:

    i386.h

Abstract:

    This module contains the i386 hardware specific header file.

Author:

    David N. Cutler (davec) 2-Aug-1989

Revision History:

    25-Jan-1990    shielint

                   Added definitions for 8259 ports and commands and
                   macros for 8259 irq# and system irql conversion.

--*/

#ifndef _i386_
#define _i386_


// begin_ntddk begin_nthal begin_ntndis begin_updriver

#if defined(_X86_)

// end_ntddk end_nthal end_ntndis end_updriver (This is so the string "updriver" doesn't appear in nthal/ntddk/ntifs.)
// begin_ntddk begin_nthal begin_ntndis
//
// Indicate that the i386 compiler supports the pragma textout construct.
//

#define ALLOC_PRAGMA 1
//
// Indicate that the i386 compiler supports the DATA_SEG("INIT") and
// DATA_SEG("PAGE") pragmas
//

#define ALLOC_DATA_PRAGMA 1

//
// Define function decoration depending on whether a driver, a file system,
// or a kernel component is being built.
//

#if (defined(_NTDDK_) || defined(_NTIFS_) || defined(_NTHAL_)) && !defined (_BLDR_)

#define NTKERNELAPI DECLSPEC_IMPORT

#else

#define NTKERNELAPI

#endif

//
// Define function decoration depending on whether the HAL or other kernel
// component is being build.
//

#if !defined(_NTHAL_) && !defined(_BLDR_)

#define NTHALAPI DECLSPEC_IMPORT

#else

#define NTHALAPI

#endif

//
// Define function decoration for FASTCALL calling convention
//

#define FASTCALL    _fastcall

// end_ntddk end_nthal end_ntndis

//  NOTE -  KiPcr is only useful for PCR references where we know we
//          won't get context switched between the call to it and the
//          variable reference, OR, were we don't care, (ie TEB pointer)

//  BUGBUG bryanwi 11 june 90 - we must not macro out things we export
//      Things like KeFlushIcache and KeFlushDcache cannot be macroed
//      out because external code (like drivers) will want to import
//      them by name.  Therefore, the defines below that turn them into
//      nothing are inappropriate.  But this isn't going to hurt us right
//      now.

//  BUGBUG kenr - remove this PIC stuff from i386.h!


//
// Interrupt controller register addresses.
//

#define PIC1_PORT0 0x20         // master PIC
#define PIC1_PORT1 0x21
#define PIC2_PORT0 0x0A0        // slave PIC
#define PIC2_PORT1 0x0A1

//
// Commands for Interrupt Controller
//

#define PIC1_EOI_MASK 0x60
#define PIC2_EOI      0x62
#define OCW2_NON_SPECIFIC_EOI 0x20
#define OCW3_READ_ISR 0xb
#define OCW3_READ_IRR 0xa


//
// Length on interupt object dispatch code in longwords.
// BUGBUG 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
#define DISPATCH_LENGTH NORMAL_DISPATCH_LENGTH      // ntddk


//
// Define constants to access the bits in CR0.
//

#define CR0_PG  0x80000000          // paging
#define CR0_ET  0x00000010          // extension type (80387)
#define CR0_TS  0x00000008          // task switched
#define CR0_EM  0x00000004          // emulate math coprocessor
#define CR0_MP  0x00000002          // math present
#define CR0_PE  0x00000001          // protection enable

//
// More CR0 bits; these only apply to the 80486.
//

#define CR0_CD  0x40000000          // cache disable
#define CR0_NW  0x20000000          // not write-through
#define CR0_AM  0x00040000          // alignment mask
#define CR0_WP  0x00010000          // write protect
#define CR0_NE  0x00000020          // numeric error

//
// CR4 bits;  These only apply to Pentium
//
#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_MCE 0x00000040          // Machine check enable

// end_nthal

//
// Define constants to access ThNpxState
//
// NOTE: NPX_STATE_EMULATED is a placeholder.  It is used to allow us
//       to have TS clear when there is no npx (ok, because EM will be set).
//       We put this value in ThNpxState, so that the ctx swap code in the MP
//       kernel will not try to save the state on systems w/o Npx's

#define NPX_STATE_NOT_LOADED    CR0_TS
#define NPX_STATE_LOADED        0
#define NPX_STATE_EMULATED      CR0_PE

//
// External references to the labels defined in int.asm
//

extern ULONG KiInterruptTemplate[NORMAL_DISPATCH_LENGTH];
extern PULONG KiInterruptTemplateObject;
extern PULONG KiInterruptTemplateDispatch;

// begin_ntddk begin_nthal
//
// 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 PROFILE_LEVEL 27            // timer used for profiling.
#define CLOCK1_LEVEL 28             // Interval clock 1 level - Not used on x86
#define CLOCK2_LEVEL 28             // Interval clock 2 level
#define IPI_LEVEL 29                // Interprocessor interrupt level
#define POWER_LEVEL 30              // Power failure level
#define HIGH_LEVEL 31               // Highest interrupt level
// end_ntddk

//
// Machine type definitions
// BUGBUG shielint This is temporary definitions.
//

#define MACHINE_TYPE_ISA 0
#define MACHINE_TYPE_EISA 1
#define MACHINE_TYPE_MCA 2

//
// Define constants used in selector tests.
//
//  RPL_MASK is the real value for extracting RPL values.  IT IS THE WRONG
//  CONSTANT TO USE FOR MODE TESTING.
//
//  MODE_MASK is the value for deciding the current mode.
//  WARNING:    MODE_MASK assumes that all code runs at either ring-0
//              or ring-3.  Ring-1 or Ring-2 support will require changing
//              this value and all of the code that refers to it.

#define MODE_MASK    1
#define RPL_MASK     3

//
// SEGMENT_MASK is used to throw away trash part of segment.  Part always
// pushes or pops 32 bits to/from stack, but if it's a segment value,
// high order 16 bits are trash.
//

#define SEGMENT_MASK    0xffff

//
// 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

//
// Define the default thread and process quantum values.
//

#define PROCESS_QUANTUM 2           // Process quantum in thread quantums
#define THREAD_QUANTUM 2            // Thread quantum in ticks

//
// Define the default quantum decrement values.
//

#define CLOCK_QUANTUM_DECREMENT 1   // Decremnet value at clock interrupt
#define WAIT_QUANTUM_DECREMENT 1    // Decrement value at wait operation

//
// 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)(l))

//
// Macro to combine two USHORT offsets into a long offset
//

#define MAKEULONG(x, y) \
    (((((ULONG)(x))<<16) & 0xffff0000) | \
    ((ULONG)(y) & 0xffff))

// end_nthal

//
// Request a software interrupt.
//

#define KiRequestSoftwareInterrupt(RequestIrql) \
    HalRequestSoftwareInterrupt( RequestIrql )

// begin_ntddk begin_nthal begin_ntndis

//
// I/O space read and write macros.
//
//  These have to be actual functions on the 386, because we need
//  to use assembler, but cannot return a value if we inline it.
//
//  The READ/WRITE_REGISTER_* calls manipulate I/O registers in MEMORY space.
//  (Use x86 move instructions, with LOCK prefix to force correct behavior
//   w.r.t. caches and write buffers.)
//
//  The READ/WRITE_PORT_* calls manipulate I/O registers in PORT space.
//  (Use x86 in/out instructions.)
//

NTKERNELAPI
UCHAR
READ_REGISTER_UCHAR(
    PUCHAR  Register
    );

NTKERNELAPI
USHORT
READ_REGISTER_USHORT(
    PUSHORT Register
    );

NTKERNELAPI
ULONG
READ_REGISTER_ULONG(
    PULONG  Register
    );

NTKERNELAPI
VOID
READ_REGISTER_BUFFER_UCHAR(
    PUCHAR  Register,
    PUCHAR  Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
READ_REGISTER_BUFFER_USHORT(
    PUSHORT Register,
    PUSHORT Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
READ_REGISTER_BUFFER_ULONG(
    PULONG  Register,
    PULONG  Buffer,
    ULONG   Count
    );


NTKERNELAPI
VOID
WRITE_REGISTER_UCHAR(
    PUCHAR  Register,
    UCHAR   Value
    );

NTKERNELAPI
VOID
WRITE_REGISTER_USHORT(
    PUSHORT Register,
    USHORT  Value
    );

NTKERNELAPI
VOID
WRITE_REGISTER_ULONG(
    PULONG  Register,
    ULONG   Value
    );

NTKERNELAPI
VOID
WRITE_REGISTER_BUFFER_UCHAR(
    PUCHAR  Register,
    PUCHAR  Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
WRITE_REGISTER_BUFFER_USHORT(
    PUSHORT Register,
    PUSHORT Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
WRITE_REGISTER_BUFFER_ULONG(
    PULONG  Register,
    PULONG  Buffer,
    ULONG   Count
    );

NTKERNELAPI
UCHAR
READ_PORT_UCHAR(
    PUCHAR  Port
    );

NTKERNELAPI
USHORT
READ_PORT_USHORT(
    PUSHORT Port
    );

NTKERNELAPI
ULONG
READ_PORT_ULONG(
    PULONG  Port
    );

NTKERNELAPI
VOID
READ_PORT_BUFFER_UCHAR(
    PUCHAR  Port,
    PUCHAR  Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
READ_PORT_BUFFER_USHORT(
    PUSHORT Port,
    PUSHORT Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
READ_PORT_BUFFER_ULONG(
    PULONG  Port,
    PULONG  Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
WRITE_PORT_UCHAR(
    PUCHAR  Port,
    UCHAR   Value
    );

NTKERNELAPI
VOID
WRITE_PORT_USHORT(
    PUSHORT Port,
    USHORT  Value
    );

NTKERNELAPI
VOID
WRITE_PORT_ULONG(
    PULONG  Port,
    ULONG   Value
    );

NTKERNELAPI
VOID
WRITE_PORT_BUFFER_UCHAR(
    PUCHAR  Port,
    PUCHAR  Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
WRITE_PORT_BUFFER_USHORT(
    PUSHORT Port,
    PUSHORT Buffer,
    ULONG   Count
    );

NTKERNELAPI
VOID
WRITE_PORT_BUFFER_ULONG(
    PULONG  Port,
    PULONG  Buffer,
    ULONG   Count
    );

// end_ntndis
//
// Get data cache fill size.
//

#define KeGetDcacheFillSize() 1L

// end_ntddk end_nthal

//
// Fill TB entry.
//

#define KeFillEntryTb(Pte, Virtual, Invalid) \
    if (Invalid != FALSE) { \
        KeFlushSingleTb(Virtual, FALSE, FALSE, Pte, *Pte); \
    }


//
// Data cache, instruction cache, I/O buffer, and write buffer flush routine
// prototypes.
//

//  386 and 486 have transparent caches, so these are noops.

#define KeSweepDcache(AllProcessors)
#define KeSweepCurrentDcache()

#define KeSweepIcache(AllProcessors)
#define KeSweepCurrentIcache()

#define KeSweepIcacheRange(AllProcessors, BaseAddress, Length)

// begin_ntddk begin_nthal begin_ntndis

#define KeFlushIoBuffers(Mdl, ReadOperation, DmaOperation)

// end_ntddk end_nthal end_ntndis

//
// 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.
//
// KeRaiseIrql is one instruction longer than KeAcquireSpinLock on x86 UP.
// KeLowerIrql and KeReleaseSpinLock are the same.
//
// begin_updriver

#if defined(NT_UP)
#define ExAcquireSpinLock(Lock, OldIrql) KeAcquireSpinLock((Lock), (OldIrql))
#define ExReleaseSpinLock(Lock, OldIrql) KeReleaseSpinLock((Lock), (OldIrql))
#define ExAcquireSpinLockAtDpcLevel(Lock)
#define ExReleaseSpinLockFromDpcLevel(Lock)
#else
#define ExAcquireSpinLock(Lock, OldIrql) KeAcquireSpinLock((Lock), (OldIrql))
#define ExReleaseSpinLock(Lock, OldIrql) KeReleaseSpinLock((Lock), (OldIrql))
#define ExAcquireSpinLockAtDpcLevel(Lock) KeAcquireSpinLockAtDpcLevel(Lock)
#define ExReleaseSpinLockFromDpcLevel(Lock) KeReleaseSpinLockFromDpcLevel(Lock)
#endif

// end_updriver
//
// 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_IX86) && !defined(USER_MODE_CODE)

#pragma warning(disable:4164)
#pragma intrinsic(_disable)
#pragma intrinsic(_enable)
#pragma warning(default:4164)

#endif

#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

VOID
FASTCALL
KiAcquireSpinLock (
    IN PKSPIN_LOCK SpinLock
    );

VOID
FASTCALL
KiReleaseSpinLock (
    IN PKSPIN_LOCK SpinLock
    );

// end_nthal

//
// Define query system time macro.
//

#define KiQuerySystemTime(CurrentTime)                                  \
    do {                                                                \
        (CurrentTime)->HighPart = SharedUserData->SystemTime.High1Time; \
        (CurrentTime)->LowPart = SharedUserData->SystemTime.LowPart;    \
    } while ((CurrentTime)->HighPart != SharedUserData->SystemTime.High2Time)

//
// Define query tick count macro.
//
// begin_ntddk begin_nthal

#if defined(_NTDDK_) || defined(_NTIFS_)

#define KeQueryTickCount(CurrentCount ) { \
    PKSYSTEM_TIME _TickCount = *((PKSYSTEM_TIME *)(&KeTickCount)); \
    do {                                                          \
        (CurrentCount)->HighPart = _TickCount->High1Time;          \
        (CurrentCount)->LowPart = _TickCount->LowPart;             \
    } while ((CurrentCount)->HighPart != _TickCount->High2Time);   \
}

#else

#define KiQueryTickCount(CurrentCount) \
    do {                                                        \
        (CurrentCount)->HighPart = KeTickCount.High1Time;       \
        (CurrentCount)->LowPart = KeTickCount.LowPart;          \
    } while ((CurrentCount)->HighPart != KeTickCount.High2Time)

VOID
KeQueryTickCount (
    OUT PLARGE_INTEGER CurrentCount
    );

#endif

// end_ntddk end_nthal

#define KiQueryLowTickCount() KeTickCount.LowPart

//
// Define query interrupt time macro.
//

#define KiQueryInterruptTime(CurrentTime)                                  \
    do {                                                                   \
        (CurrentTime)->HighPart = SharedUserData->InterruptTime.High1Time; \
        (CurrentTime)->LowPart = SharedUserData->InterruptTime.LowPart;    \
    } while ((CurrentTime)->HighPart != SharedUserData->InterruptTime.High2Time)


// begin_nthal
//
// 386 hardware structures
//

//
// A Page Table Entry on an Intel 386/486 has the following definition.
//

typedef struct _HARDWARE_PTE {
    ULONG Valid : 1;
    ULONG Write : 1;
    ULONG Owner : 1;
    ULONG WriteThrough : 1;
    ULONG CacheDisable : 1;
    ULONG Accessed : 1;
    ULONG Dirty : 1;
    ULONG Rsvd : 2;
    ULONG CopyOnWrite : 1; // software field
    ULONG Prototype : 1;   // software field
    ULONG Transition : 1;  // software field
    ULONG PageFrameNumber : 20;
} HARDWARE_PTE, *PHARDWARE_PTE;

//
// GDT Entry
//

typedef struct _KGDTENTRY {
    USHORT  LimitLow;
    USHORT  BaseLow;
    union {
        struct {
            UCHAR   BaseMid;
            UCHAR   Flags1;     // Declare as bytes to avoid alignment
            UCHAR   Flags2;     // Problems.
            UCHAR   BaseHi;
        } Bytes;
        struct {
            ULONG   BaseMid : 8;
            ULONG   Type : 5;
            ULONG   Dpl : 2;
            ULONG   Pres : 1;
            ULONG   LimitHi : 4;
            ULONG   Sys : 1;
            ULONG   Reserved_0 : 1;
            ULONG   Default_Big : 1;
            ULONG   Granularity : 1;
            ULONG   BaseHi : 8;
        } Bits;
    } HighWord;
} KGDTENTRY, *PKGDTENTRY;

#define TYPE_CODE   0x10  // 11010 = Code, Readable, NOT Conforming, Accessed
#define TYPE_DATA   0x12  // 10010 = Data, ReadWrite, NOT Expanddown, Accessed
#define TYPE_TSS    0x01  // 01001 = NonBusy TSS
#define TYPE_LDT    0x02  // 00010 = LDT

#define DPL_USER    3
#define DPL_SYSTEM  0

#define GRAN_BYTE   0
#define GRAN_PAGE   1

#define SELECTOR_TABLE_INDEX 0x04

//
// Entry of Interrupt Descriptor Table (IDTENTRY)
//

typedef struct _KIDTENTRY {
   USHORT Offset;
   USHORT Selector;
   USHORT Access;
   USHORT ExtendedOffset;
} KIDTENTRY;

typedef KIDTENTRY *PKIDTENTRY;


//
// TSS (Task switch segment) NT only uses to control stack switches.
//
//  The only fields we actually care about are Esp0, Ss0, the IoMapBase
//  and the IoAccessMaps themselves.
//
//
//  N.B.    Size of TSS must be <= 0xDFFF
//

//
// The interrupt direction bitmap is used on Pentium to allow
// the processor to emulate V86 mode software interrupts for us.
// There is one for each IOPM.  It is located by subtracting
// 32 from the IOPM base in the Tss.
//
#define INT_DIRECTION_MAP_SIZE   32
typedef UCHAR   KINT_DIRECTION_MAP[INT_DIRECTION_MAP_SIZE];

#define IOPM_COUNT      1           // Number of i/o access maps that
                                    // exist (in addition to
                                    // IO_ACCESS_MAP_NONE)

#define IO_ACCESS_MAP_NONE 0

#define IOPM_SIZE           8192    // Size of map callers can set.

#define PIOPM_SIZE          8196    // Size of structure we must allocate
                                    // to hold it.

typedef UCHAR   KIO_ACCESS_MAP[IOPM_SIZE];

typedef KIO_ACCESS_MAP *PKIO_ACCESS_MAP;

typedef struct _KiIoAccessMap {
    KINT_DIRECTION_MAP DirectionMap;
    UCHAR IoMap[PIOPM_SIZE];
} KIIO_ACCESS_MAP;


typedef struct _KTSS {

    USHORT  Backlink;
    USHORT  Reserved0;

    ULONG   Esp0;
    USHORT  Ss0;
    USHORT  Reserved1;

    ULONG   NotUsed1[4];

    ULONG   CR3;

    ULONG   Eip;

    ULONG   NotUsed2[9];

    USHORT  Es;
    USHORT  Reserved2;

    USHORT  Cs;
    USHORT  Reserved3;

    USHORT  Ss;
    USHORT  Reserved4;

    USHORT  Ds;
    USHORT  Reserved5;

    USHORT  Fs;
    USHORT  Reserved6;

    USHORT  Gs;
    USHORT  Reserved7;

    USHORT  LDT;
    USHORT  Reserved8;

    USHORT  Flags;

    USHORT  IoMapBase;

    KIIO_ACCESS_MAP IoMaps[IOPM_COUNT];

    //
    // This is the Software interrupt direction bitmap associated with
    // IO_ACCESS_MAP_NONE
    //
    KINT_DIRECTION_MAP IntDirectionMap;
} KTSS, *PKTSS;


#define KiComputeIopmOffset(MapNumber)          \
    (MapNumber == IO_ACCESS_MAP_NONE) ?         \
        (USHORT)(sizeof(KTSS) + 1) :                    \
        (USHORT)(FIELD_OFFSET(KTSS, IoMaps[MapNumber-1].IoMap))

// begin_windbgkd

#ifdef _X86_
//
// Special Registers for i386
//

typedef struct _DESCRIPTOR {
    USHORT  Pad;
    USHORT  Limit;
    ULONG   Base;
} KDESCRIPTOR, *PKDESCRIPTOR;

typedef struct _KSPECIAL_REGISTERS {
    ULONG Cr0;
    ULONG Cr2;
    ULONG Cr3;
    ULONG Cr4;
    ULONG KernelDr0;
    ULONG KernelDr1;
    ULONG KernelDr2;
    ULONG KernelDr3;
    ULONG KernelDr6;
    ULONG KernelDr7;
    KDESCRIPTOR Gdtr;
    KDESCRIPTOR Idtr;
    USHORT Tr;
    USHORT Ldtr;
    ULONG Reserved[6];
} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS;

//
// Processor State frame: Before a processor freezes itself, it
// dumps the processor state to the processor state frame for
// debugger to examine.
//

typedef struct _KPROCESSOR_STATE {
    struct _CONTEXT ContextFrame;
    struct _KSPECIAL_REGISTERS SpecialRegisters;
} KPROCESSOR_STATE, *PKPROCESSOR_STATE;
#endif // _X86_
// end_windbgkd

//
// Processor Control Block (PRCB)
//

#define PRCB_MAJOR_VERSION 1
#define PRCB_MINOR_VERSION 1
#define PRCB_BUILD_DEBUG        0x0001
#define PRCB_BUILD_UNIPROCESSOR 0x0002

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;

    struct _KTHREAD *CurrentThread;
    struct _KTHREAD *NextThread;
    struct _KTHREAD *IdleThread;

    CCHAR  Number;
    CCHAR  Reserved;
    USHORT BuildType;
    KAFFINITY SetMember;

    CCHAR   CpuType;
    CCHAR   CpuID;
    USHORT  CpuStep;

    struct _KPROCESSOR_STATE ProcessorState;

    ULONG   KernelReserved[16];         // For use by the kernel
    ULONG   HalReserved[16];            // For use by Hal

// End of the architecturally defined section of the PRCB.
// end_nthal

    struct _KTHREAD *NpxThread;

    ULONG   InterruptCount;             // per precessor counts
    ULONG   KernelTime;
    ULONG   UserTime;
    ULONG   DpcTime;
    ULONG   InterruptTime;

    KDPC QuantumEndDpc;

    volatile BOOLEAN IpiCommand[IPI_MAXIMUM_COMMAND];
    volatile CCHAR   IpiFrozen;
    volatile ULONG   IpiReverseStall;
    volatile ULONG   IpiLastPacket;

    ULONG   Space[6];
    ULONG   ThreadStartCount[2];        // perf data


//  MP tuning..

//
//  Per-processor data for various hot code which resides in the
//  kernel image.  We give each processor it's own copy of the data
//  to lessen the caching impact of sharing the data between multiple
//  processors.
//

//
//  File system runtime variables.
//

    SINGLE_LIST_ENTRY   FsRtlFreeLockList;
    SINGLE_LIST_ENTRY   FsRtlFreeWaitingLockList;

//
//  Cache manager performance counters.
//

    ULONG CcFastReadNoWait;
    ULONG CcFastReadWait;
    ULONG CcFastReadNotPossible;
    ULONG CcCopyReadNoWait;
    ULONG CcCopyReadWait;
    ULONG CcCopyReadNoWaitMiss;

//
//  Kernel performance counters.
//

    ULONG KeAlignmentFixupCount;
    ULONG KeContextSwitches;
    ULONG KeDcacheFlushCount;
    ULONG KeExceptionDispatchCount;
    ULONG KeFirstLevelTbFills;
    ULONG KeFloatingEmulationCount;
    ULONG KeIcacheFlushCount;
    ULONG KeSecondLevelTbFills;
    ULONG KeSystemCalls;

//
//  Reserved for future counters.
//

    ULONG ReservedCounter[32];

//
// DPC list head, spinlock, and count.
//

    LIST_ENTRY DpcListHead;
    ULONG DpcCount;

    ULONG KernelReserved2[15];
    KSPIN_LOCK DpcLock;
    BOOLEAN SkipTick;
    UCHAR CpuVendorString[13];
    ULONG QuantumEnd;                   // mp perf - Modified in idle loop

// begin_nthal
} KPRCB, *PKPRCB;

// 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.
//

    NT_TIB  NtTib;
    struct _KPCR *SelfPcr;              // flat address of this PCR
    struct _KPRCB *Prcb;                // pointer to Prcb
    KIRQL   Irql;
    ULONG   IRR;
    ULONG   IrrActive;
    ULONG   IDR;
    ULONG   Reserved2;

    struct _KIDTENTRY *IDT;
    struct _KGDTENTRY *GDT;
    struct _KTSS      *TSS;
    USHORT  MajorVersion;
    USHORT  MinorVersion;
    KAFFINITY SetMember;
    ULONG   StallScaleFactor;
    UCHAR   DebugActive;
    UCHAR   Number;

// end_ntddk

    UCHAR   VdmAlert;
    UCHAR   Reserved[1];                // dword align
    ULONG   KernelReserved[16];         // For use by the kernel
    ULONG   HalReserved[16];            // For use by Hal

// End of the architecturally defined section of the PCR.
// end_nthal

    ULONG   InterruptMode;
    BOOLEAN IsExecutingDpc;
    ULONG   KernelReserved2[17];
    struct _KPRCB PrcbData;

// begin_nthal begin_ntddk
} KPCR;
typedef KPCR *PKPCR;

// end_nthal end_ntddk


//
// Sanitize segCS and eFlags based on a processor mode.
//
// If kernel mode,
//      force CPL == 0
//
// If user mode,
//      force CPL == 3
//

#define SANITIZE_SEG(segCS, mode) (\
    ((mode) == KernelMode ? \
        ((0x00000000L) | ((segCS) & 0xfffc)) : \
        ((0x00000003L) | ((segCS) & 0xffff))))

//
// If kernel mode, then
//      let caller specify Carry, Parity, AuxCarry, Zero, Sign, Trap,
//      Direction, Overflow, Interrupt, AlignCheck.
//
// If user mode, then
//      let caller specify Carry, Parity, AuxCarry, Zero, Sign, Trap,
//      Direction, Overflow, AlignCheck.
//      force Interrupts on.
//

#define EFLAGS_INTERRUPT_MASK 0x00000200L
#define EFLAGS_V86_MASK       0x00020000L
#define EFLAGS_ALIGN_CHECK    0x00040000L
#define EFLAGS_IOPL_MASK      0x00003000L
#define EFLAGS_VIF            0x00080000L
#define EFLAGS_VIP            0x00100000L
#define EFLAGS_USER_SANITIZE  0x001e0dd7L

#define SANITIZE_FLAGS(eFlags, mode) (\
    ((mode) == KernelMode ? \
        ((0x00000000L) | ((eFlags) & 0x001e0fd7)) : \
        ((((eFlags) & EFLAGS_V86_MASK) && KeI386VdmIoplAllowed) ? \
        (((eFlags) & KeI386EFlagsAndMaskV86) | KeI386EFlagsOrMaskV86) : \
        ((EFLAGS_INTERRUPT_MASK) | ((eFlags) & EFLAGS_USER_SANITIZE)))))

//
// Masks for Dr7 and sanitize macros for various Dr registers.
//

#define DR6_LEGAL   0x0000e00f

#define DR7_LEGAL   0xffff0155  // R/W, LEN for Dr0-Dr4,
                                // Local enable for Dr0-Dr4,
                                // Le for "perfect" trapping

#define DR7_ACTIVE  0x00000055  // If any of these bits are set, a Dr is active

#define SANITIZE_DR6(Dr6, mode) ((Dr6 & DR6_LEGAL));

#define SANITIZE_DR7(Dr7, mode) ((Dr7 & DR7_LEGAL));

#define SANITIZE_DRADDR(DrReg, mode) (          \
    (mode) == KernelMode ?                      \
        (DrReg) :                               \
        (((PVOID)DrReg <= MM_HIGHEST_USER_ADDRESS) ?   \
            (DrReg) :                           \
            (0)                                 \
        )                                       \
    )

//
// Nonvolatile context pointers
//
// BUGBUG bryanwi 21 feb 90 - This is bogus.  The 386 doesn't have
//                            enough nonvolatile context to make this
//                            structure worthwhile.  Can't declare a
//                            field to be void, so declare a Junk structure
//                            instead.

typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
    ULONG   Junk;
} KNONVOLATILE_CONTEXT_POINTERS,  *PKNONVOLATILE_CONTEXT_POINTERS;

// begin_nthal
//
// Trap frame
//
//  NOTE - We deal only with 32bit registers, so the assembler equivalents
//         are always the extended forms.
//
//  NOTE - Unless you want to run like slow molasses everywhere in the
//         the system, this structure must be of DWORD length, DWORD
//         aligned, and its elements must all be DWORD aligned.
//
//  NOTE WELL   -
//
//      The i386 does not build stack frames in a consistent format, the
//      frames vary depending on whether or not a privledge transition
//      was involved.
//
//      In order to make NtContinue work for both user mode and kernel
//      mode callers, we must force a cononical stack.
//
//      If we're called from kernel mode, this structure is 8 bytes longer
//      than the actual frame!
//
//  WARNING:
//
//      KTRAP_FRAME_LENGTH needs to be 16byte integral (at present.)
//

typedef struct _KTRAP_FRAME {


//
//  Following 4 values are only used and defined for DBG systems,
//  but are always allocated to make switching from DBG to non-DBG
//  and back quicker.  They are not DEVL because they have a non-0
//  performance impact.
//

    ULONG   DbgEbp;         // Copy of User EBP set up so KB will work.
    ULONG   DbgEip;         // EIP of caller to system call, again, for KB.
    ULONG   DbgArgMark;     // Marker to show no args here.
    ULONG   DbgArgPointer;  // Pointer to the actual args

//
//  Temporary values used when frames are edited.
//
//
//  NOTE:   Any code that want's ESP must materialize it, since it
//          is not stored in the frame for kernel mode callers.
//
//          And code that sets ESP in a KERNEL mode frame, must put
//          the new value in TempEsp, make sure that TempSegCs holds
//          the real SegCs value, and put a special marker value into SegCs.
//

    ULONG   TempSegCs;
    ULONG   TempEsp;

//
//  Debug registers.
//

    ULONG   Dr0;
    ULONG   Dr1;
    ULONG   Dr2;
    ULONG   Dr3;
    ULONG   Dr6;
    ULONG   Dr7;

//
//  Segment registers
//

    ULONG   SegGs;
    ULONG   SegEs;
    ULONG   SegDs;

//
//  Volatile registers
//

    ULONG   Edx;
    ULONG   Ecx;
    ULONG   Eax;

//
//  Nesting state, not part of context record
//

    ULONG   PreviousPreviousMode;

    PEXCEPTION_REGISTRATION_RECORD ExceptionList;
                                            // Trash if caller was user mode.
                                            // Saved exception list if caller
                                            // was kernel mode or we're in
                                            // an interrupt.

//
//  FS is TIB/PCR pointer, is here to make save sequence easy
//

    ULONG   SegFs;

//
//  Non-volatile registers
//

    ULONG   Edi;
    ULONG   Esi;
    ULONG   Ebx;
    ULONG   Ebp;

//
//  Control registers
//

    ULONG   ErrCode;
    ULONG   Eip;
    ULONG   SegCs;
    ULONG   EFlags;

    ULONG   HardwareEsp;    // WARNING - segSS:esp are only here for stacks
    ULONG   HardwareSegSs;  // that involve a ring transition.

    ULONG   V86Es;          // these will be present for all transitions from
    ULONG   V86Ds;          // V86 mode
    ULONG   V86Fs;
    ULONG   V86Gs;
} KTRAP_FRAME;


typedef KTRAP_FRAME *PKTRAP_FRAME;
typedef KTRAP_FRAME *PKEXCEPTION_FRAME;

#define KTRAP_FRAME_LENGTH  (sizeof(KTRAP_FRAME))
#define KTRAP_FRAME_ALIGN   (sizeof(ULONG))
#define KTRAP_FRAME_ROUND   (KTRAP_FRAME_ALIGN-1)

//
//  Bits forced to 0 in SegCs if Esp has been edited.
//

#define FRAME_EDITED        0xfff8

// end_nthal

//
// BUGBUG shielint  The second level vectors have not been defined.
//

// #define MAXIMUM_VECTOR 0x20   // Maximum Interrupt Vector


//
//  Switch Frame
//
//  386 doesn't have an "exception frame", and doesn't normally make
//  any use of nonvolatile context register structures.
//
//  However, swapcontext in ctxswap.c and KeInitializeThread in
//  thredini.c need to share common stack structure used at thread
//  startup and switch time.
//
//  This is that structure.
//

typedef struct _KSWITCHFRAME {
    ULONG   ExceptionList;
    ULONG   Eflags;
    ULONG   Ebx;
    ULONG   Edi;
    ULONG   Esi;
    ULONG   Ebp;
    ULONG   RetAddr;
} KSWITCHFRAME, *PKSWITCHFRAME;


//
// Varous 387 defines
//

#define I386_80387_NP_VECTOR    0x07    // trap 7 when hardware not present


//
// i386 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_nthal begin_ntndis
//
// i386 Specific portions of mm component
//

//
// Define the page size for the Intel 386 as 4096 (0x1000).
//

#define PAGE_SIZE (ULONG)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
//
// The highest user address reserves 64K bytes for a guard
// page.  This allows the probing of address from kernel mode to
// only have to check the starting address for strucutures of 64k bytes
// or less.
//

#define MM_HIGHEST_USER_ADDRESS (PVOID)0x7FFEFFFF // temp should be 0xBFFEFFFF

#define MM_USER_PROBE_ADDRESS 0x7FFF0000    // starting address of guard page

//
// The lowest user address reserves the low 64k.
//

#define MM_LOWEST_USER_ADDRESS  (PVOID)0x00010000

//
// The lowest address for system space.
//

#define MM_LOWEST_SYSTEM_ADDRESS (PVOID)0xC0800000

// end_ntddk end_nthal

//
// Define macro to initialize directory table base.
//

#define INITIALIZE_DIRECTORY_TABLE_BASE(dirbase,pfn) \
     *((PULONG)(dirbase)) = ((pfn) << PAGE_SHIFT)


// begin_nthal
//
// Location of primary PCR (used only for UP kernel & hal code)
//

// addressed from 0xffdf0000 - 0xffdfffff are reserved for the system
// (ie, not for use by the hal)

#define KI_BEGIN_KERNEL_RESERVED    0xffdf0000
#define KI_USER_SHARED_DATA         0xffdf0000
#define KIP0PCRADDRESS              0xffdff000

#define SharedUserData  ((KUSER_SHARED_DATA * const) KI_USER_SHARED_DATA)

// begin_ntddk
//
// Result type definition for i386.  (Machine specific enumerate type
// which is return type for portable exinterlockedincrement/decrement
// procedures.)  In general, you should use the enumerated type defined
// in ex.h instead of directly referencing these constants.
//

// Flags loaded into AH by LAHF instruction

#define EFLAG_SIGN      0x8000
#define EFLAG_ZERO      0x4000
#define EFLAG_SELECT    (EFLAG_SIGN | EFLAG_ZERO)

#define RESULT_NEGATIVE ((EFLAG_SIGN & ~EFLAG_ZERO) & EFLAG_SELECT)
#define RESULT_ZERO     ((~EFLAG_SIGN & EFLAG_ZERO) & EFLAG_SELECT)
#define RESULT_POSITIVE ((~EFLAG_SIGN & ~EFLAG_ZERO) & EFLAG_SELECT)

//
// Convert various portable ExInterlock apis into their architecural
// equivalents.
//

#define ExInterlockedIncrementLong(Addend,Lock) \
        Exfi386InterlockedIncrementLong(Addend)

#define ExInterlockedDecrementLong(Addend,Lock) \
        Exfi386InterlockedDecrementLong(Addend)

#define ExInterlockedExchangeUlong(Target,Value,Lock) \
        Exfi386InterlockedExchangeUlong(Target,Value)

#define ExInterlockedAddUlong           ExfInterlockedAddUlong
#define ExInterlockedInsertHeadList     ExfInterlockedInsertHeadList
#define ExInterlockedInsertTailList     ExfInterlockedInsertTailList
#define ExInterlockedRemoveHeadList     ExfInterlockedRemoveHeadList
#define ExInterlockedPopEntryList       ExfInterlockedPopEntryList
#define ExInterlockedPushEntryList      ExfInterlockedPushEntryList

//
// Prototypes for architecural specific versions of Exi386 api
//

//
// Interlocked result type is portable, but its values are machine specific.
// Constants for value are in i386.h, mips.h, etc.
//

typedef enum _INTERLOCKED_RESULT {
    ResultNegative = RESULT_NEGATIVE,
    ResultZero     = RESULT_ZERO,
    ResultPositive = RESULT_POSITIVE
} INTERLOCKED_RESULT;

NTKERNELAPI
INTERLOCKED_RESULT
FASTCALL
Exfi386InterlockedIncrementLong (
    IN PLONG Addend
    );

NTKERNELAPI
INTERLOCKED_RESULT
FASTCALL
Exfi386InterlockedDecrementLong (
    IN PLONG Addend
    );

NTKERNELAPI
ULONG
FASTCALL
Exfi386InterlockedExchangeUlong (
    IN PULONG Target,
    IN ULONG Value
    );

// end_ntddk end_nthal

//
// Structure for Ldt information in x86 processes
//

typedef struct _LDTINFORMATION {
    ULONG Size;
    ULONG AllocatedSize;
    PLDT_ENTRY Ldt;
} LDTINFORMATION, *PLDTINFORMATION;

//
// SetProcessInformation Structure for ProcessSetIoHandlers info class
//

typedef struct _PROCESS_IO_PORT_HANDLER_INFORMATION {
    BOOLEAN Install;            // true if handlers to be installed
    ULONG NumEntries;
    ULONG Context;
    PEMULATOR_ACCESS_ENTRY EmulatorAccessEntries;
} PROCESS_IO_PORT_HANDLER_INFORMATION, *PPROCESS_IO_PORT_HANDLER_INFORMATION;


//
//    Vdm Objects and Io handling structure
//

typedef struct _VDM_IO_HANDLER_FUNCTIONS {
    PDRIVER_IO_PORT_ULONG  UlongIo;
    PDRIVER_IO_PORT_ULONG_STRING UlongStringIo;
    PDRIVER_IO_PORT_USHORT UshortIo[2];
    PDRIVER_IO_PORT_USHORT_STRING UshortStringIo[2];
    PDRIVER_IO_PORT_UCHAR UcharIo[4];
    PDRIVER_IO_PORT_UCHAR_STRING UcharStringIo[4];
} VDM_IO_HANDLER_FUNCTIONS, *PVDM_IO_HANDLER_FUNCTIONS;

typedef struct _VDM_IO_HANDLER {
    struct _VDM_IO_HANDLER *Next;
    ULONG PortNumber;
    VDM_IO_HANDLER_FUNCTIONS IoFunctions[2];
} VDM_IO_HANDLER, *PVDM_IO_HANDLER;



// begin_nthal begin_ntddk

#if !defined(MIDL_PASS) && defined(_M_IX86)
#ifndef __cplusplus

//
// i386 function definitions
//

#pragma warning(disable:4035)               // re-enable below

// end_ntddk

#if NT_UP
    #define _PCR   ds:[KIP0PCRADDRESS]
#else
    #define _PCR   fs:[0]                   // ntddk
#endif

//
// Get address of current processor block.
//
// WARNING: This inline macro can only be used by the kernel or hal
//
#define KiPcr() KeGetPcr()
__inline PKPCR KeGetPcr(VOID)
{
#if NT_UP
    _asm {  mov eax, KIP0PCRADDRESS }
#else
    _asm {  mov eax, _PCR KPCR.SelfPcr  }
#endif
}

//
// Get address of current processor block.
//
// WARNING: This inline macro can only be used by the kernel or hal
//
__inline PKPRCB KeGetCurrentPrcb (VOID)
{
    _asm {  mov eax, _PCR KPCR.Prcb     }
}

// begin_ntddk

//
// Get current IRQL.
//
// On x86 this function resides in the HAL
//

KIRQL
KeGetCurrentIrql();

//
// Get the current processor number
//

__inline ULONG KeGetCurrentProcessorNumber(VOID)
{
    _asm {  movzx eax, _PCR KPCR.Number  }
}

// end_nthal end_ntddk
//
// 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.
// WARNING: This inline macro is always MP enabled because filesystems
// utilize it
//
__inline struct _KTHREAD *KeGetCurrentThread (VOID)
{
    _asm {  mov eax, fs:[0] KPCR.PrcbData.CurrentThread }
}

//
// If processor executing DPC?
// WARNING: This inline macro is always MP enabled because filesystems
// utilize it
//
__inline BOOLEAN KeIsExecutingDpc(VOID)
{
    _asm {  mov al, fs:[0] KPCR.IsExecutingDpc }
}

// begin_nthal begin_ntddk

#else // ifdef __cplusplus

struct _KTHREAD *KeGetCurrentThread (VOID);
KIRQL
KeGetCurrentIrql();

#endif // ifdef __cplusplus
#endif // !defined(MIDL_PASS) && defined(_M_IX86)

// end_nthal end_ntddk

//
// Get previous processor mode.
//
// WARNING: This inline macro can not be used for device drivers or hals
//
// KPROCESSOR_MODE
// KeGetPreviousMode();
#define KeGetPreviousMode()     (KeGetCurrentThread()->PreviousMode)

// begin_nthal
//
// Macro to set address of a trap/interrupt handler to IDT
//
#define KiSetHandlerAddressToIDT(Vector, HandlerAddress) \
    KeGetPcr()->IDT[Vector].ExtendedOffset = HIGHWORD(HandlerAddress); \
    KeGetPcr()->IDT[Vector].Offset = LOWWORD(HandlerAddress);

//
// Macro to return address of a trap/interrupt handler in IDT
//
#define KiReturnHandlerAddressFromIDT(Vector) \
   MAKEULONG(KiPcr()->IDT[Vector].ExtendedOffset, KiPcr()->IDT[Vector].Offset)

#pragma warning(default:4035)
// end_nthal

//++
//
// BOOLEAN
// KiIsThreadNumericStateSaved(
//     IN PKTHREAD Address
//     )
//
//--
#define KiIsThreadNumericStateSaved(a) \
    (a->NpxState != NPX_STATE_LOADED)

//++
//
// VOID
// KiRundownThread(
//     IN PKTHREAD Address
//     )
//
//--
#define KiRundownThread(a)      KiFlushNPXState()

//
// i386 specific probe function definitions.
//
// Probe for write functions definitions.
//
// ++
//
// VOID
// ProbeForWriteBoolean(
//     IN PBOOLEAN Address
//     )
//
//--

#define ProbeForWriteBoolean(Address) {                                      \
    if (((Address) >= (BOOLEAN * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(BOOLEAN));                         \
    }                                                                        \
                                                                             \
    *(volatile BOOLEAN *)(Address) = *(volatile BOOLEAN *)(Address);         \
}

//++
//
// VOID
// ProbeForWriteChar(
//     IN PCHAR Address
//     )
//
//--

#define ProbeForWriteChar(Address) {                                         \
    if (((Address) >= (CHAR * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(CHAR));                            \
    }                                                                        \
                                                                             \
    *(volatile CHAR *)(Address) = *(volatile CHAR *)(Address);               \
}

//++
//
// VOID
// ProbeForWriteUchar(
//     IN PUCHAR Address
//     )
//
//--

#define ProbeForWriteUchar(Address) {                                        \
    if (((Address) >= (UCHAR * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(UCHAR));                           \
    }                                                                        \
                                                                             \
    *(volatile UCHAR *)(Address) = *(volatile UCHAR *)(Address);             \
}

//++
//
// VOID
// ProbeForWriteIoStatus(
//     IN PIO_STATUS_BLOCK Address
//     )
//
//--

#define ProbeForWriteIoStatus(Address) {                                     \
    if (((Address) >= (IO_STATUS_BLOCK * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(IO_STATUS_BLOCK));                 \
    }                                                                        \
                                                                             \
    *(volatile IO_STATUS_BLOCK *)(Address) =                                 \
                                    *(volatile IO_STATUS_BLOCK *)(Address);  \
}

//++
//
// VOID
// ProbeForWriteShort(
//     IN PSHORT Address
//     )
//
//--

#define ProbeForWriteShort(Address) {                                        \
    if (((Address) >= (SHORT * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(SHORT));                           \
    }                                                                        \
                                                                             \
    *(volatile SHORT *)(Address) = *(volatile SHORT *)(Address);             \
}

//++
//
// VOID
// ProbeForWriteUshort(
//     IN PUSHORT Address
//     )
//
//--

#define ProbeForWriteUshort(Address) {                                       \
    if (((Address) >= (USHORT * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(USHORT));                          \
    }                                                                        \
                                                                             \
    *(volatile USHORT *)(Address) = *(volatile USHORT *)(Address);           \
}

//++
//
// VOID
// ProbeForWriteHandle(
//     IN PHANDLE Address
//     )
//
//--

#define ProbeForWriteHandle(Address) {                                       \
    if (((Address) >= (HANDLE * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(HANDLE));                          \
    }                                                                        \
                                                                             \
    *(volatile HANDLE *)(Address) = *(volatile HANDLE *)(Address);           \
}

//++
//
// VOID
// ProbeForWriteLong(
//     IN PLONG Address
//     )
//
//--

#define ProbeForWriteLong(Address) {                                         \
    if (((Address) >= (LONG * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(LONG));                            \
    }                                                                        \
                                                                             \
    *(volatile LONG *)(Address) = *(volatile LONG *)(Address);               \
}

//++
//
// VOID
// ProbeForWriteUlong(
//     IN PULONG Address
//     )
//
//--

#define ProbeForWriteUlong(Address) {                                        \
    if (((Address) >= (ULONG * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(ULONG));                           \
    }                                                                        \
                                                                             \
    *(volatile ULONG *)(Address) = *(volatile ULONG *)(Address);             \
}

//++
//
// VOID
// ProbeForWriteQuad(
//     IN PQUAD Address
//     )
//
//--

#define ProbeForWriteQuad(Address) {                                         \
    if (((Address) >= (QUAD * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(QUAD));                            \
    }                                                                        \
                                                                             \
    *(volatile QUAD *)(Address) = *(volatile QUAD *)(Address);               \
}

//++
//
// VOID
// ProbeForWriteUquad(
//     IN PUQUAD Address
//     )
//
//--

#define ProbeForWriteUquad(Address) {                                        \
    if (((Address) >= (UQUAD * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(UQUAD));                           \
    }                                                                        \
                                                                             \
    *(volatile UQUAD *)(Address) = *(volatile UQUAD *)(Address);             \
}

//
// Probe and write functions definitions.
//
// ++
//
// VOID
// ProbeAndWriteBoolean(
//     IN PBOOLEAN Address,
//     IN BOOLEAN Value
//     )
//
//--

#define ProbeAndWriteBoolean(Address, Value) {                               \
    if (((Address) >= (BOOLEAN * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(BOOLEAN));                         \
    }                                                                        \
                                                                             \
    *(volatile BOOLEAN *)(Address) = (Value);                                \
}

//++
//
// VOID
// ProbeAndWriteChar(
//     IN PCHAR Address,
//     IN CHAR Value
//     )
//
//--

#define ProbeAndWriteChar(Address, Value) {                                  \
    if (((Address) >= (CHAR * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(CHAR));                            \
    }                                                                        \
                                                                             \
    *(volatile CHAR *)(Address) = (Value);                                   \
}

//++
//
// VOID
// ProbeAndWriteUchar(
//     IN PUCHAR Address,
//     IN UCHAR Value
//     )
//
//--

#define ProbeAndWriteUchar(Address, Value) {                                 \
    if (((Address) >= (UCHAR * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(UCHAR));                           \
    }                                                                        \
                                                                             \
    *(volatile UCHAR *)(Address) = (Value);                                  \
}

//++
//
// VOID
// ProbeAndWriteShort(
//     IN PSHORT Address,
//     IN SHORT Value
//     )
//
//--

#define ProbeAndWriteShort(Address, Value) {                                 \
    if (((Address) >= (SHORT * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(SHORT));                           \
    }                                                                        \
                                                                             \
    *(volatile SHORT *)(Address) = (Value);                                  \
}

//++
//
// VOID
// ProbeAndWriteUshort(
//     IN PUSHORT Address,
//     IN USHORT Value
//     )
//
//--

#define ProbeAndWriteUshort(Address, Value) {                                \
    if (((Address) >= (USHORT * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(USHORT));                          \
    }                                                                        \
                                                                             \
    *(volatile USHORT *)(Address) = (Value);                                 \
}

//++
//
// VOID
// ProbeAndWriteHandle(
//     IN PHANDLE Address,
//     IN HANDLE Value
//     )
//
//--

#define ProbeAndWriteHandle(Address, Value) {                                \
    if (((Address) >= (HANDLE * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(HANDLE));                          \
    }                                                                        \
                                                                             \
    *(volatile HANDLE *)(Address) = (Value);                                 \
}

//++
//
// VOID
// ProbeAndWriteLong(
//     IN PLONG Address,
//     IN LONG Value
//     )
//
//--

#define ProbeAndWriteLong(Address, Value) {                                  \
    if (((Address) >= (LONG * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(LONG));                            \
    }                                                                        \
                                                                             \
    *(volatile LONG *)(Address) = (Value);                                   \
}

//++
//
// VOID
// ProbeAndWriteUlong(
//     IN PULONG Address,
//     IN ULONG Value
//     )
//
//--

#define ProbeAndWriteUlong(Address, Value) {                                 \
    if (((Address) >= (ULONG * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(ULONG));                           \
    }                                                                        \
                                                                             \
    *(volatile ULONG *)(Address) = (Value);                                  \
}

//++
//
// VOID
// ProbeAndWriteQuad(
//     IN PQUAD Address,
//     IN QUAD Value
//     )
//
//--

#define ProbeAndWriteQuad(Address, Value) {                                  \
    if (((Address) >= (QUAD * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(QUAD));                            \
    }                                                                        \
                                                                             \
    *(volatile QUAD *)(Address) = (Value);                                   \
}

//++
//
// VOID
// ProbeAndWriteUquad(
//     IN PUQUAD Address,
//     IN UQUAD Value
//     )
//
//--

#define ProbeAndWriteUquad(Address, Value) {                                 \
    if (((Address) >= (UQUAD * const)MM_USER_PROBE_ADDRESS) || MmCheckPteOnProbe) { \
        MmProbeForWrite((Address), sizeof(UQUAD));                           \
    }                                                                        \
                                                                             \
    *(volatile UQUAD *)(Address) = (Value);                                  \
}

//
// functions specific to 386 structure
//

VOID
KiSetIRR (
    IN ULONG SWInterruptMask
    );

VOID
KiInitializeGDT (
    IN OUT PKGDTENTRY Gdt,
    IN USHORT GdtLimit,
    IN PKPCR Pcr,
    IN USHORT PcrLimit,
    IN PKTSS Tss,
    IN USHORT TssLimit,
    IN USHORT TebLimit
    );

VOID
KiInitializeGdtEntry (
    OUT PKGDTENTRY GdtEntry,
    IN ULONG Base,
    IN ULONG Limit,
    IN USHORT Type,
    IN USHORT Dpl,
    IN USHORT Granularity
    );

//
// Procedures to support frame manipulation
//

ULONG
KiEspFromTrapFrame(
    IN PKTRAP_FRAME TrapFrame
    );

VOID
KiEspToTrapFrame(
    IN PKTRAP_FRAME TrapFrame,
    IN ULONG Esp
    );

ULONG
KiSegSsFromTrapFrame(
    IN PKTRAP_FRAME TrapFrame
    );

VOID
KiSegSsToTrapFrame(
    IN PKTRAP_FRAME TrapFrame,
    IN ULONG SegSs
    );

//
// Define prototypes for i386 specific clock and profile interrupt routines.
//

VOID
KiUpdateRunTime (
    VOID
    );

VOID
KiUpdateSystemTime (
    VOID
    );

// begin_nthal

VOID
KeProfileInterrupt (
    IN KIRQL OldIrql,
    IN KTRAP_FRAME TrapFrame
    );

VOID
KeUpdateRuntime (
    IN KIRQL OldIrql,
    IN KTRAP_FRAME TrapFrame
    );

VOID
KeUpdateSystemTime (
    IN KIRQL OldIrql,
    IN KTRAP_FRAME TrapFrame
    );

// end_nthal (This is so the string "updriver" doesn't appear in nthal/ntddk/ntifs.)
// begin_nthal begin_ntddk begin_ntndis begin_updriver

#endif // defined(_X86_)

// end_nthal end_ntddk end_ntndis end_updriver

//
// i386 arch. specific kernel functions.
//

VOID
Ke386SetLdtProcess (
    struct _KPROCESS  *Process,
    PLDT_ENTRY  Ldt,
    ULONG       Limit
    );

VOID
Ke386SetDescriptorProcess (
    struct _KPROCESS  *Process,
    ULONG       Offset,
    LDT_ENTRY   LdtEntry
    );

VOID
Ke386GetGdtEntryThread (
    struct _KTHREAD *Thread,
    ULONG Offset,
    PKGDTENTRY Descriptor
    );

BOOLEAN
Ke386SetIoAccessMap (
    ULONG               MapNumber,
    PKIO_ACCESS_MAP     IoAccessMap
    );

BOOLEAN
Ke386QueryIoAccessMap (
    ULONG              MapNumber,
    PKIO_ACCESS_MAP    IoAccessMap
    );

BOOLEAN
Ke386IoSetAccessProcess (
    struct _KPROCESS    *Process,
    ULONG       MapNumber
    );

VOID
Ke386SetIOPL(
    struct _KPROCESS    *Process
    );

NTSTATUS
Ke386CallBios (
    IN ULONG BiosCommand,
    IN OUT PCONTEXT BiosArguments
    );

VOID
KiEditIopmDpc (
    IN struct _KDPC *Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );

BOOLEAN
Ki386GetSelectorParameters(
    IN USHORT Selector,
    OUT PULONG Flags,
    OUT PULONG Base,
    OUT PULONG Limit
    );

NTSTATUS
Ke386SetVdmInterruptHandler (
    IN struct _KPROCESS *Process,
    IN ULONG Interrupt,
    IN USHORT Selector,
    IN ULONG  Offset,
    IN BOOLEAN Gate32
    );

//
// i386 ABIOS specific routines.
//

NTSTATUS
KeI386GetLid(
    IN USHORT DeviceId,
    IN USHORT RelativeLid,
    IN BOOLEAN SharedLid,
    IN struct _DRIVER_OBJECT *DeviceObject,
    OUT PUSHORT LogicalId
    );

NTSTATUS
KeI386ReleaseLid(
    IN USHORT LogicalId,
    IN struct _DRIVER_OBJECT *DeviceObject
    );

NTSTATUS
KeI386AbiosCall(
    IN USHORT LogicalId,
    IN struct _DRIVER_OBJECT *DriverObject,
    IN PUCHAR RequestBlock,
    IN USHORT EntryPoint
    );

NTSTATUS
KeI386AllocateGdtSelectors(
    OUT PUSHORT SelectorArray,
    IN USHORT NumberOfSelectors
    );

NTSTATUS
KeI386ReleaseGdtSelectors(
    OUT PUSHORT SelectorArray,
    IN USHORT NumberOfSelectors
    );

NTSTATUS
KeI386FlatToGdtSelector(
    IN ULONG SelectorBase,
    IN USHORT Length,
    IN USHORT Selector
    );



//
// i386 Vdm specific functions
//
BOOLEAN
Ke386VdmInsertQueueApc (
    IN PKAPC             Apc,
    IN struct _KTHREAD  *Thread,
    IN KPROCESSOR_MODE   ApcMode,
    IN PKKERNEL_ROUTINE  KernelRoutine,
    IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,
    IN PKNORMAL_ROUTINE  NormalRoutine  OPTIONAL,
    IN PVOID             NormalContext   OPTIONAL,
    IN PVOID             SystemArgument1 OPTIONAL,
    IN PVOID             SystemArgument2 OPTIONAL,
    IN KPRIORITY         Increment
    );


VOID
KeI386VdmInitialize (
    VOID
    );


//
// i386 Vdm specific data
//
extern ULONG KeI386EFlagsAndMaskV86;
extern ULONG KeI386EFlagsOrMaskV86;
extern BOOLEAN KeI386VdmIoplAllowed;
extern ULONG KeI386VirtualIntExtensions;


extern ULONG KeI386CpuType;
extern ULONG KeI386CpuStep;
extern BOOLEAN KeI386NpxPresent;

//
// i386 Feature bit definitions
//

#define KF_V86_VIS          0x00000001
#define KF_RDTSC            0x00000002
#define KF_MACHINE_CHECK    0x00000004


#endif // _i386_
