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