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

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    ntosdef.h

Abstract:

    Common type definitions for the NTOS component that are private to
    NTOS, but shared between NTOS sub-components.

--*/

#ifndef _NTOSDEF_
#define _NTOSDEF_

//
// On UP systems high frequency spin locks are naturally aligned whereas on
// MP systems they cache aligned.
//

#if defined(NT_UP)

#define ALIGNED_SPINLOCK KSPIN_LOCK

#else

#define ALIGNED_SPINLOCK DECLSPEC_CACHEALIGN KSPIN_LOCK

#endif

//
// disable these for compiling w4
//
#pragma warning(disable:4214)   // bit field types other than int
#pragma warning(disable:4201)   // nameless struct/union
#pragma warning(disable:4127)   // condition expression is constant
#pragma warning(disable:4115)   // named type definition in parentheses

// begin_ntosp

//
// Define per processor nonpaged lookaside list descriptor structure.
//

struct _NPAGED_LOOKASIDE_LIST;

typedef struct _PP_LOOKASIDE_LIST {
    struct _GENERAL_LOOKASIDE *P;
    struct _GENERAL_LOOKASIDE *L;
} PP_LOOKASIDE_LIST, *PPP_LOOKASIDE_LIST;

//
// Define the number of small pool lists.
//
// N.B. This value is used in pool.h and is used to allocate single entry
//      lookaside lists in the processor block of each processor.

#define POOL_SMALL_LISTS 32

// begin_ntddk begin_wdm begin_nthal begin_ntifs

//
// Define alignment macros to align structure sizes and pointers up and down.
//

#define ALIGN_DOWN(length, type) \
    ((ULONG)(length) & ~(sizeof(type) - 1))

#define ALIGN_UP(length, type) \
    (ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))

#define ALIGN_DOWN_POINTER(address, type) \
    ((PVOID)((ULONG_PTR)(address) & ~((ULONG_PTR)sizeof(type) - 1)))

#define ALIGN_UP_POINTER(address, type) \
    (ALIGN_DOWN_POINTER(((ULONG_PTR)(address) + sizeof(type) - 1), type))

#define POOL_TAGGING 1

#ifndef DBG
#define DBG 0
#endif

#if DBG
#define IF_DEBUG if (TRUE)
#else
#define IF_DEBUG if (FALSE)
#endif

#if DEVL

// end_ntddk end_wdm end_nthal end_ntifs end_ntosp
//
// Global flag set by NtPartyByNumber(6) controls behavior of
// NT.  See \nt\sdk\inc\ntexapi.h for flag definitions
//
// begin_ntddk begin_wdm begin_nthal begin_ntifs begin_ntosp

extern ULONG NtGlobalFlag;

