summaryrefslogtreecommitdiffstats
path: root/sys/compat
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/ndis/kern_ndis.c142
-rw-r--r--sys/compat/ndis/kern_windrv.c56
-rw-r--r--sys/compat/ndis/ndis_var.h119
-rw-r--r--sys/compat/ndis/ntoskrnl_var.h142
-rw-r--r--sys/compat/ndis/subr_hal.c108
-rw-r--r--sys/compat/ndis/subr_ndis.c555
-rw-r--r--sys/compat/ndis/subr_ntoskrnl.c1286
-rw-r--r--sys/compat/ndis/winx32_wrap.S24
8 files changed, 1688 insertions, 744 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
index 573d78f..97f63f7 100644
--- a/sys/compat/ndis/kern_ndis.c
+++ b/sys/compat/ndis/kern_ndis.c
@@ -82,7 +82,7 @@ static void ndis_setdone_func(ndis_handle, ndis_status);
static void ndis_getdone_func(ndis_handle, ndis_status);
static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
static void ndis_sendrsrcavail_func(ndis_handle);
-static void ndis_intrhand(kdpc *, device_object *,
+static void ndis_intrsetup(kdpc *, device_object *,
irp *, struct ndis_softc *);
static void ndis_return(kdpc *, void *, void *, void *);
@@ -93,7 +93,7 @@ static image_patch_table kernndis_functbl[] = {
IMPORT_SFUNC(ndis_getdone_func, 2),
IMPORT_SFUNC(ndis_resetdone_func, 3),
IMPORT_SFUNC(ndis_sendrsrcavail_func, 1),
- IMPORT_SFUNC(ndis_intrhand, 4),
+ IMPORT_SFUNC(ndis_intrsetup, 4),
IMPORT_SFUNC(ndis_return, 1),
{ NULL, NULL, NULL }
@@ -183,34 +183,6 @@ ndis_modevent(module_t mod, int cmd, void *arg)
DEV_MODULE(ndisapi, ndis_modevent, NULL);
MODULE_VERSION(ndisapi, 1);
-int
-ndis_thsuspend(p, m, timo)
- struct proc *p;
- struct mtx *m;
- int timo;
-{
- int error;
-
- 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);
-}
-
-void
-ndis_thresume(p)
- struct proc *p;
-{
- wakeup(&p->p_siglist);
- return;
-}
-
static void
ndis_sendrsrcavail_func(adapter)
ndis_handle adapter;
@@ -328,7 +300,6 @@ ndis_create_sysctls(arg)
#endif
/* Add the driver-specific registry keys. */
- vals = sc->ndis_regvals;
while(1) {
if (vals->nc_cfgkey == NULL)
break;
@@ -358,17 +329,8 @@ ndis_create_sysctls(arg)
continue;
}
-#if __FreeBSD_version < 502113
- SYSCTL_ADD_STRING(&sc->ndis_ctx,
- SYSCTL_CHILDREN(sc->ndis_tree),
-#else
- SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
-#endif
- OID_AUTO, vals->nc_cfgkey,
- CTLFLAG_RW, vals->nc_val,
- sizeof(vals->nc_val),
- vals->nc_cfgdesc);
+ ndis_add_sysctl(sc, vals->nc_cfgkey, vals->nc_cfgdesc,
+ vals->nc_val, CTLFLAG_RW);
vals++;
}
@@ -420,8 +382,10 @@ ndis_add_sysctl(arg, key, desc, val, flag)
cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
- if (cfg == NULL)
+ if (cfg == NULL) {
+ printf("failed for %s\n", key);
return(ENOMEM);
+ }
cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
if (desc == NULL) {
@@ -433,6 +397,7 @@ ndis_add_sysctl(arg, key, desc, val, flag)
TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
+ cfg->ndis_oid =
#if __FreeBSD_version < 502113
SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
#else
@@ -446,18 +411,34 @@ ndis_add_sysctl(arg, key, desc, val, flag)
return(0);
}
+/*
+ * Somewhere, somebody decided "hey, let's automatically create
+ * a sysctl tree for each device instance as it's created -- it'll
+ * make life so much easier!" Lies. Why must they turn the kernel
+ * into a house of lies?
+ */
+
int
ndis_flush_sysctls(arg)
void *arg;
{
struct ndis_softc *sc;
struct ndis_cfglist *cfg;
+ struct sysctl_ctx_list *clist;
sc = arg;
+#if __FreeBSD_version < 502113
+ clist = &sc->ndis_ctx;
+#else
+ clist = device_get_sysctl_ctx(sc->ndis_dev);
+#endif
+
while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
+ sysctl_ctx_entry_del(clist, cfg->ndis_oid);
+ sysctl_remove_oid(cfg->ndis_oid, 1, 0);
free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
free(cfg, M_DEVBUF);
@@ -488,9 +469,11 @@ ndis_return(dpc, arg, sysarg1, sysarg2)
returnfunc = sc->ndis_chars->nmc_return_packet_func;
- KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+ if (NDIS_SERIALIZED(sc->ndis_block))
+ KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
MSCALL2(returnfunc, adapter, p);
- KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+ if (NDIS_SERIALIZED(sc->ndis_block))
+ KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
return;
}
@@ -691,10 +674,13 @@ ndis_ptom(m0, p)
struct mbuf **m0;
ndis_packet *p;
{
- struct mbuf *m, *prev = NULL;
+ struct mbuf *m = NULL, *prev = NULL;
ndis_buffer *buf;
ndis_packet_private *priv;
uint32_t totlen = 0;
+ struct ifnet *ifp;
+ struct ether_header *eh;
+ int diff;
if (p == NULL || m0 == NULL)
return(EINVAL);
@@ -718,6 +704,7 @@ ndis_ptom(m0, p)
MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
p, 0, EXT_NDIS);
p->np_refcnt++;
+
totlen += m->m_len;
if (m->m_flags & M_PKTHDR)
*m0 = m;
@@ -726,6 +713,24 @@ ndis_ptom(m0, p)
prev = m;
}
+ /*
+ * This is a hack to deal with the Marvell 8335 driver
+ * which, when associated with an AP in WPA-PSK mode,
+ * seems to overpad its frames by 8 bytes. I don't know
+ * that the extra 8 bytes are for, and they're not there
+ * in open mode, so for now clamp the frame size at 1514
+ * until I can figure out how to deal with this properly,
+ * otherwise if_ethersubr() will spank us by discarding
+ * the 'oversize' frames.
+ */
+
+ eh = mtod((*m0), struct ether_header *);
+ ifp = ((struct ndis_softc *)p->np_softc)->ifp;
+ if (totlen > ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE)) {
+ diff = totlen - ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE);
+ totlen -= diff;
+ m->m_len -= diff;
+ }
(*m0)->m_pkthdr.len = totlen;
return(0);
@@ -770,6 +775,7 @@ ndis_mtop(m0, p)
*p = NULL;
return(ENOMEM);
}
+ MmBuildMdlForNonPagedPool(buf);
if (priv->npp_head == NULL)
priv->npp_head = buf;
@@ -875,7 +881,6 @@ ndis_set_info(arg, oid, buf, buflen)
rval = sc->ndis_block->nmb_setstat;
}
-
if (byteswritten)
*buflen = byteswritten;
if (bytesneeded)
@@ -1080,7 +1085,7 @@ ndis_reset_nic(arg)
return(0);
}
-#define NDIS_REAP_TIMERS
+#undef NDIS_REAP_TIMERS
int
ndis_halt_nic(arg)
@@ -1112,9 +1117,9 @@ ndis_halt_nic(arg)
n->nmt_nexttimer = NULL;
}
sc->ndis_block->nmb_timerlist = NULL;
+#endif
if (!cold)
KeFlushQueuedDpcs();
-#endif
NDIS_LOCK(sc);
adapter = sc->ndis_block->nmb_miniportadapterctx;
@@ -1123,7 +1128,6 @@ ndis_halt_nic(arg)
return(EIO);
}
- sc->ndis_block->nmb_miniportadapterctx = NULL;
sc->ndis_block->nmb_devicectx = NULL;
/*
@@ -1137,6 +1141,10 @@ ndis_halt_nic(arg)
MSCALL1(haltfunc, adapter);
+ NDIS_LOCK(sc);
+ sc->ndis_block->nmb_miniportadapterctx = NULL;
+ NDIS_UNLOCK(sc);
+
return(0);
}
@@ -1216,7 +1224,7 @@ ndis_init_nic(arg)
* expects them to fire before the halt is called.
*/
- ndis_thsuspend(curthread->td_proc, NULL, hz);
+ tsleep(curthread->td_proc, PWAIT, "ndwait", hz);
NDIS_LOCK(sc);
sc->ndis_block->nmb_devicectx = sc;
@@ -1292,33 +1300,26 @@ ndis_isr(arg, ourintr, callhandler)
}
static void
-ndis_intrhand(dpc, dobj, ip, sc)
+ndis_intrsetup(dpc, dobj, ip, sc)
kdpc *dpc;
device_object *dobj;
irp *ip;
struct ndis_softc *sc;
{
- ndis_handle adapter;
- ndis_interrupt_handler intrfunc;
- uint8_t irql;
-
- adapter = sc->ndis_block->nmb_miniportadapterctx;
- intrfunc = sc->ndis_chars->nmc_interrupt_func;
-
- if (adapter == NULL || intrfunc == NULL)
- return;
-
- if (NDIS_SERIALIZED(sc->ndis_block))
- KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
+ ndis_miniport_interrupt *intr;
- MSCALL1(intrfunc, adapter);
+ intr = sc->ndis_block->nmb_interrupt;
- /* If there's a MiniportEnableInterrupt() routine, call it. */
+ /* Sanity check. */
- ndis_enable_intr(sc);
+ if (intr == NULL)
+ return;
- if (NDIS_SERIALIZED(sc->ndis_block))
- KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
+ KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
+ KeResetEvent(&intr->ni_dpcevt);
+ if (KeInsertQueueDpc(&intr->ni_dpc, NULL, NULL) == TRUE)
+ intr->ni_dpccnt++;
+ KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
return;
}
@@ -1424,6 +1425,7 @@ NdisAddDevice(drv, pdo)
block->nmb_physdeviceobj = pdo;
block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo);
KeInitializeSpinLock(&block->nmb_lock);
+ InitializeListHead(&block->nmb_parmlist);
/*
* Stash pointers to the miniport block and miniport
@@ -1447,7 +1449,7 @@ NdisAddDevice(drv, pdo)
IoDeleteDevice(fdo);
return(status);
}
- INIT_LIST_HEAD((&block->nmb_packetlist));
+ InitializeListHead((&block->nmb_packetlist));
}
/* Give interrupt handling priority over timers. */
diff --git a/sys/compat/ndis/kern_windrv.c b/sys/compat/ndis/kern_windrv.c
index 90c977b..9202911 100644
--- a/sys/compat/ndis/kern_windrv.c
+++ b/sys/compat/ndis/kern_windrv.c
@@ -137,8 +137,8 @@ windrv_libfini(void)
}
mtx_unlock(&drvdb_mtx);
- free(fake_pci_driver.dro_drivername.us_buf, M_DEVBUF);
- free(fake_pccard_driver.dro_drivername.us_buf, M_DEVBUF);
+ RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
+ RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
mtx_destroy(&drvdb_mtx);
@@ -161,16 +161,16 @@ windrv_lookup(img, name)
{
struct drvdb_ent *d;
unicode_string us;
+ ansi_string as;
bzero((char *)&us, sizeof(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);
+ RtlInitAnsiString(&as, name);
+ if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
+ return(NULL);
}
mtx_lock(&drvdb_mtx);
@@ -187,7 +187,7 @@ windrv_lookup(img, name)
mtx_unlock(&drvdb_mtx);
if (name != NULL)
- ExFreePool(us.us_buf);
+ RtlFreeUnicodeString(&us);
return(NULL);
}
@@ -230,7 +230,7 @@ windrv_unload(mod, img, len)
driver_object *drv;
device_object *d, *pdo;
device_t dev;
- list_entry *e, *c;
+ list_entry *e;
drv = windrv_lookup(img, NULL);
@@ -267,7 +267,7 @@ windrv_unload(mod, img, len)
mtx_lock(&drvdb_mtx);
}
}
-
+
STAILQ_FOREACH(db, &drvdb_head, link) {
if (db->windrv_object->dro_driverstart == (void *)img) {
r = db;
@@ -280,23 +280,23 @@ windrv_unload(mod, img, len)
if (r == NULL)
return (ENOENT);
+ if (drv == NULL)
+ return(ENOENT);
+
/*
* Destroy any custom extensions that may have been added.
*/
drv = r->windrv_object;
- e = drv->dro_driverext->dre_usrext.nle_flink;
- while (e != &drv->dro_driverext->dre_usrext) {
- c = e->nle_flink;
- REMOVE_LIST_ENTRY(e);
+ while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
+ e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
ExFreePool(e);
- e = c;
}
/* Free the driver extension */
free(drv->dro_driverext, M_DEVBUF);
/* Free the driver name */
- free(drv->dro_drivername.us_buf, M_DEVBUF);
+ RtlFreeUnicodeString(&drv->dro_drivername);
/* Free driver object */
free(drv, M_DEVBUF);
@@ -330,6 +330,7 @@ windrv_load(mod, img, len, bustype, devlist, regvals)
struct driver_object *drv;
int status;
uint32_t *ptr;
+ ansi_string as;
/*
* First step: try to relocate and dynalink the executable
@@ -396,16 +397,17 @@ skipreloc:
return(ENOMEM);
}
- INIT_LIST_HEAD((&drv->dro_driverext->dre_usrext));
+ InitializeListHead((&drv->dro_driverext->dre_usrext));
drv->dro_driverstart = (void *)img;
drv->dro_driversize = len;
- 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,
- &drv->dro_drivername.us_buf);
+ RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
+ if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
+ free(new, M_DEVBUF);
+ free(drv, M_DEVBUF);
+ return(ENOMEM);
+ }
new->windrv_object = drv;
new->windrv_regvals = regvals;
@@ -417,7 +419,7 @@ skipreloc:
status = MSCALL2(entry, drv, &drv->dro_drivername);
if (status != STATUS_SUCCESS) {
- free(drv->dro_drivername.us_buf, M_DEVBUF);
+ RtlFreeUnicodeString(&drv->dro_drivername);
free(drv, M_DEVBUF);
free(new, M_DEVBUF);
return(ENODEV);
@@ -517,15 +519,15 @@ windrv_bus_attach(drv, name)
char *name;
{
struct drvdb_ent *new;
+ ansi_string as;
new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
if (new == NULL)
return (ENOMEM);
- drv->dro_drivername.us_len = strlen(name) * 2;
- drv->dro_drivername.us_maxlen = strlen(name) * 2;
- drv->dro_drivername.us_buf = NULL;
- ndis_ascii_to_unicode(name, &drv->dro_drivername.us_buf);
+ RtlInitAnsiString(&as, name);
+ if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
+ return(ENOMEM);
/*
* Set up a fake image pointer to avoid false matches
@@ -674,7 +676,7 @@ ctxsw_utow(void)
* hasn't, we need to do it right now or else things will
* explode.
*/
-
+
if (t->tid_self != t)
x86_newldt(NULL);
diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h
index 742fae2..4fd7106 100644
--- a/sys/compat/ndis/ndis_var.h
+++ b/sys/compat/ndis/ndis_var.h
@@ -268,6 +268,31 @@ typedef uint8_t ndis_kirql;
#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105
#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
+/*
+ * These are the possible power states for
+ * OID_PNP_SET_POWER and OID_PNP_QUERY_POWER.
+ */
+#define NDIS_POWERSTATE_UNSPEC 0
+#define NDIS_POWERSTATE_D0 1
+#define NDIS_POWERSTATE_D1 2
+#define NDIS_POWERSTATE_D2 3
+#define NDIS_POWERSTATE_D3 4
+
+/*
+ * These are used with the MiniportPnpEventNotify() method.
+ */
+
+#define NDIS_POWERPROFILE_BATTERY 0
+#define NDIS_POWERPROFILE_ACONLINE 1
+
+#define NDIS_PNP_EVENT_QUERY_REMOVED 0
+#define NDIS_PNP_EVENT_REMOVED 1
+#define NDIS_PNP_EVENT_SURPRISE_REMOVED 2
+#define NDIS_PNP_EVENT_QUERY_STOPPED 3
+#define NDIS_PNP_EVENT_STOPPED 4
+#define NDIS_PNP_EVENT_PROFILECHANGED 5
+
+
/* PnP/PM Statistics (Optional). */
#define OID_PNP_WAKE_UP_OK 0xFD020200
#define OID_PNP_WAKE_UP_ERROR 0xFD020201
@@ -310,6 +335,8 @@ typedef uint8_t ndis_kirql;
#define OID_802_11_REMOVE_KEY 0x0D01011E
#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F
#define OID_802_11_TEST 0x0D010120
+#define OID_802_11_CAPABILITY 0x0D010122
+#define OID_802_11_PMKID 0x0D010123
/* structures/definitions for 802.11 */
#define NDIS_80211_NETTYPE_11FH 0x00000000
@@ -390,6 +417,8 @@ typedef struct ndis_80211_wep ndis_80211_wep;
#define NDIS_80211_AUTHMODE_WPA 0x00000003
#define NDIS_80211_AUTHMODE_WPAPSK 0x00000004
#define NDIS_80211_AUTHMODE_WPANONE 0x00000005
+#define NDIS_80211_AUTHMODE_WPA2 0x00000006
+#define NDIS_80211_AUTHMODE_WPA2PSK 0x00000007
typedef uint8_t ndis_80211_rates[8];
typedef uint8_t ndis_80211_rates_ex[16];
@@ -483,6 +512,7 @@ typedef uint32_t ndis_80211_antenna;
#define NDIS_80211_RELOADDEFAULT_WEP 0x00000000
#define NDIS_80211_STATUSTYPE_AUTH 0x00000000
+#define NDIS_80211_STATUSTYPE_PMKIDLIST 0x00000001
struct ndis_80211_status_indication {
uint32_t nsi_type;
@@ -490,6 +520,11 @@ struct ndis_80211_status_indication {
typedef struct ndis_80211_status_indication ndis_80211_status_indication;
+#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
+
struct ndis_80211_auth_request {
uint32_t nar_len;
ndis_80211_macaddr nar_bssid;
@@ -503,8 +538,9 @@ struct ndis_80211_key {
uint32_t nk_keyidx;
uint32_t nk_keylen;
ndis_80211_macaddr nk_bssid;
+ uint8_t nk_pad[6];
uint64_t nk_keyrsc;
- uint8_t nk_keydata[256];
+ uint8_t nk_keydata[32];
};
typedef struct ndis_80211_key ndis_80211_key;
@@ -573,6 +609,61 @@ struct ndis_80211_test {
typedef struct ndis_80211_test ndis_80211_test;
+struct ndis_80211_auth_encrypt {
+ uint32_t ne_authmode;
+ uint32_t ne_cryptstat;
+};
+
+typedef struct ndis_80211_auth_encrypt ndis_80211_auth_encrypt;
+
+struct ndis_80211_caps {
+ uint32_t nc_len;
+ uint32_t nc_ver;
+ uint32_t nc_numpmkids;
+ ndis_80211_auth_encrypt nc_authencs[1];
+};
+
+typedef struct ndis_80211_caps ndis_80211_caps;
+
+struct ndis_80211_bssidinfo {
+ ndis_80211_macaddr nb_bssid;
+ uint8_t nb_pmkid[16];
+};
+
+typedef struct ndis_80211_bssidinfo ndis_80211_bssidinfo;
+
+struct ndis_80211_pmkid {
+ uint32_t np_len;
+ uint32_t np_bssidcnt;
+ ndis_80211_bssidinfo np_bssidinfo[1];
+};
+
+typedef struct ndis_80211_pmkid ndis_80211_pmkid;
+
+struct ndis_80211_pmkid_cand {
+ ndis_80211_macaddr npc_bssid;
+ uint32_t npc_flags;
+};
+
+typedef struct ndis_80211_pmkid_cand ndis_80211_pmkid_cand;
+
+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED (0x01)
+
+struct ndis_80211_pmkid_candidate_list {
+ uint32_t npcl_version;
+ uint32_t npcl_numcandidates;
+ ndis_80211_pmkid_cand npcl_candidatelist[1];
+};
+
+typedef struct ndis_80211_pmkid_candidate_list ndis_80211_pmkid_candidate_list;
+
+struct ndis_80211_enc_indication {
+ uint32_t nei_statustype;
+ ndis_80211_pmkid_candidate_list nei_pmkidlist;
+};
+
+typedef struct ndis_80211_enc_indication ndis_80211_enc_indication;
+
/* TCP OIDs. */
#define OID_TCP_TASK_OFFLOAD 0xFC010201
@@ -682,6 +773,7 @@ typedef struct ndis_task_ipsec ndis_task_ipsec;
* all attributes.
*/
+#define NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT 0x00000001
#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002
#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004
#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008
@@ -805,8 +897,20 @@ struct ndis_config_parm {
} ncp_parmdata;
};
+/*
+ * Not part of Windows NDIS spec; we uses this to keep a
+ * list of ndis_config_parm structures that we've allocated.
+ */
+
typedef struct ndis_config_parm ndis_config_parm;
+struct ndis_parmlist_entry {
+ list_entry np_list;
+ ndis_config_parm np_parm;
+};
+
+typedef struct ndis_parmlist_entry ndis_parmlist_entry;
+
#ifdef notdef
struct ndis_list_entry {
struct ndis_list_entry *nle_flink;
@@ -952,16 +1056,16 @@ typedef struct ndis_request ndis_request;
* Filler, not used.
*/
struct ndis_miniport_interrupt {
- void *ni_introbj;
+ kinterrupt *ni_introbj;
ndis_kspin_lock ni_dpccountlock;
void *ni_rsvd;
void *ni_isrfunc;
void *ni_dpcfunc;
- struct ndis_kdpc ni_dpc;
+ kdpc ni_dpc;
ndis_miniport_block *ni_block;
uint8_t ni_dpccnt;
uint8_t ni_filler1;
- struct ndis_kevent ni_dpcsdoneevent;
+ struct nt_kevent ni_dpcevt;
uint8_t ni_shared;
uint8_t ni_isrreq;
};
@@ -1506,8 +1610,7 @@ struct ndis_miniport_block {
* End of windows-specific portion of miniport block. Everything
* below is BSD-specific.
*/
- uint8_t nmb_dummybuf[128];
- ndis_config_parm nmb_replyparm;
+ list_entry nmb_parmlist;
ndis_resource_list *nmb_rlist;
ndis_status nmb_getstat;
ndis_status nmb_setstat;
@@ -1600,8 +1703,6 @@ extern image_patch_table ndis_functbl[];
__BEGIN_DECLS
extern int ndis_libinit(void);
extern int ndis_libfini(void);
-extern int ndis_ascii_to_unicode(char *, uint16_t **);
-extern int ndis_unicode_to_ascii(uint16_t *, int, char **);
extern int ndis_load_driver(vm_offset_t, void *);
extern int ndis_unload_driver(void *);
extern int ndis_mtop(struct mbuf *, ndis_packet **);
@@ -1629,8 +1730,6 @@ extern int ndis_destroy_dma(void *);
extern int ndis_create_sysctls(void *);
extern int ndis_add_sysctl(void *, char *, char *, char *, int);
extern int ndis_flush_sysctls(void *);
-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 622a387..7a1f3af 100644
--- a/sys/compat/ndis/ntoskrnl_var.h
+++ b/sys/compat/ndis/ntoskrnl_var.h
@@ -48,6 +48,14 @@ struct unicode_string {
typedef struct unicode_string unicode_string;
+struct ansi_string {
+ uint16_t as_len;
+ uint16_t as_maxlen;
+ char *as_buf;
+};
+
+typedef struct ansi_string ansi_string;
+
/*
* Windows memory descriptor list. In Windows, it's possible for
* buffers to be passed between user and kernel contexts without
@@ -197,43 +205,54 @@ struct list_entry {
typedef struct list_entry list_entry;
-#define INIT_LIST_HEAD(l) \
+#define InitializeListHead(l) \
(l)->nle_flink = (l)->nle_blink = (l)
-#define REMOVE_LIST_ENTRY(e) \
+#define IsListEmpty(h) \
+ ((h)->nle_flink == (h))
+
+#define RemoveEntryList(e) \
do { \
list_entry *b; \
list_entry *f; \
\
- f = e->nle_flink; \
- b = e->nle_blink; \
+ f = (e)->nle_flink; \
+ b = (e)->nle_blink; \
b->nle_flink = f; \
f->nle_blink = b; \
} while (0)
-#define REMOVE_LIST_HEAD(l) \
- do { \
- list_entry *f; \
- list_entry *e; \
- \
- e = l->nle_flink; \
- f = e->nle_flink; \
- l->nle_flink = f; \
- f->nle_blink = l; \
- } while (0)
+/* These two have to be inlined since they return things. */
-#define REMOVE_LIST_TAIL(l) \
- do { \
- list_entry *b; \
- list_entry *e; \
- \
- e = l->nle_blink; \
- b = e->nle_blink; \
- l->nle_blink = b; \
- b->nle_flink = l; \
- } while (0)
+static __inline__ list_entry *
+RemoveHeadList(list_entry *l)
+{
+ list_entry *f;
+ list_entry *e;
+
+ e = l->nle_flink;
+ f = e->nle_flink;
+ l->nle_flink = f;
+ f->nle_blink = l;
+
+ return (e);
+}
+
+static __inline__ list_entry *
+RemoveTailList(list_entry *l)
+{
+ list_entry *b;
+ list_entry *e;
+
+ e = l->nle_blink;
+ b = e->nle_blink;
+ l->nle_blink = b;
+ b->nle_flink = l;
-#define INSERT_LIST_TAIL(l, e) \
+ return (e);
+}
+
+#define InsertTailList(l, e) \
do { \
list_entry *b; \
\
@@ -244,7 +263,7 @@ typedef struct list_entry list_entry;
l->nle_blink = (e); \
} while (0)
-#define INSERT_LIST_HEAD(l, e) \
+#define InsertHeadList(l, e) \
do { \
list_entry *f; \
\
@@ -263,12 +282,24 @@ struct nt_dispatch_header {
uint8_t dh_abs;
uint8_t dh_size;
uint8_t dh_inserted;
- uint32_t dh_sigstate;
+ int32_t dh_sigstate;
list_entry dh_waitlisthead;
};
typedef struct nt_dispatch_header nt_dispatch_header;
+/* Dispatcher object types */
+
+#define DISP_TYPE_NOTIFICATION_EVENT 0 /* KEVENT */
+#define DISP_TYPE_SYNCHRONIZATION_EVENT 1 /* KEVENT */
+#define DISP_TYPE_MUTANT 2 /* KMUTANT/KMUTEX */
+#define DISP_TYPE_PROCESS 3 /* KPROCESS */
+#define DISP_TYPE_QUEUE 4 /* KQUEUE */
+#define DISP_TYPE_SEMAPHORE 5 /* KSEMAPHORE */
+#define DISP_TYPE_THREAD 6 /* KTHREAD */
+#define DISP_TYPE_NOTIFICATION_TIMER 8 /* KTIMER */
+#define DISP_TYPE_SYNCHRONIZATION_TIMER 9 /* KTIMER */
+
#define OTYPE_EVENT 0
#define OTYPE_MUTEX 1
#define OTYPE_THREAD 2
@@ -334,14 +365,14 @@ struct ktimer {
uint64_t k_duetime;
union {
list_entry k_timerlistentry;
- struct callout_handle k_handle;
+ struct callout *k_callout;
} u;
void *k_dpc;
uint32_t k_period;
};
#define k_timerlistentry u.k_timerlistentry
-#define k_handle u.k_handle
+#define k_callout u.k_callout
typedef struct ktimer ktimer;
@@ -389,18 +420,12 @@ typedef struct kdpc kdpc;
*/
struct kmutant {
nt_dispatch_header km_header;
- union {
- list_entry km_listentry;
- uint32_t km_acquirecnt;
- } u;
+ list_entry km_listentry;
void *km_ownerthread;
uint8_t km_abandoned;
uint8_t km_apcdisable;
};
-#define km_listentry u.km_listentry
-#define km_acquirecnt u.km_acquirecnt
-
typedef struct kmutant kmutant;
#define LOOKASIDE_DEPTH 256
@@ -485,18 +510,28 @@ struct wait_block {
void *wb_kthread;
nt_dispatch_header *wb_object;
struct wait_block *wb_next;
+#ifdef notdef
uint16_t wb_waitkey;
uint16_t wb_waittype;
+#endif
+ uint8_t wb_waitkey;
+ uint8_t wb_waittype;
+ uint8_t wb_awakened;
+ uint8_t wb_oldpri;
};
typedef struct wait_block wait_block;
+#define wb_ext wb_kthread
+
#define THREAD_WAIT_OBJECTS 3
#define MAX_WAIT_OBJECTS 64
#define WAITTYPE_ALL 0
#define WAITTYPE_ANY 1
+#define WAITKEY_VALID 0x8000
+
struct thread_context {
void *tc_thrctx;
void *tc_thrfunc;
@@ -533,6 +568,23 @@ struct custom_extension {
typedef struct custom_extension custom_extension;
/*
+ * The KINTERRUPT structure in Windows is opaque to drivers.
+ * We define our own custom version with things we need.
+ */
+
+struct kinterrupt {
+ device_t ki_dev;
+ void *ki_cookie;
+ struct resource *ki_irq;
+ kspin_lock ki_lock_priv;
+ kspin_lock *ki_lock;
+ void *ki_svcfunc;
+ void *ki_svcctx;
+};
+
+typedef struct kinterrupt kinterrupt;
+
+/*
* In Windows, there are Physical Device Objects (PDOs) and
* Functional Device Objects (FDOs). Physical Device Objects are
* created and maintained by bus drivers. For example, the PCI
@@ -1199,7 +1251,7 @@ typedef struct work_queue_item work_queue_item;
do { \
(w)->wqi_func = (func); \
(w)->wqi_ctx = (ctx); \
- INIT_LIST_HEAD(&((w)->wqi_entry)); \
+ InitializeListHead(&((w)->wqi_entry)); \
} while (0); \
@@ -1251,6 +1303,16 @@ extern void ctxsw_wtou(void);
extern int ntoskrnl_libinit(void);
extern int ntoskrnl_libfini(void);
+
+extern uint32_t RtlUnicodeStringToAnsiString(ansi_string *,
+ unicode_string *, uint8_t);
+extern uint32_t RtlAnsiStringToUnicodeString(unicode_string *,
+ ansi_string *, uint8_t);
+extern void RtlInitAnsiString(ansi_string *, char *);
+extern void RtlInitUnicodeString(unicode_string *,
+ uint16_t *);
+extern void RtlFreeUnicodeString(unicode_string *);
+extern void RtlFreeAnsiString(ansi_string *);
extern void KeInitializeDpc(kdpc *, void *, void *);
extern uint8_t KeInsertQueueDpc(kdpc *, void *, void *);
extern uint8_t KeRemoveQueueDpc(kdpc *);
@@ -1280,10 +1342,16 @@ extern void KeAcquireSpinLockAtDpcLevel(kspin_lock *);
extern void KeReleaseSpinLockFromDpcLevel(kspin_lock *);
#endif
extern void KeInitializeSpinLock(kspin_lock *);
+extern uint8_t KeSynchronizeExecution(kinterrupt *, void *, void *);
extern uintptr_t InterlockedExchange(volatile uint32_t *,
uintptr_t);
extern void *ExAllocatePoolWithTag(uint32_t, size_t, uint32_t);
extern void ExFreePool(void *);
+extern uint32_t IoConnectInterrupt(kinterrupt **, void *, void *,
+ kspin_lock *, uint32_t, uint8_t, uint8_t, uint8_t, uint8_t,
+ uint32_t, uint8_t);
+extern void MmBuildMdlForNonPagedPool(mdl *);
+extern void IoDisconnectInterrupt(kinterrupt *);
extern uint32_t IoAllocateDriverObjectExtension(driver_object *,
void *, uint32_t, void **);
extern void *IoGetDriverObjectExtension(driver_object *, void *);
diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c
index ca8f009..fa376bf 100644
--- a/sys/compat/ndis/subr_hal.c
+++ b/sys/compat/ndis/subr_hal.c
@@ -80,12 +80,18 @@ static void READ_PORT_BUFFER_UCHAR(uint8_t *,
static uint64_t KeQueryPerformanceCounter(uint64_t *);
static void dummy (void);
-extern struct mtx_pool *ndis_mtxpool;
+#define NDIS_MAXCPUS 64
+static struct mtx disp_lock[NDIS_MAXCPUS];
int
hal_libinit()
{
image_patch_table *patch;
+ int i;
+
+ for (i = 0; i < NDIS_MAXCPUS; i++)
+ mtx_init(&disp_lock[i], "HAL preemption lock",
+ "HAL lock", MTX_RECURSE|MTX_DEF);
patch = hal_functbl;
while (patch->ipt_func != NULL) {
@@ -95,6 +101,7 @@ hal_libinit()
patch++;
}
+
return(0);
}
@@ -102,6 +109,10 @@ int
hal_libfini()
{
image_patch_table *patch;
+ int i;
+
+ for (i = 0; i < NDIS_MAXCPUS; i++)
+ mtx_destroy(&disp_lock[i]);
patch = hal_functbl;
while (patch->ipt_func != NULL) {
@@ -285,6 +296,72 @@ READ_PORT_BUFFER_UCHAR(port, val, cnt)
* KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If
* we detect someone trying to acquire a spinlock from DEVICE_LEVEL
* or HIGH_LEVEL, we panic.
+ *
+ * Alternate sleep-lock-based spinlock implementation
+ * --------------------------------------------------
+ *
+ * The earlier spinlock implementation was arguably a bit of a hack
+ * and presented several problems. It was basically designed to provide
+ * the functionality of spinlocks without incurring the wrath of
+ * WITNESS. We could get away with using both our spinlock implementation
+ * and FreeBSD sleep locks at the same time, but if WITNESS knew what
+ * we were really up to, it would have spanked us rather severely.
+ *
+ * There's another method we can use based entirely on sleep locks.
+ * First, it's important to realize that everything we're locking
+ * resides inside Project Evil itself: any critical data being locked
+ * by drivers belongs to the drivers, and should not be referenced
+ * by any other OS code outside of the NDISulator. The priority-based
+ * locking scheme has system-wide effects, just like real spinlocks
+ * (blocking preemption affects the whole CPU), but since we keep all
+ * our critical data private, we can use a simpler mechanism that
+ * affects only code/threads directly related to Project Evil.
+ *
+ * The idea is to create a sleep lock mutex for each CPU in the system.
+ * When a CPU running in the NDISulator wants to acquire a spinlock, it
+ * does the following:
+ * - Pin ourselves to the current CPU
+ * - Acquire the mutex for the current CPU
+ * - Spin on the spinlock variable using atomic test and set, just like
+ * a real spinlock.
+ * - Once we have the lock, we execute our critical code
+ *
+ * To give up the lock, we do:
+ * - Clear the spinlock variable with an atomic op
+ * - Release the per-CPU mutex
+ * - Unpin ourselves from the current CPU.
+ *
+ * On a uniprocessor system, this means all threads that access protected
+ * data are serialized through the per-CPU mutex. After one thread
+ * acquires the 'spinlock,' any other thread that uses a spinlock on the
+ * current CPU will block on the per-CPU mutex, which has the same general
+ * effect of blocking pre-emption, but _only_ for those threads that are
+ * running NDISulator code.
+ *
+ * On a multiprocessor system, threads on different CPUs all block on
+ * their respective per-CPU mutex, and the atomic test/set operation
+ * on the spinlock variable provides inter-CPU synchronization, though
+ * only for threads running NDISulator code.
+ *
+ * This method solves an important problem. In Windows, you're allowed
+ * to do an ExAllocatePoolWithTag() with a spinlock held, provided you
+ * allocate from NonPagedPool. This implies an atomic heap allocation
+ * that will not cause the current thread to sleep. (You can't sleep
+ * while holding real spinlock: clowns will eat you.) But in FreeBSD,
+ * malloc(9) _always_ triggers the acquisition of a sleep lock, even
+ * when you use M_NOWAIT. This is not a problem for FreeBSD native
+ * code: you're allowed to sleep in things like interrupt threads. But
+ * it is a problem with the old priority-based spinlock implementation:
+ * even though we get away with it most of the time, we really can't
+ * do a malloc(9) after doing a KeAcquireSpinLock() or KeRaiseIrql().
+ * With the new implementation, it's not a problem: you're allowed to
+ * acquire more than one sleep lock (as long as you avoid lock order
+ * reversals).
+ *
+ * The one drawback to this approach is that now we have a lot of
+ * contention on one per-CPU mutex within the NDISulator code. Whether
+ * or not this is preferable to the expected Windows spinlock behavior
+ * of blocking pre-emption is debatable.
*/
uint8_t
@@ -314,10 +391,10 @@ KfReleaseSpinLock(lock, newirql)
return;
}
- uint8_t
+uint8_t
KeGetCurrentIrql()
{
- if (AT_DISPATCH_LEVEL(curthread))
+ if (mtx_owned(&disp_lock[curthread->td_oncpu]))
return(DISPATCH_LEVEL);
return(PASSIVE_LEVEL);
}
@@ -338,19 +415,14 @@ KfRaiseIrql(irql)
{
uint8_t oldirql;
- if (irql < KeGetCurrentIrql())
+ oldirql = KeGetCurrentIrql();
+ if (irql < oldirql)
panic("IRQL_NOT_LESS_THAN");
- if (KeGetCurrentIrql() == DISPATCH_LEVEL)
- return(DISPATCH_LEVEL);
-
- mtx_lock_spin(&sched_lock);
- oldirql = curthread->td_base_pri;
- sched_prio(curthread, PI_REALTIME);
-#if __FreeBSD_version < 600000
- curthread->td_base_pri = PI_REALTIME;
-#endif
- mtx_unlock_spin(&sched_lock);
+ if (oldirql != DISPATCH_LEVEL) {
+ sched_pin();
+ mtx_lock(&disp_lock[curthread->td_oncpu]);
+ }
return(oldirql);
}
@@ -365,12 +437,8 @@ KfLowerIrql(oldirql)
if (KeGetCurrentIrql() != DISPATCH_LEVEL)
panic("IRQL_NOT_GREATER_THAN");
- mtx_lock_spin(&sched_lock);
-#if __FreeBSD_version < 600000
- curthread->td_base_pri = oldirql;
-#endif
- sched_prio(curthread, oldirql);
- mtx_unlock_spin(&sched_lock);
+ mtx_unlock(&disp_lock[curthread->td_oncpu]);
+ sched_unpin();
return;
}
diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c
index 5dfe8e5..7813515 100644
--- a/sys/compat/ndis/subr_ndis.c
+++ b/sys/compat/ndis/subr_ndis.c
@@ -104,6 +104,13 @@ __FBSDID("$FreeBSD$");
#include <compat/ndis/ndis_var.h>
#include <dev/if_ndis/if_ndisvar.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/uma.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+
static char ndis_filepath[MAXPATHLEN];
extern struct nd_head ndis_devhead;
@@ -124,17 +131,17 @@ static ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle,
static void NdisOpenConfiguration(ndis_status *,
ndis_handle *, ndis_handle);
static void NdisOpenConfigurationKeyByIndex(ndis_status *,
- ndis_handle, uint32_t, ndis_unicode_string *, ndis_handle *);
+ ndis_handle, uint32_t, unicode_string *, ndis_handle *);
static void NdisOpenConfigurationKeyByName(ndis_status *,
- ndis_handle, ndis_unicode_string *, ndis_handle *);
+ ndis_handle, unicode_string *, ndis_handle *);
static ndis_status ndis_encode_parm(ndis_miniport_block *,
struct sysctl_oid *, ndis_parm_type, ndis_config_parm **);
static ndis_status ndis_decode_parm(ndis_miniport_block *,
ndis_config_parm *, char *);
static void NdisReadConfiguration(ndis_status *, ndis_config_parm **,
- ndis_handle, ndis_unicode_string *, ndis_parm_type);
+ ndis_handle, unicode_string *, ndis_parm_type);
static void NdisWriteConfiguration(ndis_status *, ndis_handle,
- ndis_unicode_string *, ndis_config_parm *);
+ unicode_string *, ndis_config_parm *);
static void NdisCloseConfiguration(ndis_handle);
static void NdisAllocateSpinLock(ndis_spin_lock *);
static void NdisFreeSpinLock(ndis_spin_lock *);
@@ -213,11 +220,10 @@ static void NdisInitializeEvent(ndis_event *);
static void NdisSetEvent(ndis_event *);
static void NdisResetEvent(ndis_event *);
static uint8_t NdisWaitEvent(ndis_event *, uint32_t);
-static ndis_status NdisUnicodeStringToAnsiString(ndis_ansi_string *,
- ndis_unicode_string *);
+static ndis_status NdisUnicodeStringToAnsiString(ansi_string *,
+ unicode_string *);
static ndis_status
- NdisAnsiStringToUnicodeString(ndis_unicode_string *,
- ndis_ansi_string *);
+ NdisAnsiStringToUnicodeString(unicode_string *, ansi_string *);
static ndis_status NdisMPciAssignResources(ndis_handle,
uint32_t, ndis_resource_list **);
static ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *,
@@ -248,11 +254,10 @@ static uint8_t
void *, void *);
static void NdisGetCurrentSystemTime(uint64_t *);
static void NdisGetSystemUpTime(uint32_t *);
-static void NdisInitializeString(ndis_unicode_string *, char *);
-static void NdisInitAnsiString(ndis_ansi_string *, char *);
-static void NdisInitUnicodeString(ndis_unicode_string *,
- uint16_t *);
-static void NdisFreeString(ndis_unicode_string *);
+static void NdisInitializeString(unicode_string *, char *);
+static void NdisInitAnsiString(ansi_string *, char *);
+static void NdisInitUnicodeString(unicode_string *, uint16_t *);
+static void NdisFreeString(unicode_string *);
static ndis_status NdisMRemoveMiniport(ndis_handle *);
static void NdisTerminateWrapper(ndis_handle, void *);
static void NdisMGetDeviceProperty(ndis_handle, device_object **,
@@ -264,7 +269,7 @@ static void NdisGetFirstBufferFromPacketSafe(ndis_packet *,
ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t);
static int ndis_find_sym(linker_file_t, char *, char *, caddr_t *);
static void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *,
- ndis_unicode_string *, ndis_physaddr);
+ unicode_string *, ndis_physaddr);
static void NdisMapFile(ndis_status *, void **, ndis_handle);
static void NdisUnmapFile(ndis_handle);
static void NdisCloseFile(ndis_handle);
@@ -272,18 +277,19 @@ static uint8_t NdisSystemProcessorCount(void);
static void NdisMIndicateStatusComplete(ndis_handle);
static void NdisMIndicateStatus(ndis_handle, ndis_status,
void *, uint32_t);
+static void ndis_intr(void *);
+static void ndis_intrhand(kdpc *, ndis_miniport_interrupt *, void *, void *);
static funcptr ndis_findwrap(funcptr);
static void NdisCopyFromPacketToPacket(ndis_packet *,
uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *);
static void NdisCopyFromPacketToPacketSafe(ndis_packet *,
uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t);
static ndis_status NdisMRegisterDevice(ndis_handle,
- ndis_unicode_string *, ndis_unicode_string *, driver_dispatch **,
+ unicode_string *, unicode_string *, driver_dispatch **,
void **, ndis_handle *);
static ndis_status NdisMDeregisterDevice(ndis_handle);
static ndis_status
- NdisMQueryAdapterInstanceName(ndis_unicode_string *,
- ndis_handle);
+ NdisMQueryAdapterInstanceName(unicode_string *, ndis_handle);
static void NdisMRegisterUnloadHandler(ndis_handle, void *);
static void dummy(void);
@@ -346,57 +352,6 @@ ndis_findwrap(func)
}
/*
- * NDIS deals with strings in unicode format, so we have
- * do deal with them that way too. For now, we only handle
- * conversion between unicode and ASCII since that's all
- * that device drivers care about.
- */
-
-int
-ndis_ascii_to_unicode(ascii, unicode)
- char *ascii;
- uint16_t **unicode;
-{
- uint16_t *ustr;
- int i;
-
- if (*unicode == NULL)
- *unicode = malloc(strlen(ascii) * 2, M_DEVBUF, M_NOWAIT);
-
- if (*unicode == NULL)
- return(ENOMEM);
- ustr = *unicode;
- for (i = 0; i < strlen(ascii); i++) {
- *ustr = (uint16_t)ascii[i];
- ustr++;
- }
-
- return(0);
-}
-
-int
-ndis_unicode_to_ascii(unicode, ulen, ascii)
- uint16_t *unicode;
- int ulen;
- char **ascii;
-{
- uint8_t *astr;
- int i;
-
- if (*ascii == NULL)
- *ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_NOWAIT|M_ZERO);
- if (*ascii == NULL)
- return(ENOMEM);
- astr = *ascii;
- for (i = 0; i < ulen / 2; i++) {
- *astr = (uint8_t)unicode[i];
- astr++;
- }
-
- return(0);
-}
-
-/*
* This routine does the messy Windows Driver Model device attachment
* stuff on behalf of NDIS drivers. We register our own AddDevice
* routine here
@@ -465,8 +420,10 @@ NdisMRegisterMiniport(handle, characteristics, len)
if (IoAllocateDriverObjectExtension(drv, (void *)1,
sizeof(ndis_miniport_characteristics), (void **)&ch) !=
- STATUS_SUCCESS)
+ STATUS_SUCCESS) {
+ printf("register error\n");
return(NDIS_STATUS_RESOURCES);
+ }
bzero((char *)ch, sizeof(ndis_miniport_characteristics));
@@ -489,10 +446,10 @@ NdisAllocateMemoryWithTag(vaddr, len, tag)
{
void *mem;
-
mem = ExAllocatePoolWithTag(NonPagedPool, len, tag);
- if (mem == NULL)
+ if (mem == NULL) {
return(NDIS_STATUS_RESOURCES);
+ }
*vaddr = mem;
return(NDIS_STATUS_SUCCESS);
@@ -568,7 +525,7 @@ static void
NdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle)
ndis_status *status;
ndis_handle cfg;
- ndis_unicode_string *subkey;
+ unicode_string *subkey;
ndis_handle *subhandle;
{
*subhandle = cfg;
@@ -582,7 +539,7 @@ NdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle)
ndis_status *status;
ndis_handle cfg;
uint32_t idx;
- ndis_unicode_string *subkey;
+ unicode_string *subkey;
ndis_handle *subhandle;
{
*status = NDIS_STATUS_FAILURE;
@@ -597,36 +554,58 @@ ndis_encode_parm(block, oid, type, parm)
ndis_parm_type type;
ndis_config_parm **parm;
{
- uint16_t *unicode;
- ndis_unicode_string *ustr;
+ ndis_config_parm *p;
+ ndis_parmlist_entry *np;
+ unicode_string *us;
+ ansi_string as;
int base = 0;
+ uint32_t val;
+ char tmp[32];
- unicode = (uint16_t *)&block->nmb_dummybuf;
+ np = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(ndis_parmlist_entry), 0);
+ if (np == NULL)
+ return(NDIS_STATUS_RESOURCES);
+ InsertHeadList((&block->nmb_parmlist), (&np->np_list));
+ *parm = p = &np->np_parm;
switch(type) {
case ndis_parm_string:
- ndis_ascii_to_unicode((char *)oid->oid_arg1, &unicode);
- (*parm)->ncp_type = ndis_parm_string;
- ustr = &(*parm)->ncp_parmdata.ncp_stringdata;
- ustr->us_len = strlen((char *)oid->oid_arg1) * 2;
- ustr->us_buf = unicode;
+ /* See if this might be a number. */
+ val = strtoul((char *)oid->oid_arg1, NULL, 10);
+ us = &p->ncp_parmdata.ncp_stringdata;
+ p->ncp_type = ndis_parm_string;
+ if (val) {
+ snprintf(tmp, 32, "%x", val);
+ RtlInitAnsiString(&as, tmp);
+ } else {
+ RtlInitAnsiString(&as, (char *)oid->oid_arg1);
+ }
+
+ if (RtlAnsiStringToUnicodeString(us, &as, TRUE)) {
+ ExFreePool(np);
+ return(NDIS_STATUS_RESOURCES);
+ }
break;
case ndis_parm_int:
if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
base = 16;
else
base = 10;
- (*parm)->ncp_type = ndis_parm_int;
- (*parm)->ncp_parmdata.ncp_intdata =
+ p->ncp_type = ndis_parm_int;
+ p->ncp_parmdata.ncp_intdata =
strtol((char *)oid->oid_arg1, NULL, base);
break;
case ndis_parm_hexint:
+#ifdef notdef
if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
base = 16;
else
base = 10;
- (*parm)->ncp_type = ndis_parm_hexint;
- (*parm)->ncp_parmdata.ncp_intdata =
+#endif
+ base = 16;
+ p->ncp_type = ndis_parm_hexint;
+ p->ncp_parmdata.ncp_intdata =
strtoul((char *)oid->oid_arg1, NULL, base);
break;
default:
@@ -689,15 +668,15 @@ NdisReadConfiguration(status, parm, cfg, key, type)
ndis_status *status;
ndis_config_parm **parm;
ndis_handle cfg;
- ndis_unicode_string *key;
+ unicode_string *key;
ndis_parm_type type;
{
char *keystr = NULL;
- uint16_t *unicode;
ndis_miniport_block *block;
struct ndis_softc *sc;
struct sysctl_oid *oidp;
struct sysctl_ctx_entry *e;
+ ansi_string as;
block = (ndis_miniport_block *)cfg;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
@@ -707,10 +686,12 @@ NdisReadConfiguration(status, parm, cfg, key, type)
return;
}
- ndis_unicode_to_ascii(key->us_buf, key->us_len, &keystr);
- *parm = &block->nmb_replyparm;
- bzero((char *)&block->nmb_replyparm, sizeof(ndis_config_parm));
- unicode = (uint16_t *)&block->nmb_dummybuf;
+ if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
+ *status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ keystr = as.as_buf;
/*
* See if registry key is already in a list of known keys
@@ -724,12 +705,13 @@ NdisReadConfiguration(status, parm, cfg, key, type)
oidp = e->entry;
if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) {
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
*status = NDIS_STATUS_FAILURE;
return;
}
+
*status = ndis_encode_parm(block, oidp, type, parm);
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
return;
}
}
@@ -753,7 +735,7 @@ NdisReadConfiguration(status, parm, cfg, key, type)
ndis_add_sysctl(sc, keystr, "(dynamic string key)",
"UNSET", CTLFLAG_RW);
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
*status = NDIS_STATUS_FAILURE;
return;
@@ -765,15 +747,16 @@ ndis_decode_parm(block, parm, val)
ndis_config_parm *parm;
char *val;
{
- ndis_unicode_string *ustr;
- char *astr = NULL;
+ unicode_string *ustr;
+ ansi_string as;
switch(parm->ncp_type) {
case ndis_parm_string:
ustr = &parm->ncp_parmdata.ncp_stringdata;
- ndis_unicode_to_ascii(ustr->us_buf, ustr->us_len, &astr);
- bcopy(astr, val, 254);
- free(astr, M_DEVBUF);
+ if (RtlUnicodeStringToAnsiString(&as, ustr, TRUE))
+ return(NDIS_STATUS_RESOURCES);
+ bcopy(as.as_buf, val, as.as_len);
+ RtlFreeAnsiString(&as);
break;
case ndis_parm_int:
sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata);
@@ -792,9 +775,10 @@ static void
NdisWriteConfiguration(status, cfg, key, parm)
ndis_status *status;
ndis_handle cfg;
- ndis_unicode_string *key;
+ unicode_string *key;
ndis_config_parm *parm;
{
+ ansi_string as;
char *keystr = NULL;
ndis_miniport_block *block;
struct ndis_softc *sc;
@@ -805,13 +789,18 @@ NdisWriteConfiguration(status, cfg, key, parm)
block = (ndis_miniport_block *)cfg;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
- ndis_unicode_to_ascii(key->us_buf, key->us_len, &keystr);
+ if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
+ *status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ keystr = as.as_buf;
/* Decode the parameter into a string. */
bzero(val, sizeof(val));
*status = ndis_decode_parm(block, parm, val);
if (*status != NDIS_STATUS_SUCCESS) {
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
return;
}
@@ -826,7 +815,7 @@ NdisWriteConfiguration(status, cfg, key, parm)
if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
/* Found it, set the value. */
strcpy((char *)oidp->oid_arg1, val);
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
return;
}
}
@@ -835,7 +824,7 @@ NdisWriteConfiguration(status, cfg, key, parm)
ndis_add_sysctl(sc, keystr, "(dynamically set key)",
val, CTLFLAG_RW);
- free(keystr, M_DEVBUF);
+ RtlFreeAnsiString(&as);
*status = NDIS_STATUS_SUCCESS;
return;
}
@@ -844,6 +833,22 @@ static void
NdisCloseConfiguration(cfg)
ndis_handle cfg;
{
+ list_entry *e;
+ ndis_parmlist_entry *pe;
+ ndis_miniport_block *block;
+ ndis_config_parm *p;
+
+ block = (ndis_miniport_block *)cfg;
+
+ while (!IsListEmpty(&block->nmb_parmlist)) {
+ e = RemoveHeadList(&block->nmb_parmlist);
+ pe = CONTAINING_RECORD(e, ndis_parmlist_entry, np_list);
+ p = &pe->np_parm;
+ if (p->ncp_type == ndis_parm_string)
+ RtlFreeUnicodeString(&p->ncp_parmdata.ncp_stringdata);
+ ExFreePool(e);
+ }
+
return;
}
@@ -1038,6 +1043,7 @@ NdisWritePciSlotInformation(adapter, slot, offset, buf, len)
* The errorlog routine uses a variable argument list, so we
* have to declare it this way.
*/
+
#define ERRMSGLEN 512
static void
NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
@@ -1046,13 +1052,15 @@ NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
ndis_miniport_block *block;
va_list ap;
int i, error;
- char *str = NULL, *ustr = NULL;
+ char *str = NULL;
uint16_t flags;
char msgbuf[ERRMSGLEN];
device_t dev;
driver_object *drv;
struct ndis_softc *sc;
struct ifnet *ifp;
+ unicode_string us;
+ ansi_string as;
block = (ndis_miniport_block *)adapter;
dev = block->nmb_physdeviceobj->do_devext;
@@ -1064,10 +1072,10 @@ NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
code, &str, &i, &flags);
if (error == 0 && flags & MESSAGE_RESOURCE_UNICODE &&
ifp->if_flags & IFF_DEBUG) {
- ustr = msgbuf;
- ndis_unicode_to_ascii((uint16_t *)str,
- ((i / 2)) > (ERRMSGLEN - 1) ? ERRMSGLEN : i, &ustr);
- str = ustr;
+ RtlInitUnicodeString(&us, (uint16_t *)msgbuf);
+ if (RtlUnicodeStringToAnsiString(&as, &us, TRUE))
+ return;
+ str = as.as_buf;
}
device_printf (dev, "NDIS ERROR: %x (%s)\n", code,
@@ -1082,6 +1090,9 @@ NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
va_end(ap);
}
+ if (str != NULL)
+ RtlFreeAnsiString(&as);
+
return;
}
@@ -1404,10 +1415,18 @@ NdisReadNetworkAddress(status, addr, addrlen, adapter)
block = (ndis_miniport_block *)adapter;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+#ifdef IFP2ENADDR
if (bcmp(IFP2ENADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0)
+#else
+ if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0)
+#endif
*status = NDIS_STATUS_FAILURE;
else {
+#ifdef IFP2ENADDR
*addr = IFP2ENADDR(sc->ifp);
+#else
+ *addr = sc->arpcom.ac_enaddr;
+#endif
*addrlen = ETHER_ADDR_LEN;
*status = NDIS_STATUS_SUCCESS;
}
@@ -1530,6 +1549,8 @@ NdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr)
if (sh == NULL)
return;
+ InitializeListHead(&sh->ndis_list);
+
/*
* When performing shared memory allocations, create a tag
* with a lowaddr limit that restricts physical memory mappings
@@ -1582,10 +1603,11 @@ NdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr)
* searching based on the virtual address fails.
*/
+ NDIS_LOCK(sc);
sh->ndis_paddr.np_quad = paddr->np_quad;
sh->ndis_saddr = *vaddr;
- sh->ndis_next = sc->ndis_shlist;
- sc->ndis_shlist = sh;
+ InsertHeadList((&sc->ndis_shlist), (&sh->ndis_list));
+ NDIS_UNLOCK(sc);
return;
}
@@ -1674,21 +1696,24 @@ NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr)
{
ndis_miniport_block *block;
struct ndis_softc *sc;
- struct ndis_shmem *sh, *prev;
+ struct ndis_shmem *sh = NULL;
+ list_entry *l;
if (vaddr == NULL || adapter == NULL)
return;
block = (ndis_miniport_block *)adapter;
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
- sh = prev = sc->ndis_shlist;
/* Sanity check: is list empty? */
- if (sh == NULL)
+ if (IsListEmpty(&sc->ndis_shlist))
return;
- while (sh) {
+ NDIS_LOCK(sc);
+ l = sc->ndis_shlist.nle_flink;
+ while (l != &sc->ndis_shlist) {
+ sh = CONTAINING_RECORD(l, struct ndis_shmem, ndis_list);
if (sh->ndis_saddr == vaddr)
break;
/*
@@ -1697,26 +1722,25 @@ NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr)
*/
if (sh->ndis_paddr.np_quad == paddr.np_quad)
break;
- prev = sh;
- sh = sh->ndis_next;
+ l = l->nle_flink;
}
if (sh == NULL) {
+ NDIS_UNLOCK(sc);
printf("NDIS: buggy driver tried to free "
"invalid shared memory: vaddr: %p paddr: 0x%jx\n",
vaddr, (uintmax_t)paddr.np_quad);
return;
}
+ RemoveEntryList(&sh->ndis_list);
+
+ NDIS_UNLOCK(sc);
+
bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap);
bus_dma_tag_destroy(sh->ndis_stag);
- if (sh == sc->ndis_shlist)
- sc->ndis_shlist = sh->ndis_next;
- else
- prev->ndis_next = sh->ndis_next;
-
free(sh, M_DEVBUF);
return;
@@ -2077,6 +2101,7 @@ NdisAllocateBufferPool(status, pool, descnum)
ndis_handle *pool;
uint32_t descnum;
{
+
/*
* The only thing we can really do here is verify that descnum
* is a reasonable value, but I really don't know what to check
@@ -2111,6 +2136,8 @@ NdisAllocateBuffer(status, buffer, pool, vaddr, len)
return;
}
+ MmBuildMdlForNonPagedPool(buf);
+
*buffer = buf;
*status = NDIS_STATUS_SUCCESS;
@@ -2260,37 +2287,35 @@ NdisWaitEvent(event, msecs)
static ndis_status
NdisUnicodeStringToAnsiString(dstr, sstr)
- ndis_ansi_string *dstr;
- ndis_unicode_string *sstr;
+ ansi_string *dstr;
+ unicode_string *sstr;
{
- if (dstr == NULL || sstr == NULL)
- return(NDIS_STATUS_FAILURE);
- if (ndis_unicode_to_ascii(sstr->us_buf,
- sstr->us_len, &dstr->nas_buf))
+ uint32_t rval;
+
+ rval = RtlUnicodeStringToAnsiString(dstr, sstr, FALSE);
+
+ if (rval == STATUS_INSUFFICIENT_RESOURCES)
+ return(NDIS_STATUS_RESOURCES);
+ if (rval)
return(NDIS_STATUS_FAILURE);
- dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf);
+
return (NDIS_STATUS_SUCCESS);
}
static ndis_status
NdisAnsiStringToUnicodeString(dstr, sstr)
- ndis_unicode_string *dstr;
- ndis_ansi_string *sstr;
+ unicode_string *dstr;
+ ansi_string *sstr;
{
- char *str;
- if (dstr == NULL || sstr == NULL)
- return(NDIS_STATUS_FAILURE);
- str = malloc(sstr->nas_len + 1, M_DEVBUF, M_NOWAIT);
- if (str == NULL)
- return(NDIS_STATUS_FAILURE);
- strncpy(str, sstr->nas_buf, sstr->nas_len);
- *(str + sstr->nas_len) = '\0';
- if (ndis_ascii_to_unicode(str, &dstr->us_buf)) {
- free(str, M_DEVBUF);
+ uint32_t rval;
+
+ rval = RtlAnsiStringToUnicodeString(dstr, sstr, FALSE);
+
+ if (rval == STATUS_INSUFFICIENT_RESOURCES)
+ return(NDIS_STATUS_RESOURCES);
+ if (rval)
return(NDIS_STATUS_FAILURE);
- }
- dstr->us_len = dstr->us_maxlen = sstr->nas_len * 2;
- free(str, M_DEVBUF);
+
return (NDIS_STATUS_SUCCESS);
}
@@ -2311,6 +2336,77 @@ NdisMPciAssignResources(adapter, slot, list)
return (NDIS_STATUS_SUCCESS);
}
+static void
+ndis_intr(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ struct ifnet *ifp;
+ int is_our_intr = 0;
+ int call_isr = 0;
+ ndis_miniport_interrupt *intr;
+
+ sc = arg;
+ ifp = sc->ifp;
+ intr = sc->ndis_block->nmb_interrupt;
+
+ if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL)
+ return;
+
+ if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
+ ndis_isr(sc, &is_our_intr, &call_isr);
+ else {
+ ndis_disable_intr(sc);
+ call_isr = 1;
+ }
+
+ if ((is_our_intr || call_isr))
+ IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
+
+ return;
+}
+
+static void
+ndis_intrhand(dpc, intr, sysarg1, sysarg2)
+ kdpc *dpc;
+ ndis_miniport_interrupt *intr;
+ void *sysarg1;
+ void *sysarg2;
+{
+ struct ndis_softc *sc;
+ ndis_miniport_block *block;
+ ndis_handle adapter;
+
+ block = intr->ni_block;
+ adapter = block->nmb_miniportadapterctx;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+
+ if (NDIS_SERIALIZED(sc->ndis_block))
+ KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
+
+ MSCALL1(intr->ni_isrfunc, adapter);
+
+ /* If there's a MiniportEnableInterrupt() routine, call it. */
+
+ ndis_enable_intr(sc);
+
+ if (NDIS_SERIALIZED(sc->ndis_block))
+ KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
+
+ /*
+ * Set the completion event if we've drained all
+ * pending interrupts.
+ */
+
+ KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
+ intr->ni_dpccnt--;
+ if (intr->ni_dpccnt == 0)
+ KeSetEvent(&intr->ni_dpcevt, IO_NO_INCREMENT, FALSE);
+ KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
+
+ return;
+}
+
static ndis_status
NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode)
ndis_miniport_interrupt *intr;
@@ -2322,15 +2418,40 @@ NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode)
ndis_interrupt_mode imode;
{
ndis_miniport_block *block;
+ ndis_miniport_characteristics *ch;
+ struct ndis_softc *sc;
+ int error;
block = adapter;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+ ch = IoGetDriverObjectExtension(block->nmb_deviceobj->do_drvobj,
+ (void *)1);
+
+ intr->ni_rsvd = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(struct mtx), 0);
+ if (intr->ni_rsvd == NULL)
+ return(NDIS_STATUS_RESOURCES);
intr->ni_block = adapter;
intr->ni_isrreq = reqisr;
intr->ni_shared = shared;
- block->nmb_interrupt = intr;
+ intr->ni_dpccnt = 0;
+ intr->ni_isrfunc = ch->nmc_interrupt_func;
+ intr->ni_dpcfunc = ch->nmc_isr_func;
+
+ KeInitializeEvent(&intr->ni_dpcevt, EVENT_TYPE_NOTIFY, TRUE);
+ KeInitializeDpc(&intr->ni_dpc,
+ ndis_findwrap((funcptr)ndis_intrhand), intr);
+ KeSetImportanceDpc(&intr->ni_dpc, KDPC_IMPORTANCE_LOW);
- KeInitializeSpinLock(&intr->ni_dpccountlock);
+ error = IoConnectInterrupt(&intr->ni_introbj,
+ ndis_findwrap((funcptr)ndis_intr), sc, NULL,
+ ivec, ilevel, 0, imode, shared, 0, FALSE);
+
+ if (error != STATUS_SUCCESS)
+ return(NDIS_STATUS_FAILURE);
+
+ block->nmb_interrupt = intr;
return(NDIS_STATUS_SUCCESS);
}
@@ -2339,6 +2460,29 @@ static void
NdisMDeregisterInterrupt(intr)
ndis_miniport_interrupt *intr;
{
+ ndis_miniport_block *block;
+ struct ndis_softc *sc;
+ uint8_t irql;
+
+ block = intr->ni_block;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+
+ /* Should really be KeSynchronizeExecution() */
+
+ KeAcquireSpinLock(intr->ni_introbj->ki_lock, &irql);
+ block->nmb_interrupt = NULL;
+ KeReleaseSpinLock(intr->ni_introbj->ki_lock, irql);
+/*
+ KeFlushQueuedDpcs();
+*/
+ /* Disconnect our ISR */
+
+ IoDisconnectInterrupt(intr->ni_introbj);
+
+ KeWaitForSingleObject((nt_dispatch_header *)&intr->ni_dpcevt,
+ 0, 0, FALSE, NULL);
+ KeResetEvent(&intr->ni_dpcevt);
+
return;
}
@@ -2429,23 +2573,22 @@ static void
NdisMSleep(usecs)
uint32_t usecs;
{
- struct timeval tv;
+ ktimer timer;
/*
* During system bootstrap, (i.e. cold == 1), we aren't
- * allowed to msleep(), so calling ndis_thsuspend() here
- * will return 0, and we won't actually have delayed. This
- * is a problem because some drivers expect NdisMSleep()
- * to always wait, and might fail if the expected delay
- * period does not in fact elapse. As a workaround, if the
- * attempt to sleep delay fails, we do a hard DELAY() instead.
+ * allowed to sleep, so we have to do a hard DELAY()
+ * instead.
*/
- tv.tv_sec = 0;
- tv.tv_usec = usecs;
- if (ndis_thsuspend(curthread->td_proc, NULL, tvtohz(&tv)) == 0)
+ if (cold)
DELAY(usecs);
-
+ else {
+ KeInitializeTimer(&timer);
+ KeSetTimer(&timer, ((int64_t)usecs * -10), NULL);
+ KeWaitForSingleObject((nt_dispatch_header *)&timer,
+ 0, 0, FALSE, NULL);
+ }
return;
}
@@ -2571,19 +2714,7 @@ NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx)
void *syncfunc;
void *syncctx;
{
- uint8_t (*sync)(void *);
- uint8_t rval;
- uint8_t irql;
-
- if (syncfunc == NULL || syncctx == NULL)
- return(0);
-
- sync = syncfunc;
- KeAcquireSpinLock(&intr->ni_dpccountlock, &irql);
- rval = MSCALL1(sync, syncctx);
- KeReleaseSpinLock(&intr->ni_dpccountlock, irql);
-
- return(rval);
+ return(KeSynchronizeExecution(intr->ni_introbj, syncfunc, syncctx));
}
/*
@@ -2620,28 +2751,20 @@ NdisGetSystemUpTime(tval)
static void
NdisInitializeString(dst, src)
- ndis_unicode_string *dst;
+ unicode_string *dst;
char *src;
{
- ndis_unicode_string *u;
-
- u = dst;
- u->us_buf = NULL;
- if (ndis_ascii_to_unicode(src, &u->us_buf))
- return;
- u->us_len = u->us_maxlen = strlen(src) * 2;
+ ansi_string as;
+ RtlInitAnsiString(&as, src);
+ RtlAnsiStringToUnicodeString(dst, &as, TRUE);
return;
}
static void
NdisFreeString(str)
- ndis_unicode_string *str;
+ unicode_string *str;
{
- if (str == NULL)
- return;
- if (str->us_buf != NULL)
- free(str->us_buf, M_DEVBUF);
- free(str, M_DEVBUF);
+ RtlFreeUnicodeString(str);
return;
}
@@ -2654,47 +2777,19 @@ NdisMRemoveMiniport(adapter)
static void
NdisInitAnsiString(dst, src)
- ndis_ansi_string *dst;
+ ansi_string *dst;
char *src;
{
- ndis_ansi_string *a;
-
- a = dst;
- if (a == NULL)
- return;
- if (src == NULL) {
- a->nas_len = a->nas_maxlen = 0;
- a->nas_buf = NULL;
- } else {
- a->nas_buf = src;
- a->nas_len = a->nas_maxlen = strlen(src);
- }
-
+ RtlInitAnsiString(dst, src);
return;
}
static void
NdisInitUnicodeString(dst, src)
- ndis_unicode_string *dst;
+ unicode_string *dst;
uint16_t *src;
{
- ndis_unicode_string *u;
- int i;
-
- u = dst;
- if (u == NULL)
- return;
- if (src == NULL) {
- u->us_len = u->us_maxlen = 0;
- u->us_buf = NULL;
- } else {
- i = 0;
- while(src[i] != 0)
- i++;
- u->us_buf = src;
- u->us_len = u->us_maxlen = i * 2;
- }
-
+ RtlInitUnicodeString(dst, src);
return;
}
@@ -2806,9 +2901,10 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr)
ndis_status *status;
ndis_handle *filehandle;
uint32_t *filelength;
- ndis_unicode_string *filename;
+ unicode_string *filename;
ndis_physaddr highestaddr;
{
+ ansi_string as;
char *afilename = NULL;
struct thread *td = curthread;
struct nameidata nd;
@@ -2820,8 +2916,13 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr)
linker_file_t head, lf;
caddr_t kldstart, kldend;
- ndis_unicode_to_ascii(filename->us_buf,
- filename->us_len, &afilename);
+ if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) {
+ *status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ afilename = strdup(as.as_buf, M_DEVBUF);
+ RtlFreeAnsiString(&as);
fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0);
if (fh == NULL) {
@@ -3120,6 +3221,7 @@ NdisScheduleWorkItem(work)
ExInitializeWorkItem(wqi,
(work_item_func)work->nwi_func, work->nwi_ctx);
ExQueueWorkItem(wqi, WORKQUEUE_DELAYED);
+
return(NDIS_STATUS_SUCCESS);
}
@@ -3230,8 +3332,8 @@ NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio)
static ndis_status
NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle)
ndis_handle handle;
- ndis_unicode_string *devname;
- ndis_unicode_string *symname;
+ unicode_string *devname;
+ unicode_string *symname;
driver_dispatch *majorfuncs[];
void **devobj;
ndis_handle *devhandle;
@@ -3260,18 +3362,19 @@ NdisMDeregisterDevice(handle)
static ndis_status
NdisMQueryAdapterInstanceName(name, handle)
- ndis_unicode_string *name;
+ unicode_string *name;
ndis_handle handle;
{
ndis_miniport_block *block;
device_t dev;
+ ansi_string as;
block = (ndis_miniport_block *)handle;
dev = block->nmb_physdeviceobj->do_devext;
- ndis_ascii_to_unicode(__DECONST(char *,
- device_get_nameunit(dev)), &name->us_buf);
- name->us_len = strlen(device_get_nameunit(dev)) * 2;
+ RtlInitAnsiString(&as, __DECONST(char *, device_get_nameunit(dev)));
+ if (RtlAnsiStringToUnicodeString(name, &as, TRUE))
+ return(NDIS_STATUS_RESOURCES);
return(NDIS_STATUS_SUCCESS);
}
@@ -3422,6 +3525,8 @@ image_patch_table ndis_functbl[] = {
IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2),
IMPORT_SFUNC(ndis_timercall, 4),
IMPORT_SFUNC(ndis_asyncmem_complete, 2),
+ IMPORT_SFUNC(ndis_intr, 1),
+ IMPORT_SFUNC(ndis_intrhand, 4),
/*
* This last entry is a catch-all for any function we haven't
diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c
index 6ff0689..fd3955c 100644
--- a/sys/compat/ndis/subr_ntoskrnl.c
+++ b/sys/compat/ndis/subr_ntoskrnl.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <sys/kernel.h>
#include <sys/proc.h>
+#include <sys/condvar.h>
#include <sys/kthread.h>
#include <sys/module.h>
#include <sys/smp.h>
@@ -58,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <machine/clock.h>
#include <machine/bus.h>
#include <machine/stdarg.h>
+#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
@@ -77,11 +79,8 @@ __FBSDID("$FreeBSD$");
#include <compat/ndis/ndis_var.h>
struct kdpc_queue {
- list_entry kq_high;
- list_entry kq_low;
- list_entry kq_med;
+ list_entry kq_disp;
struct thread *kq_td;
- int kq_state;
int kq_cpu;
int kq_exit;
struct mtx kq_lock;
@@ -92,14 +91,22 @@ struct kdpc_queue {
typedef struct kdpc_queue kdpc_queue;
-static uint8_t RtlEqualUnicodeString(ndis_unicode_string *,
- ndis_unicode_string *, uint8_t);
-static void RtlCopyUnicodeString(ndis_unicode_string *,
- ndis_unicode_string *);
-static ndis_status RtlUnicodeStringToAnsiString(ndis_ansi_string *,
- ndis_unicode_string *, uint8_t);
-static ndis_status RtlAnsiStringToUnicodeString(ndis_unicode_string *,
- ndis_ansi_string *, uint8_t);
+struct wb_ext {
+ struct cv we_cv;
+ struct thread *we_td;
+};
+
+typedef struct wb_ext wb_ext;
+
+#define NTOSKRNL_TIMEOUTS 256
+struct callout ntoskrnl_callout[NTOSKRNL_TIMEOUTS];
+int ntoskrnl_callidx;
+#define CALLOUT_INC(i) (i) = ((i) + 1) % NTOSKRNL_TIMEOUTS
+
+static uint8_t RtlEqualUnicodeString(unicode_string *,
+ unicode_string *, uint8_t);
+static void RtlCopyUnicodeString(unicode_string *,
+ unicode_string *);
static irp *IoBuildSynchronousFsdRequest(uint32_t, device_object *,
void *, uint32_t, uint64_t *, nt_kevent *, io_status_block *);
static irp *IoBuildAsynchronousFsdRequest(uint32_t,
@@ -115,7 +122,10 @@ static irp *IoMakeAssociatedIrp(irp *, uint8_t);
static uint32_t KeWaitForMultipleObjects(uint32_t,
nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t,
int64_t *, wait_block *);
-static void ntoskrnl_wakeup(void *);
+static void ntoskrnl_waittest(nt_dispatch_header *, uint32_t);
+static void ntoskrnl_satisfy_wait(nt_dispatch_header *, struct thread *);
+static void ntoskrnl_satisfy_multiple_waits(wait_block *);
+static int ntoskrnl_is_signalled(nt_dispatch_header *, struct thread *);
static void ntoskrnl_timercall(void *);
static void ntoskrnl_run_dpc(void *);
static void ntoskrnl_dpc_thread(void *);
@@ -123,7 +133,12 @@ static void ntoskrnl_destroy_dpc_threads(void);
static void ntoskrnl_destroy_workitem_threads(void);
static void ntoskrnl_workitem_thread(void *);
static void ntoskrnl_workitem(device_object *, void *);
+static void ntoskrnl_unicode_to_ascii(uint16_t *, char *, int);
+static void ntoskrnl_ascii_to_unicode(char *, uint16_t *, int);
static uint8_t ntoskrnl_insert_dpc(list_entry *, kdpc *);
+static device_t ntoskrnl_finddev(device_t, uint32_t,
+ uint8_t, uint8_t, struct resource **);
+static void ntoskrnl_intr(void *);
static void WRITE_REGISTER_USHORT(uint16_t *, uint16_t);
static uint16_t READ_REGISTER_USHORT(uint16_t *);
static void WRITE_REGISTER_ULONG(uint32_t *, uint32_t);
@@ -163,19 +178,13 @@ static uint32_t InterlockedIncrement(volatile uint32_t *);
static uint32_t InterlockedDecrement(volatile uint32_t *);
static void ExInterlockedAddLargeStatistic(uint64_t *, uint32_t);
static uint32_t MmSizeOfMdl(void *, size_t);
-static void MmBuildMdlForNonPagedPool(mdl *);
static void *MmMapLockedPages(mdl *, uint8_t);
static void *MmMapLockedPagesSpecifyCache(mdl *,
uint8_t, uint32_t, void *, uint32_t, uint32_t);
static void MmUnmapLockedPages(void *, mdl *);
static uint8_t MmIsAddressValid(void *);
static size_t RtlCompareMemory(const void *, const void *, size_t);
-static void RtlInitAnsiString(ndis_ansi_string *, char *);
-static void RtlInitUnicodeString(ndis_unicode_string *,
- uint16_t *);
-static void RtlFreeUnicodeString(ndis_unicode_string *);
-static void RtlFreeAnsiString(ndis_ansi_string *);
-static ndis_status RtlUnicodeStringToInteger(ndis_unicode_string *,
+static ndis_status RtlUnicodeStringToInteger(unicode_string *,
uint32_t, uint32_t *);
static int atoi (const char *);
static long atol (const char *);
@@ -198,6 +207,8 @@ static void ObfDereferenceObject(void *);
static uint32_t ZwClose(ndis_handle);
static void *ntoskrnl_memset(void *, int, size_t);
static char *ntoskrnl_strstr(char *, char *);
+static int ntoskrnl_toupper(int);
+static int ntoskrnl_tolower(int);
static funcptr ntoskrnl_findwrap(funcptr);
static uint32_t DbgPrint(char *, ...);
static void DbgBreakPoint(void);
@@ -280,6 +291,9 @@ ntoskrnl_libinit()
patch++;
}
+ for (i = 0; i < NTOSKRNL_TIMEOUTS; i++)
+ callout_init(&ntoskrnl_callout[i], CALLOUT_MPSAFE);
+
/*
* MDLs are supposed to be variable size (they describe
* buffers containing some number of pages, but we don't
@@ -313,10 +327,10 @@ ntoskrnl_libfini()
patch++;
}
- /* Stop the DPC queues. */
- ntoskrnl_destroy_dpc_threads();
/* Stop the workitem queues. */
ntoskrnl_destroy_workitem_threads();
+ /* Stop the DPC queues. */
+ ntoskrnl_destroy_dpc_threads();
ExFreePool(kq_queues);
ExFreePool(wq_queues);
@@ -362,11 +376,24 @@ ntoskrnl_strstr(s, find)
return ((char *)s);
}
+static int
+ntoskrnl_toupper(c)
+ int c;
+{
+ return(toupper(c));
+}
+
+static int
+ntoskrnl_tolower(c)
+ int c;
+{
+ return(tolower(c));
+}
static uint8_t
RtlEqualUnicodeString(str1, str2, caseinsensitive)
- ndis_unicode_string *str1;
- ndis_unicode_string *str2;
+ unicode_string *str1;
+ unicode_string *str2;
uint8_t caseinsensitive;
{
int i;
@@ -390,8 +417,8 @@ RtlEqualUnicodeString(str1, str2, caseinsensitive)
static void
RtlCopyUnicodeString(dest, src)
- ndis_unicode_string *dest;
- ndis_unicode_string *src;
+ unicode_string *dest;
+ unicode_string *src;
{
if (dest->us_maxlen >= src->us_len)
@@ -402,55 +429,99 @@ RtlCopyUnicodeString(dest, src)
return;
}
-static ndis_status
+static void
+ntoskrnl_ascii_to_unicode(ascii, unicode, len)
+ char *ascii;
+ uint16_t *unicode;
+ int len;
+{
+ int i;
+ uint16_t *ustr;
+
+ ustr = unicode;
+ for (i = 0; i < len; i++) {
+ *ustr = (uint16_t)ascii[i];
+ ustr++;
+ }
+
+ return;
+}
+
+static void
+ntoskrnl_unicode_to_ascii(unicode, ascii, len)
+ uint16_t *unicode;
+ char *ascii;
+ int len;
+{
+ int i;
+ uint8_t *astr;
+
+ astr = ascii;
+ for (i = 0; i < len / 2; i++) {
+ *astr = (uint8_t)unicode[i];
+ astr++;
+ }
+
+ return;
+}
+
+uint32_t
RtlUnicodeStringToAnsiString(dest, src, allocate)
- ndis_ansi_string *dest;
- ndis_unicode_string *src;
+ ansi_string *dest;
+ unicode_string *src;
uint8_t allocate;
{
- char *astr = NULL;
-
if (dest == NULL || src == NULL)
return(NDIS_STATUS_FAILURE);
+
+ dest->as_len = src->us_len / 2;
+ if (dest->as_maxlen < dest->as_len)
+ dest->as_len = dest->as_maxlen;
+
if (allocate == TRUE) {
- if (ndis_unicode_to_ascii(src->us_buf, src->us_len, &astr))
- return(NDIS_STATUS_FAILURE);
- dest->nas_buf = astr;
- dest->nas_len = dest->nas_maxlen = strlen(astr);
+ dest->as_buf = ExAllocatePoolWithTag(NonPagedPool,
+ (src->us_len / 2) + 1, 0);
+ if (dest->as_buf == NULL)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ dest->as_len = dest->as_maxlen = src->us_len / 2;
} else {
- dest->nas_len = src->us_len / 2; /* XXX */
- if (dest->nas_maxlen < dest->nas_len)
- dest->nas_len = dest->nas_maxlen;
- ndis_unicode_to_ascii(src->us_buf, dest->nas_len * 2,
- &dest->nas_buf);
+ dest->as_len = src->us_len / 2; /* XXX */
+ if (dest->as_maxlen < dest->as_len)
+ dest->as_len = dest->as_maxlen;
}
- return (NDIS_STATUS_SUCCESS);
+
+ ntoskrnl_unicode_to_ascii(src->us_buf, dest->as_buf,
+ dest->as_len * 2);
+
+ return (STATUS_SUCCESS);
}
-static ndis_status
+uint32_t
RtlAnsiStringToUnicodeString(dest, src, allocate)
- ndis_unicode_string *dest;
- ndis_ansi_string *src;
+ unicode_string *dest;
+ ansi_string *src;
uint8_t allocate;
{
- uint16_t *ustr = NULL;
-
if (dest == NULL || src == NULL)
return(NDIS_STATUS_FAILURE);
if (allocate == TRUE) {
- if (ndis_ascii_to_unicode(src->nas_buf, &ustr))
- return(NDIS_STATUS_FAILURE);
- dest->us_buf = ustr;
- dest->us_len = dest->us_maxlen = strlen(src->nas_buf) * 2;
+ dest->us_buf = ExAllocatePoolWithTag(NonPagedPool,
+ src->as_len * 2, 0);
+ if (dest->us_buf == NULL)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ dest->us_len = dest->us_maxlen = strlen(src->as_buf) * 2;
} else {
- dest->us_len = src->nas_len * 2; /* XXX */
+ dest->us_len = src->as_len * 2; /* XXX */
if (dest->us_maxlen < dest->us_len)
dest->us_len = dest->us_maxlen;
- ndis_ascii_to_unicode(src->nas_buf, &dest->us_buf);
}
- return (NDIS_STATUS_SUCCESS);
+
+ ntoskrnl_ascii_to_unicode(src->as_buf, dest->us_buf,
+ dest->us_len / 2);
+
+ return (STATUS_SUCCESS);
}
void *
@@ -461,9 +532,10 @@ ExAllocatePoolWithTag(pooltype, len, tag)
{
void *buf;
- buf = malloc(len, M_DEVBUF, M_NOWAIT);
+ buf = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
if (buf == NULL)
return(NULL);
+
return(buf);
}
@@ -491,7 +563,7 @@ IoAllocateDriverObjectExtension(drv, clid, extlen, ext)
return(STATUS_INSUFFICIENT_RESOURCES);
ce->ce_clid = clid;
- INSERT_LIST_TAIL((&drv->dro_driverext->dre_usrext), (&ce->ce_list));
+ InsertTailList((&drv->dro_driverext->dre_usrext), (&ce->ce_list));
*ext = (void *)(ce + 1);
@@ -902,7 +974,7 @@ IoInitializeIrp(io, psize, ssize)
io->irp_size = psize;
io->irp_stackcnt = ssize;
io->irp_currentstackloc = ssize;
- INIT_LIST_HEAD(&io->irp_thlist);
+ InitializeListHead(&io->irp_thlist);
io->irp_tail.irp_overlay.irp_csl =
(io_stack_location *)(io + 1) + ssize;
@@ -1060,6 +1132,202 @@ IofCompleteRequest(ip, prioboost)
return;
}
+static device_t
+ntoskrnl_finddev(dev, vector, irql, shared, res)
+ device_t dev;
+ uint32_t vector;
+ uint8_t irql;
+ uint8_t shared;
+ struct resource **res;
+{
+ device_t *children;
+ device_t matching_dev;
+ int childcnt;
+ struct resource *r;
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+ uint32_t flags;
+ int i;
+
+ /* We only want devices that have been successfully probed. */
+
+ if (device_is_alive(dev) == FALSE)
+ return(NULL);
+
+ device_get_children(dev, &children, &childcnt);
+
+ /*
+ * If this device has no children, it's a leaf: we can
+ * examine its resources. If the interrupt resource we
+ * want isn't here, we return NULL, otherwise we return
+ * the device to terminate the recursive search.
+ */
+
+ if (childcnt == 0) {
+ rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
+ if (rl == NULL)
+ return(NULL);
+#if __FreeBSD_version < 600022
+ SLIST_FOREACH(rle, rl, link) {
+#else
+ STAILQ_FOREACH(rle, rl, link) {
+#endif
+ r = rle->res;
+
+ if (r == NULL)
+ continue;
+
+ flags = rman_get_flags(r);
+
+ if (!(flags & RF_ACTIVE))
+ continue;
+
+ if (shared == TRUE && !(flags & RF_SHAREABLE))
+ continue;
+
+ if (rle->type == SYS_RES_IRQ &&
+ rman_get_start(r) == irql) {
+ *res = r;
+ return(dev);
+ }
+ }
+ /* No match. */
+ return (NULL);
+ }
+
+ /*
+ * If this device has children, do another
+ * level of recursion to inspect them.
+ */
+
+ for (i = 0; i < childcnt; i++) {
+ matching_dev = ntoskrnl_finddev(children[i],
+ vector, irql, shared, res);
+ if (matching_dev != NULL) {
+ free(children, M_TEMP);
+ return(matching_dev);
+ }
+ }
+
+ free(children, M_TEMP);
+ return(NULL);
+}
+
+static void
+ntoskrnl_intr(arg)
+ void *arg;
+{
+ kinterrupt *iobj;
+ uint8_t irql;
+
+ iobj = arg;
+
+ KeAcquireSpinLock(iobj->ki_lock, &irql);
+ MSCALL1(iobj->ki_svcfunc, iobj->ki_svcctx);
+ KeReleaseSpinLock(iobj->ki_lock, irql);
+
+ return;
+}
+
+uint8_t
+KeSynchronizeExecution(iobj, syncfunc, syncctx)
+ kinterrupt *iobj;
+ void *syncfunc;
+ void *syncctx;
+{
+ uint8_t irql;
+
+ KeAcquireSpinLock(iobj->ki_lock, &irql);
+ MSCALL1(syncfunc, syncctx);
+ KeReleaseSpinLock(iobj->ki_lock, irql);
+
+ return(TRUE);
+}
+
+/*
+ * This routine is a pain because the only thing we get passed
+ * here is the interrupt request level and vector, but bus_setup_intr()
+ * needs the device too. We can hack around this for now, but it's
+ * awkward.
+ */
+
+uint32_t
+IoConnectInterrupt(iobj, svcfunc, svcctx, lock, vector, irql,
+ syncirql, imode, shared, affinity, savefloat)
+ kinterrupt **iobj;
+ void *svcfunc;
+ void *svcctx;
+ uint32_t vector;
+ kspin_lock *lock;
+ uint8_t irql;
+ uint8_t syncirql;
+ uint8_t imode;
+ uint8_t shared;
+ uint32_t affinity;
+ uint8_t savefloat;
+{
+ devclass_t nexus_class;
+ device_t *nexus_devs, devp;
+ int nexus_count = 0;
+ device_t matching_dev = NULL;
+ struct resource *res;
+ int i, error;
+
+ nexus_class = devclass_find("nexus");
+ devclass_get_devices(nexus_class, &nexus_devs, &nexus_count);
+
+ for (i = 0; i < nexus_count; i++) {
+ devp = nexus_devs[i];
+ matching_dev = ntoskrnl_finddev(devp, vector,
+ irql, shared, &res);
+ if (matching_dev)
+ break;
+ }
+
+ free(nexus_devs, M_TEMP);
+
+ if (matching_dev == NULL)
+ return(STATUS_INVALID_PARAMETER);
+
+ *iobj = ExAllocatePoolWithTag(NonPagedPool, sizeof(kinterrupt), 0);
+ if (*iobj == NULL)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ (*iobj)->ki_dev = matching_dev;
+ (*iobj)->ki_irq = res;
+ (*iobj)->ki_svcfunc = svcfunc;
+ (*iobj)->ki_svcctx = svcctx;
+
+ if (lock == NULL) {
+ KeInitializeSpinLock(&(*iobj)->ki_lock_priv);
+ (*iobj)->ki_lock = &(*iobj)->ki_lock_priv;
+ } else
+ (*iobj)->ki_lock = lock;
+
+ error = bus_setup_intr(matching_dev, res, INTR_TYPE_NET | INTR_MPSAFE,
+ ntoskrnl_intr, *iobj, &(*iobj)->ki_cookie);
+
+ if (error) {
+ ExFreePool(iobj);
+ return (STATUS_INVALID_PARAMETER);
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+void
+IoDisconnectInterrupt(iobj)
+ kinterrupt *iobj;
+{
+ if (iobj == NULL)
+ return;
+
+ bus_teardown_intr(iobj->ki_dev, iobj->ki_irq, iobj->ki_cookie);
+ ExFreePool(iobj);
+
+ return;
+}
+
device_object *
IoAttachDeviceToDeviceStack(src, dst)
device_object *src;
@@ -1094,7 +1362,7 @@ IoDetachDevice(topdev)
topdev->do_attacheddev = tail->do_attacheddev;
topdev->do_refcnt--;
- /* Now reduce the stacksize count for the tail objects. */
+ /* Now reduce the stacksize count for the takm_il objects. */
tail = topdev->do_attacheddev;
while (tail != NULL) {
@@ -1107,48 +1375,168 @@ IoDetachDevice(topdev)
return;
}
-/* Always called with dispatcher lock held. */
-static void
-ntoskrnl_wakeup(arg)
- void *arg;
+/*
+ * For the most part, an object is considered signalled if
+ * dh_sigstate == TRUE. The exception is for mutant objects
+ * (mutexes), where the logic works like this:
+ *
+ * - If the thread already owns the object and sigstate is
+ * less than or equal to 0, then the object is considered
+ * signalled (recursive acquisition).
+ * - If dh_sigstate == 1, the object is also considered
+ * signalled.
+ */
+
+static int
+ntoskrnl_is_signalled(obj, td)
+ nt_dispatch_header *obj;
+ struct thread *td;
{
+ kmutant *km;
+
+ if (obj->dh_type == DISP_TYPE_MUTANT) {
+ km = (kmutant *)obj;
+ if ((obj->dh_sigstate <= 0 && km->km_ownerthread == td) ||
+ obj->dh_sigstate == 1)
+ return(TRUE);
+ return(FALSE);
+ }
+
+ if (obj->dh_sigstate > 0)
+ return(TRUE);
+ return(FALSE);
+}
+
+static void
+ntoskrnl_satisfy_wait(obj, td)
nt_dispatch_header *obj;
- wait_block *w;
- list_entry *e;
struct thread *td;
+{
+ kmutant *km;
- obj = arg;
+ switch (obj->dh_type) {
+ case DISP_TYPE_MUTANT:
+ km = (struct kmutant *)obj;
+ obj->dh_sigstate--;
+ /*
+ * If sigstate reaches 0, the mutex is now
+ * non-signalled (the new thread owns it).
+ */
+ if (obj->dh_sigstate == 0) {
+ km->km_ownerthread = td;
+ if (km->km_abandoned == TRUE)
+ km->km_abandoned = FALSE;
+ }
+ break;
+ /* Synchronization objects get reset to unsignalled. */
+ case DISP_TYPE_SYNCHRONIZATION_EVENT:
+ case DISP_TYPE_SYNCHRONIZATION_TIMER:
+ obj->dh_sigstate = 0;
+ break;
+ case DISP_TYPE_SEMAPHORE:
+ obj->dh_sigstate--;
+ break;
+ default:
+ break;
+ }
- e = obj->dh_waitlisthead.nle_flink;
+ return;
+}
+
+static void
+ntoskrnl_satisfy_multiple_waits(wb)
+ wait_block *wb;
+{
+ wait_block *cur;
+ struct thread *td;
+
+ cur = wb;
+ td = wb->wb_kthread;
- obj->dh_sigstate = TRUE;
+ do {
+ ntoskrnl_satisfy_wait(wb->wb_object, td);
+ cur->wb_awakened = TRUE;
+ cur = cur->wb_next;
+ } while (cur != wb);
+
+ return;
+}
+
+/* Always called with dispatcher lock held. */
+static void
+ntoskrnl_waittest(obj, increment)
+ nt_dispatch_header *obj;
+ uint32_t increment;
+{
+ wait_block *w, *next;
+ list_entry *e;
+ struct thread *td;
+ wb_ext *we;
+ int satisfied;
/*
- * What happens if someone tells us to wake up
- * threads waiting on an object, but nobody's
- * waiting on it at the moment? For sync events,
- * the signal state is supposed to be automatically
- * reset, but this only happens in the KeWaitXXX()
- * functions. If nobody is waiting, the state never
- * gets cleared.
+ * Once an object has been signalled, we walk its list of
+ * wait blocks. If a wait block can be awakened, then satisfy
+ * waits as necessary and wake the thread.
+ *
+ * The rules work like this:
+ *
+ * If a wait block is marked as WAITTYPE_ANY, then
+ * we can satisfy the wait conditions on the current
+ * object and wake the thread right away. Satisfying
+ * the wait also has the effect of breaking us out
+ * of the search loop.
+ *
+ * If the object is marked as WAITTYLE_ALL, then the
+ * wait block will be part of a circularly linked
+ * list of wait blocks belonging to a waiting thread
+ * that's sleeping in KeWaitForMultipleObjects(). In
+ * order to wake the thread, all the objects in the
+ * wait list must be in the signalled state. If they
+ * are, we then satisfy all of them and wake the
+ * thread.
+ *
*/
- if (e == &obj->dh_waitlisthead) {
- if (obj->dh_type == EVENT_TYPE_SYNC)
- obj->dh_sigstate = FALSE;
- return;
- }
+ e = obj->dh_waitlisthead.nle_flink;
- while (e != &obj->dh_waitlisthead) {
- w = (wait_block *)e;
- td = w->wb_kthread;
- ndis_thresume(td->td_proc);
- /*
- * For synchronization objects, only wake up
- * the first waiter.
- */
- if (obj->dh_type == EVENT_TYPE_SYNC)
- break;
+ while (e != &obj->dh_waitlisthead && obj->dh_sigstate > 0) {
+ w = CONTAINING_RECORD(e, wait_block, wb_waitlist);
+ we = w->wb_ext;
+ td = we->we_td;
+ satisfied = FALSE;
+ if (w->wb_waittype == WAITTYPE_ANY) {
+ /*
+ * Thread can be awakened if
+ * any wait is satisfied.
+ */
+ ntoskrnl_satisfy_wait(obj, td);
+ satisfied = TRUE;
+ w->wb_awakened = TRUE;
+ } else {
+ /*
+ * Thread can only be woken up
+ * if all waits are satisfied.
+ * If the thread is waiting on multiple
+ * objects, they should all be linked
+ * through the wb_next pointers in the
+ * wait blocks.
+ */
+ satisfied = TRUE;
+ next = w->wb_next;
+ while (next != w) {
+ if (ntoskrnl_is_signalled(obj, td) == FALSE) {
+ satisfied = FALSE;
+ break;
+ }
+ next = next->wb_next;
+ }
+ ntoskrnl_satisfy_multiple_waits(w);
+ }
+
+ if (satisfied == TRUE)
+ cv_broadcastpri(&we->we_cv, w->wb_oldpri -
+ (increment * 4));
e = e->nle_flink;
}
@@ -1206,7 +1594,7 @@ ntoskrnl_time(tval)
*
* - For mutexes, we try to acquire the mutex and if we can't, we wait
* on the mutex until it's available and then grab it. When a mutex is
- * released, it enters the signaled state, which wakes up one of the
+ * released, it enters the signalled state, which wakes up one of the
* threads waiting to acquire it. Mutexes are always synchronization
* events.
*
@@ -1228,49 +1616,54 @@ KeWaitForSingleObject(obj, reason, mode, alertable, duetime)
uint8_t alertable;
int64_t *duetime;
{
- struct thread *td = curthread;
- kmutant *km;
wait_block w;
+ struct thread *td = curthread;
struct timeval tv;
int error = 0;
uint64_t curtime;
+ wb_ext we;
if (obj == NULL)
return(STATUS_INVALID_PARAMETER);
mtx_lock(&ntoskrnl_dispatchlock);
+ cv_init(&we.we_cv, "KeWFS");
+ we.we_td = td;
+
/*
- * See if the object is a mutex. If so, and we already own
- * it, then just increment the acquisition count and return.
- *
- * For any other kind of object, see if it's already in the
- * signalled state, and if it is, just return. If the object
- * is marked as a synchronization event, reset the state to
- * unsignalled.
+ * Check to see if this object is already signalled,
+ * and just return without waiting if it is.
*/
-
- if (obj->dh_size == OTYPE_MUTEX) {
- km = (kmutant *)obj;
- if (km->km_ownerthread == NULL ||
- km->km_ownerthread == curthread->td_proc) {
- obj->dh_sigstate = FALSE;
- km->km_acquirecnt++;
- km->km_ownerthread = curthread->td_proc;
+ if (ntoskrnl_is_signalled(obj, td) == TRUE) {
+ /* Sanity check the signal state value. */
+ if (obj->dh_sigstate != INT32_MIN) {
+ ntoskrnl_satisfy_wait(obj, curthread);
mtx_unlock(&ntoskrnl_dispatchlock);
return (STATUS_SUCCESS);
+ } else {
+ /*
+ * There's a limit to how many times we can
+ * recursively acquire a mutant. If we hit
+ * the limit, something is very wrong.
+ */
+ if (obj->dh_type == DISP_TYPE_MUTANT) {
+ mtx_unlock(&ntoskrnl_dispatchlock);
+ panic("mutant limit exceeded");
+ }
}
- } else if (obj->dh_sigstate == TRUE) {
- if (obj->dh_type == EVENT_TYPE_SYNC)
- obj->dh_sigstate = FALSE;
- mtx_unlock(&ntoskrnl_dispatchlock);
- return (STATUS_SUCCESS);
}
+ bzero((char *)&w, sizeof(wait_block));
w.wb_object = obj;
- w.wb_kthread = td;
+ w.wb_ext = &we;
+ w.wb_waittype = WAITTYPE_ANY;
+ w.wb_next = &w;
+ w.wb_waitkey = 0;
+ w.wb_awakened = FALSE;
+ w.wb_oldpri = td->td_priority;
- INSERT_LIST_TAIL((&obj->dh_waitlisthead), (&w.wb_waitlist));
+ InsertTailList((&obj->dh_waitlisthead), (&w.wb_waitlist));
/*
* The timeout value is specified in 100 nanosecond units
@@ -1298,41 +1691,30 @@ KeWaitForSingleObject(obj, reason, mode, alertable, duetime)
}
}
- error = ndis_thsuspend(td->td_proc, &ntoskrnl_dispatchlock,
- duetime == NULL ? 0 : tvtohz(&tv));
+ if (duetime == NULL)
+ cv_wait(&we.we_cv, &ntoskrnl_dispatchlock);
+ else
+ error = cv_timedwait(&we.we_cv,
+ &ntoskrnl_dispatchlock, tvtohz(&tv));
+
+ RemoveEntryList(&w.wb_waitlist);
+
+ cv_destroy(&we.we_cv);
/* We timed out. Leave the object alone and return status. */
if (error == EWOULDBLOCK) {
- REMOVE_LIST_ENTRY((&w.wb_waitlist));
- INIT_LIST_HEAD((&w.wb_waitlist));
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_TIMEOUT);
}
- /*
- * Mutexes are always synchronization objects, which means
- * if several threads are waiting to acquire it, only one will
- * be woken up. If that one is us, and the mutex is up for grabs,
- * grab it.
- */
-
- if (obj->dh_size == OTYPE_MUTEX) {
- km = (kmutant *)obj;
- if (km->km_ownerthread == NULL) {
- km->km_ownerthread = curthread->td_proc;
- km->km_acquirecnt++;
- }
- }
-
- if (obj->dh_type == EVENT_TYPE_SYNC)
- obj->dh_sigstate = FALSE;
- REMOVE_LIST_ENTRY((&w.wb_waitlist));
- INIT_LIST_HEAD((&w.wb_waitlist));
-
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_SUCCESS);
+/*
+ return(KeWaitForMultipleObjects(1, &obj, WAITTYPE_ALL, reason,
+ mode, alertable, duetime, &w));
+*/
}
static uint32_t
@@ -1348,13 +1730,15 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode,
wait_block *wb_array;
{
struct thread *td = curthread;
- kmutant *km;
- wait_block _wb_array[THREAD_WAIT_OBJECTS];
- wait_block *w;
+ wait_block *whead, *w;
+ wait_block _wb_array[MAX_WAIT_OBJECTS];
+ nt_dispatch_header *cur;
struct timeval tv;
- int i, wcnt = 0, widx = 0, error = 0;
+ int i, wcnt = 0, error = 0;
uint64_t curtime;
struct timespec t1, t2;
+ uint32_t status = STATUS_SUCCESS;
+ wb_ext we;
if (cnt > MAX_WAIT_OBJECTS)
return(STATUS_INVALID_PARAMETER);
@@ -1363,51 +1747,88 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode,
mtx_lock(&ntoskrnl_dispatchlock);
+ cv_init(&we.we_cv, "KeWFM");
+ we.we_td = td;
+
if (wb_array == NULL)
- w = &_wb_array[0];
+ whead = _wb_array;
else
- w = wb_array;
+ whead = wb_array;
+
+ bzero((char *)whead, sizeof(wait_block) * cnt);
/* First pass: see if we can satisfy any waits immediately. */
+ wcnt = 0;
+ w = whead;
+
for (i = 0; i < cnt; i++) {
- if (obj[i]->dh_size == OTYPE_MUTEX) {
- km = (kmutant *)obj[i];
- if (km->km_ownerthread == NULL ||
- km->km_ownerthread == curthread->td_proc) {
- obj[i]->dh_sigstate = FALSE;
- km->km_acquirecnt++;
- km->km_ownerthread = curthread->td_proc;
- if (wtype == WAITTYPE_ANY) {
- mtx_unlock(&ntoskrnl_dispatchlock);
- return (STATUS_WAIT_0 + i);
- }
+ InsertTailList((&obj[i]->dh_waitlisthead),
+ (&w->wb_waitlist));
+ w->wb_ext = &we;
+ w->wb_object = obj[i];
+ w->wb_waittype = wtype;
+ w->wb_waitkey = i;
+ w->wb_awakened = FALSE;
+ w->wb_oldpri = td->td_priority;
+ w->wb_next = w + 1;
+ w++;
+ wcnt++;
+ if (ntoskrnl_is_signalled(obj[i], td)) {
+ /*
+ * There's a limit to how many times
+ * we can recursively acquire a mutant.
+ * If we hit the limit, something
+ * is very wrong.
+ */
+ if (obj[i]->dh_sigstate == INT32_MIN &&
+ obj[i]->dh_type == DISP_TYPE_MUTANT) {
+ mtx_unlock(&ntoskrnl_dispatchlock);
+ panic("mutant limit exceeded");
}
- } else if (obj[i]->dh_sigstate == TRUE) {
- if (obj[i]->dh_type == EVENT_TYPE_SYNC)
- obj[i]->dh_sigstate = FALSE;
+
+ /*
+ * If this is a WAITTYPE_ANY wait, then
+ * satisfy the waited object and exit
+ * right now.
+ */
+
if (wtype == WAITTYPE_ANY) {
- mtx_unlock(&ntoskrnl_dispatchlock);
- return (STATUS_WAIT_0 + i);
+ ntoskrnl_satisfy_wait(obj[i], td);
+ status = STATUS_WAIT_0 + i;
+ goto wait_done;
+ } else {
+ w--;
+ wcnt--;
+ w->wb_object = NULL;
+ RemoveEntryList(&w->wb_waitlist);
}
}
}
/*
- * Second pass: set up wait for anything we can't
- * satisfy immediately.
+ * If this is a WAITTYPE_ALL wait and all objects are
+ * already signalled, satisfy the waits and exit now.
*/
- for (i = 0; i < cnt; i++) {
- if (obj[i]->dh_sigstate == TRUE)
- continue;
- INSERT_LIST_TAIL((&obj[i]->dh_waitlisthead),
- (&w[i].wb_waitlist));
- w[i].wb_kthread = td;
- w[i].wb_object = obj[i];
- wcnt++;
+ if (wtype == WAITTYPE_ALL && wcnt == 0) {
+ for (i = 0; i < cnt; i++)
+ ntoskrnl_satisfy_wait(obj[i], td);
+ status = STATUS_SUCCESS;
+ goto wait_done;
}
+ /*
+ * Create a circular waitblock list. The waitcount
+ * must always be non-zero when we get here.
+ */
+
+ (w - 1)->wb_next = whead;
+
+ /* Wait on any objects that aren't yet signalled. */
+
+ /* Calculate timeout, if any. */
+
if (duetime != NULL) {
if (*duetime < 0) {
tv.tv_sec = - (*duetime) / 10000000;
@@ -1428,32 +1849,62 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode,
while (wcnt) {
nanotime(&t1);
- error = ndis_thsuspend(td->td_proc, &ntoskrnl_dispatchlock,
- duetime == NULL ? 0 : tvtohz(&tv));
+ if (duetime == NULL)
+ cv_wait(&we.we_cv, &ntoskrnl_dispatchlock);
+ else
+ error = cv_timedwait(&we.we_cv,
+ &ntoskrnl_dispatchlock, tvtohz(&tv));
+
+ /* Wait with timeout expired. */
+
+ if (error) {
+ status = STATUS_TIMEOUT;
+ goto wait_done;
+ }
nanotime(&t2);
- for (i = 0; i < cnt; i++) {
- if (obj[i]->dh_size == OTYPE_MUTEX) {
- km = (kmutant *)obj;
- if (km->km_ownerthread == NULL) {
- km->km_ownerthread =
- curthread->td_proc;
- km->km_acquirecnt++;
+ /* See what's been signalled. */
+
+ w = whead;
+ do {
+ cur = w->wb_object;
+ if (ntoskrnl_is_signalled(cur, td) == TRUE ||
+ w->wb_awakened == TRUE) {
+ /* Sanity check the signal state value. */
+ if (cur->dh_sigstate == INT32_MIN &&
+ cur->dh_type == DISP_TYPE_MUTANT) {
+ mtx_unlock(&ntoskrnl_dispatchlock);
+ panic("mutant limit exceeded");
}
- }
- if (obj[i]->dh_sigstate == TRUE) {
- widx = i;
- if (obj[i]->dh_type == EVENT_TYPE_SYNC)
- obj[i]->dh_sigstate = FALSE;
- REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
- INIT_LIST_HEAD((&w[i].wb_waitlist));
wcnt--;
+ if (wtype == WAITTYPE_ANY) {
+ status = w->wb_waitkey &
+ STATUS_WAIT_0;
+ goto wait_done;
+ }
}
+ w = w->wb_next;
+ } while (w != whead);
+
+ /*
+ * If all objects have been signalled, or if this
+ * is a WAITTYPE_ANY wait and we were woke up by
+ * someone, we can bail.
+ */
+
+ if (wcnt == 0) {
+ status = STATUS_SUCCESS;
+ goto wait_done;
}
- if (error || wtype == WAITTYPE_ANY)
- break;
+ /*
+ * If this is WAITTYPE_ALL wait, and there's still
+ * objects that haven't been signalled, deduct the
+ * time that's elapsed so far from the timeout and
+ * wait again (or continue waiting indefinitely if
+ * there's no timeout).
+ */
if (duetime != NULL) {
tv.tv_sec -= (t2.tv_sec - t1.tv_sec);
@@ -1461,26 +1912,19 @@ KeWaitForMultipleObjects(cnt, obj, wtype, reason, mode,
}
}
- if (wcnt) {
- for (i = 0; i < cnt; i++) {
- REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
- INIT_LIST_HEAD((&w[i].wb_waitlist));
- }
- }
- if (error == EWOULDBLOCK) {
- mtx_unlock(&ntoskrnl_dispatchlock);
- return(STATUS_TIMEOUT);
- }
+wait_done:
- if (wtype == WAITTYPE_ANY && wcnt) {
- mtx_unlock(&ntoskrnl_dispatchlock);
- return(STATUS_WAIT_0 + widx);
- }
+ cv_destroy(&we.we_cv);
+ for (i = 0; i < cnt; i++) {
+ if (whead[i].wb_object != NULL)
+ RemoveEntryList(&whead[i].wb_waitlist);
+
+ }
mtx_unlock(&ntoskrnl_dispatchlock);
- return(STATUS_SUCCESS);
+ return(status);
}
static void
@@ -2047,7 +2491,7 @@ MmSizeOfMdl(vaddr, len)
* Instead, we just fill in the page array with the kernel virtual
* addresses of the buffers.
*/
-static void
+void
MmBuildMdlForNonPagedPool(m)
mdl *m;
{
@@ -2135,16 +2579,14 @@ ntoskrnl_workitem_thread(arg)
kq = arg;
- INIT_LIST_HEAD(&kq->kq_med);
+ InitializeListHead(&kq->kq_disp);
kq->kq_td = curthread;
kq->kq_exit = 0;
- kq->kq_state = NDIS_PSTATE_SLEEPING;
mtx_init(&kq->kq_lock, "NDIS thread lock", NULL, MTX_SPIN);
KeInitializeEvent(&kq->kq_proc, EVENT_TYPE_SYNC, FALSE);
KeInitializeEvent(&kq->kq_dead, EVENT_TYPE_SYNC, FALSE);
while (1) {
-
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_proc,
0, 0, TRUE, NULL);
@@ -2152,34 +2594,27 @@ ntoskrnl_workitem_thread(arg)
if (kq->kq_exit) {
mtx_unlock_spin(&kq->kq_lock);
- KeSetEvent(&kq->kq_dead, 0, FALSE);
+ KeSetEvent(&kq->kq_dead, IO_NO_INCREMENT, FALSE);
break;
}
- kq->kq_state = NDIS_PSTATE_RUNNING;
-
- l = kq->kq_med.nle_flink;
- while (l != & kq->kq_med) {
+ while (!IsListEmpty(&kq->kq_disp)) {
+ l = RemoveHeadList(&kq->kq_disp);
iw = CONTAINING_RECORD(l,
io_workitem, iw_listentry);
- REMOVE_LIST_HEAD((&kq->kq_med));
- INIT_LIST_HEAD(l);
- if (iw->iw_func == NULL) {
- l = kq->kq_med.nle_flink;
+ InitializeListHead((&iw->iw_listentry));
+ if (iw->iw_func == NULL)
continue;
- }
mtx_unlock_spin(&kq->kq_lock);
MSCALL2(iw->iw_func, iw->iw_dobj, iw->iw_ctx);
mtx_lock_spin(&kq->kq_lock);
- l = kq->kq_med.nle_flink;
}
- kq->kq_state = NDIS_PSTATE_SLEEPING;
-
mtx_unlock_spin(&kq->kq_lock);
}
mtx_destroy(&kq->kq_lock);
+
#if __FreeBSD_version < 502113
mtx_lock(&Giant);
#endif
@@ -2195,9 +2630,8 @@ ntoskrnl_destroy_workitem_threads(void)
for (i = 0; i < WORKITEM_THREADS; i++) {
kq = wq_queues + i;
-
kq->kq_exit = 1;
- KeSetEvent(&kq->kq_proc, 0, FALSE);
+ KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_dead,
0, 0, TRUE, NULL);
}
@@ -2215,7 +2649,7 @@ IoAllocateWorkItem(dobj)
if (iw == NULL)
return(NULL);
- INIT_LIST_HEAD(&iw->iw_listentry);
+ InitializeListHead(&iw->iw_listentry);
iw->iw_dobj = dobj;
mtx_lock(&ntoskrnl_dispatchlock);
@@ -2241,21 +2675,38 @@ IoQueueWorkItem(iw, iw_func, qtype, ctx)
uint32_t qtype;
void *ctx;
{
- int state;
kdpc_queue *kq;
+ list_entry *l;
+ io_workitem *cur;
iw->iw_func = iw_func;
iw->iw_ctx = ctx;
-
kq = wq_queues + iw->iw_idx;
mtx_lock_spin(&kq->kq_lock);
- INSERT_LIST_TAIL((&kq->kq_med), (&iw->iw_listentry));
- state = kq->kq_state;
+
+ /*
+ * Traverse the list and make sure this workitem hasn't
+ * already been inserted. Queuing the same workitem
+ * twice will hose the list but good.
+ */
+
+ l = kq->kq_disp.nle_flink;
+ while (l != &kq->kq_disp) {
+ cur = CONTAINING_RECORD(l, io_workitem, iw_listentry);
+ if (cur == iw) {
+ /* Already queued -- do nothing. */
+ mtx_unlock_spin(&kq->kq_lock);
+ return;
+ }
+ l = l->nle_flink;
+ }
+
+ InsertTailList((&kq->kq_disp), (&iw->iw_listentry));
mtx_unlock_spin(&kq->kq_lock);
- if (state == NDIS_PSTATE_SLEEPING)
- KeSetEvent(&kq->kq_proc, 0, FALSE);
+
+ KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
return;
}
@@ -2278,6 +2729,31 @@ ntoskrnl_workitem(dobj, arg)
return;
}
+/*
+ * The ExQueueWorkItem() API is deprecated in Windows XP. Microsoft
+ * warns that it's unsafe and to use IoQueueWorkItem() instead. The
+ * problem with ExQueueWorkItem() is that it can't guard against
+ * the condition where a driver submits a job to the work queue and
+ * is then unloaded before the job is able to run. IoQueueWorkItem()
+ * acquires a reference to the device's device_object via the
+ * object manager and retains it until after the job has completed,
+ * which prevents the driver from being unloaded before the job
+ * runs. (We don't currently support this behavior, though hopefully
+ * that will change once the object manager API is fleshed out a bit.)
+ *
+ * Having said all that, the ExQueueWorkItem() API remains, because
+ * there are still other parts of Windows that use it, including
+ * NDIS itself: NdisScheduleWorkItem() calls ExQueueWorkItem().
+ * We fake up the ExQueueWorkItem() API on top of our implementation
+ * of IoQueueWorkItem(). Workitem thread #3 is reserved exclusively
+ * for ExQueueWorkItem() jobs, and we pass a pointer to the work
+ * queue item (provided by the caller) in to IoAllocateWorkItem()
+ * instead of the device_object. We need to save this pointer so
+ * we can apply a sanity check: as with the DPC queue and other
+ * workitem queues, we can't allow the same work queue item to
+ * be queued twice. If it's already pending, we silently return
+ */
+
void
ExQueueWorkItem(w, qtype)
work_queue_item *w;
@@ -2285,6 +2761,33 @@ ExQueueWorkItem(w, qtype)
{
io_workitem *iw;
io_workitem_func iwf;
+ kdpc_queue *kq;
+ list_entry *l;
+ io_workitem *cur;
+
+
+ /*
+ * We need to do a special sanity test to make sure
+ * the ExQueueWorkItem() API isn't used to queue
+ * the same workitem twice. Rather than checking the
+ * io_workitem pointer itself, we test the attached
+ * device object, which is really a pointer to the
+ * legacy work queue item structure.
+ */
+
+ kq = wq_queues + WORKITEM_LEGACY_THREAD;
+ mtx_lock_spin(&kq->kq_lock);
+ l = kq->kq_disp.nle_flink;
+ while (l != &kq->kq_disp) {
+ cur = CONTAINING_RECORD(l, io_workitem, iw_listentry);
+ if (cur->iw_dobj == (device_object *)w) {
+ /* Already queued -- do nothing. */
+ mtx_unlock_spin(&kq->kq_lock);
+ return;
+ }
+ l = l->nle_flink;
+ }
+ mtx_unlock_spin(&kq->kq_lock);
iw = IoAllocateWorkItem((device_object *)w);
if (iw == NULL)
@@ -2316,33 +2819,33 @@ RtlCompareMemory(s1, s2, len)
return(total);
}
-static void
+void
RtlInitAnsiString(dst, src)
- ndis_ansi_string *dst;
+ ansi_string *dst;
char *src;
{
- ndis_ansi_string *a;
+ ansi_string *a;
a = dst;
if (a == NULL)
return;
if (src == NULL) {
- a->nas_len = a->nas_maxlen = 0;
- a->nas_buf = NULL;
+ a->as_len = a->as_maxlen = 0;
+ a->as_buf = NULL;
} else {
- a->nas_buf = src;
- a->nas_len = a->nas_maxlen = strlen(src);
+ a->as_buf = src;
+ a->as_len = a->as_maxlen = strlen(src);
}
return;
}
-static void
+void
RtlInitUnicodeString(dst, src)
- ndis_unicode_string *dst;
+ unicode_string *dst;
uint16_t *src;
{
- ndis_unicode_string *u;
+ unicode_string *u;
int i;
u = dst;
@@ -2364,7 +2867,7 @@ RtlInitUnicodeString(dst, src)
ndis_status
RtlUnicodeStringToInteger(ustr, base, val)
- ndis_unicode_string *ustr;
+ unicode_string *ustr;
uint32_t base;
uint32_t *val;
{
@@ -2410,31 +2913,31 @@ RtlUnicodeStringToInteger(ustr, base, val)
astr++;
}
- ndis_unicode_to_ascii(uchr, len, &astr);
+ ntoskrnl_unicode_to_ascii(uchr, astr, len);
*val = strtoul(abuf, NULL, base);
return(NDIS_STATUS_SUCCESS);
}
-static void
+void
RtlFreeUnicodeString(ustr)
- ndis_unicode_string *ustr;
+ unicode_string *ustr;
{
if (ustr->us_buf == NULL)
return;
- free(ustr->us_buf, M_DEVBUF);
+ ExFreePool(ustr->us_buf);
ustr->us_buf = NULL;
return;
}
-static void
+void
RtlFreeAnsiString(astr)
- ndis_ansi_string *astr;
+ ansi_string *astr;
{
- if (astr->nas_buf == NULL)
+ if (astr->as_buf == NULL)
return;
- free(astr->nas_buf, M_DEVBUF);
- astr->nas_buf = NULL;
+ ExFreePool(astr->as_buf);
+ astr->as_buf = NULL;
return;
}
@@ -2512,13 +3015,12 @@ KeInitializeMutex(kmutex, level)
kmutant *kmutex;
uint32_t level;
{
- INIT_LIST_HEAD((&kmutex->km_header.dh_waitlisthead));
+ InitializeListHead((&kmutex->km_header.dh_waitlisthead));
kmutex->km_abandoned = FALSE;
kmutex->km_apcdisable = 1;
- kmutex->km_header.dh_sigstate = TRUE;
- kmutex->km_header.dh_type = EVENT_TYPE_SYNC;
- kmutex->km_header.dh_size = OTYPE_MUTEX;
- kmutex->km_acquirecnt = 0;
+ kmutex->km_header.dh_sigstate = 1;
+ kmutex->km_header.dh_type = DISP_TYPE_MUTANT;
+ kmutex->km_header.dh_size = sizeof(kmutant) / sizeof(uint32_t);
kmutex->km_ownerthread = NULL;
return;
}
@@ -2528,19 +3030,26 @@ KeReleaseMutex(kmutex, kwait)
kmutant *kmutex;
uint8_t kwait;
{
+ uint32_t prevstate;
+
mtx_lock(&ntoskrnl_dispatchlock);
- if (kmutex->km_ownerthread != curthread->td_proc) {
+ prevstate = kmutex->km_header.dh_sigstate;
+ if (kmutex->km_ownerthread != curthread) {
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_MUTANT_NOT_OWNED);
}
- kmutex->km_acquirecnt--;
- if (kmutex->km_acquirecnt == 0) {
+
+ kmutex->km_header.dh_sigstate++;
+ kmutex->km_abandoned = FALSE;
+
+ if (kmutex->km_header.dh_sigstate == 1) {
kmutex->km_ownerthread = NULL;
- ntoskrnl_wakeup(&kmutex->km_header);
+ ntoskrnl_waittest(&kmutex->km_header, IO_NO_INCREMENT);
}
+
mtx_unlock(&ntoskrnl_dispatchlock);
- return(kmutex->km_acquirecnt);
+ return(prevstate);
}
static uint32_t
@@ -2556,10 +3065,13 @@ KeInitializeEvent(kevent, type, state)
uint32_t type;
uint8_t state;
{
- INIT_LIST_HEAD((&kevent->k_header.dh_waitlisthead));
+ InitializeListHead((&kevent->k_header.dh_waitlisthead));
kevent->k_header.dh_sigstate = state;
- kevent->k_header.dh_type = type;
- kevent->k_header.dh_size = OTYPE_EVENT;
+ if (type == EVENT_TYPE_NOTIFY)
+ kevent->k_header.dh_type = DISP_TYPE_NOTIFICATION_EVENT;
+ else
+ kevent->k_header.dh_type = DISP_TYPE_SYNCHRONIZATION_EVENT;
+ kevent->k_header.dh_size = sizeof(nt_kevent) / sizeof(uint32_t);
return;
}
@@ -2584,10 +3096,49 @@ KeSetEvent(kevent, increment, kwait)
uint8_t kwait;
{
uint32_t prevstate;
+ wait_block *w;
+ nt_dispatch_header *dh;
+ struct thread *td;
+ wb_ext *we;
mtx_lock(&ntoskrnl_dispatchlock);
prevstate = kevent->k_header.dh_sigstate;
- ntoskrnl_wakeup(&kevent->k_header);
+ dh = &kevent->k_header;
+
+ if (IsListEmpty(&dh->dh_waitlisthead))
+ /*
+ * If there's nobody in the waitlist, just set
+ * the state to signalled.
+ */
+ dh->dh_sigstate = 1;
+ else {
+ /*
+ * Get the first waiter. If this is a synchronization
+ * event, just wake up that one thread (don't bother
+ * setting the state to signalled since we're supposed
+ * to automatically clear synchronization events anyway).
+ *
+ * If it's a notification event, or the the first
+ * waiter is doing a WAITTYPE_ALL wait, go through
+ * the full wait satisfaction process.
+ */
+ w = CONTAINING_RECORD(dh->dh_waitlisthead.nle_flink,
+ wait_block, wb_waitlist);
+ we = w->wb_ext;
+ td = we->we_td;
+ if (kevent->k_header.dh_type == DISP_TYPE_NOTIFICATION_EVENT ||
+ w->wb_waittype == WAITTYPE_ALL) {
+ if (prevstate == 0) {
+ dh->dh_sigstate = 1;
+ ntoskrnl_waittest(dh, increment);
+ }
+ } else {
+ w->wb_awakened |= TRUE;
+ cv_broadcastpri(&we->we_cv, w->wb_oldpri -
+ (increment * 4));
+ }
+ }
+
mtx_unlock(&ntoskrnl_dispatchlock);
return(prevstate);
@@ -2608,6 +3159,40 @@ KeReadStateEvent(kevent)
return(kevent->k_header.dh_sigstate);
}
+/*
+ * The object manager in Windows is responsible for managing
+ * references and access to various types of objects, including
+ * device_objects, events, threads, timers and so on. However,
+ * there's a difference in the way objects are handled in user
+ * mode versus kernel mode.
+ *
+ * In user mode (i.e. Win32 applications), all objects are
+ * managed by the object manager. For example, when you create
+ * a timer or event object, you actually end up with an
+ * object_header (for the object manager's bookkeeping
+ * purposes) and an object body (which contains the actual object
+ * structure, e.g. ktimer, kevent, etc...). This allows Windows
+ * to manage resource quotas and to enforce access restrictions
+ * on basically every kind of system object handled by the kernel.
+ *
+ * However, in kernel mode, you only end up using the object
+ * manager some of the time. For example, in a driver, you create
+ * a timer object by simply allocating the memory for a ktimer
+ * structure and initializing it with KeInitializeTimer(). Hence,
+ * the timer has no object_header and no reference counting or
+ * security/resource checks are done on it. The assumption in
+ * this case is that if you're running in kernel mode, you know
+ * what you're doing, and you're already at an elevated privilege
+ * anyway.
+ *
+ * There are some exceptions to this. The two most important ones
+ * for our purposes are device_objects and threads. We need to use
+ * the object manager to do reference counting on device_objects,
+ * and for threads, you can only get a pointer to a thread's
+ * dispatch header by using ObReferenceObjectByHandle() on the
+ * handle returned by PsCreateSystemThread().
+ */
+
static ndis_status
ObReferenceObjectByHandle(handle, reqaccess, otype,
accessmode, object, handleinfo)
@@ -2624,9 +3209,12 @@ ObReferenceObjectByHandle(handle, reqaccess, otype,
if (nr == NULL)
return(NDIS_STATUS_FAILURE);
- INIT_LIST_HEAD((&nr->no_dh.dh_waitlisthead));
+ InitializeListHead((&nr->no_dh.dh_waitlisthead));
nr->no_obj = handle;
- nr->no_dh.dh_size = OTYPE_THREAD;
+ nr->no_dh.dh_type = DISP_TYPE_THREAD;
+ nr->no_dh.dh_sigstate = 0;
+ nr->no_dh.dh_size = (uint8_t)(sizeof(struct thread) /
+ sizeof(uint32_t));
TAILQ_INSERT_TAIL(&ntoskrnl_reflist, nr, link);
*object = nr;
@@ -2728,7 +3316,8 @@ PsTerminateSystemThread(status)
TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) {
if (nr->no_obj != curthread->td_proc)
continue;
- ntoskrnl_wakeup(&nr->no_dh);
+ nr->no_dh.dh_sigstate = 1;
+ ntoskrnl_waittest(&nr->no_dh, IO_NO_INCREMENT);
break;
}
mtx_unlock(&ntoskrnl_dispatchlock);
@@ -2773,14 +3362,21 @@ ntoskrnl_timercall(arg)
ktimer *timer;
struct timeval tv;
- mtx_unlock(&Giant);
-
mtx_lock(&ntoskrnl_dispatchlock);
timer = arg;
+ callout_init(timer->k_callout, CALLOUT_MPSAFE);
+
+ /* Mark the timer as no longer being on the timer queue. */
+
timer->k_header.dh_inserted = FALSE;
+ /* Now signal the object and satisfy any waits on it. */
+
+ timer->k_header.dh_sigstate = 1;
+ ntoskrnl_waittest(&timer->k_header, IO_NO_INCREMENT);
+
/*
* If this is a periodic timer, re-arm it
* so it will fire again. We do this before
@@ -2794,18 +3390,19 @@ 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_callout = &ntoskrnl_callout[ntoskrnl_callidx];
+ CALLOUT_INC(ntoskrnl_callidx);
+ callout_reset(timer->k_callout, tvtohz(&tv),
+ ntoskrnl_timercall, timer);
}
+ /* If there's a DPC associated with the timer, queue it up. */
+
if (timer->k_dpc != NULL)
KeInsertQueueDpc(timer->k_dpc, NULL, NULL);
- ntoskrnl_wakeup(&timer->k_header);
mtx_unlock(&ntoskrnl_dispatchlock);
- mtx_lock(&Giant);
-
return;
}
@@ -2830,12 +3427,14 @@ KeInitializeTimerEx(timer, type)
return;
bzero((char *)timer, sizeof(ktimer));
- INIT_LIST_HEAD((&timer->k_header.dh_waitlisthead));
+ InitializeListHead((&timer->k_header.dh_waitlisthead));
timer->k_header.dh_sigstate = FALSE;
timer->k_header.dh_inserted = FALSE;
- timer->k_header.dh_type = type;
- timer->k_header.dh_size = OTYPE_TIMER;
- callout_handle_init(&timer->k_handle);
+ if (type == EVENT_TYPE_NOTIFY)
+ timer->k_header.dh_type = DISP_TYPE_NOTIFICATION_TIMER;
+ else
+ timer->k_header.dh_type = DISP_TYPE_SYNCHRONIZATION_TIMER;
+ timer->k_header.dh_size = sizeof(ktimer) / sizeof(uint32_t);
return;
}
@@ -2868,18 +3467,27 @@ ntoskrnl_dpc_thread(arg)
kq = arg;
- INIT_LIST_HEAD(&kq->kq_high);
- INIT_LIST_HEAD(&kq->kq_low);
- INIT_LIST_HEAD(&kq->kq_med);
+ InitializeListHead(&kq->kq_disp);
kq->kq_td = curthread;
kq->kq_exit = 0;
- kq->kq_state = NDIS_PSTATE_SLEEPING;
mtx_init(&kq->kq_lock, "NDIS thread lock", NULL, MTX_SPIN);
KeInitializeEvent(&kq->kq_proc, EVENT_TYPE_SYNC, FALSE);
KeInitializeEvent(&kq->kq_done, EVENT_TYPE_SYNC, FALSE);
KeInitializeEvent(&kq->kq_dead, EVENT_TYPE_SYNC, FALSE);
+ /*
+ * Elevate our priority. DPCs are used to run interrupt
+ * handlers, and they should trigger as soon as possible
+ * once scheduled by an ISR.
+ */
+
+ mtx_lock_spin(&sched_lock);
sched_pin();
+ sched_prio(curthread, PRI_MIN_KERN);
+#if __FreeBSD_version < 600000
+ curthread->td_base_pri = PRI_MIN_KERN;
+#endif
+ mtx_unlock_spin(&sched_lock);
while (1) {
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_proc,
@@ -2889,59 +3497,23 @@ ntoskrnl_dpc_thread(arg)
if (kq->kq_exit) {
mtx_unlock_spin(&kq->kq_lock);
- KeSetEvent(&kq->kq_dead, 0, FALSE);
+ KeSetEvent(&kq->kq_dead, IO_NO_INCREMENT, FALSE);
break;
}
- kq->kq_state = NDIS_PSTATE_RUNNING;
-
- /* Process high importance list first. */
-
- l = kq->kq_high.nle_flink;
- while (l != &kq->kq_high) {
- d = CONTAINING_RECORD(l, kdpc, k_dpclistentry);
- REMOVE_LIST_ENTRY((&d->k_dpclistentry));
- INIT_LIST_HEAD((&d->k_dpclistentry));
- d->k_lock = NULL;
- mtx_unlock_spin(&kq->kq_lock);
- ntoskrnl_run_dpc(d);
- mtx_lock_spin(&kq->kq_lock);
- l = kq->kq_high.nle_flink;
- }
-
- /* Now the medium importance list. */
-
- l = kq->kq_med.nle_flink;
- while (l != &kq->kq_med) {
- d = CONTAINING_RECORD(l, kdpc, k_dpclistentry);
- REMOVE_LIST_ENTRY((&d->k_dpclistentry));
- INIT_LIST_HEAD((&d->k_dpclistentry));
- d->k_lock = NULL;
- mtx_unlock_spin(&kq->kq_lock);
- ntoskrnl_run_dpc(d);
- mtx_lock_spin(&kq->kq_lock);
- l = kq->kq_med.nle_flink;
- }
-
- /* And finally the low importance list. */
-
- l = kq->kq_low.nle_flink;
- while (l != &kq->kq_low) {
+ while (!IsListEmpty(&kq->kq_disp)) {
+ l = RemoveHeadList((&kq->kq_disp));
d = CONTAINING_RECORD(l, kdpc, k_dpclistentry);
- REMOVE_LIST_ENTRY((&d->k_dpclistentry));
- INIT_LIST_HEAD((&d->k_dpclistentry));
+ InitializeListHead((&d->k_dpclistentry));
d->k_lock = NULL;
mtx_unlock_spin(&kq->kq_lock);
ntoskrnl_run_dpc(d);
mtx_lock_spin(&kq->kq_lock);
- l = kq->kq_low.nle_flink;
}
- kq->kq_state = NDIS_PSTATE_SLEEPING;
-
mtx_unlock_spin(&kq->kq_lock);
- KeSetEvent(&kq->kq_done, 0, FALSE);
+ KeSetEvent(&kq->kq_done, IO_NO_INCREMENT, FALSE);
}
@@ -2995,7 +3567,6 @@ ntoskrnl_destroy_dpc_threads(void)
KeInitializeDpc(&dpc, NULL, NULL);
KeSetTargetProcessorDpc(&dpc, i);
KeInsertQueueDpc(&dpc, NULL, NULL);
-
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_dead,
0, 0, TRUE, NULL);
}
@@ -3019,7 +3590,11 @@ ntoskrnl_insert_dpc(head, dpc)
l = l->nle_flink;
}
- INSERT_LIST_TAIL((head), (&dpc->k_dpclistentry));
+ if (dpc->k_importance == KDPC_IMPORTANCE_HIGH)
+ InsertHeadList((head), (&dpc->k_dpclistentry));
+ else
+ InsertTailList((head), (&dpc->k_dpclistentry));
+
return (TRUE);
}
@@ -3037,13 +3612,12 @@ KeInitializeDpc(dpc, dpcfunc, dpcctx)
dpc->k_deferredctx = dpcctx;
dpc->k_num = KDPC_CPU_DEFAULT;
dpc->k_importance = KDPC_IMPORTANCE_MEDIUM;
- dpc->k_num = KeGetCurrentProcessorNumber();
/*
* In case someone tries to dequeue a DPC that
* hasn't been queued yet.
*/
- dpc->k_lock = NULL /*&ntoskrnl_dispatchlock*/;
- INIT_LIST_HEAD((&dpc->k_dpclistentry));
+ dpc->k_lock = NULL;
+ InitializeListHead((&dpc->k_dpclistentry));
return;
}
@@ -3056,7 +3630,6 @@ KeInsertQueueDpc(dpc, sysarg1, sysarg2)
{
kdpc_queue *kq;
uint8_t r;
- int state;
if (dpc == NULL)
return(FALSE);
@@ -3081,21 +3654,15 @@ KeInsertQueueDpc(dpc, sysarg1, sysarg2)
*/
mtx_lock_spin(&kq->kq_lock);
- if (dpc->k_importance == KDPC_IMPORTANCE_HIGH)
- r = ntoskrnl_insert_dpc(&kq->kq_high, dpc);
- else if (dpc->k_importance == KDPC_IMPORTANCE_LOW)
- r = ntoskrnl_insert_dpc(&kq->kq_low, dpc);
- else
- r = ntoskrnl_insert_dpc(&kq->kq_med, dpc);
+ r = ntoskrnl_insert_dpc(&kq->kq_disp, dpc);
if (r == TRUE)
dpc->k_lock = &kq->kq_lock;
- state = kq->kq_state;
mtx_unlock_spin(&kq->kq_lock);
+
if (r == FALSE)
return(r);
- if (state == NDIS_PSTATE_SLEEPING)
- KeSetEvent(&kq->kq_proc, 0, FALSE);
+ KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
return(r);
}
@@ -3104,21 +3671,26 @@ uint8_t
KeRemoveQueueDpc(dpc)
kdpc *dpc;
{
+ struct mtx *lock;
+
if (dpc == NULL)
return(FALSE);
- if (dpc->k_lock == NULL)
+ lock = dpc->k_lock;
+
+ if (lock == NULL)
return(FALSE);
- mtx_lock_spin((struct mtx*)(dpc->k_lock));
+ mtx_lock_spin(lock);
+ dpc->k_lock = NULL;
if (dpc->k_dpclistentry.nle_flink == &dpc->k_dpclistentry) {
- mtx_unlock_spin((struct mtx*)(dpc->k_lock));
+ mtx_unlock_spin(lock);
return(FALSE);
}
- REMOVE_LIST_ENTRY((&dpc->k_dpclistentry));
- INIT_LIST_HEAD((&dpc->k_dpclistentry));
- mtx_unlock_spin((struct mtx*)(dpc->k_lock));
+ RemoveEntryList((&dpc->k_dpclistentry));
+ InitializeListHead((&dpc->k_dpclistentry));
+ mtx_unlock_spin(lock);
return(TRUE);
}
@@ -3162,7 +3734,7 @@ KeFlushQueuedDpcs(void)
for (i = 0; i < mp_ncpus; i++) {
kq = kq_queues + i;
- KeSetEvent(&kq->kq_proc, 0, FALSE);
+ KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_done,
0, 0, TRUE, NULL);
}
@@ -3193,7 +3765,7 @@ KeSetTimerEx(timer, duetime, period, dpc)
mtx_lock(&ntoskrnl_dispatchlock);
if (timer->k_header.dh_inserted == TRUE) {
- untimeout(ntoskrnl_timercall, timer, timer->k_handle);
+ callout_stop(timer->k_callout);
timer->k_header.dh_inserted = FALSE;
pending = TRUE;
} else
@@ -3220,7 +3792,10 @@ KeSetTimerEx(timer, duetime, period, dpc)
}
timer->k_header.dh_inserted = TRUE;
- timer->k_handle = timeout(ntoskrnl_timercall, timer, tvtohz(&tv));
+ timer->k_callout = &ntoskrnl_callout[ntoskrnl_callidx];
+ CALLOUT_INC(ntoskrnl_callidx);
+ callout_reset(timer->k_callout, tvtohz(&tv),
+ ntoskrnl_timercall, timer);
mtx_unlock(&ntoskrnl_dispatchlock);
@@ -3236,6 +3811,12 @@ KeSetTimer(timer, duetime, dpc)
return (KeSetTimerEx(timer, duetime, 0, dpc));
}
+/*
+ * The Windows DDK documentation seems to say that cancelling
+ * a timer that has a DPC will result in the DPC also being
+ * cancelled, but this isn't really the case.
+ */
+
uint8_t
KeCancelTimer(timer)
ktimer *timer;
@@ -3247,14 +3828,12 @@ KeCancelTimer(timer)
mtx_lock(&ntoskrnl_dispatchlock);
+ pending = timer->k_header.dh_inserted;
+
if (timer->k_header.dh_inserted == TRUE) {
- untimeout(ntoskrnl_timercall, timer, timer->k_handle);
- if (timer->k_dpc != NULL)
- KeRemoveQueueDpc(timer->k_dpc);
timer->k_header.dh_inserted = FALSE;
- pending = TRUE;
- } else
- pending = KeRemoveQueueDpc(timer->k_dpc);
+ callout_stop(timer->k_callout);
+ }
mtx_unlock(&ntoskrnl_dispatchlock);
@@ -3299,6 +3878,8 @@ image_patch_table ntoskrnl_functbl[] = {
IMPORT_CFUNC(strncpy, 0),
IMPORT_CFUNC(strcpy, 0),
IMPORT_CFUNC(strlen, 0),
+ IMPORT_CFUNC_MAP(toupper, ntoskrnl_toupper, 0),
+ IMPORT_CFUNC_MAP(tolower, ntoskrnl_tolower, 0),
IMPORT_CFUNC_MAP(strstr, ntoskrnl_strstr, 0),
IMPORT_CFUNC_MAP(strchr, index, 0),
IMPORT_CFUNC(memcpy, 0),
@@ -3311,6 +3892,8 @@ image_patch_table ntoskrnl_functbl[] = {
IMPORT_SFUNC(IoAcquireCancelSpinLock, 1),
IMPORT_SFUNC(IoReleaseCancelSpinLock, 1),
IMPORT_SFUNC(IoCancelIrp, 1),
+ IMPORT_SFUNC(IoConnectInterrupt, 11),
+ IMPORT_SFUNC(IoDisconnectInterrupt, 1),
IMPORT_SFUNC(IoCreateDevice, 7),
IMPORT_SFUNC(IoDeleteDevice, 1),
IMPORT_SFUNC(IoGetAttachedDevice, 1),
@@ -3324,6 +3907,7 @@ image_patch_table ntoskrnl_functbl[] = {
IMPORT_SFUNC(IoMakeAssociatedIrp, 2),
IMPORT_SFUNC(IoFreeIrp, 1),
IMPORT_SFUNC(IoInitializeIrp, 3),
+ IMPORT_SFUNC(KeSynchronizeExecution, 3),
IMPORT_SFUNC(KeWaitForSingleObject, 5),
IMPORT_SFUNC(KeWaitForMultipleObjects, 8),
IMPORT_SFUNC(_allmul, 4),
diff --git a/sys/compat/ndis/winx32_wrap.S b/sys/compat/ndis/winx32_wrap.S
index 4fadfb5..f5d24ba 100644
--- a/sys/compat/ndis/winx32_wrap.S
+++ b/sys/compat/ndis/winx32_wrap.S
@@ -82,6 +82,13 @@
* we only know the absolute addresses of the thunk and unthunk
* routines. So we need to make sure the templates have enough
* room in them for the full address.
+ *
+ * Also note that when we call the a thunk/unthunk routine after
+ * invoking a wrapped function, we have to make sure to preserve
+ * the value returned from that function. Most functions return
+ * a 32-bit value in %eax, however some routines return 64-bit
+ * values, which span both %eax and %edx. Consequently, we have
+ * to preserve both registers.
*/
/*
@@ -114,13 +121,16 @@ ENTRY(x86_stdcall_wrap)
x86_stdcall_wrap_call:
movl $0,%eax
call *%eax # jump to routine
- mov %eax,%esi # preserve return val
+ push %eax # preserve return val
+ push %edx
movl $ctxsw_utow, %eax
call *%eax # thunk
+ pop %edx
+ pop %eax # restore return val
+
add $64,%esp # clean the stack
- mov %esi,%eax # restore return val
pop %edi
pop %esi
x86_stdcall_wrap_arg:
@@ -151,12 +161,14 @@ ENTRY(x86_stdcall_call)
call ctxsw_utow # thunk
call *12(%edi) # branch to stdcall routine
- mov %eax,%esi # preserve return val
+ push %eax # preserve return val
+ push %edx
call ctxsw_wtou # unthunk
+ pop %edx
+ pop %eax # restore return val
mov %edi,%esp # restore stack
- mov %esi,%eax # restore return val
pop %edi # restore %edi
pop %esi # and %esi
ret
@@ -188,10 +200,12 @@ x86_fastcall_wrap_call:
mov $0,%eax
call *%eax # branch to fastcall routine
push %eax # preserve return val
+ push %edx
movl $ctxsw_utow, %eax
call *%eax # thunk
+ pop %edx
pop %eax # restore return val
add $12,%esp # clean the stack
x86_fastcall_wrap_arg:
@@ -215,9 +229,11 @@ ENTRY(x86_fastcall_call)
mov 16(%esp),%edx
call *8(%esp) # branch to fastcall routine
push %eax # preserve return val
+ push %edx
call ctxsw_wtou # unthunk
+ pop %edx
pop %eax # restore return val
add $4,%esp # clean the stack
ret
OpenPOWER on IntegriCloud