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