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