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 <compat/ndis/pe_var.h>
60 #include <compat/ndis/cfg_var.h>
61 #include <compat/ndis/resource_var.h>
62 #include <compat/ndis/ntoskrnl_var.h>
63 #include <compat/ndis/ndis_var.h>
64 #include <compat/ndis/hal_var.h>
65 #include <compat/ndis/usbd_var.h>
67 static struct mtx drvdb_mtx;
68 static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
70 static driver_object fake_pci_driver; /* serves both PCI and cardbus */
71 static driver_object fake_pccard_driver;
74 static void x86_oldldt(void *);
75 static void x86_newldt(void *);
78 void *tid_except_list; /* 0x00 */
79 uint32_t tid_oldfs; /* 0x04 */
80 uint32_t tid_selector; /* 0x08 */
81 struct tid *tid_self; /* 0x0C */
82 int tid_cpu; /* 0x10 */
85 static struct tid *my_tids;
88 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
93 STAILQ_INIT(&drvdb_head);
94 mtx_init(&drvdb_mtx, "Windows driver DB lock",
95 "Windows internal lock", MTX_DEF);
98 * PCI and pccard devices don't need to use IRPs to
99 * interact with their bus drivers (usually), so our
100 * emulated PCI and pccard drivers are just stubs.
101 * USB devices, on the other hand, do all their I/O
102 * by exchanging IRPs with the USB bus driver, so
103 * for that we need to provide emulator dispatcher
104 * routines, which are in a separate module.
107 windrv_bus_attach(&fake_pci_driver, "PCI Bus");
108 windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus");
113 * In order to properly support SMP machines, we have
114 * to modify the GDT on each CPU, since we never know
115 * on which one we'll end up running.
118 my_tids = ExAllocatePoolWithTag(NonPagedPool,
119 sizeof(struct tid) * mp_ncpus, 0);
121 panic("failed to allocate thread info blocks");
122 smp_rendezvous(NULL, x86_newldt, NULL, NULL);
132 mtx_lock(&drvdb_mtx);
133 while(STAILQ_FIRST(&drvdb_head) != NULL) {
134 d = STAILQ_FIRST(&drvdb_head);
135 STAILQ_REMOVE_HEAD(&drvdb_head, link);
138 mtx_unlock(&drvdb_mtx);
140 RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
141 RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
143 mtx_destroy(&drvdb_mtx);
146 smp_rendezvous(NULL, x86_oldldt, NULL, NULL);
153 * Given the address of a driver image, find its corresponding
158 windrv_lookup(img, name)
166 bzero((char *)&us, sizeof(us));
171 RtlInitAnsiString(&as, name);
172 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
176 mtx_lock(&drvdb_mtx);
177 STAILQ_FOREACH(d, &drvdb_head, link) {
178 if (d->windrv_object->dro_driverstart == (void *)img ||
179 (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
180 (char *)us.us_buf, us.us_len) == 0 && us.us_len)) {
181 mtx_unlock(&drvdb_mtx);
183 ExFreePool(us.us_buf);
184 return(d->windrv_object);
187 mtx_unlock(&drvdb_mtx);
190 RtlFreeUnicodeString(&us);
196 windrv_match(matchfunc, ctx)
197 matchfuncptr matchfunc;
203 mtx_lock(&drvdb_mtx);
204 STAILQ_FOREACH(d, &drvdb_head, link) {
205 if (d->windrv_devlist == NULL)
207 match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx);
209 mtx_unlock(&drvdb_mtx);
213 mtx_unlock(&drvdb_mtx);
219 * Remove a driver_object from our datatabase and destroy it. Throw
220 * away any custom driver extension info that may have been added.
224 windrv_unload(mod, img, len)
229 struct drvdb_ent *db, *r = NULL;
231 device_object *d, *pdo;
235 drv = windrv_lookup(img, NULL);
238 * When we unload a driver image, we need to force a
239 * detach of any devices that might be using it. We
240 * need the PDOs of all attached devices for this.
241 * Getting at them is a little hard. We basically
242 * have to walk the device lists of all our bus
246 mtx_lock(&drvdb_mtx);
247 STAILQ_FOREACH(db, &drvdb_head, link) {
249 * Fake bus drivers have no devlist info.
250 * If this driver has devlist info, it's
251 * a loaded Windows driver and has no PDOs,
254 if (db->windrv_devlist != NULL)
256 pdo = db->windrv_object->dro_devobj;
257 while (pdo != NULL) {
258 d = pdo->do_attacheddev;
259 if (d->do_drvobj != drv) {
260 pdo = pdo->do_nextdev;
263 dev = pdo->do_devext;
264 pdo = pdo->do_nextdev;
265 mtx_unlock(&drvdb_mtx);
267 mtx_lock(&drvdb_mtx);
271 STAILQ_FOREACH(db, &drvdb_head, link) {
272 if (db->windrv_object->dro_driverstart == (void *)img) {
274 STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link);
278 mtx_unlock(&drvdb_mtx);
287 * Destroy any custom extensions that may have been added.
289 drv = r->windrv_object;
290 while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
291 e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
295 /* Free the driver extension */
296 free(drv->dro_driverext, M_DEVBUF);
298 /* Free the driver name */
299 RtlFreeUnicodeString(&drv->dro_drivername);
301 /* Free driver object */
304 /* Free our DB handle */
310 #define WINDRV_LOADED htonl(0x42534F44)
313 * Loader routine for actual Windows driver modules, ultimately
314 * calls the driver's DriverEntry() routine.
318 windrv_load(mod, img, len, bustype, devlist, regvals)
322 interface_type bustype;
326 image_import_descriptor imp_desc;
327 image_optional_header opt_hdr;
329 struct drvdb_ent *new;
330 struct driver_object *drv;
336 * First step: try to relocate and dynalink the executable
340 ptr = (uint32_t *)(img + 8);
341 if (*ptr == WINDRV_LOADED)
344 /* Perform text relocation */
345 if (pe_relocate(img))
348 /* Dynamically link the NDIS.SYS routines -- required. */
349 if (pe_patch_imports(img, "NDIS", ndis_functbl))
352 /* Dynamically link the HAL.dll routines -- also required. */
353 if (pe_patch_imports(img, "HAL", hal_functbl))
356 /* Dynamically link ntoskrnl.exe -- optional. */
357 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
358 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
362 /* Dynamically link USBD.SYS -- optional */
363 if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
364 if (pe_patch_imports(img, "USBD", usbd_functbl))
368 *ptr = WINDRV_LOADED;
372 /* Next step: find the driver entry point. */
374 pe_get_optional_header(img, &opt_hdr);
375 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
377 /* Next step: allocate and store a driver object. */
379 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
383 drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
385 free (new, M_DEVBUF);
389 /* Allocate a driver extension structure too. */
391 drv->dro_driverext = malloc(sizeof(driver_extension),
392 M_DEVBUF, M_NOWAIT|M_ZERO);
394 if (drv->dro_driverext == NULL) {
400 InitializeListHead((&drv->dro_driverext->dre_usrext));
402 drv->dro_driverstart = (void *)img;
403 drv->dro_driversize = len;
405 RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
406 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
412 new->windrv_object = drv;
413 new->windrv_regvals = regvals;
414 new->windrv_devlist = devlist;
415 new->windrv_bustype = bustype;
417 /* Now call the DriverEntry() function. */
419 status = MSCALL2(entry, drv, &drv->dro_drivername);
421 if (status != STATUS_SUCCESS) {
422 RtlFreeUnicodeString(&drv->dro_drivername);
428 mtx_lock(&drvdb_mtx);
429 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
430 mtx_unlock(&drvdb_mtx);
436 * Make a new Physical Device Object for a device that was
437 * detected/plugged in. For us, the PDO is just a way to
438 * get at the device_t.
442 windrv_create_pdo(drv, bsddev)
449 * This is a new physical device object, which technically
450 * is the "top of the stack." Consequently, we don't do
451 * an IoAttachDeviceToDeviceStack() here.
454 mtx_lock(&drvdb_mtx);
455 IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
456 mtx_unlock(&drvdb_mtx);
458 /* Stash pointer to our BSD device handle. */
460 dev->do_devext = bsddev;
462 return(STATUS_SUCCESS);
466 windrv_destroy_pdo(drv, bsddev)
472 pdo = windrv_find_pdo(drv, bsddev);
474 /* Remove reference to device_t */
476 pdo->do_devext = NULL;
478 mtx_lock(&drvdb_mtx);
480 mtx_unlock(&drvdb_mtx);
486 * Given a device_t, find the corresponding PDO in a driver's
491 windrv_find_pdo(drv, bsddev)
497 mtx_lock(&drvdb_mtx);
498 pdo = drv->dro_devobj;
499 while (pdo != NULL) {
500 if (pdo->do_devext == bsddev) {
501 mtx_unlock(&drvdb_mtx);
504 pdo = pdo->do_nextdev;
506 mtx_unlock(&drvdb_mtx);
512 * Add an internally emulated driver to the database. We need this
513 * to set up an emulated bus driver so that it can receive IRPs.
517 windrv_bus_attach(drv, name)
521 struct drvdb_ent *new;
524 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
528 RtlInitAnsiString(&as, name);
529 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
533 * Set up a fake image pointer to avoid false matches
534 * in windrv_lookup().
536 drv->dro_driverstart = (void *)0xFFFFFFFF;
538 new->windrv_object = drv;
539 new->windrv_devlist = NULL;
540 new->windrv_regvals = NULL;
542 mtx_lock(&drvdb_mtx);
543 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
544 mtx_unlock(&drvdb_mtx);
551 extern void x86_64_wrap(void);
552 extern void x86_64_wrap_call(void);
553 extern void x86_64_wrap_end(void);
556 windrv_wrap(func, wrap, argcnt, ftype)
563 vm_offset_t *calladdr;
564 vm_offset_t wrapstart, wrapend, wrapcall;
566 wrapstart = (vm_offset_t)&x86_64_wrap;
567 wrapend = (vm_offset_t)&x86_64_wrap_end;
568 wrapcall = (vm_offset_t)&x86_64_wrap_call;
570 /* Allocate a new wrapper instance. */
572 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
576 /* Copy over the code. */
578 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
580 /* Insert the function address into the new wrapper instance. */
582 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
583 *calladdr = (vm_offset_t)func;
589 #endif /* __amd64__ */
606 } __attribute__((__packed__));
608 extern uint16_t x86_getfs(void);
609 extern void x86_setfs(uint16_t);
610 extern void *x86_gettid(void);
611 extern void x86_critical_enter(void);
612 extern void x86_critical_exit(void);
613 extern void x86_getldt(struct gdt *, uint16_t *);
614 extern void x86_setldt(struct gdt *, uint16_t);
616 #define SEL_LDT 4 /* local descriptor table */
617 #define SEL_TO_FS(x) (((x) << 3))
620 * FreeBSD 6.0 and later has a special GDT segment reserved
621 * specifically for us, so if GNDIS_SEL is defined, use that.
622 * If not, use GTGATE_SEL, which is uninitialized and infrequently
627 #define FREEBSD_EMPTYSEL GNDIS_SEL
629 #define FREEBSD_EMPTYSEL GTGATE_SEL /* slot 7 */
633 * The meanings of various bits in a descriptor vary a little
634 * depending on whether the descriptor will be used as a
635 * code, data or system descriptor. (And that in turn depends
636 * on which segment register selects the descriptor.)
637 * We're only trying to create a data segment, so the definitions
638 * below are the ones that apply to a data descriptor.
641 #define SEGFLAGLO_PRESENT 0x80 /* segment is present */
642 #define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */
643 #define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */
644 #define SEGFLAGLO_MBZ 0x08 /* must be zero */
645 #define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */
646 #define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */
647 #define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */
649 #define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */
650 #define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */
653 * Context switch from UNIX to Windows. Save the existing value
654 * of %fs for this processor, then change it to point to our
655 * fake TID. Note that it is also possible to pin ourselves
656 * to our current CPU, though I'm not sure this is really
657 * necessary. It depends on whether or not an interrupt might
658 * preempt us while Windows code is running and we wind up
659 * scheduled onto another CPU as a result. So far, it doesn't
660 * seem like this is what happens.
668 t = &my_tids[curthread->td_oncpu];
671 * Ugly hack. During system bootstrap (cold == 1), only CPU 0
672 * is running. So if we were loaded at bootstrap, only CPU 0
673 * will have our special GDT entry. This is a problem for SMP
674 * systems, so to deal with this, we check here to make sure
675 * the TID for this processor has been initialized, and if it
676 * hasn't, we need to do it right now or else things will
680 if (t->tid_self != t)
683 x86_critical_enter();
684 t->tid_oldfs = x86_getfs();
685 t->tid_cpu = curthread->td_oncpu;
687 x86_setfs(SEL_TO_FS(t->tid_selector));
690 /* Now entering Windows land, population: you. */
696 * Context switch from Windows back to UNIX. Restore %fs to
697 * its previous value. This always occurs after a call to
706 x86_critical_enter();
708 x86_setfs(t->tid_oldfs);
712 /* Welcome back to UNIX land, we missed you. */
715 if (t->tid_cpu != curthread->td_oncpu)
716 panic("ctxsw GOT MOVED TO OTHER CPU!");
721 static int windrv_wrap_stdcall(funcptr, funcptr *, int);
722 static int windrv_wrap_fastcall(funcptr, funcptr *, int);
723 static int windrv_wrap_regparm(funcptr, funcptr *);
725 extern void x86_fastcall_wrap(void);
726 extern void x86_fastcall_wrap_call(void);
727 extern void x86_fastcall_wrap_arg(void);
728 extern void x86_fastcall_wrap_end(void);
731 windrv_wrap_fastcall(func, wrap, argcnt)
737 vm_offset_t *calladdr;
739 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
741 wrapstart = (vm_offset_t)&x86_fastcall_wrap;
742 wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
743 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
744 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
746 /* Allocate a new wrapper instance. */
748 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
752 /* Copy over the code. */
754 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
756 /* Insert the function address into the new wrapper instance. */
758 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
759 *calladdr = (vm_offset_t)func;
765 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
766 *argaddr = argcnt * sizeof(uint32_t);
773 extern void x86_stdcall_wrap(void);
774 extern void x86_stdcall_wrap_call(void);
775 extern void x86_stdcall_wrap_arg(void);
776 extern void x86_stdcall_wrap_end(void);
779 windrv_wrap_stdcall(func, wrap, argcnt)
785 vm_offset_t *calladdr;
787 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
789 wrapstart = (vm_offset_t)&x86_stdcall_wrap;
790 wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
791 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
792 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
794 /* Allocate a new wrapper instance. */
796 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
800 /* Copy over the code. */
802 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
804 /* Insert the function address into the new wrapper instance. */
806 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
807 *calladdr = (vm_offset_t)func;
809 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
810 *argaddr = argcnt * sizeof(uint32_t);
817 extern void x86_regparm_wrap(void);
818 extern void x86_regparm_wrap_call(void);
819 extern void x86_regparm_wrap_end(void);
822 windrv_wrap_regparm(func, wrap)
827 vm_offset_t *calladdr;
828 vm_offset_t wrapstart, wrapend, wrapcall;
830 wrapstart = (vm_offset_t)&x86_regparm_wrap;
831 wrapend = (vm_offset_t)&x86_regparm_wrap_end;
832 wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
834 /* Allocate a new wrapper instance. */
836 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
840 /* Copy over the code. */
842 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
844 /* Insert the function address into the new wrapper instance. */
846 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
847 *calladdr = (vm_offset_t)func;
855 windrv_wrap(func, wrap, argcnt, ftype)
862 case WINDRV_WRAP_FASTCALL:
863 return(windrv_wrap_fastcall(func, wrap, argcnt));
864 case WINDRV_WRAP_STDCALL:
865 return(windrv_wrap_stdcall(func, wrap, argcnt));
866 case WINDRV_WRAP_REGPARM:
867 return(windrv_wrap_regparm(func, wrap));
868 case WINDRV_WRAP_CDECL:
869 return(windrv_wrap_stdcall(func, wrap, 0));
888 mtx_lock_spin(&dt_lock);
890 /* Grab location of existing GDT. */
892 x86_getldt(>able, <able);
894 /* Find the slot we updated. */
897 gdt += FREEBSD_EMPTYSEL;
901 bzero((char *)gdt, sizeof(struct x86desc));
905 x86_setldt(>able, ltable);
907 mtx_unlock_spin(&dt_lock);
923 mtx_lock_spin(&dt_lock);
925 /* Grab location of existing GDT. */
927 x86_getldt(>able, <able);
929 /* Get pointer to the GDT table. */
933 /* Get pointer to empty slot */
935 l += FREEBSD_EMPTYSEL;
937 /* Initialize TID for this CPU. */
939 my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL;
940 my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu];
942 /* Set up new GDT entry. */
944 l->x_lolimit = sizeof(struct tid);
945 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
946 l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF;
947 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF;
948 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF;
949 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
951 /* Update the GDT. */
953 x86_setldt(>able, ltable);
955 mtx_unlock_spin(&dt_lock);
962 #endif /* __i386__ */
968 free(func, M_DEVBUF);