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                 return(ENOMEM);
  531 
  532         /*
  533          * Set up a fake image pointer to avoid false matches
  534          * in windrv_lookup().
  535          */
  536         drv->dro_driverstart = (void *)0xFFFFFFFF;
  537 
  538         new->windrv_object = drv;
  539         new->windrv_devlist = NULL;
  540         new->windrv_regvals = NULL;
  541 
  542         mtx_lock(&drvdb_mtx); 
  543         STAILQ_INSERT_HEAD(&drvdb_head, new, link);
  544         mtx_unlock(&drvdb_mtx);
  545 
  546         return(0);
  547 }
  548 
  549 #ifdef __amd64__
  550 
  551 extern void     x86_64_wrap(void);
  552 extern void     x86_64_wrap_call(void);
  553 extern void     x86_64_wrap_end(void);
  554 
  555 int
  556 windrv_wrap(func, wrap, argcnt, ftype)
  557         funcptr                 func;
  558         funcptr                 *wrap;
  559         int                     argcnt;
  560         int                     ftype;
  561 {
  562         funcptr                 p;
  563         vm_offset_t             *calladdr;
  564         vm_offset_t             wrapstart, wrapend, wrapcall;
  565 
  566         wrapstart = (vm_offset_t)&x86_64_wrap;
  567         wrapend = (vm_offset_t)&x86_64_wrap_end;
  568         wrapcall = (vm_offset_t)&x86_64_wrap_call;
  569 
  570         /* Allocate a new wrapper instance. */
  571 
  572         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  573         if (p == NULL)
  574                 return(ENOMEM);
  575 
  576         /* Copy over the code. */
  577 
  578         bcopy((char *)wrapstart, p, (wrapend - wrapstart));
  579 
  580         /* Insert the function address into the new wrapper instance. */
  581 
  582         calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
  583         *calladdr = (vm_offset_t)func;
  584 
  585         *wrap = p;
  586 
  587         return(0);
  588 }
  589 #endif /* __amd64__ */
  590 
  591 
  592 #ifdef __i386__
  593 
  594 struct x86desc {
  595         uint16_t                x_lolimit;
  596         uint16_t                x_base0;
  597         uint8_t                 x_base1;
  598         uint8_t                 x_flags;
  599         uint8_t                 x_hilimit;
  600         uint8_t                 x_base2;
  601 };
  602 
  603 struct gdt {
  604         uint16_t                limit;
  605         void                    *base;
  606 } __attribute__((__packed__));
  607 
  608 extern uint16_t x86_getfs(void);
  609 extern void x86_setfs(uint16_t);
  610 extern void *x86_gettid(void);
  611 extern void x86_critical_enter(void);
  612 extern void x86_critical_exit(void);
  613 extern void x86_getldt(struct gdt *, uint16_t *);
  614 extern void x86_setldt(struct gdt *, uint16_t);
  615 
  616 #define SEL_LDT 4               /* local descriptor table */
  617 #define SEL_TO_FS(x)            (((x) << 3))
  618 
  619 /*
  620  * FreeBSD 6.0 and later has a special GDT segment reserved
  621  * specifically for us, so if GNDIS_SEL is defined, use that.
  622  * If not, use GTGATE_SEL, which is uninitialized and infrequently
  623  * used.
  624  */
  625 
  626 #ifdef GNDIS_SEL
  627 #define FREEBSD_EMPTYSEL        GNDIS_SEL
  628 #else
  629 #define FREEBSD_EMPTYSEL        GTGATE_SEL      /* slot 7 */
  630 #endif
  631 
  632 /*
  633  * The meanings of various bits in a descriptor vary a little
  634  * depending on whether the descriptor will be used as a
  635  * code, data or system descriptor. (And that in turn depends
  636  * on which segment register selects the descriptor.)
  637  * We're only trying to create a data segment, so the definitions
  638  * below are the ones that apply to a data descriptor.
  639  */
  640 
  641 #define SEGFLAGLO_PRESENT       0x80    /* segment is present */
  642 #define SEGFLAGLO_PRIVLVL       0x60    /* privlevel needed for this seg */
  643 #define SEGFLAGLO_CD            0x10    /* 1 = code/data, 0 = system */
  644 #define SEGFLAGLO_MBZ           0x08    /* must be zero */
  645 #define SEGFLAGLO_EXPANDDOWN    0x04    /* limit expands down */
  646 #define SEGFLAGLO_WRITEABLE     0x02    /* segment is writeable */
  647 #define SEGGLAGLO_ACCESSED      0x01    /* segment has been accessed */
  648 
  649 #define SEGFLAGHI_GRAN          0x80    /* granularity, 1 = byte, 0 = page */
  650 #define SEGFLAGHI_BIG           0x40    /* 1 = 32 bit stack, 0 = 16 bit */
  651 
  652 /*
  653  * Context switch from UNIX to Windows. Save the existing value
  654  * of %fs for this processor, then change it to point to our
  655  * fake TID. Note that it is also possible to pin ourselves
  656  * to our current CPU, though I'm not sure this is really
  657  * necessary. It depends on whether or not an interrupt might
  658  * preempt us while Windows code is running and we wind up
  659  * scheduled onto another CPU as a result. So far, it doesn't
  660  * seem like this is what happens.
  661  */
  662 
  663 void
  664 ctxsw_utow(void)
  665 {
  666         struct tid              *t;
  667 
  668         t = &my_tids[curthread->td_oncpu];
  669 
  670         /*
  671          * Ugly hack. During system bootstrap (cold == 1), only CPU 0
  672          * is running. So if we were loaded at bootstrap, only CPU 0
  673          * will have our special GDT entry. This is a problem for SMP
  674          * systems, so to deal with this, we check here to make sure
  675          * the TID for this processor has been initialized, and if it
  676          * hasn't, we need to do it right now or else things will
  677          * explode.
  678          */
  679 
  680         if (t->tid_self != t)
  681                 x86_newldt(NULL);
  682 
  683         x86_critical_enter();
  684         t->tid_oldfs = x86_getfs();
  685         t->tid_cpu = curthread->td_oncpu;
  686         sched_pin();
  687         x86_setfs(SEL_TO_FS(t->tid_selector));
  688         x86_critical_exit();
  689 
  690         /* Now entering Windows land, population: you. */
  691 
  692         return;
  693 }
  694 
  695 /*
  696  * Context switch from Windows back to UNIX. Restore %fs to
  697  * its previous value. This always occurs after a call to
  698  * ctxsw_utow().
  699  */
  700 
  701 void
  702 ctxsw_wtou(void)
  703 {
  704         struct tid              *t;
  705 
  706         x86_critical_enter();
  707         t = x86_gettid();
  708         x86_setfs(t->tid_oldfs);
  709         sched_unpin();
  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_oncpu)
  716                 panic("ctxsw GOT MOVED TO OTHER CPU!");
  717 #endif
  718         return;
  719 }
  720 
  721 static int      windrv_wrap_stdcall(funcptr, funcptr *, int);
  722 static int      windrv_wrap_fastcall(funcptr, funcptr *, int);
  723 static int      windrv_wrap_regparm(funcptr, funcptr *);
  724 
  725 extern void     x86_fastcall_wrap(void);
  726 extern void     x86_fastcall_wrap_call(void);
  727 extern void     x86_fastcall_wrap_arg(void);
  728 extern void     x86_fastcall_wrap_end(void);
  729 
  730 static int
  731 windrv_wrap_fastcall(func, wrap, argcnt)
  732         funcptr                 func;
  733         funcptr                 *wrap;
  734         int8_t                  argcnt;
  735 {
  736         funcptr                 p;
  737         vm_offset_t             *calladdr;
  738         uint8_t                 *argaddr;
  739         vm_offset_t             wrapstart, wrapend, wrapcall, wraparg;
  740 
  741         wrapstart = (vm_offset_t)&x86_fastcall_wrap;
  742         wrapend = (vm_offset_t)&x86_fastcall_wrap_end;
  743         wrapcall = (vm_offset_t)&x86_fastcall_wrap_call;
  744         wraparg = (vm_offset_t)&x86_fastcall_wrap_arg;
  745 
  746         /* Allocate a new wrapper instance. */
  747 
  748         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  749         if (p == NULL)
  750                 return(ENOMEM);
  751 
  752         /* Copy over the code. */
  753 
  754         bcopy((char *)wrapstart, p, (wrapend - wrapstart));
  755 
  756         /* Insert the function address into the new wrapper instance. */
  757 
  758         calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
  759         *calladdr = (vm_offset_t)func;
  760 
  761         argcnt -= 2;
  762         if (argcnt < 1)
  763                 argcnt = 0;
  764 
  765         argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
  766         *argaddr = argcnt * sizeof(uint32_t);
  767 
  768         *wrap = p;
  769 
  770         return(0);
  771 }
  772 
  773 extern void     x86_stdcall_wrap(void);
  774 extern void     x86_stdcall_wrap_call(void);
  775 extern void     x86_stdcall_wrap_arg(void);
  776 extern void     x86_stdcall_wrap_end(void);
  777 
  778 static int
  779 windrv_wrap_stdcall(func, wrap, argcnt)
  780         funcptr                 func;
  781         funcptr                 *wrap;
  782         uint8_t                 argcnt;
  783 {
  784         funcptr                 p;
  785         vm_offset_t             *calladdr;
  786         uint8_t                 *argaddr;
  787         vm_offset_t             wrapstart, wrapend, wrapcall, wraparg;
  788 
  789         wrapstart = (vm_offset_t)&x86_stdcall_wrap;
  790         wrapend = (vm_offset_t)&x86_stdcall_wrap_end;
  791         wrapcall = (vm_offset_t)&x86_stdcall_wrap_call;
  792         wraparg = (vm_offset_t)&x86_stdcall_wrap_arg;
  793 
  794         /* Allocate a new wrapper instance. */
  795 
  796         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  797         if (p == NULL)
  798                 return(ENOMEM);
  799 
  800         /* Copy over the code. */
  801 
  802         bcopy((char *)wrapstart, p, (wrapend - wrapstart));
  803 
  804         /* Insert the function address into the new wrapper instance. */
  805 
  806         calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
  807         *calladdr = (vm_offset_t)func;
  808 
  809         argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1));
  810         *argaddr = argcnt * sizeof(uint32_t);
  811 
  812         *wrap = p;
  813 
  814         return(0);
  815 }
  816 
  817 extern void     x86_regparm_wrap(void);
  818 extern void     x86_regparm_wrap_call(void);
  819 extern void     x86_regparm_wrap_end(void);
  820 
  821 static int
  822 windrv_wrap_regparm(func, wrap)
  823         funcptr                 func;
  824         funcptr                 *wrap;
  825 {
  826         funcptr                 p;
  827         vm_offset_t             *calladdr;
  828         vm_offset_t             wrapstart, wrapend, wrapcall;
  829 
  830         wrapstart = (vm_offset_t)&x86_regparm_wrap;
  831         wrapend = (vm_offset_t)&x86_regparm_wrap_end;
  832         wrapcall = (vm_offset_t)&x86_regparm_wrap_call;
  833 
  834         /* Allocate a new wrapper instance. */
  835 
  836         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  837         if (p == NULL)
  838                 return(ENOMEM);
  839 
  840         /* Copy over the code. */
  841 
  842         bcopy(x86_regparm_wrap, p, (wrapend - wrapstart));
  843 
  844         /* Insert the function address into the new wrapper instance. */
  845 
  846         calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1));
  847         *calladdr = (vm_offset_t)func;
  848 
  849         *wrap = p;
  850 
  851         return(0);
  852 }
  853 
  854 int
  855 windrv_wrap(func, wrap, argcnt, ftype)
  856         funcptr                 func;
  857         funcptr                 *wrap;
  858         int                     argcnt;
  859         int                     ftype;
  860 {
  861         switch(ftype) {
  862         case WINDRV_WRAP_FASTCALL:
  863                 return(windrv_wrap_fastcall(func, wrap, argcnt));
  864         case WINDRV_WRAP_STDCALL:
  865                 return(windrv_wrap_stdcall(func, wrap, argcnt));
  866         case WINDRV_WRAP_REGPARM:
  867                 return(windrv_wrap_regparm(func, wrap));
  868         case WINDRV_WRAP_CDECL:
  869                 return(windrv_wrap_stdcall(func, wrap, 0));
  870         default:
  871                 break;
  872         }
  873 
  874         return(EINVAL);
  875 }
  876 
  877 static void
  878 x86_oldldt(dummy)
  879         void                    *dummy;
  880 {
  881         struct thread           *t;
  882         struct x86desc          *gdt;
  883         struct gdt              gtable;
  884         uint16_t                ltable;
  885 
  886         mtx_lock_spin(&sched_lock);
  887 
  888         t = curthread;
  889 
  890         /* Grab location of existing GDT. */
  891 
  892         x86_getldt(&gtable, &ltable);
  893 
  894         /* Find the slot we updated. */
  895 
  896         gdt = gtable.base;
  897         gdt += FREEBSD_EMPTYSEL;
  898 
  899         /* Empty it out. */
  900 
  901         bzero((char *)gdt, sizeof(struct x86desc));
  902 
  903         /* Restore GDT. */
  904 
  905         x86_setldt(&gtable, ltable);
  906 
  907         mtx_unlock_spin(&sched_lock);
  908 
  909         return;
  910 }
  911 
  912 static void
  913 x86_newldt(dummy)
  914         void                    *dummy;
  915 {
  916         struct gdt              gtable;
  917         uint16_t                ltable;
  918         struct x86desc          *l;
  919         struct thread           *t;
  920 
  921         mtx_lock_spin(&sched_lock);
  922 
  923         t = curthread;
  924 
  925         /* Grab location of existing GDT. */
  926 
  927         x86_getldt(&gtable, &ltable);
  928 
  929         /* Get pointer to the GDT table. */
  930 
  931         l = gtable.base;
  932 
  933         /* Get pointer to empty slot */
  934 
  935         l += FREEBSD_EMPTYSEL;
  936 
  937         /* Initialize TID for this CPU. */
  938 
  939         my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL;
  940         my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu];
  941 
  942         /* Set up new GDT entry. */
  943 
  944         l->x_lolimit = sizeof(struct tid);
  945         l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG;
  946         l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF;
  947         l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF;
  948         l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF;
  949         l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE;
  950 
  951         /* Update the GDT. */
  952 
  953         x86_setldt(&gtable, ltable);
  954 
  955         mtx_unlock_spin(&sched_lock);
  956 
  957         /* Whew. */
  958 
  959         return;
  960 }
  961 
  962 #endif /* __i386__ */
  963 
  964 int
  965 windrv_unwrap(func)
  966         funcptr                 func;
  967 {
  968         free(func, M_DEVBUF);
  969 
  970         return(0);
  971 }

Cache object: c00c6dc1b14caadd15a9ab294d921daa


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