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/emulation/ndis/kern_windrv.c

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

Cache object: 979aa64c76a17ce4539cf7722267a376


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