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
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.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/unistd.h>
39 #include <sys/types.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
44 #include <sys/mutex.h>
45 #include <sys/module.h>
50 #include <sys/sched.h>
53 #include <sys/queue.h>
56 #include <machine/segments.h>
59 #include <dev/usb/usb.h>
61 #include <compat/ndis/pe_var.h>
62 #include <compat/ndis/cfg_var.h>
63 #include <compat/ndis/resource_var.h>
64 #include <compat/ndis/ntoskrnl_var.h>
65 #include <compat/ndis/ndis_var.h>
66 #include <compat/ndis/hal_var.h>
67 #include <compat/ndis/usbd_var.h>
69 static struct mtx drvdb_mtx;
70 static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
72 static driver_object fake_pci_driver; /* serves both PCI and cardbus */
73 static driver_object fake_pccard_driver;
76 static void x86_oldldt(void *);
77 static void x86_newldt(void *);
80 void *tid_except_list; /* 0x00 */
81 uint32_t tid_oldfs; /* 0x04 */
82 uint32_t tid_selector; /* 0x08 */
83 struct tid *tid_self; /* 0x0C */
84 int tid_cpu; /* 0x10 */
87 static struct tid *my_tids;
90 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
95 STAILQ_INIT(&drvdb_head);
96 mtx_init(&drvdb_mtx, "Windows driver DB lock",
97 "Windows internal lock", MTX_DEF);
100 * PCI and pccard devices don't need to use IRPs to
101 * interact with their bus drivers (usually), so our
102 * emulated PCI and pccard drivers are just stubs.
103 * USB devices, on the other hand, do all their I/O
104 * by exchanging IRPs with the USB bus driver, so
105 * for that we need to provide emulator dispatcher
106 * routines, which are in a separate module.
109 windrv_bus_attach(&fake_pci_driver, "PCI Bus");
110 windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus");
115 * In order to properly support SMP machines, we have
116 * to modify the GDT on each CPU, since we never know
117 * on which one we'll end up running.
120 my_tids = ExAllocatePoolWithTag(NonPagedPool,
121 sizeof(struct tid) * mp_ncpus, 0);
123 panic("failed to allocate thread info blocks");
124 smp_rendezvous(NULL, x86_newldt, NULL, NULL);
134 mtx_lock(&drvdb_mtx);
135 while(STAILQ_FIRST(&drvdb_head) != NULL) {
136 d = STAILQ_FIRST(&drvdb_head);
137 STAILQ_REMOVE_HEAD(&drvdb_head, link);
140 mtx_unlock(&drvdb_mtx);
142 RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
143 RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
145 mtx_destroy(&drvdb_mtx);
148 smp_rendezvous(NULL, x86_oldldt, NULL, NULL);
155 * Given the address of a driver image, find its corresponding
160 windrv_lookup(img, name)
168 bzero((char *)&us, sizeof(us));
173 RtlInitAnsiString(&as, name);
174 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
178 mtx_lock(&drvdb_mtx);
179 STAILQ_FOREACH(d, &drvdb_head, link) {
180 if (d->windrv_object->dro_driverstart == (void *)img ||
181 (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
182 (char *)us.us_buf, us.us_len) == 0 && us.us_len)) {
183 mtx_unlock(&drvdb_mtx);
185 ExFreePool(us.us_buf);
186 return(d->windrv_object);
189 mtx_unlock(&drvdb_mtx);
192 RtlFreeUnicodeString(&us);
198 windrv_match(matchfunc, ctx)
199 matchfuncptr matchfunc;
205 mtx_lock(&drvdb_mtx);
206 STAILQ_FOREACH(d, &drvdb_head, link) {
207 if (d->windrv_devlist == NULL)
209 match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx);
211 mtx_unlock(&drvdb_mtx);
215 mtx_unlock(&drvdb_mtx);
221 * Remove a driver_object from our datatabase and destroy it. Throw
222 * away any custom driver extension info that may have been added.
226 windrv_unload(mod, img, len)
231 struct drvdb_ent *db, *r = NULL;
233 device_object *d, *pdo;
237 drv = windrv_lookup(img, NULL);
240 * When we unload a driver image, we need to force a
241 * detach of any devices that might be using it. We
242 * need the PDOs of all attached devices for this.
243 * Getting at them is a little hard. We basically
244 * have to walk the device lists of all our bus
248 mtx_lock(&drvdb_mtx);
249 STAILQ_FOREACH(db, &drvdb_head, link) {
251 * Fake bus drivers have no devlist info.
252 * If this driver has devlist info, it's
253 * a loaded Windows driver and has no PDOs,
256 if (db->windrv_devlist != NULL)
258 pdo = db->windrv_object->dro_devobj;
259 while (pdo != NULL) {
260 d = pdo->do_attacheddev;
261 if (d->do_drvobj != drv) {
262 pdo = pdo->do_nextdev;
265 dev = pdo->do_devext;
266 pdo = pdo->do_nextdev;
267 mtx_unlock(&drvdb_mtx);
269 mtx_lock(&drvdb_mtx);
273 STAILQ_FOREACH(db, &drvdb_head, link) {
274 if (db->windrv_object->dro_driverstart == (void *)img) {
276 STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link);
280 mtx_unlock(&drvdb_mtx);
289 * Destroy any custom extensions that may have been added.
291 drv = r->windrv_object;
292 while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
293 e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
297 /* Free the driver extension */
298 free(drv->dro_driverext, M_DEVBUF);
300 /* Free the driver name */
301 RtlFreeUnicodeString(&drv->dro_drivername);
303 /* Free driver object */
306 /* Free our DB handle */
312 #define WINDRV_LOADED htonl(0x42534F44)
315 * Loader routine for actual Windows driver modules, ultimately
316 * calls the driver's DriverEntry() routine.
320 windrv_load(mod, img, len, bustype, devlist, regvals)
324 interface_type bustype;
328 image_import_descriptor imp_desc;
329 image_optional_header opt_hdr;
331 struct drvdb_ent *new;
332 struct driver_object *drv;
338 * First step: try to relocate and dynalink the executable
342 ptr = (uint32_t *)(img + 8);
343 if (*ptr == WINDRV_LOADED)
346 /* Perform text relocation */
347 if (pe_relocate(img))
350 /* Dynamically link the NDIS.SYS routines -- required. */
351 if (pe_patch_imports(img, "NDIS", ndis_functbl))
354 /* Dynamically link the HAL.dll routines -- optional. */
355 if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
356 if (pe_patch_imports(img, "HAL", hal_functbl))
360 /* Dynamically link ntoskrnl.exe -- optional. */
361 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
362 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
366 /* Dynamically link USBD.SYS -- optional */
367 if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
368 if (pe_patch_imports(img, "USBD", usbd_functbl))
372 *ptr = WINDRV_LOADED;
376 /* Next step: find the driver entry point. */
378 pe_get_optional_header(img, &opt_hdr);
379 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
381 /* Next step: allocate and store a driver object. */
383 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
387 drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
389 free (new, M_DEVBUF);
393 /* Allocate a driver extension structure too. */
395 drv->dro_driverext = malloc(sizeof(driver_extension),
396 M_DEVBUF, M_NOWAIT|M_ZERO);
398 if (drv->dro_driverext == NULL) {
404 InitializeListHead((&drv->dro_driverext->dre_usrext));
406 drv->dro_driverstart = (void *)img;
407 drv->dro_driversize = len;
409 RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
410 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
416 new->windrv_object = drv;
417 new->windrv_regvals = regvals;
418 new->windrv_devlist = devlist;
419 new->windrv_bustype = bustype;
421 /* Now call the DriverEntry() function. */
423 status = MSCALL2(entry, drv, &drv->dro_drivername);
425 if (status != STATUS_SUCCESS) {
426 RtlFreeUnicodeString(&drv->dro_drivername);
432 mtx_lock(&drvdb_mtx);
433 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
434 mtx_unlock(&drvdb_mtx);
440 * Make a new Physical Device Object for a device that was
441 * detected/plugged in. For us, the PDO is just a way to
442 * get at the device_t.
446 windrv_create_pdo(drv, bsddev)
453 * This is a new physical device object, which technically
454 * is the "top of the stack." Consequently, we don't do
455 * an IoAttachDeviceToDeviceStack() here.
458 mtx_lock(&drvdb_mtx);
459 IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
460 mtx_unlock(&drvdb_mtx);
462 /* Stash pointer to our BSD device handle. */
464 dev->do_devext = bsddev;
466 return(STATUS_SUCCESS);
470 windrv_destroy_pdo(drv, bsddev)
476 pdo = windrv_find_pdo(drv, bsddev);
478 /* Remove reference to device_t */
480 pdo->do_devext = NULL;
482 mtx_lock(&drvdb_mtx);
484 mtx_unlock(&drvdb_mtx);
490 * Given a device_t, find the corresponding PDO in a driver's
495 windrv_find_pdo(drv, bsddev)
501 mtx_lock(&drvdb_mtx);
502 pdo = drv->dro_devobj;
503 while (pdo != NULL) {
504 if (pdo->do_devext == bsddev) {
505 mtx_unlock(&drvdb_mtx);
508 pdo = pdo->do_nextdev;
510 mtx_unlock(&drvdb_mtx);
516 * Add an internally emulated driver to the database. We need this
517 * to set up an emulated bus driver so that it can receive IRPs.
521 windrv_bus_attach(drv, name)
525 struct drvdb_ent *new;
528 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
532 RtlInitAnsiString(&as, name);
533 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
540 * Set up a fake image pointer to avoid false matches
541 * in windrv_lookup().
543 drv->dro_driverstart = (void *)0xFFFFFFFF;
545 new->windrv_object = drv;
546 new->windrv_devlist = NULL;
547 new->windrv_regvals = NULL;
549 mtx_lock(&drvdb_mtx);
550 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
551 mtx_unlock(&drvdb_mtx);
558 extern void x86_64_wrap(void);
559 extern void x86_64_wrap_call(void);
560 extern void x86_64_wrap_end(void);
563 windrv_wrap(func, wrap, argcnt, ftype)
570 vm_offset_t *calladdr;
571 vm_offset_t wrapstart, wrapend, wrapcall;
573 wrapstart = (vm_offset_t)&x86_64_wrap;
574 wrapend = (vm_offset_t)&x86_64_wrap_end;
575 wrapcall = (vm_offset_t)&x86_64_wrap_call;
577 /* Allocate a new wrapper instance. */
579 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
583 /* Copy over the code. */
585 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
587 /* Insert the function address into the new wrapper instance. */
589 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
590 *calladdr = (vm_offset_t)func;
596 #endif /* __amd64__ */
613 } __attribute__((__packed__));
615 extern uint16_t x86_getfs(void);
616 extern void x86_setfs(uint16_t);
617 extern void *x86_gettid(void);
618 extern void x86_critical_enter(void);
619 extern void x86_critical_exit(void);
620 extern void x86_getldt(struct gdt *, uint16_t *);
621 extern void x86_setldt(struct gdt *, uint16_t);
623 #define SEL_LDT 4 /* local descriptor table */
624 #define SEL_TO_FS(x) (((x) << 3))
627 * FreeBSD 6.0 and later has a special GDT segment reserved
628 * specifically for us, so if GNDIS_SEL is defined, use that.
629 * If not, use GTGATE_SEL, which is uninitialized and infrequently
634 #define FREEBSD_EMPTYSEL GNDIS_SEL
636 #define FREEBSD_EMPTYSEL GTGATE_SEL /* slot 7 */
640 * The meanings of various bits in a descriptor vary a little
641 * depending on whether the descriptor will be used as a
642 * code, data or system descriptor. (And that in turn depends
643 * on which segment register selects the descriptor.)
644 * We're only trying to create a data segment, so the definitions
645 * below are the ones that apply to a data descriptor.
648 #define SEGFLAGLO_PRESENT 0x80 /* segment is present */
649 #define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */
650 #define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */
651 #define SEGFLAGLO_MBZ 0x08 /* must be zero */
652 #define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */
653 #define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */
654 #define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */
656 #define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */
657 #define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */
660 * Context switch from UNIX to Windows. Save the existing value
661 * of %fs for this processor, then change it to point to our
662 * fake TID. Note that it is also possible to pin ourselves
663 * to our current CPU, though I'm not sure this is really
664 * necessary. It depends on whether or not an interrupt might
665 * preempt us while Windows code is running and we wind up
666 * scheduled onto another CPU as a result. So far, it doesn't
667 * seem like this is what happens.
675 t = &my_tids[curthread->td_oncpu];
678 * Ugly hack. During system bootstrap (cold == 1), only CPU 0
679 * is running. So if we were loaded at bootstrap, only CPU 0
680 * will have our special GDT entry. This is a problem for SMP
681 * systems, so to deal with this, we check here to make sure
682 * the TID for this processor has been initialized, and if it
683 * hasn't, we need to do it right now or else things will
687 if (t->tid_self != t)
690 x86_critical_enter();
691 t->tid_oldfs = x86_getfs();
692 t->tid_cpu = curthread->td_oncpu;
694 x86_setfs(SEL_TO_FS(t->tid_selector));
697 /* Now entering Windows land, population: you. */
703 * Context switch from Windows back to UNIX. Restore %fs to
704 * its previous value. This always occurs after a call to
713 x86_critical_enter();
715 x86_setfs(t->tid_oldfs);
719 /* Welcome back to UNIX land, we missed you. */
722 if (t->tid_cpu != curthread->td_oncpu)
723 panic("ctxsw GOT MOVED TO OTHER CPU!");
728 static int windrv_wrap_stdcall(funcptr, funcptr *, int);
729 static int windrv_wrap_fastcall(funcptr, funcptr *, int);
730 static int windrv_wrap_regparm(funcptr, funcptr *);
732 extern void x86_fastcall_wrap(void);
733 extern void x86_fastcall_wrap_call(void);
734 extern void x86_fastcall_wrap_arg(void);
735 extern void x86_fastcall_wrap_end(void);
738 windrv_wrap_fastcall(func, wrap, argcnt)
744 vm_offset_t *calladdr;
746 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
748 wrapstart = (vm_offset_t)&x86_fastcall_wrap;
749 wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
750 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
751 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
753 /* Allocate a new wrapper instance. */
755 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
759 /* Copy over the code. */
761 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
763 /* Insert the function address into the new wrapper instance. */
765 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
766 *calladdr = (vm_offset_t)func;
772 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
773 *argaddr = argcnt * sizeof(uint32_t);
780 extern void x86_stdcall_wrap(void);
781 extern void x86_stdcall_wrap_call(void);
782 extern void x86_stdcall_wrap_arg(void);
783 extern void x86_stdcall_wrap_end(void);
786 windrv_wrap_stdcall(func, wrap, argcnt)
792 vm_offset_t *calladdr;
794 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
796 wrapstart = (vm_offset_t)&x86_stdcall_wrap;
797 wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
798 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
799 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
801 /* Allocate a new wrapper instance. */
803 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
807 /* Copy over the code. */
809 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
811 /* Insert the function address into the new wrapper instance. */
813 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
814 *calladdr = (vm_offset_t)func;
816 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
817 *argaddr = argcnt * sizeof(uint32_t);
824 extern void x86_regparm_wrap(void);
825 extern void x86_regparm_wrap_call(void);
826 extern void x86_regparm_wrap_end(void);
829 windrv_wrap_regparm(func, wrap)
834 vm_offset_t *calladdr;
835 vm_offset_t wrapstart, wrapend, wrapcall;
837 wrapstart = (vm_offset_t)&x86_regparm_wrap;
838 wrapend = (vm_offset_t)&x86_regparm_wrap_end;
839 wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
841 /* Allocate a new wrapper instance. */
843 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
847 /* Copy over the code. */
849 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
851 /* Insert the function address into the new wrapper instance. */
853 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
854 *calladdr = (vm_offset_t)func;
862 windrv_wrap(func, wrap, argcnt, ftype)
869 case WINDRV_WRAP_FASTCALL:
870 return(windrv_wrap_fastcall(func, wrap, argcnt));
871 case WINDRV_WRAP_STDCALL:
872 return(windrv_wrap_stdcall(func, wrap, argcnt));
873 case WINDRV_WRAP_REGPARM:
874 return(windrv_wrap_regparm(func, wrap));
875 case WINDRV_WRAP_CDECL:
876 return(windrv_wrap_stdcall(func, wrap, 0));
892 mtx_lock_spin(&dt_lock);
894 /* Grab location of existing GDT. */
896 x86_getldt(>able, <able);
898 /* Find the slot we updated. */
901 gdt += FREEBSD_EMPTYSEL;
905 bzero((char *)gdt, sizeof(struct x86desc));
909 x86_setldt(>able, ltable);
911 mtx_unlock_spin(&dt_lock);
927 mtx_lock_spin(&dt_lock);
929 /* Grab location of existing GDT. */
931 x86_getldt(>able, <able);
933 /* Get pointer to the GDT table. */
937 /* Get pointer to empty slot */
939 l += FREEBSD_EMPTYSEL;
941 /* Initialize TID for this CPU. */
943 my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL;
944 my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu];
946 /* Set up new GDT entry. */
948 l->x_lolimit = sizeof(struct tid);
949 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
950 l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF;
951 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF;
952 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF;
953 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
955 /* Update the GDT. */
957 x86_setldt(>able, ltable);
959 mtx_unlock_spin(&dt_lock);
966 #endif /* __i386__ */
972 free(func, M_DEVBUF);