The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ 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  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 353420de10dc94b8954b0e54d344bf1b


[ 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.