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