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 <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>
43 #include <sys/mutex2.h>
44 #include <sys/module.h>
49 #include <sys/sched.h>
51 #include <sys/queue.h>
54 #include <machine/segments.h>
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
;
75 static void x86_oldldt(void *);
76 static void x86_newldt(void *);
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
;
89 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
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");
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);
121 panic("failed to allocate thread info blocks");
122 lwkt_cpusync_simple(-1, x86_newldt
, NULL
);
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
);
138 lockmgr(&drvdb_lock
, LK_RELEASE
);
140 RtlFreeUnicodeString(&fake_pci_driver
.dro_drivername
);
141 RtlFreeUnicodeString(&fake_pccard_driver
.dro_drivername
);
143 lockuninit(&drvdb_lock
);
146 lwkt_cpusync_simple(-1, x86_oldldt
, NULL
);
153 * Given the address of a driver image, find its corresponding
158 windrv_lookup(vm_offset_t img
, char *name
)
164 bzero((char *)&us
, sizeof(us
));
169 RtlInitAnsiString(&as
, name
);
170 if (RtlAnsiStringToUnicodeString(&us
, &as
, TRUE
))
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
);
181 ExFreePool(us
.us_buf
);
182 return (d
->windrv_object
);
185 lockmgr(&drvdb_lock
, LK_RELEASE
);
188 RtlFreeUnicodeString(&us
);
194 windrv_match(matchfuncptr matchfunc
, void *ctx
)
199 lockmgr(&drvdb_lock
, LK_EXCLUSIVE
);
200 STAILQ_FOREACH(d
, &drvdb_head
, link
) {
201 if (d
->windrv_devlist
== NULL
)
203 match
= matchfunc(d
->windrv_bustype
, d
->windrv_devlist
, ctx
);
205 lockmgr(&drvdb_lock
, LK_RELEASE
);
209 lockmgr(&drvdb_lock
, LK_RELEASE
);
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
;
224 device_object
*d
, *pdo
;
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
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,
247 if (db
->windrv_devlist
!= NULL
)
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
;
256 dev
= pdo
->do_devext
;
257 pdo
= pdo
->do_nextdev
;
258 lockmgr(&drvdb_lock
, LK_RELEASE
);
260 lockmgr(&drvdb_lock
, LK_EXCLUSIVE
);
264 STAILQ_FOREACH(db
, &drvdb_head
, link
) {
265 if (db
->windrv_object
->dro_driverstart
== (void *)img
) {
267 STAILQ_REMOVE(&drvdb_head
, db
, drvdb_ent
, link
);
271 lockmgr(&drvdb_lock
, LK_RELEASE
);
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
);
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 */
303 #define WINDRV_LOADED htonl(0x42534F44)
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
;
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
;
335 struct drvdb_ent
*new;
336 struct driver_object
*drv
;
342 * First step: try to relocate and dynalink the executable
346 ptr
= (uint32_t *)(img
+ 8);
347 if (*ptr
== WINDRV_LOADED
)
350 /* Perform text relocation */
351 if (pe_relocate(img
))
354 /* Dynamically link the NDIS.SYS routines -- required. */
355 if (pe_patch_imports(img
, "NDIS", ndis_functbl
))
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
))
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
))
371 patch_user_shared_data_address(img
, len
);
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
))
380 *ptr
= WINDRV_LOADED
;
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
);
395 drv
= kmalloc(sizeof(driver_object
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
397 kfree (new, M_DEVBUF
);
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
);
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
);
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
);
440 lockmgr(&drvdb_lock
, LK_EXCLUSIVE
);
441 STAILQ_INSERT_HEAD(&drvdb_head
, new, link
);
442 lockmgr(&drvdb_lock
, LK_RELEASE
);
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
)
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
);
476 windrv_destroy_pdo(driver_object
*drv
, device_t bsddev
)
480 pdo
= windrv_find_pdo(drv
, bsddev
);
482 /* Remove reference to device_t */
484 pdo
->do_devext
= NULL
;
486 lockmgr(&drvdb_lock
, LK_EXCLUSIVE
);
488 lockmgr(&drvdb_lock
, LK_RELEASE
);
492 * Given a device_t, find the corresponding PDO in a driver's
497 windrv_find_pdo(driver_object
*drv
, device_t bsddev
)
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
);
508 pdo
= pdo
->do_nextdev
;
510 lockmgr(&drvdb_lock
, LK_RELEASE
);
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;
526 new = kmalloc(sizeof(struct drvdb_ent
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
530 RtlInitAnsiString(&as
, name
);
531 if (RtlAnsiStringToUnicodeString(&drv
->dro_drivername
, &as
, TRUE
))
533 kfree(new, M_DEVBUF
);
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
);
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
)
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
);
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
;
590 #endif /* __x86_64__ */
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.
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
667 if (t
->tid_self
!= t
)
670 x86_critical_enter();
671 t
->tid_oldfs
= x86_getfs();
672 t
->tid_cpu
= curthread
->td_gd
->gd_cpuid
;
673 #if 0 /* XXX swildner */
676 x86_setfs(SEL_TO_FS(t
->tid_selector
));
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
693 x86_critical_enter();
695 x86_setfs(t
->tid_oldfs
);
696 #if 0 /* XXX swildner */
701 /* Welcome back to UNIX land, we missed you. */
704 if (t
->tid_cpu
!= curthread
->td_gd
->gd_cpuid
)
705 panic("ctxsw GOT MOVED TO OTHER CPU!");
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);
719 windrv_wrap_fastcall(funcptr func
, funcptr
*wrap
, int argcnt
)
722 vm_offset_t
*calladdr
;
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
);
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
;
750 argaddr
= (u_int8_t
*)((char *)p
+ ((wraparg
- wrapstart
) + 1));
751 *argaddr
= argcnt
* sizeof(uint32_t);
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);
764 windrv_wrap_stdcall(funcptr func
, funcptr
*wrap
, int argcnt
)
767 vm_offset_t
*calladdr
;
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
);
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);
799 extern void x86_regparm_wrap(void);
800 extern void x86_regparm_wrap_call(void);
801 extern void x86_regparm_wrap_end(void);
804 windrv_wrap_regparm(funcptr func
, funcptr
*wrap
)
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
);
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
;
835 windrv_wrap(funcptr func
, funcptr
*wrap
, int argcnt
, int 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));
854 x86_oldldt(void *dummy
)
860 mtx_spinlock(&dt_lock
);
862 /* Grab location of existing GDT. */
864 x86_getldt(>able
, <able
);
866 /* Find the slot we updated. */
873 bzero((char *)gdt
, sizeof(struct x86desc
));
877 x86_setldt(>able
, ltable
);
879 mtx_spinunlock(&dt_lock
);
883 x86_newldt(void *dummy
)
892 mtx_spinlock(&dt_lock
);
894 /* Grab location of existing GDT. */
896 x86_getldt(>able
, <able
);
898 /* Get pointer to the GDT table. */
902 /* Get pointer to empty slot */
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(>able
, ltable
);
924 mtx_spinunlock(&dt_lock
);
929 #endif /* __i386__ */
932 windrv_unwrap(funcptr func
)
934 kfree(func
, M_DEVBUF
);