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 return(ENOMEM);
531
532 /*
533 * Set up a fake image pointer to avoid false matches
534 * in windrv_lookup().
535 */
536 drv->dro_driverstart = (void *)0xFFFFFFFF;
537
538 new->windrv_object = drv;
539 new->windrv_devlist = NULL;
540 new->windrv_regvals = NULL;
541
542 mtx_lock(&drvdb_mtx);
543 STAILQ_INSERT_HEAD(&drvdb_head, new, link);
544 mtx_unlock(&drvdb_mtx);
545
546 return(0);
547 }
548
549 #ifdef __amd64__
550
551 extern void x86_64_wrap(void);
552 extern void x86_64_wrap_call(void);
553 extern void x86_64_wrap_end(void);
554
555 int
556 windrv_wrap(func, wrap, argcnt, ftype)
557 funcptr func;
558 funcptr *wrap;
559 int argcnt;
560 int ftype;
561 {
562 funcptr p;
563 vm_offset_t *calladdr;
564 vm_offset_t wrapstart, wrapend, wrapcall;
565
566 wrapstart = (vm_offset_t)&x86_64_wrap;
567 wrapend = (vm_offset_t)&x86_64_wrap_end;
568 wrapcall = (vm_offset_t)&x86_64_wrap_call;
569
570 /* Allocate a new wrapper instance. */
571
572 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
573 if (p == NULL)
574 return(ENOMEM);
575
576 /* Copy over the code. */
577
578 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
579
580 /* Insert the function address into the new wrapper instance. */
581
582 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
583 *calladdr = (vm_offset_t)func;
584
585 *wrap = p;
586
587 return(0);
588 }
589 #endif /* __amd64__ */
590
591
592 #ifdef __i386__
593
594 struct x86desc {
595 uint16_t x_lolimit;
596 uint16_t x_base0;
597 uint8_t x_base1;
598 uint8_t x_flags;
599 uint8_t x_hilimit;
600 uint8_t x_base2;
601 };
602
603 struct gdt {
604 uint16_t limit;
605 void *base;
606 } __attribute__((__packed__));
607
608 extern uint16_t x86_getfs(void);
609 extern void x86_setfs(uint16_t);
610 extern void *x86_gettid(void);
611 extern void x86_critical_enter(void);
612 extern void x86_critical_exit(void);
613 extern void x86_getldt(struct gdt *, uint16_t *);
614 extern void x86_setldt(struct gdt *, uint16_t);
615
616 #define SEL_LDT 4 /* local descriptor table */
617 #define SEL_TO_FS(x) (((x) << 3))
618
619 /*
620 * FreeBSD 6.0 and later has a special GDT segment reserved
621 * specifically for us, so if GNDIS_SEL is defined, use that.
622 * If not, use GTGATE_SEL, which is uninitialized and infrequently
623 * used.
624 */
625
626 #ifdef GNDIS_SEL
627 #define FREEBSD_EMPTYSEL GNDIS_SEL
628 #else
629 #define FREEBSD_EMPTYSEL GTGATE_SEL /* slot 7 */
630 #endif
631
632 /*
633 * The meanings of various bits in a descriptor vary a little
634 * depending on whether the descriptor will be used as a
635 * code, data or system descriptor. (And that in turn depends
636 * on which segment register selects the descriptor.)
637 * We're only trying to create a data segment, so the definitions
638 * below are the ones that apply to a data descriptor.
639 */
640
641 #define SEGFLAGLO_PRESENT 0x80 /* segment is present */
642 #define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */
643 #define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */
644 #define SEGFLAGLO_MBZ 0x08 /* must be zero */
645 #define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */
646 #define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */
647 #define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */
648
649 #define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */
650 #define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */
651
652 /*
653 * Context switch from UNIX to Windows. Save the existing value
654 * of %fs for this processor, then change it to point to our
655 * fake TID. Note that it is also possible to pin ourselves
656 * to our current CPU, though I'm not sure this is really
657 * necessary. It depends on whether or not an interrupt might
658 * preempt us while Windows code is running and we wind up
659 * scheduled onto another CPU as a result. So far, it doesn't
660 * seem like this is what happens.
661 */
662
663 void
664 ctxsw_utow(void)
665 {
666 struct tid *t;
667
668 t = &my_tids[curthread->td_oncpu];
669
670 /*
671 * Ugly hack. During system bootstrap (cold == 1), only CPU 0
672 * is running. So if we were loaded at bootstrap, only CPU 0
673 * will have our special GDT entry. This is a problem for SMP
674 * systems, so to deal with this, we check here to make sure
675 * the TID for this processor has been initialized, and if it
676 * hasn't, we need to do it right now or else things will
677 * explode.
678 */
679
680 if (t->tid_self != t)
681 x86_newldt(NULL);
682
683 x86_critical_enter();
684 t->tid_oldfs = x86_getfs();
685 t->tid_cpu = curthread->td_oncpu;
686 sched_pin();
687 x86_setfs(SEL_TO_FS(t->tid_selector));
688 x86_critical_exit();
689
690 /* Now entering Windows land, population: you. */
691
692 return;
693 }
694
695 /*
696 * Context switch from Windows back to UNIX. Restore %fs to
697 * its previous value. This always occurs after a call to
698 * ctxsw_utow().
699 */
700
701 void
702 ctxsw_wtou(void)
703 {
704 struct tid *t;
705
706 x86_critical_enter();
707 t = x86_gettid();
708 x86_setfs(t->tid_oldfs);
709 sched_unpin();
710 x86_critical_exit();
711
712 /* Welcome back to UNIX land, we missed you. */
713
714 #ifdef EXTRA_SANITY
715 if (t->tid_cpu != curthread->td_oncpu)
716 panic("ctxsw GOT MOVED TO OTHER CPU!");
717 #endif
718 return;
719 }
720
721 static int windrv_wrap_stdcall(funcptr, funcptr *, int);
722 static int windrv_wrap_fastcall(funcptr, funcptr *, int);
723 static int windrv_wrap_regparm(funcptr, funcptr *);
724
725 extern void x86_fastcall_wrap(void);
726 extern void x86_fastcall_wrap_call(void);
727 extern void x86_fastcall_wrap_arg(void);
728 extern void x86_fastcall_wrap_end(void);
729
730 static int
731 windrv_wrap_fastcall(func, wrap, argcnt)
732 funcptr func;
733 funcptr *wrap;
734 int8_t argcnt;
735 {
736 funcptr p;
737 vm_offset_t *calladdr;
738 uint8_t *argaddr;
739 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
740
741 wrapstart = (vm_offset_t)&x86_fastcall_wrap;
742 wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
743 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
744 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
745
746 /* Allocate a new wrapper instance. */
747
748 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
749 if (p == NULL)
750 return(ENOMEM);
751
752 /* Copy over the code. */
753
754 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
755
756 /* Insert the function address into the new wrapper instance. */
757
758 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
759 *calladdr = (vm_offset_t)func;
760
761 argcnt -= 2;
762 if (argcnt < 1)
763 argcnt = 0;
764
765 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
766 *argaddr = argcnt * sizeof(uint32_t);
767
768 *wrap = p;
769
770 return(0);
771 }
772
773 extern void x86_stdcall_wrap(void);
774 extern void x86_stdcall_wrap_call(void);
775 extern void x86_stdcall_wrap_arg(void);
776 extern void x86_stdcall_wrap_end(void);
777
778 static int
779 windrv_wrap_stdcall(func, wrap, argcnt)
780 funcptr func;
781 funcptr *wrap;
782 uint8_t argcnt;
783 {
784 funcptr p;
785 vm_offset_t *calladdr;
786 uint8_t *argaddr;
787 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
788
789 wrapstart = (vm_offset_t)&x86_stdcall_wrap;
790 wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
791 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
792 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
793
794 /* Allocate a new wrapper instance. */
795
796 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
797 if (p == NULL)
798 return(ENOMEM);
799
800 /* Copy over the code. */
801
802 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
803
804 /* Insert the function address into the new wrapper instance. */
805
806 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
807 *calladdr = (vm_offset_t)func;
808
809 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
810 *argaddr = argcnt * sizeof(uint32_t);
811
812 *wrap = p;
813
814 return(0);
815 }
816
817 extern void x86_regparm_wrap(void);
818 extern void x86_regparm_wrap_call(void);
819 extern void x86_regparm_wrap_end(void);
820
821 static int
822 windrv_wrap_regparm(func, wrap)
823 funcptr func;
824 funcptr *wrap;
825 {
826 funcptr p;
827 vm_offset_t *calladdr;
828 vm_offset_t wrapstart, wrapend, wrapcall;
829
830 wrapstart = (vm_offset_t)&x86_regparm_wrap;
831 wrapend = (vm_offset_t)&x86_regparm_wrap_end;
832 wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
833
834 /* Allocate a new wrapper instance. */
835
836 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
837 if (p == NULL)
838 return(ENOMEM);
839
840 /* Copy over the code. */
841
842 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
843
844 /* Insert the function address into the new wrapper instance. */
845
846 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
847 *calladdr = (vm_offset_t)func;
848
849 *wrap = p;
850
851 return(0);
852 }
853
854 int
855 windrv_wrap(func, wrap, argcnt, ftype)
856 funcptr func;
857 funcptr *wrap;
858 int argcnt;
859 int ftype;
860 {
861 switch(ftype) {
862 case WINDRV_WRAP_FASTCALL:
863 return(windrv_wrap_fastcall(func, wrap, argcnt));
864 case WINDRV_WRAP_STDCALL:
865 return(windrv_wrap_stdcall(func, wrap, argcnt));
866 case WINDRV_WRAP_REGPARM:
867 return(windrv_wrap_regparm(func, wrap));
868 case WINDRV_WRAP_CDECL:
869 return(windrv_wrap_stdcall(func, wrap, 0));
870 default:
871 break;
872 }
873
874 return(EINVAL);
875 }
876
877 static void
878 x86_oldldt(dummy)
879 void *dummy;
880 {
881 struct thread *t;
882 struct x86desc *gdt;
883 struct gdt gtable;
884 uint16_t ltable;
885
886 mtx_lock_spin(&sched_lock);
887
888 t = curthread;
889
890 /* Grab location of existing GDT. */
891
892 x86_getldt(>able, <able);
893
894 /* Find the slot we updated. */
895
896 gdt = gtable.base;
897 gdt += FREEBSD_EMPTYSEL;
898
899 /* Empty it out. */
900
901 bzero((char *)gdt, sizeof(struct x86desc));
902
903 /* Restore GDT. */
904
905 x86_setldt(>able, ltable);
906
907 mtx_unlock_spin(&sched_lock);
908
909 return;
910 }
911
912 static void
913 x86_newldt(dummy)
914 void *dummy;
915 {
916 struct gdt gtable;
917 uint16_t ltable;
918 struct x86desc *l;
919 struct thread *t;
920
921 mtx_lock_spin(&sched_lock);
922
923 t = curthread;
924
925 /* Grab location of existing GDT. */
926
927 x86_getldt(>able, <able);
928
929 /* Get pointer to the GDT table. */
930
931 l = gtable.base;
932
933 /* Get pointer to empty slot */
934
935 l += FREEBSD_EMPTYSEL;
936
937 /* Initialize TID for this CPU. */
938
939 my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL;
940 my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu];
941
942 /* Set up new GDT entry. */
943
944 l->x_lolimit = sizeof(struct tid);
945 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
946 l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF;
947 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF;
948 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF;
949 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
950
951 /* Update the GDT. */
952
953 x86_setldt(>able, ltable);
954
955 mtx_unlock_spin(&sched_lock);
956
957 /* Whew. */
958
959 return;
960 }
961
962 #endif /* __i386__ */
963
964 int
965 windrv_unwrap(func)
966 funcptr func;
967 {
968 free(func, M_DEVBUF);
969
970 return(0);
971 }
Cache object: c00c6dc1b14caadd15a9ab294d921daa
|