summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/compat/ndis/kern_ndis.c39
-rw-r--r--sys/compat/ndis/ndis_var.h15
-rw-r--r--sys/compat/ndis/ntoskrnl_var.h287
-rw-r--r--sys/compat/ndis/subr_hal.c14
-rw-r--r--sys/compat/ndis/subr_ndis.c218
-rw-r--r--sys/compat/ndis/subr_ntoskrnl.c740
6 files changed, 1212 insertions, 101 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
index 98b9c91..9ce8132 100644
--- a/sys/compat/ndis/kern_ndis.c
+++ b/sys/compat/ndis/kern_ndis.c
@@ -71,9 +71,9 @@ __FBSDID("$FreeBSD$");
#include <compat/ndis/pe_var.h>
#include <compat/ndis/resource_var.h>
+#include <compat/ndis/ntoskrnl_var.h>
#include <compat/ndis/ndis_var.h>
#include <compat/ndis/hal_var.h>
-#include <compat/ndis/ntoskrnl_var.h>
#include <compat/ndis/cfg_var.h>
#include <dev/if_ndis/if_ndisvar.h>
@@ -1444,7 +1444,6 @@ ndis_load_driver(img, arg)
image_optional_header opt_hdr;
image_import_descriptor imp_desc;
ndis_unicode_string dummystr;
- ndis_driver_object drv;
ndis_miniport_block *block;
ndis_status status;
int idx;
@@ -1487,23 +1486,10 @@ ndis_load_driver(img, arg)
pe_get_optional_header(img, &opt_hdr);
entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
- /*
- * Now call the DriverEntry() routine. This will cause
- * a callout to the NdisInitializeWrapper() and
- * NdisMRegisterMiniport() routines.
- */
- dummystr.nus_len = strlen(NDIS_DUMMY_PATH);
- dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH);
+ dummystr.nus_len = strlen(NDIS_DUMMY_PATH) * 2;
+ dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH) * 2;
dummystr.nus_buf = NULL;
ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
- drv.ndo_ifname = "ndis0";
-
- status = entry(&drv, &dummystr);
-
- free (dummystr.nus_buf, M_DEVBUF);
-
- if (status != NDIS_STATUS_SUCCESS)
- return(ENODEV);
/*
* Now that we have the miniport driver characteristics,
@@ -1513,12 +1499,8 @@ ndis_load_driver(img, arg)
*/
block = &sc->ndis_block;
- bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars,
- sizeof(ndis_miniport_characteristics));
- /*block->nmb_signature = 0xcafebabe;*/
-
- ptr = (uint32_t *)block;
+ ptr = (uint32_t *)block;
for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
*ptr = idx | 0xdead0000;
ptr++;
@@ -1535,6 +1517,19 @@ ndis_load_driver(img, arg)
block->nmb_ifp = &sc->arpcom.ac_if;
block->nmb_dev = sc->ndis_dev;
block->nmb_img = img;
+ block->nmb_devobj.do_rsvd = block;
+
+ /*
+ * Now call the DriverEntry() routine. This will cause
+ * a callout to the NdisInitializeWrapper() and
+ * NdisMRegisterMiniport() routines.
+ */
+ status = entry(&block->nmb_devobj, &dummystr);
+
+ free (dummystr.nus_buf, M_DEVBUF);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ return(ENODEV);
ndis_enlarge_thrqueue(8);
diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h
index cd03ca7..58f174f 100644
--- a/sys/compat/ndis/ndis_var.h
+++ b/sys/compat/ndis/ndis_var.h
@@ -793,12 +793,14 @@ struct ndis_config_parm {
typedef struct ndis_config_parm ndis_config_parm;
+#ifdef notdef
struct ndis_list_entry {
struct ndis_list_entry *nle_flink;
struct ndis_list_entry *nle_blink;
};
typedef struct ndis_list_entry ndis_list_entry;
+#endif
struct ndis_bind_paths {
uint32_t nbp_number;
@@ -807,19 +809,23 @@ struct ndis_bind_paths {
typedef struct ndis_bind_paths ndis_bind_paths;
+#ifdef notdef
struct dispatch_header {
uint8_t dh_type;
uint8_t dh_abs;
uint8_t dh_size;
uint8_t dh_inserted;
uint32_t dh_sigstate;
- ndis_list_entry dh_waitlisthead;
+ list_entry dh_waitlisthead;
};
+#endif
+
+#define dispatch_header nt_dispatch_header
struct ndis_ktimer {
struct dispatch_header nk_header;
uint64_t nk_duetime;
- ndis_list_entry nk_timerlistentry;
+ list_entry nk_timerlistentry;
void *nk_dpc;
uint32_t nk_period;
};
@@ -843,7 +849,7 @@ struct ndis_kdpc {
uint16_t nk_type;
uint8_t nk_num;
uint8_t nk_importance;
- ndis_list_entry nk_dpclistentry;
+ list_entry nk_dpclistentry;
ndis_kdpc_func nk_deferedfunc;
void *nk_deferredctx;
void *nk_sysarg1;
@@ -1355,7 +1361,7 @@ struct ndis_miniport_block {
ndis_miniport_interrupt *nmb_interrupt;
uint32_t nmb_flags;
uint32_t nmb_pnpflags;
- ndis_list_entry nmb_packetlist;
+ list_entry nmb_packetlist;
ndis_packet *nmb_firstpendingtxpacket;
ndis_packet *nmb_returnpacketqueue;
uint32_t nmb_requestbuffer;
@@ -1426,6 +1432,7 @@ struct ndis_miniport_block {
*/
struct ifnet *nmb_ifp;
uint8_t nmb_dummybuf[128];
+ device_object nmb_devobj;
ndis_config_parm nmb_replyparm;
int nmb_pciidx;
device_t nmb_dev;
diff --git a/sys/compat/ndis/ntoskrnl_var.h b/sys/compat/ndis/ntoskrnl_var.h
index adbf68b..dd7bc9a 100644
--- a/sys/compat/ndis/ntoskrnl_var.h
+++ b/sys/compat/ndis/ntoskrnl_var.h
@@ -109,6 +109,162 @@ struct list_entry {
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 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)
+
+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
+
+struct ktimer {
+ nt_dispatch_header k_header;
+ uint64_t k_duetime;
+ list_entry k_timerlistentry;
+ void *k_dpc;
+ uint32_t k_period;
+};
+
+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;
+ uint32_t *k_lock;
+};
+
+/*
+ * 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;
+ list_entry km_listentry;
+ void *km_ownerthread;
+ uint8_t km_abandoned;
+ uint8_t km_apcdisable;
+ uint32_t km_acquirecnt;
+};
+
+typedef struct kmutant kmutant;
+
struct general_lookaside {
slist_header gl_listhead;
uint16_t gl_depth;
@@ -150,12 +306,143 @@ 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
extern image_patch_table ntoskrnl_functbl[];
+extern struct mtx *ntoskrnl_dispatchlock;
__BEGIN_DECLS
extern int ntoskrnl_libinit(void);
extern int ntoskrnl_libfini(void);
+extern void ntoskrnl_wakeup(void *);
__END_DECLS
#endif /* _NTOSKRNL_VAR_H_ */
diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c
index f3bb2fd..c324d3f 100644
--- a/sys/compat/ndis/subr_hal.c
+++ b/sys/compat/ndis/subr_hal.c
@@ -79,6 +79,7 @@ __stdcall static void hal_readport_buf_uchar(uint8_t *,
__stdcall static uint8_t hal_lock(/*kspin_lock * */void);
__stdcall static void hal_unlock(/*kspin_lock *, uint8_t*/void);
__stdcall static uint8_t hal_irql(void);
+__stdcall static uint64_t hal_perfcount(uint64_t *);
__stdcall static void dummy (void);
extern struct mtx_pool *ndis_mtxpool;
@@ -231,7 +232,17 @@ hal_unlock(/*lock, newirql*/void)
__stdcall static uint8_t
hal_irql(void)
{
- return(0);
+ return(DISPATCH_LEVEL);
+}
+
+__stdcall static uint64_t
+hal_perfcount(freq)
+ uint64_t *freq;
+{
+ if (freq != NULL)
+ *freq = hz;
+
+ return((uint64_t)ticks);
}
__stdcall
@@ -258,6 +269,7 @@ image_patch_table hal_functbl[] = {
{ "KfAcquireSpinLock", (FUNC)hal_lock },
{ "KfReleaseSpinLock", (FUNC)hal_unlock },
{ "KeGetCurrentIrql", (FUNC)hal_irql },
+ { "KeQueryPerformanceCounter", (FUNC)hal_perfcount },
/*
* This last entry is a catch-all for any function we haven't
diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c
index 6f736a4..4ac3fbe 100644
--- a/sys/compat/ndis/subr_ndis.c
+++ b/sys/compat/ndis/subr_ndis.c
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
#include <sys/namei.h>
#include <sys/fcntl.h>
#include <sys/vnode.h>
+#include <sys/kthread.h>
#include <net/if.h>
#include <net/if_arp.h>
@@ -110,8 +111,8 @@ extern struct nd_head ndis_devhead;
SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath,
MAXPATHLEN, "Path used by NdisOpenFile() to search for files");
-__stdcall static void ndis_initwrap(ndis_handle,
- ndis_driver_object *, void *, void *);
+__stdcall static void ndis_initwrap(ndis_handle *,
+ device_object *, void *, void *);
__stdcall static ndis_status ndis_register_miniport(ndis_handle,
ndis_miniport_characteristics *, int);
__stdcall static ndis_status ndis_malloc_withtag(void **, uint32_t, uint32_t);
@@ -235,12 +236,12 @@ __stdcall static uint32_t ndis_read_pccard_amem(ndis_handle,
uint32_t, void *, uint32_t);
__stdcall static uint32_t ndis_write_pccard_amem(ndis_handle,
uint32_t, void *, uint32_t);
-__stdcall static ndis_list_entry *ndis_insert_head(ndis_list_entry *,
- ndis_list_entry *, ndis_spin_lock *);
-__stdcall static ndis_list_entry *ndis_remove_head(ndis_list_entry *,
+__stdcall static list_entry *ndis_insert_head(list_entry *,
+ list_entry *, ndis_spin_lock *);
+__stdcall static list_entry *ndis_remove_head(list_entry *,
ndis_spin_lock *);
-__stdcall static ndis_list_entry *ndis_insert_tail(ndis_list_entry *,
- ndis_list_entry *, ndis_spin_lock *);
+__stdcall static list_entry *ndis_insert_tail(list_entry *,
+ list_entry *, ndis_spin_lock *);
__stdcall static uint8_t ndis_sync_with_intr(ndis_miniport_interrupt *,
void *, void *);
__stdcall static void ndis_time(uint64_t *);
@@ -252,8 +253,9 @@ __stdcall static void ndis_init_unicode_string(ndis_unicode_string *,
__stdcall static void ndis_free_string(ndis_unicode_string *);
__stdcall static ndis_status ndis_remove_miniport(ndis_handle *);
__stdcall static void ndis_termwrap(ndis_handle, void *);
-__stdcall static void ndis_get_devprop(ndis_handle, void *, void *,
- void *, cm_resource_list *, cm_resource_list *);
+__stdcall static void ndis_get_devprop(ndis_handle, device_object **,
+ device_object **, device_object **, cm_resource_list *,
+ cm_resource_list *);
__stdcall static void ndis_firstbuf(ndis_packet *, ndis_buffer **,
void **, uint32_t *, uint32_t *);
__stdcall static void ndis_firstbuf_safe(ndis_packet *, ndis_buffer **,
@@ -273,10 +275,13 @@ __stdcall static void ndis_pkt_to_pkt(ndis_packet *, uint32_t, uint32_t,
ndis_packet *, uint32_t, uint32_t *);
__stdcall static void ndis_pkt_to_pkt_safe(ndis_packet *, uint32_t, uint32_t,
ndis_packet *, uint32_t, uint32_t *, uint32_t);
-__stdcall static ndis_status ndis_register_dev(ndis_handle *,
- ndis_unicode_string *, ndis_unicode_string *, void *,
- void *, ndis_handle **);
-__stdcall static ndis_status ndis_deregister_dev(ndis_handle *);
+__stdcall static ndis_status ndis_register_dev(ndis_handle,
+ ndis_unicode_string *, ndis_unicode_string *, driver_dispatch **,
+ void **, ndis_handle *);
+__stdcall static ndis_status ndis_deregister_dev(ndis_handle);
+__stdcall static ndis_status ndis_query_name(ndis_unicode_string *,
+ ndis_handle);
+__stdcall static void ndis_register_unload(ndis_handle, void *);
__stdcall static void dummy(void);
/*
@@ -359,15 +364,15 @@ ndis_unicode_to_ascii(unicode, ulen, ascii)
__stdcall static void
ndis_initwrap(wrapper, drv_obj, path, unused)
- ndis_handle wrapper;
- ndis_driver_object *drv_obj;
+ ndis_handle *wrapper;
+ device_object *drv_obj;
void *path;
void *unused;
{
- ndis_driver_object **drv;
+ ndis_miniport_block *block;
- drv = wrapper;
- *drv = drv_obj;
+ block = drv_obj->do_rsvd;
+ *wrapper = block;
return;
}
@@ -386,11 +391,20 @@ ndis_register_miniport(handle, characteristics, len)
ndis_miniport_characteristics *characteristics;
int len;
{
- ndis_driver_object *drv;
+ ndis_miniport_block *block;
+ struct ndis_softc *sc;
- drv = handle;
- bcopy((char *)characteristics, (char *)&drv->ndo_chars,
+ block = (ndis_miniport_block *)handle;
+ sc = (struct ndis_softc *)block->nmb_ifp;
+ bcopy((char *)characteristics, (char *)&sc->ndis_chars,
sizeof(ndis_miniport_characteristics));
+ if (sc->ndis_chars.nmc_version_major < 5 ||
+ sc->ndis_chars.nmc_version_minor < 1) {
+ sc->ndis_chars.nmc_shutdown_handler = NULL;
+ sc->ndis_chars.nmc_canceltxpkts_handler = NULL;
+ sc->ndis_chars.nmc_pnpevent_handler = NULL;
+ }
+
return(NDIS_STATUS_SUCCESS);
}
@@ -436,6 +450,7 @@ ndis_free(vaddr, len, flags)
if (len == 0)
return;
free(vaddr, M_DEVBUF);
+
return;
}
@@ -937,7 +952,10 @@ ndis_init_timer(timer, func, ctx)
TAILQ_INSERT_TAIL(&block->nmb_timerlist, ne, link);
ne->nte_timer = (ndis_miniport_timer *)timer;
- timer->nt_timer.nk_header.dh_sigstate = TRUE;
+ INIT_LIST_HEAD((&timer->nt_timer.nk_header.dh_waitlisthead));
+ timer->nt_timer.nk_header.dh_sigstate = FALSE;
+ timer->nt_timer.nk_header.dh_type = EVENT_TYPE_NOTIFY;
+ timer->nt_timer.nk_header.dh_size = OTYPE_TIMER;
timer->nt_dpc.nk_sysarg1 = &ne->nte_ch;
timer->nt_dpc.nk_deferedfunc = (ndis_kdpc_func)func;
timer->nt_dpc.nk_deferredctx = ctx;
@@ -961,7 +979,10 @@ ndis_create_timer(timer, handle, func, ctx)
TAILQ_INSERT_TAIL(&block->nmb_timerlist, ne, link);
ne->nte_timer = timer;
- timer->nmt_ktimer.nk_header.dh_sigstate = TRUE;
+ INIT_LIST_HEAD((&timer->nmt_ktimer.nk_header.dh_waitlisthead));
+ timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
+ timer->nmt_ktimer.nk_header.dh_type = EVENT_TYPE_NOTIFY;
+ timer->nmt_ktimer.nk_header.dh_size = OTYPE_TIMER;
timer->nmt_dpc.nk_sysarg1 = &ne->nte_ch;
timer->nmt_dpc.nk_deferedfunc = (ndis_kdpc_func)func;
timer->nmt_dpc.nk_deferredctx = ctx;
@@ -983,18 +1004,16 @@ ndis_timercall(arg)
timer = arg;
- timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
timerfunc = (ndis_timer_function)timer->nmt_dpc.nk_deferedfunc;
timerfunc(NULL, timer->nmt_dpc.nk_deferredctx, NULL, NULL);
+ ntoskrnl_wakeup(&timer->nmt_ktimer.nk_header);
return;
}
/*
* Windows specifies timeouts in milliseconds. We specify timeouts
- * in hz. Trying to compute a tenth of a second based on hz is tricky.
- * so we approximate. Note that we abuse the dpc portion of the
- * miniport timer structure to hold the UNIX callout handle.
+ * in hz, so some conversion is required.
*/
__stdcall static void
ndis_set_timer(timer, msecs)
@@ -1009,7 +1028,7 @@ ndis_set_timer(timer, msecs)
ch = timer->nmt_dpc.nk_sysarg1;
timer->nmt_dpc.nk_sysarg2 = ndis_timercall;
- timer->nmt_ktimer.nk_header.dh_sigstate = TRUE;
+ timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
return;
@@ -1026,16 +1045,16 @@ ndis_tick(arg)
timer = arg;
- timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
timerfunc = (ndis_timer_function)timer->nmt_dpc.nk_deferedfunc;
timerfunc(NULL, timer->nmt_dpc.nk_deferredctx, NULL, NULL);
+ ntoskrnl_wakeup(&timer->nmt_ktimer.nk_header);
/* Automatically reload timer. */
tv.tv_sec = 0;
tv.tv_usec = timer->nmt_ktimer.nk_period * 1000;
ch = timer->nmt_dpc.nk_sysarg1;
- timer->nmt_ktimer.nk_header.dh_sigstate = TRUE;
+ timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
timer->nmt_dpc.nk_sysarg2 = ndis_tick;
callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
@@ -1056,7 +1075,7 @@ ndis_set_periodic_timer(timer, msecs)
timer->nmt_ktimer.nk_period = msecs;
ch = timer->nmt_dpc.nk_sysarg1;
timer->nmt_dpc.nk_sysarg2 = ndis_tick;
- timer->nmt_ktimer.nk_header.dh_sigstate = TRUE;
+ timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
return;
@@ -1350,7 +1369,7 @@ ndis_asyncmem_complete(arg)
w->na_cached, &vaddr, &paddr);
donefunc(w->na_adapter, vaddr, &paddr, w->na_len, w->na_ctx);
- free(arg, M_TEMP);
+ free(arg, M_DEVBUF);
return;
}
@@ -1377,7 +1396,14 @@ ndis_alloc_sharedmem_async(adapter, len, cached, ctx)
w->na_len = len;
w->na_ctx = ctx;
- ndis_sched(ndis_asyncmem_complete, w, NDIS_TASKQUEUE);
+ /*
+ * Pawn this work off on the SWI thread instead of the
+ * taskqueue thread, because sometimes drivers will queue
+ * up work items on the taskqueue thread that will block,
+ * which would prevent the memory allocation from completing
+ * when we need it.
+ */
+ ndis_sched(ndis_asyncmem_complete, w, NDIS_SWI);
return(NDIS_STATUS_PENDING);
}
@@ -1886,6 +1912,9 @@ ndis_init_event(event)
ndis_event *event;
{
event->ne_event.nk_header.dh_sigstate = FALSE;
+ event->ne_event.nk_header.dh_size = OTYPE_EVENT;
+ event->ne_event.nk_header.dh_type = EVENT_TYPE_NOTIFY;
+ INIT_LIST_HEAD((&event->ne_event.nk_header.dh_waitlisthead));
return;
}
@@ -1893,8 +1922,7 @@ __stdcall static void
ndis_set_event(event)
ndis_event *event;
{
- event->ne_event.nk_header.dh_sigstate = TRUE;
- wakeup(event);
+ ntoskrnl_wakeup(event);
return;
}
@@ -1903,10 +1931,15 @@ ndis_reset_event(event)
ndis_event *event;
{
event->ne_event.nk_header.dh_sigstate = FALSE;
- wakeup(event);
return;
}
+/*
+ * This is a stripped-down version of KeWaitForSingleObject().
+ * Maybe it ought to just call ntoskrnl_waitforobj() to reduce
+ * code duplication.
+ */
+
__stdcall static uint8_t
ndis_wait_event(event, msecs)
ndis_event *event;
@@ -1914,14 +1947,37 @@ ndis_wait_event(event, msecs)
{
int error;
struct timeval tv;
+ wait_block w;
+ struct thread *td = curthread;
- if (event->ne_event.nk_header.dh_sigstate == TRUE)
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ if (event->ne_event.nk_header.dh_sigstate == TRUE) {
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
return(TRUE);
+ }
+
+ INSERT_LIST_HEAD((&event->ne_event.nk_header.dh_waitlisthead),
+ (&w.wb_waitlist));
tv.tv_sec = 0;
tv.tv_usec = msecs * 1000;
- error = tsleep(event, PPAUSE|PCATCH, "ndis", tvtohz(&tv));
+ w.wb_kthread = td;
+ w.wb_object = &event->ne_event.nk_header;
+
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ if (td->td_proc->p_flag & P_KTHREAD)
+ error = tsleep(td, PPAUSE|PCATCH, "ndiswe", tvtohz(&tv));
+ else
+ error = kthread_suspend(td->td_proc, tvtohz(&tv));
+
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ REMOVE_LIST_ENTRY((&w.wb_waitlist));
+
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
return(event->ne_event.nk_header.dh_sigstate);
}
@@ -2164,13 +2220,13 @@ ndis_write_pccard_amem(handle, offset, buf, len)
return(i);
}
-__stdcall static ndis_list_entry *
+__stdcall static list_entry *
ndis_insert_head(head, entry, lock)
- ndis_list_entry *head;
- ndis_list_entry *entry;
+ list_entry *head;
+ list_entry *entry;
ndis_spin_lock *lock;
{
- ndis_list_entry *flink;
+ list_entry *flink;
mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock);
flink = head->nle_flink;
@@ -2183,13 +2239,13 @@ ndis_insert_head(head, entry, lock)
return(flink);
}
-__stdcall static ndis_list_entry *
+__stdcall static list_entry *
ndis_remove_head(head, lock)
- ndis_list_entry *head;
+ list_entry *head;
ndis_spin_lock *lock;
{
- ndis_list_entry *flink;
- ndis_list_entry *entry;
+ list_entry *flink;
+ list_entry *entry;
mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock);
entry = head->nle_flink;
@@ -2201,13 +2257,13 @@ ndis_remove_head(head, lock)
return(entry);
}
-__stdcall static ndis_list_entry *
+__stdcall static list_entry *
ndis_insert_tail(head, entry, lock)
- ndis_list_entry *head;
- ndis_list_entry *entry;
+ list_entry *head;
+ list_entry *entry;
ndis_spin_lock *lock;
{
- ndis_list_entry *blink;
+ list_entry *blink;
mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock);
blink = head->nle_blink;
@@ -2255,6 +2311,8 @@ ndis_time(tval)
nanotime(&ts);
*tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
11644473600;
+
+ return;
}
/*
@@ -2268,6 +2326,8 @@ ndis_uptime(tval)
nanouptime(&ts);
*tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000;
+
+ return;
}
__stdcall static void
@@ -2353,12 +2413,21 @@ ndis_init_unicode_string(dst, src)
__stdcall static void ndis_get_devprop(adapter, phydevobj,
funcdevobj, nextdevobj, resources, transresources)
ndis_handle adapter;
- void *phydevobj;
- void *funcdevobj;
- void *nextdevobj;
+ device_object **phydevobj;
+ device_object **funcdevobj;
+ device_object **nextdevobj;
cm_resource_list *resources;
cm_resource_list *transresources;
{
+ ndis_miniport_block *block;
+
+ block = (ndis_miniport_block *)adapter;
+
+ if (phydevobj != NULL)
+ *phydevobj = &block->nmb_devobj;
+ if (funcdevobj != NULL)
+ *funcdevobj = &block->nmb_devobj;
+
return;
}
@@ -2446,7 +2515,6 @@ ndis_open_file(status, filehandle, filelength, filename, highestaddr)
mtx_unlock(&Giant);
*status = NDIS_STATUS_FILE_NOT_FOUND;
free(fh, M_TEMP);
- printf("ndis_open_file(): unable to open file '%s'\n", path);
return;
}
@@ -2726,23 +2794,51 @@ ndis_pkt_to_pkt_safe(dpkt, doff, reqlen, spkt, soff, cpylen, prio)
__stdcall static ndis_status
ndis_register_dev(handle, devname, symname, majorfuncs, devobj, devhandle)
- ndis_handle *handle;
+ ndis_handle handle;
ndis_unicode_string *devname;
ndis_unicode_string *symname;
- void *majorfuncs;
- void *devobj;
- ndis_handle **devhandle;
+ driver_dispatch *majorfuncs[];
+ void **devobj;
+ ndis_handle *devhandle;
{
+ ndis_miniport_block *block;
+
+ block = (ndis_miniport_block *)handle;
+ *devobj = &block->nmb_devobj;
+ *devhandle = handle;
+
return(NDIS_STATUS_SUCCESS);
}
__stdcall static ndis_status
-ndis_deregister_dev(devhandle)
- ndis_handle *devhandle;
+ndis_deregister_dev(handle)
+ ndis_handle handle;
{
return(NDIS_STATUS_SUCCESS);
}
+__stdcall static ndis_status
+ndis_query_name(name, handle)
+ ndis_unicode_string *name;
+ ndis_handle handle;
+{
+ ndis_miniport_block *block;
+
+ block = (ndis_miniport_block *)handle;
+ ndis_ascii_to_unicode(__DECONST(char *,
+ device_get_nameunit(block->nmb_dev)), &name->nus_buf);
+ name->nus_len = strlen(device_get_nameunit(block->nmb_dev)) * 2;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+__stdcall static void
+ndis_register_unload(handle, func)
+ ndis_handle handle;
+ void *func;
+{
+ return;
+}
__stdcall static void
dummy()
@@ -2864,6 +2960,8 @@ image_patch_table ndis_functbl[] = {
{ "NdisCloseFile", (FUNC)ndis_close_file },
{ "NdisMRegisterDevice", (FUNC)ndis_register_dev },
{ "NdisMDeregisterDevice", (FUNC)ndis_deregister_dev },
+ { "NdisMQueryAdapterInstanceName", (FUNC)ndis_query_name },
+ { "NdisMRegisterUnloadHandler", (FUNC)ndis_register_unload },
/*
* This last entry is a catch-all for any function we haven't
diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c
index 0d2d738..769ac0e 100644
--- a/sys/compat/ndis/subr_ntoskrnl.c
+++ b/sys/compat/ndis/subr_ntoskrnl.c
@@ -34,6 +34,7 @@
__FBSDID("$FreeBSD$");
#include <sys/ctype.h>
+#include <sys/unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/errno.h>
@@ -44,6 +45,8 @@ __FBSDID("$FreeBSD$");
#include <sys/callout.h>
#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/kthread.h>
#include <machine/atomic.h>
#include <machine/clock.h>
@@ -58,8 +61,8 @@ __FBSDID("$FreeBSD$");
#include <compat/ndis/pe_var.h>
#include <compat/ndis/hal_var.h>
#include <compat/ndis/resource_var.h>
-#include <compat/ndis/ndis_var.h>
#include <compat/ndis/ntoskrnl_var.h>
+#include <compat/ndis/ndis_var.h>
#define __regparm __attribute__((regparm(3)))
@@ -77,9 +80,16 @@ __stdcall static void *ntoskrnl_iobuildsynchfsdreq(uint32_t, void *,
void *, uint32_t, uint32_t *, void *, void *);
__stdcall static uint32_t ntoskrnl_iofcalldriver(/*void *, void * */ void);
__stdcall static void ntoskrnl_iofcompletereq(/*void *, uint8_t*/ void);
-__stdcall static uint32_t ntoskrnl_waitforobj(void *, uint32_t,
- uint32_t, uint8_t, void *);
-__stdcall static void ntoskrnl_initevent(void *, uint32_t, uint8_t);
+__stdcall static uint32_t ntoskrnl_waitforobj(nt_dispatch_header *, uint32_t,
+ uint32_t, uint8_t, int64_t *);
+__stdcall static uint32_t ntoskrnl_waitforobjs(uint32_t,
+ nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t,
+ int64_t *, wait_block *);
+__stdcall static void ntoskrnl_init_event(nt_kevent *, uint32_t, uint8_t);
+__stdcall static void ntoskrnl_clear_event(nt_kevent *);
+__stdcall static uint32_t ntoskrnl_read_event(nt_kevent *);
+__stdcall static uint32_t ntoskrnl_set_event(nt_kevent *, uint32_t, uint8_t);
+__stdcall static uint32_t ntoskrnl_reset_event(nt_kevent *);
__stdcall static void ntoskrnl_writereg_ushort(uint16_t *, uint16_t);
__stdcall static uint16_t ntoskrnl_readreg_ushort(uint16_t *);
__stdcall static void ntoskrnl_writereg_ulong(uint32_t *, uint32_t);
@@ -120,7 +130,12 @@ __stdcall static uint32_t
__stdcall static uint32_t
ntoskrnl_interlock_dec(/*volatile uint32_t * */ void);
__stdcall static void ntoskrnl_freemdl(ndis_buffer *);
+__stdcall static uint32_t ntoskrnl_sizeofmdl(void *, size_t);
+__stdcall static void ntoskrnl_build_npaged_mdl(ndis_buffer *);
__stdcall static void *ntoskrnl_mmaplockedpages(ndis_buffer *, uint8_t);
+__stdcall static void *ntoskrnl_mmaplockedpages_cache(ndis_buffer *,
+ uint8_t, uint32_t, void *, uint32_t, uint32_t);
+__stdcall static void ntoskrnl_munmaplockedpages(void *, ndis_buffer *);
__stdcall static void ntoskrnl_init_lock(kspin_lock *);
__stdcall static size_t ntoskrnl_memcmp(const void *, const void *, size_t);
__stdcall static void ntoskrnl_init_ansi_string(ndis_ansi_string *, char *);
@@ -132,16 +147,35 @@ __stdcall static ndis_status ntoskrnl_unicode_to_int(ndis_unicode_string *,
uint32_t, uint32_t *);
static int atoi (const char *);
static long atol (const char *);
+static void ntoskrnl_time(uint64_t *);
__stdcall static uint8_t ntoskrnl_wdmver(uint8_t, uint8_t);
+static void ntoskrnl_thrfunc(void *);
+__stdcall static ndis_status ntoskrnl_create_thread(ndis_handle *,
+ uint32_t, void *, ndis_handle, void *, void *, void *);
+__stdcall static ndis_status ntoskrnl_thread_exit(ndis_status);
+__stdcall static ndis_status ntoskrnl_devprop(device_object *, uint32_t,
+ uint32_t, void *, uint32_t *);
+__stdcall static void ntoskrnl_init_mutex(kmutant *, uint32_t);
+__stdcall static uint32_t ntoskrnl_release_mutex(kmutant *, uint8_t);
+__stdcall static uint32_t ntoskrnl_read_mutex(kmutant *);
+__stdcall static ndis_status ntoskrnl_objref(ndis_handle, uint32_t, void *,
+ uint8_t, void **, void **);
+__stdcall static void ntoskrnl_objderef(/*void * */ void);
+__stdcall static uint32_t ntoskrnl_zwclose(ndis_handle);
__stdcall static void dummy(void);
static struct mtx *ntoskrnl_interlock;
+struct mtx *ntoskrnl_dispatchlock;
extern struct mtx_pool *ndis_mtxpool;
+static int ntoskrnl_kth = 0;
+static struct nt_objref_head ntoskrnl_reflist;
int
ntoskrnl_libinit()
{
ntoskrnl_interlock = mtx_pool_alloc(ndis_mtxpool);
+ ntoskrnl_dispatchlock = mtx_pool_alloc(ndis_mtxpool);
+ TAILQ_INIT(&ntoskrnl_reflist);
return(0);
}
@@ -276,24 +310,375 @@ ntoskrnl_iofcompletereq(/*irp, prioboost*/)
return;
}
+void
+ntoskrnl_wakeup(arg)
+ void *arg;
+{
+ nt_dispatch_header *obj;
+ wait_block *w;
+ list_entry *e;
+ struct thread *td;
+
+ obj = arg;
+
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ obj->dh_sigstate = TRUE;
+ e = obj->dh_waitlisthead.nle_flink;
+ while (e != &obj->dh_waitlisthead) {
+ w = (wait_block *)e;
+ td = w->wb_kthread;
+ if (td->td_proc->p_flag & P_KTHREAD)
+ kthread_resume(td->td_proc);
+ else
+ wakeup(td);
+ /*
+ * For synchronization objects, only wake up
+ * the first waiter.
+ */
+ if (obj->dh_type == EVENT_TYPE_SYNC)
+ break;
+ e = e->nle_flink;
+ }
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ return;
+}
+
+static void
+ntoskrnl_time(tval)
+ uint64_t *tval;
+{
+ struct timespec ts;
+
+ nanotime(&ts);
+ *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
+ 11644473600;
+
+ return;
+}
+
+/*
+ * KeWaitForSingleObject() is a tricky beast, because it can be used
+ * with several different object types: semaphores, timers, events,
+ * mutexes and threads. Semaphores don't appear very often, but the
+ * other object types are quite common. KeWaitForSingleObject() is
+ * what's normally used to acquire a mutex, and it can be used to
+ * wait for a thread termination.
+ *
+ * The Windows NDIS API is implemented in terms of Windows kernel
+ * primitives, and some of the object manipulation is duplicated in
+ * NDIS. For example, NDIS has timers and events, which are actually
+ * Windows kevents and ktimers. Now, you're supposed to only use the
+ * NDIS variants of these objects within the confines of the NDIS API,
+ * but there are some naughty developers out there who will use
+ * KeWaitForSingleObject() on NDIS timer and event objects, so we
+ * have to support that as well. Conseqently, our NDIS timer and event
+ * code has to be closely tied into our ntoskrnl timer and event code,
+ * just as it is in Windows.
+ *
+ * KeWaitForSingleObject() may do different things for different kinds
+ * of objects:
+ *
+ * - For events, we check if the event has been signalled. If the
+ * event is already in the signalled state, we just return immediately,
+ * otherwise we wait for it to be set to the signalled state by someone
+ * else calling KeSetEvent(). Events can be either synchronization or
+ * notification events.
+ *
+ * - For timers, if the timer has already fired and the timer is in
+ * the signalled state, we just return, otherwise we wait on the
+ * timer. Unlike an event, timers get signalled automatically when
+ * they expire rather than someone having to trip them manually.
+ * Timers initialized with KeInitializeTimer() are always notification
+ * events: KeInitializeTimerEx() lets you initialize a timer as
+ * either a notification or synchronization event.
+ *
+ * - For mutexes, we try to acquire the mutex and if we can't, we wait
+ * on the mutex until it's available and then grab it. When a mutex is
+ * released, it enters the signaled state, which wakes up one of the
+ * threads waiting to acquire it. Mutexes are always synchronization
+ * events.
+ *
+ * - For threads, the only thing we do is wait until the thread object
+ * enters a signalled state, which occurs when the thread terminates.
+ * Threads are always notification events.
+ *
+ * A notification event wakes up all threads waiting on an object. A
+ * synchronization event wakes up just one. Also, a synchronization event
+ * is auto-clearing, which means we automatically set the event back to
+ * the non-signalled state once the wakeup is done.
+ *
+ * The problem with KeWaitForSingleObject() is that it can be called
+ * either from the main kernel 'process' or from a kthread. When sleeping
+ * inside a kernel thread, we need to use kthread_resume(), but that
+ * won't work in the kernel context proper. So if kthread_resume() returns
+ * EINVAL, we need to use tsleep() instead.
+ */
+
__stdcall static uint32_t
ntoskrnl_waitforobj(obj, reason, mode, alertable, timeout)
- void *obj;
+ nt_dispatch_header *obj;
uint32_t reason;
uint32_t mode;
uint8_t alertable;
- void *timeout;
+ int64_t *timeout;
{
- return(0);
+ struct thread *td = curthread;
+ kmutant *km;
+ wait_block w;
+ struct timeval tv;
+ int error = 0;
+ uint64_t curtime;
+
+ if (obj == NULL)
+ return(STATUS_INVALID_PARAMETER);
+
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ /*
+ * See if the object is a mutex. If so, and we already own
+ * it, then just increment the acquisition count and return.
+ *
+ * For any other kind of object, see if it's already in the
+ * signalled state, and if it is, just return. If the object
+ * is marked as a synchronization event, reset the state to
+ * unsignalled.
+ */
+
+ if (obj->dh_size == OTYPE_MUTEX) {
+ km = (kmutant *)obj;
+ if (km->km_ownerthread == NULL ||
+ km->km_ownerthread == curthread->td_proc) {
+ obj->dh_sigstate = FALSE;
+ km->km_acquirecnt++;
+ km->km_ownerthread = curthread->td_proc;
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ return (STATUS_SUCCESS);
+ }
+ } else if (obj->dh_sigstate == TRUE) {
+ if (obj->dh_type == EVENT_TYPE_SYNC)
+ obj->dh_sigstate = FALSE;
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ return (STATUS_SUCCESS);
+ }
+
+ w.wb_object = obj;
+ w.wb_kthread = td;
+
+ INSERT_LIST_HEAD((&obj->dh_waitlisthead), (&w.wb_waitlist));
+
+ /*
+ * The timeout value is specified in 100 nanosecond units
+ * and can be a positive or negative number. If it's positive,
+ * then the timeout is absolute, and we need to convert it
+ * to an absolute offset relative to now in order to use it.
+ * If it's negative, then the timeout is relative and we
+ * just have to convert the units.
+ */
+
+ if (timeout != NULL) {
+ if (*timeout < 0) {
+ tv.tv_sec = - (*timeout) / 10000000 ;
+ tv.tv_usec = (- (*timeout) / 10) -
+ (tv.tv_sec * 1000000);
+ } else {
+ ntoskrnl_time(&curtime);
+ tv.tv_sec = ((*timeout) - curtime) / 10000000 ;
+ tv.tv_usec = ((*timeout) - curtime) / 10 -
+ (tv.tv_sec * 1000000);
+ }
+ }
+
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ if (td->td_proc->p_flag & P_KTHREAD)
+ error = kthread_suspend(td->td_proc,
+ timeout == NULL ? 0 : tvtohz(&tv));
+ else
+ error = tsleep(td, PPAUSE|PDROP, "ndisws",
+ timeout == NULL ? 0 : tvtohz(&tv));
+
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ /* We timed out. Leave the object alone and return status. */
+
+ if (error == EWOULDBLOCK) {
+ REMOVE_LIST_ENTRY((&w.wb_waitlist));
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ return(STATUS_TIMEOUT);
+ }
+
+ /*
+ * Mutexes are always synchronization objects, which means
+ * if several threads are waiting to acquire it, only one will
+ * be woken up. If that one is us, and the mutex is up for grabs,
+ * grab it.
+ */
+
+ if (obj->dh_size == OTYPE_MUTEX) {
+ km = (kmutant *)obj;
+ if (km->km_ownerthread == NULL) {
+ km->km_ownerthread = curthread->td_proc;
+ km->km_acquirecnt++;
+ }
+ }
+
+ if (obj->dh_type == EVENT_TYPE_SYNC)
+ obj->dh_sigstate = FALSE;
+ REMOVE_LIST_ENTRY((&w.wb_waitlist));
+
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ return(STATUS_SUCCESS);
}
-__stdcall static void
-ntoskrnl_initevent(event, type, state)
- void *event;
- uint32_t type;
- uint8_t state;
+__stdcall static uint32_t
+ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode,
+ alertable, timeout, wb_array)
+ uint32_t cnt;
+ nt_dispatch_header *obj[];
+ uint32_t wtype;
+ uint32_t reason;
+ uint32_t mode;
+ uint8_t alertable;
+ int64_t *timeout;
+ wait_block *wb_array;
{
- return;
+ struct thread *td = curthread;
+ kmutant *km;
+ wait_block _wb_array[THREAD_WAIT_OBJECTS];
+ wait_block *w;
+ struct timeval tv;
+ int i, wcnt = 0, widx = 0, error = 0;
+ uint64_t curtime;
+ struct timespec t1, t2;
+
+ if (cnt > MAX_WAIT_OBJECTS)
+ return(STATUS_INVALID_PARAMETER);
+ if (cnt > THREAD_WAIT_OBJECTS && wb_array == NULL)
+ return(STATUS_INVALID_PARAMETER);
+
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ if (wb_array == NULL)
+ w = &_wb_array[0];
+ else
+ w = wb_array;
+
+ /* First pass: see if we can satisfy any waits immediately. */
+
+ for (i = 0; i < cnt; i++) {
+ if (obj[i]->dh_size == OTYPE_MUTEX) {
+ km = (kmutant *)obj[i];
+ if (km->km_ownerthread == NULL ||
+ km->km_ownerthread == curthread->td_proc) {
+ obj[i]->dh_sigstate = FALSE;
+ km->km_acquirecnt++;
+ km->km_ownerthread = curthread->td_proc;
+ if (wtype == WAITTYPE_ANY) {
+ mtx_pool_unlock(ndis_mtxpool,
+ ntoskrnl_dispatchlock);
+ return (STATUS_WAIT_0 + i);
+ }
+ }
+ } else if (obj[i]->dh_sigstate == TRUE) {
+ if (obj[i]->dh_type == EVENT_TYPE_SYNC)
+ obj[i]->dh_sigstate = FALSE;
+ if (wtype == WAITTYPE_ANY) {
+ mtx_pool_unlock(ndis_mtxpool,
+ ntoskrnl_dispatchlock);
+ return (STATUS_WAIT_0 + i);
+ }
+ }
+ }
+
+ /*
+ * Second pass: set up wait for anything we can't
+ * satisfy immediately.
+ */
+
+ for (i = 0; i < cnt; i++) {
+ if (obj[i]->dh_sigstate == TRUE)
+ continue;
+ INSERT_LIST_HEAD((&obj[i]->dh_waitlisthead),
+ (&w[i].wb_waitlist));
+ w[i].wb_kthread = td;
+ w[i].wb_object = obj[i];
+ wcnt++;
+ }
+
+ if (timeout != NULL) {
+ if (*timeout < 0) {
+ tv.tv_sec = - (*timeout) / 10000000 ;
+ tv.tv_usec = (- (*timeout) / 10) -
+ (tv.tv_sec * 1000000);
+ } else {
+ ntoskrnl_time(&curtime);
+ tv.tv_sec = ((*timeout) - curtime) / 10000000 ;
+ tv.tv_usec = ((*timeout) - curtime) / 10 -
+ (tv.tv_sec * 1000000);
+ }
+ }
+
+ while (wcnt) {
+ nanotime(&t1);
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ if (td->td_proc->p_flag & P_KTHREAD)
+ error = kthread_suspend(td->td_proc,
+ timeout == NULL ? 0 : tvtohz(&tv));
+ else
+ error = tsleep(td, PPAUSE|PCATCH, "ndisws",
+ timeout == NULL ? 0 : tvtohz(&tv));
+
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ nanotime(&t2);
+
+ for (i = 0; i < cnt; i++) {
+ if (obj[i]->dh_size == OTYPE_MUTEX) {
+ km = (kmutant *)obj;
+ if (km->km_ownerthread == NULL) {
+ km->km_ownerthread =
+ curthread->td_proc;
+ km->km_acquirecnt++;
+ }
+ }
+ if (obj[i]->dh_sigstate == TRUE) {
+ widx = i;
+ if (obj[i]->dh_type == EVENT_TYPE_SYNC)
+ obj[i]->dh_sigstate = FALSE;
+ REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
+ wcnt--;
+ }
+ }
+
+ if (error || wtype == WAITTYPE_ANY)
+ break;
+
+ if (*timeout != NULL) {
+ tv.tv_sec -= (t2.tv_sec - t1.tv_sec);
+ tv.tv_usec -= (t2.tv_nsec - t1.tv_nsec) / 1000;
+ }
+ }
+
+ if (wcnt) {
+ for (i = 0; i < cnt; i++)
+ REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
+ }
+
+ if (error == EWOULDBLOCK) {
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ return(STATUS_TIMEOUT);
+ }
+
+ if (wtype == WAITTYPE_ANY && wcnt) {
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ return(STATUS_WAIT_0 + widx);
+ }
+
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ return(STATUS_SUCCESS);
}
__stdcall static void
@@ -658,6 +1043,27 @@ ntoskrnl_freemdl(mdl)
return;
}
+__stdcall static uint32_t
+ntoskrnl_sizeofmdl(vaddr, len)
+ void *vaddr;
+ size_t len;
+{
+ uint32_t l;
+
+ l = sizeof(struct ndis_buffer) +
+ (sizeof(uint32_t) * SPAN_PAGES(vaddr, len));
+
+ return(l);
+}
+
+__stdcall static void
+ntoskrnl_build_npaged_mdl(mdl)
+ ndis_buffer *mdl;
+{
+ mdl->nb_mappedsystemva = (char *)mdl->nb_startva + mdl->nb_byteoffset;
+ return;
+}
+
__stdcall static void *
ntoskrnl_mmaplockedpages(buf, accessmode)
ndis_buffer *buf;
@@ -666,6 +1072,27 @@ ntoskrnl_mmaplockedpages(buf, accessmode)
return(MDL_VA(buf));
}
+__stdcall static void *
+ntoskrnl_mmaplockedpages_cache(buf, accessmode, cachetype, vaddr,
+ bugcheck, prio)
+ ndis_buffer *buf;
+ uint8_t accessmode;
+ uint32_t cachetype;
+ void *vaddr;
+ uint32_t bugcheck;
+ uint32_t prio;
+{
+ return(MDL_VA(buf));
+}
+
+__stdcall static void
+ntoskrnl_munmaplockedpages(vaddr, buf)
+ void *vaddr;
+ ndis_buffer *buf;
+{
+ return;
+}
+
/*
* The KeInitializeSpinLock(), KefAcquireSpinLockAtDpcLevel()
* and KefReleaseSpinLockFromDpcLevel() appear to be analagous
@@ -847,6 +1274,263 @@ ntoskrnl_wdmver(major, minor)
return(FALSE);
}
+__stdcall static ndis_status
+ntoskrnl_devprop(devobj, regprop, buflen, prop, reslen)
+ device_object *devobj;
+ uint32_t regprop;
+ uint32_t buflen;
+ void *prop;
+ uint32_t *reslen;
+{
+ ndis_miniport_block *block;
+
+ block = devobj->do_rsvd;
+
+ switch (regprop) {
+ case DEVPROP_DRIVER_KEYNAME:
+ ndis_ascii_to_unicode(__DECONST(char *,
+ device_get_nameunit(block->nmb_dev)), (uint16_t **)&prop);
+ *reslen = strlen(device_get_nameunit(block->nmb_dev)) * 2;
+ break;
+ default:
+ return(STATUS_INVALID_PARAMETER_2);
+ break;
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+__stdcall static void
+ntoskrnl_init_mutex(kmutex, level)
+ kmutant *kmutex;
+ uint32_t level;
+{
+ INIT_LIST_HEAD((&kmutex->km_header.dh_waitlisthead));
+ kmutex->km_abandoned = FALSE;
+ kmutex->km_apcdisable = 1;
+ kmutex->km_header.dh_sigstate = TRUE;
+ kmutex->km_header.dh_type = EVENT_TYPE_SYNC;
+ kmutex->km_header.dh_size = OTYPE_MUTEX;
+ kmutex->km_acquirecnt = 0;
+ kmutex->km_ownerthread = NULL;
+ return;
+}
+
+__stdcall static uint32_t
+ntoskrnl_release_mutex(kmutex, kwait)
+ kmutant *kmutex;
+ uint8_t kwait;
+{
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ if (kmutex->km_ownerthread != curthread->td_proc) {
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ return(STATUS_MUTANT_NOT_OWNED);
+ }
+ kmutex->km_acquirecnt--;
+ if (kmutex->km_acquirecnt == 0) {
+ kmutex->km_ownerthread = NULL;
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ ntoskrnl_wakeup(&kmutex->km_header);
+ } else
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ return(kmutex->km_acquirecnt);
+}
+
+__stdcall static uint32_t
+ntoskrnl_read_mutex(kmutex)
+ kmutant *kmutex;
+{
+ return(kmutex->km_header.dh_sigstate);
+}
+
+__stdcall static void
+ntoskrnl_init_event(kevent, type, state)
+ nt_kevent *kevent;
+ uint32_t type;
+ uint8_t state;
+{
+ INIT_LIST_HEAD((&kevent->k_header.dh_waitlisthead));
+ kevent->k_header.dh_sigstate = state;
+ kevent->k_header.dh_type = type;
+ kevent->k_header.dh_size = OTYPE_EVENT;
+ return;
+}
+
+__stdcall static uint32_t
+ntoskrnl_reset_event(kevent)
+ nt_kevent *kevent;
+{
+ uint32_t prevstate;
+
+ mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
+ prevstate = kevent->k_header.dh_sigstate;
+ kevent->k_header.dh_sigstate = FALSE;
+ mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
+
+ return(prevstate);
+}
+
+__stdcall static uint32_t
+ntoskrnl_set_event(kevent, increment, kwait)
+ nt_kevent *kevent;
+ uint32_t increment;
+ uint8_t kwait;
+{
+ uint32_t prevstate;
+
+ prevstate = kevent->k_header.dh_sigstate;
+ ntoskrnl_wakeup(&kevent->k_header);
+
+ return(prevstate);
+}
+
+__stdcall static void
+ntoskrnl_clear_event(kevent)
+ nt_kevent *kevent;
+{
+ kevent->k_header.dh_sigstate = FALSE;
+ return;
+}
+
+__stdcall static uint32_t
+ntoskrnl_read_event(kevent)
+ nt_kevent *kevent;
+{
+ return(kevent->k_header.dh_sigstate);
+}
+
+__stdcall static ndis_status
+ntoskrnl_objref(handle, reqaccess, otype, accessmode, object, handleinfo)
+ ndis_handle handle;
+ uint32_t reqaccess;
+ void *otype;
+ uint8_t accessmode;
+ void **object;
+ void **handleinfo;
+{
+ nt_objref *nr;
+
+ nr = malloc(sizeof(nt_objref), M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (nr == NULL)
+ return(NDIS_STATUS_FAILURE);
+
+ INIT_LIST_HEAD((&nr->no_dh.dh_waitlisthead));
+ nr->no_obj = handle;
+ nr->no_dh.dh_size = OTYPE_THREAD;
+ TAILQ_INSERT_TAIL(&ntoskrnl_reflist, nr, link);
+ *object = nr;
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+__stdcall static void
+ntoskrnl_objderef(/*object*/void)
+{
+ void *object;
+ nt_objref *nr;
+
+ __asm__ __volatile__ ("" : "=c" (object));
+
+ nr = object;
+ TAILQ_REMOVE(&ntoskrnl_reflist, nr, link);
+ free(nr, M_DEVBUF);
+
+ return;
+}
+
+__stdcall static uint32_t
+ntoskrnl_zwclose(handle)
+ ndis_handle handle;
+{
+ return(STATUS_SUCCESS);
+}
+
+/*
+ * This is here just in case the thread returns without calling
+ * PsTerminateSystemThread().
+ */
+static void
+ntoskrnl_thrfunc(arg)
+ void *arg;
+{
+ thread_context *thrctx;
+ __stdcall uint32_t (*tfunc)(void *);
+ void *tctx;
+ uint32_t rval;
+
+ thrctx = arg;
+ tfunc = thrctx->tc_thrfunc;
+ tctx = thrctx->tc_thrctx;
+ free(thrctx, M_TEMP);
+
+ rval = tfunc(tctx);
+
+ ntoskrnl_thread_exit(rval);
+ return; /* notreached */
+}
+
+__stdcall static ndis_status
+ntoskrnl_create_thread(handle, reqaccess, objattrs, phandle,
+ clientid, thrfunc, thrctx)
+ ndis_handle *handle;
+ uint32_t reqaccess;
+ void *objattrs;
+ ndis_handle phandle;
+ void *clientid;
+ void *thrfunc;
+ void *thrctx;
+{
+ int error;
+ char tname[128];
+ thread_context *tc;
+ struct proc *p;
+
+ tc = malloc(sizeof(thread_context), M_TEMP, M_NOWAIT);
+ if (tc == NULL)
+ return(NDIS_STATUS_FAILURE);
+
+ tc->tc_thrctx = thrctx;
+ tc->tc_thrfunc = thrfunc;
+
+ sprintf(tname, "windows kthread %d", ntoskrnl_kth);
+ error = kthread_create(ntoskrnl_thrfunc, tc, &p,
+ RFHIGHPID, 0, tname);
+ *handle = p;
+
+ ntoskrnl_kth++;
+
+ return(error);
+}
+
+/*
+ * In Windows, the exit of a thread is an event that you're allowed
+ * to wait on, assuming you've obtained a reference to the thread using
+ * ObReferenceObjectByHandle(). Unfortunately, the only way we can
+ * simulate this behavior is to register each thread we create in a
+ * reference list, and if someone holds a reference to us, we poke
+ * them.
+ */
+__stdcall static ndis_status
+ntoskrnl_thread_exit(status)
+ ndis_status status;
+{
+ struct nt_objref *nr;
+
+ TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) {
+ if (nr->no_obj != curthread->td_proc)
+ continue;
+ ntoskrnl_wakeup(&nr->no_dh);
+ break;
+ }
+
+ ntoskrnl_kth--;
+
+ mtx_lock(&Giant);
+ kthread_exit(0);
+ return(0); /* notreached */
+}
+
__stdcall static void
dummy()
{
@@ -880,7 +1564,7 @@ image_patch_table ntoskrnl_functbl[] = {
{ "IofCompleteRequest", (FUNC)ntoskrnl_iofcompletereq },
{ "IoBuildSynchronousFsdRequest", (FUNC)ntoskrnl_iobuildsynchfsdreq },
{ "KeWaitForSingleObject", (FUNC)ntoskrnl_waitforobj },
- { "KeInitializeEvent", (FUNC)ntoskrnl_initevent },
+ { "KeWaitForMultipleObjects", (FUNC)ntoskrnl_waitforobjs },
{ "_allmul", (FUNC)_allmul },
{ "_alldiv", (FUNC)_alldiv },
{ "_allrem", (FUNC)_allrem },
@@ -912,9 +1596,37 @@ image_patch_table ntoskrnl_functbl[] = {
{ "InterlockedIncrement", (FUNC)ntoskrnl_interlock_inc },
{ "InterlockedDecrement", (FUNC)ntoskrnl_interlock_dec },
{ "IoFreeMdl", (FUNC)ntoskrnl_freemdl },
+ { "MmSizeOfMdl", (FUNC)ntoskrnl_sizeofmdl },
{ "MmMapLockedPages", (FUNC)ntoskrnl_mmaplockedpages },
+ { "MmMapLockedPagesSpecifyCache",
+ (FUNC)ntoskrnl_mmaplockedpages_cache },
+ { "MmUnmapLockedPages", (FUNC)ntoskrnl_munmaplockedpages },
+ { "MmBuildMdlForNonPagedPool", (FUNC)ntoskrnl_build_npaged_mdl },
{ "KeInitializeSpinLock", (FUNC)ntoskrnl_init_lock },
{ "IoIsWdmVersionAvailable", (FUNC)ntoskrnl_wdmver },
+ { "IoGetDeviceProperty", (FUNC)ntoskrnl_devprop },
+ { "KeInitializeMutex", (FUNC)ntoskrnl_init_mutex },
+ { "KeReleaseMutex", (FUNC)ntoskrnl_release_mutex },
+ { "KeReadStateMutex", (FUNC)ntoskrnl_read_mutex },
+ { "KeInitializeEvent", (FUNC)ntoskrnl_init_event },
+ { "KeSetEvent", (FUNC)ntoskrnl_set_event },
+ { "KeResetEvent", (FUNC)ntoskrnl_reset_event },
+ { "KeClearEvent", (FUNC)ntoskrnl_clear_event },
+ { "KeReadStateEvent", (FUNC)ntoskrnl_read_event },
+#ifdef notyet
+ { "KeInitializeTimer",
+ { "KeInitializeTimerEx",
+ { "KeCancelTimer",
+ { "KeSetTimer",
+ { "KeSetTimerEx",
+ { "KeReadStateTimer",
+ { "KeInitializeDpc",
+#endif
+ { "ObReferenceObjectByHandle", (FUNC)ntoskrnl_objref },
+ { "ObfDereferenceObject", (FUNC)ntoskrnl_objderef },
+ { "ZwClose", (FUNC)ntoskrnl_zwclose },
+ { "PsCreateSystemThread", (FUNC)ntoskrnl_create_thread },
+ { "PsTerminateSystemThread", (FUNC)ntoskrnl_thread_exit },
/*
* This last entry is a catch-all for any function we haven't
OpenPOWER on IntegriCloud