freebsd-dev/sys/compat/ndis/ntoskrnl_var.h
Bill Paul d02239a3af Create new i386 windows/bsd thunking layer, similar to the amd64 thunking
layer, but with a twist.

The twist has to do with the fact that Microsoft supports structured
exception handling in kernel mode. On the i386 arch, exception handling
is implemented by hanging an exception registration list off the
Thread Environment Block (TEB), and the TEB is accessed via the %fs
register. The problem is, we use %fs as a pointer to the pcpu stucture,
which means any driver that tries to write through %fs:0 will overwrite
the curthread pointer and make a serious mess of things.

To get around this, Project Evil now creates a special entry in
the GDT on each processor. When we call into Windows code, a context
switch routine will fix up %fs so it points to our new descriptor,
which in turn points to a fake TEB. When the Windows code returns,
or calls out to an external routine, we swap %fs back again. Currently,
Project Evil makes use of GDT slot 7, which is all 0s by default.
I fully expect someone to jump up and say I can't do that, but I
couldn't find any code that makes use of this entry anywhere. Sadly,
this was the only method I could come up with that worked on both
UP and SMP. (Modifying the LDT works on UP, but becomes incredibly
complicated on SMP.) If necessary, the context switching stuff can
be yanked out while preserving the convention calling wrappers.

