3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.3.2.2 2005/03/31 04:24:35 wpaul Exp $");
38 __KERNEL_RCSID(0, "$NetBSD: kern_windrv.c,v 1.7 2009/03/18 15:14:30 cegger Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/unistd.h>
44 #include <sys/types.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
50 #include <sys/mutex.h>
51 #include <sys/module.h>
52 #endif /* __FreeBSD__ */
59 #include <sys/queue.h>
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>
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 */
79 driver_object
*windrv_object
;
80 struct windrv_type
*windrv_devlist
;
81 ndis_cfg
*windrv_regvals
;
82 STAILQ_ENTRY(drvdb_ent
) link
;
86 static STAILQ_HEAD(drvdb
, drvdb_ent
) drvdb_head
;
88 static driver_object fake_pci_driver
; /* serves both PCI and cardbus */
89 static driver_object fake_pccard_driver
;
92 #define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path"
97 STAILQ_INIT(&drvdb_head
);
98 mtx_init(&drvdb_mtx
, "Windows driver DB lock",
99 "Windows internal lock", MTX_DEF
);
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.
111 windrv_bus_attach(&fake_pci_driver
, "PCI Bus");
112 windrv_bus_attach(&fake_pccard_driver
, "PCCARD Bus");
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
);
128 mtx_unlock(&drvdb_mtx
);
130 free(fake_pci_driver
.dro_drivername
.us_buf
, M_DEVBUF
);
131 free(fake_pccard_driver
.dro_drivername
.us_buf
, M_DEVBUF
);
133 mtx_destroy(&drvdb_mtx
);
138 * Given the address of a driver image, find its corresponding
143 windrv_lookup(vm_offset_t img
, const char *name
)
148 printf("In windrv_lookup():\n");
149 printf("name = %s\n", name
);
154 us
.us_len
= strlen(name
) * 2;
155 us
.us_maxlen
= strlen(name
) * 2;
157 ndis_ascii_to_unicode(name
, &us
.us_buf
);
164 mtx_lock(&drvdb_mtx
);
165 STAILQ_FOREACH(d
, &drvdb_head
, link
) {
167 printf("d->windrv_object->dro_driverstart = %x\n", d
->windrv_object
->dro_driverstart
);
169 if (d
->windrv_object
->dro_driverstart
== (void *)img
||
170 (memcmp((char *)d
->windrv_object
->dro_drivername
.us_buf
,
171 (char *)us
.us_buf
, us
.us_len
) == 0 && us
.us_len
> 0)) {
172 mtx_unlock(&drvdb_mtx
);
173 printf("found driver object!\n");
175 printf("returning %x\n", d
->windrv_object
);
177 return(d
->windrv_object
);
180 mtx_unlock(&drvdb_mtx
);
183 ExFreePool(us
.us_buf
);
185 printf("no driver object\n");
190 * Remove a driver_object from our datatabase and destroy it. Throw
191 * away any custom driver extension info that may have been added.
195 windrv_unload(module_t mod
, vm_offset_t img
, int len
)
197 struct drvdb_ent
*d
, *r
= NULL
;
201 mtx_lock(&drvdb_mtx
);
202 STAILQ_FOREACH(d
, &drvdb_head
, link
) {
203 if (d
->windrv_object
->dro_driverstart
== (void *)img
) {
205 STAILQ_REMOVE(&drvdb_head
, d
, drvdb_ent
, link
);
209 mtx_unlock(&drvdb_mtx
);
215 * Destroy any custom extensions that may have been added.
217 drv
= r
->windrv_object
;
218 e
= drv
->dro_driverext
->dre_usrext
.nle_flink
;
219 while (e
!= &drv
->dro_driverext
->dre_usrext
) {
221 REMOVE_LIST_ENTRY(e
);
226 /* Free the driver extension */
227 free(drv
->dro_driverext
, M_DEVBUF
);
229 /* Free the driver name */
230 free(drv
->dro_drivername
.us_buf
, M_DEVBUF
);
232 /* Free driver object */
235 /* Free our DB handle */
242 * Loader routine for actual Windows driver modules, ultimately
243 * calls the driver's DriverEntry() routine.
247 windrv_load(module_t mod
, vm_offset_t img
, int len
)
249 image_import_descriptor imp_desc
;
250 image_optional_header opt_hdr
;
252 struct drvdb_ent
*new;
253 struct driver_object
*drv
;
257 printf("in windrv_load\n");
258 printf("img = %x\n", img
);
262 * First step: try to relocate and dynalink the executable
266 /* Perform text relocation */
267 if (pe_relocate(img
)) {
271 /* Dynamically link the NDIS.SYS routines -- required. */
272 if (pe_patch_imports(img
, "NDIS", ndis_functbl
)) {
276 /* Dynamically link the HAL.dll routines -- also required. */
277 if (pe_patch_imports(img
, "HAL", hal_functbl
)) {
281 /* Dynamically link ntoskrnl.exe -- optional. */
282 if (pe_get_import_descriptor(img
, &imp_desc
, "ntoskrnl") == 0) {
283 if (pe_patch_imports(img
, "ntoskrnl", ntoskrnl_functbl
))
287 /* Dynamically link USBD.SYS -- optional */
288 if (pe_get_import_descriptor(img
, &imp_desc
, "USBD") == 0) {
290 if (pe_patch_imports(img
, "USBD", usbd_functbl
)) {
294 //printf("windrv_load: pe_get_import_descriptor USBD failed");
299 /* Next step: find the driver entry point. */
301 pe_get_optional_header(img
, &opt_hdr
);
302 entry
= (driver_entry
)pe_translate_addr(img
, opt_hdr
.ioh_entryaddr
);
304 /* Next step: allocate and store a driver object. */
306 new = malloc(sizeof(struct drvdb_ent
), M_DEVBUF
, M_NOWAIT
);
310 drv
= malloc(sizeof(driver_object
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
312 free (new, M_DEVBUF
);
316 /* Allocate a driver extension structure too. */
318 drv
->dro_driverext
= malloc(sizeof(driver_extension
),
319 M_DEVBUF
, M_NOWAIT
|M_ZERO
);
321 if (drv
->dro_driverext
== NULL
) {
327 INIT_LIST_HEAD((&drv
->dro_driverext
->dre_usrext
));
329 drv
->dro_driverstart
= (void *)img
;
330 drv
->dro_driversize
= len
;
332 drv
->dro_drivername
.us_len
= strlen(DUMMY_REGISTRY_PATH
) * 2;
333 drv
->dro_drivername
.us_maxlen
= strlen(DUMMY_REGISTRY_PATH
) * 2;
334 drv
->dro_drivername
.us_buf
= NULL
;
335 ndis_ascii_to_unicode(DUMMY_REGISTRY_PATH
,
336 &drv
->dro_drivername
.us_buf
);
338 new->windrv_object
= drv
;
340 /* Now call the DriverEntry() function. */
342 status
= MSCALL2(entry
, drv
, &drv
->dro_drivername
);
344 if (status
!= STATUS_SUCCESS
) {
345 free(drv
->dro_drivername
.us_buf
, M_DEVBUF
);
351 mtx_lock(&drvdb_mtx
);
352 STAILQ_INSERT_HEAD(&drvdb_head
, new, link
);
353 mtx_unlock(&drvdb_mtx
);
359 * Make a new Physical Device Object for a device that was
360 * detected/plugged in. For us, the PDO is just a way to
361 * get at the device_t.
365 windrv_create_pdo(driver_object
*drv
, device_t bsddev
)
370 * This is a new physical device object, which technically
371 * is the "top of the stack." Consequently, we don't do
372 * an IoAttachDeviceToDeviceStack() here.
375 mtx_lock(&drvdb_mtx
);
376 IoCreateDevice(drv
, 0, NULL
, FILE_DEVICE_UNKNOWN
, 0, FALSE
, &dev
);
377 mtx_unlock(&drvdb_mtx
);
379 /* Stash pointer to our BSD device handle. */
381 dev
->do_devext
= bsddev
;
383 return(STATUS_SUCCESS
);
387 windrv_destroy_pdo(driver_object
*drv
, device_t bsddev
)
391 pdo
= windrv_find_pdo(drv
, bsddev
);
393 /* Remove reference to device_t */
395 pdo
->do_devext
= NULL
;
397 mtx_lock(&drvdb_mtx
);
399 mtx_unlock(&drvdb_mtx
);
405 * Given a device_t, find the corresponding PDO in a driver's
410 windrv_find_pdo(driver_object
*drv
, device_t bsddev
)
414 printf("In windrv_find_pdo: \ndrv = %x", drv
);
415 printf("\nbsddev = %x", bsddev
);
416 printf("\npdo = %x", drv
->dro_devobj
);
417 printf("\npdo->do_devext = %x\n", drv
->dro_devobj
->do_devext
);
419 mtx_lock(&drvdb_mtx
);
420 pdo
= drv
->dro_devobj
;
421 if (pdo
->do_devext
!= bsddev
) {
422 mtx_unlock(&drvdb_mtx
);
423 panic("PDO wasn't first device in list");
425 mtx_unlock(&drvdb_mtx
);
431 * Add an internally emulated driver to the database. We need this
432 * to set up an emulated bus driver so that it can receive IRPs.
436 windrv_bus_attach(driver_object
*drv
, const char *name
)
438 struct drvdb_ent
*new;
440 new = malloc(sizeof(struct drvdb_ent
), M_DEVBUF
, M_NOWAIT
);
444 drv
->dro_drivername
.us_len
= strlen(name
) * 2;
445 drv
->dro_drivername
.us_maxlen
= strlen(name
) * 2;
446 drv
->dro_drivername
.us_buf
= NULL
;
447 ndis_ascii_to_unicode(name
, &drv
->dro_drivername
.us_buf
);
450 /* I added this because windrv_lookup was getting
451 * fake_pccard_driver and fake_pci_driver mixed up.
452 * I'm not sure if it will mess anything else up.
454 drv
->dro_driverstart
= drv
;
457 new->windrv_object
= drv
;
458 new->windrv_devlist
= NULL
;
459 new->windrv_regvals
= NULL
;
461 mtx_lock(&drvdb_mtx
);
462 STAILQ_INSERT_HEAD(&drvdb_head
, new, link
);
463 mtx_unlock(&drvdb_mtx
);
470 extern void x86_64_wrap(void);
471 extern void x86_64_wrap_call(void);
472 extern void x86_64_wrap_end(void);
474 #endif /* __amd64__ */
477 windrv_wrap(funcptr func
, funcptr
*wrap
)
481 vm_offset_t
*calladdr
;
482 vm_offset_t wrapstart
, wrapend
, wrapcall
;
484 wrapstart
= (vm_offset_t
)&x86_64_wrap
;
485 wrapend
= (vm_offset_t
)&x86_64_wrap_end
;
486 wrapcall
= (vm_offset_t
)&x86_64_wrap_call
;
488 /* Allocate a new wrapper instance. */
490 p
= malloc((wrapend
- wrapstart
), M_DEVBUF
, M_NOWAIT
);
494 /* Copy over the code. */
496 memcpy( p
, (char *)wrapstart
, (wrapend
- wrapstart
));
498 /* Insert the function address into the new wrapper instance. */
500 calladdr
= (uint64_t *)((char *)p
+ (wrapcall
- wrapstart
) + 2);
501 *calladdr
= (vm_offset_t
)func
;
504 #else /* __amd64__ */
506 #endif /* __amd64__ */
511 windrv_unwrap(funcptr func
)
514 free(func
, M_DEVBUF
);
515 #endif /* __amd64__ */