usb4bsd: Remove more unused files.
[dragonfly.git] / sys / emulation / ndis / kern_windrv.c
blobba2e5e57b5f90311e9db1e6777799bf6d8e0a896
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 #ifdef __i386__
54 #include <machine/segments.h>
55 #endif
57 #include <bus/usb/usb.h>
58 #include <bus/usb/usbdi.h>
60 #include <emulation/ndis/pe_var.h>
61 #include <emulation/ndis/cfg_var.h>
62 #include <emulation/ndis/resource_var.h>
63 #include <emulation/ndis/ntoskrnl_var.h>
64 #include <emulation/ndis/ndis_var.h>
65 #include <emulation/ndis/hal_var.h>
66 #include <emulation/ndis/usbd_var.h>
68 static struct lock drvdb_lock;
69 static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
71 static driver_object fake_pci_driver; /* serves both PCI and cardbus */
72 static driver_object fake_pccard_driver;
74 #ifdef __i386__
75 static void x86_oldldt(void *);
76 static void x86_newldt(void *);
78 struct tid {
79 void *tid_except_list; /* 0x00 */
80 uint32_t tid_oldfs; /* 0x04 */
81 uint32_t tid_selector; /* 0x08 */
82 struct tid *tid_self; /* 0x0C */
83 int tid_cpu; /* 0x10 */
86 static struct tid *my_tids;
87 #endif /* __i386__ */
89 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
91 int
92 windrv_libinit(void)
94 STAILQ_INIT(&drvdb_head);
95 lockinit(&drvdb_lock, "Windows driver DB lock", 0, LK_CANRECURSE);
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");
110 #ifdef __i386__
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) * ncpus, 0);
120 if (my_tids == NULL)
121 panic("failed to allocate thread info blocks");
122 lwkt_cpusync_simple(-1, x86_newldt, NULL);
123 #endif
124 return (0);
128 windrv_libfini(void)
130 struct drvdb_ent *d;
132 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
133 while(STAILQ_FIRST(&drvdb_head) != NULL) {
134 d = STAILQ_FIRST(&drvdb_head);
135 STAILQ_REMOVE_HEAD(&drvdb_head, link);
136 kfree(d, M_DEVBUF);
138 lockmgr(&drvdb_lock, LK_RELEASE);
140 RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
141 RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
143 lockuninit(&drvdb_lock);
145 #ifdef __i386__
146 lwkt_cpusync_simple(-1, x86_oldldt, NULL);
147 ExFreePool(my_tids);
148 #endif
149 return (0);
153 * Given the address of a driver image, find its corresponding
154 * driver_object.
157 driver_object *
158 windrv_lookup(vm_offset_t img, char *name)
160 struct drvdb_ent *d;
161 unicode_string us;
162 ansi_string as;
164 bzero((char *)&us, sizeof(us));
166 /* Damn unicode. */
168 if (name != NULL) {
169 RtlInitAnsiString(&as, name);
170 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
171 return (NULL);
174 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
175 STAILQ_FOREACH(d, &drvdb_head, link) {
176 if (d->windrv_object->dro_driverstart == (void *)img ||
177 (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
178 (char *)us.us_buf, us.us_len) == 0 && us.us_len)) {
179 lockmgr(&drvdb_lock, LK_RELEASE);
180 if (name != NULL)
181 ExFreePool(us.us_buf);
182 return (d->windrv_object);
185 lockmgr(&drvdb_lock, LK_RELEASE);
187 if (name != NULL)
188 RtlFreeUnicodeString(&us);
190 return (NULL);
193 struct drvdb_ent *
194 windrv_match(matchfuncptr matchfunc, void *ctx)
196 struct drvdb_ent *d;
197 int match;
199 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
200 STAILQ_FOREACH(d, &drvdb_head, link) {
201 if (d->windrv_devlist == NULL)
202 continue;
203 match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx);
204 if (match == TRUE) {
205 lockmgr(&drvdb_lock, LK_RELEASE);
206 return (d);
209 lockmgr(&drvdb_lock, LK_RELEASE);
211 return (NULL);
215 * Remove a driver_object from our datatabase and destroy it. Throw
216 * away any custom driver extension info that may have been added.
220 windrv_unload(module_t mod, vm_offset_t img, int len)
222 struct drvdb_ent *db, *r = NULL;
223 driver_object *drv;
224 device_object *d, *pdo;
225 device_t dev;
226 list_entry *e;
228 drv = windrv_lookup(img, NULL);
231 * When we unload a driver image, we need to force a
232 * detach of any devices that might be using it. We
233 * need the PDOs of all attached devices for this.
234 * Getting at them is a little hard. We basically
235 * have to walk the device lists of all our bus
236 * drivers.
239 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
240 STAILQ_FOREACH(db, &drvdb_head, link) {
242 * Fake bus drivers have no devlist info.
243 * If this driver has devlist info, it's
244 * a loaded Windows driver and has no PDOs,
245 * so skip it.
247 if (db->windrv_devlist != NULL)
248 continue;
249 pdo = db->windrv_object->dro_devobj;
250 while (pdo != NULL) {
251 d = pdo->do_attacheddev;
252 if (d->do_drvobj != drv) {
253 pdo = pdo->do_nextdev;
254 continue;
256 dev = pdo->do_devext;
257 pdo = pdo->do_nextdev;
258 lockmgr(&drvdb_lock, LK_RELEASE);
259 device_detach(dev);
260 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
264 STAILQ_FOREACH(db, &drvdb_head, link) {
265 if (db->windrv_object->dro_driverstart == (void *)img) {
266 r = db;
267 STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link);
268 break;
271 lockmgr(&drvdb_lock, LK_RELEASE);
273 if (r == NULL)
274 return (ENOENT);
276 if (drv == NULL)
277 return (ENOENT);
280 * Destroy any custom extensions that may have been added.
282 drv = r->windrv_object;
283 while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
284 e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
285 ExFreePool(e);
288 /* Free the driver extension */
289 kfree(drv->dro_driverext, M_DEVBUF);
291 /* Free the driver name */
292 RtlFreeUnicodeString(&drv->dro_drivername);
294 /* Free driver object */
295 kfree(drv, M_DEVBUF);
297 /* Free our DB handle */
298 kfree(r, M_DEVBUF);
300 return (0);
303 #define WINDRV_LOADED htonl(0x42534F44)
305 #ifdef __amd64__
306 static void
307 patch_user_shared_data_address(vm_offset_t img, size_t len)
309 unsigned long i, n, max_addr, *addr;
311 n = len - sizeof(unsigned long);
312 max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data);
313 for (i = 0; i < n; i++) {
314 addr = (unsigned long *)(img + i);
315 if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) {
316 *addr -= KI_USER_SHARED_DATA;
317 *addr += (unsigned long)&kuser_shared_data;
321 #endif
324 * Loader routine for actual Windows driver modules, ultimately
325 * calls the driver's DriverEntry() routine.
329 windrv_load(module_t mod, vm_offset_t img, int len, interface_type bustype,
330 void *devlist, ndis_cfg *regvals)
332 image_import_descriptor imp_desc;
333 image_optional_header opt_hdr;
334 driver_entry entry;
335 struct drvdb_ent *new;
336 struct driver_object *drv;
337 int status;
338 uint32_t *ptr;
339 ansi_string as;
342 * First step: try to relocate and dynalink the executable
343 * driver image.
346 ptr = (uint32_t *)(img + 8);
347 if (*ptr == WINDRV_LOADED)
348 goto skipreloc;
350 /* Perform text relocation */
351 if (pe_relocate(img))
352 return (ENOEXEC);
354 /* Dynamically link the NDIS.SYS routines -- required. */
355 if (pe_patch_imports(img, "NDIS", ndis_functbl))
356 return (ENOEXEC);
358 /* Dynamically link the HAL.dll routines -- optional. */
359 if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
360 if (pe_patch_imports(img, "HAL", hal_functbl))
361 return (ENOEXEC);
364 /* Dynamically link ntoskrnl.exe -- optional. */
365 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
366 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
367 return (ENOEXEC);
370 #ifdef __amd64__
371 patch_user_shared_data_address(img, len);
372 #endif
374 /* Dynamically link USBD.SYS -- optional */
375 if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
376 if (pe_patch_imports(img, "USBD", usbd_functbl))
377 return (ENOEXEC);
380 *ptr = WINDRV_LOADED;
382 skipreloc:
384 /* Next step: find the driver entry point. */
386 pe_get_optional_header(img, &opt_hdr);
387 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
389 /* Next step: allocate and store a driver object. */
391 new = kmalloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
392 if (new == NULL)
393 return (ENOMEM);
395 drv = kmalloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
396 if (drv == NULL) {
397 kfree (new, M_DEVBUF);
398 return (ENOMEM);
401 /* Allocate a driver extension structure too. */
403 drv->dro_driverext = kmalloc(sizeof(driver_extension),
404 M_DEVBUF, M_NOWAIT|M_ZERO);
406 if (drv->dro_driverext == NULL) {
407 kfree(new, M_DEVBUF);
408 kfree(drv, M_DEVBUF);
409 return (ENOMEM);
412 InitializeListHead((&drv->dro_driverext->dre_usrext));
414 drv->dro_driverstart = (void *)img;
415 drv->dro_driversize = len;
417 RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
418 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
419 kfree(new, M_DEVBUF);
420 kfree(drv, M_DEVBUF);
421 return (ENOMEM);
424 new->windrv_object = drv;
425 new->windrv_regvals = regvals;
426 new->windrv_devlist = devlist;
427 new->windrv_bustype = bustype;
429 /* Now call the DriverEntry() function. */
431 status = MSCALL2(entry, drv, &drv->dro_drivername);
433 if (status != STATUS_SUCCESS) {
434 RtlFreeUnicodeString(&drv->dro_drivername);
435 kfree(drv, M_DEVBUF);
436 kfree(new, M_DEVBUF);
437 return (ENODEV);
440 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
441 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
442 lockmgr(&drvdb_lock, LK_RELEASE);
444 return (0);
448 * Make a new Physical Device Object for a device that was
449 * detected/plugged in. For us, the PDO is just a way to
450 * get at the device_t.
454 windrv_create_pdo(driver_object *drv, device_t bsddev)
456 device_object *dev;
459 * This is a new physical device object, which technically
460 * is the "top of the stack." Consequently, we don't do
461 * an IoAttachDeviceToDeviceStack() here.
464 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
465 IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
466 lockmgr(&drvdb_lock, LK_RELEASE);
468 /* Stash pointer to our BSD device handle. */
470 dev->do_devext = bsddev;
472 return (STATUS_SUCCESS);
475 void
476 windrv_destroy_pdo(driver_object *drv, device_t bsddev)
478 device_object *pdo;
480 pdo = windrv_find_pdo(drv, bsddev);
482 /* Remove reference to device_t */
484 pdo->do_devext = NULL;
486 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
487 IoDeleteDevice(pdo);
488 lockmgr(&drvdb_lock, LK_RELEASE);
492 * Given a device_t, find the corresponding PDO in a driver's
493 * device list.
496 device_object *
497 windrv_find_pdo(driver_object *drv, device_t bsddev)
499 device_object *pdo;
501 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
502 pdo = drv->dro_devobj;
503 while (pdo != NULL) {
504 if (pdo->do_devext == bsddev) {
505 lockmgr(&drvdb_lock, LK_RELEASE);
506 return (pdo);
508 pdo = pdo->do_nextdev;
510 lockmgr(&drvdb_lock, LK_RELEASE);
512 return (NULL);
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(driver_object *drv, char *name)
523 struct drvdb_ent *new;
524 ansi_string as;
526 new = kmalloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
527 if (new == NULL)
528 return (ENOMEM);
530 RtlInitAnsiString(&as, name);
531 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
533 kfree(new, M_DEVBUF);
534 return (ENOMEM);
538 * Set up a fake image pointer to avoid false matches
539 * in windrv_lookup().
541 drv->dro_driverstart = (void *)0xFFFFFFFF;
543 new->windrv_object = drv;
544 new->windrv_devlist = NULL;
545 new->windrv_regvals = NULL;
547 lockmgr(&drvdb_lock, LK_EXCLUSIVE);
548 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
549 lockmgr(&drvdb_lock, LK_RELEASE);
551 return (0);
554 #ifdef __x86_64__
556 extern void x86_64_wrap(void);
557 extern void x86_64_wrap_call(void);
558 extern void x86_64_wrap_end(void);
561 windrv_wrap(funcptr func, funcptr *wrap, int argcnt, int ftype)
563 funcptr p;
564 vm_offset_t *calladdr;
565 vm_offset_t wrapstart, wrapend, wrapcall;
567 wrapstart = (vm_offset_t)&x86_64_wrap;
568 wrapend = (vm_offset_t)&x86_64_wrap_end;
569 wrapcall = (vm_offset_t)&x86_64_wrap_call;
571 /* Allocate a new wrapper instance. */
573 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
574 if (p == NULL)
575 return (ENOMEM);
577 /* Copy over the code. */
579 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
581 /* Insert the function address into the new wrapper instance. */
583 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
584 *calladdr = (vm_offset_t)func;
586 *wrap = p;
588 return (0);
590 #endif /* __x86_64__ */
593 #ifdef __i386__
595 struct x86desc {
596 uint16_t x_lolimit;
597 uint16_t x_base0;
598 uint8_t x_base1;
599 uint8_t x_flags;
600 uint8_t x_hilimit;
601 uint8_t x_base2;
604 struct gdt {
605 uint16_t limit;
606 void *base;
607 } __attribute__((__packed__));
609 extern uint16_t x86_getfs(void);
610 extern void x86_setfs(uint16_t);
611 extern void *x86_gettid(void);
612 extern void x86_critical_enter(void);
613 extern void x86_critical_exit(void);
614 extern void x86_getldt(struct gdt *, uint16_t *);
615 extern void x86_setldt(struct gdt *, uint16_t);
617 #define SEL_TO_FS(x) (((x) << 3))
620 * The meanings of various bits in a descriptor vary a little
621 * depending on whether the descriptor will be used as a
622 * code, data or system descriptor. (And that in turn depends
623 * on which segment register selects the descriptor.)
624 * We're only trying to create a data segment, so the definitions
625 * below are the ones that apply to a data descriptor.
628 #define SEGFLAGLO_PRESENT 0x80 /* segment is present */
629 #define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */
630 #define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */
631 #define SEGFLAGLO_MBZ 0x08 /* must be zero */
632 #define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */
633 #define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */
634 #define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */
636 #define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */
637 #define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */
640 * Context switch from UNIX to Windows. Save the existing value
641 * of %fs for this processor, then change it to point to our
642 * fake TID. Note that it is also possible to pin ourselves
643 * to our current CPU, though I'm not sure this is really
644 * necessary. It depends on whether or not an interrupt might
645 * preempt us while Windows code is running and we wind up
646 * scheduled onto another CPU as a result. So far, it doesn't
647 * seem like this is what happens.
650 void
651 ctxsw_utow(void)
653 struct tid *t;
655 t = &my_tids[curthread->td_gd->gd_cpuid];
658 * Ugly hack. During system bootstrap (cold == 1), only CPU 0
659 * is running. So if we were loaded at bootstrap, only CPU 0
660 * will have our special GDT entry. This is a problem for SMP
661 * systems, so to deal with this, we check here to make sure
662 * the TID for this processor has been initialized, and if it
663 * hasn't, we need to do it right now or else things will
664 * explode.
667 if (t->tid_self != t)
668 x86_newldt(NULL);
670 x86_critical_enter();
671 t->tid_oldfs = x86_getfs();
672 t->tid_cpu = curthread->td_gd->gd_cpuid;
673 #if 0 /* XXX swildner */
674 sched_pin();
675 #endif
676 x86_setfs(SEL_TO_FS(t->tid_selector));
677 x86_critical_exit();
679 /* Now entering Windows land, population: you. */
683 * Context switch from Windows back to UNIX. Restore %fs to
684 * its previous value. This always occurs after a call to
685 * ctxsw_utow().
688 void
689 ctxsw_wtou(void)
691 struct tid *t;
693 x86_critical_enter();
694 t = x86_gettid();
695 x86_setfs(t->tid_oldfs);
696 #if 0 /* XXX swildner */
697 sched_unpin();
698 #endif
699 x86_critical_exit();
701 /* Welcome back to UNIX land, we missed you. */
703 #ifdef EXTRA_SANITY
704 if (t->tid_cpu != curthread->td_gd->gd_cpuid)
705 panic("ctxsw GOT MOVED TO OTHER CPU!");
706 #endif
709 static int windrv_wrap_stdcall(funcptr, funcptr *, int);
710 static int windrv_wrap_fastcall(funcptr, funcptr *, int);
711 static int windrv_wrap_regparm(funcptr, funcptr *);
713 extern void x86_fastcall_wrap(void);
714 extern void x86_fastcall_wrap_call(void);
715 extern void x86_fastcall_wrap_arg(void);
716 extern void x86_fastcall_wrap_end(void);
718 static int
719 windrv_wrap_fastcall(funcptr func, funcptr *wrap, int argcnt)
721 funcptr p;
722 vm_offset_t *calladdr;
723 uint8_t *argaddr;
724 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
726 wrapstart = (vm_offset_t)&x86_fastcall_wrap;
727 wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
728 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
729 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
731 /* Allocate a new wrapper instance. */
733 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
734 if (p == NULL)
735 return (ENOMEM);
737 /* Copy over the code. */
739 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
741 /* Insert the function address into the new wrapper instance. */
743 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
744 *calladdr = (vm_offset_t)func;
746 argcnt -= 2;
747 if (argcnt < 1)
748 argcnt = 0;
750 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
751 *argaddr = argcnt * sizeof(uint32_t);
753 *wrap = p;
755 return (0);
758 extern void x86_stdcall_wrap(void);
759 extern void x86_stdcall_wrap_call(void);
760 extern void x86_stdcall_wrap_arg(void);
761 extern void x86_stdcall_wrap_end(void);
763 static int
764 windrv_wrap_stdcall(funcptr func, funcptr *wrap, int argcnt)
766 funcptr p;
767 vm_offset_t *calladdr;
768 uint8_t *argaddr;
769 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
771 wrapstart = (vm_offset_t)&x86_stdcall_wrap;
772 wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
773 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
774 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
776 /* Allocate a new wrapper instance. */
778 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
779 if (p == NULL)
780 return (ENOMEM);
782 /* Copy over the code. */
784 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
786 /* Insert the function address into the new wrapper instance. */
788 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
789 *calladdr = (vm_offset_t)func;
791 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
792 *argaddr = argcnt * sizeof(uint32_t);
794 *wrap = p;
796 return (0);
799 extern void x86_regparm_wrap(void);
800 extern void x86_regparm_wrap_call(void);
801 extern void x86_regparm_wrap_end(void);
803 static int
804 windrv_wrap_regparm(funcptr func, funcptr *wrap)
806 funcptr p;
807 vm_offset_t *calladdr;
808 vm_offset_t wrapstart, wrapend, wrapcall;
810 wrapstart = (vm_offset_t)&x86_regparm_wrap;
811 wrapend = (vm_offset_t)&x86_regparm_wrap_end;
812 wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
814 /* Allocate a new wrapper instance. */
816 p = kmalloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
817 if (p == NULL)
818 return (ENOMEM);
820 /* Copy over the code. */
822 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
824 /* Insert the function address into the new wrapper instance. */
826 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
827 *calladdr = (vm_offset_t)func;
829 *wrap = p;
831 return (0);
835 windrv_wrap(funcptr func, funcptr *wrap, int argcnt, int ftype)
837 switch(ftype) {
838 case WINDRV_WRAP_FASTCALL:
839 return (windrv_wrap_fastcall(func, wrap, argcnt));
840 case WINDRV_WRAP_STDCALL:
841 return (windrv_wrap_stdcall(func, wrap, argcnt));
842 case WINDRV_WRAP_REGPARM:
843 return (windrv_wrap_regparm(func, wrap));
844 case WINDRV_WRAP_CDECL:
845 return (windrv_wrap_stdcall(func, wrap, 0));
846 default:
847 break;
850 return (EINVAL);
853 static void
854 x86_oldldt(void *dummy)
856 struct x86desc *gdt;
857 struct gdt gtable;
858 uint16_t ltable;
860 mtx_spinlock(&dt_lock);
862 /* Grab location of existing GDT. */
864 x86_getldt(&gtable, &ltable);
866 /* Find the slot we updated. */
868 gdt = gtable.base;
869 gdt += GNDIS_SEL;
871 /* Empty it out. */
873 bzero((char *)gdt, sizeof(struct x86desc));
875 /* Restore GDT. */
877 x86_setldt(&gtable, ltable);
879 mtx_spinunlock(&dt_lock);
882 static void
883 x86_newldt(void *dummy)
885 struct gdt gtable;
886 uint16_t ltable;
887 struct x86desc *l;
888 struct thread *t;
890 t = curthread;
892 mtx_spinlock(&dt_lock);
894 /* Grab location of existing GDT. */
896 x86_getldt(&gtable, &ltable);
898 /* Get pointer to the GDT table. */
900 l = gtable.base;
902 /* Get pointer to empty slot */
904 l += GNDIS_SEL;
906 /* Initialize TID for this CPU. */
908 my_tids[t->td_gd->gd_cpuid].tid_selector = GNDIS_SEL;
909 my_tids[t->td_gd->gd_cpuid].tid_self = &my_tids[t->td_gd->gd_cpuid];
911 /* Set up new GDT entry. */
913 l->x_lolimit = sizeof(struct tid);
914 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
915 l->x_base0 = (vm_offset_t)(&my_tids[t->td_gd->gd_cpuid]) & 0xFFFF;
916 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_gd->gd_cpuid]) >> 16) & 0xFF;
917 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_gd->gd_cpuid]) >> 24) & 0xFF;
918 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
920 /* Update the GDT. */
922 x86_setldt(&gtable, ltable);
924 mtx_spinunlock(&dt_lock);
926 /* Whew. */
929 #endif /* __i386__ */
932 windrv_unwrap(funcptr func)
934 kfree(func, M_DEVBUF);
936 return (0);