Add a whole bunch of new stuff to make the driver for the AMD Am1771/Am1772

802.11b chipset work. This chip is present on the SMC2602W version 3
NIC, which is what was used for testing. This driver creates kernel
threads (12 of them!) for various purposes, and required the following
routines:

PsCreateSystemThread()
PsTerminateSystemThread()
KeInitializeEvent()
KeSetEvent()
KeResetEvent()
KeInitializeMutex()
KeReleaseMutex()
KeWaitForSingleObject()
KeWaitForMultipleObjects()
IoGetDeviceProperty()

and several more. Also, this driver abuses the fact that NDIS events
and timers are actually Windows events and timers, and uses NDIS events
with KeWaitForSingleObject(). The NDIS event routines have been rewritten
to interface with the ntoskrnl module. Many routines with incorrect
prototypes have been cleaned up.

Also, this driver puts jobs on the NDIS taskqueue (via NdisScheduleWorkItem())
which block on events, and this interferes with the operation of
NdisMAllocateSharedMemoryAsync(), which was also being put on the
NDIS taskqueue. To avoid the deadlock, NdisMAllocateSharedMemoryAsync()
is now performed in the NDIS SWI thread instead.

There's still room for some cleanups here, and I really should implement
KeInitializeTimer() and friends.
This commit is contained in:
Bill Paul 2004-02-07 06:44:13 +00:00
parent 1e6466b61e
commit 9ec5585585
6 changed files with 1212 additions and 101 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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_ */

View File

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

View File

@ -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(handle)
ndis_handle handle;
{
return(NDIS_STATUS_SUCCESS);
}
__stdcall static ndis_status
ndis_deregister_dev(devhandle)
ndis_handle *devhandle;
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

View File

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