]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/ndis/kern_windrv.c
MFV r336851:
[FreeBSD/FreeBSD.git] / sys / compat / ndis / kern_windrv.c
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$");
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(&gtable, &ltable);
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(&gtable, 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(&gtable, &ltable);
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(&gtable, 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 }