(Fortunately, it looks like Microsoft uses some special epilog/prolog
code on amd64 to implement exception handling, so the same nastiness
won't be necessary on that arch.)

The advantages are:

- Any driver that uses %fs as though it were a TEB pointer won't
  clobber pcpu.
- All the __stdcall/__fastcall/__regparm stuff that's specific to
  gcc goes away.

Also, while I'm here, switch NdisGetSystemUpTime() back to using
nanouptime() again. It turns out nanouptime() is way more accurate
than just using ticks(). On slower machines, the Atheros drivers
I tested seem to take a long time to associate due to the loss
in accuracy.
2005-04-11 02:02:35 +00:00

1263 lines
37 KiB
C

/*-
* Copyright (c) 2003
* Bill Paul <wpaul@windriver.com>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _NTOSKRNL_VAR_H_
#define _NTOSKRNL_VAR_H_
/*
* us_buf is really a wchar_t *, but it's inconvenient to include
* all the necessary header goop needed to define it, and it's a
* pointer anyway, so for now, just make it a uint16_t *.
*/
struct unicode_string {
uint16_t us_len;
uint16_t us_maxlen;
uint16_t *us_buf;
};
typedef struct unicode_string unicode_string;
/*
* Windows memory descriptor list. In Windows, it's possible for
* buffers to be passed between user and kernel contexts without
* copying. Buffers may also be allocated in either paged or
* non-paged memory regions. An MDL describes the pages of memory
* used to contain a particular buffer. Note that a single MDL
* may describe a buffer that spans multiple pages. An array of
* page addresses appears immediately after the MDL structure itself.
* MDLs are therefore implicitly variably sized, even though they
* don't look it.
*
* Note that in FreeBSD, we can take many shortcuts in the way
* we handle MDLs because:
*
* - We are only concerned with pages in kernel context. This means
* we will only ever use the kernel's memory map, and remapping
* of buffers is never needed.
*
* - Kernel pages can never be paged out, so we don't have to worry
* about whether or not a page is actually mapped before going to
* touch it.
*/
struct mdl {
struct mdl *mdl_next;
uint16_t mdl_size;
uint16_t mdl_flags;
void *mdl_process;
void *mdl_mappedsystemva;
void *mdl_startva;
uint32_t mdl_bytecount;
uint32_t mdl_byteoffset;
};
typedef struct mdl mdl, ndis_buffer;
/* MDL flags */
#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_IO_SPACE 0x0800
#define MDL_NETWORK_HEADER 0x1000
#define MDL_MAPPING_CAN_FAIL 0x2000
#define MDL_ALLOCATED_MUST_SUCCEED 0x4000
#define MDL_ZONE_ALLOCED 0x8000 /* BSD private */
#define MDL_ZONE_PAGES 16
#define MDL_ZONE_SIZE (sizeof(mdl) + (sizeof(vm_offset_t) * MDL_ZONE_PAGES))
/* Note: assumes x86 page size of 4K. */
#if PAGE_SIZE == 4096
#define PAGE_SHIFT 12
#elif PAGE_SIZE == 8192
#define PAGE_SHIFT 13
#else
#error PAGE_SHIFT undefined!
#endif
#define SPAN_PAGES(ptr, len) \
((uint32_t)((((uintptr_t)(ptr) & (PAGE_SIZE - 1)) + \
(len) + (PAGE_SIZE - 1)) >> PAGE_SHIFT))
#define PAGE_ALIGN(ptr) \
((void *)((uintptr_t)(ptr) & ~(PAGE_SIZE - 1)))
#define BYTE_OFFSET(ptr) \
((uint32_t)((uintptr_t)(ptr) & (PAGE_SIZE - 1)))
#define MDL_PAGES(m) (vm_offset_t *)(m + 1)
#define MmInitializeMdl(b, baseva, len) \
(b)->mdl_next = NULL; \
(b)->mdl_size = (uint16_t)(sizeof(mdl) + \
(sizeof(vm_offset_t) * SPAN_PAGES((baseva), (len)))); \
(b)->mdl_flags = 0; \
(b)->mdl_startva = (void *)PAGE_ALIGN((baseva)); \
(b)->mdl_byteoffset = BYTE_OFFSET((baseva)); \
(b)->mdl_bytecount = (uint32_t)(len);
#define MmGetMdlByteOffset(mdl) ((mdl)->mdl_byteoffset)
#define MmGetMdlByteCount(mdl) ((mdl)->mdl_bytecount)
#define MmGetMdlVirtualAddress(mdl) \
((void *)((char *)((mdl)->mdl_startva) + (mdl)->mdl_byteoffset))
#define MmGetMdlStartVa(mdl) ((mdl)->mdl_startva)
#define MmGetMdlPfnArray(mdl) MDL_PAGES(mdl)
#define WDM_MAJOR 1
#define WDM_MINOR_WIN98 0x00
#define WDM_MINOR_WINME 0x05
#define WDM_MINOR_WIN2000 0x10
#define WDM_MINOR_WINXP 0x20
#define WDM_MINOR_WIN2003 0x30
/*-
* The ndis_kspin_lock type is called KSPIN_LOCK in MS-Windows.
* According to the Windows DDK header files, KSPIN_LOCK is defined like this:
* typedef ULONG_PTR KSPIN_LOCK;
*
* From basetsd.h (SDK, Feb. 2003):
* typedef [public] unsigned __int3264 ULONG_PTR, *PULONG_PTR;
* typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
* typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
*
* The keyword __int3264 specifies an integral type that has the following
* properties:
* + It is 32-bit on 32-bit platforms
* + It is 64-bit on 64-bit platforms
* + It is 32-bit on the wire for backward compatibility.
* It gets truncated on the sending side and extended appropriately
* (signed or unsigned) on the receiving side.
*
* Thus register_t seems the proper mapping onto FreeBSD for spin locks.
*/
typedef register_t kspin_lock;
struct slist_entry {
struct slist_entry *sl_next;
};
typedef struct slist_entry slist_entry;
union slist_header {
uint64_t slh_align;
struct {
struct slist_entry *slh_next;
uint16_t slh_depth;
uint16_t slh_seq;
} slh_list;
};
typedef union slist_header slist_header;
struct list_entry {
struct list_entry *nle_flink;
struct list_entry *nle_blink;
};
typedef struct list_entry list_entry;
#define INIT_LIST_HEAD(l) \
(l)->nle_flink = (l)->nle_blink = (l)
#define REMOVE_LIST_ENTRY(e) \
do { \
list_entry *b; \
list_entry *f; \
\
f = e->nle_flink; \
b = e->nle_blink; \
b->nle_flink = f; \
f->nle_blink = b; \
} while (0)
#define REMOVE_LIST_HEAD(l) \
do { \
list_entry *f; \
list_entry *e; \
\
e = l->nle_flink; \
f = e->nle_flink; \
l->nle_flink = f; \
f->nle_blink = l; \
} while (0)
#define REMOVE_LIST_TAIL(l) \
do { \
list_entry *b; \
list_entry *e; \
\
e = l->nle_blink; \
b = e->nle_blink; \
l->nle_blink = b; \
b->nle_flink = l; \
} while (0)
#define INSERT_LIST_TAIL(l, e) \
do { \
list_entry *b; \
\
b = l->nle_blink; \
e->nle_flink = l; \
e->nle_blink = b; \
b->nle_flink = (e); \
l->nle_blink = (e); \
} while (0)
#define INSERT_LIST_HEAD(l, e) \
do { \
list_entry *f; \
\
f = l->nle_flink; \
e->nle_flink = f; \
e->nle_blink = l; \
f->nle_blink = e; \
l->nle_flink = e; \
} while (0)
struct nt_dispatch_header {
uint8_t dh_type;
uint8_t dh_abs;
uint8_t dh_size;
uint8_t dh_inserted;
uint32_t dh_sigstate;
list_entry dh_waitlisthead;
};
typedef struct nt_dispatch_header nt_dispatch_header;
#define OTYPE_EVENT 0
#define OTYPE_MUTEX 1
#define OTYPE_THREAD 2
#define OTYPE_TIMER 3
/* Windows dispatcher levels. */
#define PASSIVE_LEVEL 0
#define LOW_LEVEL 0
#define APC_LEVEL 1
#define DISPATCH_LEVEL 2
#define DEVICE_LEVEL (DISPATCH_LEVEL + 1)
#define PROFILE_LEVEL 27
#define CLOCK1_LEVEL 28
#define CLOCK2_LEVEL 28
#define IPI_LEVEL 29
#define POWER_LEVEL 30
#define HIGH_LEVEL 31
#define SYNC_LEVEL_UP DISPATCH_LEVEL
#define SYNC_LEVEL_MP (IPI_LEVEL - 1)
#define AT_PASSIVE_LEVEL(td) \
((td)->td_proc->p_flag & P_KTHREAD == FALSE)
#define AT_DISPATCH_LEVEL(td) \
((td)->td_base_pri == PI_REALTIME)
#define AT_DIRQL_LEVEL(td) \
((td)->td_priority <= PI_NET)
#define AT_HIGH_LEVEL(td) \
((td)->td_critnest != 0)
struct nt_objref {
nt_dispatch_header no_dh;
void *no_obj;
TAILQ_ENTRY(nt_objref) link;
};
TAILQ_HEAD(nt_objref_head, nt_objref);
typedef struct nt_objref nt_objref;
#define EVENT_TYPE_NOTIFY 0
#define EVENT_TYPE_SYNC 1
/*
* We need to use the timeout()/untimeout() API for ktimers
* since timers can be initialized, but not destroyed (so
* malloc()ing our own callout structures would mean a leak,
* since there'd be no way to free() them). This means we
* need to use struct callout_handle, which is really just a
* pointer. To make it easier to deal with, we use a union
* to overlay the callout_handle over the k_timerlistentry.
* The latter is a list_entry, which is two pointers, so
* there's enough space available to hide a callout_handle
* there.
*/
struct ktimer {
nt_dispatch_header k_header;
uint64_t k_duetime;
union {
list_entry k_timerlistentry;
struct callout_handle k_handle;
} u;
void *k_dpc;
uint32_t k_period;
};
#define k_timerlistentry u.k_timerlistentry
#define k_handle u.k_handle
typedef struct ktimer ktimer;
struct nt_kevent {
nt_dispatch_header k_header;
};
typedef struct nt_kevent nt_kevent;
/* Kernel defered procedure call (i.e. timer callback) */
struct kdpc;
typedef void (*kdpc_func)(struct kdpc *, void *, void *, void *);
struct kdpc {
uint16_t k_type;
uint8_t k_num;
uint8_t k_importance;
list_entry k_dpclistentry;
void *k_deferedfunc;
void *k_deferredctx;
void *k_sysarg1;
void *k_sysarg2;
register_t k_lock;
};
typedef struct kdpc kdpc;
/*
* Note: the acquisition count is BSD-specific. The Microsoft
* documentation says that mutexes can be acquired recursively
* by a given thread, but that you must release the mutex as
* many times as you acquired it before it will be set to the
* signalled state (i.e. before any other threads waiting on
* the object will be woken up). However the Windows KMUTANT
* structure has no field for keeping track of the number of
* acquisitions, so we need to add one ourselves. As long as
* driver code treats the mutex as opaque, we should be ok.
*/
struct kmutant {
nt_dispatch_header km_header;
union {
list_entry km_listentry;
uint32_t km_acquirecnt;
} u;
void *km_ownerthread;
uint8_t km_abandoned;
uint8_t km_apcdisable;
};
#define km_listentry u.km_listentry
#define km_acquirecnt u.km_acquirecnt
typedef struct kmutant kmutant;
#define LOOKASIDE_DEPTH 256
struct general_lookaside {
slist_header gl_listhead;
uint16_t gl_depth;
uint16_t gl_maxdepth;
uint32_t gl_totallocs;
union {
uint32_t gl_allocmisses;
uint32_t gl_allochits;
} u_a;
uint32_t gl_totalfrees;
union {
uint32_t gl_freemisses;
uint32_t gl_freehits;
} u_m;
uint32_t gl_type;
uint32_t gl_tag;
uint32_t gl_size;
void *gl_allocfunc;
void *gl_freefunc;
list_entry gl_listent;
uint32_t gl_lasttotallocs;
union {
uint32_t gl_lastallocmisses;
uint32_t gl_lastallochits;
} u_l;
uint32_t gl_rsvd[2];
};
typedef struct general_lookaside general_lookaside;
struct npaged_lookaside_list {
general_lookaside nll_l;
#ifdef __i386__
kspin_lock nll_obsoletelock;
#endif
};
typedef struct npaged_lookaside_list npaged_lookaside_list;
typedef struct npaged_lookaside_list paged_lookaside_list;
typedef void * (*lookaside_alloc_func)(uint32_t, size_t, uint32_t);
typedef void (*lookaside_free_func)(void *);
struct irp;
struct kdevice_qentry {
list_entry kqe_devlistent;
uint32_t kqe_sortkey;
uint8_t kqe_inserted;
};
typedef struct kdevice_qentry kdevice_qentry;
struct kdevice_queue {
uint16_t kq_type;
uint16_t kq_size;
list_entry kq_devlisthead;
kspin_lock kq_lock;
uint8_t kq_busy;
};
typedef struct kdevice_queue kdevice_queue;
struct wait_ctx_block {
kdevice_qentry wcb_waitqueue;
void *wcb_devfunc;
void *wcb_devctx;
uint32_t wcb_mapregcnt;
void *wcb_devobj;
void *wcb_curirp;
void *wcb_bufchaindpc;
};
typedef struct wait_ctx_block wait_ctx_block;
struct wait_block {
list_entry wb_waitlist;
void *wb_kthread;
nt_dispatch_header *wb_object;
struct wait_block *wb_next;
uint16_t wb_waitkey;
uint16_t wb_waittype;
};
typedef struct wait_block wait_block;
#define THREAD_WAIT_OBJECTS 3
#define MAX_WAIT_OBJECTS 64
#define WAITTYPE_ALL 0
#define WAITTYPE_ANY 1
struct thread_context {
void *tc_thrctx;
void *tc_thrfunc;
};
typedef struct thread_context thread_context;
/* Forward declaration */
struct driver_object;
struct devobj_extension;
struct driver_extension {
struct driver_object *dre_driverobj;
void *dre_adddevicefunc;
uint32_t dre_reinitcnt;
unicode_string dre_srvname;
/*
* Drivers are allowed to add one or more custom extensions
* to the driver object, but there's no special pointer
* for them. Hang them off here for now.
*/
list_entry dre_usrext;
};
typedef struct driver_extension driver_extension;
struct custom_extension {
list_entry ce_list;
void *ce_clid;
};
typedef struct custom_extension custom_extension;
/*
* In Windows, there are Physical Device Objects (PDOs) and
* Functional Device Objects (FDOs). Physical Device Objects are
* created and maintained by bus drivers. For example, the PCI
* bus driver might detect two PCI ethernet cards on a given
* bus. The PCI bus driver will then allocate two device_objects
* for its own internal bookeeping purposes. This is analagous
* to the device_t that the FreeBSD PCI code allocates and passes
* into each PCI driver's probe and attach routines.
*
* When an ethernet driver claims one of the ethernet cards
* on the bus, it will create its own device_object. This is
* the Functional Device Object. This object is analagous to the
* device-specific softc structure.
*/
struct device_object {
uint16_t do_type;
uint16_t do_size;
uint32_t do_refcnt;
struct driver_object *do_drvobj;
struct device_object *do_nextdev;
struct device_object *do_attacheddev;
struct irp *do_currirp;
void *do_iotimer;
uint32_t do_flags;
uint32_t do_characteristics;
void *do_vpb;
void *do_devext;
uint32_t do_devtype;
uint8_t do_stacksize;
union {
list_entry do_listent;
wait_ctx_block do_wcb;
} queue;
uint32_t do_alignreq;
kdevice_queue do_devqueue;
struct kdpc do_dpc;
uint32_t do_activethreads;
void *do_securitydesc;
struct nt_kevent do_devlock;
uint16_t do_sectorsz;
uint16_t do_spare1;
struct devobj_extension *do_devobj_ext;
void *do_rsvd;
};
typedef struct device_object device_object;
struct devobj_extension {
uint16_t dve_type;
uint16_t dve_size;
device_object *dve_devobj;
};
typedef struct devobj_extension devobj_extension;
/* Device object flags */
#define DO_VERIFY_VOLUME 0x00000002
#define DO_BUFFERED_IO 0x00000004
#define DO_EXCLUSIVE 0x00000008
#define DO_DIRECT_IO 0x00000010
#define DO_MAP_IO_BUFFER 0x00000020
#define DO_DEVICE_HAS_NAME 0x00000040
#define DO_DEVICE_INITIALIZING 0x00000080
#define DO_SYSTEM_BOOT_PARTITION 0x00000100
#define DO_LONG_TERM_REQUESTS 0x00000200
#define DO_NEVER_LAST_DEVICE 0x00000400
#define DO_SHUTDOWN_REGISTERED 0x00000800
#define DO_BUS_ENUMERATED_DEVICE 0x00001000
#define DO_POWER_PAGABLE 0x00002000
#define DO_POWER_INRUSH 0x00004000
#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000
/* Priority boosts */
#define IO_NO_INCREMENT 0
#define IO_CD_ROM_INCREMENT 1
#define IO_DISK_INCREMENT 1
#define IO_KEYBOARD_INCREMENT 6
#define IO_MAILSLOT_INCREMENT 2
#define IO_MOUSE_INCREMENT 6
#define IO_NAMED_PIPE_INCREMENT 2
#define IO_NETWORK_INCREMENT 2
#define IO_PARALLEL_INCREMENT 1
#define IO_SERIAL_INCREMENT 2
#define IO_SOUND_INCREMENT 8
#define IO_VIDEO_INCREMENT 1
/* IRP major codes */
#define IRP_MJ_CREATE 0x00
#define IRP_MJ_CREATE_NAMED_PIPE 0x01
#define IRP_MJ_CLOSE 0x02
#define IRP_MJ_READ 0x03
#define IRP_MJ_WRITE 0x04
#define IRP_MJ_QUERY_INFORMATION 0x05
#define IRP_MJ_SET_INFORMATION 0x06
#define IRP_MJ_QUERY_EA 0x07
#define IRP_MJ_SET_EA 0x08
#define IRP_MJ_FLUSH_BUFFERS 0x09
#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
#define IRP_MJ_SET_VOLUME_INFORMATION 0x0b
#define IRP_MJ_DIRECTORY_CONTROL 0x0c
#define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d
#define IRP_MJ_DEVICE_CONTROL 0x0e
#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f
#define IRP_MJ_SHUTDOWN 0x10
#define IRP_MJ_LOCK_CONTROL 0x11
#define IRP_MJ_CLEANUP 0x12
#define IRP_MJ_CREATE_MAILSLOT 0x13
#define IRP_MJ_QUERY_SECURITY 0x14
#define IRP_MJ_SET_SECURITY 0x15
#define IRP_MJ_POWER 0x16
#define IRP_MJ_SYSTEM_CONTROL 0x17
#define IRP_MJ_DEVICE_CHANGE 0x18
#define IRP_MJ_QUERY_QUOTA 0x19
#define IRP_MJ_SET_QUOTA 0x1a
#define IRP_MJ_PNP 0x1b
#define IRP_MJ_PNP_POWER IRP_MJ_PNP // Obsolete....
#define IRP_MJ_MAXIMUM_FUNCTION 0x1b
#define IRP_MJ_SCSI IRP_MJ_INTERNAL_DEVICE_CONTROL
/* IRP minor codes */
#define IRP_MN_QUERY_DIRECTORY 0x01
#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02
#define IRP_MN_USER_FS_REQUEST 0x00
#define IRP_MN_MOUNT_VOLUME 0x01
#define IRP_MN_VERIFY_VOLUME 0x02
#define IRP_MN_LOAD_FILE_SYSTEM 0x03
#define IRP_MN_TRACK_LINK 0x04
#define IRP_MN_KERNEL_CALL 0x04
#define IRP_MN_LOCK 0x01
#define IRP_MN_UNLOCK_SINGLE 0x02
#define IRP_MN_UNLOCK_ALL 0x03
#define IRP_MN_UNLOCK_ALL_BY_KEY 0x04
#define IRP_MN_NORMAL 0x00
#define IRP_MN_DPC 0x01
#define IRP_MN_MDL 0x02
#define IRP_MN_COMPLETE 0x04
#define IRP_MN_COMPRESSED 0x08
#define IRP_MN_MDL_DPC (IRP_MN_MDL | IRP_MN_DPC)
#define IRP_MN_COMPLETE_MDL (IRP_MN_COMPLETE | IRP_MN_MDL)
#define IRP_MN_COMPLETE_MDL_DPC (IRP_MN_COMPLETE_MDL | IRP_MN_DPC)
#define IRP_MN_SCSI_CLASS 0x01
#define IRP_MN_START_DEVICE 0x00
#define IRP_MN_QUERY_REMOVE_DEVICE 0x01
#define IRP_MN_REMOVE_DEVICE 0x02
#define IRP_MN_CANCEL_REMOVE_DEVICE 0x03
#define IRP_MN_STOP_DEVICE 0x04
#define IRP_MN_QUERY_STOP_DEVICE 0x05
#define IRP_MN_CANCEL_STOP_DEVICE 0x06
#define IRP_MN_QUERY_DEVICE_RELATIONS 0x07
#define IRP_MN_QUERY_INTERFACE 0x08
#define IRP_MN_QUERY_CAPABILITIES 0x09
#define IRP_MN_QUERY_RESOURCES 0x0A
#define IRP_MN_QUERY_RESOURCE_REQUIREMENTS 0x0B
#define IRP_MN_QUERY_DEVICE_TEXT 0x0C
#define IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D
#define IRP_MN_READ_CONFIG 0x0F
#define IRP_MN_WRITE_CONFIG 0x10
#define IRP_MN_EJECT 0x11
#define IRP_MN_SET_LOCK 0x12
#define IRP_MN_QUERY_ID 0x13
#define IRP_MN_QUERY_PNP_DEVICE_STATE 0x14
#define IRP_MN_QUERY_BUS_INFORMATION 0x15
#define IRP_MN_DEVICE_USAGE_NOTIFICATION 0x16
#define IRP_MN_SURPRISE_REMOVAL 0x17
#define IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18
#define IRP_MN_WAIT_WAKE 0x00
#define IRP_MN_POWER_SEQUENCE 0x01
#define IRP_MN_SET_POWER 0x02
#define IRP_MN_QUERY_POWER 0x03
#define IRP_MN_QUERY_ALL_DATA 0x00
#define IRP_MN_QUERY_SINGLE_INSTANCE 0x01
#define IRP_MN_CHANGE_SINGLE_INSTANCE 0x02
#define IRP_MN_CHANGE_SINGLE_ITEM 0x03
#define IRP_MN_ENABLE_EVENTS 0x04
#define IRP_MN_DISABLE_EVENTS 0x05
#define IRP_MN_ENABLE_COLLECTION 0x06
#define IRP_MN_DISABLE_COLLECTION 0x07
#define IRP_MN_REGINFO 0x08
#define IRP_MN_EXECUTE_METHOD 0x09
#define IRP_MN_REGINFO_EX 0x0b
/* IRP flags */
#define IRP_NOCACHE 0x00000001
#define IRP_PAGING_IO 0x00000002
#define IRP_MOUNT_COMPLETION 0x00000002
#define IRP_SYNCHRONOUS_API 0x00000004
#define IRP_ASSOCIATED_IRP 0x00000008
#define IRP_BUFFERED_IO 0x00000010
#define IRP_DEALLOCATE_BUFFER 0x00000020
#define IRP_INPUT_OPERATION 0x00000040
#define IRP_SYNCHRONOUS_PAGING_IO 0x00000040
#define IRP_CREATE_OPERATION 0x00000080
#define IRP_READ_OPERATION 0x00000100
#define IRP_WRITE_OPERATION 0x00000200
#define IRP_CLOSE_OPERATION 0x00000400
#define IRP_DEFER_IO_COMPLETION 0x00000800
#define IRP_OB_QUERY_NAME 0x00001000
#define IRP_HOLD_DEVICE_QUEUE 0x00002000
#define IRP_RETRY_IO_COMPLETION 0x00004000
#define IRP_CLASS_CACHE_OPERATION 0x00008000
#define IRP_SET_USER_EVENT IRP_CLOSE_OPERATION
/* IRP I/O control flags */
#define IRP_QUOTA_CHARGED 0x01
#define IRP_ALLOCATED_MUST_SUCCEED 0x02
#define IRP_ALLOCATED_FIXED_SIZE 0x04
#define IRP_LOOKASIDE_ALLOCATION 0x08
/* I/O method types */
#define METHOD_BUFFERED 0
#define METHOD_IN_DIRECT 1
#define METHOD_OUT_DIRECT 2
#define METHOD_NEITHER 3
/* File access types */
#define FILE_ANY_ACCESS 0x0000
#define FILE_SPECIAL_ACCESS FILE_ANY_ACCESS
#define FILE_READ_ACCESS 0x0001
#define FILE_WRITE_ACCESS 0x0002
/* Recover I/O access method from IOCTL code. */
#define IO_METHOD(x) ((x) & 0xFFFFFFFC)
/* Recover function code from IOCTL code */
#define IO_FUNC(x) (((x) & 0x7FFC) >> 2)
/* Macro to construct an IOCTL code. */
#define IOCTL_CODE(dev, func, iomethod, acc) \
((dev) << 16) | (acc << 14) | (func << 2) | (iomethod))
struct io_status_block {
union {
uint32_t isb_status;
void *isb_ptr;
} u;
register_t isb_info;
};
#define isb_status u.isb_status
#define isb_ptr u.isb_ptr
typedef struct io_status_block io_status_block;
struct kapc {
uint16_t apc_type;
uint16_t apc_size;
uint32_t apc_spare0;
void *apc_thread;
list_entry apc_list;
void *apc_kernfunc;
void *apc_rundownfunc;
void *apc_normalfunc;
void *apc_normctx;
void *apc_sysarg1;
void *apc_sysarg2;
uint8_t apc_stateidx;
uint8_t apc_cpumode;
uint8_t apc_inserted;
};
typedef struct kapc kapc;
typedef uint32_t (*completion_func)(device_object *,
struct irp *, void *);
typedef uint32_t (*cancel_func)(device_object *,
struct irp *);
struct io_stack_location {
uint8_t isl_major;
uint8_t isl_minor;
uint8_t isl_flags;
uint8_t isl_ctl;
/*
* There's a big-ass union here in the actual Windows
* definition of the stucture, but it contains stuff
* that doesn't really apply to BSD, and defining it
* all properly would require duplicating over a dozen
* other structures that we'll never use. Since the
* io_stack_location structure is opaque to drivers
* anyway, I'm not going to bother with the extra crap.
*/
union {
struct {
uint32_t isl_len;
uint32_t *isl_key;
uint64_t isl_byteoff;
} isl_read;
struct {
uint32_t isl_len;
uint32_t *isl_key;
uint64_t isl_byteoff;
} isl_write;
struct {
uint32_t isl_obuflen;
uint32_t isl_ibuflen;
uint32_t isl_iocode;
void *isl_type3ibuf;
} isl_ioctl;
struct {
void *isl_arg1;
void *isl_arg2;
void *isl_arg3;
void *isl_arg4;
} isl_others;
} isl_parameters __attribute__((packed));
void *isl_devobj;
void *isl_fileobj;
completion_func isl_completionfunc;
void *isl_completionctx;
};
typedef struct io_stack_location io_stack_location;
/* Stack location control flags */
#define SL_PENDING_RETURNED 0x01
#define SL_INVOKE_ON_CANCEL 0x20
#define SL_INVOKE_ON_SUCCESS 0x40
#define SL_INVOKE_ON_ERROR 0x80
struct irp {
uint16_t irp_type;
uint16_t irp_size;
mdl *irp_mdl;
uint32_t irp_flags;
union {
struct irp *irp_master;
uint32_t irp_irpcnt;
void *irp_sysbuf;
} irp_assoc;
list_entry irp_thlist;
io_status_block irp_iostat;
uint8_t irp_reqmode;
uint8_t irp_pendingreturned;
uint8_t irp_stackcnt;
uint8_t irp_currentstackloc;
uint8_t irp_cancel;
uint8_t irp_cancelirql;
uint8_t irp_apcenv;
uint8_t irp_allocflags;
io_status_block *irp_usriostat;
nt_kevent *irp_usrevent;
union {
struct {
void *irp_apcfunc;
void *irp_apcctx;
} irp_asyncparms;
uint64_t irp_allocsz;
} irp_overlay;
cancel_func irp_cancelfunc;
void *irp_userbuf;
/* Windows kernel info */
union {
struct {
union {
kdevice_qentry irp_dqe;
struct {
void *irp_drvctx[4];
} s1;
} u1;
void *irp_thread;
char *irp_auxbuf;
struct {
list_entry irp_list;
union {
io_stack_location *irp_csl;
uint32_t irp_pkttype;
} u2;
} s2;
void *irp_fileobj;
} irp_overlay;
kapc irp_apc;
void *irp_compkey;
} irp_tail;
};
#define irp_csl s2.u2.irp_csl
#define irp_pkttype s2.u2.irp_pkttype
typedef struct irp irp;
#define InterlockedExchangePointer(dst, val) \
(void *)InterlockedExchange((uint32_t *)(dst), (uintptr_t)(val))
#define IoSizeOfIrp(ssize) \
((uint16_t) (sizeof(irp) + ((ssize) * (sizeof(io_stack_location)))))
#define IoSetCancelRoutine(irp, func) \
(cancel_func)InterlockedExchangePointer( \
(void *)&(ip)->irp_cancelfunc, (void *)(func))
#define IoGetCurrentIrpStackLocation(irp) \
(irp)->irp_tail.irp_overlay.irp_csl
#define IoGetNextIrpStackLocation(irp) \
((irp)->irp_tail.irp_overlay.irp_csl - 1)
#define IoSetNextIrpStackLocation(irp) \
do { \
irp->irp_currentstackloc--; \
irp->irp_tail.irp_overlay.irp_csl--; \
} while(0)
#define IoSetCompletionRoutine(irp, func, ctx, ok, err, cancel) \
do { \
io_stack_location *s; \
s = IoGetNextIrpStackLocation((irp)); \
s->isl_completionfunc = (func); \
s->isl_completionctx = (ctx); \
s->isl_ctl = 0; \
if (ok) s->isl_ctl = SL_INVOKE_ON_SUCCESS; \
if (err) s->isl_ctl |= SL_INVOKE_ON_ERROR; \
if (cancel) s->isl_ctl |= SL_INVOKE_ON_CANCEL; \
} while(0)
#define IoMarkIrpPending(irp) \
IoGetCurrentIrpStackLocation(irp)->isl_ctl |= SL_PENDING_RETURNED
#define IoCopyCurrentIrpStackLocationToNext(irp) \
do { \
io_stack_location *src, *dst; \
src = IoGetCurrentIrpStackLocation(irp); \
dst = IoGetNextIrpStackLocation(irp); \
bcopy((char *)src, (char *)dst, \
offsetof(io_stack_location, isl_completionfunc)); \
} while(0)
#define IoSkipCurrentIrpStackLocation(irp) \
do { \
(irp)->irp_currentstackloc++; \
(irp)->irp_tail.irp_overlay.irp_csl++; \
} while(0)
#define IoInitializeDpcRequest(dobj, dpcfunc) \
KeInitializeDpc(&(dobj)->do_dpc, dpcfunc, dobj)
#define IoRequestDpc(dobj, irp, ctx) \
KeInsertQueueDpc(&(dobj)->do_dpc, irp, ctx)
typedef uint32_t (*driver_dispatch)(device_object *, irp *);
/*
* The driver_object is allocated once for each driver that's loaded
* into the system. A new one is allocated for each driver and
* populated a bit via the driver's DriverEntry function.
* In general, a Windows DriverEntry() function will provide a pointer
* to its AddDevice() method and set up the dispatch table.
* For NDIS drivers, this is all done behind the scenes in the
* NdisInitializeWrapper() and/or NdisMRegisterMiniport() routines.
*/
struct driver_object {
uint16_t dro_type;
uint16_t dro_size;
device_object *dro_devobj;
uint32_t dro_flags;
void *dro_driverstart;
uint32_t dro_driversize;
void *dro_driversection;
driver_extension *dro_driverext;
unicode_string dro_drivername;
unicode_string *dro_hwdb;
void *dro_pfastiodispatch;
void *dro_driverinitfunc;
void *dro_driverstartiofunc;
void *dro_driverunloadfunc;
driver_dispatch dro_dispatch[IRP_MJ_MAXIMUM_FUNCTION + 1];
};
typedef struct driver_object driver_object;
#define DEVPROP_DEVICE_DESCRIPTION 0x00000000
#define DEVPROP_HARDWARE_ID 0x00000001
#define DEVPROP_COMPATIBLE_IDS 0x00000002
#define DEVPROP_BOOTCONF 0x00000003
#define DEVPROP_BOOTCONF_TRANSLATED 0x00000004
#define DEVPROP_CLASS_NAME 0x00000005
#define DEVPROP_CLASS_GUID 0x00000006
#define DEVPROP_DRIVER_KEYNAME 0x00000007
#define DEVPROP_MANUFACTURER 0x00000008
#define DEVPROP_FRIENDLYNAME 0x00000009
#define DEVPROP_LOCATION_INFO 0x0000000A
#define DEVPROP_PHYSDEV_NAME 0x0000000B
#define DEVPROP_BUSTYPE_GUID 0x0000000C
#define DEVPROP_LEGACY_BUSTYPE 0x0000000D
#define DEVPROP_BUS_NUMBER 0x0000000E
#define DEVPROP_ENUMERATOR_NAME 0x0000000F
#define DEVPROP_ADDRESS 0x00000010
#define DEVPROP_UINUMBER 0x00000011
#define DEVPROP_INSTALL_STATE 0x00000012
#define DEVPROP_REMOVAL_POLICY 0x00000013
/* Various supported device types (used with IoCreateDevice()) */
#define FILE_DEVICE_BEEP 0x00000001
#define FILE_DEVICE_CD_ROM 0x00000002
#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
#define FILE_DEVICE_CONTROLLER 0x00000004
#define FILE_DEVICE_DATALINK 0x00000005
#define FILE_DEVICE_DFS 0x00000006
#define FILE_DEVICE_DISK 0x00000007
#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
#define FILE_DEVICE_FILE_SYSTEM 0x00000009
#define FILE_DEVICE_INPORT_PORT 0x0000000A
#define FILE_DEVICE_KEYBOARD 0x0000000B
#define FILE_DEVICE_MAILSLOT 0x0000000C
#define FILE_DEVICE_MIDI_IN 0x0000000D
#define FILE_DEVICE_MIDI_OUT 0x0000000E
#define FILE_DEVICE_MOUSE 0x0000000F
#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010
#define FILE_DEVICE_NAMED_PIPE 0x00000011
#define FILE_DEVICE_NETWORK 0x00000012
#define FILE_DEVICE_NETWORK_BROWSER 0x00000013
#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
#define FILE_DEVICE_NULL 0x00000015
#define FILE_DEVICE_PARALLEL_PORT 0x00000016
#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
#define FILE_DEVICE_PRINTER 0x00000018
#define FILE_DEVICE_SCANNER 0x00000019
#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001A
#define FILE_DEVICE_SERIAL_PORT 0x0000001B
#define FILE_DEVICE_SCREEN 0x0000001C
#define FILE_DEVICE_SOUND 0x0000001D
#define FILE_DEVICE_STREAMS 0x0000001E
#define FILE_DEVICE_TAPE 0x0000001F
#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
#define FILE_DEVICE_TRANSPORT 0x00000021
#define FILE_DEVICE_UNKNOWN 0x00000022
#define FILE_DEVICE_VIDEO 0x00000023
#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
#define FILE_DEVICE_WAVE_IN 0x00000025
#define FILE_DEVICE_WAVE_OUT 0x00000026
#define FILE_DEVICE_8042_PORT 0x00000027
#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
#define FILE_DEVICE_BATTERY 0x00000029
#define FILE_DEVICE_BUS_EXTENDER 0x0000002A
#define FILE_DEVICE_MODEM 0x0000002B
#define FILE_DEVICE_VDM 0x0000002C
#define FILE_DEVICE_MASS_STORAGE 0x0000002D
#define FILE_DEVICE_SMB 0x0000002E
#define FILE_DEVICE_KS 0x0000002F
#define FILE_DEVICE_CHANGER 0x00000030
#define FILE_DEVICE_SMARTCARD 0x00000031
#define FILE_DEVICE_ACPI 0x00000032
#define FILE_DEVICE_DVD 0x00000033
#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034
#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035
#define FILE_DEVICE_DFS_VOLUME 0x00000036
#define FILE_DEVICE_SERENUM 0x00000037
#define FILE_DEVICE_TERMSRV 0x00000038
#define FILE_DEVICE_KSEC 0x00000039
#define FILE_DEVICE_FIPS 0x0000003A
/* Device characteristics */
#define FILE_REMOVABLE_MEDIA 0x00000001
#define FILE_READ_ONLY_DEVICE 0x00000002
#define FILE_FLOPPY_DISKETTE 0x00000004
#define FILE_WRITE_ONCE_MEDIA 0x00000008
#define FILE_REMOTE_DEVICE 0x00000010
#define FILE_DEVICE_IS_MOUNTED 0x00000020
#define FILE_VIRTUAL_VOLUME 0x00000040
#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080
#define FILE_DEVICE_SECURE_OPEN 0x00000100
/* Status codes */
#define STATUS_SUCCESS 0x00000000
#define STATUS_USER_APC 0x000000C0
#define STATUS_KERNEL_APC 0x00000100
#define STATUS_ALERTED 0x00000101
#define STATUS_TIMEOUT 0x00000102
#define STATUS_PENDING 0x00000103
#define STATUS_INVALID_PARAMETER 0xC000000D
#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010
#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
#define STATUS_BUFFER_TOO_SMALL 0xC0000023
#define STATUS_MUTANT_NOT_OWNED 0xC0000046
#define STATUS_INVALID_PARAMETER_2 0xC00000F0
#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A
#define STATUS_WAIT_0 0x00000000
/* Memory pool types, for ExAllocatePoolWithTag() */
#define NonPagedPool 0x00000000
#define PagedPool 0x00000001
#define NonPagedPoolMustSucceed 0x00000002
#define DontUseThisType 0x00000003
#define NonPagedPoolCacheAligned 0x00000004
#define PagedPoolCacheAligned 0x00000005
#define NonPagedPoolCacheAlignedMustS 0x00000006
#define MaxPoolType 0x00000007
/*
* FreeBSD's kernel stack is 2 pages in size by default. The
* Windows stack is larger, so we need to give our threads more
* stack pages. 4 should be enough, we use 8 just to extra safe.
*/
#define NDIS_KSTACK_PAGES 8
/*
* Different kinds of function wrapping we can do.
*/
#define WINDRV_WRAP_STDCALL 1
#define WINDRV_WRAP_FASTCALL 2
#define WINDRV_WRAP_REGPARM 3
#define WINDRV_WRAP_CDECL 4
#define WINDRV_WRAP_AMD64 5
extern image_patch_table ntoskrnl_functbl[];
typedef void (*funcptr)(void);
__BEGIN_DECLS
extern int windrv_libinit(void);
extern int windrv_libfini(void);
extern driver_object *windrv_lookup(vm_offset_t, char *);
extern int windrv_load(module_t, vm_offset_t, int);
extern int windrv_unload(module_t, vm_offset_t, int);
extern int windrv_create_pdo(driver_object *, device_t);
extern void windrv_destroy_pdo(driver_object *, device_t);
extern device_object *windrv_find_pdo(driver_object *, device_t);
extern int windrv_bus_attach(driver_object *, char *);
extern int windrv_wrap(funcptr, funcptr *, int, int);
extern int windrv_unwrap(funcptr);
extern void ctxsw_utow(void);
extern void ctxsw_wtou(void);
extern int ntoskrnl_libinit(void);
extern int ntoskrnl_libfini(void);
extern void KeInitializeDpc(kdpc *, void *, void *);
extern uint8_t KeInsertQueueDpc(kdpc *, void *, void *);
extern uint8_t KeRemoveQueueDpc(kdpc *);
extern void KeInitializeTimer(ktimer *);
extern void KeInitializeTimerEx(ktimer *, uint32_t);
extern uint8_t KeSetTimer(ktimer *, int64_t, kdpc *);
extern uint8_t KeSetTimerEx(ktimer *, int64_t, uint32_t, kdpc *);
extern uint8_t KeCancelTimer(ktimer *);
extern uint8_t KeReadStateTimer(ktimer *);
extern uint32_t KeWaitForSingleObject(nt_dispatch_header *, uint32_t,
uint32_t, uint8_t, int64_t *);
extern void KeInitializeEvent(nt_kevent *, uint32_t, uint8_t);
extern void KeClearEvent(nt_kevent *);
extern uint32_t KeReadStateEvent(nt_kevent *);
extern uint32_t KeSetEvent(nt_kevent *, uint32_t, uint8_t);
extern uint32_t KeResetEvent(nt_kevent *);
#ifdef __i386__
extern void KefAcquireSpinLockAtDpcLevel(kspin_lock *);
extern void KefReleaseSpinLockFromDpcLevel(kspin_lock *);
extern uint8_t KeAcquireSpinLockRaiseToDpc(kspin_lock *);
#else
extern void KeAcquireSpinLockAtDpcLevel(kspin_lock *);
extern void KeReleaseSpinLockFromDpcLevel(kspin_lock *);
#endif
extern void KeInitializeSpinLock(kspin_lock *);
extern uintptr_t InterlockedExchange(volatile uint32_t *,
uintptr_t);
extern void *ExAllocatePoolWithTag(uint32_t, size_t, uint32_t);
extern void ExFreePool(void *);
extern uint32_t IoAllocateDriverObjectExtension(driver_object *,
void *, uint32_t, void **);
extern void *IoGetDriverObjectExtension(driver_object *, void *);
extern uint32_t IoCreateDevice(driver_object *, uint32_t,
unicode_string *, uint32_t, uint32_t, uint8_t, device_object **);
extern void IoDeleteDevice(device_object *);
extern device_object *IoGetAttachedDevice(device_object *);
extern uint32_t IofCallDriver(device_object *, irp *);
extern void IofCompleteRequest(irp *, uint8_t);
extern void IoAcquireCancelSpinLock(uint8_t *);
extern void IoReleaseCancelSpinLock(uint8_t);
extern uint8_t IoCancelIrp(irp *);
extern void IoDetachDevice(device_object *);
extern device_object *IoAttachDeviceToDeviceStack(device_object *,
device_object *);
mdl *IoAllocateMdl(void *, uint32_t, uint8_t, uint8_t, irp *);
void IoFreeMdl(mdl *);
#define IoCallDriver(a, b) IofCallDriver(a, b)
#define IoCompleteRequest(a, b) IofCompleteRequest(a, b)
/*
* On the Windows x86 arch, KeAcquireSpinLock() and KeReleaseSpinLock()
* routines live in the HAL. We try to imitate this behavior.
*/
#ifdef __i386__
#define KeAcquireSpinLock(a, b) *(b) = KfAcquireSpinLock(a)
#define KeReleaseSpinLock(a, b) KfReleaseSpinLock(a, b)
#define KeRaiseIrql(a) KfRaiseIrql(a)
#define KeLowerIrql(a) KfLowerIrql(a)
#define KeAcquireSpinLockAtDpcLevel(a) KefAcquireSpinLockAtDpcLevel(a)
#define KeReleaseSpinLockFromDpcLevel(a) KefReleaseSpinLockFromDpcLevel(a)
#endif /* __i386__ */
#ifdef __amd64__
#define KeAcquireSpinLock(a, b) *(b) = KfAcquireSpinLock(a)
#define KeReleaseSpinLock(a, b) KfReleaseSpinLock(a, b)
/*
* These may need to be redefined later;
* not sure where they live on amd64 yet.
*/
#define KeRaiseIrql(a) KfRaiseIrql(a)
#define KeLowerIrql(a) KfLowerIrql(a)
#endif /* __amd64__ */
__END_DECLS
#endif /* _NTOSKRNL_VAR_H_ */