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.
32 * $FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.21 2010/11/22 20:46:38 bschmidt Exp $
35 #include "use_usb4bsd.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/unistd.h>
40 #include <sys/types.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
45 #include <sys/mutex2.h>
46 #include <sys/module.h>
51 #include <sys/sched.h>
53 #include <sys/queue.h>
56 #include <machine/segments.h>
60 #include <bus/u4b/usb.h>
61 #include <bus/u4b/usbdi.h>
63 #include <bus/usb/usb.h>
64 #include <bus/usb/usbdi.h>
67 #include <emulation/ndis/pe_var.h>
68 #include <emulation/ndis/cfg_var.h>
69 #include <emulation/ndis/resource_var.h>
70 #include <emulation/ndis/ntoskrnl_var.h>
71 #include <emulation/ndis/ndis_var.h>
72 #include <emulation/ndis/hal_var.h>
74 #include <emulation/ndis/u4bd_var.h>
76 #include <emulation/ndis/usbd_var.h>
79 static struct lock drvdb_lock;
80 static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
82 static driver_object fake_pci_driver; /* serves both PCI and cardbus */
83 static driver_object fake_pccard_driver;
86 static void x86_oldldt(void *);
87 static void x86_newldt(void *);
90 void *tid_except_list; /* 0x00 */
91 uint32_t tid_oldfs; /* 0x04 */
92 uint32_t tid_selector; /* 0x08 */
93 struct tid *tid_self; /* 0x0C */
94 int tid_cpu; /* 0x10 */
97 static struct tid *my_tids;
100 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
105 STAILQ_INIT(&drvdb_head);
106 lockinit(&drvdb_lock, "Windows driver DB lock", 0, LK_CANRECURSE);
109 * PCI and pccard devices don't need to use IRPs to
110 * interact with their bus drivers (usually), so our
111 * emulated PCI and pccard drivers are just stubs.
112 * USB devices, on the other hand, do all their I/O
113 * by exchanging IRPs with the USB bus driver, so
114 * for that we need to provide emulator dispatcher
115 * routines, which are in a separate module.
118 windrv_bus_attach(&fake_pci_driver, "PCI Bus");
119 windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus");
124 * In order to properly support SMP machines, we have
125 * to modify the GDT on each CPU, since we never know
126 * on which one we'll end up running.
129 my_tids = ExAllocatePoolWithTag(NonPagedPool,
130 sizeof(struct tid) * ncpus, 0);
132 panic("failed to allocate thread info blocks");
133 lwkt_cpusync_simple(-1, x86_newldt, NULL);
143 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
144 while(STAILQ_FIRST(&drvdb_head) != NULL) {
145 d = STAILQ_FIRST(&drvdb_head);
146 STAILQ_REMOVE_HEAD(&drvdb_head, link);
149 lockmgr(&drvdb_lock, LK_RELEASE);
151 RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
152 RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
154 lockuninit(&drvdb_lock);
157 lwkt_cpusync_simple(-1, x86_oldldt, NULL);
164 * Given the address of a driver image, find its corresponding
169 windrv_lookup(vm_offset_t img, char *name)
175 bzero((char *)&us, sizeof(us));
180 RtlInitAnsiString(&as, name);
181 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
185 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
186 STAILQ_FOREACH(d, &drvdb_head, link) {
187 if (d->windrv_object->dro_driverstart == (void *)img ||
188 (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
189 (char *)us.us_buf, us.us_len) == 0 && us.us_len)) {
190 lockmgr(&drvdb_lock, LK_RELEASE);
192 ExFreePool(us.us_buf);
193 return (d->windrv_object);
196 lockmgr(&drvdb_lock, LK_RELEASE);
199 RtlFreeUnicodeString(&us);
205 windrv_match(matchfuncptr matchfunc, void *ctx)
210 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
211 STAILQ_FOREACH(d, &drvdb_head, link) {
212 if (d->windrv_devlist == NULL)
214 match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx);
216 lockmgr(&drvdb_lock, LK_RELEASE);
220 lockmgr(&drvdb_lock, LK_RELEASE);
226 * Remove a driver_object from our datatabase and destroy it. Throw
227 * away any custom driver extension info that may have been added.
231 windrv_unload(module_t mod, vm_offset_t img, int len)
233 struct drvdb_ent *db, *r = NULL;
235 device_object *d, *pdo;
239 drv = windrv_lookup(img, NULL);
242 * When we unload a driver image, we need to force a
243 * detach of any devices that might be using it. We
244 * need the PDOs of all attached devices for this.
245 * Getting at them is a little hard. We basically
246 * have to walk the device lists of all our bus
250 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
251 STAILQ_FOREACH(db, &drvdb_head, link) {
253 * Fake bus drivers have no devlist info.
254 * If this driver has devlist info, it's
255 * a loaded Windows driver and has no PDOs,
258 if (db->windrv_devlist != NULL)
260 pdo = db->windrv_object->dro_devobj;
261 while (pdo != NULL) {
262 d = pdo->do_attacheddev;
263 if (d->do_drvobj != drv) {
264 pdo = pdo->do_nextdev;
267 dev = pdo->do_devext;
268 pdo = pdo->do_nextdev;
269 lockmgr(&drvdb_lock, LK_RELEASE);
271 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
275 STAILQ_FOREACH(db, &drvdb_head, link) {
276 if (db->windrv_object->dro_driverstart == (void *)img) {
278 STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link);
282 lockmgr(&drvdb_lock, LK_RELEASE);
291 * Destroy any custom extensions that may have been added.
293 drv = r->windrv_object;
294 while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
295 e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
299 /* Free the driver extension */
300 kfree(drv->dro_driverext, M_DEVBUF);
302 /* Free the driver name */
303 RtlFreeUnicodeString(&drv->dro_drivername);
305 /* Free driver object */
306 kfree(drv, M_DEVBUF);
308 /* Free our DB handle */
314 #define WINDRV_LOADED htonl(0x42534F44)
318 patch_user_shared_data_address(vm_offset_t img, size_t len)
320 unsigned long i, n, max_addr, *addr;
322 n = len - sizeof(unsigned long);
323 max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data);
324 for (i = 0; i < n; i++) {
325 addr = (unsigned long *)(img + i);
326 if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) {
327 *addr -= KI_USER_SHARED_DATA;
328 *addr += (unsigned long)&kuser_shared_data;
335 * Loader routine for actual Windows driver modules, ultimately
336 * calls the driver's DriverEntry() routine.
340 windrv_load(module_t mod, vm_offset_t img, int len, interface_type bustype,
341 void *devlist, ndis_cfg *regvals)
343 image_import_descriptor imp_desc;
344 image_optional_header opt_hdr;
346 struct drvdb_ent *new;
347 struct driver_object *drv;
353 * First step: try to relocate and dynalink the executable
357 ptr = (uint32_t *)(img + 8);
358 if (*ptr == WINDRV_LOADED)
361 /* Perform text relocation */
362 if (pe_relocate(img))
365 /* Dynamically link the NDIS.SYS routines -- required. */
366 if (pe_patch_imports(img, "NDIS", ndis_functbl))
369 /* Dynamically link the HAL.dll routines -- optional. */
370 if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
371 if (pe_patch_imports(img, "HAL", hal_functbl))
375 /* Dynamically link ntoskrnl.exe -- optional. */
376 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
377 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
382 patch_user_shared_data_address(img, len);
385 /* Dynamically link USBD.SYS -- optional */
386 if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
387 if (pe_patch_imports(img, "USBD", usbd_functbl))
391 *ptr = WINDRV_LOADED;
395 /* Next step: find the driver entry point. */
397 pe_get_optional_header(img, &opt_hdr);
398 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
400 /* Next step: allocate and store a driver object. */
402 new = kmalloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
406 drv = kmalloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
408 kfree (new, M_DEVBUF);
412 /* Allocate a driver extension structure too. */
414 drv->dro_driverext = kmalloc(sizeof(driver_extension),
415 M_DEVBUF, M_NOWAIT|M_ZERO);
417 if (drv->dro_driverext == NULL) {
418 kfree(new, M_DEVBUF);
419 kfree(drv, M_DEVBUF);
423 InitializeListHead((&drv->dro_driverext->dre_usrext));
425 drv->dro_driverstart = (void *)img;
426 drv->dro_driversize = len;
428 RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
429 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
430 kfree(new, M_DEVBUF);
431 kfree(drv, M_DEVBUF);
435 new->windrv_object = drv;
436 new->windrv_regvals = regvals;
437 new->windrv_devlist = devlist;
438 new->windrv_bustype = bustype;
440 /* Now call the DriverEntry() function. */
442 status = MSCALL2(entry, drv, &drv->dro_drivername);
444 if (status != STATUS_SUCCESS) {
445 RtlFreeUnicodeString(&drv->dro_drivername);
446 kfree(drv, M_DEVBUF);
447 kfree(new, M_DEVBUF);
451 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
452 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
453 lockmgr(&drvdb_lock, LK_RELEASE);
459 * Make a new Physical Device Object for a device that was
460 * detected/plugged in. For us, the PDO is just a way to
461 * get at the device_t.
465 windrv_create_pdo(driver_object *drv, device_t bsddev)
470 * This is a new physical device object, which technically
471 * is the "top of the stack." Consequently, we don't do
472 * an IoAttachDeviceToDeviceStack() here.
475 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
476 IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
477 lockmgr(&drvdb_lock, LK_RELEASE);
479 /* Stash pointer to our BSD device handle. */
481 dev->do_devext = bsddev;
483 return (STATUS_SUCCESS);
487 windrv_destroy_pdo(driver_object *drv, device_t bsddev)
491 pdo = windrv_find_pdo(drv, bsddev);
493 /* Remove reference to device_t */
495 pdo->do_devext = NULL;
497 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
499 lockmgr(&drvdb_lock, LK_RELEASE);
503 * Given a device_t, find the corresponding PDO in a driver's
508 windrv_find_pdo(driver_object *drv, device_t bsddev)
512 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
513 pdo = drv->dro_devobj;
514 while (pdo != NULL) {
515 if (pdo->do_devext == bsddev) {
516 lockmgr(&drvdb_lock, LK_RELEASE);
519 pdo = pdo->do_nextdev;
521 lockmgr(&drvdb_lock, LK_RELEASE);
527 * Add an internally emulated driver to the database. We need this
528 * to set up an emulated bus driver so that it can receive IRPs.
532 windrv_bus_attach(driver_object *drv, char *name)
534 struct drvdb_ent *new;
537 new = kmalloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
541 RtlInitAnsiString(&as, name);
542 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
544 kfree(new, M_DEVBUF);
549 * Set up a fake image pointer to avoid false matches
550 * in windrv_lookup().
552 drv->dro_driverstart = (void *)0xFFFFFFFF;
554 new->windrv_object = drv;
555 new->windrv_devlist = NULL;
556 new->windrv_regvals = NULL;
558 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
559 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
560 lockmgr(&drvdb_lock, LK_RELEASE);
567 extern void x86_64_wrap(void);
568 extern void x86_64_wrap_call(void);
569 extern void x86_64_wrap_end(void);
572 windrv_wrap(funcptr func, funcptr *wrap, int argcnt, int ftype)
575 vm_offset_t *calladdr;
576 vm_offset_t wrapstart, wrapend, wrapcall;
578 wrapstart = (vm_offset_t)&x86_64_wrap;
579 wrapend = (vm_offset_t)&x86_64_wrap_end;
580 wrapcall = (vm_offset_t)&x86_64_wrap_call;
582 /* Allocate a new wrapper instance. */
584 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
588 /* Copy over the code. */
590 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
592 /* Insert the function address into the new wrapper instance. */
594 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
595 *calladdr = (vm_offset_t)func;
601 #endif /* __x86_64__ */
618 } __attribute__((__packed__));
620 extern uint16_t x86_getfs(void);
621 extern void x86_setfs(uint16_t);
622 extern void *x86_gettid(void);
623 extern void x86_critical_enter(void);
624 extern void x86_critical_exit(void);
625 extern void x86_getldt(struct gdt *, uint16_t *);
626 extern void x86_setldt(struct gdt *, uint16_t);
628 #define SEL_TO_FS(x) (((x) << 3))
631 * The meanings of various bits in a descriptor vary a little
632 * depending on whether the descriptor will be used as a
633 * code, data or system descriptor. (And that in turn depends
634 * on which segment register selects the descriptor.)
635 * We're only trying to create a data segment, so the definitions
636 * below are the ones that apply to a data descriptor.
639 #define SEGFLAGLO_PRESENT 0x80 /* segment is present */
640 #define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */
641 #define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */
642 #define SEGFLAGLO_MBZ 0x08 /* must be zero */
643 #define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */
644 #define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */
645 #define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */
647 #define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */
648 #define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */
651 * Context switch from UNIX to Windows. Save the existing value
652 * of %fs for this processor, then change it to point to our
653 * fake TID. Note that it is also possible to pin ourselves
654 * to our current CPU, though I'm not sure this is really
655 * necessary. It depends on whether or not an interrupt might
656 * preempt us while Windows code is running and we wind up
657 * scheduled onto another CPU as a result. So far, it doesn't
658 * seem like this is what happens.
666 t = &my_tids[curthread->td_gd->gd_cpuid];
669 * Ugly hack. During system bootstrap (cold == 1), only CPU 0
670 * is running. So if we were loaded at bootstrap, only CPU 0
671 * will have our special GDT entry. This is a problem for SMP
672 * systems, so to deal with this, we check here to make sure
673 * the TID for this processor has been initialized, and if it
674 * hasn't, we need to do it right now or else things will
678 if (t->tid_self != t)
681 x86_critical_enter();
682 t->tid_oldfs = x86_getfs();
683 t->tid_cpu = curthread->td_gd->gd_cpuid;
684 #if 0 /* XXX swildner */
687 x86_setfs(SEL_TO_FS(t->tid_selector));
690 /* Now entering Windows land, population: you. */
694 * Context switch from Windows back to UNIX. Restore %fs to
695 * its previous value. This always occurs after a call to
704 x86_critical_enter();
706 x86_setfs(t->tid_oldfs);
707 #if 0 /* XXX swildner */
712 /* Welcome back to UNIX land, we missed you. */
715 if (t->tid_cpu != curthread->td_gd->gd_cpuid)
716 panic("ctxsw GOT MOVED TO OTHER CPU!");
720 static int windrv_wrap_stdcall(funcptr, funcptr *, int);
721 static int windrv_wrap_fastcall(funcptr, funcptr *, int);
722 static int windrv_wrap_regparm(funcptr, funcptr *);
724 extern void x86_fastcall_wrap(void);
725 extern void x86_fastcall_wrap_call(void);
726 extern void x86_fastcall_wrap_arg(void);
727 extern void x86_fastcall_wrap_end(void);
730 windrv_wrap_fastcall(funcptr func, funcptr *wrap, int argcnt)
733 vm_offset_t *calladdr;
735 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
737 wrapstart = (vm_offset_t)&x86_fastcall_wrap;
738 wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
739 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
740 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
742 /* Allocate a new wrapper instance. */
744 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
748 /* Copy over the code. */
750 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
752 /* Insert the function address into the new wrapper instance. */
754 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
755 *calladdr = (vm_offset_t)func;
761 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
762 *argaddr = argcnt * sizeof(uint32_t);
769 extern void x86_stdcall_wrap(void);
770 extern void x86_stdcall_wrap_call(void);
771 extern void x86_stdcall_wrap_arg(void);
772 extern void x86_stdcall_wrap_end(void);
775 windrv_wrap_stdcall(funcptr func, funcptr *wrap, int argcnt)
778 vm_offset_t *calladdr;
780 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
782 wrapstart = (vm_offset_t)&x86_stdcall_wrap;
783 wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
784 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
785 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
787 /* Allocate a new wrapper instance. */
789 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
793 /* Copy over the code. */
795 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
797 /* Insert the function address into the new wrapper instance. */
799 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
800 *calladdr = (vm_offset_t)func;
802 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
803 *argaddr = argcnt * sizeof(uint32_t);
810 extern void x86_regparm_wrap(void);
811 extern void x86_regparm_wrap_call(void);
812 extern void x86_regparm_wrap_end(void);
815 windrv_wrap_regparm(funcptr func, funcptr *wrap)
818 vm_offset_t *calladdr;
819 vm_offset_t wrapstart, wrapend, wrapcall;
821 wrapstart = (vm_offset_t)&x86_regparm_wrap;
822 wrapend = (vm_offset_t)&x86_regparm_wrap_end;
823 wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
825 /* Allocate a new wrapper instance. */
827 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
831 /* Copy over the code. */
833 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
835 /* Insert the function address into the new wrapper instance. */
837 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
838 *calladdr = (vm_offset_t)func;
846 windrv_wrap(funcptr func, funcptr *wrap, int argcnt, int ftype)
849 case WINDRV_WRAP_FASTCALL:
850 return (windrv_wrap_fastcall(func, wrap, argcnt));
851 case WINDRV_WRAP_STDCALL:
852 return (windrv_wrap_stdcall(func, wrap, argcnt));
853 case WINDRV_WRAP_REGPARM:
854 return (windrv_wrap_regparm(func, wrap));
855 case WINDRV_WRAP_CDECL:
856 return (windrv_wrap_stdcall(func, wrap, 0));
865 x86_oldldt(void *dummy)
871 mtx_spinlock(&dt_lock);
873 /* Grab location of existing GDT. */
875 x86_getldt(>able, <able);
877 /* Find the slot we updated. */
884 bzero((char *)gdt, sizeof(struct x86desc));
888 x86_setldt(>able, ltable);
890 mtx_spinunlock(&dt_lock);
894 x86_newldt(void *dummy)
903 mtx_spinlock(&dt_lock);
905 /* Grab location of existing GDT. */
907 x86_getldt(>able, <able);
909 /* Get pointer to the GDT table. */
913 /* Get pointer to empty slot */
917 /* Initialize TID for this CPU. */
919 my_tids[t->td_gd->gd_cpuid].tid_selector = GNDIS_SEL;
920 my_tids[t->td_gd->gd_cpuid].tid_self = &my_tids[t->td_gd->gd_cpuid];
922 /* Set up new GDT entry. */
924 l->x_lolimit = sizeof(struct tid);
925 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
926 l->x_base0 = (vm_offset_t)(&my_tids[t->td_gd->gd_cpuid]) & 0xFFFF;
927 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_gd->gd_cpuid]) >> 16) & 0xFF;
928 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_gd->gd_cpuid]) >> 24) & 0xFF;
929 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
931 /* Update the GDT. */
933 x86_setldt(>able, ltable);
935 mtx_spinunlock(&dt_lock);
940 #endif /* __i386__ */
943 windrv_unwrap(funcptr func)
945 kfree(func, M_DEVBUF);