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