1 /*-
2 * Copyright (c) 2003
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: src/sys/compat/ndis/subr_ntoskrnl.c,v 1.97 2008/12/27 08:03:32 weongyo Exp $");
35
36 #include <sys/ctype.h>
37 #include <sys/unistd.h>
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/errno.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45
46 #include <sys/callout.h>
47 #if __FreeBSD_version > 502113
48 #include <sys/kdb.h>
49 #endif
50 #include <sys/kernel.h>
51 #include <sys/proc.h>
52 #include <sys/condvar.h>
53 #include <sys/kthread.h>
54 #include <sys/module.h>
55 #include <sys/smp.h>
56 #include <sys/sched.h>
57 #include <sys/sysctl.h>
58
59 #include <machine/atomic.h>
60 #include <machine/bus.h>
61 #include <machine/stdarg.h>
62 #include <machine/resource.h>
63
64 #include <sys/bus.h>
65 #include <sys/rman.h>
66
67 #include <vm/vm.h>
68 #include <vm/vm_param.h>
69 #include <vm/pmap.h>
70 #include <vm/uma.h>
71 #include <vm/vm_kern.h>
72 #include <vm/vm_map.h>
73
74 #include <compat/ndis/pe_var.h>
75 #include <compat/ndis/cfg_var.h>
76 #include <compat/ndis/resource_var.h>
77 #include <compat/ndis/ntoskrnl_var.h>
78 #include <compat/ndis/hal_var.h>
79 #include <compat/ndis/ndis_var.h>
80
81 #ifdef NTOSKRNL_DEBUG_TIMERS
82 static int sysctl_show_timers(SYSCTL_HANDLER_ARGS);
83
84 SYSCTL_PROC(_debug, OID_AUTO, ntoskrnl_timers, CTLFLAG_RW, 0, 0,
85 sysctl_show_timers, "I", "Show ntoskrnl timer stats");
86 #endif
87
88 struct kdpc_queue {
89 list_entry kq_disp;
90 struct thread *kq_td;
91 int kq_cpu;
92 int kq_exit;
93 int kq_running;
94 kspin_lock kq_lock;
95 nt_kevent kq_proc;
96 nt_kevent kq_done;
97 };
98
99 typedef struct kdpc_queue kdpc_queue;
100
101 struct wb_ext {
102 struct cv we_cv;
103 struct thread *we_td;
104 };
105
106 typedef struct wb_ext wb_ext;
107
108 #define NTOSKRNL_TIMEOUTS 256
109 #ifdef NTOSKRNL_DEBUG_TIMERS
110 static uint64_t ntoskrnl_timer_fires;
111 static uint64_t ntoskrnl_timer_sets;
112 static uint64_t ntoskrnl_timer_reloads;
113 static uint64_t ntoskrnl_timer_cancels;
114 #endif
115
116 struct callout_entry {
117 struct callout ce_callout;
118 list_entry ce_list;
119 };
120
121 typedef struct callout_entry callout_entry;
122
123 static struct list_entry ntoskrnl_calllist;
124 static struct mtx ntoskrnl_calllock;
125
126 static struct list_entry ntoskrnl_intlist;
127 static kspin_lock ntoskrnl_intlock;
128
129 static uint8_t RtlEqualUnicodeString(unicode_string *,
130 unicode_string *, uint8_t);
131 static void RtlCopyUnicodeString(unicode_string *,
132 unicode_string *);
133 static irp *IoBuildSynchronousFsdRequest(uint32_t, device_object *,
134 void *, uint32_t, uint64_t *, nt_kevent *, io_status_block *);
135 static irp *IoBuildAsynchronousFsdRequest(uint32_t,
136 device_object *, void *, uint32_t, uint64_t *, io_status_block *);
137 static irp *IoBuildDeviceIoControlRequest(uint32_t,
138 device_object *, void *, uint32_t, void *, uint32_t,
139 uint8_t, nt_kevent *, io_status_block *);
140 static irp *IoAllocateIrp(uint8_t, uint8_t);
141 static void IoReuseIrp(irp *, uint32_t);
142 static void IoFreeIrp(irp *);
143 static void IoInitializeIrp(irp *, uint16_t, uint8_t);
144 static irp *IoMakeAssociatedIrp(irp *, uint8_t);
145 static uint32_t KeWaitForMultipleObjects(uint32_t,
146 nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t,
147 int64_t *, wait_block *);
148 static void ntoskrnl_waittest(nt_dispatch_header *, uint32_t);
149 static void ntoskrnl_satisfy_wait(nt_dispatch_header *, struct thread *);
150 static void ntoskrnl_satisfy_multiple_waits(wait_block *);
151 static int ntoskrnl_is_signalled(nt_dispatch_header *, struct thread *);
152 static void ntoskrnl_insert_timer(ktimer *, int);
153 static void ntoskrnl_remove_timer(ktimer *);
154 #ifdef NTOSKRNL_DEBUG_TIMERS
155 static void ntoskrnl_show_timers(void);
156 #endif
157 static void ntoskrnl_timercall(void *);
158 static void ntoskrnl_dpc_thread(void *);
159 static void ntoskrnl_destroy_dpc_threads(void);
160 static void ntoskrnl_destroy_workitem_threads(void);
161 static void ntoskrnl_workitem_thread(void *);
162 static void ntoskrnl_workitem(device_object *, void *);
163 static void ntoskrnl_unicode_to_ascii(uint16_t *, char *, int);
164 static void ntoskrnl_ascii_to_unicode(char *, uint16_t *, int);
165 static uint8_t ntoskrnl_insert_dpc(list_entry *, kdpc *);
166 static void WRITE_REGISTER_USHORT(uint16_t *, uint16_t);
167 static uint16_t READ_REGISTER_USHORT(uint16_t *);
168 static void WRITE_REGISTER_ULONG(uint32_t *, uint32_t);
169 static uint32_t READ_REGISTER_ULONG(uint32_t *);
170 static void WRITE_REGISTER_UCHAR(uint8_t *, uint8_t);
171 static uint8_t READ_REGISTER_UCHAR(uint8_t *);
172 static int64_t _allmul(int64_t, int64_t);
173 static int64_t _alldiv(int64_t, int64_t);
174 static int64_t _allrem(int64_t, int64_t);
175 static int64_t _allshr(int64_t, uint8_t);
176 static int64_t _allshl(int64_t, uint8_t);
177 static uint64_t _aullmul(uint64_t, uint64_t);
178 static uint64_t _aulldiv(uint64_t, uint64_t);
179 static uint64_t _aullrem(uint64_t, uint64_t);
180 static uint64_t _aullshr(uint64_t, uint8_t);
181 static uint64_t _aullshl(uint64_t, uint8_t);
182 static slist_entry *ntoskrnl_pushsl(slist_header *, slist_entry *);
183 static slist_entry *ntoskrnl_popsl(slist_header *);
184 static void ExInitializePagedLookasideList(paged_lookaside_list *,
185 lookaside_alloc_func *, lookaside_free_func *,
186 uint32_t, size_t, uint32_t, uint16_t);
187 static void ExDeletePagedLookasideList(paged_lookaside_list *);
188 static void ExInitializeNPagedLookasideList(npaged_lookaside_list *,
189 lookaside_alloc_func *, lookaside_free_func *,
190 uint32_t, size_t, uint32_t, uint16_t);
191 static void ExDeleteNPagedLookasideList(npaged_lookaside_list *);
192 static slist_entry
193 *ExInterlockedPushEntrySList(slist_header *,
194 slist_entry *, kspin_lock *);
195 static slist_entry
196 *ExInterlockedPopEntrySList(slist_header *, kspin_lock *);
197 static uint32_t InterlockedIncrement(volatile uint32_t *);
198 static uint32_t InterlockedDecrement(volatile uint32_t *);
199 static void ExInterlockedAddLargeStatistic(uint64_t *, uint32_t);
200 static void *MmAllocateContiguousMemory(uint32_t, uint64_t);
201 static void *MmAllocateContiguousMemorySpecifyCache(uint32_t,
202 uint64_t, uint64_t, uint64_t, uint32_t);
203 static void MmFreeContiguousMemory(void *);
204 static void MmFreeContiguousMemorySpecifyCache(void *, uint32_t, uint32_t);
205 static uint32_t MmSizeOfMdl(void *, size_t);
206 static void *MmMapLockedPages(mdl *, uint8_t);
207 static void *MmMapLockedPagesSpecifyCache(mdl *,
208 uint8_t, uint32_t, void *, uint32_t, uint32_t);
209 static void MmUnmapLockedPages(void *, mdl *);
210 static device_t ntoskrnl_finddev(device_t, uint64_t, struct resource **);
211 static void RtlZeroMemory(void *, size_t);
212 static void RtlCopyMemory(void *, const void *, size_t);
213 static size_t RtlCompareMemory(const void *, const void *, size_t);
214 static ndis_status RtlUnicodeStringToInteger(unicode_string *,
215 uint32_t, uint32_t *);
216 static int atoi (const char *);
217 static long atol (const char *);
218 static int rand(void);
219 static void srand(unsigned int);
220 static void KeQuerySystemTime(uint64_t *);
221 static uint32_t KeTickCount(void);
222 static uint8_t IoIsWdmVersionAvailable(uint8_t, uint8_t);
223 static void ntoskrnl_thrfunc(void *);
224 static ndis_status PsCreateSystemThread(ndis_handle *,
225 uint32_t, void *, ndis_handle, void *, void *, void *);
226 static ndis_status PsTerminateSystemThread(ndis_status);
227 static ndis_status IoGetDeviceObjectPointer(unicode_string *,
228 uint32_t, void *, device_object *);
229 static ndis_status IoGetDeviceProperty(device_object *, uint32_t,
230 uint32_t, void *, uint32_t *);
231 static void KeInitializeMutex(kmutant *, uint32_t);
232 static uint32_t KeReleaseMutex(kmutant *, uint8_t);
233 static uint32_t KeReadStateMutex(kmutant *);
234 static ndis_status ObReferenceObjectByHandle(ndis_handle,
235 uint32_t, void *, uint8_t, void **, void **);
236 static void ObfDereferenceObject(void *);
237 static uint32_t ZwClose(ndis_handle);
238 static uint32_t WmiQueryTraceInformation(uint32_t, void *, uint32_t,
239 uint32_t, void *);
240 static uint32_t WmiTraceMessage(uint64_t, uint32_t, void *, uint16_t, ...);
241 static uint32_t IoWMIRegistrationControl(device_object *, uint32_t);
242 static void *ntoskrnl_memset(void *, int, size_t);
243 static void *ntoskrnl_memmove(void *, void *, size_t);
244 static void *ntoskrnl_memchr(void *, unsigned char, size_t);
245 static char *ntoskrnl_strstr(char *, char *);
246 static char *ntoskrnl_strncat(char *, char *, size_t);
247 static int ntoskrnl_toupper(int);
248 static int ntoskrnl_tolower(int);
249 static funcptr ntoskrnl_findwrap(funcptr);
250 static uint32_t DbgPrint(char *, ...);
251 static void DbgBreakPoint(void);
252 static void KeBugCheckEx(uint32_t, u_long, u_long, u_long, u_long);
253 static int32_t KeDelayExecutionThread(uint8_t, uint8_t, int64_t *);
254 static int32_t KeSetPriorityThread(struct thread *, int32_t);
255 static void dummy(void);
256
257 static struct mtx ntoskrnl_dispatchlock;
258 static struct mtx ntoskrnl_interlock;
259 static kspin_lock ntoskrnl_cancellock;
260 static int ntoskrnl_kth = 0;
261 static struct nt_objref_head ntoskrnl_reflist;
262 static uma_zone_t mdl_zone;
263 static uma_zone_t iw_zone;
264 static struct kdpc_queue *kq_queues;
265 static struct kdpc_queue *wq_queues;
266 static int wq_idx = 0;
267
268 int
269 ntoskrnl_libinit()
270 {
271 image_patch_table *patch;
272 int error;
273 struct proc *p;
274 kdpc_queue *kq;
275 callout_entry *e;
276 int i;
277 char name[64];
278
279 mtx_init(&ntoskrnl_dispatchlock,
280 "ntoskrnl dispatch lock", MTX_NDIS_LOCK, MTX_DEF|MTX_RECURSE);
281 mtx_init(&ntoskrnl_interlock, MTX_NTOSKRNL_SPIN_LOCK, NULL, MTX_SPIN);
282 KeInitializeSpinLock(&ntoskrnl_cancellock);
283 KeInitializeSpinLock(&ntoskrnl_intlock);
284 TAILQ_INIT(&ntoskrnl_reflist);
285
286 InitializeListHead(&ntoskrnl_calllist);
287 InitializeListHead(&ntoskrnl_intlist);
288 mtx_init(&ntoskrnl_calllock, MTX_NTOSKRNL_SPIN_LOCK, NULL, MTX_SPIN);
289
290 kq_queues = ExAllocatePoolWithTag(NonPagedPool,
291 #ifdef NTOSKRNL_MULTIPLE_DPCS
292 sizeof(kdpc_queue) * mp_ncpus, 0);
293 #else
294 sizeof(kdpc_queue), 0);
295 #endif
296
297 if (kq_queues == NULL)
298 return(ENOMEM);
299
300 wq_queues = ExAllocatePoolWithTag(NonPagedPool,
301 sizeof(kdpc_queue) * WORKITEM_THREADS, 0);
302
303 if (wq_queues == NULL)
304 return(ENOMEM);
305
306 #ifdef NTOSKRNL_MULTIPLE_DPCS
307 bzero((char *)kq_queues, sizeof(kdpc_queue) * mp_ncpus);
308 #else
309 bzero((char *)kq_queues, sizeof(kdpc_queue));
310 #endif
311 bzero((char *)wq_queues, sizeof(kdpc_queue) * WORKITEM_THREADS);
312
313 /*
314 * Launch the DPC threads.
315 */
316
317 #ifdef NTOSKRNL_MULTIPLE_DPCS
318 for (i = 0; i < mp_ncpus; i++) {
319 #else
320 for (i = 0; i < 1; i++) {
321 #endif
322 kq = kq_queues + i;
323 kq->kq_cpu = i;
324 sprintf(name, "Windows DPC %d", i);
325 error = kproc_create(ntoskrnl_dpc_thread, kq, &p,
326 RFHIGHPID, NDIS_KSTACK_PAGES, name);
327 if (error)
328 panic("failed to launch DPC thread");
329 }
330
331 /*
332 * Launch the workitem threads.
333 */
334
335 for (i = 0; i < WORKITEM_THREADS; i++) {
336 kq = wq_queues + i;
337 sprintf(name, "Windows Workitem %d", i);
338 error = kproc_create(ntoskrnl_workitem_thread, kq, &p,
339 RFHIGHPID, NDIS_KSTACK_PAGES, name);
340 if (error)
341 panic("failed to launch workitem thread");
342 }
343
344 patch = ntoskrnl_functbl;
345 while (patch->ipt_func != NULL) {
346 windrv_wrap((funcptr)patch->ipt_func,
347 (funcptr *)&patch->ipt_wrap,
348 patch->ipt_argcnt, patch->ipt_ftype);
349 patch++;
350 }
351
352 for (i = 0; i < NTOSKRNL_TIMEOUTS; i++) {
353 e = ExAllocatePoolWithTag(NonPagedPool,
354 sizeof(callout_entry), 0);
355 if (e == NULL)
356 panic("failed to allocate timeouts");
357 mtx_lock_spin(&ntoskrnl_calllock);
358 InsertHeadList((&ntoskrnl_calllist), (&e->ce_list));
359 mtx_unlock_spin(&ntoskrnl_calllock);
360 }
361
362 /*
363 * MDLs are supposed to be variable size (they describe
364 * buffers containing some number of pages, but we don't
365 * know ahead of time how many pages that will be). But
366 * always allocating them off the heap is very slow. As
367 * a compromise, we create an MDL UMA zone big enough to
368 * handle any buffer requiring up to 16 pages, and we
369 * use those for any MDLs for buffers of 16 pages or less
370 * in size. For buffers larger than that (which we assume
371 * will be few and far between, we allocate the MDLs off
372 * the heap.
373 */
374
375 mdl_zone = uma_zcreate("Windows MDL", MDL_ZONE_SIZE,
376 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
377
378 iw_zone = uma_zcreate("Windows WorkItem", sizeof(io_workitem),
379 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
380
381 return(0);
382 }
383
384 int
385 ntoskrnl_libfini()
386 {
387 image_patch_table *patch;
388 callout_entry *e;
389 list_entry *l;
390
391 patch = ntoskrnl_functbl;
392 while (patch->ipt_func != NULL) {
393 windrv_unwrap(patch->ipt_wrap);
394 patch++;
395 }
396
397 /* Stop the workitem queues. */
398 ntoskrnl_destroy_workitem_threads();
399 /* Stop the DPC queues. */
400 ntoskrnl_destroy_dpc_threads();
401
402 ExFreePool(kq_queues);
403 ExFreePool(wq_queues);
404
405 uma_zdestroy(mdl_zone);
406 uma_zdestroy(iw_zone);
407
408 mtx_lock_spin(&ntoskrnl_calllock);
409 while(!IsListEmpty(&ntoskrnl_calllist)) {
410 l = RemoveHeadList(&ntoskrnl_calllist);
411 e = CONTAINING_RECORD(l, callout_entry, ce_list);
412 mtx_unlock_spin(&ntoskrnl_calllock);
413 ExFreePool(e);
414 mtx_lock_spin(&ntoskrnl_calllock);
415 }
416 mtx_unlock_spin(&ntoskrnl_calllock);
417
418 mtx_destroy(&ntoskrnl_dispatchlock);
419 mtx_destroy(&ntoskrnl_interlock);
420 mtx_destroy(&ntoskrnl_calllock);
421
422 return(0);
423 }
424
425 /*
426 * We need to be able to reference this externally from the wrapper;
427 * GCC only generates a local implementation of memset.
428 */
429 static void *
430 ntoskrnl_memset(buf, ch, size)
431 void *buf;
432 int ch;
433 size_t size;
434 {
435 return(memset(buf, ch, size));
436 }
437
438 static void *
439 ntoskrnl_memmove(dst, src, size)
440 void *src;
441 void *dst;
442 size_t size;
443 {
444 bcopy(src, dst, size);
445 return(dst);
446 }
447
448 static void *
449 ntoskrnl_memchr(buf, ch, len)
450 void *buf;
451 unsigned char ch;
452 size_t len;
453 {
454 if (len != 0) {
455 unsigned char *p = buf;
456
457 do {
458 if (*p++ == ch)
459 return (p - 1);
460 } while (--len != 0);
461 }
462 return (NULL);
463 }
464
465 static char *
466 ntoskrnl_strstr(s, find)
467 char *s, *find;
468 {
469 char c, sc;
470 size_t len;
471
472 if ((c = *find++) != 0) {
473 len = strlen(find);
474 do {
475 do {
476 if ((sc = *s++) == 0)
477 return (NULL);
478 } while (sc != c);
479 } while (strncmp(s, find, len) != 0);
480 s--;
481 }
482 return ((char *)s);
483 }
484
485 /* Taken from libc */
486 static char *
487 ntoskrnl_strncat(dst, src, n)
488 char *dst;
489 char *src;
490 size_t n;
491 {
492 if (n != 0) {
493 char *d = dst;
494 const char *s = src;
495
496 while (*d != 0)
497 d++;
498 do {
499 if ((*d = *s++) == 0)
500 break;
501 d++;
502 } while (--n != 0);
503 *d = 0;
504 }
505 return (dst);
506 }
507
508 static int
509 ntoskrnl_toupper(c)
510 int c;
511 {
512 return(toupper(c));
513 }
514
515 static int
516 ntoskrnl_tolower(c)
517 int c;
518 {
519 return(tolower(c));
520 }
521
522 static uint8_t
523 RtlEqualUnicodeString(str1, str2, caseinsensitive)
524 unicode_string *str1;
525 unicode_string *str2;
526 uint8_t caseinsensitive;
527 {
528 int i;
529
530 if (str1->us_len != str2->us_len)
531 return(FALSE);
532
533 for (i = 0; i < str1->us_len; i++) {
534 if (caseinsensitive == TRUE) {
535 if (toupper((char)(str1->us_buf[i] & 0xFF)) !=
536 toupper((char)(str2->us_buf[i] & 0xFF)))
537 return(FALSE);
538 } else {
539 if (str1->us_buf[i] != str2->us_buf[i])
540 return(FALSE);
541 }
542 }
543
544 return(TRUE);
545 }
546
547 static void
548 RtlCopyUnicodeString(dest, src)
549 unicode_string *dest;
550 unicode_string *src;
551 {
552
553 if (dest->us_maxlen >= src->us_len)
554 dest->us_len = src->us_len;
555 else
556 dest->us_len = dest->us_maxlen;
557 memcpy(dest->us_buf, src->us_buf, dest->us_len);
558 return;
559 }
560
561 static void
562 ntoskrnl_ascii_to_unicode(ascii, unicode, len)
563 char *ascii;
564 uint16_t *unicode;
565 int len;
566 {
567 int i;
568 uint16_t *ustr;
569
570 ustr = unicode;
571 for (i = 0; i < len; i++) {
572 *ustr = (uint16_t)ascii[i];
573 ustr++;
574 }
575
576 return;
577 }
578
579 static void
580 ntoskrnl_unicode_to_ascii(unicode, ascii, len)
581 uint16_t *unicode;
582 char *ascii;
583 int len;
584 {
585 int i;
586 uint8_t *astr;
587
588 astr = ascii;
589 for (i = 0; i < len / 2; i++) {
590 *astr = (uint8_t)unicode[i];
591 astr++;
592 }
593
594 return;
595 }
596
597 uint32_t
598 RtlUnicodeStringToAnsiString(dest, src, allocate)
599 ansi_string *dest;
600 unicode_string *src;
601 uint8_t allocate;
602 {
603 if (dest == NULL || src == NULL)
604 return(STATUS_INVALID_PARAMETER);
605
606 dest->as_len = src->us_len / 2;
607 if (dest->as_maxlen < dest->as_len)
608 dest->as_len = dest->as_maxlen;
609
610 if (allocate == TRUE) {
611 dest->as_buf = ExAllocatePoolWithTag(NonPagedPool,
612 (src->us_len / 2) + 1, 0);
613 if (dest->as_buf == NULL)
614 return(STATUS_INSUFFICIENT_RESOURCES);
615 dest->as_len = dest->as_maxlen = src->us_len / 2;
616 } else {
617 dest->as_len = src->us_len / 2; /* XXX */
618 if (dest->as_maxlen < dest->as_len)
619 dest->as_len = dest->as_maxlen;
620 }
621
622 ntoskrnl_unicode_to_ascii(src->us_buf, dest->as_buf,
623 dest->as_len * 2);
624
625 return (STATUS_SUCCESS);
626 }
627
628 uint32_t
629 RtlAnsiStringToUnicodeString(dest, src, allocate)
630 unicode_string *dest;
631 ansi_string *src;
632 uint8_t allocate;
633 {
634 if (dest == NULL || src == NULL)
635 return(STATUS_INVALID_PARAMETER);
636
637 if (allocate == TRUE) {
638 dest->us_buf = ExAllocatePoolWithTag(NonPagedPool,
639 src->as_len * 2, 0);
640 if (dest->us_buf == NULL)
641 return(STATUS_INSUFFICIENT_RESOURCES);
642 dest->us_len = dest->us_maxlen = strlen(src->as_buf) * 2;
643 } else {
644 dest->us_len = src->as_len * 2; /* XXX */
645 if (dest->us_maxlen < dest->us_len)
646 dest->us_len = dest->us_maxlen;
647 }
648
649 ntoskrnl_ascii_to_unicode(src->as_buf, dest->us_buf,
650 dest->us_len / 2);
651
652 return (STATUS_SUCCESS);
653 }
654
655 void *
656 ExAllocatePoolWithTag(pooltype, len, tag)
657 uint32_t pooltype;
658 size_t len;
659 uint32_t tag;
660 {
661 void *buf;
662
663 buf = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
664 if (buf == NULL)
665 return(NULL);
666
667 return(buf);
668 }
669
670 void
671 ExFreePool(buf)
672 void *buf;
673 {
674 free(buf, M_DEVBUF);
675 return;
676 }
677
678 uint32_t
679 IoAllocateDriverObjectExtension(drv, clid, extlen, ext)
680 driver_object *drv;
681 void *clid;
682 uint32_t extlen;
683 void **ext;
684 {
685 custom_extension *ce;
686
687 ce = ExAllocatePoolWithTag(NonPagedPool, sizeof(custom_extension)
688 + extlen, 0);
689
690 if (ce == NULL)
691 return(STATUS_INSUFFICIENT_RESOURCES);
692
693 ce->ce_clid = clid;
694 InsertTailList((&drv->dro_driverext->dre_usrext), (&ce->ce_list));
695
696 *ext = (void *)(ce + 1);
697
698 return(STATUS_SUCCESS);
699 }
700
701 void *
702 IoGetDriverObjectExtension(drv, clid)
703 driver_object *drv;
704 void *clid;
705 {
706 list_entry *e;
707 custom_extension *ce;
708
709 /*
710 * Sanity check. Our dummy bus drivers don't have
711 * any driver extentions.
712 */
713
714 if (drv->dro_driverext == NULL)
715 return(NULL);
716
717 e = drv->dro_driverext->dre_usrext.nle_flink;
718 while (e != &drv->dro_driverext->dre_usrext) {
719 ce = (custom_extension *)e;
720 if (ce->ce_clid == clid)
721 return((void *)(ce + 1));
722 e = e->nle_flink;
723 }
724
725 return(NULL);
726 }
727
728
729 uint32_t
730 IoCreateDevice(drv, devextlen, devname, devtype, devchars, exclusive, newdev)
731 driver_object *drv;
732 uint32_t devextlen;
733 unicode_string *devname;
734 uint32_t devtype;
735 uint32_t devchars;
736 uint8_t exclusive;
737 device_object **newdev;
738 {
739 device_object *dev;
740
741 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device_object), 0);
742 if (dev == NULL)
743 return(STATUS_INSUFFICIENT_RESOURCES);
744
745 dev->do_type = devtype;
746 dev->do_drvobj = drv;
747 dev->do_currirp = NULL;
748 dev->do_flags = 0;
749
750 if (devextlen) {
751 dev->do_devext = ExAllocatePoolWithTag(NonPagedPool,
752 devextlen, 0);
753
754 if (dev->do_devext == NULL) {
755 ExFreePool(dev);
756 return(STATUS_INSUFFICIENT_RESOURCES);
757 }
758
759 bzero(dev->do_devext, devextlen);
760 } else
761 dev->do_devext = NULL;
762
763 dev->do_size = sizeof(device_object) + devextlen;
764 dev->do_refcnt = 1;
765 dev->do_attacheddev = NULL;
766 dev->do_nextdev = NULL;
767 dev->do_devtype = devtype;
768 dev->do_stacksize = 1;
769 dev->do_alignreq = 1;
770 dev->do_characteristics = devchars;
771 dev->do_iotimer = NULL;
772 KeInitializeEvent(&dev->do_devlock, EVENT_TYPE_SYNC, TRUE);
773
774 /*
775 * Vpd is used for disk/tape devices,
776 * but we don't support those. (Yet.)
777 */
778 dev->do_vpb = NULL;
779
780 dev->do_devobj_ext = ExAllocatePoolWithTag(NonPagedPool,
781 sizeof(devobj_extension), 0);
782
783 if (dev->do_devobj_ext == NULL) {
784 if (dev->do_devext != NULL)
785 ExFreePool(dev->do_devext);
786 ExFreePool(dev);
787 return(STATUS_INSUFFICIENT_RESOURCES);
788 }
789
790 dev->do_devobj_ext->dve_type = 0;
791 dev->do_devobj_ext->dve_size = sizeof(devobj_extension);
792 dev->do_devobj_ext->dve_devobj = dev;
793
794 /*
795 * Attach this device to the driver object's list
796 * of devices. Note: this is not the same as attaching
797 * the device to the device stack. The driver's AddDevice
798 * routine must explicitly call IoAddDeviceToDeviceStack()
799 * to do that.
800 */
801
802 if (drv->dro_devobj == NULL) {
803 drv->dro_devobj = dev;
804 dev->do_nextdev = NULL;
805 } else {
806 dev->do_nextdev = drv->dro_devobj;
807 drv->dro_devobj = dev;
808 }
809
810 *newdev = dev;
811
812 return(STATUS_SUCCESS);
813 }
814
815 void
816 IoDeleteDevice(dev)
817 device_object *dev;
818 {
819 device_object *prev;
820
821 if (dev == NULL)
822 return;
823
824 if (dev->do_devobj_ext != NULL)
825 ExFreePool(dev->do_devobj_ext);
826
827 if (dev->do_devext != NULL)
828 ExFreePool(dev->do_devext);
829
830 /* Unlink the device from the driver's device list. */
831
832 prev = dev->do_drvobj->dro_devobj;
833 if (prev == dev)
834 dev->do_drvobj->dro_devobj = dev->do_nextdev;
835 else {
836 while (prev->do_nextdev != dev)
837 prev = prev->do_nextdev;
838 prev->do_nextdev = dev->do_nextdev;
839 }
840
841 ExFreePool(dev);
842
843 return;
844 }
845
846 device_object *
847 IoGetAttachedDevice(dev)
848 device_object *dev;
849 {
850 device_object *d;
851
852 if (dev == NULL)
853 return (NULL);
854
855 d = dev;
856
857 while (d->do_attacheddev != NULL)
858 d = d->do_attacheddev;
859
860 return (d);
861 }
862
863 static irp *
864 IoBuildSynchronousFsdRequest(func, dobj, buf, len, off, event, status)
865 uint32_t func;
866 device_object *dobj;
867 void *buf;
868 uint32_t len;
869 uint64_t *off;
870 nt_kevent *event;
871 io_status_block *status;
872 {
873 irp *ip;
874
875 ip = IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status);
876 if (ip == NULL)
877 return(NULL);
878 ip->irp_usrevent = event;
879
880 return(ip);
881 }
882
883 static irp *
884 IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status)
885 uint32_t func;
886 device_object *dobj;
887 void *buf;
888 uint32_t len;
889 uint64_t *off;
890 io_status_block *status;
891 {
892 irp *ip;
893 io_stack_location *sl;
894
895 ip = IoAllocateIrp(dobj->do_stacksize, TRUE);
896 if (ip == NULL)
897 return(NULL);
898
899 ip->irp_usriostat = status;
900 ip->irp_tail.irp_overlay.irp_thread = NULL;
901
902 sl = IoGetNextIrpStackLocation(ip);
903 sl->isl_major = func;
904 sl->isl_minor = 0;
905 sl->isl_flags = 0;
906 sl->isl_ctl = 0;
907 sl->isl_devobj = dobj;
908 sl->isl_fileobj = NULL;
909 sl->isl_completionfunc = NULL;
910
911 ip->irp_userbuf = |