3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
32 * $FreeBSD: src/sys/compat/ndis/subr_ntoskrnl.c,v 1.40 2004/07/20 20:28:57 wpaul Exp $
33 * $DragonFly: src/sys/emulation/ndis/subr_ntoskrnl.c,v 1.2 2004/07/29 21:35:57 dillon Exp $
36 #include <sys/ctype.h>
37 #include <sys/unistd.h>
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/errno.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
45 #include <sys/callout.h>
46 #if __FreeBSD_version > 502113
49 #include <sys/kernel.h>
51 #include <sys/kthread.h>
53 #include <machine/atomic.h>
54 #include <machine/clock.h>
55 #include <machine/bus_memio.h>
56 #include <machine/bus_pio.h>
57 #include <machine/bus.h>
58 #include <machine/stdarg.h>
65 #include "resource_var.h"
66 #include "ntoskrnl_var.h"
70 #define __regparm __attribute__((regparm(3)))
72 #define FUNC void(*)(void)
74 __stdcall static uint8_t ntoskrnl_unicode_equal(ndis_unicode_string *,
75 ndis_unicode_string *, uint8_t);
76 __stdcall static void ntoskrnl_unicode_copy(ndis_unicode_string *,
77 ndis_unicode_string *);
78 __stdcall static ndis_status ntoskrnl_unicode_to_ansi(ndis_ansi_string *,
79 ndis_unicode_string *, uint8_t);
80 __stdcall static ndis_status ntoskrnl_ansi_to_unicode(ndis_unicode_string *,
81 ndis_ansi_string *, uint8_t);
82 __stdcall static void *ntoskrnl_iobuildsynchfsdreq(uint32_t, void *,
83 void *, uint32_t, uint32_t *, void *, void *);
88 __stdcall __regcall static uint32_t
89 ntoskrnl_iofcalldriver(REGARGS2(void *dobj, void *irp));
90 __stdcall __regcall static void
91 ntoskrnl_iofcompletereq(REGARGS2(void *irp, uint8_t prioboost));
92 __stdcall __regcall static slist_entry *
93 ntoskrnl_push_slist(REGARGS2(slist_header *head, slist_entry *entry));
94 __stdcall __regcall static slist_entry *
95 ntoskrnl_pop_slist(REGARGS1(slist_header *head));
96 __stdcall __regcall static slist_entry *
97 ntoskrnl_push_slist_ex(REGARGS2(slist_header *head, slist_entry *entry), kspin_lock *lock);
98 __stdcall __regcall static slist_entry *
99 ntoskrnl_pop_slist_ex(REGARGS2(slist_header *head, kspin_lock *lock));
101 __stdcall __regcall static uint32_t
102 ntoskrnl_interlock_inc(REGARGS1(volatile uint32_t *addend));
103 __stdcall __regcall static uint32_t
104 ntoskrnl_interlock_dec(REGARGS1(volatile uint32_t *addend));
105 __stdcall __regcall static void
106 ntoskrnl_interlock_addstat(REGARGS2(uint64_t *addend, uint32_t inc));
107 __stdcall __regcall static void
108 ntoskrnl_objderef(REGARGS1(void *object));
110 __stdcall static uint32_t ntoskrnl_waitforobjs(uint32_t,
111 nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t,
112 int64_t *, wait_block *);
113 static void ntoskrnl_wakeup(void *);
114 static void ntoskrnl_timercall(void *);
115 static void ntoskrnl_run_dpc(void *);
116 __stdcall static void ntoskrnl_writereg_ushort(uint16_t *, uint16_t);
117 __stdcall static uint16_t ntoskrnl_readreg_ushort(uint16_t *);
118 __stdcall static void ntoskrnl_writereg_ulong(uint32_t *, uint32_t);
119 __stdcall static uint32_t ntoskrnl_readreg_ulong(uint32_t *);
120 __stdcall static void ntoskrnl_writereg_uchar(uint8_t *, uint8_t);
121 __stdcall static uint8_t ntoskrnl_readreg_uchar(uint8_t *);
122 __stdcall static int64_t _allmul(int64_t, int64_t);
123 __stdcall static int64_t _alldiv(int64_t, int64_t);
124 __stdcall static int64_t _allrem(int64_t, int64_t);
125 __regparm static int64_t _allshr(int64_t, uint8_t);
126 __regparm static int64_t _allshl(int64_t, uint8_t);
127 __stdcall static uint64_t _aullmul(uint64_t, uint64_t);
128 __stdcall static uint64_t _aulldiv(uint64_t, uint64_t);
129 __stdcall static uint64_t _aullrem(uint64_t, uint64_t);
130 __regparm static uint64_t _aullshr(uint64_t, uint8_t);
131 __regparm static uint64_t _aullshl(uint64_t, uint8_t);
132 __stdcall static void *ntoskrnl_allocfunc(uint32_t, size_t, uint32_t);
133 __stdcall static void ntoskrnl_freefunc(void *);
134 static slist_entry *ntoskrnl_pushsl(slist_header *, slist_entry *);
135 static slist_entry *ntoskrnl_popsl(slist_header *);
136 __stdcall static void ntoskrnl_init_lookaside(paged_lookaside_list *,
137 lookaside_alloc_func *, lookaside_free_func *,
138 uint32_t, size_t, uint32_t, uint16_t);
139 __stdcall static void ntoskrnl_delete_lookaside(paged_lookaside_list *);
140 __stdcall static void ntoskrnl_init_nplookaside(npaged_lookaside_list *,
141 lookaside_alloc_func *, lookaside_free_func *,
142 uint32_t, size_t, uint32_t, uint16_t);
143 __stdcall static void ntoskrnl_delete_nplookaside(npaged_lookaside_list *);
144 __stdcall static void ntoskrnl_freemdl(ndis_buffer *);
145 __stdcall static uint32_t ntoskrnl_sizeofmdl(void *, size_t);
146 __stdcall static void ntoskrnl_build_npaged_mdl(ndis_buffer *);
147 __stdcall static void *ntoskrnl_mmaplockedpages(ndis_buffer *, uint8_t);
148 __stdcall static void *ntoskrnl_mmaplockedpages_cache(ndis_buffer *,
149 uint8_t, uint32_t, void *, uint32_t, uint32_t);
150 __stdcall static void ntoskrnl_munmaplockedpages(void *, ndis_buffer *);
151 __stdcall static void ntoskrnl_init_lock(kspin_lock *);
152 __stdcall static size_t ntoskrnl_memcmp(const void *, const void *, size_t);
153 __stdcall static void ntoskrnl_init_ansi_string(ndis_ansi_string *, char *);
154 __stdcall static void ntoskrnl_init_unicode_string(ndis_unicode_string *,
156 __stdcall static void ntoskrnl_free_unicode_string(ndis_unicode_string *);
157 __stdcall static void ntoskrnl_free_ansi_string(ndis_ansi_string *);
158 __stdcall static ndis_status ntoskrnl_unicode_to_int(ndis_unicode_string *,
159 uint32_t, uint32_t *);
160 static int atoi (const char *);
161 static long atol (const char *);
162 static int rand(void);
163 static void ntoskrnl_time(uint64_t *);
164 __stdcall static uint8_t ntoskrnl_wdmver(uint8_t, uint8_t);
165 static void ntoskrnl_thrfunc(void *);
166 __stdcall static ndis_status ntoskrnl_create_thread(ndis_handle *,
167 uint32_t, void *, ndis_handle, void *, void *, void *);
168 __stdcall static ndis_status ntoskrnl_thread_exit(ndis_status);
169 __stdcall static ndis_status ntoskrnl_devprop(device_object *, uint32_t,
170 uint32_t, void *, uint32_t *);
171 __stdcall static void ntoskrnl_init_mutex(kmutant *, uint32_t);
172 __stdcall static uint32_t ntoskrnl_release_mutex(kmutant *, uint8_t);
173 __stdcall static uint32_t ntoskrnl_read_mutex(kmutant *);
174 __stdcall static ndis_status ntoskrnl_objref(ndis_handle, uint32_t, void *,
175 uint8_t, void **, void **);
176 __stdcall static uint32_t ntoskrnl_zwclose(ndis_handle);
177 static uint32_t ntoskrnl_dbgprint(char *, ...);
178 __stdcall static void ntoskrnl_debugger(void);
179 __stdcall static void dummy(void);
181 static struct lwkt_token ntoskrnl_dispatchtoken;
182 static kspin_lock ntoskrnl_global;
183 static int ntoskrnl_kth = 0;
184 static struct nt_objref_head ntoskrnl_reflist;
189 lwkt_token_init(&ntoskrnl_dispatchtoken);
190 ntoskrnl_init_lock(&ntoskrnl_global);
191 TAILQ_INIT(&ntoskrnl_reflist);
198 lwkt_token_uninit(&ntoskrnl_dispatchtoken);
202 __stdcall static uint8_t
203 ntoskrnl_unicode_equal(str1, str2, caseinsensitive)
204 ndis_unicode_string *str1;
205 ndis_unicode_string *str2;
206 uint8_t caseinsensitive;
210 if (str1->nus_len != str2->nus_len)
213 for (i = 0; i < str1->nus_len; i++) {
214 if (caseinsensitive == TRUE) {
215 if (toupper((char)(str1->nus_buf[i] & 0xFF)) !=
216 toupper((char)(str2->nus_buf[i] & 0xFF)))
219 if (str1->nus_buf[i] != str2->nus_buf[i])
227 __stdcall static void
228 ntoskrnl_unicode_copy(dest, src)
229 ndis_unicode_string *dest;
230 ndis_unicode_string *src;
233 if (dest->nus_maxlen >= src->nus_len)
234 dest->nus_len = src->nus_len;
236 dest->nus_len = dest->nus_maxlen;
237 memcpy(dest->nus_buf, src->nus_buf, dest->nus_len);
241 __stdcall static ndis_status
242 ntoskrnl_unicode_to_ansi(dest, src, allocate)
243 ndis_ansi_string *dest;
244 ndis_unicode_string *src;
249 if (dest == NULL || src == NULL)
250 return(NDIS_STATUS_FAILURE);
252 if (allocate == TRUE) {
253 if (ndis_unicode_to_ascii(src->nus_buf, src->nus_len, &astr))
254 return(NDIS_STATUS_FAILURE);
255 dest->nas_buf = astr;
256 dest->nas_len = dest->nas_maxlen = strlen(astr);
258 dest->nas_len = src->nus_len / 2; /* XXX */
259 if (dest->nas_maxlen < dest->nas_len)
260 dest->nas_len = dest->nas_maxlen;
261 ndis_unicode_to_ascii(src->nus_buf, dest->nas_len * 2,
264 return (NDIS_STATUS_SUCCESS);
267 __stdcall static ndis_status
268 ntoskrnl_ansi_to_unicode(dest, src, allocate)
269 ndis_unicode_string *dest;
270 ndis_ansi_string *src;
273 uint16_t *ustr = NULL;
275 if (dest == NULL || src == NULL)
276 return(NDIS_STATUS_FAILURE);
278 if (allocate == TRUE) {
279 if (ndis_ascii_to_unicode(src->nas_buf, &ustr))
280 return(NDIS_STATUS_FAILURE);
281 dest->nus_buf = ustr;
282 dest->nus_len = dest->nus_maxlen = strlen(src->nas_buf) * 2;
284 dest->nus_len = src->nas_len * 2; /* XXX */
285 if (dest->nus_maxlen < dest->nus_len)
286 dest->nus_len = dest->nus_maxlen;
287 ndis_ascii_to_unicode(src->nas_buf, &dest->nus_buf);
289 return (NDIS_STATUS_SUCCESS);
292 __stdcall static void *
293 ntoskrnl_iobuildsynchfsdreq(func, dobj, buf, len, off, event, status)
305 __stdcall __regcall static uint32_t
306 ntoskrnl_iofcalldriver(REGARGS2(void *dobj, void *irp))
311 __stdcall __regcall static void
312 ntoskrnl_iofcompletereq(REGARGS2(void *irp, uint8_t prioboost))
320 nt_dispatch_header *obj;
324 struct lwkt_tokref tokref;
328 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
329 obj->dh_sigstate = TRUE;
330 e = obj->dh_waitlisthead.nle_flink;
331 while (e != &obj->dh_waitlisthead) {
336 * For synchronization objects, only wake up
339 if (obj->dh_type == EVENT_TYPE_SYNC)
343 lwkt_reltoken(&tokref);
355 *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
362 * KeWaitForSingleObject() is a tricky beast, because it can be used
363 * with several different object types: semaphores, timers, events,
364 * mutexes and threads. Semaphores don't appear very often, but the
365 * other object types are quite common. KeWaitForSingleObject() is
366 * what's normally used to acquire a mutex, and it can be used to
367 * wait for a thread termination.
369 * The Windows NDIS API is implemented in terms of Windows kernel
370 * primitives, and some of the object manipulation is duplicated in
371 * NDIS. For example, NDIS has timers and events, which are actually
372 * Windows kevents and ktimers. Now, you're supposed to only use the
373 * NDIS variants of these objects within the confines of the NDIS API,
374 * but there are some naughty developers out there who will use
375 * KeWaitForSingleObject() on NDIS timer and event objects, so we
376 * have to support that as well. Conseqently, our NDIS timer and event
377 * code has to be closely tied into our ntoskrnl timer and event code,
378 * just as it is in Windows.
380 * KeWaitForSingleObject() may do different things for different kinds
383 * - For events, we check if the event has been signalled. If the
384 * event is already in the signalled state, we just return immediately,
385 * otherwise we wait for it to be set to the signalled state by someone
386 * else calling KeSetEvent(). Events can be either synchronization or
387 * notification events.
389 * - For timers, if the timer has already fired and the timer is in
390 * the signalled state, we just return, otherwise we wait on the
391 * timer. Unlike an event, timers get signalled automatically when
392 * they expire rather than someone having to trip them manually.
393 * Timers initialized with KeInitializeTimer() are always notification
394 * events: KeInitializeTimerEx() lets you initialize a timer as
395 * either a notification or synchronization event.
397 * - For mutexes, we try to acquire the mutex and if we can't, we wait
398 * on the mutex until it's available and then grab it. When a mutex is
399 * released, it enters the signaled state, which wakes up one of the
400 * threads waiting to acquire it. Mutexes are always synchronization
403 * - For threads, the only thing we do is wait until the thread object
404 * enters a signalled state, which occurs when the thread terminates.
405 * Threads are always notification events.
407 * A notification event wakes up all threads waiting on an object. A
408 * synchronization event wakes up just one. Also, a synchronization event
409 * is auto-clearing, which means we automatically set the event back to
410 * the non-signalled state once the wakeup is done.
414 ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime)
415 nt_dispatch_header *obj;
421 struct thread *td = curthread;
428 struct lwkt_tokref tokref;
431 return(STATUS_INVALID_PARAMETER);
433 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
436 * See if the object is a mutex. If so, and we already own
437 * it, then just increment the acquisition count and return.
439 * For any other kind of object, see if it's already in the
440 * signalled state, and if it is, just return. If the object
441 * is marked as a synchronization event, reset the state to
445 if (obj->dh_size == OTYPE_MUTEX) {
447 if (km->km_ownerthread == NULL ||
448 km->km_ownerthread == curthread->td_proc) {
449 obj->dh_sigstate = FALSE;
451 km->km_ownerthread = curthread->td_proc;
452 lwkt_reltoken(&tokref);
453 return (STATUS_SUCCESS);
455 } else if (obj->dh_sigstate == TRUE) {
456 if (obj->dh_type == EVENT_TYPE_SYNC)
457 obj->dh_sigstate = FALSE;
458 lwkt_reltoken(&tokref);
459 return (STATUS_SUCCESS);
465 INSERT_LIST_TAIL((&obj->dh_waitlisthead), (&w.wb_waitlist));
468 * The timeout value is specified in 100 nanosecond units
469 * and can be a positive or negative number. If it's positive,
470 * then the duetime is absolute, and we need to convert it
471 * to an absolute offset relative to now in order to use it.
472 * If it's negative, then the duetime is relative and we
473 * just have to convert the units.
476 if (duetime != NULL) {
478 tv.tv_sec = - (*duetime) / 10000000;
479 tv.tv_usec = (- (*duetime) / 10) -
480 (tv.tv_sec * 1000000);
482 ntoskrnl_time(&curtime);
483 if (*duetime < curtime)
484 tv.tv_sec = tv.tv_usec = 0;
486 tv.tv_sec = ((*duetime) - curtime) / 10000000;
487 tv.tv_usec = ((*duetime) - curtime) / 10 -
488 (tv.tv_sec * 1000000);
493 lwkt_reltoken(&tokref);
495 ticks = 1 + tv.tv_sec * hz + tv.tv_usec * hz / 1000000;
496 error = ndis_thsuspend(td, duetime == NULL ? 0 : ticks);
498 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
500 /* We timed out. Leave the object alone and return status. */
502 if (error == EWOULDBLOCK) {
503 REMOVE_LIST_ENTRY((&w.wb_waitlist));
504 lwkt_reltoken(&tokref);
505 return(STATUS_TIMEOUT);
509 * Mutexes are always synchronization objects, which means
510 * if several threads are waiting to acquire it, only one will
511 * be woken up. If that one is us, and the mutex is up for grabs,
515 if (obj->dh_size == OTYPE_MUTEX) {
517 if (km->km_ownerthread == NULL) {
518 km->km_ownerthread = curthread->td_proc;
523 if (obj->dh_type == EVENT_TYPE_SYNC)
524 obj->dh_sigstate = FALSE;
525 REMOVE_LIST_ENTRY((&w.wb_waitlist));
527 lwkt_reltoken(&tokref);
529 return(STATUS_SUCCESS);
532 __stdcall static uint32_t
533 ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode,
534 alertable, duetime, wb_array)
536 nt_dispatch_header *obj[];
542 wait_block *wb_array;
544 struct thread *td = curthread;
546 wait_block _wb_array[THREAD_WAIT_OBJECTS];
549 int i, wcnt = 0, widx = 0, error = 0;
551 struct timespec t1, t2;
552 struct lwkt_tokref tokref;
554 if (cnt > MAX_WAIT_OBJECTS)
555 return(STATUS_INVALID_PARAMETER);
556 if (cnt > THREAD_WAIT_OBJECTS && wb_array == NULL)
557 return(STATUS_INVALID_PARAMETER);
559 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
561 if (wb_array == NULL)
566 /* First pass: see if we can satisfy any waits immediately. */
568 for (i = 0; i < cnt; i++) {
569 if (obj[i]->dh_size == OTYPE_MUTEX) {
570 km = (kmutant *)obj[i];
571 if (km->km_ownerthread == NULL ||
572 km->km_ownerthread == curthread->td_proc) {
573 obj[i]->dh_sigstate = FALSE;
575 km->km_ownerthread = curthread->td_proc;
576 if (wtype == WAITTYPE_ANY) {
577 lwkt_reltoken(&tokref);
578 return (STATUS_WAIT_0 + i);
581 } else if (obj[i]->dh_sigstate == TRUE) {
582 if (obj[i]->dh_type == EVENT_TYPE_SYNC)
583 obj[i]->dh_sigstate = FALSE;
584 if (wtype == WAITTYPE_ANY) {
585 lwkt_reltoken(&tokref);
586 return (STATUS_WAIT_0 + i);
592 * Second pass: set up wait for anything we can't
593 * satisfy immediately.
596 for (i = 0; i < cnt; i++) {
597 if (obj[i]->dh_sigstate == TRUE)
599 INSERT_LIST_TAIL((&obj[i]->dh_waitlisthead),
600 (&w[i].wb_waitlist));
601 w[i].wb_kthread = td;
602 w[i].wb_object = obj[i];
606 if (duetime != NULL) {
608 tv.tv_sec = - (*duetime) / 10000000;
609 tv.tv_usec = (- (*duetime) / 10) -
610 (tv.tv_sec * 1000000);
612 ntoskrnl_time(&curtime);
613 if (*duetime < curtime)
614 tv.tv_sec = tv.tv_usec = 0;
616 tv.tv_sec = ((*duetime) - curtime) / 10000000;
617 tv.tv_usec = ((*duetime) - curtime) / 10 -
618 (tv.tv_sec * 1000000);
625 lwkt_reltoken(&tokref);
627 ticks = 1 + tv.tv_sec * hz + tv.tv_usec * hz / 1000000;
629 error = ndis_thsuspend(td, duetime == NULL ? 0 : ticks);
631 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
634 for (i = 0; i < cnt; i++) {
635 if (obj[i]->dh_size == OTYPE_MUTEX) {
637 if (km->km_ownerthread == NULL) {
643 if (obj[i]->dh_sigstate == TRUE) {
645 if (obj[i]->dh_type == EVENT_TYPE_SYNC)
646 obj[i]->dh_sigstate = FALSE;
647 REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
652 if (error || wtype == WAITTYPE_ANY)
655 if (duetime != NULL) {
656 tv.tv_sec -= (t2.tv_sec - t1.tv_sec);
657 tv.tv_usec -= (t2.tv_nsec - t1.tv_nsec) / 1000;
662 for (i = 0; i < cnt; i++)
663 REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
666 if (error == EWOULDBLOCK) {
667 lwkt_reltoken(&tokref);
668 return(STATUS_TIMEOUT);
671 if (wtype == WAITTYPE_ANY && wcnt) {
672 lwkt_reltoken(&tokref);
673 return(STATUS_WAIT_0 + widx);
676 lwkt_reltoken(&tokref);
678 return(STATUS_SUCCESS);
681 __stdcall static void
682 ntoskrnl_writereg_ushort(reg, val)
686 bus_space_write_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
690 __stdcall static uint16_t
691 ntoskrnl_readreg_ushort(reg)
694 return(bus_space_read_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
697 __stdcall static void
698 ntoskrnl_writereg_ulong(reg, val)
702 bus_space_write_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
706 __stdcall static uint32_t
707 ntoskrnl_readreg_ulong(reg)
710 return(bus_space_read_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
713 __stdcall static uint8_t
714 ntoskrnl_readreg_uchar(reg)
717 return(bus_space_read_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
720 __stdcall static void
721 ntoskrnl_writereg_uchar(reg, val)
725 bus_space_write_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
729 __stdcall static int64_t
737 __stdcall static int64_t
745 __stdcall static int64_t
753 __stdcall static uint64_t
761 __stdcall static uint64_t
769 __stdcall static uint64_t
777 __regparm static int64_t
785 __regparm static uint64_t
793 __regparm static int64_t
801 __regparm static uint64_t
810 ntoskrnl_pushsl(head, entry)
814 slist_entry *oldhead;
816 oldhead = head->slh_list.slh_next;
817 entry->sl_next = head->slh_list.slh_next;
818 head->slh_list.slh_next = entry;
819 head->slh_list.slh_depth++;
820 head->slh_list.slh_seq++;
831 first = head->slh_list.slh_next;
833 head->slh_list.slh_next = first->sl_next;
834 head->slh_list.slh_depth--;
835 head->slh_list.slh_seq++;
841 __stdcall static void *
842 ntoskrnl_allocfunc(pooltype, size, tag)
847 return(malloc(size, M_DEVBUF, M_NOWAIT));
850 __stdcall static void
851 ntoskrnl_freefunc(buf)
858 __stdcall static void
859 ntoskrnl_init_lookaside(lookaside, allocfunc, freefunc,
860 flags, size, tag, depth)
861 paged_lookaside_list *lookaside;
862 lookaside_alloc_func *allocfunc;
863 lookaside_free_func *freefunc;
869 bzero((char *)lookaside, sizeof(paged_lookaside_list));
871 if (size < sizeof(slist_entry))
872 lookaside->nll_l.gl_size = sizeof(slist_entry);
874 lookaside->nll_l.gl_size = size;
875 lookaside->nll_l.gl_tag = tag;
876 if (allocfunc == NULL)
877 lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc;
879 lookaside->nll_l.gl_allocfunc = allocfunc;
881 if (freefunc == NULL)
882 lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc;
884 lookaside->nll_l.gl_freefunc = freefunc;
886 ntoskrnl_init_lock(&lookaside->nll_obsoletelock);
888 lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH;
889 lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
894 __stdcall static void
895 ntoskrnl_delete_lookaside(lookaside)
896 paged_lookaside_list *lookaside;
899 __stdcall void (*freefunc)(void *);
901 freefunc = lookaside->nll_l.gl_freefunc;
902 while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
908 __stdcall static void
909 ntoskrnl_init_nplookaside(lookaside, allocfunc, freefunc,
910 flags, size, tag, depth)
911 npaged_lookaside_list *lookaside;
912 lookaside_alloc_func *allocfunc;
913 lookaside_free_func *freefunc;
919 bzero((char *)lookaside, sizeof(npaged_lookaside_list));
921 if (size < sizeof(slist_entry))
922 lookaside->nll_l.gl_size = sizeof(slist_entry);
924 lookaside->nll_l.gl_size = size;
925 lookaside->nll_l.gl_tag = tag;
926 if (allocfunc == NULL)
927 lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc;
929 lookaside->nll_l.gl_allocfunc = allocfunc;
931 if (freefunc == NULL)
932 lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc;
934 lookaside->nll_l.gl_freefunc = freefunc;
936 ntoskrnl_init_lock(&lookaside->nll_obsoletelock);
938 lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH;
939 lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
944 __stdcall static void
945 ntoskrnl_delete_nplookaside(lookaside)
946 npaged_lookaside_list *lookaside;
949 __stdcall void (*freefunc)(void *);
951 freefunc = lookaside->nll_l.gl_freefunc;
952 while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
959 * Note: the interlocked slist push and pop routines are
960 * declared to be _fastcall in Windows. gcc 3.4 is supposed
961 * to have support for this calling convention, however we
962 * don't have that version available yet, so we kludge things
963 * up using some inline assembly.
966 __stdcall __regcall static slist_entry *
967 ntoskrnl_push_slist(REGARGS2(slist_header *head, slist_entry *entry))
969 slist_entry *oldhead;
971 oldhead = (slist_entry *)FASTCALL3(ntoskrnl_push_slist_ex,
972 head, entry, &ntoskrnl_global);
977 __stdcall __regcall static slist_entry *
978 ntoskrnl_pop_slist(REGARGS1(slist_header *head))
982 first = (slist_entry *)FASTCALL2(ntoskrnl_pop_slist_ex,
983 head, &ntoskrnl_global);
988 __stdcall __regcall static slist_entry *
989 ntoskrnl_push_slist_ex(REGARGS2(slist_header *head, slist_entry *entry), kspin_lock *lock)
991 slist_entry *oldhead;
994 irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL);
995 oldhead = ntoskrnl_pushsl(head, entry);
996 FASTCALL2(hal_unlock, lock, irql);
1001 __stdcall __regcall static slist_entry *
1002 ntoskrnl_pop_slist_ex(REGARGS2(slist_header *head, kspin_lock *lock))
1007 irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL);
1008 first = ntoskrnl_popsl(head);
1009 FASTCALL2(hal_unlock, lock, irql);
1014 __stdcall __regcall void
1015 ntoskrnl_lock_dpc(REGARGS1(kspin_lock *lock))
1017 while (atomic_poll_acquire_int((volatile u_int *)lock) == 0)
1021 __stdcall __regcall void
1022 ntoskrnl_unlock_dpc(REGARGS1(kspin_lock *lock))
1024 atomic_poll_release_int((volatile u_int *)lock);
1027 __stdcall __regcall static uint32_t
1028 ntoskrnl_interlock_inc(REGARGS1(volatile uint32_t *addend))
1030 atomic_add_long((volatile u_long *)addend, 1);
1034 __stdcall __regcall static uint32_t
1035 ntoskrnl_interlock_dec(REGARGS1(volatile uint32_t *addend))
1037 atomic_subtract_long((volatile u_long *)addend, 1);
1041 __stdcall __regcall static void
1042 ntoskrnl_interlock_addstat(REGARGS2(uint64_t *addend, uint32_t inc))
1046 irql = FASTCALL2(hal_lock, &ntoskrnl_global, DISPATCH_LEVEL);
1048 FASTCALL2(hal_unlock, &ntoskrnl_global, irql);
1053 __stdcall static void
1054 ntoskrnl_freemdl(mdl)
1059 if (mdl == NULL || mdl->nb_process == NULL)
1062 head = mdl->nb_process;
1064 if (head->nb_flags != 0x1)
1067 mdl->nb_next = head->nb_next;
1068 head->nb_next = mdl;
1070 /* Decrement count of busy buffers. */
1072 head->nb_bytecount--;
1075 * If the pool has been marked for deletion and there are
1076 * no more buffers outstanding, nuke the pool.
1079 if (head->nb_byteoffset && head->nb_bytecount == 0)
1080 free(head, M_DEVBUF);
1085 __stdcall static uint32_t
1086 ntoskrnl_sizeofmdl(vaddr, len)
1092 l = sizeof(struct ndis_buffer) +
1093 (sizeof(uint32_t) * SPAN_PAGES(vaddr, len));
1098 __stdcall static void
1099 ntoskrnl_build_npaged_mdl(mdl)
1102 mdl->nb_mappedsystemva = (char *)mdl->nb_startva + mdl->nb_byteoffset;
1106 __stdcall static void *
1107 ntoskrnl_mmaplockedpages(buf, accessmode)
1111 return(MDL_VA(buf));
1114 __stdcall static void *
1115 ntoskrnl_mmaplockedpages_cache(buf, accessmode, cachetype, vaddr,
1124 return(MDL_VA(buf));
1127 __stdcall static void
1128 ntoskrnl_munmaplockedpages(vaddr, buf)
1136 * The KeInitializeSpinLock(), KefAcquireSpinLockAtDpcLevel()
1137 * and KefReleaseSpinLockFromDpcLevel() appear to be analagous
1138 * to splnet()/splx() in their use. We can't create a new mutex
1139 * lock here because there is no complimentary KeFreeSpinLock()
1140 * function. Instead, we grab a mutex from the mutex pool.
1142 __stdcall static void
1143 ntoskrnl_init_lock(lock)
1151 __stdcall static size_t
1152 ntoskrnl_memcmp(s1, s2, len)
1157 size_t i, total = 0;
1160 m1 = __DECONST(char *, s1);
1161 m2 = __DECONST(char *, s2);
1163 for (i = 0; i < len; i++) {
1170 __stdcall static void
1171 ntoskrnl_init_ansi_string(dst, src)
1172 ndis_ansi_string *dst;
1175 ndis_ansi_string *a;
1181 a->nas_len = a->nas_maxlen = 0;
1185 a->nas_len = a->nas_maxlen = strlen(src);
1191 __stdcall static void
1192 ntoskrnl_init_unicode_string(dst, src)
1193 ndis_unicode_string *dst;
1196 ndis_unicode_string *u;
1203 u->nus_len = u->nus_maxlen = 0;
1210 u->nus_len = u->nus_maxlen = i * 2;
1216 __stdcall ndis_status
1217 ntoskrnl_unicode_to_int(ustr, base, val)
1218 ndis_unicode_string *ustr;
1227 uchr = ustr->nus_buf;
1228 len = ustr->nus_len;
1229 bzero(abuf, sizeof(abuf));
1231 if ((char)((*uchr) & 0xFF) == '-') {
1235 } else if ((char)((*uchr) & 0xFF) == '+') {
1242 if ((char)((*uchr) & 0xFF) == 'b') {
1246 } else if ((char)((*uchr) & 0xFF) == 'o') {
1250 } else if ((char)((*uchr) & 0xFF) == 'x') {
1264 ndis_unicode_to_ascii(uchr, len, &astr);
1265 *val = strtoul(abuf, NULL, base);
1267 return(NDIS_STATUS_SUCCESS);
1270 __stdcall static void
1271 ntoskrnl_free_unicode_string(ustr)
1272 ndis_unicode_string *ustr;
1274 if (ustr->nus_buf == NULL)
1276 free(ustr->nus_buf, M_DEVBUF);
1277 ustr->nus_buf = NULL;
1281 __stdcall static void
1282 ntoskrnl_free_ansi_string(astr)
1283 ndis_ansi_string *astr;
1285 if (astr->nas_buf == NULL)
1287 free(astr->nas_buf, M_DEVBUF);
1288 astr->nas_buf = NULL;
1296 return (int)strtol(str, (char **)NULL, 10);
1303 return strtol(str, (char **)NULL, 10);
1312 srandom(tv.tv_usec);
1313 return((int)random());
1316 __stdcall static uint8_t
1317 ntoskrnl_wdmver(major, minor)
1321 if (major == WDM_MAJOR && minor == WDM_MINOR_WINXP)
1326 __stdcall static ndis_status
1327 ntoskrnl_devprop(devobj, regprop, buflen, prop, reslen)
1328 device_object *devobj;
1334 ndis_miniport_block *block;
1336 block = devobj->do_rsvd;
1339 case DEVPROP_DRIVER_KEYNAME:
1340 ndis_ascii_to_unicode(__DECONST(char *,
1341 device_get_nameunit(block->nmb_dev)), (uint16_t **)&prop);
1342 *reslen = strlen(device_get_nameunit(block->nmb_dev)) * 2;
1345 return(STATUS_INVALID_PARAMETER_2);
1349 return(STATUS_SUCCESS);
1352 __stdcall static void
1353 ntoskrnl_init_mutex(kmutex, level)
1357 INIT_LIST_HEAD((&kmutex->km_header.dh_waitlisthead));
1358 kmutex->km_abandoned = FALSE;
1359 kmutex->km_apcdisable = 1;
1360 kmutex->km_header.dh_sigstate = TRUE;
1361 kmutex->km_header.dh_type = EVENT_TYPE_SYNC;
1362 kmutex->km_header.dh_size = OTYPE_MUTEX;
1363 kmutex->km_acquirecnt = 0;
1364 kmutex->km_ownerthread = NULL;
1368 __stdcall static uint32_t
1369 ntoskrnl_release_mutex(kmutex, kwait)
1373 struct lwkt_tokref tokref;
1375 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
1376 if (kmutex->km_ownerthread != curthread->td_proc) {
1377 lwkt_reltoken(&tokref);
1378 return(STATUS_MUTANT_NOT_OWNED);
1380 kmutex->km_acquirecnt--;
1381 if (kmutex->km_acquirecnt == 0) {
1382 kmutex->km_ownerthread = NULL;
1383 lwkt_reltoken(&tokref);
1384 ntoskrnl_wakeup(&kmutex->km_header);
1386 lwkt_reltoken(&tokref);
1388 return(kmutex->km_acquirecnt);
1391 __stdcall static uint32_t
1392 ntoskrnl_read_mutex(kmutex)
1395 return(kmutex->km_header.dh_sigstate);
1399 ntoskrnl_init_event(kevent, type, state)
1404 INIT_LIST_HEAD((&kevent->k_header.dh_waitlisthead));
1405 kevent->k_header.dh_sigstate = state;
1406 kevent->k_header.dh_type = type;
1407 kevent->k_header.dh_size = OTYPE_EVENT;
1412 ntoskrnl_reset_event(kevent)
1416 struct lwkt_tokref tokref;
1418 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
1419 prevstate = kevent->k_header.dh_sigstate;
1420 kevent->k_header.dh_sigstate = FALSE;
1421 lwkt_reltoken(&tokref);
1427 ntoskrnl_set_event(kevent, increment, kwait)
1434 prevstate = kevent->k_header.dh_sigstate;
1435 ntoskrnl_wakeup(&kevent->k_header);
1441 ntoskrnl_clear_event(kevent)
1444 kevent->k_header.dh_sigstate = FALSE;
1449 ntoskrnl_read_event(kevent)
1452 return(kevent->k_header.dh_sigstate);
1455 __stdcall static ndis_status
1456 ntoskrnl_objref(handle, reqaccess, otype, accessmode, object, handleinfo)
1466 nr = malloc(sizeof(nt_objref), M_DEVBUF, M_NOWAIT|M_ZERO);
1468 return(NDIS_STATUS_FAILURE);
1470 INIT_LIST_HEAD((&nr->no_dh.dh_waitlisthead));
1471 nr->no_obj = handle;
1472 nr->no_dh.dh_size = OTYPE_THREAD;
1473 TAILQ_INSERT_TAIL(&ntoskrnl_reflist, nr, link);
1476 return(NDIS_STATUS_SUCCESS);
1479 __stdcall __regcall static void
1480 ntoskrnl_objderef(REGARGS1(void *object))
1485 TAILQ_REMOVE(&ntoskrnl_reflist, nr, link);
1491 __stdcall static uint32_t
1492 ntoskrnl_zwclose(handle)
1495 return(STATUS_SUCCESS);
1499 * This is here just in case the thread returns without calling
1500 * PsTerminateSystemThread().
1503 ntoskrnl_thrfunc(arg)
1506 thread_context *thrctx;
1507 __stdcall uint32_t (*tfunc)(void *);
1512 tfunc = thrctx->tc_thrfunc;
1513 tctx = thrctx->tc_thrctx;
1514 free(thrctx, M_TEMP);
1518 ntoskrnl_thread_exit(rval);
1519 return; /* notreached */
1522 __stdcall static ndis_status
1523 ntoskrnl_create_thread(handle, reqaccess, objattrs, phandle,
1524 clientid, thrfunc, thrctx)
1525 ndis_handle *handle;
1528 ndis_handle phandle;
1538 tc = malloc(sizeof(thread_context), M_TEMP, M_NOWAIT);
1540 return(NDIS_STATUS_FAILURE);
1542 tc->tc_thrctx = thrctx;
1543 tc->tc_thrfunc = thrfunc;
1545 sprintf(tname, "windows kthread %d", ntoskrnl_kth);
1546 error = kthread_create_stk(ntoskrnl_thrfunc, tc, &td,
1547 NDIS_KSTACK_PAGES * PAGE_SIZE, tname);
1556 * In Windows, the exit of a thread is an event that you're allowed
1557 * to wait on, assuming you've obtained a reference to the thread using
1558 * ObReferenceObjectByHandle(). Unfortunately, the only way we can
1559 * simulate this behavior is to register each thread we create in a
1560 * reference list, and if someone holds a reference to us, we poke
1563 __stdcall static ndis_status
1564 ntoskrnl_thread_exit(status)
1567 struct nt_objref *nr;
1569 TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) {
1570 if (nr->no_obj != curthread)
1572 ntoskrnl_wakeup(&nr->no_dh);
1579 return(0); /* notreached */
1583 ntoskrnl_dbgprint(char *fmt, ...)
1588 __va_start(ap, fmt);
1592 return(STATUS_SUCCESS);
1595 __stdcall static void
1596 ntoskrnl_debugger(void)
1599 #if __FreeBSD_version < 502113
1600 Debugger("ntoskrnl_debugger(): breakpoint");
1602 kdb_enter("ntoskrnl_debugger(): breakpoint");
1607 ntoskrnl_timercall(arg)
1614 timer->k_header.dh_inserted = FALSE;
1617 * If this is a periodic timer, re-arm it
1618 * so it will fire again. We do this before
1619 * calling any deferred procedure calls because
1620 * it's possible the DPC might cancel the timer,
1621 * in which case it would be wrong for us to
1622 * re-arm it again afterwards.
1625 if (timer->k_period) {
1626 timer->k_header.dh_inserted = TRUE;
1627 timer->k_handle = timeout(ntoskrnl_timercall, timer,
1628 1 + timer->k_period * hz / 1000);
1631 if (timer->k_dpc != NULL)
1632 ntoskrnl_queue_dpc(timer->k_dpc, NULL, NULL);
1634 ntoskrnl_wakeup(&timer->k_header);
1638 ntoskrnl_init_timer(timer)
1644 ntoskrnl_init_timer_ex(timer, EVENT_TYPE_NOTIFY);
1648 ntoskrnl_init_timer_ex(timer, type)
1655 INIT_LIST_HEAD((&timer->k_header.dh_waitlisthead));
1656 timer->k_header.dh_sigstate = FALSE;
1657 timer->k_header.dh_inserted = FALSE;
1658 timer->k_header.dh_type = type;
1659 timer->k_header.dh_size = OTYPE_TIMER;
1660 callout_handle_init(&timer->k_handle);
1666 * This is a wrapper for Windows deferred procedure calls that
1667 * have been placed on an NDIS thread work queue. We need it
1668 * since the DPC could be a _stdcall function. Also, as far as
1669 * I can tell, defered procedure calls must run at DISPATCH_LEVEL.
1672 ntoskrnl_run_dpc(arg)
1680 dpcfunc = (kdpc_func)dpc->k_deferedfunc;
1681 irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
1682 dpcfunc(dpc, dpc->k_deferredctx, dpc->k_sysarg1, dpc->k_sysarg2);
1683 FASTCALL1(hal_lower_irql, irql);
1689 ntoskrnl_init_dpc(dpc, dpcfunc, dpcctx)
1697 dpc->k_deferedfunc = dpcfunc;
1698 dpc->k_deferredctx = dpcctx;
1704 ntoskrnl_queue_dpc(dpc, sysarg1, sysarg2)
1709 dpc->k_sysarg1 = sysarg1;
1710 dpc->k_sysarg2 = sysarg2;
1711 if (ndis_sched(ntoskrnl_run_dpc, dpc, NDIS_SWI))
1718 ntoskrnl_dequeue_dpc(dpc)
1721 if (ndis_unsched(ntoskrnl_run_dpc, dpc, NDIS_SWI))
1728 ntoskrnl_set_timer_ex(timer, duetime, period, dpc)
1742 if (timer->k_header.dh_inserted == TRUE) {
1743 untimeout(ntoskrnl_timercall, timer, timer->k_handle);
1744 timer->k_header.dh_inserted = FALSE;
1749 timer->k_duetime = duetime;
1750 timer->k_period = period;
1751 timer->k_header.dh_sigstate = FALSE;
1755 tv.tv_sec = - (duetime) / 10000000;
1756 tv.tv_usec = (- (duetime) / 10) -
1757 (tv.tv_sec * 1000000);
1759 ntoskrnl_time(&curtime);
1760 if (duetime < curtime)
1761 tv.tv_sec = tv.tv_usec = 0;
1763 tv.tv_sec = ((duetime) - curtime) / 10000000;
1764 tv.tv_usec = ((duetime) - curtime) / 10 -
1765 (tv.tv_sec * 1000000);
1769 ticks = 1 + tv.tv_sec * hz + tv.tv_usec * hz / 1000000;
1770 timer->k_header.dh_inserted = TRUE;
1771 timer->k_handle = timeout(ntoskrnl_timercall, timer, ticks);
1777 ntoskrnl_set_timer(timer, duetime, dpc)
1782 return (ntoskrnl_set_timer_ex(timer, duetime, 0, dpc));
1786 ntoskrnl_cancel_timer(timer)
1794 if (timer->k_header.dh_inserted == TRUE) {
1795 untimeout(ntoskrnl_timercall, timer, timer->k_handle);
1796 if (timer->k_dpc != NULL)
1797 ntoskrnl_dequeue_dpc(timer->k_dpc);
1807 ntoskrnl_read_timer(timer)
1810 return(timer->k_header.dh_sigstate);
1813 __stdcall static void
1816 printf ("ntoskrnl dummy called...\n");
1821 image_patch_table ntoskrnl_functbl[] = {
1822 { "RtlCompareMemory", (FUNC)ntoskrnl_memcmp },
1823 { "RtlEqualUnicodeString", (FUNC)ntoskrnl_unicode_equal },
1824 { "RtlCopyUnicodeString", (FUNC)ntoskrnl_unicode_copy },
1825 { "RtlUnicodeStringToAnsiString", (FUNC)ntoskrnl_unicode_to_ansi },
1826 { "RtlAnsiStringToUnicodeString", (FUNC)ntoskrnl_ansi_to_unicode },
1827 { "RtlInitAnsiString", (FUNC)ntoskrnl_init_ansi_string },
1828 { "RtlInitUnicodeString", (FUNC)ntoskrnl_init_unicode_string },
1829 { "RtlFreeAnsiString", (FUNC)ntoskrnl_free_ansi_string },
1830 { "RtlFreeUnicodeString", (FUNC)ntoskrnl_free_unicode_string },
1831 { "RtlUnicodeStringToInteger", (FUNC)ntoskrnl_unicode_to_int },
1832 { "sprintf", (FUNC)sprintf },
1833 { "vsprintf", (FUNC)vsprintf },
1834 { "_snprintf", (FUNC)snprintf },
1835 { "_vsnprintf", (FUNC)vsnprintf },
1836 { "DbgPrint", (FUNC)ntoskrnl_dbgprint },
1837 { "DbgBreakPoint", (FUNC)ntoskrnl_debugger },
1838 { "strncmp", (FUNC)strncmp },
1839 { "strcmp", (FUNC)strcmp },
1840 { "strncpy", (FUNC)strncpy },
1841 { "strcpy", (FUNC)strcpy },
1842 { "strlen", (FUNC)strlen },
1843 { "memcpy", (FUNC)memcpy },
1844 { "memmove", (FUNC)memcpy },
1845 { "memset", (FUNC)memset },
1846 { "IofCallDriver", (FUNC)ntoskrnl_iofcalldriver },
1847 { "IofCompleteRequest", (FUNC)ntoskrnl_iofcompletereq },
1848 { "IoBuildSynchronousFsdRequest", (FUNC)ntoskrnl_iobuildsynchfsdreq },
1849 { "KeWaitForSingleObject", (FUNC)ntoskrnl_waitforobj },
1850 { "KeWaitForMultipleObjects", (FUNC)ntoskrnl_waitforobjs },
1851 { "_allmul", (FUNC)_allmul },
1852 { "_alldiv", (FUNC)_alldiv },
1853 { "_allrem", (FUNC)_allrem },
1854 { "_allshr", (FUNC)_allshr },
1855 { "_allshl", (FUNC)_allshl },
1856 { "_aullmul", (FUNC)_aullmul },
1857 { "_aulldiv", (FUNC)_aulldiv },
1858 { "_aullrem", (FUNC)_aullrem },
1859 { "_aullshr", (FUNC)_aullshr },
1860 { "_aullshl", (FUNC)_aullshl },
1861 { "atoi", (FUNC)atoi },
1862 { "atol", (FUNC)atol },
1863 { "rand", (FUNC)rand },
1864 { "WRITE_REGISTER_USHORT", (FUNC)ntoskrnl_writereg_ushort },
1865 { "READ_REGISTER_USHORT", (FUNC)ntoskrnl_readreg_ushort },
1866 { "WRITE_REGISTER_ULONG", (FUNC)ntoskrnl_writereg_ulong },
1867 { "READ_REGISTER_ULONG", (FUNC)ntoskrnl_readreg_ulong },
1868 { "READ_REGISTER_UCHAR", (FUNC)ntoskrnl_readreg_uchar },
1869 { "WRITE_REGISTER_UCHAR", (FUNC)ntoskrnl_writereg_uchar },
1870 { "ExInitializePagedLookasideList", (FUNC)ntoskrnl_init_lookaside },
1871 { "ExDeletePagedLookasideList", (FUNC)ntoskrnl_delete_lookaside },
1872 { "ExInitializeNPagedLookasideList", (FUNC)ntoskrnl_init_nplookaside },
1873 { "ExDeleteNPagedLookasideList", (FUNC)ntoskrnl_delete_nplookaside },
1874 { "InterlockedPopEntrySList", (FUNC)ntoskrnl_pop_slist },
1875 { "InterlockedPushEntrySList", (FUNC)ntoskrnl_push_slist },
1876 { "ExInterlockedPopEntrySList", (FUNC)ntoskrnl_pop_slist_ex },
1877 { "ExInterlockedPushEntrySList",(FUNC)ntoskrnl_push_slist_ex },
1878 { "KefAcquireSpinLockAtDpcLevel", (FUNC)ntoskrnl_lock_dpc },
1879 { "KefReleaseSpinLockFromDpcLevel", (FUNC)ntoskrnl_unlock_dpc },
1880 { "InterlockedIncrement", (FUNC)ntoskrnl_interlock_inc },
1881 { "InterlockedDecrement", (FUNC)ntoskrnl_interlock_dec },
1882 { "ExInterlockedAddLargeStatistic",
1883 (FUNC)ntoskrnl_interlock_addstat },
1884 { "IoFreeMdl", (FUNC)ntoskrnl_freemdl },
1885 { "MmSizeOfMdl", (FUNC)ntoskrnl_sizeofmdl },
1886 { "MmMapLockedPages", (FUNC)ntoskrnl_mmaplockedpages },
1887 { "MmMapLockedPagesSpecifyCache",
1888 (FUNC)ntoskrnl_mmaplockedpages_cache },
1889 { "MmUnmapLockedPages", (FUNC)ntoskrnl_munmaplockedpages },
1890 { "MmBuildMdlForNonPagedPool", (FUNC)ntoskrnl_build_npaged_mdl },
1891 { "KeInitializeSpinLock", (FUNC)ntoskrnl_init_lock },
1892 { "IoIsWdmVersionAvailable", (FUNC)ntoskrnl_wdmver },
1893 { "IoGetDeviceProperty", (FUNC)ntoskrnl_devprop },
1894 { "KeInitializeMutex", (FUNC)ntoskrnl_init_mutex },
1895 { "KeReleaseMutex", (FUNC)ntoskrnl_release_mutex },
1896 { "KeReadStateMutex", (FUNC)ntoskrnl_read_mutex },
1897 { "KeInitializeEvent", (FUNC)ntoskrnl_init_event },
1898 { "KeSetEvent", (FUNC)ntoskrnl_set_event },
1899 { "KeResetEvent", (FUNC)ntoskrnl_reset_event },
1900 { "KeClearEvent", (FUNC)ntoskrnl_clear_event },
1901 { "KeReadStateEvent", (FUNC)ntoskrnl_read_event },
1902 { "KeInitializeTimer", (FUNC)ntoskrnl_init_timer },
1903 { "KeInitializeTimerEx", (FUNC)ntoskrnl_init_timer_ex },
1904 { "KeSetTimer", (FUNC)ntoskrnl_set_timer },
1905 { "KeSetTimerEx", (FUNC)ntoskrnl_set_timer_ex },
1906 { "KeCancelTimer", (FUNC)ntoskrnl_cancel_timer },
1907 { "KeReadStateTimer", (FUNC)ntoskrnl_read_timer },
1908 { "KeInitializeDpc", (FUNC)ntoskrnl_init_dpc },
1909 { "KeInsertQueueDpc", (FUNC)ntoskrnl_queue_dpc },
1910 { "KeRemoveQueueDpc", (FUNC)ntoskrnl_dequeue_dpc },
1911 { "ObReferenceObjectByHandle", (FUNC)ntoskrnl_objref },
1912 { "ObfDereferenceObject", (FUNC)ntoskrnl_objderef },
1913 { "ZwClose", (FUNC)ntoskrnl_zwclose },
1914 { "PsCreateSystemThread", (FUNC)ntoskrnl_create_thread },
1915 { "PsTerminateSystemThread", (FUNC)ntoskrnl_thread_exit },
1918 * This last entry is a catch-all for any function we haven't
1919 * implemented yet. The PE import list patching routine will
1920 * use it for any function that doesn't have an explicit match
1924 { NULL, (FUNC)dummy },