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

Cache object: 5f2f94531ae9409a27d54f6ce2090b58


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