2 * SPDX-License-Identifier: BSD-4-Clause
5 * Bill Paul <wpaul@windriver.com>. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Bill Paul.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/unistd.h>
41 #include <sys/types.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
46 #include <sys/mutex.h>
47 #include <sys/module.h>
52 #include <sys/sched.h>
55 #include <sys/queue.h>
58 #include <machine/segments.h>
62 #include <machine/fpu.h>
65 #include <dev/usb/usb.h>
67 #include <compat/ndis/pe_var.h>
68 #include <compat/ndis/cfg_var.h>
69 #include <compat/ndis/resource_var.h>
70 #include <compat/ndis/ntoskrnl_var.h>
71 #include <compat/ndis/ndis_var.h>
72 #include <compat/ndis/hal_var.h>
73 #include <compat/ndis/usbd_var.h>
77 struct fpu_kern_ctx *ctx;
78 LIST_ENTRY(fpu_cc_ent) entries;
80 static LIST_HEAD(fpu_ctx_free, fpu_cc_ent) fpu_free_head =
81 LIST_HEAD_INITIALIZER(fpu_free_head);
82 static LIST_HEAD(fpu_ctx_busy, fpu_cc_ent) fpu_busy_head =
83 LIST_HEAD_INITIALIZER(fpu_busy_head);
84 static struct mtx fpu_free_mtx;
85 static struct mtx fpu_busy_mtx;
88 static struct mtx drvdb_mtx;
89 static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
91 static driver_object fake_pci_driver; /* serves both PCI and cardbus */
92 static driver_object fake_pccard_driver;
95 static void x86_oldldt(void *);
96 static void x86_newldt(void *);
99 void *tid_except_list; /* 0x00 */
100 uint32_t tid_oldfs; /* 0x04 */
101 uint32_t tid_selector; /* 0x08 */
102 struct tid *tid_self; /* 0x0C */
103 int tid_cpu; /* 0x10 */
106 static struct tid *my_tids;
107 #endif /* __i386__ */
109 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
114 STAILQ_INIT(&drvdb_head);
115 mtx_init(&drvdb_mtx, "Windows driver DB lock",
116 "Windows internal lock", MTX_DEF);
119 LIST_INIT(&fpu_free_head);
120 LIST_INIT(&fpu_busy_head);
121 mtx_init(&fpu_free_mtx, "free fpu context list lock", NULL, MTX_DEF);
122 mtx_init(&fpu_busy_mtx, "busy fpu context list lock", NULL, MTX_DEF);
126 * PCI and pccard devices don't need to use IRPs to
127 * interact with their bus drivers (usually), so our
128 * emulated PCI and pccard drivers are just stubs.
129 * USB devices, on the other hand, do all their I/O
130 * by exchanging IRPs with the USB bus driver, so
131 * for that we need to provide emulator dispatcher
132 * routines, which are in a separate module.
135 windrv_bus_attach(&fake_pci_driver, "PCI Bus");
136 windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus");
141 * In order to properly support SMP machines, we have
142 * to modify the GDT on each CPU, since we never know
143 * on which one we'll end up running.
146 my_tids = ExAllocatePoolWithTag(NonPagedPool,
147 sizeof(struct tid) * mp_ncpus, 0);
149 panic("failed to allocate thread info blocks");
150 smp_rendezvous(NULL, x86_newldt, NULL, NULL);
160 struct fpu_cc_ent *ent;
163 mtx_lock(&drvdb_mtx);
164 while(STAILQ_FIRST(&drvdb_head) != NULL) {
165 d = STAILQ_FIRST(&drvdb_head);
166 STAILQ_REMOVE_HEAD(&drvdb_head, link);
169 mtx_unlock(&drvdb_mtx);
171 RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
172 RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
174 mtx_destroy(&drvdb_mtx);
177 smp_rendezvous(NULL, x86_oldldt, NULL, NULL);
181 while ((ent = LIST_FIRST(&fpu_free_head)) != NULL) {
182 LIST_REMOVE(ent, entries);
183 fpu_kern_free_ctx(ent->ctx);
186 mtx_destroy(&fpu_free_mtx);
188 ent = LIST_FIRST(&fpu_busy_head);
189 KASSERT(ent == NULL, ("busy fpu context list is not empty"));
190 mtx_destroy(&fpu_busy_mtx);
196 * Given the address of a driver image, find its corresponding
201 windrv_lookup(img, name)
209 bzero((char *)&us, sizeof(us));
214 RtlInitAnsiString(&as, name);
215 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
219 mtx_lock(&drvdb_mtx);
220 STAILQ_FOREACH(d, &drvdb_head, link) {
221 if (d->windrv_object->dro_driverstart == (void *)img ||
222 (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
223 (char *)us.us_buf, us.us_len) == 0 && us.us_len)) {
224 mtx_unlock(&drvdb_mtx);
226 ExFreePool(us.us_buf);
227 return (d->windrv_object);
230 mtx_unlock(&drvdb_mtx);
233 RtlFreeUnicodeString(&us);
239 windrv_match(matchfunc, ctx)
240 matchfuncptr matchfunc;
246 mtx_lock(&drvdb_mtx);
247 STAILQ_FOREACH(d, &drvdb_head, link) {
248 if (d->windrv_devlist == NULL)
250 match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx);
252 mtx_unlock(&drvdb_mtx);
256 mtx_unlock(&drvdb_mtx);
262 * Remove a driver_object from our datatabase and destroy it. Throw
263 * away any custom driver extension info that may have been added.
267 windrv_unload(mod, img, len)
272 struct drvdb_ent *db, *r = NULL;
274 device_object *d, *pdo;
278 drv = windrv_lookup(img, NULL);
281 * When we unload a driver image, we need to force a
282 * detach of any devices that might be using it. We
283 * need the PDOs of all attached devices for this.
284 * Getting at them is a little hard. We basically
285 * have to walk the device lists of all our bus
289 mtx_lock(&drvdb_mtx);
290 STAILQ_FOREACH(db, &drvdb_head, link) {
292 * Fake bus drivers have no devlist info.
293 * If this driver has devlist info, it's
294 * a loaded Windows driver and has no PDOs,
297 if (db->windrv_devlist != NULL)
299 pdo = db->windrv_object->dro_devobj;
300 while (pdo != NULL) {
301 d = pdo->do_attacheddev;
302 if (d->do_drvobj != drv) {
303 pdo = pdo->do_nextdev;
306 dev = pdo->do_devext;
307 pdo = pdo->do_nextdev;
308 mtx_unlock(&drvdb_mtx);
310 mtx_lock(&drvdb_mtx);
314 STAILQ_FOREACH(db, &drvdb_head, link) {
315 if (db->windrv_object->dro_driverstart == (void *)img) {
317 STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link);
321 mtx_unlock(&drvdb_mtx);
330 * Destroy any custom extensions that may have been added.
332 drv = r->windrv_object;
333 while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
334 e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
338 /* Free the driver extension */
339 free(drv->dro_driverext, M_DEVBUF);
341 /* Free the driver name */
342 RtlFreeUnicodeString(&drv->dro_drivername);
344 /* Free driver object */
347 /* Free our DB handle */
353 #define WINDRV_LOADED htonl(0x42534F44)
357 patch_user_shared_data_address(vm_offset_t img, size_t len)
359 unsigned long i, n, max_addr, *addr;
361 n = len - sizeof(unsigned long);
362 max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data);
363 for (i = 0; i < n; i++) {
364 addr = (unsigned long *)(img + i);
365 if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) {
366 *addr -= KI_USER_SHARED_DATA;
367 *addr += (unsigned long)&kuser_shared_data;
374 * Loader routine for actual Windows driver modules, ultimately
375 * calls the driver's DriverEntry() routine.
379 windrv_load(mod, img, len, bustype, devlist, regvals)
383 interface_type bustype;
387 image_import_descriptor imp_desc;
388 image_optional_header opt_hdr;
390 struct drvdb_ent *new;
391 struct driver_object *drv;
397 * First step: try to relocate and dynalink the executable
401 ptr = (uint32_t *)(img + 8);
402 if (*ptr == WINDRV_LOADED)
405 /* Perform text relocation */
406 if (pe_relocate(img))
409 /* Dynamically link the NDIS.SYS routines -- required. */
410 if (pe_patch_imports(img, "NDIS", ndis_functbl))
413 /* Dynamically link the HAL.dll routines -- optional. */
414 if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
415 if (pe_patch_imports(img, "HAL", hal_functbl))
419 /* Dynamically link ntoskrnl.exe -- optional. */
420 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
421 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
426 patch_user_shared_data_address(img, len);
429 /* Dynamically link USBD.SYS -- optional */
430 if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
431 if (pe_patch_imports(img, "USBD", usbd_functbl))
435 *ptr = WINDRV_LOADED;
439 /* Next step: find the driver entry point. */
441 pe_get_optional_header(img, &opt_hdr);
442 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
444 /* Next step: allocate and store a driver object. */
446 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
450 drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
452 free (new, M_DEVBUF);
456 /* Allocate a driver extension structure too. */
458 drv->dro_driverext = malloc(sizeof(driver_extension),
459 M_DEVBUF, M_NOWAIT|M_ZERO);
461 if (drv->dro_driverext == NULL) {
467 InitializeListHead((&drv->dro_driverext->dre_usrext));
469 drv->dro_driverstart = (void *)img;
470 drv->dro_driversize = len;
472 RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
473 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
479 new->windrv_object = drv;
480 new->windrv_regvals = regvals;
481 new->windrv_devlist = devlist;
482 new->windrv_bustype = bustype;
484 /* Now call the DriverEntry() function. */
486 status = MSCALL2(entry, drv, &drv->dro_drivername);
488 if (status != STATUS_SUCCESS) {
489 RtlFreeUnicodeString(&drv->dro_drivername);
495 mtx_lock(&drvdb_mtx);
496 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
497 mtx_unlock(&drvdb_mtx);
503 * Make a new Physical Device Object for a device that was
504 * detected/plugged in. For us, the PDO is just a way to
505 * get at the device_t.
509 windrv_create_pdo(drv, bsddev)
516 * This is a new physical device object, which technically
517 * is the "top of the stack." Consequently, we don't do
518 * an IoAttachDeviceToDeviceStack() here.
521 mtx_lock(&drvdb_mtx);
522 IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
523 mtx_unlock(&drvdb_mtx);
525 /* Stash pointer to our BSD device handle. */
527 dev->do_devext = bsddev;
529 return (STATUS_SUCCESS);
533 windrv_destroy_pdo(drv, bsddev)
539 pdo = windrv_find_pdo(drv, bsddev);
541 /* Remove reference to device_t */
543 pdo->do_devext = NULL;
545 mtx_lock(&drvdb_mtx);
547 mtx_unlock(&drvdb_mtx);
551 * Given a device_t, find the corresponding PDO in a driver's
556 windrv_find_pdo(drv, bsddev)
562 mtx_lock(&drvdb_mtx);
563 pdo = drv->dro_devobj;
564 while (pdo != NULL) {
565 if (pdo->do_devext == bsddev) {
566 mtx_unlock(&drvdb_mtx);
569 pdo = pdo->do_nextdev;
571 mtx_unlock(&drvdb_mtx);
577 * Add an internally emulated driver to the database. We need this
578 * to set up an emulated bus driver so that it can receive IRPs.
582 windrv_bus_attach(drv, name)
586 struct drvdb_ent *new;
589 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
593 RtlInitAnsiString(&as, name);
594 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
601 * Set up a fake image pointer to avoid false matches
602 * in windrv_lookup().
604 drv->dro_driverstart = (void *)0xFFFFFFFF;
606 new->windrv_object = drv;
607 new->windrv_devlist = NULL;
608 new->windrv_regvals = NULL;
610 mtx_lock(&drvdb_mtx);
611 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
612 mtx_unlock(&drvdb_mtx);
619 extern void x86_64_wrap(void);
620 extern void x86_64_wrap_call(void);
621 extern void x86_64_wrap_end(void);
624 windrv_wrap(func, wrap, argcnt, ftype)
631 vm_offset_t *calladdr;
632 vm_offset_t wrapstart, wrapend, wrapcall;
634 wrapstart = (vm_offset_t)&x86_64_wrap;
635 wrapend = (vm_offset_t)&x86_64_wrap_end;
636 wrapcall = (vm_offset_t)&x86_64_wrap_call;
638 /* Allocate a new wrapper instance. */
640 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
644 /* Copy over the code. */
646 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
648 /* Insert the function address into the new wrapper instance. */
650 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
651 *calladdr = (vm_offset_t)func;
658 static struct fpu_cc_ent *
659 request_fpu_cc_ent(void)
661 struct fpu_cc_ent *ent;
663 mtx_lock(&fpu_free_mtx);
664 if ((ent = LIST_FIRST(&fpu_free_head)) != NULL) {
665 LIST_REMOVE(ent, entries);
666 mtx_unlock(&fpu_free_mtx);
667 mtx_lock(&fpu_busy_mtx);
668 LIST_INSERT_HEAD(&fpu_busy_head, ent, entries);
669 mtx_unlock(&fpu_busy_mtx);
672 mtx_unlock(&fpu_free_mtx);
674 if ((ent = malloc(sizeof(struct fpu_cc_ent), M_DEVBUF, M_NOWAIT |
676 ent->ctx = fpu_kern_alloc_ctx(FPU_KERN_NORMAL |
678 if (ent->ctx != NULL) {
679 mtx_lock(&fpu_busy_mtx);
680 LIST_INSERT_HEAD(&fpu_busy_head, ent, entries);
681 mtx_unlock(&fpu_busy_mtx);
692 release_fpu_cc_ent(struct fpu_cc_ent *ent)
694 mtx_lock(&fpu_busy_mtx);
695 LIST_REMOVE(ent, entries);
696 mtx_unlock(&fpu_busy_mtx);
697 mtx_lock(&fpu_free_mtx);
698 LIST_INSERT_HEAD(&fpu_free_head, ent, entries);
699 mtx_unlock(&fpu_free_mtx);
703 _x86_64_call1(void *fn, uint64_t a)
705 struct fpu_cc_ent *ent;
708 if ((ent = request_fpu_cc_ent()) == NULL)
710 fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL);
711 ret = x86_64_call1(fn, a);
712 fpu_kern_leave(curthread, ent->ctx);
713 release_fpu_cc_ent(ent);
719 _x86_64_call2(void *fn, uint64_t a, uint64_t b)
721 struct fpu_cc_ent *ent;
724 if ((ent = request_fpu_cc_ent()) == NULL)
726 fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL);
727 ret = x86_64_call2(fn, a, b);
728 fpu_kern_leave(curthread, ent->ctx);
729 release_fpu_cc_ent(ent);
735 _x86_64_call3(void *fn, uint64_t a, uint64_t b, uint64_t c)
737 struct fpu_cc_ent *ent;
740 if ((ent = request_fpu_cc_ent()) == NULL)
742 fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL);
743 ret = x86_64_call3(fn, a, b, c);
744 fpu_kern_leave(curthread, ent->ctx);
745 release_fpu_cc_ent(ent);
751 _x86_64_call4(void *fn, uint64_t a, uint64_t b, uint64_t c, uint64_t d)
753 struct fpu_cc_ent *ent;
756 if ((ent = request_fpu_cc_ent()) == NULL)
758 fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL);
759 ret = x86_64_call4(fn, a, b, c, d);
760 fpu_kern_leave(curthread, ent->ctx);
761 release_fpu_cc_ent(ent);
767 _x86_64_call5(void *fn, uint64_t a, uint64_t b, uint64_t c, uint64_t d,
770 struct fpu_cc_ent *ent;
773 if ((ent = request_fpu_cc_ent()) == NULL)
775 fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL);
776 ret = x86_64_call5(fn, a, b, c, d, e);
777 fpu_kern_leave(curthread, ent->ctx);
778 release_fpu_cc_ent(ent);
784 _x86_64_call6(void *fn, uint64_t a, uint64_t b, uint64_t c, uint64_t d,
785 uint64_t e, uint64_t f)
787 struct fpu_cc_ent *ent;
790 if ((ent = request_fpu_cc_ent()) == NULL)
792 fpu_kern_enter(curthread, ent->ctx, FPU_KERN_NORMAL);
793 ret = x86_64_call6(fn, a, b, c, d, e, f);
794 fpu_kern_leave(curthread, ent->ctx);
795 release_fpu_cc_ent(ent);
799 #endif /* __amd64__ */
816 } __attribute__((__packed__));
818 extern uint16_t x86_getfs(void);
819 extern void x86_setfs(uint16_t);
820 extern void *x86_gettid(void);
821 extern void x86_critical_enter(void);
822 extern void x86_critical_exit(void);
823 extern void x86_getldt(struct gdt *, uint16_t *);
824 extern void x86_setldt(struct gdt *, uint16_t);
826 #define SEL_LDT 4 /* local descriptor table */
827 #define SEL_TO_FS(x) (((x) << 3))
830 * FreeBSD 6.0 and later has a special GDT segment reserved
831 * specifically for us, so if GNDIS_SEL is defined, use that.
832 * If not, use GTGATE_SEL, which is uninitialized and infrequently
837 #define FREEBSD_EMPTYSEL GNDIS_SEL
839 #define FREEBSD_EMPTYSEL GTGATE_SEL /* slot 7 */
843 * The meanings of various bits in a descriptor vary a little
844 * depending on whether the descriptor will be used as a
845 * code, data or system descriptor. (And that in turn depends
846 * on which segment register selects the descriptor.)
847 * We're only trying to create a data segment, so the definitions
848 * below are the ones that apply to a data descriptor.
851 #define SEGFLAGLO_PRESENT 0x80 /* segment is present */
852 #define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */
853 #define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */
854 #define SEGFLAGLO_MBZ 0x08 /* must be zero */
855 #define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */
856 #define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */
857 #define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */
859 #define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */
860 #define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */
863 * Context switch from UNIX to Windows. Save the existing value
864 * of %fs for this processor, then change it to point to our
865 * fake TID. Note that it is also possible to pin ourselves
866 * to our current CPU, though I'm not sure this is really
867 * necessary. It depends on whether or not an interrupt might
868 * preempt us while Windows code is running and we wind up
869 * scheduled onto another CPU as a result. So far, it doesn't
870 * seem like this is what happens.
878 t = &my_tids[curthread->td_oncpu];
881 * Ugly hack. During system bootstrap (cold == 1), only CPU 0
882 * is running. So if we were loaded at bootstrap, only CPU 0
883 * will have our special GDT entry. This is a problem for SMP
884 * systems, so to deal with this, we check here to make sure
885 * the TID for this processor has been initialized, and if it
886 * hasn't, we need to do it right now or else things will
890 if (t->tid_self != t)
893 x86_critical_enter();
894 t->tid_oldfs = x86_getfs();
895 t->tid_cpu = curthread->td_oncpu;
897 x86_setfs(SEL_TO_FS(t->tid_selector));
900 /* Now entering Windows land, population: you. */
904 * Context switch from Windows back to UNIX. Restore %fs to
905 * its previous value. This always occurs after a call to
914 x86_critical_enter();
916 x86_setfs(t->tid_oldfs);
920 /* Welcome back to UNIX land, we missed you. */
923 if (t->tid_cpu != curthread->td_oncpu)
924 panic("ctxsw GOT MOVED TO OTHER CPU!");
928 static int windrv_wrap_stdcall(funcptr, funcptr *, int);
929 static int windrv_wrap_fastcall(funcptr, funcptr *, int);
930 static int windrv_wrap_regparm(funcptr, funcptr *);
932 extern void x86_fastcall_wrap(void);
933 extern void x86_fastcall_wrap_call(void);
934 extern void x86_fastcall_wrap_arg(void);
935 extern void x86_fastcall_wrap_end(void);
938 windrv_wrap_fastcall(func, wrap, argcnt)
944 vm_offset_t *calladdr;
946 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
948 wrapstart = (vm_offset_t)&x86_fastcall_wrap;
949 wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
950 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
951 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
953 /* Allocate a new wrapper instance. */
955 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
959 /* Copy over the code. */
961 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
963 /* Insert the function address into the new wrapper instance. */
965 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
966 *calladdr = (vm_offset_t)func;
972 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
973 *argaddr = argcnt * sizeof(uint32_t);
980 extern void x86_stdcall_wrap(void);
981 extern void x86_stdcall_wrap_call(void);
982 extern void x86_stdcall_wrap_arg(void);
983 extern void x86_stdcall_wrap_end(void);
986 windrv_wrap_stdcall(func, wrap, argcnt)
992 vm_offset_t *calladdr;
994 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
996 wrapstart = (vm_offset_t)&x86_stdcall_wrap;
997 wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
998 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
999 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
1001 /* Allocate a new wrapper instance. */
1003 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
1007 /* Copy over the code. */
1009 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
1011 /* Insert the function address into the new wrapper instance. */
1013 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
1014 *calladdr = (vm_offset_t)func;
1016 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
1017 *argaddr = argcnt * sizeof(uint32_t);
1024 extern void x86_regparm_wrap(void);
1025 extern void x86_regparm_wrap_call(void);
1026 extern void x86_regparm_wrap_end(void);
1029 windrv_wrap_regparm(func, wrap)
1034 vm_offset_t *calladdr;
1035 vm_offset_t wrapstart, wrapend, wrapcall;
1037 wrapstart = (vm_offset_t)&x86_regparm_wrap;
1038 wrapend = (vm_offset_t)&x86_regparm_wrap_end;
1039 wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
1041 /* Allocate a new wrapper instance. */
1043 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
1047 /* Copy over the code. */
1049 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
1051 /* Insert the function address into the new wrapper instance. */
1053 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
1054 *calladdr = (vm_offset_t)func;
1062 windrv_wrap(func, wrap, argcnt, ftype)
1069 case WINDRV_WRAP_FASTCALL:
1070 return (windrv_wrap_fastcall(func, wrap, argcnt));
1071 case WINDRV_WRAP_STDCALL:
1072 return (windrv_wrap_stdcall(func, wrap, argcnt));
1073 case WINDRV_WRAP_REGPARM:
1074 return (windrv_wrap_regparm(func, wrap));
1075 case WINDRV_WRAP_CDECL:
1076 return (windrv_wrap_stdcall(func, wrap, 0));
1088 struct x86desc *gdt;
1092 mtx_lock_spin(&dt_lock);
1094 /* Grab location of existing GDT. */
1096 x86_getldt(>able, <able);
1098 /* Find the slot we updated. */
1101 gdt += FREEBSD_EMPTYSEL;
1105 bzero((char *)gdt, sizeof(struct x86desc));
1109 x86_setldt(>able, ltable);
1111 mtx_unlock_spin(&dt_lock);
1125 mtx_lock_spin(&dt_lock);
1127 /* Grab location of existing GDT. */
1129 x86_getldt(>able, <able);
1131 /* Get pointer to the GDT table. */
1135 /* Get pointer to empty slot */
1137 l += FREEBSD_EMPTYSEL;
1139 /* Initialize TID for this CPU. */
1141 my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL;
1142 my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu];
1144 /* Set up new GDT entry. */
1146 l->x_lolimit = sizeof(struct tid);
1147 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
1148 l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF;
1149 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF;
1150 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF;
1151 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
1153 /* Update the GDT. */
1155 x86_setldt(>able, ltable);
1157 mtx_unlock_spin(&dt_lock);
1162 #endif /* __i386__ */
1168 free(func, M_DEVBUF);