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: releng/6.0/sys/compat/ndis/kern_windrv.c 151742 2005-10-27 17:08:57Z wpaul $");
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 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 t->tid_oldfs = x86_getfs();
684 t->tid_cpu = curthread->td_oncpu;
685
686 x86_setfs(SEL_TO_FS(t->tid_selector));
687
688 /* Now entering Windows land, population: you. */
689
690 return;
691 }
692
693 /*
694 * Context switch from Windows back to UNIX. Restore %fs to
695 * its previous value. This always occurs after a call to
696 * ctxsw_utow().
697 */
698
699 void
700 ctxsw_wtou(void)
701 {
702 struct tid *t;
703
704 t = x86_gettid();
705 x86_setfs(t->tid_oldfs);
706
707 /* Welcome back to UNIX land, we missed you. */
708
709 #ifdef EXTRA_SANITY
710 if (t->tid_cpu != curthread->td_oncpu)
711 panic("ctxsw GOT MOVED TO OTHER CPU!");
712 #endif
713 return;
714 }
715
716 static int windrv_wrap_stdcall(funcptr, funcptr *, int);
717 static int windrv_wrap_fastcall(funcptr, funcptr *, int);
718 static int windrv_wrap_regparm(funcptr, funcptr *);
719
720 extern void x86_fastcall_wrap(void);
721 extern void x86_fastcall_wrap_call(void);
722 extern void x86_fastcall_wrap_arg(void);
723 extern void x86_fastcall_wrap_end(void);
724
725 static int
726 windrv_wrap_fastcall(func, wrap, argcnt)
727 funcptr func;
728 funcptr *wrap;
729 int8_t argcnt;
730 {
731 funcptr p;
732 vm_offset_t *calladdr;
733 uint8_t *argaddr;
734 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
735
736 wrapstart = (vm_offset_t)&x86_fastcall_wrap;
737 wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
738 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
739 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
740
741 /* Allocate a new wrapper instance. */
742
743 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
744 if (p == NULL)
745 return(ENOMEM);
746
747 /* Copy over the code. */
748
749 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
750
751 /* Insert the function address into the new wrapper instance. */
752
753 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
754 *calladdr = (vm_offset_t)func;
755
756 argcnt -= 2;
757 if (argcnt < 1)
758 argcnt = 0;
759
760 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
761 *argaddr = argcnt * sizeof(uint32_t);
762
763 *wrap = p;
764
765 return(0);
766 }
767
768 extern void x86_stdcall_wrap(void);
769 extern void x86_stdcall_wrap_call(void);
770 extern void x86_stdcall_wrap_arg(void);
771 extern void x86_stdcall_wrap_end(void);
772
773 static int
774 windrv_wrap_stdcall(func, wrap, argcnt)
775 funcptr func;
776 funcptr *wrap;
777 uint8_t argcnt;
778 {
779 funcptr p;
780 vm_offset_t *calladdr;
781 uint8_t *argaddr;
782 vm_offset_t wrapstart, wrapend, wrapcall, wraparg;
783
784 wrapstart = (vm_offset_t)&x86_stdcall_wrap;
785 wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
786 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
787 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
788
789 /* Allocate a new wrapper instance. */
790
791 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
792 if (p == NULL)
793 return(ENOMEM);
794
795 /* Copy over the code. */
796
797 bcopy((char *)wrapstart, p, (wrapend - wrapstart));
798
799 /* Insert the function address into the new wrapper instance. */
800
801 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
802 *calladdr = (vm_offset_t)func;
803
804 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
805 *argaddr = argcnt * sizeof(uint32_t);
806
807 *wrap = p;
808
809 return(0);
810 }
811
812 extern void x86_regparm_wrap(void);
813 extern void x86_regparm_wrap_call(void);
814 extern void x86_regparm_wrap_end(void);
815
816 static int
817 windrv_wrap_regparm(func, wrap)
818 funcptr func;
819 funcptr *wrap;
820 {
821 funcptr p;
822 vm_offset_t *calladdr;
823 vm_offset_t wrapstart, wrapend, wrapcall;
824
825 wrapstart = (vm_offset_t)&x86_regparm_wrap;
826 wrapend = (vm_offset_t)&x86_regparm_wrap_end;
827 wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
828
829 /* Allocate a new wrapper instance. */
830
831 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
832 if (p == NULL)
833 return(ENOMEM);
834
835 /* Copy over the code. */
836
837 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
838
839 /* Insert the function address into the new wrapper instance. */
840
841 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
842 *calladdr = (vm_offset_t)func;
843
844 *wrap = p;
845
846 return(0);
847 }
848
849 int
850 windrv_wrap(func, wrap, argcnt, ftype)
851 funcptr func;
852 funcptr *wrap;
853 int argcnt;
854 int ftype;
855 {
856 switch(ftype) {
857 case WINDRV_WRAP_FASTCALL:
858 return(windrv_wrap_fastcall(func, wrap, argcnt));
859 case WINDRV_WRAP_STDCALL:
860 return(windrv_wrap_stdcall(func, wrap, argcnt));
861 case WINDRV_WRAP_REGPARM:
862 return(windrv_wrap_regparm(func, wrap));
863 case WINDRV_WRAP_CDECL:
864 return(windrv_wrap_stdcall(func, wrap, 0));
865 default:
866 break;
867 }
868
869 return(EINVAL);
870 }
871
872 static void
873 x86_oldldt(dummy)
874 void *dummy;
875 {
876 struct thread *t;
877 struct x86desc *gdt;
878 struct gdt gtable;
879 uint16_t ltable;
880
881 mtx_lock_spin(&sched_lock);
882
883 t = curthread;
884
885 /* Grab location of existing GDT. */
886
887 x86_getldt(>able, <able);
888
889 /* Find the slot we updated. */
890
891 gdt = gtable.base;
892 gdt += FREEBSD_EMPTYSEL;
893
894 /* Empty it out. */
895
896 bzero((char *)gdt, sizeof(struct x86desc));
897
898 /* Restore GDT. */
899
900 x86_setldt(>able, ltable);
901
902 mtx_unlock_spin(&sched_lock);
903
904 return;
905 }
906
907 static void
908 x86_newldt(dummy)
909 void *dummy;
910 {
911 struct gdt gtable;
912 uint16_t ltable;
913 struct x86desc *l;
914 struct thread *t;
915
916 mtx_lock_spin(&sched_lock);
917
918 t = curthread;
919
920 /* Grab location of existing GDT. */
921
922 x86_getldt(>able, <able);
923
924 /* Get pointer to the GDT table. */
925
926 l = gtable.base;
927
928 /* Get pointer to empty slot */
929
930 l += FREEBSD_EMPTYSEL;
931
932 /* Initialize TID for this CPU. */
933
934 my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL;
935 my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu];
936
937 /* Set up new GDT entry. */
938
939 l->x_lolimit = sizeof(struct tid);
940 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
941 l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF;
942 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF;
943 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF;
944 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
945
946 /* Update the GDT. */
947
948 x86_setldt(>able, ltable);
949
950 mtx_unlock_spin(&sched_lock);
951
952 /* Whew. */
953
954 return;
955 }
956
957 #endif /* __i386__ */
958
959 int
960 windrv_unwrap(func)
961 funcptr func;
962 {
963 free(func, M_DEVBUF);
964
965 return(0);
966 }
Cache object: d14e62cbdf7abc2c5b203bc13e17f7c9
|