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

Cache object: a99f0680c194c6312812509273424733


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