[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/ndis/subr_ntoskrnl.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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 =