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

Cache object: 03a142ee415abc6cbb1b7a006fdb04d4


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