mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Get rid of the timer tracking and reaping code in NdisMInitializeTimer()
and ndis_halt_nic(). It's been disabled for some time anyway, and it turns out there's a possible deadlock in NdisMInitializeTimer() when acquiring the miniport block lock to modify the timer list: it's possible for a driver to call NdisMInitializeTimer() when the miniport block lock has already been acquired by an earlier piece of code. You can't acquire the same spinlock twice, so this can deadlock. Also, implement MmMapIoSpace() and MmUnmapIoSpace(), and make NdisMMapIoSpace() and NdisMUnmapIoSpace() use them. There are some drivers that want MmMapIoSpace() and MmUnmapIoSpace() so that they can map arbitrary register spaces not directly associated with their device resources. For example, there's an Atheros driver for a miniPci card (0x168C:0x1014) on the IBM Thinkpad x40 that wants to map some I/O spaces at 0xF00000 and 0xE00000 which are held by the acpi0 device. I don't know what it wants these ranges for, but if it can't map and access them, the MiniportInitialize() method fails.
This commit is contained in:
parent
c9003bc7fa
commit
7f3cc43211
4 changed files with 118 additions and 47 deletions
|
|
@ -1108,8 +1108,6 @@ ndis_reset_nic(arg)
|
|||
return(0);
|
||||
}
|
||||
|
||||
#undef NDIS_REAP_TIMERS
|
||||
|
||||
int
|
||||
ndis_halt_nic(arg)
|
||||
void *arg;
|
||||
|
|
@ -1117,9 +1115,6 @@ ndis_halt_nic(arg)
|
|||
struct ndis_softc *sc;
|
||||
ndis_handle adapter;
|
||||
ndis_halt_handler haltfunc;
|
||||
#ifdef NDIS_REAP_TIMERS
|
||||
ndis_miniport_timer *t, *n;
|
||||
#endif
|
||||
ndis_miniport_block *block;
|
||||
int empty = 0;
|
||||
uint8_t irql;
|
||||
|
|
@ -1127,24 +1122,6 @@ ndis_halt_nic(arg)
|
|||
sc = arg;
|
||||
block = sc->ndis_block;
|
||||
|
||||
#ifdef NDIS_REAP_TIMERS
|
||||
/*
|
||||
* Drivers are sometimes very lax about cancelling all
|
||||
* their timers. Cancel them all ourselves, just to be
|
||||
* safe. We must do this before invoking MiniportHalt(),
|
||||
* since if we wait until after, the memory in which
|
||||
* the timers reside will no longer be valid.
|
||||
*/
|
||||
|
||||
t = sc->ndis_block->nmb_timerlist;
|
||||
while (t != NULL) {
|
||||
KeCancelTimer(&t->nmt_ktimer);
|
||||
n = t;
|
||||
t = t->nmt_nexttimer;
|
||||
n->nmt_nexttimer = NULL;
|
||||
}
|
||||
sc->ndis_block->nmb_timerlist = NULL;
|
||||
#endif
|
||||
if (!cold)
|
||||
KeFlushQueuedDpcs();
|
||||
|
||||
|
|
|
|||
|
|
@ -1362,6 +1362,8 @@ 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 *MmMapIoSpace(uint64_t, uint32_t, uint32_t);
|
||||
extern void MmUnmapIoSpace(void *, size_t);
|
||||
extern void MmBuildMdlForNonPagedPool(mdl *);
|
||||
extern void IoDisconnectInterrupt(kinterrupt *);
|
||||
extern uint32_t IoAllocateDriverObjectExtension(driver_object *,
|
||||
|
|
|
|||
|
|
@ -1257,8 +1257,6 @@ NdisMInitializeTimer(timer, handle, func, ctx)
|
|||
ndis_timer_function func;
|
||||
void *ctx;
|
||||
{
|
||||
uint8_t irql;
|
||||
|
||||
/* Save the driver's funcptr and context */
|
||||
|
||||
timer->nmt_timerfunc = func;
|
||||
|
|
@ -1276,13 +1274,6 @@ NdisMInitializeTimer(timer, handle, func, ctx)
|
|||
ndis_findwrap((funcptr)ndis_timercall), timer);
|
||||
timer->nmt_ktimer.k_dpc = &timer->nmt_kdpc;
|
||||
|
||||
KeAcquireSpinLock(&timer->nmt_block->nmb_lock, &irql);
|
||||
|
||||
timer->nmt_nexttimer = timer->nmt_block->nmb_timerlist;
|
||||
timer->nmt_block->nmb_timerlist = timer;
|
||||
|
||||
KeReleaseSpinLock(&timer->nmt_block->nmb_lock, irql);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1750,25 +1741,12 @@ NdisMMapIoSpace(vaddr, adapter, paddr, len)
|
|||
ndis_physaddr paddr;
|
||||
uint32_t len;
|
||||
{
|
||||
ndis_miniport_block *block;
|
||||
struct ndis_softc *sc;
|
||||
|
||||
if (adapter == NULL)
|
||||
return(NDIS_STATUS_FAILURE);
|
||||
|
||||
block = (ndis_miniport_block *)adapter;
|
||||
sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
|
||||
*vaddr = MmMapIoSpace(paddr.np_quad, len, 0);
|
||||
|
||||
if (sc->ndis_res_mem != NULL &&
|
||||
paddr.np_quad == rman_get_start(sc->ndis_res_mem))
|
||||
*vaddr = (void *)rman_get_virtual(sc->ndis_res_mem);
|
||||
else if (sc->ndis_res_altmem != NULL &&
|
||||
paddr.np_quad == rman_get_start(sc->ndis_res_altmem))
|
||||
*vaddr = (void *)rman_get_virtual(sc->ndis_res_altmem);
|
||||
else if (sc->ndis_res_am != NULL &&
|
||||
paddr.np_quad == rman_get_start(sc->ndis_res_am))
|
||||
*vaddr = (void *)rman_get_virtual(sc->ndis_res_am);
|
||||
else
|
||||
if (*vaddr == NULL)
|
||||
return(NDIS_STATUS_FAILURE);
|
||||
|
||||
return(NDIS_STATUS_SUCCESS);
|
||||
|
|
@ -1780,6 +1758,7 @@ NdisMUnmapIoSpace(adapter, vaddr, len)
|
|||
void *vaddr;
|
||||
uint32_t len;
|
||||
{
|
||||
MmUnmapIoSpace(vaddr, len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ static void *MmMapLockedPagesSpecifyCache(mdl *,
|
|||
uint8_t, uint32_t, void *, uint32_t, uint32_t);
|
||||
static void MmUnmapLockedPages(void *, mdl *);
|
||||
static uint8_t MmIsAddressValid(void *);
|
||||
static device_t ntoskrnl_finddev(device_t, uint64_t, struct resource **);
|
||||
static size_t RtlCompareMemory(const void *, const void *, size_t);
|
||||
static ndis_status RtlUnicodeStringToInteger(unicode_string *,
|
||||
uint32_t, uint32_t *);
|
||||
|
|
@ -2541,6 +2542,116 @@ MmIsAddressValid(vaddr)
|
|||
return(FALSE);
|
||||
}
|
||||
|
||||
void *
|
||||
MmMapIoSpace(paddr, len, cachetype)
|
||||
uint64_t paddr;
|
||||
uint32_t len;
|
||||
uint32_t cachetype;
|
||||
{
|
||||
devclass_t nexus_class;
|
||||
device_t *nexus_devs, devp;
|
||||
int nexus_count = 0;
|
||||
device_t matching_dev = NULL;
|
||||
struct resource *res;
|
||||
int i;
|
||||
vm_offset_t v;
|
||||
|
||||
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, paddr, &res);
|
||||
if (matching_dev)
|
||||
break;
|
||||
}
|
||||
|
||||
free(nexus_devs, M_TEMP);
|
||||
|
||||
if (matching_dev == NULL)
|
||||
return(NULL);
|
||||
|
||||
v = (vm_offset_t)rman_get_virtual(res);
|
||||
if (paddr > rman_get_start(res))
|
||||
v += paddr - rman_get_start(res);
|
||||
|
||||
return((void *)v);
|
||||
}
|
||||
|
||||
void
|
||||
MmUnmapIoSpace(vaddr, len)
|
||||
void *vaddr;
|
||||
size_t len;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static device_t
|
||||
ntoskrnl_finddev(dev, paddr, res)
|
||||
device_t dev;
|
||||
uint64_t paddr;
|
||||
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);
|
||||
|
||||
rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
|
||||
if (rl != 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 (rle->type == SYS_RES_MEMORY &&
|
||||
paddr >= rman_get_start(r) &&
|
||||
paddr <= rman_get_end(r)) {
|
||||
if (!(flags & RF_ACTIVE))
|
||||
bus_activate_resource(dev,
|
||||
SYS_RES_MEMORY, 0, r);
|
||||
*res = r;
|
||||
return(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this device has children, do another
|
||||
* level of recursion to inspect them.
|
||||
*/
|
||||
|
||||
device_get_children(dev, &children, &childcnt);
|
||||
|
||||
for (i = 0; i < childcnt; i++) {
|
||||
matching_dev = ntoskrnl_finddev(children[i], paddr, res);
|
||||
if (matching_dev != NULL) {
|
||||
free(children, M_TEMP);
|
||||
return(matching_dev);
|
||||
}
|
||||
}
|
||||
|
||||
free(children, M_TEMP);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Workitems are unlike DPCs, in that they run in a user-mode thread
|
||||
* context rather than at DISPATCH_LEVEL in kernel context. In our
|
||||
|
|
@ -4053,6 +4164,8 @@ image_patch_table ntoskrnl_functbl[] = {
|
|||
IMPORT_SFUNC(MmUnmapLockedPages, 2),
|
||||
IMPORT_SFUNC(MmBuildMdlForNonPagedPool, 1),
|
||||
IMPORT_SFUNC(MmIsAddressValid, 1),
|
||||
IMPORT_SFUNC(MmMapIoSpace, 3 + 1),
|
||||
IMPORT_SFUNC(MmUnmapIoSpace, 2),
|
||||
IMPORT_SFUNC(KeInitializeSpinLock, 1),
|
||||
IMPORT_SFUNC(IoIsWdmVersionAvailable, 2),
|
||||
IMPORT_SFUNC(IoGetDeviceProperty, 5),
|
||||
|
|
|
|||
Loading…
Reference in a new issue