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 #ifdef __FreeBSD__
   35 __FBSDID("$FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.3.2.2 2005/03/31 04:24:35 wpaul Exp $");
   36 #endif
   37 #ifdef __NetBSD__
   38 __KERNEL_RCSID(0, "$NetBSD: kern_windrv.c,v 1.5 2006/11/16 01:32:44 christos Exp $");
   39 #endif
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/unistd.h>
   44 #include <sys/types.h>
   45 
   46 #include <sys/kernel.h>
   47 #include <sys/malloc.h>
   48 #include <sys/lock.h>
   49 #ifdef __FreeBSD__
   50 #include <sys/mutex.h>
   51 #include <sys/module.h>
   52 #endif /* __FreeBSD__ */
   53 #include <sys/conf.h>
   54 #include <sys/mbuf.h>
   55 #ifdef __FreeBSD__
   56 #include <sys/bus.h>
   57 #endif
   58 
   59 #include <sys/queue.h>
   60 
   61 #include <compat/ndis/pe_var.h>
   62 #include <compat/ndis/cfg_var.h>
   63 #include <compat/ndis/resource_var.h>
   64 #include <compat/ndis/ntoskrnl_var.h>
   65 #include <compat/ndis/ndis_var.h>
   66 #include <compat/ndis/hal_var.h>
   67 #include <compat/ndis/usbd_var.h>
   68 
   69 struct windrv_type {
   70         uint16_t                windrv_vid;     /* for PCI or USB */
   71         uint16_t                windrv_did;     /* for PCI or USB */
   72         uint32_t                windrv_subsys;  /* for PCI */
   73         char                    *windrv_vname;  /* for pccard */
   74         char                    *windrv_dname;  /* for pccard */
   75         char                    *windrv_name;   /* for pccard, PCI or USB */
   76 };
   77 
   78 struct drvdb_ent {
   79         driver_object           *windrv_object;
   80         struct windrv_type      *windrv_devlist;
   81         ndis_cfg                *windrv_regvals;
   82         STAILQ_ENTRY(drvdb_ent) link;
   83 };
   84 
   85 struct mtx drvdb_mtx;
   86 static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head;
   87 
   88 static driver_object    fake_pci_driver; /* serves both PCI and cardbus */
   89 static driver_object    fake_pccard_driver;
   90 
   91 
   92 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
   93 
   94 int
   95 windrv_libinit(void)
   96 {
   97         STAILQ_INIT(&drvdb_head);
   98         mtx_init(&drvdb_mtx, "Windows driver DB lock",
   99            "Windows internal lock", MTX_DEF);
  100 
  101         /*
  102          * PCI and pccard devices don't need to use IRPs to
  103          * interact with their bus drivers (usually), so our
  104          * emulated PCI and pccard drivers are just stubs.
  105          * USB devices, on the other hand, do all their I/O
  106          * by exchanging IRPs with the USB bus driver, so
  107          * for that we need to provide emulator dispatcher
  108          * routines, which are in a separate module.
  109          */
  110 
  111         windrv_bus_attach(&fake_pci_driver, "PCI Bus");
  112         windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus");
  113 
  114         return(0);
  115 }
  116 
  117 int
  118 windrv_libfini(void)
  119 {
  120         struct drvdb_ent        *d;
  121 
  122         mtx_lock(&drvdb_mtx); 
  123         while(STAILQ_FIRST(&drvdb_head) != NULL) {
  124                 d = STAILQ_FIRST(&drvdb_head);
  125                 STAILQ_REMOVE_HEAD(&drvdb_head, link);
  126                 free(d, M_DEVBUF);
  127         }
  128         mtx_unlock(&drvdb_mtx);
  129 
  130         free(fake_pci_driver.dro_drivername.us_buf, M_DEVBUF);
  131         free(fake_pccard_driver.dro_drivername.us_buf, M_DEVBUF);
  132 
  133         mtx_destroy(&drvdb_mtx);
  134         return(0);
  135 }
  136 
  137 /*
  138  * Given the address of a driver image, find its corresponding
  139  * driver_object.
  140  */
  141 
  142 driver_object *
  143 windrv_lookup(img, name)
  144         vm_offset_t             img;
  145         const char              *name;
  146 {
  147         struct drvdb_ent        *d;
  148         unicode_string          us;
  149 
  150         printf("In windrv_lookup():\n");
  151         printf("name = %s\n", name);
  152         
  153         /* Damn unicode. */
  154 
  155         if (name != NULL) {
  156                 us.us_len = strlen(name) * 2;
  157                 us.us_maxlen = strlen(name) * 2;
  158                 us.us_buf = NULL;
  159                 ndis_ascii_to_unicode(name, &us.us_buf);
  160         } else {
  161                 us.us_len = 0;
  162                 us.us_maxlen = 0;
  163                 us.us_buf = NULL;
  164         }
  165 
  166         mtx_lock(&drvdb_mtx); 
  167         STAILQ_FOREACH(d, &drvdb_head, link) {
  168 #ifdef NDIS_DBG         
  169                 printf("d->windrv_object->dro_driverstart = %x\n", d->windrv_object->dro_driverstart);
  170 #endif          
  171                 if (d->windrv_object->dro_driverstart == (void *)img || 
  172                     (bcmp((char *)d->windrv_object->dro_drivername.us_buf,
  173                          (char *)us.us_buf, us.us_len) == 0 && us.us_len > 0)) {                
  174                         mtx_unlock(&drvdb_mtx);         
  175                         printf("found driver object!\n");
  176 #ifdef NDIS_DBG
  177                         printf("returning %x\n", d->windrv_object);
  178 #endif                          
  179                         return(d->windrv_object);
  180                 }
  181         }
  182         mtx_unlock(&drvdb_mtx);
  183 
  184         if (name != NULL)
  185                 ExFreePool(us.us_buf);
  186 
  187         printf("no driver object\n");
  188         return(NULL);
  189 }
  190 
  191 /*
  192  * Remove a driver_object from our datatabase and destroy it. Throw
  193  * away any custom driver extension info that may have been added.
  194  */
  195 
  196 int
  197 windrv_unload(module_t mod, vm_offset_t img, int len)
  198 {
  199         struct drvdb_ent        *d, *r = NULL;
  200         driver_object           *drv;
  201         list_entry              *e, *c;
  202 
  203         mtx_lock(&drvdb_mtx); 
  204         STAILQ_FOREACH(d, &drvdb_head, link) {
  205                 if (d->windrv_object->dro_driverstart == (void *)img) {
  206                         r = d;
  207                         STAILQ_REMOVE(&drvdb_head, d, drvdb_ent, link);
  208                         break;
  209                 }
  210         }
  211         mtx_unlock(&drvdb_mtx);
  212 
  213         if (r == NULL)
  214                 return (ENOENT);
  215 
  216         /*
  217          * Destroy any custom extensions that may have been added.
  218          */
  219         drv = r->windrv_object;
  220         e = drv->dro_driverext->dre_usrext.nle_flink;
  221         while (e != &drv->dro_driverext->dre_usrext) {
  222                 c = e->nle_flink;
  223                 REMOVE_LIST_ENTRY(e);
  224                 ExFreePool(e);
  225                 e = c;
  226         }
  227 
  228         /* Free the driver extension */
  229         free(drv->dro_driverext, M_DEVBUF);
  230 
  231         /* Free the driver name */
  232         free(drv->dro_drivername.us_buf, M_DEVBUF);
  233 
  234         /* Free driver object */
  235         free(drv, M_DEVBUF);
  236 
  237         /* Free our DB handle */
  238         free(r, M_DEVBUF);
  239 
  240         return(0);
  241 }
  242 
  243 /*
  244  * Loader routine for actual Windows driver modules, ultimately
  245  * calls the driver's DriverEntry() routine.
  246  */
  247 
  248 int
  249 windrv_load(module_t mod, vm_offset_t img, int len)
  250 {
  251         image_import_descriptor imp_desc;
  252         image_optional_header   opt_hdr;
  253         driver_entry            entry;
  254         struct drvdb_ent        *new;
  255         struct driver_object    *drv;
  256         int                     status;
  257 
  258 #ifdef NDIS_DBG
  259         printf("in windrv_load\n");
  260         printf("img = %x\n", img);
  261 #endif  
  262 
  263         /*
  264          * First step: try to relocate and dynalink the executable
  265          * driver image.
  266          */
  267 
  268         /* Perform text relocation */
  269         if (pe_relocate(img)) {
  270                 return(ENOEXEC);
  271         }
  272 
  273         /* Dynamically link the NDIS.SYS routines -- required. */
  274         if (pe_patch_imports(img, "NDIS", ndis_functbl)) {
  275                 return(ENOEXEC);
  276         }
  277 
  278         /* Dynamically link the HAL.dll routines -- also required. */
  279         if (pe_patch_imports(img, "HAL", hal_functbl)) {                
  280                 return(ENOEXEC);
  281         }
  282 
  283         /* Dynamically link ntoskrnl.exe -- optional. */
  284         if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
  285                 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))        
  286                         return(ENOEXEC);
  287         }
  288 
  289         /* Dynamically link USBD.SYS -- optional */
  290         if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) {
  291 #if ubsimplemented
  292                 if (pe_patch_imports(img, "USBD", usbd_functbl)) {      
  293                         return(ENOEXEC);
  294                 }
  295 #else
  296             //printf("windrv_load: pe_get_import_descriptor USBD failed");      
  297             return(ENOEXEC);
  298 #endif
  299         }       
  300 
  301         /* Next step: find the driver entry point. */
  302 
  303         pe_get_optional_header(img, &opt_hdr);
  304         entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
  305 
  306         /* Next step: allocate and store a driver object. */
  307 
  308         new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT);
  309         if (new == NULL)
  310                 return (ENOMEM);
  311 
  312         drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO);
  313         if (drv == NULL) {
  314                 free (new, M_DEVBUF);
  315                 return (ENOMEM);
  316         }
  317 
  318         /* Allocate a driver extension structure too. */
  319 
  320         drv->dro_driverext = malloc(sizeof(driver_extension),
  321             M_DEVBUF, M_NOWAIT|M_ZERO);
  322 
  323         if (drv->dro_driverext == NULL) {
  324                 free(new, M_DEVBUF);
  325                 free(drv, M_DEVBUF);
  326                 return(ENOMEM);
  327         }
  328 
  329         INIT_LIST_HEAD((&drv->dro_driverext->dre_usrext));
  330 
  331         drv->dro_driverstart = (void *)img;
  332         drv->dro_driversize = len;
  333 
  334         drv->dro_drivername.us_len = strlen(DUMMY_REGISTRY_PATH) * 2;
  335         drv->dro_drivername.us_maxlen = strlen(DUMMY_REGISTRY_PATH) * 2;
  336         drv->dro_drivername.us_buf = NULL;
  337         ndis_ascii_to_unicode(DUMMY_REGISTRY_PATH,
  338             &drv->dro_drivername.us_buf);
  339 
  340         new->windrv_object = drv;
  341 
  342         /* Now call the DriverEntry() function. */
  343 
  344         status = MSCALL2(entry, drv, &drv->dro_drivername);
  345 
  346         if (status != STATUS_SUCCESS) {
  347                 free(drv->dro_drivername.us_buf, M_DEVBUF);
  348                 free(drv, M_DEVBUF);
  349                 free(new, M_DEVBUF);
  350                 return(ENODEV);
  351         }
  352 
  353         mtx_lock(&drvdb_mtx); 
  354         STAILQ_INSERT_HEAD(&drvdb_head, new, link);
  355         mtx_unlock(&drvdb_mtx); 
  356 
  357         return (0);
  358 }
  359 
  360 /*
  361  * Make a new Physical Device Object for a device that was
  362  * detected/plugged in. For us, the PDO is just a way to
  363  * get at the device_t.
  364  */
  365 
  366 int
  367 windrv_create_pdo(drv, bsddev)
  368         driver_object           *drv;
  369         device_t                bsddev;
  370 {
  371         device_object           *dev;
  372 
  373         /*
  374          * This is a new physical device object, which technically
  375          * is the "top of the stack." Consequently, we don't do
  376          * an IoAttachDeviceToDeviceStack() here.
  377          */
  378 
  379         mtx_lock(&drvdb_mtx);
  380         IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
  381         mtx_unlock(&drvdb_mtx);
  382 
  383         /* Stash pointer to our BSD device handle. */
  384 
  385         dev->do_devext = bsddev;
  386 
  387         return(STATUS_SUCCESS);
  388 }
  389 
  390 void
  391 windrv_destroy_pdo(drv, bsddev)
  392         driver_object           *drv;
  393         device_t                bsddev;
  394 {
  395         device_object           *pdo;
  396 
  397         pdo = windrv_find_pdo(drv, bsddev);
  398 
  399         /* Remove reference to device_t */
  400 
  401         pdo->do_devext = NULL;
  402 
  403         mtx_lock(&drvdb_mtx);
  404         IoDeleteDevice(pdo);
  405         mtx_unlock(&drvdb_mtx);
  406 
  407         return;
  408 }
  409 
  410 /*
  411  * Given a device_t, find the corresponding PDO in a driver's
  412  * device list.
  413  */
  414 
  415 device_object *
  416 windrv_find_pdo(drv, bsddev)
  417         driver_object           *drv;
  418         device_t                bsddev;
  419 {
  420         device_object           *pdo;
  421 #ifdef NDIS_DBG
  422         printf("In windrv_find_pdo: \ndrv = %x", drv);
  423         printf("\nbsddev = %x", bsddev);
  424         printf("\npdo = %x", drv->dro_devobj);
  425         printf("\npdo->do_devext = %x\n", drv->dro_devobj->do_devext);
  426 #endif
  427         mtx_lock(&drvdb_mtx);
  428         pdo = drv->dro_devobj;
  429         if (pdo->do_devext != bsddev) {
  430                 mtx_unlock(&drvdb_mtx);
  431                 panic("PDO wasn't first device in list");
  432         }
  433         mtx_unlock(&drvdb_mtx);
  434 
  435         return(pdo);
  436 }
  437 
  438 /*
  439  * Add an internally emulated driver to the database. We need this
  440  * to set up an emulated bus driver so that it can receive IRPs.
  441  */
  442 
  443 int
  444 windrv_bus_attach(drv, name)
  445         driver_object           *drv;
  446         const char                      *name;
  447 {
  448         struct drvdb_ent        *new;
  449 
  450         new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT);
  451         if (new == NULL)
  452                 return (ENOMEM);
  453 
  454         drv->dro_drivername.us_len = strlen(name) * 2;
  455         drv->dro_drivername.us_maxlen = strlen(name) * 2;
  456         drv->dro_drivername.us_buf = NULL;
  457         ndis_ascii_to_unicode(name, &drv->dro_drivername.us_buf);
  458                 
  459 #ifdef __NetBSD__
  460 /* I added this because windrv_lookup was getting 
  461  * fake_pccard_driver and fake_pci_driver mixed up.
  462  * I'm not sure if it will mess anything else up.
  463  */
  464         drv->dro_driverstart = drv;
  465 #endif          
  466 
  467         new->windrv_object = drv;
  468         new->windrv_devlist = NULL;
  469         new->windrv_regvals = NULL;
  470 
  471         mtx_lock(&drvdb_mtx); 
  472         STAILQ_INSERT_HEAD(&drvdb_head, new, link);
  473         mtx_unlock(&drvdb_mtx);
  474 
  475         return(0);
  476 }
  477 
  478 #ifdef __amd64__
  479 
  480 extern void     x86_64_wrap(void);
  481 extern void     x86_64_wrap_call(void);
  482 extern void     x86_64_wrap_end(void);
  483 
  484 #endif /* __amd64__ */
  485 
  486 int
  487 windrv_wrap(func, wrap)
  488         funcptr                 func;
  489         funcptr                 *wrap;
  490 {
  491 #ifdef __amd64__
  492         funcptr                 p;
  493         vm_offset_t             *calladdr;
  494         vm_offset_t             wrapstart, wrapend, wrapcall;
  495 
  496         wrapstart = (vm_offset_t)&x86_64_wrap;
  497         wrapend = (vm_offset_t)&x86_64_wrap_end;
  498         wrapcall = (vm_offset_t)&x86_64_wrap_call;
  499 
  500         /* Allocate a new wrapper instance. */
  501 
  502         p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT);
  503         if (p == NULL)
  504                 return(ENOMEM);
  505 
  506         /* Copy over the code. */
  507 
  508         bcopy((char *)wrapstart, p, (wrapend - wrapstart));
  509 
  510         /* Insert the function address into the new wrapper instance. */
  511 
  512         calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2);
  513         *calladdr = (vm_offset_t)func;
  514 
  515         *wrap = p;
  516 #else /* __amd64__ */
  517         *wrap = func;
  518 #endif /* __amd64__ */
  519         return(0);
  520 }
  521 
  522 int
  523 windrv_unwrap(funcptr func)
  524 {
  525 #ifdef __amd64__
  526         free(func, M_DEVBUF);
  527 #endif /* __amd64__ */
  528         return(0);
  529 }

Cache object: 090cae3acb8795e1d1cbe4a56d458897


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