1 /*-
2 * Copyright (c) 2005
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
4 *
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.
19 *
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.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.16 2008/12/28 13:50:58 ganbold Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/unistd.h>
39 #include <sys/types.h>
40
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/module.h>
46 #include <sys/conf.h>
47 #include <sys/mbuf.h>
48 #include <sys/bus.h>
49 #include <sys/proc.h>
50 #include <sys/sched.h>
51 #include <sys/smp.h>
52
53 #include <sys/queue.h>
54
55 #ifdef __i386__
56 #include <machine/segments.h>
57 #endif
58
59 #include <dev/usb/usb.h>
60 #include <dev/usb/usbdi.h>
61
62 #include <compat/ndis/pe_var.h>
63 #include <compat/ndis/cfg_var.h>
64 #include <compat/ndis/resource_var.h>
65 #include <compat/ndis/ntoskrnl_var.h>
66 #include <compat/ndis/ndis_var.h>
67 #include <compat/ndis/hal_var.h>
68 #include <compat/ndis/usbd_var.h>
69
70 static struct mtx drvdb_mtx;
71 static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
72
73 static driver_object fake_pci_driver; /* serves both PCI and cardbus */
74 static driver_object fake_pccard_driver;
75
76 #ifdef __i386__
77 static void x86_oldldt(void *);
78 static void x86_newldt(void *);
79
80 struct tid {
81 void *tid_except_list; /* 0x00 */
82 uint32_t tid_oldfs; /* 0x04 */
83 uint32_t tid_selector; /* 0x08 */
84 struct tid *tid_self; /* 0x0C */
85 int tid_cpu; /* 0x10 */
86 };
87
88 static struct tid *my_tids;
89 #endif /* __i386__ */
90
91 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
92
93 int
94 windrv_libinit(void)
95 {
96 STAILQ_INIT(&drvdb_head);
97 mtx_init(&drvdb_mtx, "Windows driver DB lock",
98 "Windows internal lock", MTX_DEF);
99
100 /*
101 * PCI and pccard devices don't need to use IRPs to
102 * interact with their bus drivers (usually), so our
103 * emulated PCI and pccard drivers are just stubs.
104 * USB devices, on the other hand, do all their I/O
105 * by exchanging IRPs with the USB bus driver, so
106 * for that we need to provide emulator dispatcher
107 * routines, which are in a separate module.
108 */
109
110 windrv_bus_attach(&fake_pci_driver, "PCI Bus");
111 windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus");
112
113 #ifdef __i386__
114
115 /*
116 * In order to properly support SMP machines, we have
117 * to modify the GDT on each CPU, since we never know
118 * on which one we'll end up running.
119 */
120
121 my_tids = ExAllocatePoolWithTag(NonPagedPool,
122 sizeof(struct tid) * mp_ncpus, 0);
123 if (my_tids == NULL)
124 panic("failed to allocate thread info blocks");
125 smp_rendezvous(NULL, x86_newldt, NULL, NULL);
126 #endif
127 return(0);
128 }
129
130 int
131 windrv_libfini(void)
132 {
133 struct drvdb_ent *d;
134
135 mtx_lock(&drvdb_mtx);
136 while(STAILQ_FIRST(&drvdb_head) != NULL) {
137 d = STAILQ_FIRST(&drvdb_head);
138 STAILQ_REMOVE_HEAD(&drvdb_head, link);
139 free(d, M_DEVBUF);
140 }
141 mtx_unlock(&drvdb_mtx);
142
143 RtlFreeUnicodeString(&fake_pci_driver.dro_drivername);
144 RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername);
145
146 mtx_destroy(&drvdb_mtx);
147
148 #ifdef __i386__
149 smp_rendezvous(NULL, x86_oldldt, NULL, NULL);
150 ExFreePool(my_tids);
151 #endif
152 return(0);
153 }
154
155 /*
156 * Given the address of a driver image, find its corresponding
157 * driver_object.
158 */
159
160 driver_object *
161 windrv_lookup(img, name)
162 vm_offset_t img;
163 char *name;
164 {
165 struct drvdb_ent *d;
166 unicode_string us;
167 ansi_string as;
168
169 bzero((char *)&us, sizeof(us));
170
171 /* Damn unicode. */
172
173 if (name != NULL) {
174 RtlInitAnsiString(&as, name);
175 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE))
176 return(NULL);
177 }
178
179 mtx_lock(&drvdb_mtx);
180 STAILQ_FOREACH(d, &drvdb_head, link) {
181 if (d->windrv_object->dro_driverstart == (void *)img ||
182 (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
183 (char *)us.us_buf, us.us_len) == 0 && us.us_len)) {
184 mtx_unlock(&drvdb_mtx);
185 if (name != NULL)
186 ExFreePool(us.us_buf);
187 return(d->windrv_object);
188 }
189 }
190 mtx_unlock(&drvdb_mtx);
191
192 if (name != NULL)
193 RtlFreeUnicodeString(&us);
194
195 return(NULL);
196 }
197
198 struct drvdb_ent *
199 windrv_match(matchfunc, ctx)
200 matchfuncptr matchfunc;
201 void *ctx;
202 {
203 struct drvdb_ent *d;
204 int match;
205
206 mtx_lock(&drvdb_mtx);
207 STAILQ_FOREACH(d, &drvdb_head, link) {
208 if (d->windrv_devlist == NULL)
209 continue;
210 match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx);
211 if (match == TRUE) {
212 mtx_unlock(&drvdb_mtx);
213 return(d);
214 }
215 }
216 mtx_unlock(&drvdb_mtx);
217
218 return(NULL);
219 }
220
221 /*
222 * Remove a driver_object from our datatabase and destroy it. Throw
223 * away any custom driver extension info that may have been added.
224 */
225
226 int
227 windrv_unload(mod, img, len)
228 module_t mod;
229 vm_offset_t img;
230 int len;
231 {
232 struct drvdb_ent *db, *r = NULL;
233 driver_object *drv;
234 device_object *d, *pdo;
235 device_t dev;
236 list_entry *e;
237
238 drv = windrv_lookup(img, NULL);
239
240 /*
241 * When we unload a driver image, we need to force a
242 * detach of any devices that might be using it. We
243 * need the PDOs of all attached devices for this.
244 * Getting at them is a little hard. We basically
245 * have to walk the device lists of all our bus
246 * drivers.
247 */
248
249 mtx_lock(&drvdb_mtx);
250 STAILQ_FOREACH(db, &drvdb_head, link) {
251 /*
252 * Fake bus drivers have no devlist info.
253 * If this driver has devlist info, it's
254 * a loaded Windows driver and has no PDOs,
255 * so skip it.
256 */
257 if (db->windrv_devlist != NULL)
258 continue;
259 pdo = db->windrv_object->dro_devobj;
260 while (pdo != NULL) {
261 d = pdo->do_attacheddev;
262 if (d->do_drvobj != drv) {
263 pdo = pdo->do_nextdev;
264 continue;
265 }
266 dev = pdo->do_devext;
267 pdo = pdo->do_nextdev;
268 mtx_unlock(&drvdb_mtx);
269 device_detach(dev);
270 mtx_lock(&drvdb_mtx);
271 }
272 }
273
274 STAILQ_FOREACH(db, &drvdb_head, link) {
275 if (db->windrv_object->dro_driverstart == (void *)img) {
276 r = db;
277 STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link);
278 break;
279 }
280 }
281 mtx_unlock(&drvdb_mtx);
282
283 if (r == NULL)
284 return (ENOENT);
285
286 if (drv == NULL)
287 return(ENOENT);
288
289 /*
290 * Destroy any custom extensions that may have been added.
291 */
292 drv = r->windrv_object;
293 while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) {
294 e = RemoveHeadList(&drv->dro_driverext->dre_usrext);
295 ExFreePool(e);
296 }
297
298 /* Free the driver extension */
299 free(drv->dro_driverext, M_DEVBUF);
300
301 /* Free the driver name */
302 RtlFreeUnicodeString(&drv->dro_drivername);
303
304 /* Free driver object */
305 free(drv, M_DEVBUF);
306
307 /* Free our DB handle */
308 free(r, M_DEVBUF);
309
310 return(0);
311 }
312
313 #define WINDRV_LOADED htonl(0x42534F44)
314
315 /*
316 * Loader routine for actual Windows driver modules, ultimately
317 * calls the driver's DriverEntry() routine.
318 */
319
320 int
321 windrv_load(mod, img, len, bustype, devlist, regvals)
322 module_t mod;
323 vm_offset_t img;
324 int len;
325 interface_type bustype;
326 void *devlist;
327 ndis_cfg *regvals;
328 {
329 image_import_descriptor imp_desc;
330 image_optional_header opt_hdr;
331 driver_entry entry;
332 struct drvdb_ent *new;
333 struct driver_object *drv;
334 int status;
335 uint32_t *ptr;
336 ansi_string as;
337
338 /*
339 * First step: try to relocate and dynalink the executable
340 * driver image.
341 */
342
343 ptr = (uint32_t *)(img + 8);
344 if (*ptr == WINDRV_LOADED)
345 goto skipreloc;
346
347 /* Perform text relocation */
348 if (pe_relocate(img))
349 return(ENOEXEC);
350
351 /* Dynamically link the NDIS.SYS routines -- required. */
352 if (pe_patch_imports(img, "NDIS", ndis_functbl))
353 return(ENOEXEC);
354
355 /* Dynamically link the HAL.dll routines -- optional. */
356 if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
357 if (pe_patch_imports(img, "HAL", hal_functbl))
358 return(ENOEXEC);
359 }
360
361 /* Dynamically link ntoskrnl.exe -- optional. */
362 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
363 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
364 return(ENOEXEC);
365 }
366
367 /* Dynamically link USBD.SYS -- optional */
368 if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
369 if (pe_patch_imports(img, "USBD", usbd_functbl))
370 return(ENOEXEC);
371 }
372
373 *ptr = WINDRV_LOADED;
374
375 skipreloc:
376
377 /* Next step: find the driver entry point. */
378
379 pe_get_optional_header(img, &opt_hdr);
380 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
381
382 /* Next step: allocate and store a driver object. */
383
384 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
385 if (new == NULL)
386 return (ENOMEM);
387
388 drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
389 if (drv == NULL) {
390 free (new, M_DEVBUF);
391 return (ENOMEM);
392 }
393
394 /* Allocate a driver extension structure too. */
395
396 drv->dro_driverext = malloc(sizeof(driver_extension),
397 M_DEVBUF, M_NOWAIT|M_ZERO);
398
399 if (drv->dro_driverext == NULL) {
400 free(new, M_DEVBUF);
401 free(drv, M_DEVBUF);
402 return(ENOMEM);
403 }
404
405 InitializeListHead((&drv->dro_driverext->dre_usrext));
406
407 drv->dro_driverstart = (void *)img;
408 drv->dro_driversize = len;
409
410 RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
411 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
412 free(new, M_DEVBUF);
413 free(drv, M_DEVBUF);
414 return(ENOMEM);
415 }
416
417 new->windrv_object = drv;
418 new->windrv_regvals = regvals;
419 new->windrv_devlist = devlist;
420 new->windrv_bustype = bustype;
421
422 /* Now call the DriverEntry() function. */
423
424 status = MSCALL2(entry, drv, &drv->dro_drivername);
425
426 if (status != STATUS_SUCCESS) {
427 RtlFreeUnicodeString(&drv->dro_drivername);
428 free(drv, M_DEVBUF);
429 free(new, M_DEVBUF);
430 return(ENODEV);
431 }
432
433 mtx_lock(&drvdb_mtx);
434 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
435 mtx_unlock(&drvdb_mtx);
436
437 return (0);
438 }
439
440 /*
441 * Make a new Physical Device Object for a device that was
442 * detected/plugged in. For us, the PDO is just a way to
443 * get at the device_t.
444 */
445
446 int
447 windrv_create_pdo(drv, bsddev)
448 driver_object *drv;
449 device_t bsddev;
450 {
451 device_object *dev;
452
453 /*
454 * This is a new physical device object, which technically
455 * is the "top of the stack." Consequently, we don't do
456 * an IoAttachDeviceToDeviceStack() here.
457 */
458
459 mtx_lock(&drvdb_mtx);
460 IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
461 mtx_unlock(&drvdb_mtx);
462
463 /* Stash pointer to our BSD device handle. */
464
465 dev->do_devext = bsddev;
466
467 return(STATUS_SUCCESS);
468 }
469
470 void
471 windrv_destroy_pdo(drv, bsddev)
472 driver_object *drv;
473 device_t bsddev;
474 {
475 device_object *pdo;
476
477 pdo = windrv_find_pdo(drv, bsddev);
478
479 /* Remove reference to device_t */
480
481 pdo->do_devext = NULL;
482
483 mtx_lock(&drvdb_mtx);
484 IoDeleteDevice(pdo);
485 mtx_unlock(&drvdb_mtx);
486
487 return;
488 }
489
490 /*
491 * Given a device_t, find the corresponding PDO in a driver's
492 * device list.
493 */
494
495 device_object *
496 windrv_find_pdo(drv, bsddev)
497 driver_object *drv;
498 device_t bsddev;
499 {
500 device_object *pdo;
501
502 mtx_lock(&drvdb_mtx);
503 pdo = drv->dro_devobj;
504 while (pdo != NULL) {
505 if (pdo->do_devext == bsddev) {
506 mtx_unlock(&drvdb_mtx);
507 return(pdo);
508 }
509 pdo = pdo->do_nextdev;
510 }
511 mtx_unlock(&drvdb_mtx);
512
513 return(NULL);
514 }
515
516 /*
517 * Add an internally emulated driver to the database. We need this
518 * to set up an emulated bus driver so that it can receive IRPs.
519 */
520
521 int
522 windrv_bus_attach(drv, name)
523 driver_object *drv;
524 char *name;
525 {
526 struct drvdb_ent *new;
527 ansi_string as;
528
529 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
530 if (new == NULL)
531 return (ENOMEM);
532
533 RtlInitAnsiString(&as, name);
534 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
535 return(ENOMEM);
536
537 /*
538 * Set up a fake image pointer to avoid false matches
539 * in windrv_lookup().
540 */
541 drv->dro_driverstart = (void *)0xFFFFFFFF;
542
543 new->windrv_object = drv;
544 new->windrv_devlist = NULL;
545 new->windrv_regvals = NULL;
546
547 mtx_lock(&drvdb_mtx);
548 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
549 mtx_unlock(&drvdb_mtx);
550
551 return(0);
552 }
553
554 #ifdef __amd64__
555
556 extern void x86_64_wrap(void);
557 extern void x86_64_wrap_call(void);
558 extern void x86_64_wrap_end(void);
559
560 int
561 windrv_wrap(func, wrap, argcnt, ftype)
562 funcptr func;
563 funcptr *wrap;
564 int argcnt;
565 int ftype;
566 {
567 funcptr p;
568 vm_offset_t *calladdr;
569 vm_offset_t wrapstart, wrapend, wrapcall;
570
571 wrapstart = (vm_offset_t)&x86_64_wrap;
572 wrapend = (vm_offset_t)&x86_64_wrap_end;
573 wrapcall = (vm_offset_t)&x86_64_wrap_call;
574
575 /* Allocate a new wrapper instance. */
576
577 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
578 if (p == NULL)
579 return(ENOMEM);
580
581 /* Copy over the code. */
582
583 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
584
585 /* Insert the function address into the new wrapper instance. */
586
587 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
588 *calladdr = (vm_offset_t)func;
589
590 *wrap = p;
591
592 return(0);
593 }
594 #endif /* __amd64__ */
595
596
597 #ifdef __i386__
598
599 struct x86desc {
600 uint16_t x_lolimit;
601 uint16_t x_base0;
602 uint8_t x_base1;
603 uint8_t x_flags;
604 uint8_t x_hilimit;
605 uint8_t x_base2;
606 };
607
608 struct gdt {
609 uint16_t limit;
610 void *base;
611 } __attribute__((__packed__));
612
613 extern uint16_t x86_getfs(void);
614 extern void x86_setfs(uint16_t);
615 extern void *x86_gettid(void);
616 extern void x86_critical_enter(void);
617 extern void x86_critical_exit(void);
618 extern void x86_getldt(struct gdt *, uint16_t *);
619 extern void x86_setldt(struct gdt *, uint16_t);
620
621 #define SEL_LDT 4 /* local descriptor table */
622 #define SEL_TO_FS(x) (((x) << 3))
623
624 /*
625 * FreeBSD 6.0 and later has a special GDT segment reserved
626 * specifically for us, so if GNDIS_SEL is defined, use that.
627 * If not, use GTGATE_SEL, which is uninitialized and infrequently
628 * used.
629 */
630
631 #ifdef GNDIS_SEL
632 #define FREEBSD_EMPTYSEL GNDIS_SEL
633 #else
634 #define FREEBSD_EMPTYSEL GTGATE_SEL /* slot 7 */
635 #endif
636
637 /*
638 * The meanings of various bits in a descriptor vary a little
639 * depending on whether the descriptor will be used as a
640 * code, data or system descriptor. (And that in turn depends
641 * on which segment register selects the descriptor.)
642 * We're only trying to create a data segment, so the definitions
643 * below are the ones that apply to a data descriptor.
644 */
645
646 #define SEGFLAGLO_PRESENT 0x80 /* segment is present */
647 #define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */
648 #define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */
649 #define SEGFLAGLO_MBZ 0x08 /* must be zero */
650 #define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */
651 #define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */
652 #define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */
653
654 #define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */
655 #define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */
656
657 /*
658 * Context switch from UNIX to Windows. Save the existing value
659 * of %fs for this processor, then change it to point to our
660 * fake TID. Note that it is also possible to pin ourselves
661 * to our current CPU, though I'm not sure this is really
662 * necessary. It depends on whether or not an interrupt might
663 * preempt us while Windows code is running and we wind up
664 * scheduled onto another CPU as a result. So far, it doesn't
665 * seem like this is what happens.
666 */
667
668 void
669 ctxsw_utow(void)
670 {
671 struct tid *t;
672
673 t = &my_tids[curthread->td_oncpu];
674
675 /*
676 * Ugly hack. During system bootstrap (cold == 1), only CPU 0
677 * is running. So if we were loaded at bootstrap, only CPU 0
678 * will have our special GDT entry. This is a problem for SMP
679 * systems, so to deal with this, we check here to make sure
680 * the TID for this processor has been initialized, and if it
681 * hasn't, we need to do it right now or else things will
682 * explode.
683 */
684
685 if (t->tid_self != t)
686 x86_newldt(NULL);
687
688 x86_critical_enter();
689 t->tid_oldfs = x86_getfs();
690 t->tid_cpu = curthread->td_oncpu;
691 sched_pin();
692 x86_setfs(SEL_TO_FS(t->tid_selector));
693 x86_critical_exit();
694
695 /* Now entering Windows land, population: you. */
696
697 return;
698 }
699
700 /*
701 * Context switch from Windows back to UNIX. Restore %fs to
702 * its previous value. This always occurs after a call to
703 * ctxsw_utow().
704 */
705
706 void
707 ctxsw_wtou(void)
708 {
709 struct tid *t;
710
711 x86_critical_enter();
712 t = x86_gettid();
713 x86_setfs(t->tid_oldfs);
714 sched_unpin();
715 x86_critical_exit();
716
717 /* Welcome back to UNIX land, we missed you. */
718
719 #ifdef EXTRA_SANITY
720 if (t->tid_cpu != curthread->td_oncpu)
721 panic("ctxsw GOT MOVED TO OTHER CPU!");
722 #endif
723 return;
724 }
725
726 static int windrv_wrap_stdcall(funcptr, funcptr *, int);
727 static int windrv_wrap_fastcall(funcptr, funcptr *, int);
728 static int windrv_wrap_regparm(funcptr, funcptr *);
729
730 extern void x86_fastcall_wrap(void);
731 extern void x86_fastcall_wrap_call(void);
732 extern void x86_fastcall_wrap_arg(void);
733 extern void x86_fastcall_wrap_end(void);
734
735 static int
736 windrv_wrap_fastcall(func, wrap, argcnt)
737 funcptr func;
738 funcptr *wrap;
739 int8_t argcnt;
740 {
741 funcptr p;
742 vm_offset_t *calladdr;
743 uint8_t *argaddr;
744 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
745
746 wrapstart = (vm_offset_t)&x86_fastcall_wrap;
747 wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
748 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
749 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
750
751 /* Allocate a new wrapper instance. */
752
753 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
754 if (p == NULL)
755 return(ENOMEM);
756
757 /* Copy over the code. */
758
759 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
760
761 /* Insert the function address into the new wrapper instance. */
762
763 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
764 *calladdr = (vm_offset_t)func;
765
766 argcnt -= 2;
767 if (argcnt < 1)
768 argcnt = 0;
769
770 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
771 *argaddr = argcnt * sizeof(uint32_t);
772
773 *wrap = p;
774
775 return(0);
776 }
777
778 extern void x86_stdcall_wrap(void);
779 extern void x86_stdcall_wrap_call(void);
780 extern void x86_stdcall_wrap_arg(void);
781 extern void x86_stdcall_wrap_end(void);
782
783 static int
784 windrv_wrap_stdcall(func, wrap, argcnt)
785 funcptr func;
786 funcptr *wrap;
787 uint8_t argcnt;
788 {
789 funcptr p;
790 vm_offset_t *calladdr;
791 uint8_t *argaddr;
792 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
793
794 wrapstart = (vm_offset_t)&x86_stdcall_wrap;
795 wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
796 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
797 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
798
799 /* Allocate a new wrapper instance. */
800
801 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
802 if (p == NULL)
803 return(ENOMEM);
804
805 /* Copy over the code. */
806
807 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
808
809 /* Insert the function address into the new wrapper instance. */
810
811 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
812 *calladdr = (vm_offset_t)func;
813
814 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
815 *argaddr = argcnt * sizeof(uint32_t);
816
817 *wrap = p;
818
819 return(0);
820 }
821
822 extern void x86_regparm_wrap(void);
823 extern void x86_regparm_wrap_call(void);
824 extern void x86_regparm_wrap_end(void);
825
826 static int
827 windrv_wrap_regparm(func, wrap)
828 funcptr func;
829 funcptr *wrap;
830 {
831 funcptr p;
832 vm_offset_t *calladdr;
833 vm_offset_t wrapstart, wrapend, wrapcall;
834
835 wrapstart = (vm_offset_t)&x86_regparm_wrap;
836 wrapend = (vm_offset_t)&x86_regparm_wrap_end;
837 wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
838
839 /* Allocate a new wrapper instance. */
840
841 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
842 if (p == NULL)
843 return(ENOMEM);
844
845 /* Copy over the code. */
846
847 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
848
849 /* Insert the function address into the new wrapper instance. */
850
851 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
852 *calladdr = (vm_offset_t)func;
853
854 *wrap = p;
855
856 return(0);
857 }
858
859 int
860 windrv_wrap(func, wrap, argcnt, ftype)
861 funcptr func;
862 funcptr *wrap;
863 int argcnt;
864 int ftype;
865 {
866 switch(ftype) {
867 case WINDRV_WRAP_FASTCALL:
868 return(windrv_wrap_fastcall(func, wrap, argcnt));
869 case WINDRV_WRAP_STDCALL:
870 return(windrv_wrap_stdcall(func, wrap, argcnt));
871 case WINDRV_WRAP_REGPARM:
872 return(windrv_wrap_regparm(func, wrap));
873 case WINDRV_WRAP_CDECL:
874 return(windrv_wrap_stdcall(func, wrap, 0));
875 default:
876 break;
877 }
878
879 return(EINVAL);
880 }
881
882 static void
883 x86_oldldt(dummy)
884 void *dummy;
885 {
886 struct x86desc *gdt;
887 struct gdt gtable;
888 uint16_t ltable;
889
890 mtx_lock_spin(&dt_lock);
891
892 /* Grab location of existing GDT. */
893
894 x86_getldt(>able, <able);
895
896 /* Find the slot we updated. */
897
898 gdt = gtable.base;
899 gdt += FREEBSD_EMPTYSEL;
900
901 /* Empty it out. */
902
903 bzero((char *)gdt, sizeof(struct x86desc));
904
905 /* Restore GDT. */
906
907 x86_setldt(>able, ltable);
908
909 mtx_unlock_spin(&dt_lock);
910
911 return;
912 }
913
914 static void
915 x86_newldt(dummy)
916 void *dummy;
917 {
918 struct gdt gtable;
919 uint16_t ltable;
920 struct x86desc *l;
921 struct thread *t;
922
923 t = curthread;
924
925 mtx_lock_spin(&dt_lock);
926
927 /* Grab location of existing GDT. */
928
929 x86_getldt(>able, <able);
930
931 /* Get pointer to the GDT table. */
932
933 l = gtable.base;
934
935 /* Get pointer to empty slot */
936
937 l += FREEBSD_EMPTYSEL;
938
939 /* Initialize TID for this CPU. */
940
941 my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL;
942 my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu];
943
944 /* Set up new GDT entry. */
945
946 l->x_lolimit = sizeof(struct tid);
947 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
948 l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF;
949 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF;
950 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF;
951 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
952
953 /* Update the GDT. */
954
955 x86_setldt(>able, ltable);
956
957 mtx_unlock_spin(&dt_lock);
958
959 /* Whew. */
960
961 return;
962 }
963
964 #endif /* __i386__ */
965
966 int
967 windrv_unwrap(func)
968 funcptr func;
969 {
970 free(func, M_DEVBUF);
971
972 return(0);
973 }
974 Cache object: 721ae8c1cdc5f24a65b968d77af1a6c4
|