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