diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/compat/ndis/kern_ndis.c | 39 | ||||
-rw-r--r-- | sys/compat/ndis/ndis_var.h | 15 | ||||
-rw-r--r-- | sys/compat/ndis/ntoskrnl_var.h | 287 | ||||
-rw-r--r-- | sys/compat/ndis/subr_hal.c | 14 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ndis.c | 218 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ntoskrnl.c | 740 |
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 |