boot/efi: Add paging to the 'memmap' and 'configuration' commands.
[dragonfly.git] / sys / emulation / ndis / kern_windrv.c
bloba6bea68bc63ff95b61d1e93127c9b95f34ca0b2a
1 /*-
2 * Copyright (c) 2005
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
32 * $FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.21 2010/11/22 20:46:38 bschmidt Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/unistd.h>
38 #include <sys/types.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/lock.h>
43 #include <sys/mutex2.h>
44 #include <sys/module.h>
45 #include <sys/conf.h>
46 #include <sys/mbuf.h>
47 #include <sys/bus.h>
48 #include <sys/proc.h>
49 #include <sys/sched.h>
51 #include <sys/queue.h>
53 #include <bus/u4b/usb.h>
54 #include <bus/u4b/usbdi.h>
56 #include <emulation/ndis/pe_var.h>
57 #include <emulation/ndis/cfg_var.h>
58 #include <emulation/ndis/resource_var.h>
59 #include <emulation/ndis/ntoskrnl_var.h>
60 #include <emulation/ndis/ndis_var.h>
61 #include <emulation/ndis/hal_var.h>
62 #include <emulation/ndis/u4bd_var.h>
64 static struct lock drvdb_lock;
65 static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
67 static driver_object fake_pci_driver; /* serves both PCI and cardbus */
68 static driver_object fake_pccard_driver;
70 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
72 int
73 windrv_libinit(void)
75 STAILQ_INIT(&drvdb_head);
76 lockinit(&drvdb_lock, "Windows driver DB lock", 0, LK_CANRECURSE);
79 * PCI and pccard devices don't need to use IRPs to
80 * interact with their bus drivers (usually), so our
81 * emulated PCI and pccard drivers are just stubs.
82 * USB devices, on the other hand, do all their I/O
83 * by exchanging IRPs with the USB bus driver, so
84 * for that we need to provide emulator dispatcher
85 * routines, which are in a separate module.
88 windrv_bus_attach(&fake_pci_driver, "PCI Bus");
89 windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus");
91 return (0);
94 int
95 windrv_libfini(void)
97 struct drvdb_ent *d;
99 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
100 while(STAILQ_FIRST(&drvdb_head) != NULL) {
101 d = STAILQ_FIRST(&drvdb_head);
102 STAILQ_REMOVE_HEAD(&drvdb_head, link);
103 kfree(d, M_DEVBUF);
105 lockmgr(&drvdb_lock, LK_RELEASE);
107 RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
108 RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
110 lockuninit(&drvdb_lock);
112 return (0);
116 * Given the address of a driver image, find its corresponding
117 * driver_object.
120 driver_object *
121 windrv_lookup(vm_offset_t img, char *name)
123 struct drvdb_ent *d;
124 unicode_string us;
125 ansi_string as;
127 bzero((char *)&us, sizeof(us));
129 /* Damn unicode. */
131 if (name != NULL) {
132 RtlInitAnsiString(&as, name);
133 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
134 return (NULL);
137 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
138 STAILQ_FOREACH(d, &drvdb_head, link) {
139 if (d->windrv_object->dro_driverstart == (void *)img ||
140 (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
141 (char *)us.us_buf, us.us_len) == 0 && us.us_len)) {
142 lockmgr(&drvdb_lock, LK_RELEASE);
143 if (name != NULL)
144 ExFreePool(us.us_buf);
145 return (d->windrv_object);
148 lockmgr(&drvdb_lock, LK_RELEASE);
150 if (name != NULL)
151 RtlFreeUnicodeString(&us);
153 return (NULL);
156 struct drvdb_ent *
157 windrv_match(matchfuncptr matchfunc, void *ctx)
159 struct drvdb_ent *d;
160 int match;
162 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
163 STAILQ_FOREACH(d, &drvdb_head, link) {
164 if (d->windrv_devlist == NULL)
165 continue;
166 match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx);
167 if (match == TRUE) {
168 lockmgr(&drvdb_lock, LK_RELEASE);
169 return (d);
172 lockmgr(&drvdb_lock, LK_RELEASE);
174 return (NULL);
178 * Remove a driver_object from our datatabase and destroy it. Throw
179 * away any custom driver extension info that may have been added.
183 windrv_unload(module_t mod, vm_offset_t img, int len)
185 struct drvdb_ent *db, *r = NULL;
186 driver_object *drv;
187 device_object *d, *pdo;
188 device_t dev;
189 list_entry *e;
191 drv = windrv_lookup(img, NULL);
194 * When we unload a driver image, we need to force a
195 * detach of any devices that might be using it. We
196 * need the PDOs of all attached devices for this.
197 * Getting at them is a little hard. We basically
198 * have to walk the device lists of all our bus
199 * drivers.
202 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
203 STAILQ_FOREACH(db, &drvdb_head, link) {
205 * Fake bus drivers have no devlist info.
206 * If this driver has devlist info, it's
207 * a loaded Windows driver and has no PDOs,
208 * so skip it.
210 if (db->windrv_devlist != NULL)
211 continue;
212 pdo = db->windrv_object->dro_devobj;
213 while (pdo != NULL) {
214 d = pdo->do_attacheddev;
215 if (d->do_drvobj != drv) {
216 pdo = pdo->do_nextdev;
217 continue;
219 dev = pdo->do_devext;
220 pdo = pdo->do_nextdev;
221 lockmgr(&drvdb_lock, LK_RELEASE);
222 device_detach(dev);
223 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
227 STAILQ_FOREACH(db, &drvdb_head, link) {
228 if (db->windrv_object->dro_driverstart == (void *)img) {
229 r = db;
230 STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link);
231 break;
234 lockmgr(&drvdb_lock, LK_RELEASE);
236 if (r == NULL)
237 return (ENOENT);
239 if (drv == NULL)
240 return (ENOENT);
243 * Destroy any custom extensions that may have been added.
245 drv = r->windrv_object;
246 while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
247 e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
248 ExFreePool(e);
251 /* Free the driver extension */
252 kfree(drv->dro_driverext, M_DEVBUF);
254 /* Free the driver name */
255 RtlFreeUnicodeString(&drv->dro_drivername);
257 /* Free driver object */
258 kfree(drv, M_DEVBUF);
260 /* Free our DB handle */
261 kfree(r, M_DEVBUF);
263 return (0);
266 #define WINDRV_LOADED htonl(0x42534F44)
268 #ifdef __x86_64__
269 static void
270 patch_user_shared_data_address(vm_offset_t img, size_t len)
272 unsigned long i, n, max_addr, *addr;
274 n = len - sizeof(unsigned long);
275 max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data);
276 for (i = 0; i < n; i++) {
277 addr = (unsigned long *)(img + i);
278 if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) {
279 *addr -= KI_USER_SHARED_DATA;
280 *addr += (unsigned long)&kuser_shared_data;
284 #endif
287 * Loader routine for actual Windows driver modules, ultimately
288 * calls the driver's DriverEntry() routine.
292 windrv_load(module_t mod, vm_offset_t img, int len, interface_type bustype,
293 void *devlist, ndis_cfg *regvals)
295 image_import_descriptor imp_desc;
296 image_optional_header opt_hdr;
297 driver_entry entry;
298 struct drvdb_ent *new;
299 struct driver_object *drv;
300 int status;
301 uint32_t *ptr;
302 ansi_string as;
305 * First step: try to relocate and dynalink the executable
306 * driver image.
309 ptr = (uint32_t *)(img + 8);
310 if (*ptr == WINDRV_LOADED)
311 goto skipreloc;
313 /* Perform text relocation */
314 if (pe_relocate(img))
315 return (ENOEXEC);
317 /* Dynamically link the NDIS.SYS routines -- required. */
318 if (pe_patch_imports(img, "NDIS", ndis_functbl))
319 return (ENOEXEC);
321 /* Dynamically link the HAL.dll routines -- optional. */
322 if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
323 if (pe_patch_imports(img, "HAL", hal_functbl))
324 return (ENOEXEC);
327 /* Dynamically link ntoskrnl.exe -- optional. */
328 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
329 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
330 return (ENOEXEC);
333 #ifdef __x86_64__
334 patch_user_shared_data_address(img, len);
335 #endif
337 /* Dynamically link USBD.SYS -- optional */
338 if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
339 if (pe_patch_imports(img, "USBD", usbd_functbl))
340 return (ENOEXEC);
343 *ptr = WINDRV_LOADED;
345 skipreloc:
347 /* Next step: find the driver entry point. */
349 pe_get_optional_header(img, &opt_hdr);
350 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
352 /* Next step: allocate and store a driver object. */
354 new = kmalloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
355 if (new == NULL)
356 return (ENOMEM);
358 drv = kmalloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
359 if (drv == NULL) {
360 kfree (new, M_DEVBUF);
361 return (ENOMEM);
364 /* Allocate a driver extension structure too. */
366 drv->dro_driverext = kmalloc(sizeof(driver_extension),
367 M_DEVBUF, M_NOWAIT|M_ZERO);
369 if (drv->dro_driverext == NULL) {
370 kfree(new, M_DEVBUF);
371 kfree(drv, M_DEVBUF);
372 return (ENOMEM);
375 InitializeListHead((&drv->dro_driverext->dre_usrext));
377 drv->dro_driverstart = (void *)img;
378 drv->dro_driversize = len;
380 RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
381 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
382 kfree(new, M_DEVBUF);
383 kfree(drv, M_DEVBUF);
384 return (ENOMEM);
387 new->windrv_object = drv;
388 new->windrv_regvals = regvals;
389 new->windrv_devlist = devlist;
390 new->windrv_bustype = bustype;
392 /* Now call the DriverEntry() function. */
394 status = MSCALL2(entry, drv, &drv->dro_drivername);
396 if (status != STATUS_SUCCESS) {
397 RtlFreeUnicodeString(&drv->dro_drivername);
398 kfree(drv, M_DEVBUF);
399 kfree(new, M_DEVBUF);
400 return (ENODEV);
403 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
404 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
405 lockmgr(&drvdb_lock, LK_RELEASE);
407 return (0);
411 * Make a new Physical Device Object for a device that was
412 * detected/plugged in. For us, the PDO is just a way to
413 * get at the device_t.
417 windrv_create_pdo(driver_object *drv, device_t bsddev)
419 device_object *dev;
422 * This is a new physical device object, which technically
423 * is the "top of the stack." Consequently, we don't do
424 * an IoAttachDeviceToDeviceStack() here.
427 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
428 IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
429 lockmgr(&drvdb_lock, LK_RELEASE);
431 /* Stash pointer to our BSD device handle. */
433 dev->do_devext = bsddev;
435 return (STATUS_SUCCESS);
438 void
439 windrv_destroy_pdo(driver_object *drv, device_t bsddev)
441 device_object *pdo;
443 pdo = windrv_find_pdo(drv, bsddev);
445 /* Remove reference to device_t */
447 pdo->do_devext = NULL;
449 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
450 IoDeleteDevice(pdo);
451 lockmgr(&drvdb_lock, LK_RELEASE);
455 * Given a device_t, find the corresponding PDO in a driver's
456 * device list.
459 device_object *
460 windrv_find_pdo(driver_object *drv, device_t bsddev)
462 device_object *pdo;
464 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
465 pdo = drv->dro_devobj;
466 while (pdo != NULL) {
467 if (pdo->do_devext == bsddev) {
468 lockmgr(&drvdb_lock, LK_RELEASE);
469 return (pdo);
471 pdo = pdo->do_nextdev;
473 lockmgr(&drvdb_lock, LK_RELEASE);
475 return (NULL);
479 * Add an internally emulated driver to the database. We need this
480 * to set up an emulated bus driver so that it can receive IRPs.
484 windrv_bus_attach(driver_object *drv, char *name)
486 struct drvdb_ent *new;
487 ansi_string as;
489 new = kmalloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
490 if (new == NULL)
491 return (ENOMEM);
493 RtlInitAnsiString(&as, name);
494 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
496 kfree(new, M_DEVBUF);
497 return (ENOMEM);
501 * Set up a fake image pointer to avoid false matches
502 * in windrv_lookup().
504 drv->dro_driverstart = (void *)0xFFFFFFFF;
506 new->windrv_object = drv;
507 new->windrv_devlist = NULL;
508 new->windrv_regvals = NULL;
510 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
511 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
512 lockmgr(&drvdb_lock, LK_RELEASE);
514 return (0);
517 #ifdef __x86_64__
519 extern void x86_64_wrap(void);
520 extern void x86_64_wrap_call(void);
521 extern void x86_64_wrap_end(void);
524 windrv_wrap(funcptr func, funcptr *wrap, int argcnt, int ftype)
526 funcptr p;
527 vm_offset_t *calladdr;
528 vm_offset_t wrapstart, wrapend, wrapcall;
530 wrapstart = (vm_offset_t)&x86_64_wrap;
531 wrapend = (vm_offset_t)&x86_64_wrap_end;
532 wrapcall = (vm_offset_t)&x86_64_wrap_call;
534 /* Allocate a new wrapper instance. */
536 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
537 if (p == NULL)
538 return (ENOMEM);
540 /* Copy over the code. */
542 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
544 /* Insert the function address into the new wrapper instance. */
546 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
547 *calladdr = (vm_offset_t)func;
549 *wrap = p;
551 return (0);
553 #endif /* __x86_64__ */
557 windrv_unwrap(funcptr func)
559 kfree(func, M_DEVBUF);
561 return (0);