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/10.4/sys/compat/ndis/kern_windrv.c 215708 2010-11-22 20:46:38Z bschmidt $");
   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 #ifdef __amd64__
  315 static void
  316 patch_user_shared_data_address(vm_offset_t img, size_t len)
  317 {
  318         unsigned long i, n, max_addr, *addr;
  319 
  320         n = len - sizeof(unsigned long);
  321         max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data);
  322         for (i = 0; i < n; i++) {
  323                 addr = (unsigned long *)(img + i);
  324                 if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) {
  325                         *addr -= KI_USER_SHARED_DATA;
  326                         *addr += (unsigned long)&kuser_shared_data;
  327                 }
  328         }
  329 }
  330 #endif
  331 
  332 /*
  333  * Loader routine for actual Windows driver modules, ultimately
  334  * calls the driver's DriverEntry() routine.
  335  */
  336 
  337 int
  338 windrv_load(mod, img, len, bustype, devlist, regvals)
  339         module_t                mod;
  340         vm_offset_t             img;
  341         int                     len;
  342         interface_type          bustype;
  343         void                    *devlist;
  344         ndis_cfg                *regvals;
  345 {
  346         image_import_descriptor imp_desc;
  347         image_optional_header   opt_hdr;
  348         driver_entry            entry;
  349         struct drvdb_ent        *new;
  350         struct driver_object    *drv;
  351         int                     status;
  352         uint32_t                *ptr;
  353         ansi_string             as;
  354 
  355         /*
  356          * First step: try to relocate and dynalink the executable
  357          * driver image.
  358          */
  359 
  360         ptr = (uint32_t *)(img + 8);
  361         if (*ptr == WINDRV_LOADED)
  362                 goto skipreloc;
  363 
  364         /* Perform text relocation */
  365         if (pe_relocate(img))
  366                 return (ENOEXEC);
  367 
  368         /* Dynamically link the NDIS.SYS routines -- required. */
  369         if (pe_patch_imports(img, "NDIS", ndis_functbl))
  370                 return (ENOEXEC);
  371 
  372         /* Dynamically link the HAL.dll routines -- optional. */
  373         if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
  374                 if (pe_patch_imports(img, "HAL", hal_functbl))
  375                         return (ENOEXEC);
  376         }
  377 
  378         /* Dynamically link ntoskrnl.exe -- optional. */
  379         if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
  380                 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
  381                         return (ENOEXEC);
  382         }
  383 
  384 #ifdef __amd64__
  385         patch_user_shared_data_address(img, len);
  386 #endif
  387 
  388         /* Dynamically link USBD.SYS -- optional */
  389         if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
  390                 if (pe_patch_imports(img, "USBD", usbd_functbl))
  391                         return (ENOEXEC);
  392         }
  393 
  394         *ptr = WINDRV_LOADED;
  395 
  396 skipreloc:
  397 
  398         /* Next step: find the driver entry point. */
  399 
  400         pe_get_optional_header(img, &opt_hdr);
  401         entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
  402 
  403         /* Next step: allocate and store a driver object. */
  404 
  405         new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
  406         if (new == NULL)
  407                 return (ENOMEM);
  408 
  409         drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
  410         if (drv == NULL) {
  411                 free (new, M_DEVBUF);
  412                 return (ENOMEM);
  413         }
  414 
  415         /* Allocate a driver extension structure too. */
  416 
  417         drv->dro_driverext = malloc(sizeof(driver_extension),
  418             M_DEVBUF, M_NOWAIT|M_ZERO);
  419 
  420         if (drv->dro_driverext == NULL) {
  421                 free(new, M_DEVBUF);
  422                 free(drv, M_DEVBUF);
  423                 return (ENOMEM);
  424         }
  425 
  426         InitializeListHead((&drv->dro_driverext->dre_usrext));
  427 
  428         drv->dro_driverstart = (void *)img;
  429         drv->dro_driversize = len;
  430 
  431         RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH);
  432         if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) {
  433                 free(new, M_DEVBUF);
  434                 free(drv, M_DEVBUF);
  435                 return (ENOMEM);
  436         }
  437 
  438         new->windrv_object = drv;
  439         new->windrv_regvals = regvals;
  440         new->windrv_devlist = devlist;
  441         new->windrv_bustype = bustype;
  442 
  443         /* Now call the DriverEntry() function. */
  444 
  445         status = MSCALL2(entry, drv, &drv->dro_drivername);
  446 
  447         if (status != STATUS_SUCCESS) {
  448                 RtlFreeUnicodeString(&drv->dro_drivername);
  449                 free(drv, M_DEVBUF);
  450                 free(new, M_DEVBUF);
  451                 return (ENODEV);
  452         }
  453 
  454         mtx_lock(&drvdb_mtx); 
  455         STAILQ_INSERT_HEAD(&drvdb_head, new, link);
  456         mtx_unlock(&drvdb_mtx); 
  457 
  458         return (0);
  459 }
  460 
  461 /*
  462  * Make a new Physical Device Object for a device that was
  463  * detected/plugged in. For us, the PDO is just a way to
  464  * get at the device_t.
  465  */
  466 
  467 int
  468 windrv_create_pdo(drv, bsddev)
  469         driver_object           *drv;
  470         device_t                bsddev;
  471 {
  472         device_object           *dev;
  473 
  474         /*
  475          * This is a new physical device object, which technically
  476          * is the "top of the stack." Consequently, we don't do
  477          * an IoAttachDeviceToDeviceStack() here.
  478          */
  479 
  480         mtx_lock(&drvdb_mtx);
  481         IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
  482         mtx_unlock(&drvdb_mtx);
  483 
  484         /* Stash pointer to our BSD device handle. */
  485 
  486         dev->do_devext = bsddev;
  487 
  488         return (STATUS_SUCCESS);
  489 }
  490 
  491 void
  492 windrv_destroy_pdo(drv, bsddev)
  493         driver_object           *drv;
  494         device_t                bsddev;
  495 {
  496         device_object           *pdo;
  497 
  498         pdo = windrv_find_pdo(drv, bsddev);
  499 
  500         /* Remove reference to device_t */
  501 
  502         pdo->do_devext = NULL;
  503 
  504         mtx_lock(&drvdb_mtx);
  505         IoDeleteDevice(pdo);
  506         mtx_unlock(&drvdb_mtx);
  507 }
  508 
  509 /*
  510  * Given a device_t, find the corresponding PDO in a driver's
  511  * device list.
  512  */
  513 
  514 device_object *
  515 windrv_find_pdo(drv, bsddev)
  516         driver_object           *drv;
  517         device_t                bsddev;
  518 {
  519         device_object           *pdo;
  520 
  521         mtx_lock(&drvdb_mtx);
  522         pdo = drv->dro_devobj;
  523         while (pdo != NULL) {
  524                 if (pdo->do_devext == bsddev) {
  525                         mtx_unlock(&drvdb_mtx);
  526                         return (pdo);
  527                 }
  528                 pdo = pdo->do_nextdev;
  529         }
  530         mtx_unlock(&drvdb_mtx);
  531 
  532         return (NULL);
  533 }
  534 
  535 /*
  536  * Add an internally emulated driver to the database. We need this
  537  * to set up an emulated bus driver so that it can receive IRPs.
  538  */
  539 
  540 int
  541 windrv_bus_attach(drv, name)
  542         driver_object           *drv;
  543         char                    *name;
  544 {
  545         struct drvdb_ent        *new;
  546         ansi_string             as;
  547 
  548         new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO);
  549         if (new == NULL)
  550                 return (ENOMEM);
  551 
  552         RtlInitAnsiString(&as, name);
  553         if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE))
  554         {
  555                 free(new, M_DEVBUF);
  556                 return (ENOMEM);
  557         }
  558 
  559         /*
  560          * Set up a fake image pointer to avoid false matches
  561          * in windrv_lookup().
  562          */
  563         drv->dro_driverstart = (void *)0xFFFFFFFF;
  564 
  565         new->windrv_object = drv;
  566         new->windrv_devlist = NULL;
  567         new->windrv_regvals = NULL;
  568 
  569         mtx_lock(&drvdb_mtx);
  570         STAILQ_INSERT_HEAD(&drvdb_head, new, link);
  571         mtx_unlock(&drvdb_mtx);
  572 
  573         return (0);
  574 }
  575 
  576 #ifdef __amd64__
  577 
  578 extern void     x86_64_wrap(void);
  579 extern void     x86_64_wrap_call(void);
  580 extern void     x86_64_wrap_end(void);
  581 
  582 int
  583 windrv_wrap(func, wrap, argcnt, ftype)
  584         funcptr                 func;
  585         funcptr                 *wrap;
  586         int                     argcnt;
  587         int                     ftype;
  588 {
  589         funcptr                 p;
  590         vm_offset_t             *calladdr;
  591         vm_offset_t             wrapstart, wrapend, wrapcall;
  592 
  593         wrapstart = (vm_offset_t)&x86_64_wrap;
  594         wrapend = (vm_offset_t)&x86_64_wrap_end;
  595         wrapcall = (vm_offset_t)&x86_64_wrap_call;
  596 
  597         /* Allocate a new wrapper instance. */
  598 
  599         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  600         if (p == NULL)
  601                 return (ENOMEM);
  602 
  603         /* Copy over the code. */
  604 
  605         bcopy((char *)wrapstart, p, (wrapend - wrapstart));
  606 
  607         /* Insert the function address into the new wrapper instance. */
  608 
  609         calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
  610         *calladdr = (vm_offset_t)func;
  611 
  612         *wrap = p;
  613 
  614         return (0);
  615 }
  616 #endif /* __amd64__ */
  617 
  618 
  619 #ifdef __i386__
  620 
  621 struct x86desc {
  622         uint16_t                x_lolimit;
  623         uint16_t                x_base0;
  624         uint8_t                 x_base1;
  625         uint8_t                 x_flags;
  626         uint8_t                 x_hilimit;
  627         uint8_t                 x_base2;
  628 };
  629 
  630 struct gdt {
  631         uint16_t                limit;
  632         void                    *base;
  633 } __attribute__((__packed__));
  634 
  635 extern uint16_t x86_getfs(void);
  636 extern void x86_setfs(uint16_t);
  637 extern void *x86_gettid(void);
  638 extern void x86_critical_enter(void);
  639 extern void x86_critical_exit(void);
  640 extern void x86_getldt(struct gdt *, uint16_t *);
  641 extern void x86_setldt(struct gdt *, uint16_t);
  642 
  643 #define SEL_LDT 4               /* local descriptor table */
  644 #define SEL_TO_FS(x)            (((x) << 3))
  645 
  646 /*
  647  * FreeBSD 6.0 and later has a special GDT segment reserved
  648  * specifically for us, so if GNDIS_SEL is defined, use that.
  649  * If not, use GTGATE_SEL, which is uninitialized and infrequently
  650  * used.
  651  */
  652 
  653 #ifdef GNDIS_SEL
  654 #define FREEBSD_EMPTYSEL        GNDIS_SEL
  655 #else
  656 #define FREEBSD_EMPTYSEL        GTGATE_SEL      /* slot 7 */
  657 #endif
  658 
  659 /*
  660  * The meanings of various bits in a descriptor vary a little
  661  * depending on whether the descriptor will be used as a
  662  * code, data or system descriptor. (And that in turn depends
  663  * on which segment register selects the descriptor.)
  664  * We're only trying to create a data segment, so the definitions
  665  * below are the ones that apply to a data descriptor.
  666  */
  667 
  668 #define SEGFLAGLO_PRESENT       0x80    /* segment is present */
  669 #define SEGFLAGLO_PRIVLVL       0x60    /* privlevel needed for this seg */
  670 #define SEGFLAGLO_CD            0x10    /* 1 = code/data, 0 = system */
  671 #define SEGFLAGLO_MBZ           0x08    /* must be zero */
  672 #define SEGFLAGLO_EXPANDDOWN    0x04    /* limit expands down */
  673 #define SEGFLAGLO_WRITEABLE     0x02    /* segment is writeable */
  674 #define SEGGLAGLO_ACCESSED      0x01    /* segment has been accessed */
  675 
  676 #define SEGFLAGHI_GRAN          0x80    /* granularity, 1 = byte, 0 = page */
  677 #define SEGFLAGHI_BIG           0x40    /* 1 = 32 bit stack, 0 = 16 bit */
  678 
  679 /*
  680  * Context switch from UNIX to Windows. Save the existing value
  681  * of %fs for this processor, then change it to point to our
  682  * fake TID. Note that it is also possible to pin ourselves
  683  * to our current CPU, though I'm not sure this is really
  684  * necessary. It depends on whether or not an interrupt might
  685  * preempt us while Windows code is running and we wind up
  686  * scheduled onto another CPU as a result. So far, it doesn't
  687  * seem like this is what happens.
  688  */
  689 
  690 void
  691 ctxsw_utow(void)
  692 {
  693         struct tid              *t;
  694 
  695         t = &my_tids[curthread->td_oncpu];
  696 
  697         /*
  698          * Ugly hack. During system bootstrap (cold == 1), only CPU 0
  699          * is running. So if we were loaded at bootstrap, only CPU 0
  700          * will have our special GDT entry. This is a problem for SMP
  701          * systems, so to deal with this, we check here to make sure
  702          * the TID for this processor has been initialized, and if it
  703          * hasn't, we need to do it right now or else things will
  704          * explode.
  705          */
  706 
  707         if (t->tid_self != t)
  708                 x86_newldt(NULL);
  709 
  710         x86_critical_enter();
  711         t->tid_oldfs = x86_getfs();
  712         t->tid_cpu = curthread->td_oncpu;
  713         sched_pin();
  714         x86_setfs(SEL_TO_FS(t->tid_selector));
  715         x86_critical_exit();
  716 
  717         /* Now entering Windows land, population: you. */
  718 }
  719 
  720 /*
  721  * Context switch from Windows back to UNIX. Restore %fs to
  722  * its previous value. This always occurs after a call to
  723  * ctxsw_utow().
  724  */
  725 
  726 void
  727 ctxsw_wtou(void)
  728 {
  729         struct tid              *t;
  730 
  731         x86_critical_enter();
  732         t = x86_gettid();
  733         x86_setfs(t->tid_oldfs);
  734         sched_unpin();
  735         x86_critical_exit();
  736 
  737         /* Welcome back to UNIX land, we missed you. */
  738 
  739 #ifdef EXTRA_SANITY
  740         if (t->tid_cpu != curthread->td_oncpu)
  741                 panic("ctxsw GOT MOVED TO OTHER CPU!");
  742 #endif
  743 }
  744 
  745 static int      windrv_wrap_stdcall(funcptr, funcptr *, int);
  746 static int      windrv_wrap_fastcall(funcptr, funcptr *, int);
  747 static int      windrv_wrap_regparm(funcptr, funcptr *);
  748 
  749 extern void     x86_fastcall_wrap(void);
  750 extern void     x86_fastcall_wrap_call(void);
  751 extern void     x86_fastcall_wrap_arg(void);
  752 extern void     x86_fastcall_wrap_end(void);
  753 
  754 static int
  755 windrv_wrap_fastcall(func, wrap, argcnt)
  756         funcptr                 func;
  757         funcptr                 *wrap;
  758         int8_t                  argcnt;
  759 {
  760         funcptr                 p;
  761         vm_offset_t             *calladdr;
  762         uint8_t                 *argaddr;
  763         vm_offset_t             wrapstart, wrapend, wrapcall, wraparg;
  764 
  765         wrapstart = (vm_offset_t)&x86_fastcall_wrap;
  766         wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
  767         wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
  768         wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
  769 
  770         /* Allocate a new wrapper instance. */
  771 
  772         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  773         if (p == NULL)
  774                 return (ENOMEM);
  775 
  776         /* Copy over the code. */
  777 
  778         bcopy((char *)wrapstart, p, (wrapend - wrapstart));
  779 
  780         /* Insert the function address into the new wrapper instance. */
  781 
  782         calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
  783         *calladdr = (vm_offset_t)func;
  784 
  785         argcnt -= 2;
  786         if (argcnt < 1)
  787                 argcnt = 0;
  788 
  789         argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
  790         *argaddr = argcnt * sizeof(uint32_t);
  791 
  792         *wrap = p;
  793 
  794         return (0);
  795 }
  796 
  797 extern void     x86_stdcall_wrap(void);
  798 extern void     x86_stdcall_wrap_call(void);
  799 extern void     x86_stdcall_wrap_arg(void);
  800 extern void     x86_stdcall_wrap_end(void);
  801 
  802 static int
  803 windrv_wrap_stdcall(func, wrap, argcnt)
  804         funcptr                 func;
  805         funcptr                 *wrap;
  806         uint8_t                 argcnt;
  807 {
  808         funcptr                 p;
  809         vm_offset_t             *calladdr;
  810         uint8_t                 *argaddr;
  811         vm_offset_t             wrapstart, wrapend, wrapcall, wraparg;
  812 
  813         wrapstart = (vm_offset_t)&x86_stdcall_wrap;
  814         wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
  815         wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
  816         wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
  817 
  818         /* Allocate a new wrapper instance. */
  819 
  820         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  821         if (p == NULL)
  822                 return (ENOMEM);
  823 
  824         /* Copy over the code. */
  825 
  826         bcopy((char *)wrapstart, p, (wrapend - wrapstart));
  827 
  828         /* Insert the function address into the new wrapper instance. */
  829 
  830         calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
  831         *calladdr = (vm_offset_t)func;
  832 
  833         argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
  834         *argaddr = argcnt * sizeof(uint32_t);
  835 
  836         *wrap = p;
  837 
  838         return (0);
  839 }
  840 
  841 extern void     x86_regparm_wrap(void);
  842 extern void     x86_regparm_wrap_call(void);
  843 extern void     x86_regparm_wrap_end(void);
  844 
  845 static int
  846 windrv_wrap_regparm(func, wrap)
  847         funcptr                 func;
  848         funcptr                 *wrap;
  849 {
  850         funcptr                 p;
  851         vm_offset_t             *calladdr;
  852         vm_offset_t             wrapstart, wrapend, wrapcall;
  853 
  854         wrapstart = (vm_offset_t)&x86_regparm_wrap;
  855         wrapend = (vm_offset_t)&x86_regparm_wrap_end;
  856         wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
  857 
  858         /* Allocate a new wrapper instance. */
  859 
  860         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  861         if (p == NULL)
  862                 return (ENOMEM);
  863 
  864         /* Copy over the code. */
  865 
  866         bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
  867 
  868         /* Insert the function address into the new wrapper instance. */
  869 
  870         calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
  871         *calladdr = (vm_offset_t)func;
  872 
  873         *wrap = p;
  874 
  875         return (0);
  876 }
  877 
  878 int
  879 windrv_wrap(func, wrap, argcnt, ftype)
  880         funcptr                 func;
  881         funcptr                 *wrap;
  882         int                     argcnt;
  883         int                     ftype;
  884 {
  885         switch(ftype) {
  886         case WINDRV_WRAP_FASTCALL:
  887                 return (windrv_wrap_fastcall(func, wrap, argcnt));
  888         case WINDRV_WRAP_STDCALL:
  889                 return (windrv_wrap_stdcall(func, wrap, argcnt));
  890         case WINDRV_WRAP_REGPARM:
  891                 return (windrv_wrap_regparm(func, wrap));
  892         case WINDRV_WRAP_CDECL:
  893                 return (windrv_wrap_stdcall(func, wrap, 0));
  894         default:
  895                 break;
  896         }
  897 
  898         return (EINVAL);
  899 }
  900 
  901 static void
  902 x86_oldldt(dummy)
  903         void                    *dummy;
  904 {
  905         struct x86desc          *gdt;
  906         struct gdt              gtable;
  907         uint16_t                ltable;
  908 
  909         mtx_lock_spin(&dt_lock);
  910 
  911         /* Grab location of existing GDT. */
  912 
  913         x86_getldt(&gtable, &ltable);
  914 
  915         /* Find the slot we updated. */
  916 
  917         gdt = gtable.base;
  918         gdt += FREEBSD_EMPTYSEL;
  919 
  920         /* Empty it out. */
  921 
  922         bzero((char *)gdt, sizeof(struct x86desc));
  923 
  924         /* Restore GDT. */
  925 
  926         x86_setldt(&gtable, ltable);
  927 
  928         mtx_unlock_spin(&dt_lock);
  929 }
  930 
  931 static void
  932 x86_newldt(dummy)
  933         void                    *dummy;
  934 {
  935         struct gdt              gtable;
  936         uint16_t                ltable;
  937         struct x86desc          *l;
  938         struct thread           *t;
  939 
  940         t = curthread;
  941 
  942         mtx_lock_spin(&dt_lock);
  943 
  944         /* Grab location of existing GDT. */
  945 
  946         x86_getldt(&gtable, &ltable);
  947 
  948         /* Get pointer to the GDT table. */
  949 
  950         l = gtable.base;
  951 
  952         /* Get pointer to empty slot */
  953 
  954         l += FREEBSD_EMPTYSEL;
  955 
  956         /* Initialize TID for this CPU. */
  957 
  958         my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL;
  959         my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu];
  960 
  961         /* Set up new GDT entry. */
  962 
  963         l->x_lolimit = sizeof(struct tid);
  964         l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
  965         l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF;
  966         l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF;
  967         l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF;
  968         l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
  969 
  970         /* Update the GDT. */
  971 
  972         x86_setldt(&gtable, ltable);
  973 
  974         mtx_unlock_spin(&dt_lock);
  975 
  976         /* Whew. */
  977 }
  978 
  979 #endif /* __i386__ */
  980 
  981 int
  982 windrv_unwrap(func)
  983         funcptr                 func;
  984 {
  985         free(func, M_DEVBUF);
  986 
  987         return (0);
  988 }

Cache object: a8759c9be3596fc1ee789b99b43a454e


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