Merge branch 'vendor/XZ'
[dragonfly.git] / sys / emulation / ndis / kern_windrv.c
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_oldusb.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 NOLDUSB == 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 NOLDUSB == 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(&gtable, &ltable);
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(&gtable, 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(&gtable, &ltable);
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(&gtable, 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 }