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