]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/compat/ndis/subr_ntoskrnl.c
MFC r216242:
[FreeBSD/stable/8.git] / sys / compat / ndis / subr_ntoskrnl.c
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$");
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 #include <sys/kdb.h>
48 #include <sys/kernel.h>
49 #include <sys/proc.h>
50 #include <sys/condvar.h>
51 #include <sys/kthread.h>
52 #include <sys/module.h>
53 #include <sys/smp.h>
54 #include <sys/sched.h>
55 #include <sys/sysctl.h>
56
57 #include <machine/atomic.h>
58 #include <machine/bus.h>
59 #include <machine/stdarg.h>
60 #include <machine/resource.h>
61
62 #include <sys/bus.h>
63 #include <sys/rman.h>
64
65 #include <vm/vm.h>
66 #include <vm/vm_param.h>
67 #include <vm/pmap.h>
68 #include <vm/uma.h>
69 #include <vm/vm_kern.h>
70 #include <vm/vm_map.h>
71 #include <vm/vm_extern.h>
72
73 #include <compat/ndis/pe_var.h>
74 #include <compat/ndis/cfg_var.h>
75 #include <compat/ndis/resource_var.h>
76 #include <compat/ndis/ntoskrnl_var.h>
77 #include <compat/ndis/hal_var.h>
78 #include <compat/ndis/ndis_var.h>
79
80 #ifdef NTOSKRNL_DEBUG_TIMERS
81 static int sysctl_show_timers(SYSCTL_HANDLER_ARGS);
82
83 SYSCTL_PROC(_debug, OID_AUTO, ntoskrnl_timers, CTLFLAG_RW, 0, 0,
84         sysctl_show_timers, "I", "Show ntoskrnl timer stats");
85 #endif
86
87 struct kdpc_queue {
88         list_entry              kq_disp;
89         struct thread           *kq_td;
90         int                     kq_cpu;
91         int                     kq_exit;
92         int                     kq_running;
93         kspin_lock              kq_lock;
94         nt_kevent               kq_proc;
95         nt_kevent               kq_done;
96 };
97
98 typedef struct kdpc_queue kdpc_queue;
99
100 struct wb_ext {
101         struct cv               we_cv;
102         struct thread           *we_td;
103 };
104
105 typedef struct wb_ext wb_ext;
106
107 #define NTOSKRNL_TIMEOUTS       256
108 #ifdef NTOSKRNL_DEBUG_TIMERS
109 static uint64_t ntoskrnl_timer_fires;
110 static uint64_t ntoskrnl_timer_sets;
111 static uint64_t ntoskrnl_timer_reloads;
112 static uint64_t ntoskrnl_timer_cancels;
113 #endif
114
115 struct callout_entry {
116         struct callout          ce_callout;
117         list_entry              ce_list;
118 };
119
120 typedef struct callout_entry callout_entry;
121
122 static struct list_entry ntoskrnl_calllist;
123 static struct mtx ntoskrnl_calllock;
124 struct kuser_shared_data kuser_shared_data;
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 RtlCopyString(ansi_string *, const ansi_string *);
132 static void RtlCopyUnicodeString(unicode_string *,
133         unicode_string *);
134 static irp *IoBuildSynchronousFsdRequest(uint32_t, device_object *,
135          void *, uint32_t, uint64_t *, nt_kevent *, io_status_block *);
136 static irp *IoBuildAsynchronousFsdRequest(uint32_t,
137         device_object *, void *, uint32_t, uint64_t *, io_status_block *);
138 static irp *IoBuildDeviceIoControlRequest(uint32_t,
139         device_object *, void *, uint32_t, void *, uint32_t,
140         uint8_t, nt_kevent *, io_status_block *);
141 static irp *IoAllocateIrp(uint8_t, uint8_t);
142 static void IoReuseIrp(irp *, uint32_t);
143 static void IoFreeIrp(irp *);
144 static void IoInitializeIrp(irp *, uint16_t, uint8_t);
145 static irp *IoMakeAssociatedIrp(irp *, uint8_t);
146 static uint32_t KeWaitForMultipleObjects(uint32_t,
147         nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t,
148         int64_t *, wait_block *);
149 static void ntoskrnl_waittest(nt_dispatch_header *, uint32_t);
150 static void ntoskrnl_satisfy_wait(nt_dispatch_header *, struct thread *);
151 static void ntoskrnl_satisfy_multiple_waits(wait_block *);
152 static int ntoskrnl_is_signalled(nt_dispatch_header *, struct thread *);
153 static void ntoskrnl_insert_timer(ktimer *, int);
154 static void ntoskrnl_remove_timer(ktimer *);
155 #ifdef NTOSKRNL_DEBUG_TIMERS
156 static void ntoskrnl_show_timers(void);
157 #endif
158 static void ntoskrnl_timercall(void *);
159 static void ntoskrnl_dpc_thread(void *);
160 static void ntoskrnl_destroy_dpc_threads(void);
161 static void ntoskrnl_destroy_workitem_threads(void);
162 static void ntoskrnl_workitem_thread(void *);
163 static void ntoskrnl_workitem(device_object *, void *);
164 static void ntoskrnl_unicode_to_ascii(uint16_t *, char *, int);
165 static void ntoskrnl_ascii_to_unicode(char *, uint16_t *, int);
166 static uint8_t ntoskrnl_insert_dpc(list_entry *, kdpc *);
167 static void WRITE_REGISTER_USHORT(uint16_t *, uint16_t);
168 static uint16_t READ_REGISTER_USHORT(uint16_t *);
169 static void WRITE_REGISTER_ULONG(uint32_t *, uint32_t);
170 static uint32_t READ_REGISTER_ULONG(uint32_t *);
171 static void WRITE_REGISTER_UCHAR(uint8_t *, uint8_t);
172 static uint8_t READ_REGISTER_UCHAR(uint8_t *);
173 static int64_t _allmul(int64_t, int64_t);
174 static int64_t _alldiv(int64_t, int64_t);
175 static int64_t _allrem(int64_t, int64_t);
176 static int64_t _allshr(int64_t, uint8_t);
177 static int64_t _allshl(int64_t, uint8_t);
178 static uint64_t _aullmul(uint64_t, uint64_t);
179 static uint64_t _aulldiv(uint64_t, uint64_t);
180 static uint64_t _aullrem(uint64_t, uint64_t);
181 static uint64_t _aullshr(uint64_t, uint8_t);
182 static uint64_t _aullshl(uint64_t, uint8_t);
183 static slist_entry *ntoskrnl_pushsl(slist_header *, slist_entry *);
184 static void InitializeSListHead(slist_header *);
185 static slist_entry *ntoskrnl_popsl(slist_header *);
186 static void ExFreePoolWithTag(void *, uint32_t);
187 static void ExInitializePagedLookasideList(paged_lookaside_list *,
188         lookaside_alloc_func *, lookaside_free_func *,
189         uint32_t, size_t, uint32_t, uint16_t);
190 static void ExDeletePagedLookasideList(paged_lookaside_list *);
191 static void ExInitializeNPagedLookasideList(npaged_lookaside_list *,
192         lookaside_alloc_func *, lookaside_free_func *,
193         uint32_t, size_t, uint32_t, uint16_t);
194 static void ExDeleteNPagedLookasideList(npaged_lookaside_list *);
195 static slist_entry
196         *ExInterlockedPushEntrySList(slist_header *,
197         slist_entry *, kspin_lock *);
198 static slist_entry
199         *ExInterlockedPopEntrySList(slist_header *, kspin_lock *);
200 static uint32_t InterlockedIncrement(volatile uint32_t *);
201 static uint32_t InterlockedDecrement(volatile uint32_t *);
202 static void ExInterlockedAddLargeStatistic(uint64_t *, uint32_t);
203 static void *MmAllocateContiguousMemory(uint32_t, uint64_t);
204 static void *MmAllocateContiguousMemorySpecifyCache(uint32_t,
205         uint64_t, uint64_t, uint64_t, enum nt_caching_type);
206 static void MmFreeContiguousMemory(void *);
207 static void MmFreeContiguousMemorySpecifyCache(void *, uint32_t,
208         enum nt_caching_type);
209 static uint32_t MmSizeOfMdl(void *, size_t);
210 static void *MmMapLockedPages(mdl *, uint8_t);
211 static void *MmMapLockedPagesSpecifyCache(mdl *,
212         uint8_t, uint32_t, void *, uint32_t, uint32_t);
213 static void MmUnmapLockedPages(void *, mdl *);
214 static device_t ntoskrnl_finddev(device_t, uint64_t, struct resource **);
215 static void RtlZeroMemory(void *, size_t);
216 static void RtlSecureZeroMemory(void *, size_t);
217 static void RtlFillMemory(void *, size_t, uint8_t);
218 static void RtlMoveMemory(void *, const void *, size_t);
219 static ndis_status RtlCharToInteger(const char *, uint32_t, uint32_t *);
220 static void RtlCopyMemory(void *, const void *, size_t);
221 static size_t RtlCompareMemory(const void *, const void *, size_t);
222 static ndis_status RtlUnicodeStringToInteger(unicode_string *,
223         uint32_t, uint32_t *);
224 static int atoi (const char *);
225 static long atol (const char *);
226 static int rand(void);
227 static void srand(unsigned int);
228 static void KeQuerySystemTime(uint64_t *);
229 static uint32_t KeTickCount(void);
230 static uint8_t IoIsWdmVersionAvailable(uint8_t, uint8_t);
231 static int32_t IoOpenDeviceRegistryKey(struct device_object *, uint32_t,
232     uint32_t, void **);
233 static void ntoskrnl_thrfunc(void *);
234 static ndis_status PsCreateSystemThread(ndis_handle *,
235         uint32_t, void *, ndis_handle, void *, void *, void *);
236 static ndis_status PsTerminateSystemThread(ndis_status);
237 static ndis_status IoGetDeviceObjectPointer(unicode_string *,
238         uint32_t, void *, device_object *);
239 static ndis_status IoGetDeviceProperty(device_object *, uint32_t,
240         uint32_t, void *, uint32_t *);
241 static void KeInitializeMutex(kmutant *, uint32_t);
242 static uint32_t KeReleaseMutex(kmutant *, uint8_t);
243 static uint32_t KeReadStateMutex(kmutant *);
244 static ndis_status ObReferenceObjectByHandle(ndis_handle,
245         uint32_t, void *, uint8_t, void **, void **);
246 static void ObfDereferenceObject(void *);
247 static uint32_t ZwClose(ndis_handle);
248 static uint32_t WmiQueryTraceInformation(uint32_t, void *, uint32_t,
249         uint32_t, void *);
250 static uint32_t WmiTraceMessage(uint64_t, uint32_t, void *, uint16_t, ...);
251 static uint32_t IoWMIRegistrationControl(device_object *, uint32_t);
252 static void *ntoskrnl_memset(void *, int, size_t);
253 static void *ntoskrnl_memmove(void *, void *, size_t);
254 static void *ntoskrnl_memchr(void *, unsigned char, size_t);
255 static char *ntoskrnl_strstr(char *, char *);
256 static char *ntoskrnl_strncat(char *, char *, size_t);
257 static int ntoskrnl_toupper(int);
258 static int ntoskrnl_tolower(int);
259 static funcptr ntoskrnl_findwrap(funcptr);
260 static uint32_t DbgPrint(char *, ...);
261 static void DbgBreakPoint(void);
262 static void KeBugCheckEx(uint32_t, u_long, u_long, u_long, u_long);
263 static int32_t KeDelayExecutionThread(uint8_t, uint8_t, int64_t *);
264 static int32_t KeSetPriorityThread(struct thread *, int32_t);
265 static void dummy(void);
266
267 static struct mtx ntoskrnl_dispatchlock;
268 static struct mtx ntoskrnl_interlock;
269 static kspin_lock ntoskrnl_cancellock;
270 static int ntoskrnl_kth = 0;
271 static struct nt_objref_head ntoskrnl_reflist;
272 static uma_zone_t mdl_zone;
273 static uma_zone_t iw_zone;
274 static struct kdpc_queue *kq_queues;
275 static struct kdpc_queue *wq_queues;
276 static int wq_idx = 0;
277
278 int
279 ntoskrnl_libinit()
280 {
281         image_patch_table       *patch;
282         int                     error;
283         struct proc             *p;
284         kdpc_queue              *kq;
285         callout_entry           *e;
286         int                     i;
287
288         mtx_init(&ntoskrnl_dispatchlock,
289             "ntoskrnl dispatch lock", MTX_NDIS_LOCK, MTX_DEF|MTX_RECURSE);
290         mtx_init(&ntoskrnl_interlock, MTX_NTOSKRNL_SPIN_LOCK, NULL, MTX_SPIN);
291         KeInitializeSpinLock(&ntoskrnl_cancellock);
292         KeInitializeSpinLock(&ntoskrnl_intlock);
293         TAILQ_INIT(&ntoskrnl_reflist);
294
295         InitializeListHead(&ntoskrnl_calllist);
296         InitializeListHead(&ntoskrnl_intlist);
297         mtx_init(&ntoskrnl_calllock, MTX_NTOSKRNL_SPIN_LOCK, NULL, MTX_SPIN);
298
299         kq_queues = ExAllocatePoolWithTag(NonPagedPool,
300 #ifdef NTOSKRNL_MULTIPLE_DPCS
301             sizeof(kdpc_queue) * mp_ncpus, 0);
302 #else
303             sizeof(kdpc_queue), 0);
304 #endif
305
306         if (kq_queues == NULL)
307                 return (ENOMEM);
308
309         wq_queues = ExAllocatePoolWithTag(NonPagedPool,
310             sizeof(kdpc_queue) * WORKITEM_THREADS, 0);
311
312         if (wq_queues == NULL)
313                 return (ENOMEM);
314
315 #ifdef NTOSKRNL_MULTIPLE_DPCS
316         bzero((char *)kq_queues, sizeof(kdpc_queue) * mp_ncpus);
317 #else
318         bzero((char *)kq_queues, sizeof(kdpc_queue));
319 #endif
320         bzero((char *)wq_queues, sizeof(kdpc_queue) * WORKITEM_THREADS);
321
322         /*
323          * Launch the DPC threads.
324          */
325
326 #ifdef NTOSKRNL_MULTIPLE_DPCS
327         for (i = 0; i < mp_ncpus; i++) {
328 #else
329         for (i = 0; i < 1; i++) {
330 #endif
331                 kq = kq_queues + i;
332                 kq->kq_cpu = i;
333                 error = kproc_create(ntoskrnl_dpc_thread, kq, &p,
334                     RFHIGHPID, NDIS_KSTACK_PAGES, "Windows DPC %d", i);
335                 if (error)
336                         panic("failed to launch DPC thread");
337         }
338
339         /*
340          * Launch the workitem threads.
341          */
342
343         for (i = 0; i < WORKITEM_THREADS; i++) {
344                 kq = wq_queues + i;
345                 error = kproc_create(ntoskrnl_workitem_thread, kq, &p,
346                     RFHIGHPID, NDIS_KSTACK_PAGES, "Windows Workitem %d", i);
347                 if (error)
348                         panic("failed to launch workitem thread");
349         }
350
351         patch = ntoskrnl_functbl;
352         while (patch->ipt_func != NULL) {
353                 windrv_wrap((funcptr)patch->ipt_func,
354                     (funcptr *)&patch->ipt_wrap,
355                     patch->ipt_argcnt, patch->ipt_ftype);
356                 patch++;
357         }
358
359         for (i = 0; i < NTOSKRNL_TIMEOUTS; i++) {
360                 e = ExAllocatePoolWithTag(NonPagedPool,
361                     sizeof(callout_entry), 0);
362                 if (e == NULL)
363                         panic("failed to allocate timeouts");
364                 mtx_lock_spin(&ntoskrnl_calllock);
365                 InsertHeadList((&ntoskrnl_calllist), (&e->ce_list));
366                 mtx_unlock_spin(&ntoskrnl_calllock);
367         }
368
369         /*
370          * MDLs are supposed to be variable size (they describe
371          * buffers containing some number of pages, but we don't
372          * know ahead of time how many pages that will be). But
373          * always allocating them off the heap is very slow. As
374          * a compromise, we create an MDL UMA zone big enough to
375          * handle any buffer requiring up to 16 pages, and we
376          * use those for any MDLs for buffers of 16 pages or less
377          * in size. For buffers larger than that (which we assume
378          * will be few and far between, we allocate the MDLs off
379          * the heap.
380          */
381
382         mdl_zone = uma_zcreate("Windows MDL", MDL_ZONE_SIZE,
383             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
384
385         iw_zone = uma_zcreate("Windows WorkItem", sizeof(io_workitem),
386             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
387
388         return (0);
389 }
390
391 int
392 ntoskrnl_libfini()
393 {
394         image_patch_table       *patch;
395         callout_entry           *e;
396         list_entry              *l;
397
398         patch = ntoskrnl_functbl;
399         while (patch->ipt_func != NULL) {
400                 windrv_unwrap(patch->ipt_wrap);
401                 patch++;
402         }
403
404         /* Stop the workitem queues. */
405         ntoskrnl_destroy_workitem_threads();
406         /* Stop the DPC queues. */
407         ntoskrnl_destroy_dpc_threads();
408
409         ExFreePool(kq_queues);
410         ExFreePool(wq_queues);
411
412         uma_zdestroy(mdl_zone);
413         uma_zdestroy(iw_zone);
414
415         mtx_lock_spin(&ntoskrnl_calllock);
416         while(!IsListEmpty(&ntoskrnl_calllist)) {
417                 l = RemoveHeadList(&ntoskrnl_calllist);
418                 e = CONTAINING_RECORD(l, callout_entry, ce_list);
419                 mtx_unlock_spin(&ntoskrnl_calllock);
420                 ExFreePool(e);
421                 mtx_lock_spin(&ntoskrnl_calllock);
422         }
423         mtx_unlock_spin(&ntoskrnl_calllock);
424
425         mtx_destroy(&ntoskrnl_dispatchlock);
426         mtx_destroy(&ntoskrnl_interlock);
427         mtx_destroy(&ntoskrnl_calllock);
428
429         return (0);
430 }
431
432 /*
433  * We need to be able to reference this externally from the wrapper;
434  * GCC only generates a local implementation of memset.
435  */
436 static void *
437 ntoskrnl_memset(buf, ch, size)
438         void                    *buf;
439         int                     ch;
440         size_t                  size;
441 {
442         return (memset(buf, ch, size));
443 }
444
445 static void *
446 ntoskrnl_memmove(dst, src, size)
447         void                    *src;
448         void                    *dst;
449         size_t                  size;
450 {
451         bcopy(src, dst, size);
452         return (dst);
453 }
454
455 static void *
456 ntoskrnl_memchr(void *buf, unsigned char ch, size_t len)
457 {
458         if (len != 0) {
459                 unsigned char *p = buf;
460
461                 do {
462                         if (*p++ == ch)
463                                 return (p - 1);
464                 } while (--len != 0);
465         }
466         return (NULL);
467 }
468
469 static char *
470 ntoskrnl_strstr(s, find)
471         char *s, *find;
472 {
473         char c, sc;
474         size_t len;
475
476         if ((c = *find++) != 0) {
477                 len = strlen(find);
478                 do {
479                         do {
480                                 if ((sc = *s++) == 0)
481                                         return (NULL);
482                         } while (sc != c);
483                 } while (strncmp(s, find, len) != 0);
484                 s--;
485         }
486         return ((char *)s);
487 }
488
489 /* Taken from libc */
490 static char *
491 ntoskrnl_strncat(dst, src, n)
492         char            *dst;
493         char            *src;
494         size_t          n;
495 {
496         if (n != 0) {
497                 char *d = dst;
498                 const char *s = src;
499
500                 while (*d != 0)
501                         d++;
502                 do {
503                         if ((*d = *s++) == 0)
504                                 break;
505                         d++;
506                 } while (--n != 0);
507                 *d = 0;
508         }
509         return (dst);
510 }
511
512 static int
513 ntoskrnl_toupper(c)
514         int                     c;
515 {
516         return (toupper(c));
517 }
518
519 static int
520 ntoskrnl_tolower(c)
521         int                     c;
522 {
523         return (tolower(c));
524 }
525
526 static uint8_t
527 RtlEqualUnicodeString(unicode_string *str1, unicode_string *str2,
528         uint8_t caseinsensitive)
529 {
530         int                     i;
531
532         if (str1->us_len != str2->us_len)
533                 return (FALSE);
534
535         for (i = 0; i < str1->us_len; i++) {
536                 if (caseinsensitive == TRUE) {
537                         if (toupper((char)(str1->us_buf[i] & 0xFF)) !=
538                             toupper((char)(str2->us_buf[i] & 0xFF)))
539                                 return (FALSE);
540                 } else {
541                         if (str1->us_buf[i] != str2->us_buf[i])
542                                 return (FALSE);
543                 }
544         }
545
546         return (TRUE);
547 }
548
549 static void
550 RtlCopyString(dst, src)
551         ansi_string             *dst;
552         const ansi_string       *src;
553 {
554         if (src != NULL && src->as_buf != NULL && dst->as_buf != NULL) {
555                 dst->as_len = min(src->as_len, dst->as_maxlen);
556                 memcpy(dst->as_buf, src->as_buf, dst->as_len);
557                 if (dst->as_len < dst->as_maxlen)
558                         dst->as_buf[dst->as_len] = 0;
559         } else
560                 dst->as_len = 0;
561 }
562
563 static void
564 RtlCopyUnicodeString(dest, src)
565         unicode_string          *dest;
566         unicode_string          *src;
567 {
568
569         if (dest->us_maxlen >= src->us_len)
570                 dest->us_len = src->us_len;
571         else
572                 dest->us_len = dest->us_maxlen;
573         memcpy(dest->us_buf, src->us_buf, dest->us_len);
574 }
575
576 static void
577 ntoskrnl_ascii_to_unicode(ascii, unicode, len)
578         char                    *ascii;
579         uint16_t                *unicode;
580         int                     len;
581 {
582         int                     i;
583         uint16_t                *ustr;
584
585         ustr = unicode;
586         for (i = 0; i < len; i++) {
587                 *ustr = (uint16_t)ascii[i];
588                 ustr++;
589         }
590 }
591
592 static void
593 ntoskrnl_unicode_to_ascii(unicode, ascii, len)
594         uint16_t                *unicode;
595         char                    *ascii;
596         int                     len;
597 {
598         int                     i;
599         uint8_t                 *astr;
600
601         astr = ascii;
602         for (i = 0; i < len / 2; i++) {
603                 *astr = (uint8_t)unicode[i];
604                 astr++;
605         }
606 }
607
608 uint32_t
609 RtlUnicodeStringToAnsiString(ansi_string *dest, unicode_string *src, uint8_t allocate)
610 {
611         if (dest == NULL || src == NULL)
612                 return (STATUS_INVALID_PARAMETER);
613
614         dest->as_len = src->us_len / 2;
615         if (dest->as_maxlen < dest->as_len)
616                 dest->as_len = dest->as_maxlen;
617
618         if (allocate == TRUE) {
619                 dest->as_buf = ExAllocatePoolWithTag(NonPagedPool,
620                     (src->us_len / 2) + 1, 0);
621                 if (dest->as_buf == NULL)
622                         return (STATUS_INSUFFICIENT_RESOURCES);
623                 dest->as_len = dest->as_maxlen = src->us_len / 2;
624         } else {
625                 dest->as_len = src->us_len / 2; /* XXX */
626                 if (dest->as_maxlen < dest->as_len)
627                         dest->as_len = dest->as_maxlen;
628         }
629
630         ntoskrnl_unicode_to_ascii(src->us_buf, dest->as_buf,
631             dest->as_len * 2);
632
633         return (STATUS_SUCCESS);
634 }
635
636 uint32_t
637 RtlAnsiStringToUnicodeString(unicode_string *dest, ansi_string *src,
638         uint8_t allocate)
639 {
640         if (dest == NULL || src == NULL)
641                 return (STATUS_INVALID_PARAMETER);
642
643         if (allocate == TRUE) {
644                 dest->us_buf = ExAllocatePoolWithTag(NonPagedPool,
645                     src->as_len * 2, 0);
646                 if (dest->us_buf == NULL)
647                         return (STATUS_INSUFFICIENT_RESOURCES);
648                 dest->us_len = dest->us_maxlen = strlen(src->as_buf) * 2;
649         } else {
650                 dest->us_len = src->as_len * 2; /* XXX */
651                 if (dest->us_maxlen < dest->us_len)
652                         dest->us_len = dest->us_maxlen;
653         }
654
655         ntoskrnl_ascii_to_unicode(src->as_buf, dest->us_buf,
656             dest->us_len / 2);
657
658         return (STATUS_SUCCESS);
659 }
660
661 void *
662 ExAllocatePoolWithTag(pooltype, len, tag)
663         uint32_t                pooltype;
664         size_t                  len;
665         uint32_t                tag;
666 {
667         void                    *buf;
668
669         buf = malloc(len, M_DEVBUF, M_NOWAIT|M_ZERO);
670         if (buf == NULL)
671                 return (NULL);
672
673         return (buf);
674 }
675
676 static void
677 ExFreePoolWithTag(buf, tag)
678         void            *buf;
679         uint32_t        tag;
680 {
681         ExFreePool(buf);
682 }
683
684 void
685 ExFreePool(buf)
686         void                    *buf;
687 {
688         free(buf, M_DEVBUF);
689 }
690
691 uint32_t
692 IoAllocateDriverObjectExtension(drv, clid, extlen, ext)
693         driver_object           *drv;
694         void                    *clid;
695         uint32_t                extlen;
696         void                    **ext;
697 {
698         custom_extension        *ce;
699
700         ce = ExAllocatePoolWithTag(NonPagedPool, sizeof(custom_extension)
701             + extlen, 0);
702
703         if (ce == NULL)
704                 return (STATUS_INSUFFICIENT_RESOURCES);
705
706         ce->ce_clid = clid;
707         InsertTailList((&drv->dro_driverext->dre_usrext), (&ce->ce_list));
708
709         *ext = (void *)(ce + 1);
710
711         return (STATUS_SUCCESS);
712 }
713
714 void *
715 IoGetDriverObjectExtension(drv, clid)
716         driver_object           *drv;
717         void                    *clid;
718 {
719         list_entry              *e;
720         custom_extension        *ce;
721
722         /*
723          * Sanity check. Our dummy bus drivers don't have
724          * any driver extentions.
725          */
726
727         if (drv->dro_driverext == NULL)
728                 return (NULL);
729
730         e = drv->dro_driverext->dre_usrext.nle_flink;
731         while (e != &drv->dro_driverext->dre_usrext) {
732                 ce = (custom_extension *)e;
733                 if (ce->ce_clid == clid)
734                         return ((void *)(ce + 1));
735                 e = e->nle_flink;
736         }
737
738         return (NULL);
739 }
740
741
742 uint32_t
743 IoCreateDevice(driver_object *drv, uint32_t devextlen, unicode_string *devname,
744         uint32_t devtype, uint32_t devchars, uint8_t exclusive,
745         device_object **newdev)
746 {
747         device_object           *dev;
748
749         dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device_object), 0);
750         if (dev == NULL)
751                 return (STATUS_INSUFFICIENT_RESOURCES);
752
753         dev->do_type = devtype;
754         dev->do_drvobj = drv;
755         dev->do_currirp = NULL;
756         dev->do_flags = 0;
757
758         if (devextlen) {
759                 dev->do_devext = ExAllocatePoolWithTag(NonPagedPool,
760                     devextlen, 0);
761
762                 if (dev->do_devext == NULL) {
763                         ExFreePool(dev);
764                         return (STATUS_INSUFFICIENT_RESOURCES);
765                 }
766
767                 bzero(dev->do_devext, devextlen);
768         } else
769                 dev->do_devext = NULL;
770
771         dev->do_size = sizeof(device_object) + devextlen;
772         dev->do_refcnt = 1;
773         dev->do_attacheddev = NULL;
774         dev->do_nextdev = NULL;
775         dev->do_devtype = devtype;
776         dev->do_stacksize = 1;
777         dev->do_alignreq = 1;
778         dev->do_characteristics = devchars;
779         dev->do_iotimer = NULL;
780         KeInitializeEvent(&dev->do_devlock, EVENT_TYPE_SYNC, TRUE);
781
782         /*
783          * Vpd is used for disk/tape devices,
784          * but we don't support those. (Yet.)
785          */
786         dev->do_vpb = NULL;
787
788         dev->do_devobj_ext = ExAllocatePoolWithTag(NonPagedPool,
789             sizeof(devobj_extension), 0);
790
791         if (dev->do_devobj_ext == NULL) {
792                 if (dev->do_devext != NULL)
793                         ExFreePool(dev->do_devext);
794                 ExFreePool(dev);
795                 return (STATUS_INSUFFICIENT_RESOURCES);
796         }
797
798         dev->do_devobj_ext->dve_type = 0;
799         dev->do_devobj_ext->dve_size = sizeof(devobj_extension);
800         dev->do_devobj_ext->dve_devobj = dev;
801
802         /*
803          * Attach this device to the driver object's list
804          * of devices. Note: this is not the same as attaching
805          * the device to the device stack. The driver's AddDevice
806          * routine must explicitly call IoAddDeviceToDeviceStack()
807          * to do that.
808          */
809
810         if (drv->dro_devobj == NULL) {
811                 drv->dro_devobj = dev;
812                 dev->do_nextdev = NULL;
813         } else {
814                 dev->do_nextdev = drv->dro_devobj;
815                 drv->dro_devobj = dev;
816         }
817
818         *newdev = dev;
819
820         return (STATUS_SUCCESS);
821 }
822
823 void
824 IoDeleteDevice(dev)
825         device_object           *dev;
826 {
827         device_object           *prev;
828
829         if (dev == NULL)
830                 return;
831
832         if (dev->do_devobj_ext != NULL)
833                 ExFreePool(dev->do_devobj_ext);
834
835         if (dev->do_devext != NULL)
836                 ExFreePool(dev->do_devext);
837
838         /* Unlink the device from the driver's device list. */
839
840         prev = dev->do_drvobj->dro_devobj;
841         if (prev == dev)
842                 dev->do_drvobj->dro_devobj = dev->do_nextdev;
843         else {
844                 while (prev->do_nextdev != dev)
845                         prev = prev->do_nextdev;
846                 prev->do_nextdev = dev->do_nextdev;
847         }
848
849         ExFreePool(dev);
850 }
851
852 device_object *
853 IoGetAttachedDevice(dev)
854         device_object           *dev;
855 {
856         device_object           *d;
857
858         if (dev == NULL)
859                 return (NULL);
860
861         d = dev;
862
863         while (d->do_attacheddev != NULL)
864                 d = d->do_attacheddev;
865
866         return (d);
867 }
868
869 static irp *
870 IoBuildSynchronousFsdRequest(func, dobj, buf, len, off, event, status)
871         uint32_t                func;
872         device_object           *dobj;
873         void                    *buf;
874         uint32_t                len;
875         uint64_t                *off;
876         nt_kevent               *event;
877         io_status_block         *status;
878 {
879         irp                     *ip;
880
881         ip = IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status);
882         if (ip == NULL)
883                 return (NULL);
884         ip->irp_usrevent = event;
885
886         return (ip);
887 }
888
889 static irp *
890 IoBuildAsynchronousFsdRequest(func, dobj, buf, len, off, status)
891         uint32_t                func;
892         device_object           *dobj;
893         void                    *buf;
894         uint32_t                len;
895         uint64_t                *off;
896         io_status_block         *status;
897 {
898         irp                     *ip;
899         io_stack_location       *sl;
900
901         ip = IoAllocateIrp(dobj->do_stacksize, TRUE);
902         if (ip == NULL)
903                 return (NULL);
904
905         ip->irp_usriostat = status;
906         ip->irp_tail.irp_overlay.irp_thread = NULL;
907
908         sl = IoGetNextIrpStackLocation(ip);
909         sl->isl_major = func;
910         sl->isl_minor = 0;
911         sl->isl_flags = 0;
912         sl->isl_ctl = 0;
913         sl->isl_devobj = dobj;
914         sl->isl_fileobj = NULL;
915         sl->isl_completionfunc = NULL;
916
917         ip->irp_userbuf = buf;
918
919         if (dobj->do_flags & DO_BUFFERED_IO) {
920                 ip->irp_assoc.irp_sysbuf =
921                     ExAllocatePoolWithTag(NonPagedPool, len, 0);
922                 if (ip->irp_assoc.irp_sysbuf == NULL) {
923                         IoFreeIrp(ip);
924                         return (NULL);
925                 }
926                 bcopy(buf, ip->irp_assoc.irp_sysbuf, len);
927         }
928
929         if (dobj->do_flags & DO_DIRECT_IO) {
930                 ip->irp_mdl = IoAllocateMdl(buf, len, FALSE, FALSE, ip);
931                 if (ip->irp_mdl == NULL) {
932                         if (ip->irp_assoc.irp_sysbuf != NULL)
933                                 ExFreePool(ip->irp_assoc.irp_sysbuf);
934                         IoFreeIrp(ip);
935                         return (NULL);
936                 }
937                 ip->irp_userbuf = NULL;
938                 ip->irp_assoc.irp_sysbuf = NULL;
939         }
940
941         if (func == IRP_MJ_READ) {
942                 sl->isl_parameters.isl_read.isl_len = len;
943                 if (off != NULL)
944                         sl->isl_parameters.isl_read.isl_byteoff = *off;
945                 else
946                         sl->isl_parameters.isl_read.isl_byteoff = 0;
947         }
948
949         if (func == IRP_MJ_WRITE) {
950                 sl->isl_parameters.isl_write.isl_len = len;
951                 if (off != NULL)
952                         sl->isl_parameters.isl_write.isl_byteoff = *off;
953                 else
954                         sl->isl_parameters.isl_write.isl_byteoff = 0;
955         }
956
957         return (ip);
958 }
959
960 static irp *
961 IoBuildDeviceIoControlRequest(uint32_t iocode, device_object *dobj, void *ibuf,
962         uint32_t ilen, void *obuf, uint32_t olen, uint8_t isinternal,
963         nt_kevent *event, io_status_block *status)
964 {
965         irp                     *ip;
966         io_stack_location       *sl;
967         uint32_t                buflen;
968
969         ip = IoAllocateIrp(dobj->do_stacksize, TRUE);
970         if (ip == NULL)
971                 return (NULL);
972         ip->irp_usrevent = event;
973         ip->irp_usriostat = status;
974         ip->irp_tail.irp_overlay.irp_thread = NULL;
975
976         sl = IoGetNextIrpStackLocation(ip);
977         sl->isl_major = isinternal == TRUE ?
978             IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL;
979         sl->isl_minor = 0;
980         sl->isl_flags = 0;
981         sl->isl_ctl = 0;
982         sl->isl_devobj = dobj;
983         sl->isl_fileobj = NULL;
984         sl->isl_completionfunc = NULL;
985         sl->isl_parameters.isl_ioctl.isl_iocode = iocode;
986         sl->isl_parameters.isl_ioctl.isl_ibuflen = ilen;
987         sl->isl_parameters.isl_ioctl.isl_obuflen = olen;
988
989         switch(IO_METHOD(iocode)) {
990         case METHOD_BUFFERED:
991                 if (ilen > olen)
992                         buflen = ilen;
993                 else
994                         buflen = olen;
995                 if (buflen) {
996                         ip->irp_assoc.irp_sysbuf =
997                             ExAllocatePoolWithTag(NonPagedPool, buflen, 0);
998                         if (ip->irp_assoc.irp_sysbuf == NULL) {
999                                 IoFreeIrp(ip);
1000                                 return (NULL);
1001                         }
1002                 }
1003                 if (ilen && ibuf != NULL) {
1004                         bcopy(ibuf, ip->irp_assoc.irp_sysbuf, ilen);
1005                         bzero((char *)ip->irp_assoc.irp_sysbuf + ilen,
1006                             buflen - ilen);
1007                 } else
1008                         bzero(ip->irp_assoc.irp_sysbuf, ilen);
1009                 ip->irp_userbuf = obuf;
1010                 break;
1011         case METHOD_IN_DIRECT:
1012         case METHOD_OUT_DIRECT:
1013                 if (ilen && ibuf != NULL) {
1014                         ip->irp_assoc.irp_sysbuf =
1015                             ExAllocatePoolWithTag(NonPagedPool, ilen, 0);
1016                         if (ip->irp_assoc.irp_sysbuf == NULL) {
1017                                 IoFreeIrp(ip);
1018                                 return (NULL);
1019                         }
1020                         bcopy(ibuf, ip->irp_assoc.irp_sysbuf, ilen);
1021                 }
1022                 if (olen && obuf != NULL) {
1023                         ip->irp_mdl = IoAllocateMdl(obuf, olen,
1024                             FALSE, FALSE, ip);
1025                         /*
1026                          * Normally we would MmProbeAndLockPages()
1027                          * here, but we don't have to in our
1028                          * imlementation.
1029                          */
1030                 }
1031                 break;
1032         case METHOD_NEITHER:
1033                 ip->irp_userbuf = obuf;
1034                 sl->isl_parameters.isl_ioctl.isl_type3ibuf = ibuf;
1035                 break;
1036         default:
1037                 break;
1038         }
1039
1040         /*
1041          * Ideally, we should associate this IRP with the calling
1042          * thread here.
1043          */
1044
1045         return (ip);
1046 }
1047
1048 static irp *
1049 IoAllocateIrp(uint8_t stsize, uint8_t chargequota)
1050 {
1051         irp                     *i;
1052
1053         i = ExAllocatePoolWithTag(NonPagedPool, IoSizeOfIrp(stsize), 0);
1054         if (i == NULL)
1055                 return (NULL);
1056
1057         IoInitializeIrp(i, IoSizeOfIrp(stsize), stsize);
1058
1059         return (i);
1060 }
1061
1062 static irp *
1063 IoMakeAssociatedIrp(irp *ip, uint8_t stsize)
1064 {
1065         irp                     *associrp;
1066
1067         associrp = IoAllocateIrp(stsize, FALSE);
1068         if (associrp == NULL)
1069                 return (NULL);
1070
1071         mtx_lock(&ntoskrnl_dispatchlock);
1072         associrp->irp_flags |= IRP_ASSOCIATED_IRP;
1073         associrp->irp_tail.irp_overlay.irp_thread =
1074             ip->irp_tail.irp_overlay.irp_thread;
1075         associrp->irp_assoc.irp_master = ip;
1076         mtx_unlock(&ntoskrnl_dispatchlock);
1077
1078         return (associrp);
1079 }
1080
1081 static void
1082 IoFreeIrp(ip)
1083         irp                     *ip;
1084 {
1085         ExFreePool(ip);
1086 }
1087
1088 static void
1089 IoInitializeIrp(irp *io, uint16_t psize, uint8_t ssize)
1090 {
1091         bzero((char *)io, IoSizeOfIrp(ssize));
1092         io->irp_size = psize;
1093         io->irp_stackcnt = ssize;
1094         io->irp_currentstackloc = ssize;
1095         InitializeListHead(&io->irp_thlist);
1096         io->irp_tail.irp_overlay.irp_csl =
1097             (io_stack_location *)(io + 1) + ssize;
1098 }
1099
1100 static void
1101 IoReuseIrp(ip, status)
1102         irp                     *ip;
1103         uint32_t                status;
1104 {
1105         uint8_t                 allocflags;
1106
1107         allocflags = ip->irp_allocflags;
1108         IoInitializeIrp(ip, ip->irp_size, ip->irp_stackcnt);
1109         ip->irp_iostat.isb_status = status;
1110         ip->irp_allocflags = allocflags;
1111 }
1112
1113 void
1114 IoAcquireCancelSpinLock(uint8_t *irql)
1115 {
1116         KeAcquireSpinLock(&ntoskrnl_cancellock, irql);
1117 }
1118
1119 void
1120 IoReleaseCancelSpinLock(uint8_t irql)
1121 {
1122         KeReleaseSpinLock(&ntoskrnl_cancellock, irql);
1123 }
1124
1125 uint8_t
1126 IoCancelIrp(irp *ip)
1127 {
1128         cancel_func             cfunc;
1129         uint8_t                 cancelirql;
1130
1131         IoAcquireCancelSpinLock(&cancelirql);
1132         cfunc = IoSetCancelRoutine(ip, NULL);
1133         ip->irp_cancel = TRUE;
1134         if (cfunc == NULL) {
1135                 IoReleaseCancelSpinLock(cancelirql);
1136                 return (FALSE);
1137         }
1138         ip->irp_cancelirql = cancelirql;
1139         MSCALL2(cfunc, IoGetCurrentIrpStackLocation(ip)->isl_devobj, ip);
1140         return (uint8_t)IoSetCancelValue(ip, TRUE);
1141 }
1142
1143 uint32_t
1144 IofCallDriver(dobj, ip)
1145         device_object           *dobj;
1146         irp                     *ip;
1147 {
1148         driver_object           *drvobj;
1149         io_stack_location       *sl;
1150         uint32_t                status;
1151         driver_dispatch         disp;
1152
1153         drvobj = dobj->do_drvobj;
1154
1155         if (ip->irp_currentstackloc <= 0)
1156                 panic("IoCallDriver(): out of stack locations");
1157
1158         IoSetNextIrpStackLocation(ip);
1159         sl = IoGetCurrentIrpStackLocation(ip);
1160
1161         sl->isl_devobj = dobj;
1162
1163         disp = drvobj->dro_dispatch[sl->isl_major];
1164         status = MSCALL2(disp, dobj, ip);
1165
1166         return (status);
1167 }
1168
1169 void
1170 IofCompleteRequest(irp *ip, uint8_t prioboost)
1171 {
1172         uint32_t                status;
1173         device_object           *dobj;
1174         io_stack_location       *sl;
1175         completion_func         cf;
1176
1177         KASSERT(ip->irp_iostat.isb_status != STATUS_PENDING,
1178             ("incorrect IRP(%p) status (STATUS_PENDING)", ip));
1179
1180         sl = IoGetCurrentIrpStackLocation(ip);
1181         IoSkipCurrentIrpStackLocation(ip);
1182
1183         do {
1184                 if (sl->isl_ctl & SL_PENDING_RETURNED)
1185                         ip->irp_pendingreturned = TRUE;
1186
1187                 if (ip->irp_currentstackloc != (ip->irp_stackcnt + 1))
1188                         dobj = IoGetCurrentIrpStackLocation(ip)->isl_devobj;
1189                 else
1190                         dobj = NULL;
1191
1192                 if (sl->isl_completionfunc != NULL &&
1193                     ((ip->irp_iostat.isb_status == STATUS_SUCCESS &&
1194                     sl->isl_ctl & SL_INVOKE_ON_SUCCESS) ||
1195                     (ip->irp_iostat.isb_status != STATUS_SUCCESS &&
1196                     sl->isl_ctl & SL_INVOKE_ON_ERROR) ||
1197                     (ip->irp_cancel == TRUE &&
1198                     sl->isl_ctl & SL_INVOKE_ON_CANCEL))) {
1199                         cf = sl->isl_completionfunc;
1200                         status = MSCALL3(cf, dobj, ip, sl->isl_completionctx);
1201                         if (status == STATUS_MORE_PROCESSING_REQUIRED)
1202                                 return;
1203                 } else {
1204                         if ((ip->irp_currentstackloc <= ip->irp_stackcnt) &&
1205                             (ip->irp_pendingreturned == TRUE))
1206                                 IoMarkIrpPending(ip);
1207                 }
1208
1209                 /* move to the next.  */
1210                 IoSkipCurrentIrpStackLocation(ip);
1211                 sl++;
1212         } while (ip->irp_currentstackloc <= (ip->irp_stackcnt + 1));
1213
1214         if (ip->irp_usriostat != NULL)
1215                 *ip->irp_usriostat = ip->irp_iostat;
1216         if (ip->irp_usrevent != NULL)
1217                 KeSetEvent(ip->irp_usrevent, prioboost, FALSE);
1218
1219         /* Handle any associated IRPs. */
1220
1221         if (ip->irp_flags & IRP_ASSOCIATED_IRP) {
1222                 uint32_t                masterirpcnt;
1223                 irp                     *masterirp;
1224                 mdl                     *m;
1225
1226                 masterirp = ip->irp_assoc.irp_master;
1227                 masterirpcnt =
1228                     InterlockedDecrement(&masterirp->irp_assoc.irp_irpcnt);
1229
1230                 while ((m = ip->irp_mdl) != NULL) {
1231                         ip->irp_mdl = m->mdl_next;
1232                         IoFreeMdl(m);
1233                 }
1234                 IoFreeIrp(ip);
1235                 if (masterirpcnt == 0)
1236                         IoCompleteRequest(masterirp, IO_NO_INCREMENT);
1237                 return;
1238         }
1239
1240         /* With any luck, these conditions will never arise. */
1241
1242         if (ip->irp_flags & IRP_PAGING_IO) {
1243                 if (ip->irp_mdl != NULL)
1244                         IoFreeMdl(ip->irp_mdl);
1245                 IoFreeIrp(ip);
1246         }
1247 }
1248
1249 void
1250 ntoskrnl_intr(arg)
1251         void                    *arg;
1252 {
1253         kinterrupt              *iobj;
1254         uint8_t                 irql;
1255         uint8_t                 claimed;
1256         list_entry              *l;
1257
1258         KeAcquireSpinLock(&ntoskrnl_intlock, &irql);
1259         l = ntoskrnl_intlist.nle_flink;
1260         while (l != &ntoskrnl_intlist) {
1261                 iobj = CONTAINING_RECORD(l, kinterrupt, ki_list);
1262                 claimed = MSCALL2(iobj->ki_svcfunc, iobj, iobj->ki_svcctx);
1263                 if (claimed == TRUE)
1264                         break;
1265                 l = l->nle_flink;
1266         }
1267         KeReleaseSpinLock(&ntoskrnl_intlock, irql);
1268 }
1269
1270 uint8_t
1271 KeAcquireInterruptSpinLock(iobj)
1272         kinterrupt              *iobj;
1273 {
1274         uint8_t                 irql;
1275         KeAcquireSpinLock(&ntoskrnl_intlock, &irql);
1276         return (irql);
1277 }
1278
1279 void
1280 KeReleaseInterruptSpinLock(kinterrupt *iobj, uint8_t irql)
1281 {
1282         KeReleaseSpinLock(&ntoskrnl_intlock, irql);
1283 }
1284
1285 uint8_t
1286 KeSynchronizeExecution(iobj, syncfunc, syncctx)
1287         kinterrupt              *iobj;
1288         void                    *syncfunc;
1289         void                    *syncctx;
1290 {
1291         uint8_t                 irql;
1292
1293         KeAcquireSpinLock(&ntoskrnl_intlock, &irql);
1294         MSCALL1(syncfunc, syncctx);
1295         KeReleaseSpinLock(&ntoskrnl_intlock, irql);
1296
1297         return (TRUE);
1298 }
1299
1300 /*
1301  * IoConnectInterrupt() is passed only the interrupt vector and
1302  * irql that a device wants to use, but no device-specific tag
1303  * of any kind. This conflicts rather badly with FreeBSD's
1304  * bus_setup_intr(), which needs the device_t for the device
1305  * requesting interrupt delivery. In order to bypass this
1306  * inconsistency, we implement a second level of interrupt
1307  * dispatching on top of bus_setup_intr(). All devices use
1308  * ntoskrnl_intr() as their ISR, and any device requesting
1309  * interrupts will be registered with ntoskrnl_intr()'s interrupt
1310  * dispatch list. When an interrupt arrives, we walk the list
1311  * and invoke all the registered ISRs. This effectively makes all
1312  * interrupts shared, but it's the only way to duplicate the
1313  * semantics of IoConnectInterrupt() and IoDisconnectInterrupt() properly.
1314  */
1315
1316 uint32_t
1317 IoConnectInterrupt(kinterrupt **iobj, void *svcfunc, void *svcctx,
1318         kspin_lock *lock, uint32_t vector, uint8_t irql, uint8_t syncirql,
1319         uint8_t imode, uint8_t shared, uint32_t affinity, uint8_t savefloat)
1320 {
1321         uint8_t                 curirql;
1322
1323         *iobj = ExAllocatePoolWithTag(NonPagedPool, sizeof(kinterrupt), 0);
1324         if (*iobj == NULL)
1325                 return (STATUS_INSUFFICIENT_RESOURCES);
1326
1327         (*iobj)->ki_svcfunc = svcfunc;
1328         (*iobj)->ki_svcctx = svcctx;
1329
1330         if (lock == NULL) {
1331                 KeInitializeSpinLock(&(*iobj)->ki_lock_priv);
1332                 (*iobj)->ki_lock = &(*iobj)->ki_lock_priv;
1333         } else
1334                 (*iobj)->ki_lock = lock;
1335
1336         KeAcquireSpinLock(&ntoskrnl_intlock, &curirql);
1337         InsertHeadList((&ntoskrnl_intlist), (&(*iobj)->ki_list));
1338         KeReleaseSpinLock(&ntoskrnl_intlock, curirql);
1339
1340         return (STATUS_SUCCESS);
1341 }
1342
1343 void
1344 IoDisconnectInterrupt(iobj)
1345         kinterrupt              *iobj;
1346 {
1347         uint8_t                 irql;
1348
1349         if (iobj == NULL)
1350                 return;
1351
1352         KeAcquireSpinLock(&ntoskrnl_intlock, &irql);
1353         RemoveEntryList((&iobj->ki_list));
1354         KeReleaseSpinLock(&ntoskrnl_intlock, irql);
1355
1356         ExFreePool(iobj);
1357 }
1358
1359 device_object *
1360 IoAttachDeviceToDeviceStack(src, dst)
1361         device_object           *src;
1362         device_object           *dst;
1363 {
1364         device_object           *attached;
1365
1366         mtx_lock(&ntoskrnl_dispatchlock);
1367         attached = IoGetAttachedDevice(dst);
1368         attached->do_attacheddev = src;
1369         src->do_attacheddev = NULL;
1370         src->do_stacksize = attached->do_stacksize + 1;
1371         mtx_unlock(&ntoskrnl_dispatchlock);
1372
1373         return (attached);
1374 }
1375
1376 void
1377 IoDetachDevice(topdev)
1378         device_object           *topdev;
1379 {
1380         device_object           *tail;
1381
1382         mtx_lock(&ntoskrnl_dispatchlock);
1383
1384         /* First, break the chain. */
1385         tail = topdev->do_attacheddev;
1386         if (tail == NULL) {
1387                 mtx_unlock(&ntoskrnl_dispatchlock);
1388                 return;
1389         }
1390         topdev->do_attacheddev = tail->do_attacheddev;
1391         topdev->do_refcnt--;
1392
1393         /* Now reduce the stacksize count for the takm_il objects. */
1394
1395         tail = topdev->do_attacheddev;
1396         while (tail != NULL) {
1397                 tail->do_stacksize--;
1398                 tail = tail->do_attacheddev;
1399         }
1400
1401         mtx_unlock(&ntoskrnl_dispatchlock);
1402 }
1403
1404 /*
1405  * For the most part, an object is considered signalled if
1406  * dh_sigstate == TRUE. The exception is for mutant objects
1407  * (mutexes), where the logic works like this:
1408  *
1409  * - If the thread already owns the object and sigstate is
1410  *   less than or equal to 0, then the object is considered
1411  *   signalled (recursive acquisition).
1412  * - If dh_sigstate == 1, the object is also considered
1413  *   signalled.
1414  */
1415
1416 static int
1417 ntoskrnl_is_signalled(obj, td)
1418         nt_dispatch_header      *obj;
1419         struct thread           *td;
1420 {
1421         kmutant                 *km;
1422
1423         if (obj->dh_type == DISP_TYPE_MUTANT) {
1424                 km = (kmutant *)obj;
1425                 if ((obj->dh_sigstate <= 0 && km->km_ownerthread == td) ||
1426                     obj->dh_sigstate == 1)
1427                         return (TRUE);
1428                 return (FALSE);
1429         }
1430
1431         if (obj->dh_sigstate > 0)
1432                 return (TRUE);
1433         return (FALSE);
1434 }
1435
1436 static void
1437 ntoskrnl_satisfy_wait(obj, td)
1438         nt_dispatch_header      *obj;
1439         struct thread           *td;
1440 {
1441         kmutant                 *km;
1442
1443         switch (obj->dh_type) {
1444         case DISP_TYPE_MUTANT:
1445                 km = (struct kmutant *)obj;
1446                 obj->dh_sigstate--;
1447                 /*
1448                  * If sigstate reaches 0, the mutex is now
1449                  * non-signalled (the new thread owns it).
1450                  */
1451                 if (obj->dh_sigstate == 0) {
1452                         km->km_ownerthread = td;
1453                         if (km->km_abandoned == TRUE)
1454                                 km->km_abandoned = FALSE;
1455                 }
1456                 break;
1457         /* Synchronization objects get reset to unsignalled. */
1458         case DISP_TYPE_SYNCHRONIZATION_EVENT:
1459         case DISP_TYPE_SYNCHRONIZATION_TIMER:
1460                 obj->dh_sigstate = 0;
1461                 break;
1462         case DISP_TYPE_SEMAPHORE:
1463                 obj->dh_sigstate--;
1464                 break;
1465         default:
1466                 break;
1467         }
1468 }
1469
1470 static void
1471 ntoskrnl_satisfy_multiple_waits(wb)
1472         wait_block              *wb;
1473 {
1474         wait_block              *cur;
1475         struct thread           *td;
1476
1477         cur = wb;
1478         td = wb->wb_kthread;
1479
1480         do {
1481                 ntoskrnl_satisfy_wait(wb->wb_object, td);
1482                 cur->wb_awakened = TRUE;
1483                 cur = cur->wb_next;
1484         } while (cur != wb);
1485 }
1486
1487 /* Always called with dispatcher lock held. */
1488 static void
1489 ntoskrnl_waittest(obj, increment)
1490         nt_dispatch_header      *obj;
1491         uint32_t                increment;
1492 {
1493         wait_block              *w, *next;
1494         list_entry              *e;
1495         struct thread           *td;
1496         wb_ext                  *we;
1497         int                     satisfied;
1498
1499         /*
1500          * Once an object has been signalled, we walk its list of
1501          * wait blocks. If a wait block can be awakened, then satisfy
1502          * waits as necessary and wake the thread.
1503          *
1504          * The rules work like this:
1505          *
1506          * If a wait block is marked as WAITTYPE_ANY, then
1507          * we can satisfy the wait conditions on the current
1508          * object and wake the thread right away. Satisfying
1509          * the wait also has the effect of breaking us out
1510          * of the search loop.
1511          *
1512          * If the object is marked as WAITTYLE_ALL, then the
1513          * wait block will be part of a circularly linked
1514          * list of wait blocks belonging to a waiting thread
1515          * that's sleeping in KeWaitForMultipleObjects(). In
1516          * order to wake the thread, all the objects in the
1517          * wait list must be in the signalled state. If they
1518          * are, we then satisfy all of them and wake the
1519          * thread.
1520          *
1521          */
1522
1523         e = obj->dh_waitlisthead.nle_flink;
1524
1525         while (e != &obj->dh_waitlisthead && obj->dh_sigstate > 0) {
1526                 w = CONTAINING_RECORD(e, wait_block, wb_waitlist);
1527                 we = w->wb_ext;
1528                 td = we->we_td;
1529                 satisfied = FALSE;
1530                 if (w->wb_waittype == WAITTYPE_ANY) {
1531                         /*
1532                          * Thread can be awakened if
1533                          * any wait is satisfied.
1534                          */
1535                         ntoskrnl_satisfy_wait(obj, td);
1536                         satisfied = TRUE;
1537                         w->wb_awakened = TRUE;
1538                 } else {
1539                         /*
1540                          * Thread can only be woken up
1541                          * if all waits are satisfied.
1542                          * If the thread is waiting on multiple
1543                          * objects, they should all be linked
1544                          * through the wb_next pointers in the
1545                          * wait blocks.
1546                          */
1547                         satisfied = TRUE;
1548                         next = w->wb_next;
1549                         while (next != w) {
1550                                 if (ntoskrnl_is_signalled(obj, td) == FALSE) {
1551                                         satisfied = FALSE;
1552                                         break;
1553                                 }
1554                                 next = next->wb_next;
1555                         }
1556                         ntoskrnl_satisfy_multiple_waits(w);
1557                 }
1558
1559                 if (satisfied == TRUE)
1560                         cv_broadcastpri(&we->we_cv,
1561                             (w->wb_oldpri - (increment * 4)) > PRI_MIN_KERN ?
1562                             w->wb_oldpri - (increment * 4) : PRI_MIN_KERN);
1563
1564                 e = e->nle_flink;
1565         }
1566 }
1567
1568 /*
1569  * Return the number of 100 nanosecond intervals since
1570  * January 1, 1601. (?!?!)
1571  */
1572 void
1573 ntoskrnl_time(tval)
1574         uint64_t                *tval;
1575 {
1576         struct timespec         ts;
1577
1578         nanotime(&ts);
1579         *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
1580             11644473600 * 10000000; /* 100ns ticks from 1601 to 1970 */
1581 }
1582
1583 static void
1584 KeQuerySystemTime(current_time)
1585         uint64_t                *current_time;
1586 {
1587         ntoskrnl_time(current_time);
1588 }
1589
1590 static uint32_t
1591 KeTickCount(void)
1592 {
1593         struct timeval tv;
1594         getmicrouptime(&tv);
1595         return tvtohz(&tv);
1596 }
1597
1598
1599 /*
1600  * KeWaitForSingleObject() is a tricky beast, because it can be used
1601  * with several different object types: semaphores, timers, events,
1602  * mutexes and threads. Semaphores don't appear very often, but the
1603  * other object types are quite common. KeWaitForSingleObject() is
1604  * what's normally used to acquire a mutex, and it can be used to
1605  * wait for a thread termination.
1606  *
1607  * The Windows NDIS API is implemented in terms of Windows kernel
1608  * primitives, and some of the object manipulation is duplicated in
1609  * NDIS. For example, NDIS has timers and events, which are actually
1610  * Windows kevents and ktimers. Now, you're supposed to only use the
1611  * NDIS variants of these objects within the confines of the NDIS API,
1612  * but there are some naughty developers out there who will use
1613  * KeWaitForSingleObject() on NDIS timer and event objects, so we
1614  * have to support that as well. Conseqently, our NDIS timer and event
1615  * code has to be closely tied into our ntoskrnl timer and event code,
1616  * just as it is in Windows.
1617  *
1618  * KeWaitForSingleObject() may do different things for different kinds
1619  * of objects:
1620  *
1621  * - For events, we check if the event has been signalled. If the
1622  *   event is already in the signalled state, we just return immediately,
1623  *   otherwise we wait for it to be set to the signalled state by someone
1624  *   else calling KeSetEvent(). Events can be either synchronization or
1625  *   notification events.
1626  *
1627  * - For timers, if the timer has already fired and the timer is in
1628  *   the signalled state, we just return, otherwise we wait on the
1629  *   timer. Unlike an event, timers get signalled automatically when
1630  *   they expire rather than someone having to trip them manually.
1631  *   Timers initialized with KeInitializeTimer() are always notification
1632  *   events: KeInitializeTimerEx() lets you initialize a timer as
1633  *   either a notification or synchronization event.
1634  *
1635  * - For mutexes, we try to acquire the mutex and if we can't, we wait
1636  *   on the mutex until it's available and then grab it. When a mutex is
1637  *   released, it enters the signalled state, which wakes up one of the
1638  *   threads waiting to acquire it. Mutexes are always synchronization
1639  *   events.
1640  *
1641  * - For threads, the only thing we do is wait until the thread object
1642  *   enters a signalled state, which occurs when the thread terminates.
1643  *   Threads are always notification events.
1644  *
1645  * A notification event wakes up all threads waiting on an object. A
1646  * synchronization event wakes up just one. Also, a synchronization event
1647  * is auto-clearing, which means we automatically set the event back to
1648  * the non-signalled state once the wakeup is done.
1649  */
1650
1651 uint32_t
1652 KeWaitForSingleObject(void *arg, uint32_t reason, uint32_t mode,
1653     uint8_t alertable, int64_t *duetime)
1654 {
1655         wait_block              w;
1656         struct thread           *td = curthread;
1657         struct timeval          tv;
1658         int                     error = 0;
1659         uint64_t                curtime;
1660         wb_ext                  we;
1661         nt_dispatch_header      *obj;
1662
1663         obj = arg;
1664
1665         if (obj == NULL)
1666                 return (STATUS_INVALID_PARAMETER);
1667
1668         mtx_lock(&ntoskrnl_dispatchlock);
1669
1670         cv_init(&we.we_cv, "KeWFS");
1671         we.we_td = td;
1672
1673         /*
1674          * Check to see if this object is already signalled,
1675          * and just return without waiting if it is.
1676          */
1677         if (ntoskrnl_is_signalled(obj, td) == TRUE) {
1678                 /* Sanity check the signal state value. */
1679                 if (obj->dh_sigstate != INT32_MIN) {
1680                         ntoskrnl_satisfy_wait(obj, curthread);
1681                         mtx_unlock(&ntoskrnl_dispatchlock);
1682                         return (STATUS_SUCCESS);
1683                 } else {
1684                         /*
1685                          * There's a limit to how many times we can
1686                          * recursively acquire a mutant. If we hit
1687                          * the limit, something is very wrong.
1688                          */
1689                         if (obj->dh_type == DISP_TYPE_MUTANT) {
1690                                 mtx_unlock(&ntoskrnl_dispatchlock);
1691                                 panic("mutant limit exceeded");
1692                         }
1693                 }
1694         }
1695
1696         bzero((char *)&w, sizeof(wait_block));
1697         w.wb_object = obj;
1698         w.wb_ext = &we;
1699         w.wb_waittype = WAITTYPE_ANY;
1700         w.wb_next = &w;
1701         w.wb_waitkey = 0;
1702         w.wb_awakened = FALSE;
1703         w.wb_oldpri = td->td_priority;
1704
1705         InsertTailList((&obj->dh_waitlisthead), (&w.wb_waitlist));
1706
1707         /*
1708          * The timeout value is specified in 100 nanosecond units
1709          * and can be a positive or negative number. If it's positive,
1710          * then the duetime is absolute, and we need to convert it
1711          * to an absolute offset relative to now in order to use it.
1712          * If it's negative, then the duetime is relative and we
1713          * just have to convert the units.
1714          */
1715
1716         if (duetime != NULL) {
1717                 if (*duetime < 0) {
1718                         tv.tv_sec = - (*duetime) / 10000000;
1719                         tv.tv_usec = (- (*duetime) / 10) -
1720                             (tv.tv_sec * 1000000);
1721                 } else {
1722                         ntoskrnl_time(&curtime);
1723                         if (*duetime < curtime)
1724                                 tv.tv_sec = tv.tv_usec = 0;
1725                         else {
1726                                 tv.tv_sec = ((*duetime) - curtime) / 10000000;
1727                                 tv.tv_usec = ((*duetime) - curtime) / 10 -
1728                                     (tv.tv_sec * 1000000);
1729                         }
1730                 }
1731         }
1732
1733         if (duetime == NULL)
1734                 cv_wait(&we.we_cv, &ntoskrnl_dispatchlock);
1735         else
1736                 error = cv_timedwait(&we.we_cv,
1737                     &ntoskrnl_dispatchlock, tvtohz(&tv));
1738
1739         RemoveEntryList(&w.wb_waitlist);
1740
1741         cv_destroy(&we.we_cv);
1742
1743         /* We timed out. Leave the object alone and return status. */
1744
1745         if (error == EWOULDBLOCK) {
1746                 mtx_unlock(&ntoskrnl_dispatchlock);
1747                 return (STATUS_TIMEOUT);
1748         }
1749
1750         mtx_unlock(&ntoskrnl_dispatchlock);
1751
1752         return (STATUS_SUCCESS);
1753 /*
1754         return (KeWaitForMultipleObjects(1, &obj, WAITTYPE_ALL, reason,
1755             mode, alertable, duetime, &w));
1756 */
1757 }
1758
1759 static uint32_t
1760 KeWaitForMultipleObjects(uint32_t cnt, nt_dispatch_header *obj[], uint32_t wtype,
1761         uint32_t reason, uint32_t mode, uint8_t alertable, int64_t *duetime,
1762         wait_block *wb_array)
1763 {
1764         struct thread           *td = curthread;
1765         wait_block              *whead, *w;
1766         wait_block              _wb_array[MAX_WAIT_OBJECTS];
1767         nt_dispatch_header      *cur;
1768         struct timeval          tv;
1769         int                     i, wcnt = 0, error = 0;
1770         uint64_t                curtime;
1771         struct timespec         t1, t2;
1772         uint32_t                status = STATUS_SUCCESS;
1773         wb_ext                  we;
1774
1775         if (cnt > MAX_WAIT_OBJECTS)
1776                 return (STATUS_INVALID_PARAMETER);
1777         if (cnt > THREAD_WAIT_OBJECTS && wb_array == NULL)
1778                 return (STATUS_INVALID_PARAMETER);
1779
1780         mtx_lock(&ntoskrnl_dispatchlock);
1781
1782         cv_init(&we.we_cv, "KeWFM");
1783         we.we_td = td;
1784
1785         if (wb_array == NULL)
1786                 whead = _wb_array;
1787         else
1788                 whead = wb_array;
1789
1790         bzero((char *)whead, sizeof(wait_block) * cnt);
1791
1792         /* First pass: see if we can satisfy any waits immediately. */
1793
1794         wcnt = 0;
1795         w = whead;
1796
1797         for (i = 0; i < cnt; i++) {
1798                 InsertTailList((&obj[i]->dh_waitlisthead),
1799                     (&w->wb_waitlist));
1800                 w->wb_ext = &we;
1801                 w->wb_object = obj[i];
1802                 w->wb_waittype = wtype;
1803                 w->wb_waitkey = i;
1804                 w->wb_awakened = FALSE;
1805                 w->wb_oldpri = td->td_priority;
1806                 w->wb_next = w + 1;
1807                 w++;
1808                 wcnt++;
1809                 if (ntoskrnl_is_signalled(obj[i], td)) {
1810                         /*
1811                          * There's a limit to how many times
1812                          * we can recursively acquire a mutant.
1813                          * If we hit the limit, something
1814                          * is very wrong.
1815                          */
1816                         if (obj[i]->dh_sigstate == INT32_MIN &&
1817                             obj[i]->dh_type == DISP_TYPE_MUTANT) {
1818                                 mtx_unlock(&ntoskrnl_dispatchlock);
1819                                 panic("mutant limit exceeded");
1820                         }
1821
1822                         /*
1823                          * If this is a WAITTYPE_ANY wait, then
1824                          * satisfy the waited object and exit
1825                          * right now.
1826                          */
1827
1828                         if (wtype == WAITTYPE_ANY) {
1829                                 ntoskrnl_satisfy_wait(obj[i], td);
1830                                 status = STATUS_WAIT_0 + i;
1831                                 goto wait_done;
1832                         } else {
1833                                 w--;
1834                                 wcnt--;
1835                                 w->wb_object = NULL;
1836                                 RemoveEntryList(&w->wb_waitlist);
1837                         }
1838                 }
1839         }
1840
1841         /*
1842          * If this is a WAITTYPE_ALL wait and all objects are
1843          * already signalled, satisfy the waits and exit now.
1844          */
1845
1846         if (wtype == WAITTYPE_ALL && wcnt == 0) {
1847                 for (i = 0; i < cnt; i++)
1848                         ntoskrnl_satisfy_wait(obj[i], td);
1849                 status = STATUS_SUCCESS;
1850                 goto wait_done;
1851         }
1852
1853         /*
1854          * Create a circular waitblock list. The waitcount
1855          * must always be non-zero when we get here.
1856          */
1857
1858         (w - 1)->wb_next = whead;
1859
1860         /* Wait on any objects that aren't yet signalled. */
1861
1862         /* Calculate timeout, if any. */
1863
1864         if (duetime != NULL) {
1865                 if (*duetime < 0) {
1866                         tv.tv_sec = - (*duetime) / 10000000;
1867                         tv.tv_usec = (- (*duetime) / 10) -
1868                             (tv.tv_sec * 1000000);
1869                 } else {
1870                         ntoskrnl_time(&curtime);
1871                         if (*duetime < curtime)
1872                                 tv.tv_sec = tv.tv_usec = 0;
1873                         else {
1874                                 tv.tv_sec = ((*duetime) - curtime) / 10000000;
1875                                 tv.tv_usec = ((*duetime) - curtime) / 10 -
1876                                     (tv.tv_sec * 1000000);
1877                         }
1878                 }
1879         }
1880
1881         while (wcnt) {
1882                 nanotime(&t1);
1883
1884                 if (duetime == NULL)
1885                         cv_wait(&we.we_cv, &ntoskrnl_dispatchlock);
1886                 else
1887                         error = cv_timedwait(&we.we_cv,
1888                             &ntoskrnl_dispatchlock, tvtohz(&tv));
1889
1890                 /* Wait with timeout expired. */
1891
1892                 if (error) {
1893                         status = STATUS_TIMEOUT;
1894                         goto wait_done;
1895                 }
1896
1897                 nanotime(&t2);
1898
1899                 /* See what's been signalled. */
1900
1901                 w = whead;
1902                 do {
1903                         cur = w->wb_object;
1904                         if (ntoskrnl_is_signalled(cur, td) == TRUE ||
1905                             w->wb_awakened == TRUE) {
1906                                 /* Sanity check the signal state value. */
1907                                 if (cur->dh_sigstate == INT32_MIN &&
1908                                     cur->dh_type == DISP_TYPE_MUTANT) {
1909                                         mtx_unlock(&ntoskrnl_dispatchlock);
1910                                         panic("mutant limit exceeded");
1911                                 }
1912                                 wcnt--;
1913                                 if (wtype == WAITTYPE_ANY) {
1914                                         status = w->wb_waitkey &
1915                                             STATUS_WAIT_0;
1916                                         goto wait_done;
1917                                 }
1918                         }
1919                         w = w->wb_next;
1920                 } while (w != whead);
1921
1922                 /*
1923                  * If all objects have been signalled, or if this
1924                  * is a WAITTYPE_ANY wait and we were woke up by
1925                  * someone, we can bail.
1926                  */
1927
1928                 if (wcnt == 0) {
1929                         status = STATUS_SUCCESS;
1930                         goto wait_done;
1931                 }
1932
1933                 /*
1934                  * If this is WAITTYPE_ALL wait, and there's still
1935                  * objects that haven't been signalled, deduct the
1936                  * time that's elapsed so far from the timeout and
1937                  * wait again (or continue waiting indefinitely if
1938                  * there's no timeout).
1939                  */
1940
1941                 if (duetime != NULL) {
1942                         tv.tv_sec -= (t2.tv_sec - t1.tv_sec);
1943                         tv.tv_usec -= (t2.tv_nsec - t1.tv_nsec) / 1000;
1944                 }
1945         }
1946
1947
1948 wait_done:
1949
1950         cv_destroy(&we.we_cv);
1951
1952         for (i = 0; i < cnt; i++) {
1953                 if (whead[i].wb_object != NULL)
1954                         RemoveEntryList(&whead[i].wb_waitlist);
1955
1956         }
1957         mtx_unlock(&ntoskrnl_dispatchlock);
1958
1959         return (status);
1960 }
1961
1962 static void
1963 WRITE_REGISTER_USHORT(uint16_t *reg, uint16_t val)
1964 {
1965         bus_space_write_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
1966 }
1967
1968 static uint16_t
1969 READ_REGISTER_USHORT(reg)
1970         uint16_t                *reg;
1971 {
1972         return (bus_space_read_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
1973 }
1974
1975 static void
1976 WRITE_REGISTER_ULONG(reg, val)
1977         uint32_t                *reg;
1978         uint32_t                val;
1979 {
1980         bus_space_write_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
1981 }
1982
1983 static uint32_t
1984 READ_REGISTER_ULONG(reg)
1985         uint32_t                *reg;
1986 {
1987         return (bus_space_read_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
1988 }
1989
1990 static uint8_t
1991 READ_REGISTER_UCHAR(uint8_t *reg)
1992 {
1993         return (bus_space_read_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
1994 }
1995
1996 static void
1997 WRITE_REGISTER_UCHAR(uint8_t *reg, uint8_t val)
1998 {
1999         bus_space_write_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
2000 }
2001
2002 static int64_t
2003 _allmul(a, b)
2004         int64_t                 a;
2005         int64_t                 b;
2006 {
2007         return (a * b);
2008 }
2009
2010 static int64_t
2011 _alldiv(a, b)
2012         int64_t                 a;
2013         int64_t                 b;
2014 {
2015         return (a / b);
2016 }
2017
2018 static int64_t
2019 _allrem(a, b)
2020         int64_t                 a;
2021         int64_t                 b;
2022 {
2023         return (a % b);
2024 }
2025
2026 static uint64_t
2027 _aullmul(a, b)
2028         uint64_t                a;
2029         uint64_t                b;
2030 {
2031         return (a * b);
2032 }
2033
2034 static uint64_t
2035 _aulldiv(a, b)
2036         uint64_t                a;
2037         uint64_t                b;
2038 {
2039         return (a / b);
2040 }
2041
2042 static uint64_t
2043 _aullrem(a, b)
2044         uint64_t                a;
2045         uint64_t                b;
2046 {
2047         return (a % b);
2048 }
2049
2050 static int64_t
2051 _allshl(int64_t a, uint8_t b)
2052 {
2053         return (a << b);
2054 }
2055
2056 static uint64_t
2057 _aullshl(uint64_t a, uint8_t b)
2058 {
2059         return (a << b);
2060 }
2061
2062 static int64_t
2063 _allshr(int64_t a, uint8_t b)
2064 {
2065         return (a >> b);
2066 }
2067
2068 static uint64_t
2069 _aullshr(uint64_t a, uint8_t b)
2070 {
2071         return (a >> b);
2072 }
2073
2074 static slist_entry *
2075 ntoskrnl_pushsl(head, entry)
2076         slist_header            *head;
2077         slist_entry             *entry;
2078 {
2079         slist_entry             *oldhead;
2080
2081         oldhead = head->slh_list.slh_next;
2082         entry->sl_next = head->slh_list.slh_next;
2083         head->slh_list.slh_next = entry;
2084         head->slh_list.slh_depth++;
2085         head->slh_list.slh_seq++;
2086
2087         return (oldhead);
2088 }
2089
2090 static void
2091 InitializeSListHead(head)
2092         slist_header            *head;
2093 {
2094         memset(head, 0, sizeof(*head));
2095 }
2096
2097 static slist_entry *
2098 ntoskrnl_popsl(head)
2099         slist_header            *head;
2100 {
2101         slist_entry             *first;
2102
2103         first = head->slh_list.slh_next;
2104         if (first != NULL) {
2105                 head->slh_list.slh_next = first->sl_next;
2106                 head->slh_list.slh_depth--;
2107                 head->slh_list.slh_seq++;
2108         }
2109
2110         return (first);
2111 }
2112
2113 /*
2114  * We need this to make lookaside lists work for amd64.
2115  * We pass a pointer to ExAllocatePoolWithTag() the lookaside
2116  * list structure. For amd64 to work right, this has to be a
2117  * pointer to the wrapped version of the routine, not the
2118  * original. Letting the Windows driver invoke the original
2119  * function directly will result in a convention calling
2120  * mismatch and a pretty crash. On x86, this effectively
2121  * becomes a no-op since ipt_func and ipt_wrap are the same.
2122  */
2123
2124 static funcptr
2125 ntoskrnl_findwrap(func)
2126         funcptr                 func;
2127 {
2128         image_patch_table       *patch;
2129
2130         patch = ntoskrnl_functbl;
2131         while (patch->ipt_func != NULL) {
2132                 if ((funcptr)patch->ipt_func == func)
2133                         return ((funcptr)patch->ipt_wrap);
2134                 patch++;
2135         }
2136
2137         return (NULL);
2138 }
2139
2140 static void
2141 ExInitializePagedLookasideList(paged_lookaside_list *lookaside,
2142         lookaside_alloc_func *allocfunc, lookaside_free_func *freefunc,
2143         uint32_t flags, size_t size, uint32_t tag, uint16_t depth)
2144 {
2145         bzero((char *)lookaside, sizeof(paged_lookaside_list));
2146
2147         if (size < sizeof(slist_entry))
2148                 lookaside->nll_l.gl_size = sizeof(slist_entry);
2149         else
2150                 lookaside->nll_l.gl_size = size;
2151         lookaside->nll_l.gl_tag = tag;
2152         if (allocfunc == NULL)
2153                 lookaside->nll_l.gl_allocfunc =
2154                     ntoskrnl_findwrap((funcptr)ExAllocatePoolWithTag);
2155         else
2156                 lookaside->nll_l.gl_allocfunc = allocfunc;
2157
2158         if (freefunc == NULL)
2159                 lookaside->nll_l.gl_freefunc =
2160                     ntoskrnl_findwrap((funcptr)ExFreePool);
2161         else
2162                 lookaside->nll_l.gl_freefunc = freefunc;
2163
2164 #ifdef __i386__
2165         KeInitializeSpinLock(&lookaside->nll_obsoletelock);
2166 #endif
2167
2168         lookaside->nll_l.gl_type = NonPagedPool;
2169         lookaside->nll_l.gl_depth = depth;
2170         lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
2171 }
2172
2173 static void
2174 ExDeletePagedLookasideList(lookaside)
2175         paged_lookaside_list   *lookaside;
2176 {
2177         void                    *buf;
2178         void            (*freefunc)(void *);
2179
2180         freefunc = lookaside->nll_l.gl_freefunc;
2181         while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
2182                 MSCALL1(freefunc, buf);
2183 }
2184
2185 static void
2186 ExInitializeNPagedLookasideList(npaged_lookaside_list *lookaside,
2187         lookaside_alloc_func *allocfunc, lookaside_free_func *freefunc,
2188         uint32_t flags, size_t size, uint32_t tag, uint16_t depth)
2189 {
2190         bzero((char *)lookaside, sizeof(npaged_lookaside_list));
2191
2192         if (size < sizeof(slist_entry))
2193                 lookaside->nll_l.gl_size = sizeof(slist_entry);
2194         else
2195                 lookaside->nll_l.gl_size = size;
2196         lookaside->nll_l.gl_tag = tag;
2197         if (allocfunc == NULL)
2198                 lookaside->nll_l.gl_allocfunc =
2199                     ntoskrnl_findwrap((funcptr)ExAllocatePoolWithTag);
2200         else
2201                 lookaside->nll_l.gl_allocfunc = allocfunc;
2202
2203         if (freefunc == NULL)
2204                 lookaside->nll_l.gl_freefunc =
2205                     ntoskrnl_findwrap((funcptr)ExFreePool);
2206         else
2207                 lookaside->nll_l.gl_freefunc = freefunc;
2208
2209 #ifdef __i386__
2210         KeInitializeSpinLock(&lookaside->nll_obsoletelock);
2211 #endif
2212
2213         lookaside->nll_l.gl_type = NonPagedPool;
2214         lookaside->nll_l.gl_depth = depth;
2215         lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
2216 }
2217
2218 static void
2219 ExDeleteNPagedLookasideList(lookaside)
2220         npaged_lookaside_list   *lookaside;
2221 {
2222         void                    *buf;
2223         void            (*freefunc)(void *);
2224
2225         freefunc = lookaside->nll_l.gl_freefunc;
2226         while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
2227                 MSCALL1(freefunc, buf);
2228 }
2229
2230 slist_entry *
2231 InterlockedPushEntrySList(head, entry)
2232         slist_header            *head;
2233         slist_entry             *entry;
2234 {
2235         slist_entry             *oldhead;
2236
2237         mtx_lock_spin(&ntoskrnl_interlock);
2238         oldhead = ntoskrnl_pushsl(head, entry);
2239         mtx_unlock_spin(&ntoskrnl_interlock);
2240
2241         return (oldhead);
2242 }
2243
2244 slist_entry *
2245 InterlockedPopEntrySList(head)
2246         slist_header            *head;
2247 {
2248         slist_entry             *first;
2249
2250         mtx_lock_spin(&ntoskrnl_interlock);
2251         first = ntoskrnl_popsl(head);
2252         mtx_unlock_spin(&ntoskrnl_interlock);
2253
2254         return (first);
2255 }
2256
2257 static slist_entry *
2258 ExInterlockedPushEntrySList(head, entry, lock)
2259         slist_header            *head;
2260         slist_entry             *entry;
2261         kspin_lock              *lock;
2262 {
2263         return (InterlockedPushEntrySList(head, entry));
2264 }
2265
2266 static slist_entry *
2267 ExInterlockedPopEntrySList(head, lock)
2268         slist_header            *head;
2269         kspin_lock              *lock;
2270 {
2271         return (InterlockedPopEntrySList(head));
2272 }
2273
2274 uint16_t
2275 ExQueryDepthSList(head)
2276         slist_header            *head;
2277 {
2278         uint16_t                depth;
2279
2280         mtx_lock_spin(&ntoskrnl_interlock);
2281         depth = head->slh_list.slh_depth;
2282         mtx_unlock_spin(&ntoskrnl_interlock);
2283
2284         return (depth);
2285 }
2286
2287 void
2288 KeInitializeSpinLock(lock)
2289         kspin_lock              *lock;
2290 {
2291         *lock = 0;
2292 }
2293
2294 #ifdef __i386__
2295 void
2296 KefAcquireSpinLockAtDpcLevel(lock)
2297         kspin_lock              *lock;
2298 {
2299 #ifdef NTOSKRNL_DEBUG_SPINLOCKS
2300         int                     i = 0;
2301 #endif
2302
2303         while (atomic_cmpset_acq_int((volatile u_int *)lock, 0, 1) == 0) {
2304                 /* sit and spin */;
2305 #ifdef NTOSKRNL_DEBUG_SPINLOCKS
2306                 i++;
2307                 if (i > 200000000)
2308                         panic("DEADLOCK!");
2309 #endif
2310         }
2311 }
2312
2313 void
2314 KefReleaseSpinLockFromDpcLevel(lock)
2315         kspin_lock              *lock;
2316 {
2317         atomic_store_rel_int((volatile u_int *)lock, 0);
2318 }
2319
2320 uint8_t
2321 KeAcquireSpinLockRaiseToDpc(kspin_lock *lock)
2322 {
2323         uint8_t                 oldirql;
2324
2325         if (KeGetCurrentIrql() > DISPATCH_LEVEL)
2326                 panic("IRQL_NOT_LESS_THAN_OR_EQUAL");
2327
2328         KeRaiseIrql(DISPATCH_LEVEL, &oldirql);
2329         KeAcquireSpinLockAtDpcLevel(lock);
2330
2331         return (oldirql);
2332 }
2333 #else
2334 void
2335 KeAcquireSpinLockAtDpcLevel(kspin_lock *lock)
2336 {
2337         while (atomic_cmpset_acq_int((volatile u_int *)lock, 0, 1) == 0)
2338                 /* sit and spin */;
2339 }
2340
2341 void
2342 KeReleaseSpinLockFromDpcLevel(kspin_lock *lock)
2343 {
2344         atomic_store_rel_int((volatile u_int *)lock, 0);
2345 }
2346 #endif /* __i386__ */
2347
2348 uintptr_t
2349 InterlockedExchange(dst, val)
2350         volatile uint32_t       *dst;
2351         uintptr_t               val;
2352 {
2353         uintptr_t               r;
2354
2355         mtx_lock_spin(&ntoskrnl_interlock);
2356         r = *dst;
2357         *dst = val;
2358         mtx_unlock_spin(&ntoskrnl_interlock);
2359
2360         return (r);
2361 }
2362
2363 static uint32_t
2364 InterlockedIncrement(addend)
2365         volatile uint32_t       *addend;
2366 {
2367         atomic_add_long((volatile u_long *)addend, 1);
2368         return (*addend);
2369 }
2370
2371 static uint32_t
2372 InterlockedDecrement(addend)
2373         volatile uint32_t       *addend;
2374 {
2375         atomic_subtract_long((volatile u_long *)addend, 1);
2376         return (*addend);
2377 }
2378
2379 static void
2380 ExInterlockedAddLargeStatistic(addend, inc)
2381         uint64_t                *addend;
2382         uint32_t                inc;
2383 {
2384         mtx_lock_spin(&ntoskrnl_interlock);
2385         *addend += inc;
2386         mtx_unlock_spin(&ntoskrnl_interlock);
2387 };
2388
2389 mdl *
2390 IoAllocateMdl(void *vaddr, uint32_t len, uint8_t secondarybuf,
2391         uint8_t chargequota, irp *iopkt)
2392 {
2393         mdl                     *m;
2394         int                     zone = 0;
2395
2396         if (MmSizeOfMdl(vaddr, len) > MDL_ZONE_SIZE)
2397                 m = ExAllocatePoolWithTag(NonPagedPool,
2398                     MmSizeOfMdl(vaddr, len), 0);
2399         else {
2400                 m = uma_zalloc(mdl_zone, M_NOWAIT | M_ZERO);
2401                 zone++;
2402         }
2403
2404         if (m == NULL)
2405                 return (NULL);
2406
2407         MmInitializeMdl(m, vaddr, len);
2408
2409         /*
2410          * MmInitializMdl() clears the flags field, so we
2411          * have to set this here. If the MDL came from the
2412          * MDL UMA zone, tag it so we can release it to
2413          * the right place later.
2414          */
2415         if (zone)
2416                 m->mdl_flags = MDL_ZONE_ALLOCED;
2417
2418         if (iopkt != NULL) {
2419                 if (secondarybuf == TRUE) {
2420                         mdl                     *last;
2421                         last = iopkt->irp_mdl;
2422                         while (last->mdl_next != NULL)
2423                                 last = last->mdl_next;
2424                         last->mdl_next = m;
2425                 } else {
2426                         if (iopkt->irp_mdl != NULL)
2427                                 panic("leaking an MDL in IoAllocateMdl()");
2428                         iopkt->irp_mdl = m;
2429                 }
2430         }
2431
2432         return (m);
2433 }
2434
2435 void
2436 IoFreeMdl(m)
2437         mdl                     *m;
2438 {
2439         if (m == NULL)
2440                 return;
2441
2442         if (m->mdl_flags & MDL_ZONE_ALLOCED)
2443                 uma_zfree(mdl_zone, m);
2444         else
2445                 ExFreePool(m);
2446 }
2447
2448 static void *
2449 MmAllocateContiguousMemory(size, highest)
2450         uint32_t                size;
2451         uint64_t                highest;
2452 {
2453         void *addr;
2454         size_t pagelength = roundup(size, PAGE_SIZE);
2455
2456         addr = ExAllocatePoolWithTag(NonPagedPool, pagelength, 0);
2457
2458         return (addr);
2459 }
2460
2461 static void *
2462 MmAllocateContiguousMemorySpecifyCache(size, lowest, highest,
2463     boundary, cachetype)
2464         uint32_t                size;
2465         uint64_t                lowest;
2466         uint64_t                highest;
2467         uint64_t                boundary;
2468         enum nt_caching_type    cachetype;
2469 {
2470         vm_memattr_t            memattr;
2471         void                    *ret;
2472
2473         switch (cachetype) {
2474         case MmNonCached:
2475                 memattr = VM_MEMATTR_UNCACHEABLE;
2476                 break;
2477         case MmWriteCombined:
2478                 memattr = VM_MEMATTR_WRITE_COMBINING;
2479                 break;
2480         case MmNonCachedUnordered:
2481                 memattr = VM_MEMATTR_UNCACHEABLE;
2482                 break;
2483         case MmCached:
2484         case MmHardwareCoherentCached:
2485         case MmUSWCCached:
2486         default:
2487                 memattr = VM_MEMATTR_DEFAULT;
2488                 break;
2489         }
2490
2491         ret = (void *)kmem_alloc_contig(kernel_map, size, M_ZERO | M_NOWAIT,
2492             lowest, highest, PAGE_SIZE, boundary, memattr);
2493         if (ret != NULL)
2494                 malloc_type_allocated(M_DEVBUF, round_page(size));
2495         return (ret);
2496 }
2497
2498 static void
2499 MmFreeContiguousMemory(base)
2500         void                    *base;
2501 {
2502         ExFreePool(base);
2503 }
2504
2505 static void
2506 MmFreeContiguousMemorySpecifyCache(base, size, cachetype)
2507         void                    *base;
2508         uint32_t                size;
2509         enum nt_caching_type    cachetype;
2510 {
2511         contigfree(base, size, M_DEVBUF);
2512 }
2513
2514 static uint32_t
2515 MmSizeOfMdl(vaddr, len)
2516         void                    *vaddr;
2517         size_t                  len;
2518 {
2519         uint32_t                l;
2520
2521         l = sizeof(struct mdl) +
2522             (sizeof(vm_offset_t *) * SPAN_PAGES(vaddr, len));
2523
2524         return (l);
2525 }
2526
2527 /*
2528  * The Microsoft documentation says this routine fills in the
2529  * page array of an MDL with the _physical_ page addresses that
2530  * comprise the buffer, but we don't really want to do that here.
2531  * Instead, we just fill in the page array with the kernel virtual
2532  * addresses of the buffers.
2533  */
2534 void
2535 MmBuildMdlForNonPagedPool(m)
2536         mdl                     *m;
2537 {
2538         vm_offset_t             *mdl_pages;
2539         int                     pagecnt, i;
2540
2541         pagecnt = SPAN_PAGES(m->mdl_byteoffset, m->mdl_bytecount);
2542
2543         if (pagecnt > (m->mdl_size - sizeof(mdl)) / sizeof(vm_offset_t *))
2544                 panic("not enough pages in MDL to describe buffer");
2545
2546         mdl_pages = MmGetMdlPfnArray(m);
2547
2548         for (i = 0; i < pagecnt; i++)
2549                 *mdl_pages = (vm_offset_t)m->mdl_startva + (i * PAGE_SIZE);
2550
2551         m->mdl_flags |= MDL_SOURCE_IS_NONPAGED_POOL;
2552         m->mdl_mappedsystemva = MmGetMdlVirtualAddress(m);
2553 }
2554
2555 static void *
2556 MmMapLockedPages(mdl *buf, uint8_t accessmode)
2557 {
2558         buf->mdl_flags |= MDL_MAPPED_TO_SYSTEM_VA;
2559         return (MmGetMdlVirtualAddress(buf));
2560 }
2561
2562 static void *
2563 MmMapLockedPagesSpecifyCache(mdl *buf, uint8_t accessmode, uint32_t cachetype,
2564         void *vaddr, uint32_t bugcheck, uint32_t prio)
2565 {
2566         return (MmMapLockedPages(buf, accessmode));
2567 }
2568
2569 static void
2570 MmUnmapLockedPages(vaddr, buf)
2571         void                    *vaddr;
2572         mdl                     *buf;
2573 {
2574         buf->mdl_flags &= ~MDL_MAPPED_TO_SYSTEM_VA;
2575 }
2576
2577 /*
2578  * This function has a problem in that it will break if you
2579  * compile this module without PAE and try to use it on a PAE
2580  * kernel. Unfortunately, there's no way around this at the
2581  * moment. It's slightly less broken that using pmap_kextract().
2582  * You'd think the virtual memory subsystem would help us out
2583  * here, but it doesn't.
2584  */
2585
2586 static uint64_t
2587 MmGetPhysicalAddress(void *base)
2588 {
2589         return (pmap_extract(kernel_map->pmap, (vm_offset_t)base));
2590 }
2591
2592 void *
2593 MmGetSystemRoutineAddress(ustr)
2594         unicode_string          *ustr;
2595 {
2596         ansi_string             astr;
2597
2598         if (RtlUnicodeStringToAnsiString(&astr, ustr, TRUE))
2599                 return (NULL);
2600         return (ndis_get_routine_address(ntoskrnl_functbl, astr.as_buf));
2601 }
2602
2603 uint8_t
2604 MmIsAddressValid(vaddr)
2605         void                    *vaddr;
2606 {
2607         if (pmap_extract(kernel_map->pmap, (vm_offset_t)vaddr))
2608                 return (TRUE);
2609
2610         return (FALSE);
2611 }
2612
2613 void *
2614 MmMapIoSpace(paddr, len, cachetype)
2615         uint64_t                paddr;
2616         uint32_t                len;
2617         uint32_t                cachetype;
2618 {
2619         devclass_t              nexus_class;
2620         device_t                *nexus_devs, devp;
2621         int                     nexus_count = 0;
2622         device_t                matching_dev = NULL;
2623         struct resource         *res;
2624         int                     i;
2625         vm_offset_t             v;
2626
2627         /* There will always be at least one nexus. */
2628
2629         nexus_class = devclass_find("nexus");
2630         devclass_get_devices(nexus_class, &nexus_devs, &nexus_count);
2631
2632         for (i = 0; i < nexus_count; i++) {
2633                 devp = nexus_devs[i];
2634                 matching_dev = ntoskrnl_finddev(devp, paddr, &res);
2635                 if (matching_dev)
2636                         break;
2637         }
2638
2639         free(nexus_devs, M_TEMP);
2640
2641         if (matching_dev == NULL)
2642                 return (NULL);
2643
2644         v = (vm_offset_t)rman_get_virtual(res);
2645         if (paddr > rman_get_start(res))
2646                 v += paddr - rman_get_start(res);
2647
2648         return ((void *)v);
2649 }
2650
2651 void
2652 MmUnmapIoSpace(vaddr, len)
2653         void                    *vaddr;
2654         size_t                  len;
2655 {
2656 }
2657
2658
2659 static device_t
2660 ntoskrnl_finddev(dev, paddr, res)
2661         device_t                dev;
2662         uint64_t                paddr;
2663         struct resource         **res;
2664 {
2665         device_t                *children = NULL;
2666         device_t                matching_dev;
2667         int                     childcnt;
2668         struct resource         *r;
2669         struct resource_list    *rl;
2670         struct resource_list_entry      *rle;
2671         uint32_t                flags;
2672         int                     i;
2673
2674         /* We only want devices that have been successfully probed. */
2675
2676         if (device_is_alive(dev) == FALSE)
2677                 return (NULL);
2678
2679         rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
2680         if (rl != NULL) {
2681                 STAILQ_FOREACH(rle, rl, link) {
2682                         r = rle->res;
2683
2684                         if (r == NULL)
2685                                 continue;
2686
2687                         flags = rman_get_flags(r);
2688
2689                         if (rle->type == SYS_RES_MEMORY &&
2690                             paddr >= rman_get_start(r) &&
2691                             paddr <= rman_get_end(r)) {
2692                                 if (!(flags & RF_ACTIVE))
2693                                         bus_activate_resource(dev,
2694                                             SYS_RES_MEMORY, 0, r);
2695                                 *res = r;
2696                                 return (dev);
2697                         }
2698                 }
2699         }
2700
2701         /*
2702          * If this device has children, do another
2703          * level of recursion to inspect them.
2704          */
2705
2706         device_get_children(dev, &children, &childcnt);
2707
2708         for (i = 0; i < childcnt; i++) {
2709                 matching_dev = ntoskrnl_finddev(children[i], paddr, res);
2710                 if (matching_dev != NULL) {
2711                         free(children, M_TEMP);
2712                         return (matching_dev);
2713                 }
2714         }
2715
2716
2717         /* Won't somebody please think of the children! */
2718
2719         if (children != NULL)
2720                 free(children, M_TEMP);
2721
2722         return (NULL);
2723 }
2724
2725 /*
2726  * Workitems are unlike DPCs, in that they run in a user-mode thread
2727  * context rather than at DISPATCH_LEVEL in kernel context. In our
2728  * case we run them in kernel context anyway.
2729  */
2730 static void
2731 ntoskrnl_workitem_thread(arg)
2732         void                    *arg;
2733 {
2734         kdpc_queue              *kq;
2735         list_entry              *l;
2736         io_workitem             *iw;
2737         uint8_t                 irql;
2738
2739         kq = arg;
2740
2741         InitializeListHead(&kq->kq_disp);
2742         kq->kq_td = curthread;
2743         kq->kq_exit = 0;
2744         KeInitializeSpinLock(&kq->kq_lock);
2745         KeInitializeEvent(&kq->kq_proc, EVENT_TYPE_SYNC, FALSE);
2746
2747         while (1) {
2748                 KeWaitForSingleObject(&kq->kq_proc, 0, 0, TRUE, NULL);
2749
2750                 KeAcquireSpinLock(&kq->kq_lock, &irql);
2751
2752                 if (kq->kq_exit) {
2753                         kq->kq_exit = 0;
2754                         KeReleaseSpinLock(&kq->kq_lock, irql);
2755                         break;
2756                 }
2757
2758                 while (!IsListEmpty(&kq->kq_disp)) {
2759                         l = RemoveHeadList(&kq->kq_disp);
2760                         iw = CONTAINING_RECORD(l,
2761                             io_workitem, iw_listentry);
2762                         InitializeListHead((&iw->iw_listentry));
2763                         if (iw->iw_func == NULL)
2764                                 continue;
2765                         KeReleaseSpinLock(&kq->kq_lock, irql);
2766                         MSCALL2(iw->iw_func, iw->iw_dobj, iw->iw_ctx);
2767                         KeAcquireSpinLock(&kq->kq_lock, &irql);
2768                 }
2769
2770                 KeReleaseSpinLock(&kq->kq_lock, irql);
2771         }
2772
2773         kproc_exit(0);
2774         return; /* notreached */
2775 }
2776
2777 static ndis_status
2778 RtlCharToInteger(src, base, val)
2779         const char              *src;
2780         uint32_t                base;
2781         uint32_t                *val;
2782 {
2783         int negative = 0;
2784         uint32_t res;
2785
2786         if (!src || !val)
2787                 return (STATUS_ACCESS_VIOLATION);
2788         while (*src != '\0' && *src <= ' ')
2789                 src++;
2790         if (*src == '+')
2791                 src++;
2792         else if (*src == '-') {
2793                 src++;
2794                 negative = 1;
2795         }
2796         if (base == 0) {
2797                 base = 10;
2798                 if (*src == '0') {
2799                         src++;
2800                         if (*src == 'b') {
2801                                 base = 2;
2802                                 src++;
2803                         } else if (*src == 'o') {
2804                                 base = 8;
2805                                 src++;
2806                         } else if (*src == 'x') {
2807                                 base = 16;
2808                                 src++;
2809                         }
2810                 }
2811         } else if (!(base == 2 || base == 8 || base == 10 || base == 16))
2812                 return (STATUS_INVALID_PARAMETER);
2813
2814         for (res = 0; *src; src++) {
2815                 int v;
2816                 if (isdigit(*src))
2817                         v = *src - '0';
2818                 else if (isxdigit(*src))
2819                         v = tolower(*src) - 'a' + 10;
2820                 else
2821                         v = base;
2822                 if (v >= base)
2823                         return (STATUS_INVALID_PARAMETER);
2824                 res = res * base + v;
2825         }
2826         *val = negative ? -res : res;
2827         return (STATUS_SUCCESS);
2828 }
2829
2830 static void
2831 ntoskrnl_destroy_workitem_threads(void)
2832 {
2833         kdpc_queue              *kq;
2834         int                     i;
2835
2836         for (i = 0; i < WORKITEM_THREADS; i++) {
2837                 kq = wq_queues + i;
2838                 kq->kq_exit = 1;
2839                 KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
2840                 while (kq->kq_exit)
2841                         tsleep(kq->kq_td->td_proc, PWAIT, "waitiw", hz/10);
2842         }
2843 }
2844
2845 io_workitem *
2846 IoAllocateWorkItem(dobj)
2847         device_object           *dobj;
2848 {
2849         io_workitem             *iw;
2850
2851         iw = uma_zalloc(iw_zone, M_NOWAIT);
2852         if (iw == NULL)
2853                 return (NULL);
2854
2855         InitializeListHead(&iw->iw_listentry);
2856         iw->iw_dobj = dobj;
2857
2858         mtx_lock(&ntoskrnl_dispatchlock);
2859         iw->iw_idx = wq_idx;
2860         WORKIDX_INC(wq_idx);
2861         mtx_unlock(&ntoskrnl_dispatchlock);
2862
2863         return (iw);
2864 }
2865
2866 void
2867 IoFreeWorkItem(iw)
2868         io_workitem             *iw;
2869 {
2870         uma_zfree(iw_zone, iw);
2871 }
2872
2873 void
2874 IoQueueWorkItem(iw, iw_func, qtype, ctx)
2875         io_workitem             *iw;
2876         io_workitem_func        iw_func;
2877         uint32_t                qtype;
2878         void                    *ctx;
2879 {
2880         kdpc_queue              *kq;
2881         list_entry              *l;
2882         io_workitem             *cur;
2883         uint8_t                 irql;
2884
2885         kq = wq_queues + iw->iw_idx;
2886
2887         KeAcquireSpinLock(&kq->kq_lock, &irql);
2888
2889         /*
2890          * Traverse the list and make sure this workitem hasn't
2891          * already been inserted. Queuing the same workitem
2892          * twice will hose the list but good.
2893          */
2894
2895         l = kq->kq_disp.nle_flink;
2896         while (l != &kq->kq_disp) {
2897                 cur = CONTAINING_RECORD(l, io_workitem, iw_listentry);
2898                 if (cur == iw) {
2899                         /* Already queued -- do nothing. */
2900                         KeReleaseSpinLock(&kq->kq_lock, irql);
2901                         return;
2902                 }
2903                 l = l->nle_flink;
2904         }
2905
2906         iw->iw_func = iw_func;
2907         iw->iw_ctx = ctx;
2908
2909         InsertTailList((&kq->kq_disp), (&iw->iw_listentry));
2910         KeReleaseSpinLock(&kq->kq_lock, irql);
2911
2912         KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
2913 }
2914
2915 static void
2916 ntoskrnl_workitem(dobj, arg)
2917         device_object           *dobj;
2918         void                    *arg;
2919 {
2920         io_workitem             *iw;
2921         work_queue_item         *w;
2922         work_item_func          f;
2923
2924         iw = arg;
2925         w = (work_queue_item *)dobj;
2926         f = (work_item_func)w->wqi_func;
2927         uma_zfree(iw_zone, iw);
2928         MSCALL2(f, w, w->wqi_ctx);
2929 }
2930
2931 /*
2932  * The ExQueueWorkItem() API is deprecated in Windows XP. Microsoft
2933  * warns that it's unsafe and to use IoQueueWorkItem() instead. The
2934  * problem with ExQueueWorkItem() is that it can't guard against
2935  * the condition where a driver submits a job to the work queue and
2936  * is then unloaded before the job is able to run. IoQueueWorkItem()
2937  * acquires a reference to the device's device_object via the
2938  * object manager and retains it until after the job has completed,
2939  * which prevents the driver from being unloaded before the job
2940  * runs. (We don't currently support this behavior, though hopefully
2941  * that will change once the object manager API is fleshed out a bit.)
2942  *
2943  * Having said all that, the ExQueueWorkItem() API remains, because
2944  * there are still other parts of Windows that use it, including
2945  * NDIS itself: NdisScheduleWorkItem() calls ExQueueWorkItem().
2946  * We fake up the ExQueueWorkItem() API on top of our implementation
2947  * of IoQueueWorkItem(). Workitem thread #3 is reserved exclusively
2948  * for ExQueueWorkItem() jobs, and we pass a pointer to the work
2949  * queue item (provided by the caller) in to IoAllocateWorkItem()
2950  * instead of the device_object. We need to save this pointer so
2951  * we can apply a sanity check: as with the DPC queue and other
2952  * workitem queues, we can't allow the same work queue item to
2953  * be queued twice. If it's already pending, we silently return
2954  */
2955
2956 void
2957 ExQueueWorkItem(w, qtype)
2958         work_queue_item         *w;
2959         uint32_t                qtype;
2960 {
2961         io_workitem             *iw;
2962         io_workitem_func        iwf;
2963         kdpc_queue              *kq;
2964         list_entry              *l;
2965         io_workitem             *cur;
2966         uint8_t                 irql;
2967
2968
2969         /*
2970          * We need to do a special sanity test to make sure
2971          * the ExQueueWorkItem() API isn't used to queue
2972          * the same workitem twice. Rather than checking the
2973          * io_workitem pointer itself, we test the attached
2974          * device object, which is really a pointer to the
2975          * legacy work queue item structure.
2976          */
2977
2978         kq = wq_queues + WORKITEM_LEGACY_THREAD;
2979         KeAcquireSpinLock(&kq->kq_lock, &irql);
2980         l = kq->kq_disp.nle_flink;
2981         while (l != &kq->kq_disp) {
2982                 cur = CONTAINING_RECORD(l, io_workitem, iw_listentry);
2983                 if (cur->iw_dobj == (device_object *)w) {
2984                         /* Already queued -- do nothing. */
2985                         KeReleaseSpinLock(&kq->kq_lock, irql);
2986                         return;
2987                 }
2988                 l = l->nle_flink;
2989         }
2990         KeReleaseSpinLock(&kq->kq_lock, irql);
2991
2992         iw = IoAllocateWorkItem((device_object *)w);
2993         if (iw == NULL)
2994                 return;
2995
2996         iw->iw_idx = WORKITEM_LEGACY_THREAD;
2997         iwf = (io_workitem_func)ntoskrnl_findwrap((funcptr)ntoskrnl_workitem);
2998         IoQueueWorkItem(iw, iwf, qtype, iw);
2999 }
3000
3001 static void
3002 RtlZeroMemory(dst, len)
3003         void                    *dst;
3004         size_t                  len;
3005 {
3006         bzero(dst, len);
3007 }
3008
3009 static void
3010 RtlSecureZeroMemory(dst, len)
3011         void                    *dst;
3012         size_t                  len;
3013 {
3014         memset(dst, 0, len);
3015 }
3016
3017 static void
3018 RtlFillMemory(dst, len, c)
3019         void                    *dst;
3020         size_t                  len;
3021         uint8_t                 c;
3022 {
3023         memset(dst, c, len);
3024 }
3025
3026 static void
3027 RtlMoveMemory(dst, src, len)
3028         void                    *dst;
3029         const void              *src;
3030         size_t                  len;
3031 {
3032         memmove(dst, src, len);
3033 }
3034
3035 static void
3036 RtlCopyMemory(dst, src, len)
3037         void                    *dst;
3038         const void              *src;
3039         size_t                  len;
3040 {
3041         bcopy(src, dst, len);
3042 }
3043
3044 static size_t
3045 RtlCompareMemory(s1, s2, len)
3046         const void              *s1;
3047         const void              *s2;
3048         size_t                  len;
3049 {
3050         size_t                  i;
3051         uint8_t                 *m1, *m2;
3052
3053         m1 = __DECONST(char *, s1);
3054         m2 = __DECONST(char *, s2);
3055
3056         for (i = 0; i < len && m1[i] == m2[i]; i++);
3057         return (i);
3058 }
3059
3060 void
3061 RtlInitAnsiString(dst, src)
3062         ansi_string             *dst;
3063         char                    *src;
3064 {
3065         ansi_string             *a;
3066
3067         a = dst;
3068         if (a == NULL)
3069                 return;
3070         if (src == NULL) {
3071                 a->as_len = a->as_maxlen = 0;
3072                 a->as_buf = NULL;
3073         } else {
3074                 a->as_buf = src;
3075                 a->as_len = a->as_maxlen = strlen(src);
3076         }
3077 }
3078
3079 void
3080 RtlInitUnicodeString(dst, src)
3081         unicode_string          *dst;
3082         uint16_t                *src;
3083 {
3084         unicode_string          *u;
3085         int                     i;
3086
3087         u = dst;
3088         if (u == NULL)
3089                 return;
3090         if (src == NULL) {
3091                 u->us_len = u->us_maxlen = 0;
3092                 u->us_buf = NULL;
3093         } else {
3094                 i = 0;
3095                 while(src[i] != 0)
3096                         i++;
3097                 u->us_buf = src;
3098                 u->us_len = u->us_maxlen = i * 2;
3099         }
3100 }
3101
3102 ndis_status
3103 RtlUnicodeStringToInteger(ustr, base, val)
3104         unicode_string          *ustr;
3105         uint32_t                base;
3106         uint32_t                *val;
3107 {
3108         uint16_t                *uchr;
3109         int                     len, neg = 0;
3110         char                    abuf[64];
3111         char                    *astr;
3112
3113         uchr = ustr->us_buf;
3114         len = ustr->us_len;
3115         bzero(abuf, sizeof(abuf));
3116
3117         if ((char)((*uchr) & 0xFF) == '-') {
3118                 neg = 1;
3119                 uchr++;
3120                 len -= 2;
3121         } else if ((char)((*uchr) & 0xFF) == '+') {
3122                 neg = 0;
3123                 uchr++;
3124                 len -= 2;
3125         }
3126
3127         if (base == 0) {
3128                 if ((char)((*uchr) & 0xFF) == 'b') {
3129                         base = 2;
3130                         uchr++;
3131                         len -= 2;
3132                 } else if ((char)((*uchr) & 0xFF) == 'o') {
3133                         base = 8;
3134                         uchr++;
3135                         len -= 2;
3136                 } else if ((char)((*uchr) & 0xFF) == 'x') {
3137                         base = 16;
3138                         uchr++;
3139                         len -= 2;
3140                 } else
3141                         base = 10;
3142         }
3143
3144         astr = abuf;
3145         if (neg) {
3146                 strcpy(astr, "-");
3147                 astr++;
3148         }
3149
3150         ntoskrnl_unicode_to_ascii(uchr, astr, len);
3151         *val = strtoul(abuf, NULL, base);
3152
3153         return (STATUS_SUCCESS);
3154 }
3155
3156 void
3157 RtlFreeUnicodeString(ustr)
3158         unicode_string          *ustr;
3159 {
3160         if (ustr->us_buf == NULL)
3161                 return;
3162         ExFreePool(ustr->us_buf);
3163         ustr->us_buf = NULL;
3164 }
3165
3166 void
3167 RtlFreeAnsiString(astr)
3168         ansi_string             *astr;
3169 {
3170         if (astr->as_buf == NULL)
3171                 return;
3172         ExFreePool(astr->as_buf);
3173         astr->as_buf = NULL;
3174 }
3175
3176 static int
3177 atoi(str)
3178         const char              *str;
3179 {
3180         return (int)strtol(str, (char **)NULL, 10);
3181 }
3182
3183 static long
3184 atol(str)
3185         const char              *str;
3186 {
3187         return strtol(str, (char **)NULL, 10);
3188 }
3189
3190 static int
3191 rand(void)
3192 {
3193         struct timeval          tv;
3194
3195         microtime(&tv);
3196         srandom(tv.tv_usec);
3197         return ((int)random());
3198 }
3199
3200 static void
3201 srand(seed)
3202         unsigned int            seed;
3203 {
3204         srandom(seed);
3205 }
3206
3207 static uint8_t
3208 IoIsWdmVersionAvailable(uint8_t major, uint8_t minor)
3209 {
3210         if (major == WDM_MAJOR && minor == WDM_MINOR_WINXP)
3211                 return (TRUE);
3212         return (FALSE);
3213 }
3214
3215 static int32_t
3216 IoOpenDeviceRegistryKey(struct device_object *devobj, uint32_t type,
3217     uint32_t mask, void **key)
3218 {
3219         return (NDIS_STATUS_INVALID_DEVICE_REQUEST);
3220 }
3221
3222 static ndis_status
3223 IoGetDeviceObjectPointer(name, reqaccess, fileobj, devobj)
3224         unicode_string          *name;
3225         uint32_t                reqaccess;
3226         void                    *fileobj;
3227         device_object           *devobj;
3228 {
3229         return (STATUS_SUCCESS);
3230 }
3231
3232 static ndis_status
3233 IoGetDeviceProperty(devobj, regprop, buflen, prop, reslen)
3234         device_object           *devobj;
3235         uint32_t                regprop;
3236         uint32_t                buflen;
3237         void                    *prop;
3238         uint32_t                *reslen;
3239 {
3240         driver_object           *drv;
3241         uint16_t                **name;
3242
3243         drv = devobj->do_drvobj;
3244
3245         switch (regprop) {
3246         case DEVPROP_DRIVER_KEYNAME:
3247                 name = prop;
3248                 *name = drv->dro_drivername.us_buf;
3249                 *reslen = drv->dro_drivername.us_len;
3250                 break;
3251         default:
3252                 return (STATUS_INVALID_PARAMETER_2);
3253                 break;
3254         }
3255
3256         return (STATUS_SUCCESS);
3257 }
3258
3259 static void
3260 KeInitializeMutex(kmutex, level)
3261         kmutant                 *kmutex;
3262         uint32_t                level;
3263 {
3264         InitializeListHead((&kmutex->km_header.dh_waitlisthead));
3265         kmutex->km_abandoned = FALSE;
3266         kmutex->km_apcdisable = 1;
3267         kmutex->km_header.dh_sigstate = 1;
3268         kmutex->km_header.dh_type = DISP_TYPE_MUTANT;
3269         kmutex->km_header.dh_size = sizeof(kmutant) / sizeof(uint32_t);
3270         kmutex->km_ownerthread = NULL;
3271 }
3272
3273 static uint32_t
3274 KeReleaseMutex(kmutant *kmutex, uint8_t kwait)
3275 {
3276         uint32_t                prevstate;
3277
3278         mtx_lock(&ntoskrnl_dispatchlock);
3279         prevstate = kmutex->km_header.dh_sigstate;
3280         if (kmutex->km_ownerthread != curthread) {
3281                 mtx_unlock(&ntoskrnl_dispatchlock);
3282                 return (STATUS_MUTANT_NOT_OWNED);
3283         }
3284
3285         kmutex->km_header.dh_sigstate++;
3286         kmutex->km_abandoned = FALSE;
3287
3288         if (kmutex->km_header.dh_sigstate == 1) {
3289                 kmutex->km_ownerthread = NULL;
3290                 ntoskrnl_waittest(&kmutex->km_header, IO_NO_INCREMENT);
3291         }
3292
3293         mtx_unlock(&ntoskrnl_dispatchlock);
3294
3295         return (prevstate);
3296 }
3297
3298 static uint32_t
3299 KeReadStateMutex(kmutex)
3300         kmutant                 *kmutex;
3301 {
3302         return (kmutex->km_header.dh_sigstate);
3303 }
3304
3305 void
3306 KeInitializeEvent(nt_kevent *kevent, uint32_t type, uint8_t state)
3307 {
3308         InitializeListHead((&kevent->k_header.dh_waitlisthead));
3309         kevent->k_header.dh_sigstate = state;
3310         if (type == EVENT_TYPE_NOTIFY)
3311                 kevent->k_header.dh_type = DISP_TYPE_NOTIFICATION_EVENT;
3312         else
3313                 kevent->k_header.dh_type = DISP_TYPE_SYNCHRONIZATION_EVENT;
3314         kevent->k_header.dh_size = sizeof(nt_kevent) / sizeof(uint32_t);
3315 }
3316
3317 uint32_t
3318 KeResetEvent(kevent)
3319         nt_kevent               *kevent;
3320 {
3321         uint32_t                prevstate;
3322
3323         mtx_lock(&ntoskrnl_dispatchlock);
3324         prevstate = kevent->k_header.dh_sigstate;
3325         kevent->k_header.dh_sigstate = FALSE;
3326         mtx_unlock(&ntoskrnl_dispatchlock);
3327
3328         return (prevstate);
3329 }
3330
3331 uint32_t
3332 KeSetEvent(nt_kevent *kevent, uint32_t increment, uint8_t kwait)
3333 {
3334         uint32_t                prevstate;
3335         wait_block              *w;
3336         nt_dispatch_header      *dh;
3337         struct thread           *td;
3338         wb_ext                  *we;
3339
3340         mtx_lock(&ntoskrnl_dispatchlock);
3341         prevstate = kevent->k_header.dh_sigstate;
3342         dh = &kevent->k_header;
3343
3344         if (IsListEmpty(&dh->dh_waitlisthead))
3345                 /*
3346                  * If there's nobody in the waitlist, just set
3347                  * the state to signalled.
3348                  */
3349                 dh->dh_sigstate = 1;
3350         else {
3351                 /*
3352                  * Get the first waiter. If this is a synchronization
3353                  * event, just wake up that one thread (don't bother
3354                  * setting the state to signalled since we're supposed
3355                  * to automatically clear synchronization events anyway).
3356                  *
3357                  * If it's a notification event, or the the first
3358                  * waiter is doing a WAITTYPE_ALL wait, go through
3359                  * the full wait satisfaction process.
3360                  */
3361                 w = CONTAINING_RECORD(dh->dh_waitlisthead.nle_flink,
3362                     wait_block, wb_waitlist);
3363                 we = w->wb_ext;
3364                 td = we->we_td;
3365                 if (kevent->k_header.dh_type == DISP_TYPE_NOTIFICATION_EVENT ||
3366                     w->wb_waittype == WAITTYPE_ALL) {
3367                         if (prevstate == 0) {
3368                                 dh->dh_sigstate = 1;
3369                                 ntoskrnl_waittest(dh, increment);
3370                         }
3371                 } else {
3372                         w->wb_awakened |= TRUE;
3373                         cv_broadcastpri(&we->we_cv,
3374                             (w->wb_oldpri - (increment * 4)) > PRI_MIN_KERN ?
3375                             w->wb_oldpri - (increment * 4) : PRI_MIN_KERN);
3376                 }
3377         }
3378
3379         mtx_unlock(&ntoskrnl_dispatchlock);
3380
3381         return (prevstate);
3382 }
3383
3384 void
3385 KeClearEvent(kevent)
3386         nt_kevent               *kevent;
3387 {
3388         kevent->k_header.dh_sigstate = FALSE;
3389 }
3390
3391 uint32_t
3392 KeReadStateEvent(kevent)
3393         nt_kevent               *kevent;
3394 {
3395         return (kevent->k_header.dh_sigstate);
3396 }
3397
3398 /*
3399  * The object manager in Windows is responsible for managing
3400  * references and access to various types of objects, including
3401  * device_objects, events, threads, timers and so on. However,
3402  * there's a difference in the way objects are handled in user
3403  * mode versus kernel mode.
3404  *
3405  * In user mode (i.e. Win32 applications), all objects are
3406  * managed by the object manager. For example, when you create
3407  * a timer or event object, you actually end up with an 
3408  * object_header (for the object manager's bookkeeping
3409  * purposes) and an object body (which contains the actual object
3410  * structure, e.g. ktimer, kevent, etc...). This allows Windows
3411  * to manage resource quotas and to enforce access restrictions
3412  * on basically every kind of system object handled by the kernel.
3413  *
3414  * However, in kernel mode, you only end up using the object
3415  * manager some of the time. For example, in a driver, you create
3416  * a timer object by simply allocating the memory for a ktimer
3417  * structure and initializing it with KeInitializeTimer(). Hence,
3418  * the timer has no object_header and no reference counting or
3419  * security/resource checks are done on it. The assumption in
3420  * this case is that if you're running in kernel mode, you know
3421  * what you're doing, and you're already at an elevated privilege
3422  * anyway.
3423  *
3424  * There are some exceptions to this. The two most important ones
3425  * for our purposes are device_objects and threads. We need to use
3426  * the object manager to do reference counting on device_objects,
3427  * and for threads, you can only get a pointer to a thread's
3428  * dispatch header by using ObReferenceObjectByHandle() on the
3429  * handle returned by PsCreateSystemThread().
3430  */
3431
3432 static ndis_status
3433 ObReferenceObjectByHandle(ndis_handle handle, uint32_t reqaccess, void *otype,
3434         uint8_t accessmode, void **object, void **handleinfo)
3435 {
3436         nt_objref               *nr;
3437
3438         nr = malloc(sizeof(nt_objref), M_DEVBUF, M_NOWAIT|M_ZERO);
3439         if (nr == NULL)
3440                 return (STATUS_INSUFFICIENT_RESOURCES);
3441
3442         InitializeListHead((&nr->no_dh.dh_waitlisthead));
3443         nr->no_obj = handle;
3444         nr->no_dh.dh_type = DISP_TYPE_THREAD;
3445         nr->no_dh.dh_sigstate = 0;
3446         nr->no_dh.dh_size = (uint8_t)(sizeof(struct thread) /
3447             sizeof(uint32_t));
3448         TAILQ_INSERT_TAIL(&ntoskrnl_reflist, nr, link);
3449         *object = nr;
3450
3451         return (STATUS_SUCCESS);
3452 }
3453
3454 static void
3455 ObfDereferenceObject(object)
3456         void                    *object;
3457 {
3458         nt_objref               *nr;
3459
3460         nr = object;
3461         TAILQ_REMOVE(&ntoskrnl_reflist, nr, link);
3462         free(nr, M_DEVBUF);
3463 }
3464
3465 static uint32_t
3466 ZwClose(handle)
3467         ndis_handle             handle;
3468 {
3469         return (STATUS_SUCCESS);
3470 }
3471
3472 static uint32_t
3473 WmiQueryTraceInformation(traceclass, traceinfo, infolen, reqlen, buf)
3474         uint32_t                traceclass;
3475         void                    *traceinfo;
3476         uint32_t                infolen;
3477         uint32_t                reqlen;
3478         void                    *buf;
3479 {
3480         return (STATUS_NOT_FOUND);
3481 }
3482
3483 static uint32_t
3484 WmiTraceMessage(uint64_t loghandle, uint32_t messageflags,
3485         void *guid, uint16_t messagenum, ...)
3486 {
3487         return (STATUS_SUCCESS);
3488 }
3489
3490 static uint32_t
3491 IoWMIRegistrationControl(dobj, action)
3492         device_object           *dobj;
3493         uint32_t                action;
3494 {
3495         return (STATUS_SUCCESS);
3496 }
3497
3498 /*
3499  * This is here just in case the thread returns without calling
3500  * PsTerminateSystemThread().
3501  */
3502 static void
3503 ntoskrnl_thrfunc(arg)
3504         void                    *arg;
3505 {
3506         thread_context          *thrctx;
3507         uint32_t (*tfunc)(void *);
3508         void                    *tctx;
3509         uint32_t                rval;
3510
3511         thrctx = arg;
3512         tfunc = thrctx->tc_thrfunc;
3513         tctx = thrctx->tc_thrctx;
3514         free(thrctx, M_TEMP);
3515
3516         rval = MSCALL1(tfunc, tctx);
3517
3518         PsTerminateSystemThread(rval);
3519         return; /* notreached */
3520 }
3521
3522 static ndis_status
3523 PsCreateSystemThread(handle, reqaccess, objattrs, phandle,
3524         clientid, thrfunc, thrctx)
3525         ndis_handle             *handle;
3526         uint32_t                reqaccess;
3527         void                    *objattrs;
3528         ndis_handle             phandle;
3529         void                    *clientid;
3530         void                    *thrfunc;
3531         void                    *thrctx;
3532 {
3533         int                     error;
3534         thread_context          *tc;
3535         struct proc             *p;
3536
3537         tc = malloc(sizeof(thread_context), M_TEMP, M_NOWAIT);
3538         if (tc == NULL)
3539                 return (STATUS_INSUFFICIENT_RESOURCES);
3540
3541         tc->tc_thrctx = thrctx;
3542         tc->tc_thrfunc = thrfunc;
3543
3544         error = kproc_create(ntoskrnl_thrfunc, tc, &p,
3545             RFHIGHPID, NDIS_KSTACK_PAGES, "Windows Kthread %d", ntoskrnl_kth);
3546
3547         if (error) {
3548                 free(tc, M_TEMP);
3549                 return (STATUS_INSUFFICIENT_RESOURCES);
3550         }
3551
3552         *handle = p;
3553         ntoskrnl_kth++;
3554
3555         return (STATUS_SUCCESS);
3556 }
3557
3558 /*
3559  * In Windows, the exit of a thread is an event that you're allowed
3560  * to wait on, assuming you've obtained a reference to the thread using
3561  * ObReferenceObjectByHandle(). Unfortunately, the only way we can
3562  * simulate this behavior is to register each thread we create in a
3563  * reference list, and if someone holds a reference to us, we poke
3564  * them.
3565  */
3566 static ndis_status
3567 PsTerminateSystemThread(status)
3568         ndis_status             status;
3569 {
3570         struct nt_objref        *nr;
3571
3572         mtx_lock(&ntoskrnl_dispatchlock);
3573         TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) {
3574                 if (nr->no_obj != curthread->td_proc)
3575                         continue;
3576                 nr->no_dh.dh_sigstate = 1;
3577                 ntoskrnl_waittest(&nr->no_dh, IO_NO_INCREMENT);
3578                 break;
3579         }
3580         mtx_unlock(&ntoskrnl_dispatchlock);
3581
3582         ntoskrnl_kth--;
3583
3584         kproc_exit(0);
3585         return (0);     /* notreached */
3586 }
3587
3588 static uint32_t
3589 DbgPrint(char *fmt, ...)
3590 {
3591         va_list                 ap;
3592
3593         if (bootverbose) {
3594                 va_start(ap, fmt);
3595                 vprintf(fmt, ap);
3596         }
3597
3598         return (STATUS_SUCCESS);
3599 }
3600
3601 static void
3602 DbgBreakPoint(void)
3603 {
3604
3605         kdb_enter(KDB_WHY_NDIS, "DbgBreakPoint(): breakpoint");
3606 }
3607
3608 static void
3609 KeBugCheckEx(code, param1, param2, param3, param4)
3610     uint32_t                    code;
3611     u_long                      param1;
3612     u_long                      param2;
3613     u_long                      param3;
3614     u_long                      param4;
3615 {
3616         panic("KeBugCheckEx: STOP 0x%X", code);
3617 }
3618
3619 static void
3620 ntoskrnl_timercall(arg)
3621         void                    *arg;
3622 {
3623         ktimer                  *timer;
3624         struct timeval          tv;
3625         kdpc                    *dpc;
3626
3627         mtx_lock(&ntoskrnl_dispatchlock);
3628
3629         timer = arg;
3630
3631 #ifdef NTOSKRNL_DEBUG_TIMERS
3632         ntoskrnl_timer_fires++;
3633 #endif
3634         ntoskrnl_remove_timer(timer);
3635
3636         /*
3637          * This should never happen, but complain
3638          * if it does.
3639          */
3640
3641         if (timer->k_header.dh_inserted == FALSE) {
3642                 mtx_unlock(&ntoskrnl_dispatchlock);
3643                 printf("NTOS: timer %p fired even though "
3644                     "it was canceled\n", timer);
3645                 return;
3646         }
3647
3648         /* Mark the timer as no longer being on the timer queue. */
3649
3650         timer->k_header.dh_inserted = FALSE;
3651
3652         /* Now signal the object and satisfy any waits on it. */
3653
3654         timer->k_header.dh_sigstate = 1;
3655         ntoskrnl_waittest(&timer->k_header, IO_NO_INCREMENT);
3656
3657         /*
3658          * If this is a periodic timer, re-arm it
3659          * so it will fire again. We do this before
3660          * calling any deferred procedure calls because
3661          * it's possible the DPC might cancel the timer,
3662          * in which case it would be wrong for us to
3663          * re-arm it again afterwards.
3664          */
3665
3666         if (timer->k_period) {
3667                 tv.tv_sec = 0;
3668                 tv.tv_usec = timer->k_period * 1000;
3669                 timer->k_header.dh_inserted = TRUE;
3670                 ntoskrnl_insert_timer(timer, tvtohz(&tv));
3671 #ifdef NTOSKRNL_DEBUG_TIMERS
3672                 ntoskrnl_timer_reloads++;
3673 #endif
3674         }
3675
3676         dpc = timer->k_dpc;
3677
3678         mtx_unlock(&ntoskrnl_dispatchlock);
3679
3680         /* If there's a DPC associated with the timer, queue it up. */
3681
3682         if (dpc != NULL)
3683                 KeInsertQueueDpc(dpc, NULL, NULL);
3684 }
3685
3686 #ifdef NTOSKRNL_DEBUG_TIMERS
3687 static int
3688 sysctl_show_timers(SYSCTL_HANDLER_ARGS)
3689 {
3690         int                     ret;
3691
3692         ret = 0;
3693         ntoskrnl_show_timers();
3694         return (sysctl_handle_int(oidp, &ret, 0, req));
3695 }
3696
3697 static void
3698 ntoskrnl_show_timers()
3699 {
3700         int                     i = 0;
3701         list_entry              *l;
3702
3703         mtx_lock_spin(&ntoskrnl_calllock);
3704         l = ntoskrnl_calllist.nle_flink;
3705         while(l != &ntoskrnl_calllist) {
3706                 i++;
3707                 l = l->nle_flink;
3708         }
3709         mtx_unlock_spin(&ntoskrnl_calllock);
3710
3711         printf("\n");
3712         printf("%d timers available (out of %d)\n", i, NTOSKRNL_TIMEOUTS);
3713         printf("timer sets: %qu\n", ntoskrnl_timer_sets);
3714         printf("timer reloads: %qu\n", ntoskrnl_timer_reloads);
3715         printf("timer cancels: %qu\n", ntoskrnl_timer_cancels);
3716         printf("timer fires: %qu\n", ntoskrnl_timer_fires);
3717         printf("\n");
3718 }
3719 #endif
3720
3721 /*
3722  * Must be called with dispatcher lock held.
3723  */
3724
3725 static void
3726 ntoskrnl_insert_timer(timer, ticks)
3727         ktimer                  *timer;
3728         int                     ticks;
3729 {
3730         callout_entry           *e;
3731         list_entry              *l;
3732         struct callout          *c;
3733
3734         /*
3735          * Try and allocate a timer.
3736          */
3737         mtx_lock_spin(&ntoskrnl_calllock);
3738         if (IsListEmpty(&ntoskrnl_calllist)) {
3739                 mtx_unlock_spin(&ntoskrnl_calllock);
3740 #ifdef NTOSKRNL_DEBUG_TIMERS
3741                 ntoskrnl_show_timers();
3742 #endif
3743                 panic("out of timers!");
3744         }
3745         l = RemoveHeadList(&ntoskrnl_calllist);
3746         mtx_unlock_spin(&ntoskrnl_calllock);
3747
3748         e = CONTAINING_RECORD(l, callout_entry, ce_list);
3749         c = &e->ce_callout;
3750
3751         timer->k_callout = c;
3752
3753         callout_init(c, CALLOUT_MPSAFE);
3754         callout_reset(c, ticks, ntoskrnl_timercall, timer);
3755 }
3756
3757 static void
3758 ntoskrnl_remove_timer(timer)
3759         ktimer                  *timer;
3760 {
3761         callout_entry           *e;
3762
3763         e = (callout_entry *)timer->k_callout;
3764         callout_stop(timer->k_callout);
3765
3766         mtx_lock_spin(&ntoskrnl_calllock);
3767         InsertHeadList((&ntoskrnl_calllist), (&e->ce_list));
3768         mtx_unlock_spin(&ntoskrnl_calllock);
3769 }
3770
3771 void
3772 KeInitializeTimer(timer)
3773         ktimer                  *timer;
3774 {
3775         if (timer == NULL)
3776                 return;
3777
3778         KeInitializeTimerEx(timer,  EVENT_TYPE_NOTIFY);
3779 }
3780
3781 void
3782 KeInitializeTimerEx(timer, type)
3783         ktimer                  *timer;
3784         uint32_t                type;
3785 {
3786         if (timer == NULL)
3787                 return;
3788
3789         bzero((char *)timer, sizeof(ktimer));
3790         InitializeListHead((&timer->k_header.dh_waitlisthead));
3791         timer->k_header.dh_sigstate = FALSE;
3792         timer->k_header.dh_inserted = FALSE;
3793         if (type == EVENT_TYPE_NOTIFY)
3794                 timer->k_header.dh_type = DISP_TYPE_NOTIFICATION_TIMER;
3795         else
3796                 timer->k_header.dh_type = DISP_TYPE_SYNCHRONIZATION_TIMER;
3797         timer->k_header.dh_size = sizeof(ktimer) / sizeof(uint32_t);
3798 }
3799
3800 /*
3801  * DPC subsystem. A Windows Defered Procedure Call has the following
3802  * properties:
3803  * - It runs at DISPATCH_LEVEL.
3804  * - It can have one of 3 importance values that control when it
3805  *   runs relative to other DPCs in the queue.
3806  * - On SMP systems, it can be set to run on a specific processor.
3807  * In order to satisfy the last property, we create a DPC thread for
3808  * each CPU in the system and bind it to that CPU. Each thread
3809  * maintains three queues with different importance levels, which
3810  * will be processed in order from lowest to highest.
3811  *
3812  * In Windows, interrupt handlers run as DPCs. (Not to be confused
3813  * with ISRs, which run in interrupt context and can preempt DPCs.)
3814  * ISRs are given the highest importance so that they'll take
3815  * precedence over timers and other things.
3816  */
3817
3818 static void
3819 ntoskrnl_dpc_thread(arg)
3820         void                    *arg;
3821 {
3822         kdpc_queue              *kq;
3823         kdpc                    *d;
3824         list_entry              *l;
3825         uint8_t                 irql;
3826
3827         kq = arg;
3828
3829         InitializeListHead(&kq->kq_disp);
3830         kq->kq_td = curthread;
3831         kq->kq_exit = 0;
3832         kq->kq_running = FALSE;
3833         KeInitializeSpinLock(&kq->kq_lock);
3834         KeInitializeEvent(&kq->kq_proc, EVENT_TYPE_SYNC, FALSE);
3835         KeInitializeEvent(&kq->kq_done, EVENT_TYPE_SYNC, FALSE);
3836
3837         /*
3838          * Elevate our priority. DPCs are used to run interrupt
3839          * handlers, and they should trigger as soon as possible
3840          * once scheduled by an ISR.
3841          */
3842
3843         thread_lock(curthread);
3844 #ifdef NTOSKRNL_MULTIPLE_DPCS
3845         sched_bind(curthread, kq->kq_cpu);
3846 #endif
3847         sched_prio(curthread, PRI_MIN_KERN);
3848         thread_unlock(curthread);
3849
3850         while (1) {
3851                 KeWaitForSingleObject(&kq->kq_proc, 0, 0, TRUE, NULL);
3852
3853                 KeAcquireSpinLock(&kq->kq_lock, &irql);
3854
3855                 if (kq->kq_exit) {
3856                         kq->kq_exit = 0;
3857                         KeReleaseSpinLock(&kq->kq_lock, irql);
3858                         break;
3859                 }
3860
3861                 kq->kq_running = TRUE;
3862
3863                 while (!IsListEmpty(&kq->kq_disp)) {
3864                         l = RemoveHeadList((&kq->kq_disp));
3865                         d = CONTAINING_RECORD(l, kdpc, k_dpclistentry);
3866                         InitializeListHead((&d->k_dpclistentry));
3867                         KeReleaseSpinLockFromDpcLevel(&kq->kq_lock);
3868                         MSCALL4(d->k_deferedfunc, d, d->k_deferredctx,
3869                             d->k_sysarg1, d->k_sysarg2);
3870                         KeAcquireSpinLockAtDpcLevel(&kq->kq_lock);
3871                 }
3872
3873                 kq->kq_running = FALSE;
3874
3875                 KeReleaseSpinLock(&kq->kq_lock, irql);
3876
3877                 KeSetEvent(&kq->kq_done, IO_NO_INCREMENT, FALSE);
3878         }
3879
3880         kproc_exit(0);
3881         return; /* notreached */
3882 }
3883
3884 static void
3885 ntoskrnl_destroy_dpc_threads(void)
3886 {
3887         kdpc_queue              *kq;
3888         kdpc                    dpc;
3889         int                     i;
3890
3891         kq = kq_queues;
3892 #ifdef NTOSKRNL_MULTIPLE_DPCS
3893         for (i = 0; i < mp_ncpus; i++) {
3894 #else
3895         for (i = 0; i < 1; i++) {
3896 #endif
3897                 kq += i;
3898
3899                 kq->kq_exit = 1;
3900                 KeInitializeDpc(&dpc, NULL, NULL);
3901                 KeSetTargetProcessorDpc(&dpc, i);
3902                 KeInsertQueueDpc(&dpc, NULL, NULL);
3903                 while (kq->kq_exit)
3904                         tsleep(kq->kq_td->td_proc, PWAIT, "dpcw", hz/10);
3905         }
3906 }
3907
3908 static uint8_t
3909 ntoskrnl_insert_dpc(head, dpc)
3910         list_entry              *head;
3911         kdpc                    *dpc;
3912 {
3913         list_entry              *l;
3914         kdpc                    *d;
3915
3916         l = head->nle_flink;
3917         while (l != head) {
3918                 d = CONTAINING_RECORD(l, kdpc, k_dpclistentry);
3919                 if (d == dpc)
3920                         return (FALSE);
3921                 l = l->nle_flink;
3922         }
3923
3924         if (dpc->k_importance == KDPC_IMPORTANCE_LOW)
3925                 InsertTailList((head), (&dpc->k_dpclistentry));
3926         else
3927                 InsertHeadList((head), (&dpc->k_dpclistentry));
3928
3929         return (TRUE);
3930 }
3931
3932 void
3933 KeInitializeDpc(dpc, dpcfunc, dpcctx)
3934         kdpc                    *dpc;
3935         void                    *dpcfunc;
3936         void                    *dpcctx;
3937 {
3938
3939         if (dpc == NULL)
3940                 return;
3941
3942         dpc->k_deferedfunc = dpcfunc;
3943         dpc->k_deferredctx = dpcctx;
3944         dpc->k_num = KDPC_CPU_DEFAULT;
3945         dpc->k_importance = KDPC_IMPORTANCE_MEDIUM;
3946         InitializeListHead((&dpc->k_dpclistentry));
3947 }
3948
3949 uint8_t
3950 KeInsertQueueDpc(dpc, sysarg1, sysarg2)
3951         kdpc                    *dpc;
3952         void                    *sysarg1;
3953         void                    *sysarg2;
3954 {
3955         kdpc_queue              *kq;
3956         uint8_t                 r;
3957         uint8_t                 irql;
3958
3959         if (dpc == NULL)
3960                 return (FALSE);
3961
3962         kq = kq_queues;
3963
3964 #ifdef NTOSKRNL_MULTIPLE_DPCS
3965         KeRaiseIrql(DISPATCH_LEVEL, &irql);
3966
3967         /*
3968          * By default, the DPC is queued to run on the same CPU
3969          * that scheduled it.
3970          */
3971
3972         if (dpc->k_num == KDPC_CPU_DEFAULT)
3973                 kq += curthread->td_oncpu;
3974         else
3975                 kq += dpc->k_num;
3976         KeAcquireSpinLockAtDpcLevel(&kq->kq_lock);
3977 #else
3978         KeAcquireSpinLock(&kq->kq_lock, &irql);
3979 #endif
3980
3981         r = ntoskrnl_insert_dpc(&kq->kq_disp, dpc);
3982         if (r == TRUE) {
3983                 dpc->k_sysarg1 = sysarg1;
3984                 dpc->k_sysarg2 = sysarg2;
3985         }
3986         KeReleaseSpinLock(&kq->kq_lock, irql);
3987
3988         if (r == FALSE)
3989                 return (r);
3990
3991         KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
3992
3993         return (r);
3994 }
3995
3996 uint8_t
3997 KeRemoveQueueDpc(dpc)
3998         kdpc                    *dpc;
3999 {
4000         kdpc_queue              *kq;
4001         uint8_t                 irql;
4002
4003         if (dpc == NULL)
4004                 return (FALSE);
4005
4006 #ifdef NTOSKRNL_MULTIPLE_DPCS
4007         KeRaiseIrql(DISPATCH_LEVEL, &irql);
4008
4009         kq = kq_queues + dpc->k_num;
4010
4011         KeAcquireSpinLockAtDpcLevel(&kq->kq_lock);
4012 #else
4013         kq = kq_queues;
4014         KeAcquireSpinLock(&kq->kq_lock, &irql);
4015 #endif
4016
4017         if (dpc->k_dpclistentry.nle_flink == &dpc->k_dpclistentry) {
4018                 KeReleaseSpinLockFromDpcLevel(&kq->kq_lock);
4019                 KeLowerIrql(irql);
4020                 return (FALSE);
4021         }
4022
4023         RemoveEntryList((&dpc->k_dpclistentry));
4024         InitializeListHead((&dpc->k_dpclistentry));
4025
4026         KeReleaseSpinLock(&kq->kq_lock, irql);
4027
4028         return (TRUE);
4029 }
4030
4031 void
4032 KeSetImportanceDpc(dpc, imp)
4033         kdpc                    *dpc;
4034         uint32_t                imp;
4035 {
4036         if (imp != KDPC_IMPORTANCE_LOW &&
4037             imp != KDPC_IMPORTANCE_MEDIUM &&
4038             imp != KDPC_IMPORTANCE_HIGH)
4039                 return;
4040
4041         dpc->k_importance = (uint8_t)imp;
4042 }
4043
4044 void
4045 KeSetTargetProcessorDpc(kdpc *dpc, uint8_t cpu)
4046 {
4047         if (cpu > mp_ncpus)
4048                 return;
4049
4050         dpc->k_num = cpu;
4051 }
4052
4053 void
4054 KeFlushQueuedDpcs(void)
4055 {
4056         kdpc_queue              *kq;
4057         int                     i;
4058
4059         /*
4060          * Poke each DPC queue and wait
4061          * for them to drain.
4062          */
4063
4064 #ifdef NTOSKRNL_MULTIPLE_DPCS
4065         for (i = 0; i < mp_ncpus; i++) {
4066 #else
4067         for (i = 0; i < 1; i++) {
4068 #endif
4069                 kq = kq_queues + i;
4070                 KeSetEvent(&kq->kq_proc, IO_NO_INCREMENT, FALSE);
4071                 KeWaitForSingleObject(&kq->kq_done, 0, 0, TRUE, NULL);
4072         }
4073 }
4074
4075 uint32_t
4076 KeGetCurrentProcessorNumber(void)
4077 {
4078         return ((uint32_t)curthread->td_oncpu);
4079 }
4080
4081 uint8_t
4082 KeSetTimerEx(timer, duetime, period, dpc)
4083         ktimer                  *timer;
4084         int64_t                 duetime;
4085         uint32_t                period;
4086         kdpc                    *dpc;
4087 {
4088         struct timeval          tv;
4089         uint64_t                curtime;
4090         uint8_t                 pending;
4091
4092         if (timer == NULL)
4093                 return (FALSE);
4094
4095         mtx_lock(&ntoskrnl_dispatchlock);
4096
4097         if (timer->k_header.dh_inserted == TRUE) {
4098                 ntoskrnl_remove_timer(timer);
4099 #ifdef NTOSKRNL_DEBUG_TIMERS
4100                 ntoskrnl_timer_cancels++;
4101 #endif
4102                 timer->k_header.dh_inserted = FALSE;
4103                 pending = TRUE;
4104         } else
4105                 pending = FALSE;
4106
4107         timer->k_duetime = duetime;
4108         timer->k_period = period;
4109         timer->k_header.dh_sigstate = FALSE;
4110         timer->k_dpc = dpc;
4111
4112         if (duetime < 0) {
4113                 tv.tv_sec = - (duetime) / 10000000;
4114                 tv.tv_usec = (- (duetime) / 10) -
4115                     (tv.tv_sec * 1000000);
4116         } else {
4117                 ntoskrnl_time(&curtime);
4118                 if (duetime < curtime)
4119                         tv.tv_sec = tv.tv_usec = 0;
4120                 else {
4121                         tv.tv_sec = ((duetime) - curtime) / 10000000;
4122                         tv.tv_usec = ((duetime) - curtime) / 10 -
4123                             (tv.tv_sec * 1000000);
4124                 }
4125         }
4126
4127         timer->k_header.dh_inserted = TRUE;
4128         ntoskrnl_insert_timer(timer, tvtohz(&tv));
4129 #ifdef NTOSKRNL_DEBUG_TIMERS
4130         ntoskrnl_timer_sets++;
4131 #endif
4132
4133         mtx_unlock(&ntoskrnl_dispatchlock);
4134
4135         return (pending);
4136 }
4137
4138 uint8_t
4139 KeSetTimer(timer, duetime, dpc)
4140         ktimer                  *timer;
4141         int64_t                 duetime;
4142         kdpc                    *dpc;
4143 {
4144         return (KeSetTimerEx(timer, duetime, 0, dpc));
4145 }
4146
4147 /*
4148  * The Windows DDK documentation seems to say that cancelling
4149  * a timer that has a DPC will result in the DPC also being
4150  * cancelled, but this isn't really the case.
4151  */
4152
4153 uint8_t
4154 KeCancelTimer(timer)
4155         ktimer                  *timer;
4156 {
4157         uint8_t                 pending;
4158
4159         if (timer == NULL)
4160                 return (FALSE);
4161
4162         mtx_lock(&ntoskrnl_dispatchlock);
4163
4164         pending = timer->k_header.dh_inserted;
4165
4166         if (timer->k_header.dh_inserted == TRUE) {
4167                 timer->k_header.dh_inserted = FALSE;
4168                 ntoskrnl_remove_timer(timer);
4169 #ifdef NTOSKRNL_DEBUG_TIMERS
4170                 ntoskrnl_timer_cancels++;
4171 #endif
4172         }
4173
4174         mtx_unlock(&ntoskrnl_dispatchlock);
4175
4176         return (pending);
4177 }
4178
4179 uint8_t
4180 KeReadStateTimer(timer)
4181         ktimer                  *timer;
4182 {
4183         return (timer->k_header.dh_sigstate);
4184 }
4185
4186 static int32_t
4187 KeDelayExecutionThread(uint8_t wait_mode, uint8_t alertable, int64_t *interval)
4188 {
4189         ktimer                  timer;
4190
4191         if (wait_mode != 0)
4192                 panic("invalid wait_mode %d", wait_mode);
4193
4194         KeInitializeTimer(&timer);
4195         KeSetTimer(&timer, *interval, NULL);
4196         KeWaitForSingleObject(&timer, 0, 0, alertable, NULL);
4197
4198         return STATUS_SUCCESS;
4199 }
4200
4201 static uint64_t
4202 KeQueryInterruptTime(void)
4203 {
4204         int ticks;
4205         struct timeval tv;
4206
4207         getmicrouptime(&tv);
4208
4209         ticks = tvtohz(&tv);
4210
4211         return ticks * ((10000000 + hz - 1) / hz);
4212 }
4213
4214 static struct thread *
4215 KeGetCurrentThread(void)
4216 {
4217
4218         return curthread;
4219 }
4220
4221 static int32_t
4222 KeSetPriorityThread(td, pri)
4223         struct thread   *td;
4224         int32_t         pri;
4225 {
4226         int32_t old;
4227
4228         if (td == NULL)
4229                 return LOW_REALTIME_PRIORITY;
4230
4231         if (td->td_priority <= PRI_MIN_KERN)
4232                 old = HIGH_PRIORITY;
4233         else if (td->td_priority >= PRI_MAX_KERN)
4234                 old = LOW_PRIORITY;
4235         else
4236                 old = LOW_REALTIME_PRIORITY;
4237
4238         thread_lock(td);
4239         if (pri == HIGH_PRIORITY)
4240                 sched_prio(td, PRI_MIN_KERN);
4241         if (pri == LOW_REALTIME_PRIORITY)
4242                 sched_prio(td, PRI_MIN_KERN + (PRI_MAX_KERN - PRI_MIN_KERN) / 2);
4243         if (pri == LOW_PRIORITY)
4244                 sched_prio(td, PRI_MAX_KERN);
4245         thread_unlock(td);
4246
4247         return old;
4248 }
4249
4250 static void
4251 dummy()
4252 {
4253         printf("ntoskrnl dummy called...\n");
4254 }
4255
4256
4257 image_patch_table ntoskrnl_functbl[] = {
4258         IMPORT_SFUNC(RtlZeroMemory, 2),
4259         IMPORT_SFUNC(RtlSecureZeroMemory, 2),
4260         IMPORT_SFUNC(RtlFillMemory, 3),
4261         IMPORT_SFUNC(RtlMoveMemory, 3),
4262         IMPORT_SFUNC(RtlCharToInteger, 3),
4263         IMPORT_SFUNC(RtlCopyMemory, 3),
4264         IMPORT_SFUNC(RtlCopyString, 2),
4265         IMPORT_SFUNC(RtlCompareMemory, 3),
4266         IMPORT_SFUNC(RtlEqualUnicodeString, 3),
4267         IMPORT_SFUNC(RtlCopyUnicodeString, 2),
4268         IMPORT_SFUNC(RtlUnicodeStringToAnsiString, 3),
4269         IMPORT_SFUNC(RtlAnsiStringToUnicodeString, 3),
4270         IMPORT_SFUNC(RtlInitAnsiString, 2),
4271         IMPORT_SFUNC_MAP(RtlInitString, RtlInitAnsiString, 2),
4272         IMPORT_SFUNC(RtlInitUnicodeString, 2),
4273         IMPORT_SFUNC(RtlFreeAnsiString, 1),
4274         IMPORT_SFUNC(RtlFreeUnicodeString, 1),
4275         IMPORT_SFUNC(RtlUnicodeStringToInteger, 3),
4276         IMPORT_CFUNC(sprintf, 0),
4277         IMPORT_CFUNC(vsprintf, 0),
4278         IMPORT_CFUNC_MAP(_snprintf, snprintf, 0),
4279         IMPORT_CFUNC_MAP(_vsnprintf, vsnprintf, 0),
4280         IMPORT_CFUNC(DbgPrint, 0),
4281         IMPORT_SFUNC(DbgBreakPoint, 0),
4282         IMPORT_SFUNC(KeBugCheckEx, 5),
4283         IMPORT_CFUNC(strncmp, 0),
4284         IMPORT_CFUNC(strcmp, 0),
4285         IMPORT_CFUNC_MAP(stricmp, strcasecmp, 0),
4286         IMPORT_CFUNC(strncpy, 0),
4287         IMPORT_CFUNC(strcpy, 0),
4288         IMPORT_CFUNC(strlen, 0),
4289         IMPORT_CFUNC_MAP(toupper, ntoskrnl_toupper, 0),
4290         IMPORT_CFUNC_MAP(tolower, ntoskrnl_tolower, 0),
4291         IMPORT_CFUNC_MAP(strstr, ntoskrnl_strstr, 0),
4292         IMPORT_CFUNC_MAP(strncat, ntoskrnl_strncat, 0),
4293         IMPORT_CFUNC_MAP(strchr, index, 0),
4294         IMPORT_CFUNC_MAP(strrchr, rindex, 0),
4295         IMPORT_CFUNC(memcpy, 0),
4296         IMPORT_CFUNC_MAP(memmove, ntoskrnl_memmove, 0),
4297         IMPORT_CFUNC_MAP(memset, ntoskrnl_memset, 0),
4298         IMPORT_CFUNC_MAP(memchr, ntoskrnl_memchr, 0),
4299         IMPORT_SFUNC(IoAllocateDriverObjectExtension, 4),
4300         IMPORT_SFUNC(IoGetDriverObjectExtension, 2),
4301         IMPORT_FFUNC(IofCallDriver, 2),
4302         IMPORT_FFUNC(IofCompleteRequest, 2),
4303         IMPORT_SFUNC(IoAcquireCancelSpinLock, 1),
4304         IMPORT_SFUNC(IoReleaseCancelSpinLock, 1),
4305         IMPORT_SFUNC(IoCancelIrp, 1),
4306         IMPORT_SFUNC(IoConnectInterrupt, 11),
4307         IMPORT_SFUNC(IoDisconnectInterrupt, 1),
4308         IMPORT_SFUNC(IoCreateDevice, 7),
4309         IMPORT_SFUNC(IoDeleteDevice, 1),
4310         IMPORT_SFUNC(IoGetAttachedDevice, 1),
4311         IMPORT_SFUNC(IoAttachDeviceToDeviceStack, 2),
4312         IMPORT_SFUNC(IoDetachDevice, 1),
4313         IMPORT_SFUNC(IoBuildSynchronousFsdRequest, 7),
4314         IMPORT_SFUNC(IoBuildAsynchronousFsdRequest, 6),
4315         IMPORT_SFUNC(IoBuildDeviceIoControlRequest, 9),
4316         IMPORT_SFUNC(IoAllocateIrp, 2),
4317         IMPORT_SFUNC(IoReuseIrp, 2),
4318         IMPORT_SFUNC(IoMakeAssociatedIrp, 2),
4319         IMPORT_SFUNC(IoFreeIrp, 1),
4320         IMPORT_SFUNC(IoInitializeIrp, 3),
4321         IMPORT_SFUNC(KeAcquireInterruptSpinLock, 1),
4322         IMPORT_SFUNC(KeReleaseInterruptSpinLock, 2),
4323         IMPORT_SFUNC(KeSynchronizeExecution, 3),
4324         IMPORT_SFUNC(KeWaitForSingleObject, 5),
4325         IMPORT_SFUNC(KeWaitForMultipleObjects, 8),
4326         IMPORT_SFUNC(_allmul, 4),
4327         IMPORT_SFUNC(_alldiv, 4),
4328         IMPORT_SFUNC(_allrem, 4),
4329         IMPORT_RFUNC(_allshr, 0),
4330         IMPORT_RFUNC(_allshl, 0),
4331         IMPORT_SFUNC(_aullmul, 4),
4332         IMPORT_SFUNC(_aulldiv, 4),
4333         IMPORT_SFUNC(_aullrem, 4),
4334         IMPORT_RFUNC(_aullshr, 0),
4335         IMPORT_RFUNC(_aullshl, 0),
4336         IMPORT_CFUNC(atoi, 0),
4337         IMPORT_CFUNC(atol, 0),
4338         IMPORT_CFUNC(rand, 0),
4339         IMPORT_CFUNC(srand, 0),
4340         IMPORT_SFUNC(WRITE_REGISTER_USHORT, 2),
4341         IMPORT_SFUNC(READ_REGISTER_USHORT, 1),
4342         IMPORT_SFUNC(WRITE_REGISTER_ULONG, 2),
4343         IMPORT_SFUNC(READ_REGISTER_ULONG, 1),
4344         IMPORT_SFUNC(READ_REGISTER_UCHAR, 1),
4345         IMPORT_SFUNC(WRITE_REGISTER_UCHAR, 2),
4346         IMPORT_SFUNC(ExInitializePagedLookasideList, 7),
4347         IMPORT_SFUNC(ExDeletePagedLookasideList, 1),
4348         IMPORT_SFUNC(ExInitializeNPagedLookasideList, 7),
4349         IMPORT_SFUNC(ExDeleteNPagedLookasideList, 1),
4350         IMPORT_FFUNC(InterlockedPopEntrySList, 1),
4351         IMPORT_FFUNC(InitializeSListHead, 1),
4352         IMPORT_FFUNC(InterlockedPushEntrySList, 2),
4353         IMPORT_SFUNC(ExQueryDepthSList, 1),
4354         IMPORT_FFUNC_MAP(ExpInterlockedPopEntrySList,
4355                 InterlockedPopEntrySList, 1),
4356         IMPORT_FFUNC_MAP(ExpInterlockedPushEntrySList,
4357                 InterlockedPushEntrySList, 2),
4358         IMPORT_FFUNC(ExInterlockedPopEntrySList, 2),
4359         IMPORT_FFUNC(ExInterlockedPushEntrySList, 3),
4360         IMPORT_SFUNC(ExAllocatePoolWithTag, 3),
4361         IMPORT_SFUNC(ExFreePoolWithTag, 2),
4362         IMPORT_SFUNC(ExFreePool, 1),
4363 #ifdef __i386__
4364         IMPORT_FFUNC(KefAcquireSpinLockAtDpcLevel, 1),
4365         IMPORT_FFUNC(KefReleaseSpinLockFromDpcLevel,1),
4366         IMPORT_FFUNC(KeAcquireSpinLockRaiseToDpc, 1),
4367 #else
4368         /*
4369          * For AMD64, we can get away with just mapping
4370          * KeAcquireSpinLockRaiseToDpc() directly to KfAcquireSpinLock()
4371          * because the calling conventions end up being the same.
4372          * On i386, we have to be careful because KfAcquireSpinLock()
4373          * is _fastcall but KeAcquireSpinLockRaiseToDpc() isn't.
4374          */
4375         IMPORT_SFUNC(KeAcquireSpinLockAtDpcLevel, 1),
4376         IMPORT_SFUNC(KeReleaseSpinLockFromDpcLevel, 1),
4377         IMPORT_SFUNC_MAP(KeAcquireSpinLockRaiseToDpc, KfAcquireSpinLock, 1),
4378 #endif
4379         IMPORT_SFUNC_MAP(KeReleaseSpinLock, KfReleaseSpinLock, 1),
4380         IMPORT_FFUNC(InterlockedIncrement, 1),
4381         IMPORT_FFUNC(InterlockedDecrement, 1),
4382         IMPORT_FFUNC(InterlockedExchange, 2),
4383         IMPORT_FFUNC(ExInterlockedAddLargeStatistic, 2),
4384         IMPORT_SFUNC(IoAllocateMdl, 5),
4385         IMPORT_SFUNC(IoFreeMdl, 1),
4386         IMPORT_SFUNC(MmAllocateContiguousMemory, 2 + 1),
4387         IMPORT_SFUNC(MmAllocateContiguousMemorySpecifyCache, 5 + 3),
4388         IMPORT_SFUNC(MmFreeContiguousMemory, 1),
4389         IMPORT_SFUNC(MmFreeContiguousMemorySpecifyCache, 3),
4390         IMPORT_SFUNC(MmSizeOfMdl, 1),
4391         IMPORT_SFUNC(MmMapLockedPages, 2),
4392         IMPORT_SFUNC(MmMapLockedPagesSpecifyCache, 6),
4393         IMPORT_SFUNC(MmUnmapLockedPages, 2),
4394         IMPORT_SFUNC(MmBuildMdlForNonPagedPool, 1),
4395         IMPORT_SFUNC(MmGetPhysicalAddress, 1),
4396         IMPORT_SFUNC(MmGetSystemRoutineAddress, 1),
4397         IMPORT_SFUNC(MmIsAddressValid, 1),
4398         IMPORT_SFUNC(MmMapIoSpace, 3 + 1),
4399         IMPORT_SFUNC(MmUnmapIoSpace, 2),
4400         IMPORT_SFUNC(KeInitializeSpinLock, 1),
4401         IMPORT_SFUNC(IoIsWdmVersionAvailable, 2),
4402         IMPORT_SFUNC(IoOpenDeviceRegistryKey, 4),
4403         IMPORT_SFUNC(IoGetDeviceObjectPointer, 4),
4404         IMPORT_SFUNC(IoGetDeviceProperty, 5),
4405         IMPORT_SFUNC(IoAllocateWorkItem, 1),
4406         IMPORT_SFUNC(IoFreeWorkItem, 1),
4407         IMPORT_SFUNC(IoQueueWorkItem, 4),
4408         IMPORT_SFUNC(ExQueueWorkItem, 2),
4409         IMPORT_SFUNC(ntoskrnl_workitem, 2),
4410         IMPORT_SFUNC(KeInitializeMutex, 2),
4411         IMPORT_SFUNC(KeReleaseMutex, 2),
4412         IMPORT_SFUNC(KeReadStateMutex, 1),
4413         IMPORT_SFUNC(KeInitializeEvent, 3),
4414         IMPORT_SFUNC(KeSetEvent, 3),
4415         IMPORT_SFUNC(KeResetEvent, 1),
4416         IMPORT_SFUNC(KeClearEvent, 1),
4417         IMPORT_SFUNC(KeReadStateEvent, 1),
4418         IMPORT_SFUNC(KeInitializeTimer, 1),
4419         IMPORT_SFUNC(KeInitializeTimerEx, 2),
4420         IMPORT_SFUNC(KeSetTimer, 3),
4421         IMPORT_SFUNC(KeSetTimerEx, 4),
4422         IMPORT_SFUNC(KeCancelTimer, 1),
4423         IMPORT_SFUNC(KeReadStateTimer, 1),
4424         IMPORT_SFUNC(KeInitializeDpc, 3),
4425         IMPORT_SFUNC(KeInsertQueueDpc, 3),
4426         IMPORT_SFUNC(KeRemoveQueueDpc, 1),
4427         IMPORT_SFUNC(KeSetImportanceDpc, 2),
4428         IMPORT_SFUNC(KeSetTargetProcessorDpc, 2),
4429         IMPORT_SFUNC(KeFlushQueuedDpcs, 0),
4430         IMPORT_SFUNC(KeGetCurrentProcessorNumber, 1),
4431         IMPORT_SFUNC(ObReferenceObjectByHandle, 6),
4432         IMPORT_FFUNC(ObfDereferenceObject, 1),
4433         IMPORT_SFUNC(ZwClose, 1),
4434         IMPORT_SFUNC(PsCreateSystemThread, 7),
4435         IMPORT_SFUNC(PsTerminateSystemThread, 1),
4436         IMPORT_SFUNC(IoWMIRegistrationControl, 2),
4437         IMPORT_SFUNC(WmiQueryTraceInformation, 5),
4438         IMPORT_CFUNC(WmiTraceMessage, 0),
4439         IMPORT_SFUNC(KeQuerySystemTime, 1),
4440         IMPORT_CFUNC(KeTickCount, 0),
4441         IMPORT_SFUNC(KeDelayExecutionThread, 3),
4442         IMPORT_SFUNC(KeQueryInterruptTime, 0),
4443         IMPORT_SFUNC(KeGetCurrentThread, 0),
4444         IMPORT_SFUNC(KeSetPriorityThread, 2),
4445
4446         /*
4447          * This last entry is a catch-all for any function we haven't
4448          * implemented yet. The PE import list patching routine will
4449          * use it for any function that doesn't have an explicit match
4450          * in this table.
4451          */
4452
4453         { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
4454
4455         /* End of list. */
4456
4457         { NULL, NULL, NULL }
4458 };