diff options
author | wpaul <wpaul@FreeBSD.org> | 2005-02-08 17:23:25 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2005-02-08 17:23:25 +0000 |
commit | df89b626983fe6b8b3366ad0147e35b1a6a8fd37 (patch) | |
tree | 508b01687ab62847ee4114b92f273c0cdbd4da49 /sys/compat/ndis/kern_ndis.c | |
parent | 81617011cd4fc0a322fee7174006255fc9f5e82c (diff) | |
download | FreeBSD-src-df89b626983fe6b8b3366ad0147e35b1a6a8fd37.zip FreeBSD-src-df89b626983fe6b8b3366ad0147e35b1a6a8fd37.tar.gz |
Next step on the road to IRPs: create and use an imitation of the
Windows DRIVER_OBJECT and DEVICE_OBJECT mechanism so that we can
simulate driver stacking.
In Windows, each loaded driver image is attached to a DRIVER_OBJECT
structure. Windows uses the registry to match up a given vendor/device
ID combination with a corresponding DRIVER_OBJECT. When a driver image
is first loaded, its DriverEntry() routine is invoked, which sets up
the AddDevice() function pointer in the DRIVER_OBJECT and creates
a dispatch table (based on IRP major codes). When a Windows bus driver
detects a new device, it creates a Physical Device Object (PDO) for
it. This is a DEVICE_OBJECT structure, with semantics analagous to
that of a device_t in FreeBSD. The Windows PNP manager will invoke
the driver's AddDevice() function and pass it pointers to the DRIVER_OBJECT
and the PDO.
The AddDevice() function then creates a new DRIVER_OBJECT structure of
its own. This is known as the Functional Device Object (FDO) and
corresponds roughly to a private softc instance. The driver uses
IoAttachDeviceToDeviceStack() to add this device object to the
driver stack for this PDO. Subsequent drivers (called filter drivers
in Windows-speak) can be loaded which add themselves to the stack.
When someone issues an IRP to a device, it travel along the stack
passing through several possible filter drivers until it reaches
the functional driver (which actually knows how to talk to the hardware)
at which point it will be completed. This is how Windows achieves
driver layering.
Project Evil now simulates most of this. if_ndis now has a modevent
handler which will use MOD_LOAD and MOD_UNLOAD events to drive the
creation and destruction of DRIVER_OBJECTs. (The load event also
does the relocation/dynalinking of the image.) We don't have a registry,
so the DRIVER_OBJECTS are stored in a linked list for now. Eventually,
the list entry will contain the vendor/device ID list extracted from
the .INF file. When ndis_probe() is called and detectes a supported
device, it will create a PDO for the device instance and attach it
to the DRIVER_OBJECT just as in Windows. ndis_attach() will then call
our NdisAddDevice() handler to create the FDO. The NDIS miniport block
is now a device extension hung off the FDO, just as it is in Windows.
The miniport characteristics table is now an extension hung off the
DRIVER_OBJECT as well (the characteristics are the same for all devices
handled by a given driver, so they don't need to be per-instance.)
We also do an IoAttachDeviceToDeviceStack() to put the FDO on the
stack for the PDO. There are a couple of fake bus drivers created
for the PCI and pccard buses. Eventually, there will be one for USB,
which will actually accept USB IRP.s
Things should still work just as before, only now we do things in
the proper order and maintain the correct framework to support passing
IRPs between drivers.
Various changes:
- corrected the comments about IRQL handling in subr_hal.c to more
accurately reflect reality
- update ndiscvt to make the drv_data symbol in ndis_driver_data.h a
global so that if_ndis_pci.o and/or if_ndis_pccard.o can see it.
- Obtain the softc pointer from the miniport block by referencing
the PDO rather than a private pointer of our own (nmb_ifp is no
longer used)
- implement IoAttachDeviceToDeviceStack(), IoDetachDevice(),
IoGetAttachedDevice(), IoAllocateDriverObjectExtension(),
IoGetDriverObjectExtension(), IoCreateDevice(), IoDeleteDevice(),
IoAllocateIrp(), IoReuseIrp(), IoMakeAssociatedIrp(), IoFreeIrp(),
IoInitializeIrp()
- fix a few mistakes in the driver_object and device_object definitions
- add a new module, kern_windrv.c, to handle the driver registration
and relocation/dynalinkign duties (which don't really belong in
kern_ndis.c).
- made ndis_block and ndis_chars in the ndis_softc stucture pointers
and modified all references to it
- fixed NdisMRegisterMiniport() and NdisInitializeWrapper() so they
work correctly with the new driver_object mechanism
- changed ndis_attach() to call NdisAddDevice() instead of ndis_load_driver()
(which is now deprecated)
- used ExAllocatePoolWithTag()/ExFreePool() in lookaside list routines
instead of kludged up alloc/free routines
- added kern_windrv.c to sys/modules/ndis/Makefile and files.i386.
Diffstat (limited to 'sys/compat/ndis/kern_ndis.c')
-rw-r--r-- | sys/compat/ndis/kern_ndis.c | 268 |
1 files changed, 115 insertions, 153 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c index f6db9c7..f93bf4e 100644 --- a/sys/compat/ndis/kern_ndis.c +++ b/sys/compat/ndis/kern_ndis.c @@ -125,6 +125,7 @@ static struct ndisproc ndis_iproc; * collision with if_ndis.ko, which internally calls itself * 'ndis.' */ + static int ndis_modevent(module_t mod, int cmd, void *arg) { @@ -133,6 +134,7 @@ ndis_modevent(module_t mod, int cmd, void *arg) switch (cmd) { case MOD_LOAD: /* Initialize subsystems */ + windrv_libinit(); ndis_libinit(); ntoskrnl_libinit(); @@ -169,6 +171,7 @@ ndis_modevent(module_t mod, int cmd, void *arg) /* Shut down subsystems */ ndis_libfini(); ntoskrnl_libfini(); + windrv_libfini(); /* Remove zones */ uma_zdestroy(ndis_packet_zone); @@ -542,10 +545,14 @@ ndis_status_func(adapter, status, sbuf, slen) uint32_t slen; { ndis_miniport_block *block; - block = adapter; + struct ndis_softc *sc; + struct ifnet *ifp; - if (block->nmb_ifp->if_flags & IFF_DEBUG) - device_printf (block->nmb_dev, "status: %x\n", status); + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = &sc->arpcom.ac_if; + if (ifp->if_flags & IFF_DEBUG) + device_printf (sc->ndis_dev, "status: %x\n", status); return; } @@ -554,10 +561,14 @@ ndis_statusdone_func(adapter) ndis_handle adapter; { ndis_miniport_block *block; + struct ndis_softc *sc; + struct ifnet *ifp; + block = adapter; - - if (block->nmb_ifp->if_flags & IFF_DEBUG) - device_printf (block->nmb_dev, "status complete\n"); + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = &sc->arpcom.ac_if; + if (ifp->if_flags & IFF_DEBUG) + device_printf (sc->ndis_dev, "status complete\n"); return; } @@ -594,11 +605,16 @@ ndis_resetdone_func(adapter, status, addressingreset) uint8_t addressingreset; { ndis_miniport_block *block; + struct ndis_softc *sc; + struct ifnet *ifp; + block = adapter; + sc = device_get_softc(block->nmb_physdeviceobj->do_devext); + ifp = &sc->arpcom.ac_if; - if (block->nmb_ifp->if_flags & IFF_DEBUG) - device_printf (block->nmb_dev, "reset done...\n"); - wakeup(block->nmb_ifp); + if (ifp->if_flags & IFF_DEBUG) + device_printf (sc->ndis_dev, "reset done...\n"); + wakeup(ifp); return; } @@ -780,12 +796,12 @@ ndis_return(arg) p = arg; sc = p->np_softc; - adapter = sc->ndis_block.nmb_miniportadapterctx; + adapter = sc->ndis_block->nmb_miniportadapterctx; if (adapter == NULL) return; - returnfunc = sc->ndis_chars.nmc_return_packet_func; + returnfunc = sc->ndis_chars->nmc_return_packet_func; irql = KeRaiseIrql(DISPATCH_LEVEL); returnfunc(adapter, p); KeLowerIrql(irql); @@ -863,7 +879,7 @@ ndis_convert_res(arg) int error = 0; sc = arg; - block = &sc->ndis_block; + block = sc->ndis_block; dev = sc->ndis_dev; SLIST_INIT(&brl_rev); @@ -1129,25 +1145,25 @@ ndis_set_info(arg, oid, buf, buflen) sc = arg; NDIS_LOCK(sc); - setfunc = sc->ndis_chars.nmc_setinfo_func; - adapter = sc->ndis_block.nmb_miniportadapterctx; + setfunc = sc->ndis_chars->nmc_setinfo_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; NDIS_UNLOCK(sc); if (adapter == NULL || setfunc == NULL) return(ENXIO); - KeAcquireSpinLock(&sc->ndis_block.nmb_lock, &irql); + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); rval = setfunc(adapter, oid, buf, *buflen, &byteswritten, &bytesneeded); - KeReleaseSpinLock(&sc->ndis_block.nmb_lock, irql); + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); if (rval == NDIS_STATUS_PENDING) { mtx_lock(&ndis_req_mtx); - error = msleep(&sc->ndis_block.nmb_setstat, + error = msleep(&sc->ndis_block->nmb_setstat, &ndis_req_mtx, curthread->td_priority|PDROP, "ndisset", 5 * hz); - rval = sc->ndis_block.nmb_setstat; + rval = sc->ndis_block->nmb_setstat; } if (byteswritten) @@ -1188,11 +1204,11 @@ ndis_send_packets(arg, packets, cnt) uint8_t irql; sc = arg; - adapter = sc->ndis_block.nmb_miniportadapterctx; + adapter = sc->ndis_block->nmb_miniportadapterctx; if (adapter == NULL) return(ENXIO); - sendfunc = sc->ndis_chars.nmc_sendmulti_func; - senddonefunc = sc->ndis_block.nmb_senddone_func; + sendfunc = sc->ndis_chars->nmc_sendmulti_func; + senddonefunc = sc->ndis_block->nmb_senddone_func; irql = KeRaiseIrql(DISPATCH_LEVEL); sendfunc(adapter, packets, cnt); KeLowerIrql(irql); @@ -1207,7 +1223,7 @@ ndis_send_packets(arg, packets, cnt) */ if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) continue; - senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status); + senddonefunc(sc->ndis_block, p, p->np_oob.npo_status); } return(0); @@ -1226,11 +1242,11 @@ ndis_send_packet(arg, packet) uint8_t irql; sc = arg; - adapter = sc->ndis_block.nmb_miniportadapterctx; + adapter = sc->ndis_block->nmb_miniportadapterctx; if (adapter == NULL) return(ENXIO); - sendfunc = sc->ndis_chars.nmc_sendsingle_func; - senddonefunc = sc->ndis_block.nmb_senddone_func; + sendfunc = sc->ndis_chars->nmc_sendsingle_func; + senddonefunc = sc->ndis_block->nmb_senddone_func; irql = KeRaiseIrql(DISPATCH_LEVEL); status = sendfunc(adapter, packet, packet->np_private.npp_flags); @@ -1239,7 +1255,7 @@ ndis_send_packet(arg, packet) if (status == NDIS_STATUS_PENDING) return(0); - senddonefunc(&sc->ndis_block, packet, status); + senddonefunc(sc->ndis_block, packet, status); return(0); } @@ -1315,8 +1331,8 @@ ndis_reset_nic(arg) sc = arg; ifp = &sc->arpcom.ac_if; NDIS_LOCK(sc); - adapter = sc->ndis_block.nmb_miniportadapterctx; - resetfunc = sc->ndis_chars.nmc_reset_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; + resetfunc = sc->ndis_chars->nmc_reset_func; NDIS_UNLOCK(sc); if (adapter == NULL || resetfunc == NULL) return(EIO); @@ -1347,7 +1363,7 @@ ndis_halt_nic(arg) ifp = &sc->arpcom.ac_if; NDIS_LOCK(sc); - adapter = sc->ndis_block.nmb_miniportadapterctx; + adapter = sc->ndis_block->nmb_miniportadapterctx; if (adapter == NULL) { NDIS_UNLOCK(sc); return(EIO); @@ -1359,13 +1375,13 @@ ndis_halt_nic(arg) * halt handler has been called. */ - haltfunc = sc->ndis_chars.nmc_halt_func; + haltfunc = sc->ndis_chars->nmc_halt_func; NDIS_UNLOCK(sc); haltfunc(adapter); NDIS_LOCK(sc); - sc->ndis_block.nmb_miniportadapterctx = NULL; + sc->ndis_block->nmb_miniportadapterctx = NULL; NDIS_UNLOCK(sc); return(0); @@ -1381,19 +1397,19 @@ ndis_shutdown_nic(arg) sc = arg; NDIS_LOCK(sc); - adapter = sc->ndis_block.nmb_miniportadapterctx; - shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; + adapter = sc->ndis_block->nmb_miniportadapterctx; + shutdownfunc = sc->ndis_chars->nmc_shutdown_handler; NDIS_UNLOCK(sc); if (adapter == NULL || shutdownfunc == NULL) return(EIO); - if (sc->ndis_chars.nmc_rsvd0 == NULL) + if (sc->ndis_chars->nmc_rsvd0 == NULL) shutdownfunc(adapter); else - shutdownfunc(sc->ndis_chars.nmc_rsvd0); + shutdownfunc(sc->ndis_chars->nmc_rsvd0); ndis_shrink_thrqueue(8); - TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); + TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); return(0); } @@ -1414,8 +1430,8 @@ ndis_init_nic(arg) sc = arg; NDIS_LOCK(sc); - block = &sc->ndis_block; - initfunc = sc->ndis_chars.nmc_init_func; + block = sc->ndis_block; + initfunc = sc->ndis_chars->nmc_init_func; NDIS_UNLOCK(sc); TAILQ_INIT(&block->nmb_timerlist); @@ -1433,7 +1449,7 @@ ndis_init_nic(arg) */ if (status != NDIS_STATUS_SUCCESS) { NDIS_LOCK(sc); - sc->ndis_block.nmb_miniportadapterctx = NULL; + sc->ndis_block->nmb_miniportadapterctx = NULL; NDIS_UNLOCK(sc); return(ENXIO); } @@ -1450,8 +1466,8 @@ ndis_enable_intr(arg) __stdcall ndis_enable_interrupts_handler intrenbfunc; sc = arg; - adapter = sc->ndis_block.nmb_miniportadapterctx; - intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; + intrenbfunc = sc->ndis_chars->nmc_enable_interrupts_func; if (adapter == NULL || intrenbfunc == NULL) return; intrenbfunc(adapter); @@ -1468,10 +1484,8 @@ ndis_disable_intr(arg) __stdcall ndis_disable_interrupts_handler intrdisfunc; sc = arg; - NDIS_LOCK(sc); - adapter = sc->ndis_block.nmb_miniportadapterctx; - intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; - NDIS_UNLOCK(sc); + adapter = sc->ndis_block->nmb_miniportadapterctx; + intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func; if (adapter == NULL || intrdisfunc == NULL) return; intrdisfunc(adapter); @@ -1494,8 +1508,8 @@ ndis_isr(arg, ourintr, callhandler) return(EINVAL); sc = arg; - adapter = sc->ndis_block.nmb_miniportadapterctx; - isrfunc = sc->ndis_chars.nmc_isr_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; + isrfunc = sc->ndis_chars->nmc_isr_func; if (adapter == NULL || isrfunc == NULL) return(ENXIO); @@ -1519,8 +1533,8 @@ ndis_intrhand(arg) sc = arg; NDIS_LOCK(sc); - adapter = sc->ndis_block.nmb_miniportadapterctx; - intrfunc = sc->ndis_chars.nmc_interrupt_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; + intrfunc = sc->ndis_chars->nmc_interrupt_func; NDIS_UNLOCK(sc); if (adapter == NULL || intrfunc == NULL) return(EINVAL); @@ -1547,27 +1561,27 @@ ndis_get_info(arg, oid, buf, buflen) sc = arg; NDIS_LOCK(sc); - queryfunc = sc->ndis_chars.nmc_queryinfo_func; - adapter = sc->ndis_block.nmb_miniportadapterctx; + queryfunc = sc->ndis_chars->nmc_queryinfo_func; + adapter = sc->ndis_block->nmb_miniportadapterctx; NDIS_UNLOCK(sc); if (adapter == NULL || queryfunc == NULL) return(ENXIO); - KeAcquireSpinLock(&sc->ndis_block.nmb_lock, &irql); + KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); rval = queryfunc(adapter, oid, buf, *buflen, &byteswritten, &bytesneeded); - KeReleaseSpinLock(&sc->ndis_block.nmb_lock, irql); + KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); /* Wait for requests that block. */ if (rval == NDIS_STATUS_PENDING) { mtx_lock(&ndis_req_mtx); - error = msleep(&sc->ndis_block.nmb_getstat, + error = msleep(&sc->ndis_block->nmb_getstat, &ndis_req_mtx, curthread->td_priority|PDROP, "ndisget", 5 * hz); - rval = sc->ndis_block.nmb_getstat; + rval = sc->ndis_block->nmb_getstat; } if (byteswritten) @@ -1592,96 +1606,39 @@ ndis_get_info(arg, oid, buf, buflen) return(0); } -int -ndis_unload_driver(arg) - void *arg; +__stdcall uint32_t +NdisAddDevice(drv, pdo) + driver_object *drv; + device_object *pdo; { + device_object *fdo; + ndis_miniport_block *block; struct ndis_softc *sc; + uint32_t status; - sc = arg; - - free(sc->ndis_block.nmb_rlist, M_DEVBUF); - - ndis_flush_sysctls(sc); - - ndis_shrink_thrqueue(8); - TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); - - return(0); -} - -#define NDIS_LOADED htonl(0x42534F44) - -int -ndis_load_driver(img, arg) - vm_offset_t img; - void *arg; -{ - driver_entry entry; - image_optional_header opt_hdr; - image_import_descriptor imp_desc; - ndis_unicode_string dummystr; - ndis_miniport_block *block; - ndis_status status; - int idx; - uint32_t *ptr; - struct ndis_softc *sc; - - sc = arg; + status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, + FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); - /* - * Only perform the relocation/linking phase once - * since the binary image may be shared among multiple - * device instances. - */ - - ptr = (uint32_t *)(img + 8); - if (*ptr != NDIS_LOADED) { - /* Perform text relocation */ - if (pe_relocate(img)) - return(ENOEXEC); - - /* Dynamically link the NDIS.SYS routines -- required. */ - if (pe_patch_imports(img, "NDIS", ndis_functbl)) - return(ENOEXEC); - - /* Dynamically link the HAL.dll routines -- also required. */ - if (pe_patch_imports(img, "HAL", hal_functbl)) - return(ENOEXEC); - - /* Dynamically link ntoskrnl.exe -- optional. */ - if (pe_get_import_descriptor(img, - &imp_desc, "ntoskrnl") == 0) { - if (pe_patch_imports(img, - "ntoskrnl", ntoskrnl_functbl)) - return(ENOEXEC); - } - *ptr = NDIS_LOADED; - } + if (status != STATUS_SUCCESS) + return(status); - /* Locate the driver entry point */ - pe_get_optional_header(img, &opt_hdr); - entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); - - dummystr.nus_len = strlen(NDIS_DUMMY_PATH) * 2; - dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH) * 2; - dummystr.nus_buf = NULL; - ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); + block = fdo->do_devext; + block->nmb_deviceobj = fdo; + block->nmb_physdeviceobj = pdo; + block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); + KeInitializeSpinLock(&block->nmb_lock); /* - * Now that we have the miniport driver characteristics, - * create an NDIS block and call the init handler. - * This will cause the driver to try to probe for - * a device. - */ - - block = &sc->ndis_block; + * Stash pointers to the miniport block and miniport + * characteristics info in the if_ndis softc so the + * UNIX wrapper driver can get to them later. + */ - ptr = (uint32_t *)block; - for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { - *ptr = idx | 0xdead0000; - ptr++; - } + sc = device_get_softc(pdo->do_devext); + sc->ndis_block = block; + sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); + + /* Finish up BSD-specific setup. */ block->nmb_signature = (void *)0xcafebabe; block->nmb_setdone_func = ndis_setdone_func; @@ -1691,27 +1648,32 @@ ndis_load_driver(img, arg) block->nmb_resetdone_func = ndis_resetdone_func; block->nmb_sendrsrc_func = ndis_sendrsrcavail_func; - block->nmb_ifp = &sc->arpcom.ac_if; - block->nmb_dev = sc->ndis_dev; - block->nmb_img = img; - block->nmb_devobj.do_rsvd = block; + ndis_enlarge_thrqueue(8); - /* - * Now call the DriverEntry() routine. This will cause - * a callout to the NdisInitializeWrapper() and - * NdisMRegisterMiniport() routines. - */ - status = entry(&block->nmb_devobj, &dummystr); + TAILQ_INSERT_TAIL(&ndis_devhead, block, link); - free (dummystr.nus_buf, M_DEVBUF); + return (STATUS_SUCCESS); +} - if (status != NDIS_STATUS_SUCCESS) - return(ENODEV); +int +ndis_unload_driver(arg) + void *arg; +{ + struct ndis_softc *sc; + device_object *fdo; - ndis_enlarge_thrqueue(8); + sc = arg; - TAILQ_INSERT_TAIL(&ndis_devhead, block, link); - KeInitializeSpinLock(&block->nmb_lock); + free(sc->ndis_block->nmb_rlist, M_DEVBUF); + + ndis_flush_sysctls(sc); + + ndis_shrink_thrqueue(8); + TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); + + fdo = sc->ndis_block->nmb_deviceobj; + IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); + IoDeleteDevice(fdo); return(0); } |