summaryrefslogtreecommitdiff
path: root/sys/compat
diff options
context:
space:
mode:
authorBill Paul <wpaul@FreeBSD.org>2005-03-31 04:24:36 +0000
committerBill Paul <wpaul@FreeBSD.org>2005-03-31 04:24:36 +0000
commitd7ff03e4305179f2c13b822008e76b58661fa732 (patch)
treed43a34518774bb6f0a7a4719a077116838c2bc17 /sys/compat
parent61f79baa158601a67920814b3c333750f9eb0291 (diff)
Notes
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/ndis/kern_ndis.c240
-rw-r--r--sys/compat/ndis/kern_windrv.c59
-rw-r--r--sys/compat/ndis/ndis_var.h56
-rw-r--r--sys/compat/ndis/ntoskrnl_var.h113
-rw-r--r--sys/compat/ndis/subr_hal.c8
-rw-r--r--sys/compat/ndis/subr_ndis.c188
-rw-r--r--sys/compat/ndis/subr_ntoskrnl.c429
-rw-r--r--sys/compat/ndis/subr_pe.c6
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);