#define IF_NTOS_DEBUG( FlagName ) \
    if (NtGlobalFlag & (FLG_ ## FlagName))

#else
#define IF_NTOS_DEBUG( FlagName ) if (FALSE)
#endif

//
// Kernel definitions that need to be here for forward reference purposes
//

// begin_ntndis
//
// Processor modes.
//

typedef CCHAR KPROCESSOR_MODE;

typedef enum _MODE {
    KernelMode,
    UserMode,
    MaximumMode
} MODE;

// end_ntndis
//
// APC function types
//

//
// Put in an empty definition for the KAPC so that the
// routines can reference it before it is declared.
//

struct _KAPC;

typedef
VOID
(*PKNORMAL_ROUTINE) (
    IN PVOID NormalContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );

typedef
VOID
(*PKKERNEL_ROUTINE) (
    IN struct _KAPC *Apc,
    IN OUT PKNORMAL_ROUTINE *NormalRoutine,
    IN OUT PVOID *NormalContext,
    IN OUT PVOID *SystemArgument1,
    IN OUT PVOID *SystemArgument2
    );

typedef
VOID
(*PKRUNDOWN_ROUTINE) (
    IN struct _KAPC *Apc
    );

typedef
BOOLEAN
(*PKSYNCHRONIZE_ROUTINE) (
    IN PVOID SynchronizeContext
    );

typedef
BOOLEAN
(*PKTRANSFER_ROUTINE) (
    VOID
    );

//
//
// Asynchronous Procedure Call (APC) object
//
// N.B. The size of this structure cannot change since it has been exported.
//

typedef struct _KAPC {
    UCHAR Type;
    UCHAR SpareByte0;
    UCHAR Size;
    UCHAR SpareByte1;
    ULONG SpareLong0;
    struct _KTHREAD *Thread;
    LIST_ENTRY ApcListEntry;
    PKKERNEL_ROUTINE KernelRoutine;
    PKRUNDOWN_ROUTINE RundownRoutine;
    PKNORMAL_ROUTINE NormalRoutine;
    PVOID NormalContext;

    //
    // N.B. The following two members MUST be together.
    //

    PVOID SystemArgument1;
    PVOID SystemArgument2;
    CCHAR ApcStateIndex;
    KPROCESSOR_MODE ApcMode;
    BOOLEAN Inserted;
} KAPC, *PKAPC, *PRKAPC;

#define KAPC_OFFSET_TO_SPARE_BYTE0 FIELD_OFFSET(KAPC, SpareByte0)
#define KAPC_OFFSET_TO_SPARE_BYTE1 FIELD_OFFSET(KAPC, SpareByte1)
#define KAPC_OFFSET_TO_SPARE_LONG FIELD_OFFSET(KAPC, SpareLong0)
#define KAPC_OFFSET_TO_SYSTEMARGUMENT1 FIELD_OFFSET(KAPC, SystemArgument1)
#define KAPC_OFFSET_TO_SYSTEMARGUMENT2 FIELD_OFFSET(KAPC, SystemArgument2)
#define KAPC_OFFSET_TO_APCSTATEINDEX FIELD_OFFSET(KAPC, ApcStateIndex)
#define KAPC_ACTUAL_LENGTH (FIELD_OFFSET(KAPC, Inserted) + sizeof(BOOLEAN))

// begin_ntndis
//
// DPC routine
//

struct _KDPC;

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

//
// Define DPC importance.
//
// LowImportance - Queue DPC at end of target DPC queue.
// MediumImportance - Queue DPC at end of target DPC queue.
// HighImportance - Queue DPC at front of target DPC DPC queue.
//
// If there is currently a DPC active on the target processor, or a DPC
// interrupt has already been requested on the target processor when a
// DPC is queued, then no further action is necessary. The DPC will be
// executed on the target processor when its queue entry is processed.
//
// If there is not a DPC active on the target processor and a DPC interrupt
// has not been requested on the target processor, then the exact treatment
// of the DPC is dependent on whether the host system is a UP system or an
// MP system.
//
// UP system.
//
// If the DPC is of medium or high importance, the current DPC queue depth
// is greater than the maximum target depth, or current DPC request rate is
// less the minimum target rate, then a DPC interrupt is requested on the
// host processor and the DPC will be processed when the interrupt occurs.
// Otherwise, no DPC interupt is requested and the DPC execution will be
// delayed until the DPC queue depth is greater that the target depth or the
// minimum DPC rate is less than the target rate.
//
// MP system.
//
// If the DPC is being queued to another processor and the depth of the DPC
// queue on the target processor is greater than the maximum target depth or
// the DPC is of high importance, then a DPC interrupt is requested on the
// target processor and the DPC will be processed when the interrupt occurs.
// Otherwise, the DPC execution will be delayed on the target processor until
// the DPC queue depth on the target processor is greater that the maximum
// target depth or the minimum DPC rate on the target processor is less than
// the target minimum rate.
//
// If the DPC is being queued to the current processor and the DPC is not of
// low importance, the current DPC queue depth is greater than the maximum
// target depth, or the minimum DPC rate is less than the minimum target rate,
// then a DPC interrupt is request on the current processor and the DPV will
// be processed whne the interrupt occurs. Otherwise, no DPC interupt is
// requested and the DPC execution will be delayed until the DPC queue depth
// is greater that the target depth or the minimum DPC rate is less than the
// target rate.
//

typedef enum _KDPC_IMPORTANCE {
    LowImportance,
    MediumImportance,
    HighImportance
} KDPC_IMPORTANCE;

//
// Define DPC type indicies.
//

#define DPC_NORMAL 0
#define DPC_THREADED 1

//
// Deferred Procedure Call (DPC) object
//

#define ASSERT_DPC(Object)                                                   \
    ASSERT(((Object)->Type == DpcObject) ||                                  \
           ((Object)->Type == ThreadedDpcObject))

typedef struct _KDPC {
    UCHAR Type;
    UCHAR Importance;
    UCHAR Number;
    UCHAR Expedite;
    LIST_ENTRY DpcListEntry;
    PKDEFERRED_ROUTINE DeferredRoutine;
    PVOID DeferredContext;
    PVOID SystemArgument1;
    PVOID SystemArgument2;
    PVOID DpcData;
} KDPC, *PKDPC, *PRKDPC;

//
// Interprocessor interrupt worker routine function prototype.
//

typedef PVOID PKIPI_CONTEXT;

typedef
VOID
(*PKIPI_WORKER)(
    IN PKIPI_CONTEXT PacketContext,
    IN PVOID Parameter1,
    IN PVOID Parameter2,
    IN PVOID Parameter3
    );

//
// Define interprocessor interrupt performance counters.
//

typedef struct _KIPI_COUNTS {
    ULONG Freeze;
    ULONG Packet;
    ULONG DPC;
    ULONG APC;
    ULONG FlushSingleTb;
    ULONG FlushMultipleTb;
    ULONG FlushEntireTb;
    ULONG GenericCall;
    ULONG ChangeColor;
    ULONG SweepDcache;
    ULONG SweepIcache;
    ULONG SweepIcacheRange;
    ULONG FlushIoBuffers;
    ULONG GratuitousDPC;
} KIPI_COUNTS, *PKIPI_COUNTS;

// end_ntddk end_wdm end_ntifs end_ntosp end_ntndis

#if defined(NT_UP)

#define HOT_STATISTIC(a) a

#else

#define HOT_STATISTIC(a) (KeGetCurrentPrcb()->a)

#endif

// begin_ntddk begin_wdm begin_ntifs begin_ntosp begin_ntndis

//
// I/O system definitions.
//
// Define a Memory Descriptor List (MDL)
//
// An MDL describes pages in a virtual buffer in terms of physical pages.  The
// pages associated with the buffer are described in an array that is allocated
// just after the MDL header structure itself.
//
// One simply calculates the base of the array by adding one to the base
// MDL pointer:
//
//      Pages = (PPFN_NUMBER) (Mdl + 1);
//
// Notice that while in the context of the subject thread, the base virtual
// address of a buffer mapped by an MDL may be referenced using the following:
//
//      Mdl->StartVa | Mdl->ByteOffset
//


typedef struct _MDL {
    struct _MDL *Next;
    CSHORT Size;
    CSHORT MdlFlags;
    struct _EPROCESS *Process;
    PVOID MappedSystemVa;
    PVOID StartVa;
    ULONG ByteCount;
    ULONG ByteOffset;
} MDL, *PMDL;

#define MDL_MAPPED_TO_SYSTEM_VA     0x0001
#define MDL_PAGES_LOCKED            0x0002
#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004
#define MDL_ALLOCATED_FIXED_SIZE    0x0008
#define MDL_PARTIAL                 0x0010
#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020
#define MDL_IO_PAGE_READ            0x0040
#define MDL_WRITE_OPERATION         0x0080
#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100
#define MDL_FREE_EXTRA_PTES         0x0200
#define MDL_DESCRIBES_AWE           0x0400
#define MDL_IO_SPACE                0x0800
#define MDL_NETWORK_HEADER          0x1000
#define MDL_MAPPING_CAN_FAIL        0x2000
#define MDL_ALLOCATED_MUST_SUCCEED  0x4000


#define MDL_MAPPING_FLAGS (MDL_MAPPED_TO_SYSTEM_VA     | \
                           MDL_PAGES_LOCKED            | \
                           MDL_SOURCE_IS_NONPAGED_POOL | \
                           MDL_PARTIAL_HAS_BEEN_MAPPED | \
                           MDL_PARENT_MAPPED_SYSTEM_VA | \
                           MDL_SYSTEM_VA               | \
                           MDL_IO_SPACE )

// end_ntndis
//
// switch to DBG when appropriate
//

#if DBG
#define PAGED_CODE() \
    { if (KeGetCurrentIrql() > APC_LEVEL) { \
          KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
          ASSERT(FALSE); \
       } \
    }
#else
#define PAGED_CODE() NOP_FUNCTION;
#endif

// end_ntddk end_wdm end_nthal end_ntifs end_ntosp


// begin_ntifs begin_ntosp
//
// Data structure used to represent client security context for a thread.
// This data structure is used to support impersonation.
//
//  THE FIELDS OF THIS DATA STRUCTURE SHOULD BE CONSIDERED OPAQUE
//  BY ALL EXCEPT THE SECURITY ROUTINES.
//

typedef struct _SECURITY_CLIENT_CONTEXT {
    SECURITY_QUALITY_OF_SERVICE SecurityQos;
    PACCESS_TOKEN ClientToken;
    BOOLEAN DirectlyAccessClientToken;
    BOOLEAN DirectAccessEffectiveOnly;
    BOOLEAN ServerIsRemote;
    TOKEN_CONTROL ClientTokenControl;
    } SECURITY_CLIENT_CONTEXT, *PSECURITY_CLIENT_CONTEXT;

//
// where
//
//    SecurityQos - is the security quality of service information in effect
//        for this client.  This information is used when directly accessing
//        the client's token.  In this case, the information here over-rides
//        the information in the client's token.  If a copy of the client's
//        token is requested, it must be generated using this information,
//        not the information in the client's token.  In all cases, this
//        information may not provide greater access than the information
//        in the client's token.  In particular, if the client's token is
//        an impersonation token with an impersonation level of
//        "SecurityDelegation", but the information in this field indicates
//        an impersonation level of "SecurityIdentification", then
//        the server may only get a copy of the token with an Identification
//        level of impersonation.
//
//    ClientToken - If the DirectlyAccessClientToken field is FALSE,
//        then this field contains a pointer to a duplicate of the
//        client's token.  Otherwise, this field points directly to
//        the client's token.
//
//    DirectlyAccessClientToken - This boolean flag indicates whether the
//        token pointed to by ClientToken is a copy of the client's token
//        or is a direct reference to the client's token.  A value of TRUE
//        indicates the client's token is directly accessed, FALSE indicates
//        a copy has been made.
//
//    DirectAccessEffectiveOnly - This boolean flag indicates whether the
//        the disabled portions of the token that is currently directly
//        referenced may be enabled.  This field is only valid if the
//        DirectlyAccessClientToken field is TRUE.  In that case, this
//        value supersedes the EffectiveOnly value in the SecurityQos
//        FOR THE CURRENT TOKEN ONLY!  If the client changes to impersonate
//        another client, this value may change.  This value is always
//        minimized by the EffectiveOnly flag in the SecurityQos field.
//
//    ServerIsRemote - If TRUE indicates that the server of the client's
//        request is remote.  This is used for determining the legitimacy
//        of certain levels of impersonation and to determine how to
//        track context.
//
//    ClientTokenControl - If the ServerIsRemote flag is TRUE, and the
//        tracking mode is DYNAMIC, then this field contains a copy of
//        the TOKEN_SOURCE from the client's token to assist in deciding
//        whether the information at the remote server needs to be
//        updated to match the current state of the client's security
//        context.
//
//
//    NOTE: At some point, we may find it worthwhile to keep an array of
//          elements in this data structure, where each element of the
//          array contains {ClientToken, ClientTokenControl} fields.
//          This would allow efficient handling of the case where a client
//          thread was constantly switching between a couple different
//          contexts - presumably impersonating client's of its own.
//
// end_ntifs end_ntosp

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

#if (defined(_NTDRIVER_) || defined(_NTDDK_) || defined(_NTIFS_) || defined(_NTHAL_) || defined(_NTOSP_)) && !defined(_BLDR_)
// begin_ntosp
#if defined(_NTSYSTEM_)

#define NTKERNELAPI

#else

#define NTKERNELAPI DECLSPEC_IMPORT     // wdm ntddk nthal ntndis ntifs

#endif
// end_ntosp
#else

#define NTKERNELAPI

#endif

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

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

#define NTHALAPI DECLSPEC_IMPORT            // wdm ntndis ntifs ntosp

#else

#define NTHALAPI                            // nthal

#endif
// end_ntddk

// begin_ntddk begin_wdm begin_nthal begin_ntifs begin_ntndis begin_ntosp
//
// Common dispatcher object header
//
// N.B. The size field contains the number of dwords in the structure.
//

typedef struct _DISPATCHER_HEADER {
    union {
        struct {
            UCHAR Type;
            union {
                UCHAR Absolute;
                UCHAR NpxIrql;
            };

            union {
                UCHAR Size;
                UCHAR Hand;
            };

            union {
                UCHAR Inserted;
                BOOLEAN DebugActive;
            };
        };

        volatile LONG Lock;
    };

    LONG SignalState;
    LIST_ENTRY WaitListHead;
} DISPATCHER_HEADER;

//
// Event object
//

typedef struct _KEVENT {
    DISPATCHER_HEADER Header;
} KEVENT, *PKEVENT, *PRKEVENT;

//
// Gate object
//
// N.B. Gate object services allow the specification of synchronization
//      events. This allows fast mutex to be transparently replaced with
//      gates.
//

#define ASSERT_GATE(object)                                                  \
    ASSERT((((object)->Header.Type & KOBJECT_TYPE_MASK) == GateObject) ||    \
          (((object)->Header.Type & KOBJECT_TYPE_MASK) == EventSynchronizationObject))

typedef struct _KGATE {
    DISPATCHER_HEADER Header;
} KGATE, *PKGATE;

//
// Define timer table size.
//
// N.B. The size of the timer table must be less than or equal to 256 and a
//      power of 2 in size.

#define TIMER_TABLE_SIZE 512
#define TIMER_TABLE_SHIFT 9

C_ASSERT((1 << TIMER_TABLE_SHIFT) == TIMER_TABLE_SIZE);
C_ASSERT((TIMER_TABLE_SIZE & (TIMER_TABLE_SIZE - 1)) == 0);

//
// Timer object
//
// N.B. The period field must be the last member of this structure.
//

typedef struct _KTIMER {
    DISPATCHER_HEADER Header;
    ULARGE_INTEGER DueTime;
    LIST_ENTRY TimerListEntry;
    struct _KDPC *Dpc;
    LONG Period;
} KTIMER, *PKTIMER, *PRKTIMER;

#define KTIMER_ACTUAL_LENGTH                                                \
    (FIELD_OFFSET(KTIMER, Period) + sizeof(LONG))

typedef enum _LOCK_OPERATION {
    IoReadAccess,
    IoWriteAccess,
    IoModifyAccess
} LOCK_OPERATION;

// end_ntddk end_wdm end_nthal end_ntifs end_ntndis end_ntosp

//
// Define kernel stack segment.
//

typedef struct _KERNEL_STACK_SEGMENT {
    ULONG_PTR StackBase;
    ULONG_PTR StackLimit;
    ULONG_PTR KernelStack;
    ULONG_PTR InitialStack;
    ULONG_PTR ActualLimit;
} KERNEL_STACK_SEGMENT, *PKERNEL_STACK_SEGMENT;

#endif // _NTOSDEF_
