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