[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/ndis/kern_windrv.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

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

Cache object: 721ae8c1cdc5f24a65b968d77af1a6c4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.