6f4481422e
- In ntoskrnl_var.h, I had defined compat macros for ntoskrnl_acquire_spinlock() and ntoskrnl_release_spinlock() but never used them. This is fortunate since they were stale. Fix them to work properly. (In Windows/x86 KeAcquireSpinLock() is a macro that calls KefAcquireSpinLock(), which lives in HAL.dll. To imitate this, ntoskrnl_acquire_spinlock() is just a macro that calls hal_lock(), which lives in subr_hal.o.) - Add macros for ntoskrnl_raise_irql() and ntoskrnl_lower_irql() that call hal_raise_irql() and hal_lower_irql(). - Use these macros in kern_ndis.c, subr_ndis.c and subr_ntoskrnl.c. - Along the way, I realised subr_ndis.c:ndis_lock() was not calling hal_lock() correctly (it was using the FASTCALL2() wrapper when in reality this routine is FASTCALL1()). Using the ntoskrnl_acquire_spinlock() fixes this. Not sure if this actually caused any bugs since hal_lock() would have just ignored what was in %edx, but it was still bogus. This hides many of the uses of the FASTCALLx() macros which makes the code a little cleaner. Should not have any effect on generated object code, other than the one fix in ndis_lock().
527 lines
14 KiB
C
527 lines
14 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_
|
|
|
|
/* Note: assumes x86 page size of 4K. */
|
|
#define PAGE_SHIFT 12
|
|
#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_INIT(b, baseva, len) \
|
|
(b)->nb_next = NULL; \
|
|
(b)->nb_size = (uint16_t)(sizeof(struct ndis_buffer) + \
|
|
(sizeof(uint32_t) * SPAN_PAGES((baseva), (len)))); \
|
|
(b)->nb_flags = 0; \
|
|
(b)->nb_startva = (void *)PAGE_ALIGN((baseva)); \
|
|
(b)->nb_byteoffset = BYTE_OFFSET((baseva)); \
|
|
(b)->nb_bytecount = (uint32_t)(len);
|
|
#define MDL_VA(b) \
|
|
((void *)((char *)((b)->nb_startva) + (b)->nb_byteoffset))
|
|
|
|
#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;
|
|
kdpc_func 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;
|
|
kspin_lock nll_obsoletelock;
|
|
};
|
|
|
|
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;
|
|
|
|
struct device_object {
|
|
uint16_t do_type;
|
|
uint16_t do_size;
|
|
uint32_t do_refcnt;
|
|
struct device_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;
|
|
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;
|
|
void *do_devobj_ext;
|
|
void *do_rsvd;
|
|
};
|
|
|
|
typedef struct device_object device_object;
|
|
|
|
struct irp {
|
|
uint32_t i_dummy;
|
|
};
|
|
|
|
typedef struct irp irp;
|
|
|
|
typedef uint32_t (*driver_dispatch)(device_object *, irp *);
|
|
|
|
#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
|
|
|
|
#define STATUS_SUCCESS 0x00000000
|
|
#define STATUS_USER_APC 0x000000C0
|
|
#define STATUS_KERNEL_APC 0x00000100
|
|
#define STATUS_ALERTED 0x00000101
|
|
#define STATUS_TIMEOUT 0x00000102
|
|
#define STATUS_INVALID_PARAMETER 0xC000000D
|
|
#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010
|
|
#define STATUS_BUFFER_TOO_SMALL 0xC0000023
|
|
#define STATUS_MUTANT_NOT_OWNED 0xC0000046
|
|
#define STATUS_INVALID_PARAMETER_2 0xC00000F0
|
|
|
|
#define STATUS_WAIT_0 0x00000000
|
|
|
|
/*
|
|
* 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
|
|
|
|
extern image_patch_table ntoskrnl_functbl[];
|
|
|
|
__BEGIN_DECLS
|
|
extern int ntoskrnl_libinit(void);
|
|
extern int ntoskrnl_libfini(void);
|
|
__stdcall extern void ntoskrnl_init_dpc(kdpc *, void *, void *);
|
|
__stdcall extern uint8_t ntoskrnl_queue_dpc(kdpc *, void *, void *);
|
|
__stdcall extern uint8_t ntoskrnl_dequeue_dpc(kdpc *);
|
|
__stdcall extern void ntoskrnl_init_timer(ktimer *);
|
|
__stdcall extern void ntoskrnl_init_timer_ex(ktimer *, uint32_t);
|
|
__stdcall extern uint8_t ntoskrnl_set_timer(ktimer *, int64_t, kdpc *);
|
|
__stdcall extern uint8_t ntoskrnl_set_timer_ex(ktimer *, int64_t,
|
|
uint32_t, kdpc *);
|
|
__stdcall extern uint8_t ntoskrnl_cancel_timer(ktimer *);
|
|
__stdcall extern uint8_t ntoskrnl_read_timer(ktimer *);
|
|
__stdcall extern uint32_t ntoskrnl_waitforobj(nt_dispatch_header *, uint32_t,
|
|
uint32_t, uint8_t, int64_t *);
|
|
__stdcall extern void ntoskrnl_init_event(nt_kevent *, uint32_t, uint8_t);
|
|
__stdcall extern void ntoskrnl_clear_event(nt_kevent *);
|
|
__stdcall extern uint32_t ntoskrnl_read_event(nt_kevent *);
|
|
__stdcall extern uint32_t ntoskrnl_set_event(nt_kevent *, uint32_t, uint8_t);
|
|
__stdcall extern uint32_t ntoskrnl_reset_event(nt_kevent *);
|
|
__fastcall extern void ntoskrnl_lock_dpc(REGARGS1(kspin_lock *));
|
|
__fastcall extern void ntoskrnl_unlock_dpc(REGARGS1(kspin_lock *));
|
|
|
|
/*
|
|
* On the Windows x86 arch, KeAcquireSpinLock() and KeReleaseSpinLock()
|
|
* routines live in the HAL. We try to imitate this behavior.
|
|
*/
|
|
#ifdef __i386__
|
|
#define ntoskrnl_acquire_spinlock(a, b) *(b) = FASTCALL1(hal_lock, a)
|
|
#define ntoskrnl_release_spinlock(a, b) FASTCALL2(hal_unlock, a, b)
|
|
#define ntoskrnl_raise_irql(a) FASTCALL1(hal_raise_irql, a)
|
|
#define ntoskrnl_lower_irql(a) FASTCALL1(hal_lower_irql, a)
|
|
#endif /* __i386__ */
|
|
__END_DECLS
|
|
|
|
#endif /* _NTOSKRNL_VAR_H_ */
|