diff options
author | Bill Paul <wpaul@FreeBSD.org> | 2005-03-31 04:24:36 +0000 |
---|---|---|
committer | Bill Paul <wpaul@FreeBSD.org> | 2005-03-31 04:24:36 +0000 |
commit | d7ff03e4305179f2c13b822008e76b58661fa732 (patch) | |
tree | d43a34518774bb6f0a7a4719a077116838c2bc17 /sys/compat | |
parent | 61f79baa158601a67920814b3c333750f9eb0291 (diff) |
Notes
Diffstat (limited to 'sys/compat')
-rw-r--r-- | sys/compat/ndis/kern_ndis.c | 240 | ||||
-rw-r--r-- | sys/compat/ndis/kern_windrv.c | 59 | ||||
-rw-r--r-- | sys/compat/ndis/ndis_var.h | 56 | ||||
-rw-r--r-- | sys/compat/ndis/ntoskrnl_var.h | 113 | ||||
-rw-r--r-- | sys/compat/ndis/subr_hal.c | 8 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ndis.c | 188 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ntoskrnl.c | 429 | ||||
-rw-r--r-- | sys/compat/ndis/subr_pe.c | 6 |
8 files changed, 889 insertions, 210 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c index 589742badc60c..3c512cc1620f1 100644 --- a/sys/compat/ndis/kern_ndis.c +++ b/sys/compat/ndis/kern_ndis.c @@ -56,8 +56,6 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <sys/rman.h> -#include <vm/uma.h> - #include <net/if.h> #include <net/if_arp.h> #include <net/ethernet.h> @@ -73,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include <compat/ndis/ndis_var.h> #include <compat/ndis/hal_var.h> #include <compat/ndis/cfg_var.h> +#include <compat/ndis/usbd_var.h> #include <dev/if_ndis/if_ndisvar.h> #define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" @@ -84,6 +83,8 @@ __stdcall static void ndis_setdone_func(ndis_handle, ndis_status); __stdcall static void ndis_getdone_func(ndis_handle, ndis_status); __stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); __stdcall static void ndis_sendrsrcavail_func(ndis_handle); +__stdcall static void ndis_intrhand(kdpc *, device_object *, + irp *, struct ndis_softc *); static image_patch_table kernndis_functbl[] = { IMPORT_FUNC(ndis_status_func), @@ -119,9 +120,8 @@ static int ndis_enlarge_thrqueue(int); static int ndis_shrink_thrqueue(int); static void ndis_runq(void *); -static uma_zone_t ndis_buffer_zone; -struct mtx ndis_thr_mtx; -struct mtx ndis_req_mtx; +static struct mtx ndis_thr_mtx; +static struct mtx ndis_req_mtx; static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo; static struct ndisqhead ndis_itodo; static struct ndisqhead ndis_free; @@ -150,6 +150,7 @@ ndis_modevent(module_t mod, int cmd, void *arg) hal_libinit(); ndis_libinit(); ntoskrnl_libinit(); + usbd_libinit(); patch = kernndis_functbl; while (patch->ipt_func != NULL) { @@ -158,11 +159,6 @@ ndis_modevent(module_t mod, int cmd, void *arg) patch++; } - /* Initialize TX buffer UMA zone. */ - ndis_buffer_zone = uma_zcreate("NDIS buffer", - sizeof(struct mdl) + (sizeof(vm_offset_t *) * 16), - NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - ndis_create_kthreads(); TAILQ_INIT(&ndis_devhead); @@ -176,6 +172,7 @@ ndis_modevent(module_t mod, int cmd, void *arg) hal_libfini(); ndis_libfini(); ntoskrnl_libfini(); + usbd_libfini(); windrv_libfini(); patch = kernndis_functbl; @@ -183,9 +180,6 @@ ndis_modevent(module_t mod, int cmd, void *arg) windrv_unwrap(patch->ipt_wrap); patch++; } - - /* Remove zones */ - uma_zdestroy(ndis_buffer_zone); } break; case MOD_UNLOAD: @@ -196,6 +190,7 @@ ndis_modevent(module_t mod, int cmd, void *arg) hal_libfini(); ndis_libfini(); ntoskrnl_libfini(); + usbd_libfini(); windrv_libfini(); patch = kernndis_functbl; @@ -204,8 +199,6 @@ ndis_modevent(module_t mod, int cmd, void *arg) patch++; } - /* Remove zones */ - uma_zdestroy(ndis_buffer_zone); break; default: error = EINVAL; @@ -244,23 +237,23 @@ ndis_runq(arg) while (1) { /* Sleep, but preserve our original priority. */ - ndis_thsuspend(p->np_p, 0); + ndis_thsuspend(p->np_p, NULL, 0); /* Look for any jobs on the work queue. */ - mtx_lock(&ndis_thr_mtx); + mtx_lock_spin(&ndis_thr_mtx); p->np_state = NDIS_PSTATE_RUNNING; while(STAILQ_FIRST(p->np_q) != NULL) { r = STAILQ_FIRST(p->np_q); STAILQ_REMOVE_HEAD(p->np_q, link); - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); /* Do the work. */ if (r->nr_func != NULL) (*r->nr_func)(r->nr_arg); - mtx_lock(&ndis_thr_mtx); + mtx_lock_spin(&ndis_thr_mtx); STAILQ_INSERT_HEAD(&ndis_free, r, link); /* Check for a shutdown request */ @@ -269,7 +262,7 @@ ndis_runq(arg) die = r; } p->np_state = NDIS_PSTATE_SLEEPING; - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); /* Bail if we were told to shut down. */ @@ -291,10 +284,8 @@ ndis_create_kthreads() struct ndis_req *r; int i, error = 0; - mtx_init(&ndis_thr_mtx, "NDIS thread lock", - MTX_NDIS_LOCK, MTX_DEF); - mtx_init(&ndis_req_mtx, "NDIS request lock", - MTX_NDIS_LOCK, MTX_DEF); + mtx_init(&ndis_thr_mtx, "NDIS thread lock", NULL, MTX_SPIN); + mtx_init(&ndis_req_mtx, "NDIS request lock", MTX_NDIS_LOCK, MTX_DEF); STAILQ_INIT(&ndis_ttodo); STAILQ_INIT(&ndis_itodo); @@ -377,14 +368,14 @@ ndis_stop_thread(t) /* Create and post a special 'exit' job. */ - mtx_lock(&ndis_thr_mtx); + mtx_lock_spin(&ndis_thr_mtx); r = STAILQ_FIRST(&ndis_free); STAILQ_REMOVE_HEAD(&ndis_free, link); r->nr_func = NULL; r->nr_arg = NULL; r->nr_exit = TRUE; STAILQ_INSERT_TAIL(q, r, link); - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); ndis_thresume(p); @@ -394,12 +385,12 @@ ndis_stop_thread(t) /* Now empty the job list. */ - mtx_lock(&ndis_thr_mtx); + mtx_lock_spin(&ndis_thr_mtx); while ((r = STAILQ_FIRST(q)) != NULL) { STAILQ_REMOVE_HEAD(q, link); STAILQ_INSERT_HEAD(&ndis_free, r, link); } - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); return; } @@ -415,10 +406,10 @@ ndis_enlarge_thrqueue(cnt) r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); if (r == NULL) return(ENOMEM); - mtx_lock(&ndis_thr_mtx); + mtx_lock_spin(&ndis_thr_mtx); STAILQ_INSERT_HEAD(&ndis_free, r, link); ndis_jobs++; - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); } return(0); @@ -432,15 +423,15 @@ ndis_shrink_thrqueue(cnt) int i; for (i = 0; i < cnt; i++) { - mtx_lock(&ndis_thr_mtx); + mtx_lock_spin(&ndis_thr_mtx); r = STAILQ_FIRST(&ndis_free); if (r == NULL) { - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); return(ENOMEM); } STAILQ_REMOVE_HEAD(&ndis_free, link); ndis_jobs--; - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); free(r, M_DEVBUF); } @@ -465,17 +456,17 @@ ndis_unsched(func, arg, t) p = ndis_iproc.np_p; } - mtx_lock(&ndis_thr_mtx); + mtx_lock_spin(&ndis_thr_mtx); STAILQ_FOREACH(r, q, link) { if (r->nr_func == func && r->nr_arg == arg) { STAILQ_REMOVE(q, r, ndis_req, link); STAILQ_INSERT_HEAD(&ndis_free, r, link); - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); return(0); } } - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); return(ENOENT); } @@ -499,20 +490,20 @@ ndis_sched(func, arg, t) p = ndis_iproc.np_p; } - mtx_lock(&ndis_thr_mtx); + mtx_lock_spin(&ndis_thr_mtx); /* * Check to see if an instance of this job is already * pending. If so, don't bother queuing it again. */ STAILQ_FOREACH(r, q, link) { if (r->nr_func == func && r->nr_arg == arg) { - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); return(0); } } r = STAILQ_FIRST(&ndis_free); if (r == NULL) { - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); return(EAGAIN); } STAILQ_REMOVE_HEAD(&ndis_free, link); @@ -524,7 +515,7 @@ ndis_sched(func, arg, t) s = ndis_tproc.np_state; else s = ndis_iproc.np_state; - mtx_unlock(&ndis_thr_mtx); + mtx_unlock_spin(&ndis_thr_mtx); /* * Post the job, but only if the thread is actually blocked @@ -540,15 +531,22 @@ ndis_sched(func, arg, t) } int -ndis_thsuspend(p, timo) +ndis_thsuspend(p, m, timo) struct proc *p; + struct mtx *m; int timo; { int error; - PROC_LOCK(p); - error = msleep(&p->p_siglist, &p->p_mtx, - curthread->td_priority|PDROP, "ndissp", timo); + if (m != NULL) { + error = msleep(&p->p_siglist, m, + curthread->td_priority, "ndissp", timo); + } else { + PROC_LOCK(p); + error = msleep(&p->p_siglist, &p->p_mtx, + curthread->td_priority|PDROP, "ndissp", timo); + } + return(error); } @@ -644,7 +642,7 @@ ndis_resetdone_func(adapter, status, addressingreset) if (ifp->if_flags & IFF_DEBUG) device_printf (sc->ndis_dev, "reset done...\n"); - wakeup(ifp); + wakeup(sc); return; } @@ -832,9 +830,10 @@ ndis_return(arg) return; returnfunc = sc->ndis_chars->nmc_return_packet_func; - irql = KeRaiseIrql(DISPATCH_LEVEL); + + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); MSCALL2(returnfunc, adapter, p); - KeLowerIrql(irql); + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); return; } @@ -858,7 +857,7 @@ ndis_return_packet(buf, arg) if (p->np_refcnt) return; - ndis_sched(ndis_return, p, NDIS_SWI); + ndis_sched(ndis_return, p, NDIS_TASKQUEUE); return; } @@ -874,13 +873,13 @@ ndis_free_bufs(b0) while(b0 != NULL) { next = b0->mdl_next; - uma_zfree (ndis_buffer_zone, b0); + IoFreeMdl(b0); b0 = next; } return; } - +int in_reset = 0; void ndis_free_packet(p) ndis_packet *p; @@ -890,7 +889,6 @@ ndis_free_packet(p) ndis_free_bufs(p->np_private.npp_head); NdisFreePacket(p); - return; } @@ -904,15 +902,20 @@ ndis_convert_res(arg) ndis_miniport_block *block; device_t dev; struct resource_list *brl; + struct resource_list_entry *brle; +#if __FreeBSD_version < 600022 struct resource_list brl_rev; - struct resource_list_entry *brle, *n; + struct resource_list_entry *n; +#endif int error = 0; sc = arg; block = sc->ndis_block; dev = sc->ndis_dev; +#if __FreeBSD_version < 600022 SLIST_INIT(&brl_rev); +#endif rl = malloc(sizeof(ndis_resource_list) + (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), @@ -930,6 +933,7 @@ ndis_convert_res(arg) if (brl != NULL) { +#if __FreeBSD_version < 600022 /* * We have a small problem. Some PCI devices have * multiple I/O ranges. Windows orders them starting @@ -956,6 +960,9 @@ ndis_convert_res(arg) } SLIST_FOREACH(brle, &brl_rev, link) { +#else + STAILQ_FOREACH(brle, brl, link) { +#endif switch (brle->type) { case SYS_RES_IOPORT: prd->cprd_type = CmResourceTypePort; @@ -994,6 +1001,7 @@ ndis_convert_res(arg) block->nmb_rlist = rl; +#if __FreeBSD_version < 600022 bad: while (!SLIST_EMPTY(&brl_rev)) { @@ -1001,6 +1009,7 @@ bad: SLIST_REMOVE_HEAD(&brl_rev, link); free (n, M_TEMP); } +#endif return(error); } @@ -1064,7 +1073,7 @@ ndis_ptom(m0, p) } /* - * Create an mbuf chain from an NDIS packet chain. + * Create an NDIS packet from an mbuf chain. * This is used mainly when transmitting packets, where we need * to turn an mbuf off an interface's send queue and transform it * into an NDIS packet which will be fed into the NDIS driver's @@ -1096,14 +1105,13 @@ ndis_mtop(m0, p) for (m = m0; m != NULL; m = m->m_next) { if (m->m_len == 0) continue; - buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO); + buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); if (buf == NULL) { ndis_free_packet(*p); *p = NULL; return(ENOMEM); } - MmInitializeMdl(buf, m->m_data, m->m_len); if (priv->npp_head == NULL) priv->npp_head = buf; else @@ -1112,7 +1120,6 @@ ndis_mtop(m0, p) } priv->npp_tail = buf; - priv->npp_totlen = m0->m_pkthdr.len; return(0); } @@ -1163,18 +1170,36 @@ ndis_set_info(arg, oid, buf, buflen) int error; uint8_t irql; + /* + * According to the NDIS spec, MiniportQueryInformation() + * and MiniportSetInformation() requests are handled serially: + * once one request has been issued, we must wait for it to + * finish before allowing another request to proceed. + */ + sc = arg; - NDIS_LOCK(sc); + + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + if (sc->ndis_block->nmb_pendingreq != NULL) + panic("ndis_set_info() called while other request pending"); + else + sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; + setfunc = sc->ndis_chars->nmc_setinfo_func; adapter = sc->ndis_block->nmb_miniportadapterctx; - NDIS_UNLOCK(sc); - if (adapter == NULL || setfunc == NULL) + if (adapter == NULL || setfunc == NULL) { + sc->ndis_block->nmb_pendingreq = NULL; + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); return(ENXIO); + } - KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); rval = MSCALL6(setfunc, adapter, oid, buf, *buflen, &byteswritten, &bytesneeded); + + sc->ndis_block->nmb_pendingreq = NULL; + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); if (rval == NDIS_STATUS_PENDING) { @@ -1186,6 +1211,7 @@ ndis_set_info(arg, oid, buf, buflen) rval = sc->ndis_block->nmb_setstat; } + if (byteswritten) *buflen = byteswritten; if (bytesneeded) @@ -1229,9 +1255,11 @@ ndis_send_packets(arg, packets, cnt) return(ENXIO); sendfunc = sc->ndis_chars->nmc_sendmulti_func; senddonefunc = sc->ndis_block->nmb_senddone_func; - irql = KeRaiseIrql(DISPATCH_LEVEL); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + MSCALL3(sendfunc, adapter, packets, cnt); - KeLowerIrql(irql); for (i = 0; i < cnt; i++) { p = packets[i]; @@ -1246,6 +1274,9 @@ ndis_send_packets(arg, packets, cnt) MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status); } + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + return(0); } @@ -1268,16 +1299,22 @@ ndis_send_packet(arg, packet) sendfunc = sc->ndis_chars->nmc_sendsingle_func; senddonefunc = sc->ndis_block->nmb_senddone_func; - irql = KeRaiseIrql(DISPATCH_LEVEL); + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); status = MSCALL3(sendfunc, adapter, packet, packet->np_private.npp_flags); - KeLowerIrql(irql); - if (status == NDIS_STATUS_PENDING) + if (status == NDIS_STATUS_PENDING) { + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); return(0); + } MSCALL3(senddonefunc, sc->ndis_block, packet, status); + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + return(0); } @@ -1351,16 +1388,20 @@ ndis_reset_nic(arg) sc = arg; ifp = &sc->arpcom.ac_if; - NDIS_LOCK(sc); + adapter = sc->ndis_block->nmb_miniportadapterctx; resetfunc = sc->ndis_chars->nmc_reset_func; - NDIS_UNLOCK(sc); + if (adapter == NULL || resetfunc == NULL) return(EIO); - irql = KeRaiseIrql(DISPATCH_LEVEL); + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + rval = MSCALL2(resetfunc, &addressing_reset, adapter); - KeLowerIrql(irql); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); if (rval == NDIS_STATUS_PENDING) { mtx_lock(&ndis_req_mtx); @@ -1507,6 +1548,7 @@ ndis_disable_intr(arg) intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func; if (adapter == NULL || intrdisfunc == NULL) return; + MSCALL1(intrdisfunc, adapter); return; @@ -1529,38 +1571,48 @@ ndis_isr(arg, ourintr, callhandler) sc = arg; adapter = sc->ndis_block->nmb_miniportadapterctx; isrfunc = sc->ndis_chars->nmc_isr_func; + if (adapter == NULL || isrfunc == NULL) return(ENXIO); MSCALL3(isrfunc, &accepted, &queue, adapter); + *ourintr = accepted; *callhandler = queue; return(0); } -int -ndis_intrhand(arg) - void *arg; -{ +__stdcall static void +ndis_intrhand(dpc, dobj, ip, sc) + kdpc *dpc; + device_object *dobj; + irp *ip; struct ndis_softc *sc; +{ ndis_handle adapter; __stdcall ndis_interrupt_handler intrfunc; + uint8_t irql; - if (arg == NULL) - return(EINVAL); - - sc = arg; - NDIS_LOCK(sc); adapter = sc->ndis_block->nmb_miniportadapterctx; intrfunc = sc->ndis_chars->nmc_interrupt_func; - NDIS_UNLOCK(sc); + if (adapter == NULL || intrfunc == NULL) - return(EINVAL); + return; + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); MSCALL1(intrfunc, adapter); - return(0); + /* If there's a MiniportEnableInterrupt() routine, call it. */ + + ndis_enable_intr(sc); + + if (NDIS_SERIALIZED(sc->ndis_block)) + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); + + return; } int @@ -1577,19 +1629,29 @@ ndis_get_info(arg, oid, buf, buflen) uint32_t byteswritten = 0, bytesneeded = 0; int error; uint8_t irql; - + sc = arg; - NDIS_LOCK(sc); + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); + + if (sc->ndis_block->nmb_pendingreq != NULL) + panic("ndis_get_info() called while other request pending"); + else + sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; + queryfunc = sc->ndis_chars->nmc_queryinfo_func; adapter = sc->ndis_block->nmb_miniportadapterctx; - NDIS_UNLOCK(sc); - if (adapter == NULL || queryfunc == NULL) + if (adapter == NULL || queryfunc == NULL) { + sc->ndis_block->nmb_pendingreq = NULL; + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); return(ENXIO); + } - KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, &byteswritten, &bytesneeded); + + sc->ndis_block->nmb_pendingreq = NULL; + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); /* Wait for requests that block. */ @@ -1656,6 +1718,8 @@ NdisAddDevice(drv, pdo) sc->ndis_block = block; sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); + IoInitializeDpcRequest(fdo, ndis_intrhand); + /* Finish up BSD-specific setup. */ block->nmb_signature = (void *)0xcafebabe; @@ -1665,6 +1729,7 @@ NdisAddDevice(drv, pdo) block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; + block->nmb_pendingreq = NULL; ndis_enlarge_thrqueue(8); @@ -1682,7 +1747,8 @@ ndis_unload_driver(arg) sc = arg; - free(sc->ndis_block->nmb_rlist, M_DEVBUF); + if (sc->ndis_block->nmb_rlist != NULL) + free(sc->ndis_block->nmb_rlist, M_DEVBUF); ndis_flush_sysctls(sc); diff --git a/sys/compat/ndis/kern_windrv.c b/sys/compat/ndis/kern_windrv.c index 6fa3575fea34a..67c3c0e7e2878 100644 --- a/sys/compat/ndis/kern_windrv.c +++ b/sys/compat/ndis/kern_windrv.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <compat/ndis/ntoskrnl_var.h> #include <compat/ndis/ndis_var.h> #include <compat/ndis/hal_var.h> +#include <compat/ndis/usbd_var.h> struct windrv_type { uint16_t windrv_vid; /* for PCI or USB */ @@ -130,20 +131,36 @@ windrv_libfini(void) */ driver_object * -windrv_lookup(img) +windrv_lookup(img, name) vm_offset_t img; + char *name; { struct drvdb_ent *d; + unicode_string us; + + /* Damn unicode. */ + + if (name != NULL) { + us.us_len = strlen(name) * 2; + us.us_maxlen = strlen(name) * 2; + us.us_buf = NULL; + ndis_ascii_to_unicode(name, &us.us_buf); + } mtx_lock(&drvdb_mtx); STAILQ_FOREACH(d, &drvdb_head, link) { - if (d->windrv_object->dro_driverstart == (void *)img) { + if (d->windrv_object->dro_driverstart == (void *)img || + bcmp((char *)d->windrv_object->dro_drivername.us_buf, + (char *)us.us_buf, us.us_len) == 0) { mtx_unlock(&drvdb_mtx); return(d->windrv_object); } } mtx_unlock(&drvdb_mtx); + if (name != NULL) + ExFreePool(us.us_buf); + return(NULL); } @@ -217,7 +234,7 @@ windrv_load(mod, img, len) image_optional_header opt_hdr; driver_entry entry; struct drvdb_ent *new; - struct driver_object *dobj; + struct driver_object *drv; int status; /* @@ -244,12 +261,10 @@ windrv_load(mod, img, len) } /* Dynamically link USBD.SYS -- optional */ -#ifdef notyet if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) { - if (pe_patch_imports(img, "USBD", ntoskrnl_functbl)) + if (pe_patch_imports(img, "USBD", usbd_functbl)) return(ENOEXEC); } -#endif /* Next step: find the driver entry point. */ @@ -262,43 +277,43 @@ windrv_load(mod, img, len) if (new == NULL) return (ENOMEM); - dobj = malloc(sizeof(device_object), M_DEVBUF, M_NOWAIT|M_ZERO); - if (dobj == NULL) { + drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO); + if (drv == NULL) { free (new, M_DEVBUF); return (ENOMEM); } /* Allocate a driver extension structure too. */ - dobj->dro_driverext = malloc(sizeof(driver_extension), + drv->dro_driverext = malloc(sizeof(driver_extension), M_DEVBUF, M_NOWAIT|M_ZERO); - if (dobj->dro_driverext == NULL) { + if (drv->dro_driverext == NULL) { free(new, M_DEVBUF); - free(dobj, M_DEVBUF); + free(drv, M_DEVBUF); return(ENOMEM); } - INIT_LIST_HEAD((&dobj->dro_driverext->dre_usrext)); + INIT_LIST_HEAD((&drv->dro_driverext->dre_usrext)); - dobj->dro_driverstart = (void *)img; - dobj->dro_driversize = len; + drv->dro_driverstart = (void *)img; + drv->dro_driversize = len; - dobj->dro_drivername.us_len = strlen(DUMMY_REGISTRY_PATH) * 2; - dobj->dro_drivername.us_maxlen = strlen(DUMMY_REGISTRY_PATH) * 2; - dobj->dro_drivername.us_buf = NULL; + drv->dro_drivername.us_len = strlen(DUMMY_REGISTRY_PATH) * 2; + drv->dro_drivername.us_maxlen = strlen(DUMMY_REGISTRY_PATH) * 2; + drv->dro_drivername.us_buf = NULL; ndis_ascii_to_unicode(DUMMY_REGISTRY_PATH, - &dobj->dro_drivername.us_buf); + &drv->dro_drivername.us_buf); - new->windrv_object = dobj; + new->windrv_object = drv; /* Now call the DriverEntry() function. */ - status = MSCALL2(entry, dobj, &dobj->dro_drivername); + status = MSCALL2(entry, drv, &drv->dro_drivername); if (status != STATUS_SUCCESS) { - free(dobj->dro_drivername.us_buf, M_DEVBUF); - free(dobj, M_DEVBUF); + free(drv->dro_drivername.us_buf, M_DEVBUF); + free(drv, M_DEVBUF); free(new, M_DEVBUF); return(ENODEV); } diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h index 7b33a3e3142c1..7221862ca99a1 100644 --- a/sys/compat/ndis/ndis_var.h +++ b/sys/compat/ndis/ndis_var.h @@ -692,6 +692,9 @@ typedef struct ndis_task_ipsec ndis_task_ipsec; #define NDIS_ATTRIBUTE_NOT_CO_NDIS 0x00000100 #define NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS 0x00000200 +#define NDIS_SERIALIZED(block) \ + (((block)->nmb_flags & NDIS_ATTRIBUTE_DESERIALIZE) == 0) + enum ndis_media_state { nmc_connected, nmc_disconnected @@ -875,7 +878,7 @@ struct ndis_timer { typedef struct ndis_timer ndis_timer; -typedef void (*ndis_timer_function)(void *, void *, void *, void *); +typedef __stdcall void (*ndis_timer_function)(void *, void *, void *, void *); struct ndis_miniport_timer { struct ktimer nmt_ktimer; @@ -1161,6 +1164,7 @@ struct ndis_packet { void *np_softc; void *np_m0; int np_txidx; + kspin_lock np_lock; }; typedef struct ndis_packet ndis_packet; @@ -1503,6 +1507,53 @@ extern image_patch_table ndis_functbl[]; #define NDIS_PSTATE_RUNNING 1 #define NDIS_PSTATE_SLEEPING 2 +#define NdisQueryPacket(p, pbufcnt, bufcnt, firstbuf, plen) \ + do { \ + if ((firstbuf) != NULL) { \ + ndis_buffer **_first; \ + _first = firstbuf; \ + *(_first) = (p)->np_private.npp_head; \ + } \ + if ((plen) || (bufcnt) || (pbufcnt)) { \ + if ((p)->np_private.npp_validcounts == FALSE) { \ + ndis_buffer *tmp; \ + unsigned int tlen = 0, pcnt = 0; \ + unsigned int add = 0; \ + unsigned int pktlen, off; \ + \ + tmp = (p)->np_private.npp_head; \ + while (tmp != NULL) { \ + off = MmGetMdlByteOffset(tmp); \ + pktlen = MmGetMdlByteCount(tmp);\ + tlen += pktlen; \ + pcnt += \ + NDIS_BUFFER_TO_SPAN_PAGES(tmp); \ + add++; \ + tmp = tmp->mdl_next; \ + } \ + (p)->np_private.npp_count = add; \ + (p)->np_private.npp_totlen = tlen; \ + (p)->np_private.npp_physcnt = pcnt; \ + (p)->np_private.npp_validcounts = TRUE; \ + } \ + if (pbufcnt) { \ + unsigned int *_pbufcnt; \ + _pbufcnt = (pbufcnt); \ + *(_pbufcnt) = (p)->np_private.npp_physcnt; \ + } \ + if (bufcnt) { \ + unsigned int *_bufcnt; \ + _bufcnt = (bufcnt); \ + *(_bufcnt) = (p)->np_private.npp_count; \ + } \ + if (plen) { \ + unsigned int *_plen; \ + _plen = (plen); \ + *(_plen) = (p)->np_private.npp_totlen; \ + } \ + } \ + } while (0) + __BEGIN_DECLS extern int ndis_libinit(void); extern int ndis_libfini(void); @@ -1527,7 +1578,6 @@ extern int ndis_halt_nic(void *); extern int ndis_shutdown_nic(void *); extern int ndis_init_nic(void *); extern int ndis_isr(void *, int *, int *); -extern int ndis_intrhand(void *); extern void ndis_return_packet(void *, void *); extern void ndis_enable_intr(void *); extern void ndis_disable_intr(void *); @@ -1538,7 +1588,7 @@ extern int ndis_add_sysctl(void *, char *, char *, char *, int); extern int ndis_flush_sysctls(void *); extern int ndis_sched(void (*)(void *), void *, int); extern int ndis_unsched(void (*)(void *), void *, int); -extern int ndis_thsuspend(struct proc *, int); +extern int ndis_thsuspend(struct proc *, struct mtx *, int); extern void ndis_thresume(struct proc *); extern int ndis_strcasecmp(const char *, const char *); extern int ndis_strncasecmp(const char *, const char *, size_t); diff --git a/sys/compat/ndis/ntoskrnl_var.h b/sys/compat/ndis/ntoskrnl_var.h index 54ae903afd15c..3928db86e0752 100644 --- a/sys/compat/ndis/ntoskrnl_var.h +++ b/sys/compat/ndis/ntoskrnl_var.h @@ -100,6 +100,10 @@ typedef struct mdl mdl, ndis_buffer; #define MDL_NETWORK_HEADER 0x1000 #define MDL_MAPPING_CAN_FAIL 0x2000 #define MDL_ALLOCATED_MUST_SUCCEED 0x4000 +#define MDL_ZONE_ALLOCED 0x8000 /* BSD private */ + +#define MDL_ZONE_PAGES 16 +#define MDL_ZONE_SIZE (sizeof(mdl) + (sizeof(vm_offset_t) * MDL_ZONE_PAGES)) /* Note: assumes x86 page size of 4K. */ @@ -126,7 +130,7 @@ typedef struct mdl mdl, ndis_buffer; #define MmInitializeMdl(b, baseva, len) \ (b)->mdl_next = NULL; \ (b)->mdl_size = (uint16_t)(sizeof(mdl) + \ - (sizeof(uint32_t) * SPAN_PAGES((baseva), (len)))); \ + (sizeof(vm_offset_t) * SPAN_PAGES((baseva), (len)))); \ (b)->mdl_flags = 0; \ (b)->mdl_startva = (void *)PAGE_ALIGN((baseva)); \ (b)->mdl_byteoffset = BYTE_OFFSET((baseva)); \ @@ -347,7 +351,7 @@ 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 *); +typedef __stdcall void (*kdpc_func)(struct kdpc *, void *, void *, void *); struct kdpc { uint16_t k_type; @@ -424,7 +428,9 @@ typedef struct general_lookaside general_lookaside; struct npaged_lookaside_list { general_lookaside nll_l; +#ifdef __i386__ kspin_lock nll_obsoletelock; +#endif }; typedef struct npaged_lookaside_list npaged_lookaside_list; @@ -574,6 +580,26 @@ struct devobj_extension { typedef struct devobj_extension devobj_extension; +/* Device object flags */ + +#define DO_VERIFY_VOLUME 0x00000002 +#define DO_BUFFERED_IO 0x00000004 +#define DO_EXCLUSIVE 0x00000008 +#define DO_DIRECT_IO 0x00000010 +#define DO_MAP_IO_BUFFER 0x00000020 +#define DO_DEVICE_HAS_NAME 0x00000040 +#define DO_DEVICE_INITIALIZING 0x00000080 +#define DO_SYSTEM_BOOT_PARTITION 0x00000100 +#define DO_LONG_TERM_REQUESTS 0x00000200 +#define DO_NEVER_LAST_DEVICE 0x00000400 +#define DO_SHUTDOWN_REGISTERED 0x00000800 +#define DO_BUS_ENUMERATED_DEVICE 0x00001000 +#define DO_POWER_PAGABLE 0x00002000 +#define DO_POWER_INRUSH 0x00004000 +#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000 + +/* Priority boosts */ + #define IO_NO_INCREMENT 0 #define IO_CD_ROM_INCREMENT 1 #define IO_DISK_INCREMENT 1 @@ -630,7 +656,7 @@ typedef struct devobj_extension devobj_extension; #define IRP_MN_MOUNT_VOLUME 0x01 #define IRP_MN_VERIFY_VOLUME 0x02 #define IRP_MN_LOAD_FILE_SYSTEM 0x03 -#define IRP_MN_TRACK_LINK 0x04 // To be obsoleted soon +#define IRP_MN_TRACK_LINK 0x04 #define IRP_MN_KERNEL_CALL 0x04 #define IRP_MN_LOCK 0x01 @@ -723,6 +749,34 @@ typedef struct devobj_extension devobj_extension; #define IRP_ALLOCATED_FIXED_SIZE 0x04 #define IRP_LOOKASIDE_ALLOCATION 0x08 +/* I/O method types */ + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* File access types */ + +#define FILE_ANY_ACCESS 0x0000 +#define FILE_SPECIAL_ACCESS FILE_ANY_ACCESS +#define FILE_READ_ACCESS 0x0001 +#define FILE_WRITE_ACCESS 0x0002 + +/* Recover I/O access method from IOCTL code. */ + +#define IO_METHOD(x) ((x) & 0xFFFFFFFC) + +/* Recover function code from IOCTL code */ + +#define IO_FUNC(x) (((x) & 0x7FFC) >> 2) + +/* Macro to construct an IOCTL code. */ + +#define IOCTL_CODE(dev, func, iomethod, acc) \ + ((dev) << 16) | (acc << 14) | (func << 2) | (iomethod)) + + struct io_status_block { union { uint32_t isb_status; @@ -756,6 +810,8 @@ typedef struct kapc kapc; typedef __stdcall uint32_t (*completion_func)(device_object *, struct irp *, void *); +typedef __stdcall uint32_t (*cancel_func)(device_object *, + struct irp *); struct io_stack_location { uint8_t isl_major; @@ -775,12 +831,28 @@ struct io_stack_location { union { struct { + uint32_t isl_len; + uint32_t *isl_key; + uint64_t isl_byteoff; + } isl_read; + struct { + uint32_t isl_len; + uint32_t *isl_key; + uint64_t isl_byteoff; + } isl_write; + struct { + uint32_t isl_obuflen; + uint32_t isl_ibuflen; + uint32_t isl_iocode; + void *isl_type3ibuf; + } isl_ioctl; + struct { void *isl_arg1; void *isl_arg2; void *isl_arg3; void *isl_arg4; } isl_others; - } isl_parameters; + } isl_parameters __attribute__((packed)); void *isl_devobj; void *isl_fileobj; @@ -826,7 +898,7 @@ struct irp { } irp_asyncparms; uint64_t irp_allocsz; } irp_overlay; - void *irp_cancelfunc; + cancel_func irp_cancelfunc; void *irp_userbuf; /* Windows kernel info */ @@ -860,9 +932,16 @@ struct irp { typedef struct irp irp; +#define InterlockedExchangePointer(dst, val) \ + (void *)FASTCALL2(InterlockedExchange, (uint32_t *)(dst), \ + (uintptr_t)(val)) + #define IoSizeOfIrp(ssize) \ ((uint16_t) (sizeof(irp) + ((ssize) * (sizeof(io_stack_location))))) +#define IoSetCancelRoutine(irp, func) \ + (cancel_func)InterlockedExchangePointer( \ + (void *)&(ip)->irp_cancelfunc, (void *)(func)) #define IoGetCurrentIrpStackLocation(irp) \ (irp)->irp_tail.irp_overlay.irp_csl @@ -906,6 +985,12 @@ typedef struct irp irp; (irp)->irp_tail.irp_overlay.irp_csl++; \ } while(0) +#define IoInitializeDpcRequest(dobj, dpcfunc) \ + KeInitializeDpc(&(dobj)->do_dpc, dpcfunc, dobj) + +#define IoRequestDpc(dobj, irp, ctx) \ + KeInsertQueueDpc(&(dobj)->do_dpc, irp, ctx) + typedef __stdcall uint32_t (*driver_dispatch)(device_object *, irp *); /* @@ -1039,6 +1124,7 @@ typedef struct driver_object driver_object; #define STATUS_KERNEL_APC 0x00000100 #define STATUS_ALERTED 0x00000101 #define STATUS_TIMEOUT 0x00000102 +#define STATUS_PENDING 0x00000103 #define STATUS_INVALID_PARAMETER 0xC000000D #define STATUS_INVALID_DEVICE_REQUEST 0xC0000010 #define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 @@ -1073,7 +1159,7 @@ typedef void (*funcptr)(void); __BEGIN_DECLS extern int windrv_libinit(void); extern int windrv_libfini(void); -extern driver_object *windrv_lookup(vm_offset_t); +extern driver_object *windrv_lookup(vm_offset_t, char *); extern int windrv_load(module_t, vm_offset_t, int); extern int windrv_unload(module_t, vm_offset_t, int); extern int windrv_create_pdo(driver_object *, device_t); @@ -1101,9 +1187,17 @@ __stdcall extern void KeClearEvent(nt_kevent *); __stdcall extern uint32_t KeReadStateEvent(nt_kevent *); __stdcall extern uint32_t KeSetEvent(nt_kevent *, uint32_t, uint8_t); __stdcall extern uint32_t KeResetEvent(nt_kevent *); +#ifdef __i386__ __fastcall extern void KefAcquireSpinLockAtDpcLevel(REGARGS1(kspin_lock *)); __fastcall extern void KefReleaseSpinLockFromDpcLevel(REGARGS1(kspin_lock *)); +__stdcall extern uint8_t KeAcquireSpinLockRaiseToDpc(kspin_lock *); +#else +__stdcall extern void KeAcquireSpinLockAtDpcLevel(kspin_lock *); +__stdcall extern void KeReleaseSpinLockFromDpcLevel(kspin_lock *); +#endif __stdcall extern void KeInitializeSpinLock(kspin_lock *); +__fastcall extern uintptr_t InterlockedExchange(REGARGS2(volatile uint32_t *, + uintptr_t)); __stdcall extern void *ExAllocatePoolWithTag(uint32_t, size_t, uint32_t); __stdcall extern void ExFreePool(void *); __stdcall extern uint32_t IoAllocateDriverObjectExtension(driver_object *, @@ -1115,6 +1209,9 @@ __stdcall extern void IoDeleteDevice(device_object *); __stdcall extern device_object *IoGetAttachedDevice(device_object *); __fastcall extern uint32_t IofCallDriver(REGARGS2(device_object *, irp *)); __fastcall extern void IofCompleteRequest(REGARGS2(irp *, uint8_t)); +__stdcall extern void IoAcquireCancelSpinLock(uint8_t *); +__stdcall extern void IoReleaseCancelSpinLock(uint8_t); +__stdcall extern uint8_t IoCancelIrp(irp *); __stdcall extern void IoDetachDevice(device_object *); __stdcall extern device_object *IoAttachDeviceToDeviceStack(device_object *, device_object *); @@ -1133,6 +1230,10 @@ __stdcall void IoFreeMdl(mdl *); #define KeReleaseSpinLock(a, b) FASTCALL2(KfReleaseSpinLock, a, b) #define KeRaiseIrql(a) FASTCALL1(KfRaiseIrql, a) #define KeLowerIrql(a) FASTCALL1(KfLowerIrql, a) +#define KeAcquireSpinLockAtDpcLevel(a) \ + FASTCALL1(KefAcquireSpinLockAtDpcLevel, a) +#define KeReleaseSpinLockFromDpcLevel(a) \ + FASTCALL1(KefReleaseSpinLockFromDpcLevel, a) #endif /* __i386__ */ #ifdef __amd64__ diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c index 0ec036acb59a5..63897713b38e7 100644 --- a/sys/compat/ndis/subr_hal.c +++ b/sys/compat/ndis/subr_hal.c @@ -295,8 +295,8 @@ KfAcquireSpinLock(REGARGS1(kspin_lock *lock)) if (KeGetCurrentIrql() > DISPATCH_LEVEL) panic("IRQL_NOT_LESS_THAN_OR_EQUAL"); - oldirql = FASTCALL1(KfRaiseIrql, DISPATCH_LEVEL); - FASTCALL1(KefAcquireSpinLockAtDpcLevel, lock); + oldirql = KeRaiseIrql(DISPATCH_LEVEL); + KeAcquireSpinLockAtDpcLevel(lock); return(oldirql); } @@ -304,8 +304,8 @@ KfAcquireSpinLock(REGARGS1(kspin_lock *lock)) __fastcall void KfReleaseSpinLock(REGARGS2(kspin_lock *lock, uint8_t newirql)) { - FASTCALL1(KefReleaseSpinLockFromDpcLevel, lock); - FASTCALL1(KfLowerIrql, newirql); + KeReleaseSpinLockFromDpcLevel(lock); + KeLowerIrql(newirql); return; } diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c index 9d42901a2d0d6..388cd6204bfa2 100644 --- a/sys/compat/ndis/subr_ndis.c +++ b/sys/compat/ndis/subr_ndis.c @@ -161,6 +161,8 @@ __stdcall static void NdisInitializeTimer(ndis_timer *, __stdcall static void NdisSetTimer(ndis_timer *, uint32_t); __stdcall static void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t); __stdcall static void NdisMCancelTimer(ndis_timer *, uint8_t *); +__stdcall static void ndis_timercall(kdpc *, ndis_miniport_timer *, + void *, void *); __stdcall static void NdisMQueryAdapterResources(ndis_status *, ndis_handle, ndis_resource_list *, uint32_t *); __stdcall static ndis_status NdisMRegisterIoPortRange(void **, @@ -341,7 +343,7 @@ ndis_ascii_to_unicode(ascii, unicode) int i; if (*unicode == NULL) - *unicode = malloc(strlen(ascii) * 2, M_DEVBUF, M_WAITOK); + *unicode = malloc(strlen(ascii) * 2, M_DEVBUF, M_NOWAIT); if (*unicode == NULL) return(ENOMEM); @@ -364,7 +366,7 @@ ndis_unicode_to_ascii(unicode, ulen, ascii) int i; if (*ascii == NULL) - *ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_WAITOK|M_ZERO); + *ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_NOWAIT|M_ZERO); if (*ascii == NULL) return(ENOMEM); astr = *ascii; @@ -888,7 +890,7 @@ __stdcall static void NdisDprAcquireSpinLock(lock) ndis_spin_lock *lock; { - FASTCALL1(KefAcquireSpinLockAtDpcLevel, &lock->nsl_spinlock); + KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock); return; } @@ -899,7 +901,7 @@ __stdcall static void NdisDprReleaseSpinLock(lock) ndis_spin_lock *lock; { - FASTCALL1(KefReleaseSpinLockFromDpcLevel, &lock->nsl_spinlock); + KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock); return; } @@ -922,8 +924,26 @@ NdisReadPciSlotInformation(adapter, slot, offset, buf, len) return(0); dev = block->nmb_physdeviceobj->do_devext; - for (i = 0; i < len; i++) + + /* + * I have a test system consisting of a Sun w2100z + * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g + * "Aries" miniPCI NIC. (The NIC is installed in the + * machine using a miniPCI to PCI bus adapter card.) + * When running in SMP mode, I found that + * performing a large number of consecutive calls to + * NdisReadPciSlotInformation() would result in a + * sudden system reset (or in some cases a freeze). + * My suspicion is that the multiple reads are somehow + * triggering a fatal PCI bus error that leads to a + * machine check. The 1us delay in the loop below + * seems to prevent this problem. + */ + + for (i = 0; i < len; i++) { + DELAY(1); dest[i] = pci_read_config(dev, i + offset, 1); + } return(len); } @@ -948,8 +968,10 @@ NdisWritePciSlotInformation(adapter, slot, offset, buf, len) return(0); dev = block->nmb_physdeviceobj->do_devext; - for (i = 0; i < len; i++) + for (i = 0; i < len; i++) { + DELAY(1); pci_write_config(dev, i + offset, dest[i], 1); + } return(len); } @@ -1094,15 +1116,9 @@ NdisMCompleteBufferPhysicalMapping(adapter, buf, mapreg) } /* - * This is an older pre-miniport timer init routine which doesn't - * accept a miniport context handle. The function context (ctx) - * is supposed to be a pointer to the adapter handle, which should - * have been handed to us via NdisSetAttributesEx(). We use this - * function context to track down the corresponding ndis_miniport_block - * structure. It's vital that we track down the miniport block structure, - * so if we can't do it, we panic. Note that we also play some games - * here by treating ndis_timer and ndis_miniport_timer as the same - * thing. + * This is an older (?) timer init routine which doesn't + * accept a miniport context handle. Serialized miniports should + * never call this function. */ __stdcall static void @@ -1118,20 +1134,64 @@ NdisInitializeTimer(timer, func, ctx) } __stdcall static void +ndis_timercall(dpc, timer, sysarg1, sysarg2) + kdpc *dpc; + ndis_miniport_timer *timer; + void *sysarg1; + void *sysarg2; +{ + /* + * Since we're called as a DPC, we should be running + * at DISPATCH_LEVEL here. This means to acquire the + * spinlock, we can use KeAcquireSpinLockAtDpcLevel() + * rather than KeAcquireSpinLock(). + */ + if (NDIS_SERIALIZED(timer->nmt_block)) + KeAcquireSpinLockAtDpcLevel(&timer->nmt_block->nmb_lock); + + MSCALL4(timer->nmt_timerfunc, dpc, timer->nmt_timerctx, + sysarg1, sysarg2); + + if (NDIS_SERIALIZED(timer->nmt_block)) + KeReleaseSpinLockFromDpcLevel(&timer->nmt_block->nmb_lock); + + return; +} + +/* + * For a long time I wondered why there were two NDIS timer initialization + * routines, and why this one needed an NDIS_MINIPORT_TIMER and the + * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout + * function and context pointers separate from those in the DPC, which + * allows for another level of indirection: when the timer fires, we + * can have our own timer function invoked, and from there we can call + * the driver's function. But why go to all that trouble? Then it hit + * me: for serialized miniports, the timer callouts are not re-entrant. + * By trapping the callouts and having access to the MiniportAdapterHandle, + * we can protect the driver callouts by acquiring the NDIS serialization + * lock. This is essential for allowing serialized miniports to work + * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL + * is enough to prevent other threads from pre-empting you, but with + * SMP, you must acquire a lock as well, otherwise the other CPU is + * free to clobber you. + */ +__stdcall static void NdisMInitializeTimer(timer, handle, func, ctx) ndis_miniport_timer *timer; ndis_handle handle; ndis_timer_function func; void *ctx; { - /* Save the funcptr and context */ + /* Save the driver's funcptr and context */ timer->nmt_timerfunc = func; timer->nmt_timerctx = ctx; timer->nmt_block = handle; + /* Set up the timer so it will call our intermediate DPC. */ + KeInitializeTimer(&timer->nmt_ktimer); - KeInitializeDpc(&timer->nmt_kdpc, func, ctx); + KeInitializeDpc(&timer->nmt_kdpc, ndis_timercall, timer); return; } @@ -1170,7 +1230,7 @@ NdisMSetPeriodicTimer(timer, msecs) * Technically, this is really NdisCancelTimer(), but we also * (ab)use it for NdisMCancelTimer(), since in our implementation * we don't need the extra info in the ndis_miniport_timer - * structure. + * structure just to cancel a timer. */ __stdcall static void @@ -1526,6 +1586,11 @@ NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr) sc = device_get_softc(block->nmb_physdeviceobj->do_devext); sh = prev = sc->ndis_shlist; + /* Sanity check: is list empty? */ + + if (sh == NULL) + return; + while (sh) { if (sh->ndis_saddr == vaddr) break; @@ -1660,6 +1725,7 @@ NdisAllocatePacketPool(status, pool, descnum, protrsvdlen) } cur = (ndis_packet *)*pool; + KeInitializeSpinLock(&cur->np_lock); cur->np_private.npp_flags = 0x1; /* mark the head of the list */ cur->np_private.npp_totlen = 0; /* init deletetion flag */ for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) { @@ -1688,10 +1754,15 @@ NdisPacketPoolUsage(pool) ndis_handle pool; { ndis_packet *head; + uint8_t irql; + uint32_t cnt; head = (ndis_packet *)pool; + KeAcquireSpinLock(&head->np_lock, &irql); + cnt = head->np_private.npp_count; + KeReleaseSpinLock(&head->np_lock, irql); - return(head->np_private.npp_count); + return(cnt); } __stdcall void @@ -1699,19 +1770,24 @@ NdisFreePacketPool(pool) ndis_handle pool; { ndis_packet *head; + uint8_t irql; head = pool; /* Mark this pool as 'going away.' */ + KeAcquireSpinLock(&head->np_lock, &irql); head->np_private.npp_totlen = 1; /* If there are no buffers loaned out, destroy the pool. */ - if (head->np_private.npp_count == 0) + if (head->np_private.npp_count == 0) { + KeReleaseSpinLock(&head->np_lock, irql); free(pool, M_DEVBUF); - else + } else { printf("NDIS: buggy driver deleting active packet pool!\n"); + KeReleaseSpinLock(&head->np_lock, irql); + } return; } @@ -1723,11 +1799,14 @@ NdisAllocatePacket(status, packet, pool) ndis_handle pool; { ndis_packet *head, *pkt; + uint8_t irql; head = (ndis_packet *)pool; + KeAcquireSpinLock(&head->np_lock, &irql); if (head->np_private.npp_flags != 0x1) { *status = NDIS_STATUS_FAILURE; + KeReleaseSpinLock(&head->np_lock, irql); return; } @@ -1738,6 +1817,7 @@ NdisAllocatePacket(status, packet, pool) if (head->np_private.npp_totlen) { *status = NDIS_STATUS_FAILURE; + KeReleaseSpinLock(&head->np_lock, irql); return; } @@ -1745,6 +1825,7 @@ NdisAllocatePacket(status, packet, pool) if (pkt == NULL) { *status = NDIS_STATUS_RESOURCES; + KeReleaseSpinLock(&head->np_lock, irql); return; } @@ -1765,12 +1846,15 @@ NdisAllocatePacket(status, packet, pool) * correctly. */ pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; + pkt->np_private.npp_validcounts = FALSE; *packet = pkt; head->np_private.npp_count++; *status = NDIS_STATUS_SUCCESS; + KeReleaseSpinLock(&head->np_lock, irql); + return; } @@ -1779,13 +1863,18 @@ NdisFreePacket(packet) ndis_packet *packet; { ndis_packet *head; + uint8_t irql; if (packet == NULL || packet->np_private.npp_pool == NULL) return; head = packet->np_private.npp_pool; - if (head->np_private.npp_flags != 0x1) + KeAcquireSpinLock(&head->np_lock, &irql); + + if (head->np_private.npp_flags != 0x1) { + KeReleaseSpinLock(&head->np_lock, irql); return; + } packet->np_private.npp_head = head->np_private.npp_head; head->np_private.npp_head = (ndis_buffer *)packet; @@ -1796,8 +1885,11 @@ NdisFreePacket(packet) * no more packets outstanding, nuke the pool. */ - if (head->np_private.npp_totlen && head->np_private.npp_count == 0) + if (head->np_private.npp_totlen && head->np_private.npp_count == 0) { + KeReleaseSpinLock(&head->np_lock, irql); free(head, M_DEVBUF); + } else + KeReleaseSpinLock(&head->np_lock, irql); return; } @@ -2235,7 +2327,7 @@ NdisMSleep(usecs) tv.tv_sec = 0; tv.tv_usec = usecs; - ndis_thsuspend(curthread->td_proc, tvtohz(&tv)); + ndis_thsuspend(curthread->td_proc, NULL, tvtohz(&tv)); return; } @@ -2401,10 +2493,7 @@ __stdcall static void NdisGetSystemUpTime(tval) uint32_t *tval; { - struct timespec ts; - - nanouptime(&ts); - *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000; + *tval = (ticks * hz) / 1000; return; } @@ -2556,14 +2645,20 @@ ndis_find_sym(lf, filename, suffix, sym) char *suffix; caddr_t *sym; { - char fullsym[MAXPATHLEN]; + char *fullsym; char *suf; int i; - bzero(fullsym, sizeof(fullsym)); - strcpy(fullsym, filename); - if (strlen(filename) < 4) + fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); + if (fullsym == NULL) + return(ENOMEM); + + bzero(fullsym, MAXPATHLEN); + strncpy(fullsym, filename, MAXPATHLEN); + if (strlen(filename) < 4) { + ExFreePool(fullsym); return(EINVAL); + } /* If the filename has a .ko suffix, strip if off. */ suf = fullsym + (strlen(filename) - 3); @@ -2578,6 +2673,7 @@ ndis_find_sym(lf, filename, suffix, sym) } strcat(fullsym, suffix); *sym = linker_file_lookup_symbol(lf, fullsym, 0); + ExFreePool(fullsym); if (*sym == 0) return(ENOENT); @@ -2600,14 +2696,14 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr) struct vattr vat; struct vattr *vap = &vat; ndis_fh *fh; - char path[MAXPATHLEN]; + char *path; linker_file_t head, lf; caddr_t kldstart, kldend; ndis_unicode_to_ascii(filename->us_buf, filename->us_len, &afilename); - fh = malloc(sizeof(ndis_fh), M_TEMP, M_NOWAIT); + fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0); if (fh == NULL) { *status = NDIS_STATUS_RESOURCES; return; @@ -2656,7 +2752,7 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr) } if (TAILQ_EMPTY(&mountlist)) { - free(fh, M_TEMP); + ExFreePool(fh); *status = NDIS_STATUS_FILE_NOT_FOUND; printf("NDIS: could not find file %s in linker list\n", afilename); @@ -2666,7 +2762,14 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr) return; } - sprintf(path, "%s/%s", ndis_filepath, afilename); + path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); + if (path == NULL) { + ExFreePool(fh); + *status = NDIS_STATUS_RESOURCES; + return; + } + + snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename); free(afilename, M_DEVBUF); mtx_lock(&Giant); @@ -2685,11 +2788,14 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr) if (error) { mtx_unlock(&Giant); *status = NDIS_STATUS_FILE_NOT_FOUND; - free(fh, M_TEMP); + ExFreePool(fh); printf("NDIS: open file %s failed: %d\n", path, error); + ExFreePool(path); return; } + ExFreePool(path); + NDFREE(&nd, NDF_ONLY_PNBUF); /* Get the file size. */ @@ -2748,7 +2854,7 @@ NdisMapFile(status, mappedbuffer, filehandle) return; } - fh->nf_map = malloc(fh->nf_maplen, M_DEVBUF, M_NOWAIT); + fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0); if (fh->nf_map == NULL) { *status = NDIS_STATUS_RESOURCES; @@ -2781,7 +2887,7 @@ NdisUnmapFile(filehandle) return; if (fh->nf_type == NDIS_FH_TYPE_VFS) - free(fh->nf_map, M_DEVBUF); + ExFreePool(fh->nf_map); fh->nf_map = NULL; return; @@ -2800,7 +2906,7 @@ NdisCloseFile(filehandle) fh = (ndis_fh *)filehandle; if (fh->nf_map != NULL) { if (fh->nf_type == NDIS_FH_TYPE_VFS) - free(fh->nf_map, M_DEVBUF); + ExFreePool(fh->nf_map); fh->nf_map = NULL; } @@ -2814,7 +2920,7 @@ NdisCloseFile(filehandle) } fh->nf_vp = NULL; - free(fh, M_DEVBUF); + ExFreePool(fh); return; } diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c index eb7f5bafd25b5..46aefd4f77a9c 100644 --- a/sys/compat/ndis/subr_ntoskrnl.c +++ b/sys/compat/ndis/subr_ntoskrnl.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/pmap.h> +#include <vm/uma.h> #include <compat/ndis/pe_var.h> #include <compat/ndis/ntoskrnl_var.h> @@ -137,6 +138,8 @@ __fastcall static slist_entry __fastcall static slist_entry *ExInterlockedPopEntrySList(REGARGS2(slist_header *head, kspin_lock *lock)); +__stdcall static uint16_t + ExQueryDepthSList(slist_header *); __fastcall static uint32_t InterlockedIncrement(REGARGS1(volatile uint32_t *addend)); __fastcall static uint32_t @@ -177,14 +180,17 @@ __stdcall static ndis_status ObReferenceObjectByHandle(ndis_handle, __fastcall static void ObfDereferenceObject(REGARGS1(void *object)); __stdcall static uint32_t ZwClose(ndis_handle); static void *ntoskrnl_memset(void *, int, size_t); +static funcptr ntoskrnl_findwrap(funcptr); static uint32_t DbgPrint(char *, ...); __stdcall static void DbgBreakPoint(void); __stdcall static void dummy(void); static struct mtx ntoskrnl_dispatchlock; static kspin_lock ntoskrnl_global; +static kspin_lock ntoskrnl_cancellock; static int ntoskrnl_kth = 0; static struct nt_objref_head ntoskrnl_reflist; +static uma_zone_t mdl_zone; int ntoskrnl_libinit() @@ -194,6 +200,7 @@ ntoskrnl_libinit() mtx_init(&ntoskrnl_dispatchlock, "ntoskrnl dispatch lock", MTX_NDIS_LOCK, MTX_DEF); KeInitializeSpinLock(&ntoskrnl_global); + KeInitializeSpinLock(&ntoskrnl_cancellock); TAILQ_INIT(&ntoskrnl_reflist); patch = ntoskrnl_functbl; @@ -203,6 +210,22 @@ ntoskrnl_libinit() patch++; } + /* + * MDLs are supposed to be variable size (they describe + * buffers containing some number of pages, but we don't + * know ahead of time how many pages that will be). But + * always allocating them off the heap is very slow. As + * a compromize, we create an MDL UMA zone big enough to + * handle any buffer requiring up to 16 pages, and we + * use those for any MDLs for buffers of 16 pages or less + * in size. For buffers larger than that (which we assume + * will be few and far between, we allocate the MDLs off + * the heap. + */ + + mdl_zone = uma_zcreate("Windows MDL", MDL_ZONE_SIZE, + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + return(0); } @@ -210,7 +233,6 @@ int ntoskrnl_libfini() { image_patch_table *patch; - mtx_destroy(&ntoskrnl_dispatchlock); patch = ntoskrnl_functbl; while (patch->ipt_func != NULL) { @@ -218,6 +240,10 @@ ntoskrnl_libfini() patch++; } + uma_zdestroy(mdl_zone); + + mtx_destroy(&ntoskrnl_dispatchlock); + return(0); } @@ -418,6 +444,8 @@ IoCreateDevice(drv, devextlen, devname, devtype, devchars, exclusive, newdev) ExFreePool(dev); return(STATUS_INSUFFICIENT_RESOURCES); } + + bzero(dev->do_devext, devextlen); } else dev->do_devext = NULL; @@ -531,7 +559,14 @@ IoBuildSynchronousFsdRequest(func, dobj, buf, len, off, event, status) nt_kevent *event; io_status_block *status; { - return(NULL); + irp *ip; + + ip = IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status); + if (ip == NULL) + return(NULL); + ip->irp_usrevent = event; + + return(ip); } __stdcall static irp * @@ -543,7 +578,66 @@ IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status) uint64_t *off; io_status_block *status; { - return(NULL); + irp *ip; + io_stack_location *sl; + + ip = IoAllocateIrp(dobj->do_stacksize, TRUE); + if (ip == NULL) + return(NULL); + + ip->irp_usriostat = status; + ip->irp_tail.irp_overlay.irp_thread = NULL; + + sl = IoGetNextIrpStackLocation(ip); + sl->isl_major = func; + sl->isl_minor = 0; + sl->isl_flags = 0; + sl->isl_ctl = 0; + sl->isl_devobj = dobj; + sl->isl_fileobj = NULL; + sl->isl_completionfunc = NULL; + + ip->irp_userbuf = buf; + + if (dobj->do_flags & DO_BUFFERED_IO) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, len, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return(NULL); + } + bcopy(buf, ip->irp_assoc.irp_sysbuf, len); + } + + if (dobj->do_flags & DO_DIRECT_IO) { + ip->irp_mdl = IoAllocateMdl(buf, len, FALSE, FALSE, ip); + if (ip->irp_mdl == NULL) { + if (ip->irp_assoc.irp_sysbuf != NULL) + ExFreePool(ip->irp_assoc.irp_sysbuf); + IoFreeIrp(ip); + return(NULL); + } + ip->irp_userbuf = NULL; + ip->irp_assoc.irp_sysbuf = NULL; + } + + if (func == IRP_MJ_READ) { + sl->isl_parameters.isl_read.isl_len = len; + if (off != NULL) + sl->isl_parameters.isl_read.isl_byteoff = *off; + else + sl->isl_parameters.isl_read.isl_byteoff = 0; + } + + if (func == IRP_MJ_WRITE) { + sl->isl_parameters.isl_write.isl_len = len; + if (off != NULL) + sl->isl_parameters.isl_write.isl_byteoff = *off; + else + sl->isl_parameters.isl_write.isl_byteoff = 0; + } + + return(ip); } __stdcall static irp * @@ -559,7 +653,87 @@ IoBuildDeviceIoControlRequest(iocode, dobj, ibuf, ilen, obuf, olen, nt_kevent *event; io_status_block *status; { - return (NULL); + irp *ip; + io_stack_location *sl; + uint32_t buflen; + + ip = IoAllocateIrp(dobj->do_stacksize, TRUE); + if (ip == NULL) + return(NULL); + ip->irp_usrevent = event; + ip->irp_usriostat = status; + ip->irp_tail.irp_overlay.irp_thread = NULL; + + sl = IoGetNextIrpStackLocation(ip); + sl->isl_major = isinternal == TRUE ? + IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; + sl->isl_minor = 0; + sl->isl_flags = 0; + sl->isl_ctl = 0; + sl->isl_devobj = dobj; + sl->isl_fileobj = NULL; + sl->isl_completionfunc = NULL; + sl->isl_parameters.isl_ioctl.isl_iocode = iocode; + sl->isl_parameters.isl_ioctl.isl_ibuflen = ilen; + sl->isl_parameters.isl_ioctl.isl_obuflen = olen; + + switch(IO_METHOD(iocode)) { + case METHOD_BUFFERED: + if (ilen > olen) + buflen = ilen; + else + buflen = olen; + if (buflen) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, buflen, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return(NULL); + } + } + if (ilen && ibuf != NULL) { + bcopy(ibuf, ip->irp_assoc.irp_sysbuf, ilen); + bzero((char *)ip->irp_assoc.irp_sysbuf + ilen, + buflen - ilen); + } else + bzero(ip->irp_assoc.irp_sysbuf, ilen); + ip->irp_userbuf = obuf; + break; + case METHOD_IN_DIRECT: + case METHOD_OUT_DIRECT: + if (ilen && ibuf != NULL) { + ip->irp_assoc.irp_sysbuf = + ExAllocatePoolWithTag(NonPagedPool, ilen, 0); + if (ip->irp_assoc.irp_sysbuf == NULL) { + IoFreeIrp(ip); + return(NULL); + } + bcopy(ibuf, ip->irp_assoc.irp_sysbuf, ilen); + } + if (olen && obuf != NULL) { + ip->irp_mdl = IoAllocateMdl(obuf, olen, + FALSE, FALSE, ip); + /* + * Normally we would MmProbeAndLockPages() + * here, but we don't have to in our + * imlementation. + */ + } + break; + case METHOD_NEITHER: + ip->irp_userbuf = obuf; + sl->isl_parameters.isl_ioctl.isl_type3ibuf = ibuf; + break; + default: + break; + } + + /* + * Ideally, we should associate this IRP with the calling + * thread here. + */ + + return (ip); } __stdcall static irp * @@ -575,7 +749,7 @@ IoAllocateIrp(stsize, chargequota) IoInitializeIrp(i, IoSizeOfIrp(stsize), stsize); - return (NULL); + return (i); } __stdcall static irp * @@ -613,7 +787,7 @@ IoInitializeIrp(io, psize, ssize) uint16_t psize; uint8_t ssize; { - bzero((char *)io, sizeof(irp)); + bzero((char *)io, IoSizeOfIrp(ssize)); io->irp_size = psize; io->irp_stackcnt = ssize; io->irp_currentstackloc = ssize; @@ -639,6 +813,38 @@ IoReuseIrp(ip, status) return; } +__stdcall void +IoAcquireCancelSpinLock(irql) + uint8_t *irql; +{ + KeAcquireSpinLock(&ntoskrnl_cancellock, irql); + return; +} + +__stdcall void +IoReleaseCancelSpinLock(irql) + uint8_t irql; +{ + KeReleaseSpinLock(&ntoskrnl_cancellock, irql); + return; +} + +__stdcall uint8_t +IoCancelIrp(irp *ip) +{ + cancel_func cfunc; + + IoAcquireCancelSpinLock(&ip->irp_cancelirql); + cfunc = IoSetCancelRoutine(ip, NULL); + ip->irp_cancel = TRUE; + if (ip->irp_cancelfunc == NULL) { + IoReleaseCancelSpinLock(ip->irp_cancelirql); + return(FALSE); + } + MSCALL2(cfunc, IoGetCurrentIrpStackLocation(ip)->isl_devobj, ip); + return(TRUE); +} + __fastcall uint32_t IofCallDriver(REGARGS2(device_object *dobj, irp *ip)) { @@ -658,7 +864,7 @@ IofCallDriver(REGARGS2(device_object *dobj, irp *ip)) sl->isl_devobj = dobj; disp = drvobj->dro_dispatch[sl->isl_major]; - status = disp(dobj, ip); + status = MSCALL2(disp, dobj, ip); return(status); } @@ -691,7 +897,7 @@ IofCompleteRequest(REGARGS2(irp *ip, uint8_t prioboost)) (ip->irp_cancel == TRUE && sl->isl_ctl & SL_INVOKE_ON_CANCEL))) { cf = sl->isl_completionfunc; - status = cf(dobj, ip, sl->isl_completionctx); + status = MSCALL3(cf, dobj, ip, sl->isl_completionctx); if (status == STATUS_MORE_PROCESSING_REQUIRED) return; } @@ -747,12 +953,10 @@ IoAttachDeviceToDeviceStack(src, dst) device_object *attached; mtx_lock(&ntoskrnl_dispatchlock); - attached = IoGetAttachedDevice(dst); attached->do_attacheddev = src; src->do_attacheddev = NULL; src->do_stacksize = attached->do_stacksize + 1; - mtx_unlock(&ntoskrnl_dispatchlock); return(attached); @@ -788,6 +992,7 @@ IoDetachDevice(topdev) return; } +/* Always called with dispatcher lock held. */ static void ntoskrnl_wakeup(arg) void *arg; @@ -799,7 +1004,6 @@ ntoskrnl_wakeup(arg) obj = arg; - mtx_lock(&ntoskrnl_dispatchlock); obj->dh_sigstate = TRUE; e = obj->dh_waitlisthead.nle_flink; while (e != &obj->dh_waitlisthead) { @@ -814,7 +1018,6 @@ ntoskrnl_wakeup(arg) break; e = e->nle_flink; } - mtx_unlock(&ntoskrnl_dispatchlock); return; } @@ -962,13 +1165,9 @@ KeWaitForSingleObject(obj, reason, mode, alertable, duetime) } } - mtx_unlock(&ntoskrnl_dispatchlock); - - error = ndis_thsuspend(td->td_proc, + error = ndis_thsuspend(td->td_proc, &ntoskrnl_dispatchlock, duetime == NULL ? 0 : tvtohz(&tv)); - mtx_lock(&ntoskrnl_dispatchlock); - /* We timed out. Leave the object alone and return status. */ if (error == EWOULDBLOCK) { @@ -1093,12 +1292,10 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode, while (wcnt) { nanotime(&t1); - mtx_unlock(&ntoskrnl_dispatchlock); - error = ndis_thsuspend(td->td_proc, + error = ndis_thsuspend(td->td_proc, &ntoskrnl_dispatchlock, duetime == NULL ? 0 : tvtohz(&tv)); - mtx_lock(&ntoskrnl_dispatchlock); nanotime(&t2); for (i = 0; i < cnt; i++) { @@ -1308,6 +1505,33 @@ ntoskrnl_popsl(head) return(first); } +/* + * We need this to make lookaside lists work for amd64. + * We pass a pointer to ExAllocatePoolWithTag() the lookaside + * list structure. For amd64 to work right, this has to be a + * pointer to the wrapped version of the routine, not the + * original. Letting the Windows driver invoke the original + * function directly will result in a convention calling + * mismatch and a pretty crash. On x86, this effectively + * becomes a no-op since ipt_func and ipt_wrap are the same. + */ + +static funcptr +ntoskrnl_findwrap(func) + funcptr func; +{ + image_patch_table *patch; + + patch = ntoskrnl_functbl; + while (patch->ipt_func != NULL) { + if ((funcptr)patch->ipt_func == func) + return((funcptr)patch->ipt_wrap); + patch++; + } + + return(NULL); +} + __stdcall static void ExInitializePagedLookasideList(lookaside, allocfunc, freefunc, flags, size, tag, depth) @@ -1327,18 +1551,23 @@ ExInitializePagedLookasideList(lookaside, allocfunc, freefunc, lookaside->nll_l.gl_size = size; lookaside->nll_l.gl_tag = tag; if (allocfunc == NULL) - lookaside->nll_l.gl_allocfunc = ExAllocatePoolWithTag; + lookaside->nll_l.gl_allocfunc = + ntoskrnl_findwrap((funcptr)ExAllocatePoolWithTag); else lookaside->nll_l.gl_allocfunc = allocfunc; if (freefunc == NULL) - lookaside->nll_l.gl_freefunc = ExFreePool; + lookaside->nll_l.gl_freefunc = + ntoskrnl_findwrap((funcptr)ExFreePool); else lookaside->nll_l.gl_freefunc = freefunc; +#ifdef __i386__ KeInitializeSpinLock(&lookaside->nll_obsoletelock); +#endif - lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH; + lookaside->nll_l.gl_type = NonPagedPool; + lookaside->nll_l.gl_depth = depth; lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH; return; @@ -1377,18 +1606,23 @@ ExInitializeNPagedLookasideList(lookaside, allocfunc, freefunc, lookaside->nll_l.gl_size = size; lookaside->nll_l.gl_tag = tag; if (allocfunc == NULL) - lookaside->nll_l.gl_allocfunc = ExAllocatePoolWithTag; + lookaside->nll_l.gl_allocfunc = + ntoskrnl_findwrap((funcptr)ExAllocatePoolWithTag); else lookaside->nll_l.gl_allocfunc = allocfunc; if (freefunc == NULL) - lookaside->nll_l.gl_freefunc = ExFreePool; + lookaside->nll_l.gl_freefunc = + ntoskrnl_findwrap((funcptr)ExFreePool); else lookaside->nll_l.gl_freefunc = freefunc; +#ifdef __i386__ KeInitializeSpinLock(&lookaside->nll_obsoletelock); +#endif - lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH; + lookaside->nll_l.gl_type = NonPagedPool; + lookaside->nll_l.gl_depth = depth; lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH; return; @@ -1465,6 +1699,20 @@ ExInterlockedPopEntrySList(REGARGS2(slist_header *head, kspin_lock *lock)) return(first); } +__stdcall static uint16_t +ExQueryDepthSList(head) + slist_header *head; +{ + uint16_t depth; + uint8_t irql; + + KeAcquireSpinLock(&ntoskrnl_global, &irql); + depth = head->slh_list.slh_depth; + KeReleaseSpinLock(&ntoskrnl_global, irql); + + return(depth); +} + /* * The KeInitializeSpinLock(), KefAcquireSpinLockAtDpcLevel() * and KefReleaseSpinLockFromDpcLevel() appear to be analagous @@ -1481,6 +1729,7 @@ KeInitializeSpinLock(lock) return; } +#ifdef __i386__ __fastcall void KefAcquireSpinLockAtDpcLevel(REGARGS1(kspin_lock *lock)) { @@ -1498,6 +1747,52 @@ KefReleaseSpinLockFromDpcLevel(REGARGS1(kspin_lock *lock)) return; } +__stdcall uint8_t +KeAcquireSpinLockRaiseToDpc(kspin_lock *lock) +{ + uint8_t oldirql; + + if (KeGetCurrentIrql() > DISPATCH_LEVEL) + panic("IRQL_NOT_LESS_THAN_OR_EQUAL"); + + oldirql = KeRaiseIrql(DISPATCH_LEVEL); + KeAcquireSpinLockAtDpcLevel(lock); + + return(oldirql); +} +#else +__stdcall void +KeAcquireSpinLockAtDpcLevel(kspin_lock *lock) +{ + while (atomic_cmpset_acq_int((volatile u_int *)lock, 0, 1) == 0) + /* sit and spin */; + + return; +} + +__stdcall void +KeReleaseSpinLockFromDpcLevel(kspin_lock *lock) +{ + atomic_store_rel_int((volatile u_int *)lock, 0); + + return; +} +#endif /* __i386__ */ + +__fastcall uintptr_t +InterlockedExchange(REGARGS2(volatile uint32_t *dst, uintptr_t val)) +{ + uint8_t irql; + uintptr_t r; + + KeAcquireSpinLock(&ntoskrnl_global, &irql); + r = *dst; + *dst = val; + KeReleaseSpinLock(&ntoskrnl_global, irql); + + return(r); +} + __fastcall static uint32_t InterlockedIncrement(REGARGS1(volatile uint32_t *addend)) { @@ -1533,15 +1828,30 @@ IoAllocateMdl(vaddr, len, secondarybuf, chargequota, iopkt) irp *iopkt; { mdl *m; + int zone = 0; - m = ExAllocatePoolWithTag(NonPagedPool, - MmSizeOfMdl(vaddr, len), 0); + if (MmSizeOfMdl(vaddr, len) > MDL_ZONE_SIZE) + m = ExAllocatePoolWithTag(NonPagedPool, + MmSizeOfMdl(vaddr, len), 0); + else { + m = uma_zalloc(mdl_zone, M_NOWAIT | M_ZERO); + zone++; + } if (m == NULL) return (NULL); MmInitializeMdl(m, vaddr, len); + /* + * MmInitializMdl() clears the flags field, so we + * have to set this here. If the MDL came from the + * MDL UMA zone, tag it so we can release it to + * the right place later. + */ + if (zone) + m->mdl_flags = MDL_ZONE_ALLOCED; + if (iopkt != NULL) { if (secondarybuf == TRUE) { mdl *last; @@ -1566,7 +1876,10 @@ IoFreeMdl(m) if (m == NULL) return; - free (m, M_DEVBUF); + if (m->mdl_flags & MDL_ZONE_ALLOCED) + uma_zfree(mdl_zone, m); + else + ExFreePool(m); return; } @@ -1884,10 +2197,9 @@ KeReleaseMutex(kmutex, kwait) kmutex->km_acquirecnt--; if (kmutex->km_acquirecnt == 0) { kmutex->km_ownerthread = NULL; - mtx_unlock(&ntoskrnl_dispatchlock); ntoskrnl_wakeup(&kmutex->km_header); - } else - mtx_unlock(&ntoskrnl_dispatchlock); + } + mtx_unlock(&ntoskrnl_dispatchlock); return(kmutex->km_acquirecnt); } @@ -1934,8 +2246,10 @@ KeSetEvent(kevent, increment, kwait) { uint32_t prevstate; + mtx_lock(&ntoskrnl_dispatchlock); prevstate = kevent->k_header.dh_sigstate; ntoskrnl_wakeup(&kevent->k_header); + mtx_unlock(&ntoskrnl_dispatchlock); return(prevstate); } @@ -2070,12 +2384,14 @@ PsTerminateSystemThread(status) { struct nt_objref *nr; + mtx_lock(&ntoskrnl_dispatchlock); TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) { if (nr->no_obj != curthread->td_proc) continue; ntoskrnl_wakeup(&nr->no_dh); break; } + mtx_unlock(&ntoskrnl_dispatchlock); ntoskrnl_kth--; @@ -2119,6 +2435,8 @@ ntoskrnl_timercall(arg) mtx_unlock(&Giant); + mtx_lock(&ntoskrnl_dispatchlock); + timer = arg; timer->k_header.dh_inserted = FALSE; @@ -2136,14 +2454,15 @@ ntoskrnl_timercall(arg) tv.tv_sec = 0; tv.tv_usec = timer->k_period * 1000; timer->k_header.dh_inserted = TRUE; - timer->k_handle = - timeout(ntoskrnl_timercall, timer, tvtohz(&tv)); + timer->k_handle = timeout(ntoskrnl_timercall, + timer, tvtohz(&tv)); } if (timer->k_dpc != NULL) KeInsertQueueDpc(timer->k_dpc, NULL, NULL); ntoskrnl_wakeup(&timer->k_header); + mtx_unlock(&ntoskrnl_dispatchlock); mtx_lock(&Giant); @@ -2210,17 +2529,12 @@ KeInitializeDpc(dpc, dpcfunc, dpcctx) void *dpcfunc; void *dpcctx; { - uint8_t irql; if (dpc == NULL) return; - KeInitializeSpinLock(&dpc->k_lock); - - KeAcquireSpinLock(&dpc->k_lock, &irql); dpc->k_deferedfunc = dpcfunc; dpc->k_deferredctx = dpcctx; - KeReleaseSpinLock(&dpc->k_lock, irql); return; } @@ -2231,12 +2545,8 @@ KeInsertQueueDpc(dpc, sysarg1, sysarg2) void *sysarg1; void *sysarg2; { - uint8_t irql; - - KeAcquireSpinLock(&dpc->k_lock, &irql); dpc->k_sysarg1 = sysarg1; dpc->k_sysarg2 = sysarg2; - KeReleaseSpinLock(&dpc->k_lock, irql); if (ndis_sched(ntoskrnl_run_dpc, dpc, NDIS_SWI)) return(FALSE); @@ -2268,6 +2578,8 @@ KeSetTimerEx(timer, duetime, period, dpc) if (timer == NULL) return(FALSE); + mtx_lock(&ntoskrnl_dispatchlock); + if (timer->k_header.dh_inserted == TRUE) { untimeout(ntoskrnl_timercall, timer, timer->k_handle); timer->k_header.dh_inserted = FALSE; @@ -2298,6 +2610,8 @@ KeSetTimerEx(timer, duetime, period, dpc) timer->k_header.dh_inserted = TRUE; timer->k_handle = timeout(ntoskrnl_timercall, timer, tvtohz(&tv)); + mtx_unlock(&ntoskrnl_dispatchlock); + return(pending); } @@ -2319,14 +2633,15 @@ KeCancelTimer(timer) if (timer == NULL) return(FALSE); + mtx_lock(&ntoskrnl_dispatchlock); + if (timer->k_header.dh_inserted == TRUE) { untimeout(ntoskrnl_timercall, timer, timer->k_handle); - if (timer->k_dpc != NULL) - KeRemoveQueueDpc(timer->k_dpc); pending = TRUE; } else - pending = FALSE; + pending = KeRemoveQueueDpc(timer->k_dpc); + mtx_unlock(&ntoskrnl_dispatchlock); return(pending); } @@ -2376,6 +2691,9 @@ image_patch_table ntoskrnl_functbl[] = { IMPORT_FUNC(IoGetDriverObjectExtension), IMPORT_FUNC(IofCallDriver), IMPORT_FUNC(IofCompleteRequest), + IMPORT_FUNC(IoAcquireCancelSpinLock), + IMPORT_FUNC(IoReleaseCancelSpinLock), + IMPORT_FUNC(IoCancelIrp), IMPORT_FUNC(IoCreateDevice), IMPORT_FUNC(IoDeleteDevice), IMPORT_FUNC(IoGetAttachedDevice), @@ -2417,11 +2735,30 @@ image_patch_table ntoskrnl_functbl[] = { IMPORT_FUNC(ExDeleteNPagedLookasideList), IMPORT_FUNC(InterlockedPopEntrySList), IMPORT_FUNC(InterlockedPushEntrySList), + IMPORT_FUNC(ExQueryDepthSList), + IMPORT_FUNC_MAP(ExpInterlockedPopEntrySList, InterlockedPopEntrySList), + IMPORT_FUNC_MAP(ExpInterlockedPushEntrySList, + InterlockedPushEntrySList), IMPORT_FUNC(ExInterlockedPopEntrySList), IMPORT_FUNC(ExInterlockedPushEntrySList), + IMPORT_FUNC(ExAllocatePoolWithTag), + IMPORT_FUNC(ExFreePool), +#ifdef __i386__ IMPORT_FUNC(KefAcquireSpinLockAtDpcLevel), IMPORT_FUNC(KefReleaseSpinLockFromDpcLevel), + IMPORT_FUNC(KeAcquireSpinLockRaiseToDpc), +#else + /* + * For AMD64, we can get away with just mapping + * KeAcquireSpinLockRaiseToDpc() directly to KfAcquireSpinLock() + * because the calling conventions end up being the same. + * On i386, we have to be careful because KfAcquireSpinLock() + * is _fastcall but KeAcquireSpinLockRaiseToDpc() isn't. + */ + IMPORT_FUNC(KeAcquireSpinLockAtDpcLevel), + IMPORT_FUNC(KeReleaseSpinLockFromDpcLevel), IMPORT_FUNC_MAP(KeAcquireSpinLockRaiseToDpc, KfAcquireSpinLock), +#endif IMPORT_FUNC_MAP(KeReleaseSpinLock, KfReleaseSpinLock), IMPORT_FUNC(InterlockedIncrement), IMPORT_FUNC(InterlockedDecrement), diff --git a/sys/compat/ndis/subr_pe.c b/sys/compat/ndis/subr_pe.c index 5a8d897ffb7ca..a3f5071ebe169 100644 --- a/sys/compat/ndis/subr_pe.c +++ b/sys/compat/ndis/subr_pe.c @@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$"); #include <sys/errno.h> #ifdef _KERNEL #include <sys/systm.h> +extern int ndis_strncasecmp(const char *, const char *, size_t); +#define strncasecmp(a, b, c) ndis_strncasecmp(a, b, c) #else #include <stdio.h> #include <stdlib.h> @@ -431,6 +433,8 @@ pe_relocate(imgbase) * may be linked against several modules, typically HAL.dll, ntoskrnl.exe * and NDIS.SYS. For each module, there is a list of imported function * names and their addresses. + * + * Note: module names are case insensitive! */ int @@ -455,7 +459,7 @@ pe_get_import_descriptor(imgbase, desc, module) while (imp_desc->iid_nameaddr) { modname = (char *)pe_translate_addr(imgbase, imp_desc->iid_nameaddr); - if (!strncmp(module, modname, strlen(module))) { + if (!strncasecmp(module, modname, strlen(module))) { bcopy((char *)imp_desc, (char *)desc, sizeof(image_import_descriptor)); return(0); |