Remove now unnecessary messing with PCI command register.
[dragonfly.git] / sys / emulation / ndis / subr_ntoskrnl.c
1 /*
2  * Copyright (c) 2003
3  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Bill Paul.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * $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.6 2005/06/10 23:27:02 dillon Exp $
34  */
35
36 #include <sys/ctype.h>
37 #include <sys/unistd.h>
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/errno.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/lock.h>
44
45 #include <sys/callout.h>
46 #if __FreeBSD_version > 502113
47 #include <sys/kdb.h>
48 #endif
49 #include <sys/kernel.h>
50 #include <sys/proc.h>
51 #include <sys/kthread.h>
52
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>
59
60 #include <sys/bus.h>
61 #include <sys/rman.h>
62
63 #include "regcall.h"
64 #include "pe_var.h"
65 #include "resource_var.h"
66 #include "ntoskrnl_var.h"
67 #include "ndis_var.h"
68 #include "hal_var.h"
69
70 #define __regparm __attribute__((regparm(3)))
71
72 #define FUNC void(*)(void)
73
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 *);
84
85 /*
86  * registerized calls
87  */
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));
100
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));
109
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 *,
155         uint16_t *);
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);
180
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;
185
186 static MALLOC_DEFINE(M_NDIS, "ndis", "ndis emulation");
187
188 int
189 ntoskrnl_libinit()
190 {
191         lwkt_token_init(&ntoskrnl_dispatchtoken);
192         ntoskrnl_init_lock(&ntoskrnl_global);
193         TAILQ_INIT(&ntoskrnl_reflist);
194         return(0);
195 }
196
197 int
198 ntoskrnl_libfini()
199 {
200         lwkt_token_uninit(&ntoskrnl_dispatchtoken);
201         return(0);
202 }
203
204 __stdcall static uint8_t 
205 ntoskrnl_unicode_equal(str1, str2, caseinsensitive)
206         ndis_unicode_string     *str1;
207         ndis_unicode_string     *str2;
208         uint8_t                 caseinsensitive;
209 {
210         int                     i;
211
212         if (str1->nus_len != str2->nus_len)
213                 return(FALSE);
214
215         for (i = 0; i < str1->nus_len; i++) {
216                 if (caseinsensitive == TRUE) {
217                         if (toupper((char)(str1->nus_buf[i] & 0xFF)) !=
218                             toupper((char)(str2->nus_buf[i] & 0xFF)))
219                                 return(FALSE);
220                 } else {
221                         if (str1->nus_buf[i] != str2->nus_buf[i])
222                                 return(FALSE);
223                 }
224         }
225
226         return(TRUE);
227 }
228
229 __stdcall static void
230 ntoskrnl_unicode_copy(dest, src)
231         ndis_unicode_string     *dest;
232         ndis_unicode_string     *src;
233 {
234
235         if (dest->nus_maxlen >= src->nus_len)
236                 dest->nus_len = src->nus_len;
237         else
238                 dest->nus_len = dest->nus_maxlen;
239         memcpy(dest->nus_buf, src->nus_buf, dest->nus_len);
240         return;
241 }
242
243 __stdcall static ndis_status
244 ntoskrnl_unicode_to_ansi(dest, src, allocate)
245         ndis_ansi_string        *dest;
246         ndis_unicode_string     *src;
247         uint8_t                 allocate;
248 {
249         char                    *astr = NULL;
250
251         if (dest == NULL || src == NULL)
252                 return(NDIS_STATUS_FAILURE);
253
254         if (allocate == TRUE) {
255                 if (ndis_unicode_to_ascii(src->nus_buf, src->nus_len, &astr))
256                         return(NDIS_STATUS_FAILURE);
257                 dest->nas_buf = astr;
258                 dest->nas_len = dest->nas_maxlen = strlen(astr);
259         } else {
260                 dest->nas_len = src->nus_len / 2; /* XXX */
261                 if (dest->nas_maxlen < dest->nas_len)
262                         dest->nas_len = dest->nas_maxlen;
263                 ndis_unicode_to_ascii(src->nus_buf, dest->nas_len * 2,
264                     &dest->nas_buf);
265         }
266         return (NDIS_STATUS_SUCCESS);
267 }
268
269 __stdcall static ndis_status
270 ntoskrnl_ansi_to_unicode(dest, src, allocate)
271         ndis_unicode_string     *dest;
272         ndis_ansi_string        *src;
273         uint8_t                 allocate;
274 {
275         uint16_t                *ustr = NULL;
276
277         if (dest == NULL || src == NULL)
278                 return(NDIS_STATUS_FAILURE);
279
280         if (allocate == TRUE) {
281                 if (ndis_ascii_to_unicode(src->nas_buf, &ustr))
282                         return(NDIS_STATUS_FAILURE);
283                 dest->nus_buf = ustr;
284                 dest->nus_len = dest->nus_maxlen = strlen(src->nas_buf) * 2;
285         } else {
286                 dest->nus_len = src->nas_len * 2; /* XXX */
287                 if (dest->nus_maxlen < dest->nus_len)
288                         dest->nus_len = dest->nus_maxlen;
289                 ndis_ascii_to_unicode(src->nas_buf, &dest->nus_buf);
290         }
291         return (NDIS_STATUS_SUCCESS);
292 }
293
294 __stdcall static void *
295 ntoskrnl_iobuildsynchfsdreq(func, dobj, buf, len, off, event, status)
296         uint32_t                func;
297         void                    *dobj;
298         void                    *buf;
299         uint32_t                len;
300         uint32_t                *off;
301         void                    *event;
302         void                    *status;
303 {
304         return(NULL);
305 }
306         
307 __stdcall __regcall static uint32_t
308 ntoskrnl_iofcalldriver(REGARGS2(void *dobj, void *irp))
309 {
310         return(0);
311 }
312
313 __stdcall __regcall static void
314 ntoskrnl_iofcompletereq(REGARGS2(void *irp, uint8_t prioboost))
315 {
316 }
317
318 static void
319 ntoskrnl_wakeup(arg)
320         void                    *arg;
321 {
322         nt_dispatch_header      *obj;
323         wait_block              *w;
324         list_entry              *e;
325         struct thread           *td;
326         struct lwkt_tokref      tokref;
327
328         obj = arg;
329
330         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
331         obj->dh_sigstate = TRUE;
332         e = obj->dh_waitlisthead.nle_flink;
333         while (e != &obj->dh_waitlisthead) {
334                 w = (wait_block *)e;
335                 td = w->wb_kthread;
336                 ndis_thresume(td);
337                 /*
338                  * For synchronization objects, only wake up
339                  * the first waiter.
340                  */
341                 if (obj->dh_type == EVENT_TYPE_SYNC)
342                         break;
343                 e = e->nle_flink;
344         }
345         lwkt_reltoken(&tokref);
346
347         return;
348 }
349
350 static void 
351 ntoskrnl_time(tval)
352         uint64_t                *tval;
353 {
354         struct timespec         ts;
355
356         nanotime(&ts);
357         *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
358             11644473600LL;
359
360         return;
361 }
362
363 /*
364  * KeWaitForSingleObject() is a tricky beast, because it can be used
365  * with several different object types: semaphores, timers, events,
366  * mutexes and threads. Semaphores don't appear very often, but the
367  * other object types are quite common. KeWaitForSingleObject() is
368  * what's normally used to acquire a mutex, and it can be used to
369  * wait for a thread termination.
370  *
371  * The Windows NDIS API is implemented in terms of Windows kernel
372  * primitives, and some of the object manipulation is duplicated in
373  * NDIS. For example, NDIS has timers and events, which are actually
374  * Windows kevents and ktimers. Now, you're supposed to only use the
375  * NDIS variants of these objects within the confines of the NDIS API,
376  * but there are some naughty developers out there who will use
377  * KeWaitForSingleObject() on NDIS timer and event objects, so we
378  * have to support that as well. Conseqently, our NDIS timer and event
379  * code has to be closely tied into our ntoskrnl timer and event code,
380  * just as it is in Windows.
381  *
382  * KeWaitForSingleObject() may do different things for different kinds
383  * of objects:
384  *
385  * - For events, we check if the event has been signalled. If the
386  *   event is already in the signalled state, we just return immediately,
387  *   otherwise we wait for it to be set to the signalled state by someone
388  *   else calling KeSetEvent(). Events can be either synchronization or
389  *   notification events.
390  *
391  * - For timers, if the timer has already fired and the timer is in
392  *   the signalled state, we just return, otherwise we wait on the
393  *   timer. Unlike an event, timers get signalled automatically when
394  *   they expire rather than someone having to trip them manually.
395  *   Timers initialized with KeInitializeTimer() are always notification
396  *   events: KeInitializeTimerEx() lets you initialize a timer as
397  *   either a notification or synchronization event.
398  *
399  * - For mutexes, we try to acquire the mutex and if we can't, we wait
400  *   on the mutex until it's available and then grab it. When a mutex is
401  *   released, it enters the signaled state, which wakes up one of the
402  *   threads waiting to acquire it. Mutexes are always synchronization
403  *   events.
404  *
405  * - For threads, the only thing we do is wait until the thread object
406  *   enters a signalled state, which occurs when the thread terminates.
407  *   Threads are always notification events.
408  *
409  * A notification event wakes up all threads waiting on an object. A
410  * synchronization event wakes up just one. Also, a synchronization event
411  * is auto-clearing, which means we automatically set the event back to
412  * the non-signalled state once the wakeup is done.
413  */
414
415 __stdcall uint32_t
416 ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime)
417         nt_dispatch_header      *obj;
418         uint32_t                reason;
419         uint32_t                mode;
420         uint8_t                 alertable;
421         int64_t                 *duetime;
422 {
423         struct thread           *td = curthread;
424         kmutant                 *km;
425         wait_block              w;
426         struct timeval          tv;
427         int                     error = 0;
428         int                     ticks;
429         uint64_t                curtime;
430         struct lwkt_tokref      tokref;
431
432         if (obj == NULL)
433                 return(STATUS_INVALID_PARAMETER);
434
435         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
436
437         /*
438          * See if the object is a mutex. If so, and we already own
439          * it, then just increment the acquisition count and return.
440          *
441          * For any other kind of object, see if it's already in the
442          * signalled state, and if it is, just return. If the object
443          * is marked as a synchronization event, reset the state to
444          * unsignalled.
445          */
446
447         if (obj->dh_size == OTYPE_MUTEX) {
448                 km = (kmutant *)obj;
449                 if (km->km_ownerthread == NULL ||
450                     km->km_ownerthread == curthread->td_proc) {
451                         obj->dh_sigstate = FALSE;
452                         km->km_acquirecnt++;
453                         km->km_ownerthread = curthread->td_proc;
454                         lwkt_reltoken(&tokref);
455                         return (STATUS_SUCCESS);
456                 }
457         } else if (obj->dh_sigstate == TRUE) {
458                 if (obj->dh_type == EVENT_TYPE_SYNC)
459                         obj->dh_sigstate = FALSE;
460                 lwkt_reltoken(&tokref);
461                 return (STATUS_SUCCESS);
462         }
463
464         w.wb_object = obj;
465         w.wb_kthread = td;
466
467         INSERT_LIST_TAIL((&obj->dh_waitlisthead), (&w.wb_waitlist));
468
469         /*
470          * The timeout value is specified in 100 nanosecond units
471          * and can be a positive or negative number. If it's positive,
472          * then the duetime is absolute, and we need to convert it
473          * to an absolute offset relative to now in order to use it.
474          * If it's negative, then the duetime is relative and we
475          * just have to convert the units.
476          */
477
478         if (duetime != NULL) {
479                 if (*duetime < 0) {
480                         tv.tv_sec = - (*duetime) / 10000000;
481                         tv.tv_usec = (- (*duetime) / 10) -
482                             (tv.tv_sec * 1000000);
483                 } else {
484                         ntoskrnl_time(&curtime);
485                         if (*duetime < curtime)
486                                 tv.tv_sec = tv.tv_usec = 0;
487                         else {
488                                 tv.tv_sec = ((*duetime) - curtime) / 10000000;
489                                 tv.tv_usec = ((*duetime) - curtime) / 10 -
490                                     (tv.tv_sec * 1000000);
491                         }
492                 }
493         }
494
495         lwkt_reltoken(&tokref);
496
497         ticks = 1 + tv.tv_sec * hz + tv.tv_usec * hz / 1000000;
498         error = ndis_thsuspend(td, duetime == NULL ? 0 : ticks);
499
500         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
501
502         /* We timed out. Leave the object alone and return status. */
503
504         if (error == EWOULDBLOCK) {
505                 REMOVE_LIST_ENTRY((&w.wb_waitlist));
506                 lwkt_reltoken(&tokref);
507                 return(STATUS_TIMEOUT);
508         }
509
510         /*
511          * Mutexes are always synchronization objects, which means
512          * if several threads are waiting to acquire it, only one will
513          * be woken up. If that one is us, and the mutex is up for grabs,
514          * grab it.
515          */
516
517         if (obj->dh_size == OTYPE_MUTEX) {
518                 km = (kmutant *)obj;
519                 if (km->km_ownerthread == NULL) {
520                         km->km_ownerthread = curthread->td_proc;
521                         km->km_acquirecnt++;
522                 }
523         }
524
525         if (obj->dh_type == EVENT_TYPE_SYNC)
526                 obj->dh_sigstate = FALSE;
527         REMOVE_LIST_ENTRY((&w.wb_waitlist));
528
529         lwkt_reltoken(&tokref);
530
531         return(STATUS_SUCCESS);
532 }
533
534 __stdcall static uint32_t
535 ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode,
536         alertable, duetime, wb_array)
537         uint32_t                cnt;
538         nt_dispatch_header      *obj[];
539         uint32_t                wtype;
540         uint32_t                reason;
541         uint32_t                mode;
542         uint8_t                 alertable;
543         int64_t                 *duetime;
544         wait_block              *wb_array;
545 {
546         struct thread           *td = curthread;
547         kmutant                 *km;
548         wait_block              _wb_array[THREAD_WAIT_OBJECTS];
549         wait_block              *w;
550         struct timeval          tv;
551         int                     i, wcnt = 0, widx = 0, error = 0;
552         uint64_t                curtime;
553         struct timespec         t1, t2;
554         struct lwkt_tokref      tokref;
555
556         if (cnt > MAX_WAIT_OBJECTS)
557                 return(STATUS_INVALID_PARAMETER);
558         if (cnt > THREAD_WAIT_OBJECTS && wb_array == NULL)
559                 return(STATUS_INVALID_PARAMETER);
560
561         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
562
563         if (wb_array == NULL)
564                 w = &_wb_array[0];
565         else
566                 w = wb_array;
567
568         /* First pass: see if we can satisfy any waits immediately. */
569
570         for (i = 0; i < cnt; i++) {
571                 if (obj[i]->dh_size == OTYPE_MUTEX) {
572                         km = (kmutant *)obj[i];
573                         if (km->km_ownerthread == NULL ||
574                             km->km_ownerthread == curthread->td_proc) {
575                                 obj[i]->dh_sigstate = FALSE;
576                                 km->km_acquirecnt++;
577                                 km->km_ownerthread = curthread->td_proc;
578                                 if (wtype == WAITTYPE_ANY) {
579                                         lwkt_reltoken(&tokref);
580                                         return (STATUS_WAIT_0 + i);
581                                 }
582                         }
583                 } else if (obj[i]->dh_sigstate == TRUE) {
584                         if (obj[i]->dh_type == EVENT_TYPE_SYNC)
585                                 obj[i]->dh_sigstate = FALSE;
586                         if (wtype == WAITTYPE_ANY) {
587                                 lwkt_reltoken(&tokref);
588                                 return (STATUS_WAIT_0 + i);
589                         }
590                 }
591         }
592
593         /*
594          * Second pass: set up wait for anything we can't
595          * satisfy immediately.
596          */
597
598         for (i = 0; i < cnt; i++) {
599                 if (obj[i]->dh_sigstate == TRUE)
600                         continue;
601                 INSERT_LIST_TAIL((&obj[i]->dh_waitlisthead),
602                     (&w[i].wb_waitlist));
603                 w[i].wb_kthread = td;
604                 w[i].wb_object = obj[i];
605                 wcnt++;
606         }
607
608         if (duetime != NULL) {
609                 if (*duetime < 0) {
610                         tv.tv_sec = - (*duetime) / 10000000;
611                         tv.tv_usec = (- (*duetime) / 10) -
612                             (tv.tv_sec * 1000000);
613                 } else {
614                         ntoskrnl_time(&curtime);
615                         if (*duetime < curtime)
616                                 tv.tv_sec = tv.tv_usec = 0;
617                         else {
618                                 tv.tv_sec = ((*duetime) - curtime) / 10000000;
619                                 tv.tv_usec = ((*duetime) - curtime) / 10 -
620                                     (tv.tv_sec * 1000000);
621                         }
622                 }
623         }
624
625         while (wcnt) {
626                 nanotime(&t1);
627                 lwkt_reltoken(&tokref);
628
629                 ticks = 1 + tv.tv_sec * hz + tv.tv_usec * hz / 1000000;
630
631                 error = ndis_thsuspend(td, duetime == NULL ? 0 : ticks);
632
633                 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
634                 nanotime(&t2);
635
636                 for (i = 0; i < cnt; i++) {
637                         if (obj[i]->dh_size == OTYPE_MUTEX) {
638                                 km = (kmutant *)obj;
639                                 if (km->km_ownerthread == NULL) {
640                                         km->km_ownerthread =
641                                             curthread->td_proc;
642                                         km->km_acquirecnt++;
643                                 }
644                         }
645                         if (obj[i]->dh_sigstate == TRUE) {
646                                 widx = i;
647                                 if (obj[i]->dh_type == EVENT_TYPE_SYNC)
648                                         obj[i]->dh_sigstate = FALSE;
649                                 REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
650                                 wcnt--;
651                         }
652                 }
653
654                 if (error || wtype == WAITTYPE_ANY)
655                         break;
656
657                 if (duetime != NULL) {
658                         tv.tv_sec -= (t2.tv_sec - t1.tv_sec);
659                         tv.tv_usec -= (t2.tv_nsec - t1.tv_nsec) / 1000;
660                 }
661         }
662
663         if (wcnt) {
664                 for (i = 0; i < cnt; i++)
665                         REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
666         }
667
668         if (error == EWOULDBLOCK) {
669                 lwkt_reltoken(&tokref);
670                 return(STATUS_TIMEOUT);
671         }
672
673         if (wtype == WAITTYPE_ANY && wcnt) {
674                 lwkt_reltoken(&tokref);
675                 return(STATUS_WAIT_0 + widx);
676         }
677
678         lwkt_reltoken(&tokref);
679
680         return(STATUS_SUCCESS);
681 }
682
683 __stdcall static void
684 ntoskrnl_writereg_ushort(reg, val)
685         uint16_t                *reg;
686         uint16_t                val;
687 {
688         bus_space_write_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
689         return;
690 }
691
692 __stdcall static uint16_t
693 ntoskrnl_readreg_ushort(reg)
694         uint16_t                *reg;
695 {
696         return(bus_space_read_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
697 }
698
699 __stdcall static void
700 ntoskrnl_writereg_ulong(reg, val)
701         uint32_t                *reg;
702         uint32_t                val;
703 {
704         bus_space_write_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
705         return;
706 }
707
708 __stdcall static uint32_t
709 ntoskrnl_readreg_ulong(reg)
710         uint32_t                *reg;
711 {
712         return(bus_space_read_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
713 }
714
715 __stdcall static uint8_t
716 ntoskrnl_readreg_uchar(reg)
717         uint8_t                 *reg;
718 {
719         return(bus_space_read_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
720 }
721
722 __stdcall static void
723 ntoskrnl_writereg_uchar(reg, val)
724         uint8_t                 *reg;
725         uint8_t                 val;
726 {
727         bus_space_write_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
728         return;
729 }
730
731 __stdcall static int64_t
732 _allmul(a, b)
733         int64_t                 a;
734         int64_t                 b;
735 {
736         return (a * b);
737 }
738
739 __stdcall static int64_t
740 _alldiv(a, b)
741         int64_t                 a;
742         int64_t                 b;
743 {
744         return (a / b);
745 }
746
747 __stdcall static int64_t
748 _allrem(a, b)
749         int64_t                 a;
750         int64_t                 b;
751 {
752         return (a % b);
753 }
754
755 __stdcall static uint64_t
756 _aullmul(a, b)
757         uint64_t                a;
758         uint64_t                b;
759 {
760         return (a * b);
761 }
762
763 __stdcall static uint64_t
764 _aulldiv(a, b)
765         uint64_t                a;
766         uint64_t                b;
767 {
768         return (a / b);
769 }
770
771 __stdcall static uint64_t
772 _aullrem(a, b)
773         uint64_t                a;
774         uint64_t                b;
775 {
776         return (a % b);
777 }
778
779 __regparm static int64_t
780 _allshl(a, b)
781         int64_t                 a;
782         uint8_t                 b;
783 {
784         return (a << b);
785 }
786
787 __regparm static uint64_t
788 _aullshl(a, b)
789         uint64_t                a;
790         uint8_t                 b;
791 {
792         return (a << b);
793 }
794
795 __regparm static int64_t
796 _allshr(a, b)
797         int64_t                 a;
798         uint8_t                 b;
799 {
800         return (a >> b);
801 }
802
803 __regparm static uint64_t
804 _aullshr(a, b)
805         uint64_t                a;
806         uint8_t                 b;
807 {
808         return (a >> b);
809 }
810
811 static slist_entry *
812 ntoskrnl_pushsl(head, entry)
813         slist_header            *head;
814         slist_entry             *entry;
815 {
816         slist_entry             *oldhead;
817
818         oldhead = head->slh_list.slh_next;
819         entry->sl_next = head->slh_list.slh_next;
820         head->slh_list.slh_next = entry;
821         head->slh_list.slh_depth++;
822         head->slh_list.slh_seq++;
823
824         return(oldhead);
825 }
826
827 static slist_entry *
828 ntoskrnl_popsl(head)
829         slist_header            *head;
830 {
831         slist_entry             *first;
832
833         first = head->slh_list.slh_next;
834         if (first != NULL) {
835                 head->slh_list.slh_next = first->sl_next;
836                 head->slh_list.slh_depth--;
837                 head->slh_list.slh_seq++;
838         }
839
840         return(first);
841 }
842
843 __stdcall static void *
844 ntoskrnl_allocfunc(pooltype, size, tag)
845         uint32_t                pooltype;
846         size_t                  size;
847         uint32_t                tag;
848 {
849         return(malloc(size, M_DEVBUF, M_WAITOK));
850 }
851
852 __stdcall static void
853 ntoskrnl_freefunc(buf)
854         void                    *buf;
855 {
856         free(buf, M_DEVBUF);
857         return;
858 }
859
860 __stdcall static void
861 ntoskrnl_init_lookaside(lookaside, allocfunc, freefunc,
862     flags, size, tag, depth)
863         paged_lookaside_list    *lookaside;
864         lookaside_alloc_func    *allocfunc;
865         lookaside_free_func     *freefunc;
866         uint32_t                flags;
867         size_t                  size;
868         uint32_t                tag;
869         uint16_t                depth;
870 {
871         bzero((char *)lookaside, sizeof(paged_lookaside_list));
872
873         if (size < sizeof(slist_entry))
874                 lookaside->nll_l.gl_size = sizeof(slist_entry);
875         else
876                 lookaside->nll_l.gl_size = size;
877         lookaside->nll_l.gl_tag = tag;
878         if (allocfunc == NULL)
879                 lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc;
880         else
881                 lookaside->nll_l.gl_allocfunc = allocfunc;
882
883         if (freefunc == NULL)
884                 lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc;
885         else
886                 lookaside->nll_l.gl_freefunc = freefunc;
887
888         ntoskrnl_init_lock(&lookaside->nll_obsoletelock);
889
890         lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH;
891         lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
892
893         return;
894 }
895
896 __stdcall static void
897 ntoskrnl_delete_lookaside(lookaside)
898         paged_lookaside_list   *lookaside;
899 {
900         void                    *buf;
901         __stdcall void          (*freefunc)(void *);
902
903         freefunc = lookaside->nll_l.gl_freefunc;
904         while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
905                 freefunc(buf);
906
907         return;
908 }
909
910 __stdcall static void
911 ntoskrnl_init_nplookaside(lookaside, allocfunc, freefunc,
912     flags, size, tag, depth)
913         npaged_lookaside_list   *lookaside;
914         lookaside_alloc_func    *allocfunc;
915         lookaside_free_func     *freefunc;
916         uint32_t                flags;
917         size_t                  size;
918         uint32_t                tag;
919         uint16_t                depth;
920 {
921         bzero((char *)lookaside, sizeof(npaged_lookaside_list));
922
923         if (size < sizeof(slist_entry))
924                 lookaside->nll_l.gl_size = sizeof(slist_entry);
925         else
926                 lookaside->nll_l.gl_size = size;
927         lookaside->nll_l.gl_tag = tag;
928         if (allocfunc == NULL)
929                 lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc;
930         else
931                 lookaside->nll_l.gl_allocfunc = allocfunc;
932
933         if (freefunc == NULL)
934                 lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc;
935         else
936                 lookaside->nll_l.gl_freefunc = freefunc;
937
938         ntoskrnl_init_lock(&lookaside->nll_obsoletelock);
939
940         lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH;
941         lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
942
943         return;
944 }
945
946 __stdcall static void
947 ntoskrnl_delete_nplookaside(lookaside)
948         npaged_lookaside_list   *lookaside;
949 {
950         void                    *buf;
951         __stdcall void          (*freefunc)(void *);
952
953         freefunc = lookaside->nll_l.gl_freefunc;
954         while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
955                 freefunc(buf);
956
957         return;
958 }
959
960 /*
961  * Note: the interlocked slist push and pop routines are
962  * declared to be _fastcall in Windows. gcc 3.4 is supposed
963  * to have support for this calling convention, however we
964  * don't have that version available yet, so we kludge things
965  * up using some inline assembly.
966  */
967
968 __stdcall __regcall static slist_entry *
969 ntoskrnl_push_slist(REGARGS2(slist_header *head, slist_entry *entry))
970 {
971         slist_entry             *oldhead;
972
973         oldhead = (slist_entry *)FASTCALL3(ntoskrnl_push_slist_ex,
974             head, entry, &ntoskrnl_global);
975
976         return(oldhead);
977 }
978
979 __stdcall __regcall static slist_entry *
980 ntoskrnl_pop_slist(REGARGS1(slist_header *head))
981 {
982         slist_entry             *first;
983
984         first = (slist_entry *)FASTCALL2(ntoskrnl_pop_slist_ex,
985             head, &ntoskrnl_global);
986
987         return(first);
988 }
989
990 __stdcall __regcall static slist_entry *
991 ntoskrnl_push_slist_ex(REGARGS2(slist_header *head, slist_entry *entry), kspin_lock *lock)
992 {
993         slist_entry             *oldhead;
994         uint8_t                 irql;
995
996         irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL);
997         oldhead = ntoskrnl_pushsl(head, entry);
998         FASTCALL2(hal_unlock, lock, irql);
999
1000         return(oldhead);
1001 }
1002
1003 __stdcall __regcall static slist_entry *
1004 ntoskrnl_pop_slist_ex(REGARGS2(slist_header *head, kspin_lock *lock))
1005 {
1006         slist_entry             *first;
1007         uint8_t                 irql;
1008
1009         irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL);
1010         first = ntoskrnl_popsl(head);
1011         FASTCALL2(hal_unlock, lock, irql);
1012
1013         return(first);
1014 }
1015
1016 __stdcall __regcall void
1017 ntoskrnl_lock_dpc(REGARGS1(kspin_lock *lock))
1018 {
1019         while (atomic_poll_acquire_int((volatile u_int *)lock) == 0)
1020                 /* sit and spin */;
1021 }
1022
1023 __stdcall __regcall void
1024 ntoskrnl_unlock_dpc(REGARGS1(kspin_lock *lock))
1025 {
1026         atomic_poll_release_int((volatile u_int *)lock);
1027 }
1028
1029 __stdcall __regcall static uint32_t
1030 ntoskrnl_interlock_inc(REGARGS1(volatile uint32_t *addend))
1031 {
1032         atomic_add_long((volatile u_long *)addend, 1);
1033         return(*addend);
1034 }
1035
1036 __stdcall __regcall static uint32_t
1037 ntoskrnl_interlock_dec(REGARGS1(volatile uint32_t *addend))
1038 {
1039         atomic_subtract_long((volatile u_long *)addend, 1);
1040         return(*addend);
1041 }
1042
1043 __stdcall __regcall static void
1044 ntoskrnl_interlock_addstat(REGARGS2(uint64_t *addend, uint32_t inc))
1045 {
1046         uint8_t                 irql;
1047
1048         irql = FASTCALL2(hal_lock, &ntoskrnl_global, DISPATCH_LEVEL);
1049         *addend += inc;
1050         FASTCALL2(hal_unlock, &ntoskrnl_global, irql);
1051
1052         return;
1053 };
1054
1055 __stdcall static void
1056 ntoskrnl_freemdl(mdl)
1057         ndis_buffer             *mdl;
1058 {
1059         ndis_buffer             *head;
1060
1061         if (mdl == NULL || mdl->nb_process == NULL)
1062                 return;
1063
1064         head = mdl->nb_process;
1065
1066         if (head->nb_flags != 0x1)
1067                 return;
1068
1069         mdl->nb_next = head->nb_next;
1070         head->nb_next = mdl;
1071
1072         /* Decrement count of busy buffers. */
1073
1074         head->nb_bytecount--;
1075
1076         /*
1077          * If the pool has been marked for deletion and there are
1078          * no more buffers outstanding, nuke the pool.
1079          */
1080
1081         if (head->nb_byteoffset && head->nb_bytecount == 0)
1082                 free(head, M_DEVBUF);
1083
1084         return;
1085 }
1086
1087 __stdcall static uint32_t
1088 ntoskrnl_sizeofmdl(vaddr, len)
1089         void                    *vaddr;
1090         size_t                  len;
1091 {
1092         uint32_t                l;
1093
1094         l = sizeof(struct ndis_buffer) +
1095             (sizeof(uint32_t) * SPAN_PAGES(vaddr, len));
1096
1097         return(l);
1098 }
1099
1100 __stdcall static void
1101 ntoskrnl_build_npaged_mdl(mdl)
1102         ndis_buffer             *mdl;
1103 {
1104         mdl->nb_mappedsystemva = (char *)mdl->nb_startva + mdl->nb_byteoffset;
1105         return;
1106 }
1107
1108 __stdcall static void *
1109 ntoskrnl_mmaplockedpages(buf, accessmode)
1110         ndis_buffer             *buf;
1111         uint8_t                 accessmode;
1112 {
1113         return(MDL_VA(buf));
1114 }
1115
1116 __stdcall static void *
1117 ntoskrnl_mmaplockedpages_cache(buf, accessmode, cachetype, vaddr,
1118     bugcheck, prio)
1119         ndis_buffer             *buf;
1120         uint8_t                 accessmode;
1121         uint32_t                cachetype;
1122         void                    *vaddr;
1123         uint32_t                bugcheck;
1124         uint32_t                prio;
1125 {
1126         return(MDL_VA(buf));
1127 }
1128
1129 __stdcall static void
1130 ntoskrnl_munmaplockedpages(vaddr, buf)
1131         void                    *vaddr;
1132         ndis_buffer             *buf;
1133 {
1134         return;
1135 }
1136
1137 /*
1138  * The KeInitializeSpinLock(), KefAcquireSpinLockAtDpcLevel()
1139  * and KefReleaseSpinLockFromDpcLevel() appear to be analagous
1140  * to crit_enter()/crit_exit() in their use. We can't create a new mutex
1141  * lock here because there is no complimentary KeFreeSpinLock()
1142  * function. Instead, we grab a mutex from the mutex pool.
1143  */
1144 __stdcall static void
1145 ntoskrnl_init_lock(lock)
1146         kspin_lock              *lock;
1147 {
1148         *lock = 0;
1149
1150         return;
1151 }
1152
1153 __stdcall static size_t
1154 ntoskrnl_memcmp(s1, s2, len)
1155         const void              *s1;
1156         const void              *s2;
1157         size_t                  len;
1158 {
1159         size_t                  i, total = 0;
1160         uint8_t                 *m1, *m2;
1161
1162         m1 = __DECONST(char *, s1);
1163         m2 = __DECONST(char *, s2);
1164
1165         for (i = 0; i < len; i++) {
1166                 if (m1[i] == m2[i])
1167                         total++;
1168         }
1169         return(total);
1170 }
1171
1172 __stdcall static void
1173 ntoskrnl_init_ansi_string(dst, src)
1174         ndis_ansi_string        *dst;
1175         char                    *src;
1176 {
1177         ndis_ansi_string        *a;
1178
1179         a = dst;
1180         if (a == NULL)
1181                 return;
1182         if (src == NULL) {
1183                 a->nas_len = a->nas_maxlen = 0;
1184                 a->nas_buf = NULL;
1185         } else {
1186                 a->nas_buf = src;
1187                 a->nas_len = a->nas_maxlen = strlen(src);
1188         }
1189
1190         return;
1191 }
1192
1193 __stdcall static void
1194 ntoskrnl_init_unicode_string(dst, src)
1195         ndis_unicode_string     *dst;
1196         uint16_t                *src;
1197 {
1198         ndis_unicode_string     *u;
1199         int                     i;
1200
1201         u = dst;
1202         if (u == NULL)
1203                 return;
1204         if (src == NULL) {
1205                 u->nus_len = u->nus_maxlen = 0;
1206                 u->nus_buf = NULL;
1207         } else {
1208                 i = 0;
1209                 while(src[i] != 0)
1210                         i++;
1211                 u->nus_buf = src;
1212                 u->nus_len = u->nus_maxlen = i * 2;
1213         }
1214
1215         return;
1216 }
1217
1218 __stdcall ndis_status
1219 ntoskrnl_unicode_to_int(ustr, base, val)
1220         ndis_unicode_string     *ustr;
1221         uint32_t                base;
1222         uint32_t                *val;
1223 {
1224         uint16_t                *uchr;
1225         int                     len, neg = 0;
1226         char                    abuf[64];
1227         char                    *astr;
1228
1229         uchr = ustr->nus_buf;
1230         len = ustr->nus_len;
1231         bzero(abuf, sizeof(abuf));
1232
1233         if ((char)((*uchr) & 0xFF) == '-') {
1234                 neg = 1;
1235                 uchr++;
1236                 len -= 2;
1237         } else if ((char)((*uchr) & 0xFF) == '+') {
1238                 neg = 0;
1239                 uchr++;
1240                 len -= 2;
1241         }
1242
1243         if (base == 0) {
1244                 if ((char)((*uchr) & 0xFF) == 'b') {
1245                         base = 2;
1246                         uchr++;
1247                         len -= 2;
1248                 } else if ((char)((*uchr) & 0xFF) == 'o') {
1249                         base = 8;
1250                         uchr++;
1251                         len -= 2;
1252                 } else if ((char)((*uchr) & 0xFF) == 'x') {
1253                         base = 16;
1254                         uchr++;
1255                         len -= 2;
1256                 } else
1257                         base = 10;
1258         }
1259
1260         astr = abuf;
1261         if (neg) {
1262                 strcpy(astr, "-");
1263                 astr++;
1264         }
1265
1266         ndis_unicode_to_ascii(uchr, len, &astr);
1267         *val = strtoul(abuf, NULL, base);
1268
1269         return(NDIS_STATUS_SUCCESS);
1270 }
1271
1272 __stdcall static void
1273 ntoskrnl_free_unicode_string(ustr)
1274         ndis_unicode_string     *ustr;
1275 {
1276         if (ustr->nus_buf == NULL)
1277                 return;
1278         free(ustr->nus_buf, M_DEVBUF);
1279         ustr->nus_buf = NULL;
1280         return;
1281 }
1282
1283 __stdcall static void
1284 ntoskrnl_free_ansi_string(astr)
1285         ndis_ansi_string        *astr;
1286 {
1287         if (astr->nas_buf == NULL)
1288                 return;
1289         free(astr->nas_buf, M_DEVBUF);
1290         astr->nas_buf = NULL;
1291         return;
1292 }
1293
1294 static int
1295 atoi(str)
1296         const char              *str;
1297 {
1298         return (int)strtol(str, (char **)NULL, 10);
1299 }
1300
1301 static long
1302 atol(str)
1303         const char              *str;
1304 {
1305         return strtol(str, (char **)NULL, 10);
1306 }
1307
1308 static int
1309 rand(void)
1310 {
1311         struct timeval          tv;
1312
1313         microtime(&tv);
1314         srandom(tv.tv_usec);
1315         return((int)random());
1316 }
1317
1318 __stdcall static uint8_t
1319 ntoskrnl_wdmver(major, minor)
1320         uint8_t                 major;
1321         uint8_t                 minor;
1322 {
1323         if (major == WDM_MAJOR && minor == WDM_MINOR_WINXP)
1324                 return(TRUE);
1325         return(FALSE);
1326 }
1327
1328 __stdcall static ndis_status
1329 ntoskrnl_devprop(devobj, regprop, buflen, prop, reslen)
1330         device_object           *devobj;
1331         uint32_t                regprop;
1332         uint32_t                buflen;
1333         void                    *prop;
1334         uint32_t                *reslen;
1335 {
1336         ndis_miniport_block     *block;
1337
1338         block = devobj->do_rsvd;
1339
1340         switch (regprop) {
1341         case DEVPROP_DRIVER_KEYNAME:
1342                 ndis_ascii_to_unicode(__DECONST(char *,
1343                     device_get_nameunit(block->nmb_dev)), (uint16_t **)&prop);
1344                 *reslen = strlen(device_get_nameunit(block->nmb_dev)) * 2;
1345                 break;
1346         default:
1347                 return(STATUS_INVALID_PARAMETER_2);
1348                 break;
1349         }
1350
1351         return(STATUS_SUCCESS);
1352 }
1353
1354 __stdcall static void
1355 ntoskrnl_init_mutex(kmutex, level)
1356         kmutant                 *kmutex;
1357         uint32_t                level;
1358 {
1359         INIT_LIST_HEAD((&kmutex->km_header.dh_waitlisthead));
1360         kmutex->km_abandoned = FALSE;
1361         kmutex->km_apcdisable = 1;
1362         kmutex->km_header.dh_sigstate = TRUE;
1363         kmutex->km_header.dh_type = EVENT_TYPE_SYNC;
1364         kmutex->km_header.dh_size = OTYPE_MUTEX;
1365         kmutex->km_acquirecnt = 0;
1366         kmutex->km_ownerthread = NULL;
1367         return;
1368 }
1369
1370 __stdcall static uint32_t
1371 ntoskrnl_release_mutex(kmutex, kwait)
1372         kmutant                 *kmutex;
1373         uint8_t                 kwait;
1374 {
1375         struct lwkt_tokref      tokref;
1376
1377         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
1378         if (kmutex->km_ownerthread != curthread->td_proc) {
1379                 lwkt_reltoken(&tokref);
1380                 return(STATUS_MUTANT_NOT_OWNED);
1381         }
1382         kmutex->km_acquirecnt--;
1383         if (kmutex->km_acquirecnt == 0) {
1384                 kmutex->km_ownerthread = NULL;
1385                 lwkt_reltoken(&tokref);
1386                 ntoskrnl_wakeup(&kmutex->km_header);
1387         } else
1388                 lwkt_reltoken(&tokref);
1389
1390         return(kmutex->km_acquirecnt);
1391 }
1392
1393 __stdcall static uint32_t
1394 ntoskrnl_read_mutex(kmutex)
1395         kmutant                 *kmutex;
1396 {
1397         return(kmutex->km_header.dh_sigstate);
1398 }
1399
1400 __stdcall void
1401 ntoskrnl_init_event(kevent, type, state)
1402         nt_kevent               *kevent;
1403         uint32_t                type;
1404         uint8_t                 state;
1405 {
1406         INIT_LIST_HEAD((&kevent->k_header.dh_waitlisthead));
1407         kevent->k_header.dh_sigstate = state;
1408         kevent->k_header.dh_type = type;
1409         kevent->k_header.dh_size = OTYPE_EVENT;
1410         return;
1411 }
1412
1413 __stdcall uint32_t
1414 ntoskrnl_reset_event(kevent)
1415         nt_kevent               *kevent;
1416 {
1417         uint32_t                prevstate;
1418         struct lwkt_tokref      tokref;
1419
1420         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
1421         prevstate = kevent->k_header.dh_sigstate;
1422         kevent->k_header.dh_sigstate = FALSE;
1423         lwkt_reltoken(&tokref);
1424
1425         return(prevstate);
1426 }
1427
1428 __stdcall uint32_t
1429 ntoskrnl_set_event(kevent, increment, kwait)
1430         nt_kevent               *kevent;
1431         uint32_t                increment;
1432         uint8_t                 kwait;
1433 {
1434         uint32_t                prevstate;
1435
1436         prevstate = kevent->k_header.dh_sigstate;
1437         ntoskrnl_wakeup(&kevent->k_header);
1438
1439         return(prevstate);
1440 }
1441
1442 __stdcall void
1443 ntoskrnl_clear_event(kevent)
1444         nt_kevent               *kevent;
1445 {
1446         kevent->k_header.dh_sigstate = FALSE;
1447         return;
1448 }
1449
1450 __stdcall uint32_t
1451 ntoskrnl_read_event(kevent)
1452         nt_kevent               *kevent;
1453 {
1454         return(kevent->k_header.dh_sigstate);
1455 }
1456
1457 __stdcall static ndis_status
1458 ntoskrnl_objref(handle, reqaccess, otype, accessmode, object, handleinfo)
1459         ndis_handle             handle;
1460         uint32_t                reqaccess;
1461         void                    *otype;
1462         uint8_t                 accessmode;
1463         void                    **object;
1464         void                    **handleinfo;
1465 {
1466         nt_objref               *nr;
1467
1468         nr = malloc(sizeof(nt_objref), M_DEVBUF, M_WAITOK|M_ZERO);
1469
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);
1474         *object = nr;
1475
1476         return(NDIS_STATUS_SUCCESS);
1477 }
1478
1479 __stdcall __regcall static void
1480 ntoskrnl_objderef(REGARGS1(void *object))
1481 {
1482         nt_objref               *nr;
1483
1484         nr = object;
1485         TAILQ_REMOVE(&ntoskrnl_reflist, nr, link);
1486         free(nr, M_DEVBUF);
1487
1488         return;
1489 }
1490
1491 __stdcall static uint32_t
1492 ntoskrnl_zwclose(handle)
1493         ndis_handle             handle;
1494 {
1495         return(STATUS_SUCCESS);
1496 }
1497
1498 /*
1499  * This is here just in case the thread returns without calling
1500  * PsTerminateSystemThread().
1501  */
1502 static void
1503 ntoskrnl_thrfunc(arg)
1504         void                    *arg;
1505 {
1506         thread_context          *thrctx;
1507         __stdcall uint32_t (*tfunc)(void *);
1508         void                    *tctx;
1509         uint32_t                rval;
1510
1511         thrctx = arg;
1512         tfunc = thrctx->tc_thrfunc;
1513         tctx = thrctx->tc_thrctx;
1514         free(thrctx, M_TEMP);
1515
1516         rval = tfunc(tctx);
1517
1518         ntoskrnl_thread_exit(rval);
1519         return; /* notreached */
1520 }
1521
1522 __stdcall static ndis_status
1523 ntoskrnl_create_thread(handle, reqaccess, objattrs, phandle,
1524         clientid, thrfunc, thrctx)
1525         ndis_handle             *handle;
1526         uint32_t                reqaccess;
1527         void                    *objattrs;
1528         ndis_handle             phandle;
1529         void                    *clientid;
1530         void                    *thrfunc;
1531         void                    *thrctx;
1532 {
1533         int                     error;
1534         char                    tname[128];
1535         thread_context          *tc;
1536         thread_t                td;
1537
1538         tc = malloc(sizeof(thread_context), M_TEMP, M_WAITOK);
1539
1540         tc->tc_thrctx = thrctx;
1541         tc->tc_thrfunc = thrfunc;
1542
1543         sprintf(tname, "windows kthread %d", ntoskrnl_kth);
1544         error = kthread_create_stk(ntoskrnl_thrfunc, tc, &td,
1545             NDIS_KSTACK_PAGES * PAGE_SIZE, tname);
1546         *handle = td;
1547
1548         ntoskrnl_kth++;
1549
1550         return(error);
1551 }
1552
1553 /*
1554  * In Windows, the exit of a thread is an event that you're allowed
1555  * to wait on, assuming you've obtained a reference to the thread using
1556  * ObReferenceObjectByHandle(). Unfortunately, the only way we can
1557  * simulate this behavior is to register each thread we create in a
1558  * reference list, and if someone holds a reference to us, we poke
1559  * them.
1560  */
1561 __stdcall static ndis_status
1562 ntoskrnl_thread_exit(status)
1563         ndis_status             status;
1564 {
1565         struct nt_objref        *nr;
1566
1567         TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) {
1568                 if (nr->no_obj != curthread)
1569                         continue;
1570                 ntoskrnl_wakeup(&nr->no_dh);
1571                 break;
1572         }
1573
1574         ntoskrnl_kth--;
1575
1576         kthread_exit();
1577         return(0);      /* notreached */
1578 }
1579
1580 static uint32_t
1581 ntoskrnl_dbgprint(char *fmt, ...)
1582 {
1583         __va_list                       ap;
1584
1585         if (bootverbose) {
1586                 __va_start(ap, fmt);
1587                 vprintf(fmt, ap);
1588         }
1589
1590         return(STATUS_SUCCESS);
1591 }
1592
1593 __stdcall static void
1594 ntoskrnl_debugger(void)
1595 {
1596
1597 #if __FreeBSD_version < 502113
1598         Debugger("ntoskrnl_debugger(): breakpoint");
1599 #else
1600         kdb_enter("ntoskrnl_debugger(): breakpoint");
1601 #endif
1602 }
1603
1604 static void
1605 ntoskrnl_timercall(arg)
1606         void                    *arg;
1607 {
1608         ktimer                  *timer;
1609
1610         timer = arg;
1611
1612         timer->k_header.dh_inserted = FALSE;
1613
1614         /*
1615          * If this is a periodic timer, re-arm it
1616          * so it will fire again. We do this before
1617          * calling any deferred procedure calls because
1618          * it's possible the DPC might cancel the timer,
1619          * in which case it would be wrong for us to
1620          * re-arm it again afterwards.
1621          */
1622
1623         if (timer->k_period) {
1624                 timer->k_header.dh_inserted = TRUE;
1625                 callout_reset(timer->k_handle, 1 + timer->k_period * hz / 1000,
1626                               ntoskrnl_timercall, timer);
1627         } else {
1628                 callout_deactivate(timer->k_handle);
1629                 free(timer->k_handle, M_NDIS);
1630                 timer->k_handle = NULL;
1631         }
1632
1633         if (timer->k_dpc != NULL)
1634                 ntoskrnl_queue_dpc(timer->k_dpc, NULL, NULL);
1635
1636         ntoskrnl_wakeup(&timer->k_header);
1637 }
1638
1639 __stdcall void
1640 ntoskrnl_init_timer(timer)
1641         ktimer                  *timer;
1642 {
1643         if (timer == NULL)
1644                 return;
1645
1646         ntoskrnl_init_timer_ex(timer,  EVENT_TYPE_NOTIFY);
1647 }
1648
1649 __stdcall void
1650 ntoskrnl_init_timer_ex(timer, type)
1651         ktimer                  *timer;
1652         uint32_t                type;
1653 {
1654         if (timer == NULL)
1655                 return;
1656
1657         INIT_LIST_HEAD((&timer->k_header.dh_waitlisthead));
1658         timer->k_header.dh_sigstate = FALSE;
1659         timer->k_header.dh_inserted = FALSE;
1660         timer->k_header.dh_type = type;
1661         timer->k_header.dh_size = OTYPE_TIMER;
1662         timer->k_handle = NULL;
1663
1664         return;
1665 }
1666
1667 /*
1668  * This is a wrapper for Windows deferred procedure calls that
1669  * have been placed on an NDIS thread work queue. We need it
1670  * since the DPC could be a _stdcall function. Also, as far as
1671  * I can tell, defered procedure calls must run at DISPATCH_LEVEL.
1672  */
1673 static void
1674 ntoskrnl_run_dpc(arg)
1675         void                    *arg;
1676 {
1677         kdpc_func               dpcfunc;
1678         kdpc                    *dpc;
1679         uint8_t                 irql;
1680
1681         dpc = arg;
1682         dpcfunc = (kdpc_func)dpc->k_deferedfunc;
1683         irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
1684         dpcfunc(dpc, dpc->k_deferredctx, dpc->k_sysarg1, dpc->k_sysarg2);
1685         FASTCALL1(hal_lower_irql, irql);
1686
1687         return;
1688 }
1689
1690 __stdcall void
1691 ntoskrnl_init_dpc(dpc, dpcfunc, dpcctx)
1692         kdpc                    *dpc;
1693         void                    *dpcfunc;
1694         void                    *dpcctx;
1695 {
1696         if (dpc == NULL)
1697                 return;
1698
1699         dpc->k_deferedfunc = dpcfunc;
1700         dpc->k_deferredctx = dpcctx;
1701
1702         return;
1703 }
1704
1705 __stdcall uint8_t
1706 ntoskrnl_queue_dpc(dpc, sysarg1, sysarg2)
1707         kdpc                    *dpc;
1708         void                    *sysarg1;
1709         void                    *sysarg2;
1710 {
1711         dpc->k_sysarg1 = sysarg1;
1712         dpc->k_sysarg2 = sysarg2;
1713         if (ndis_sched(ntoskrnl_run_dpc, dpc, NDIS_SWI))
1714                 return(FALSE);
1715
1716         return(TRUE);
1717 }
1718
1719 __stdcall uint8_t
1720 ntoskrnl_dequeue_dpc(dpc)
1721         kdpc                    *dpc;
1722 {
1723         if (ndis_unsched(ntoskrnl_run_dpc, dpc, NDIS_SWI))
1724                 return(FALSE);
1725
1726         return(TRUE);
1727 }
1728
1729 __stdcall uint8_t
1730 ntoskrnl_set_timer_ex(timer, duetime, period, dpc)
1731         ktimer                  *timer;
1732         int64_t                 duetime;
1733         uint32_t                period;
1734         kdpc                    *dpc;
1735 {
1736         struct timeval          tv;
1737         uint64_t                curtime;
1738         uint8_t                 pending;
1739         int                     ticks;
1740
1741         if (timer == NULL)
1742                 return(FALSE);
1743
1744         if (timer->k_header.dh_inserted == TRUE) {
1745                 if (timer->k_handle != NULL)
1746                         callout_stop(timer->k_handle);
1747                 timer->k_header.dh_inserted = FALSE;
1748                 pending = TRUE;
1749         } else
1750                 pending = FALSE;
1751
1752         timer->k_duetime = duetime;
1753         timer->k_period = period;
1754         timer->k_header.dh_sigstate = FALSE;
1755         timer->k_dpc = dpc;
1756
1757         if (duetime < 0) {
1758                 tv.tv_sec = - (duetime) / 10000000;
1759                 tv.tv_usec = (- (duetime) / 10) -
1760                     (tv.tv_sec * 1000000);
1761         } else {
1762                 ntoskrnl_time(&curtime);
1763                 if (duetime < curtime)
1764                         tv.tv_sec = tv.tv_usec = 0;
1765                 else {
1766                         tv.tv_sec = ((duetime) - curtime) / 10000000;
1767                         tv.tv_usec = ((duetime) - curtime) / 10 -
1768                             (tv.tv_sec * 1000000);
1769                 }
1770         }
1771
1772         ticks = 1 + tv.tv_sec * hz + tv.tv_usec * hz / 1000000;
1773         timer->k_header.dh_inserted = TRUE;
1774         if (timer->k_handle == NULL) {
1775                 timer->k_handle = malloc(sizeof(struct callout), M_NDIS,
1776                                          M_INTWAIT);
1777                 callout_init(timer->k_handle);
1778         }
1779         callout_reset(timer->k_handle, ticks, ntoskrnl_timercall, timer);
1780
1781         return(pending);
1782 }
1783
1784 __stdcall uint8_t
1785 ntoskrnl_set_timer(timer, duetime, dpc)
1786         ktimer                  *timer;
1787         int64_t                 duetime;
1788         kdpc                    *dpc;
1789 {
1790         return (ntoskrnl_set_timer_ex(timer, duetime, 0, dpc));
1791 }
1792
1793 __stdcall uint8_t
1794 ntoskrnl_cancel_timer(timer)
1795         ktimer                  *timer;
1796 {
1797         uint8_t                 pending;
1798
1799         if (timer == NULL)
1800                 return(FALSE);
1801
1802         if (timer->k_header.dh_inserted == TRUE) {
1803                 if (timer->k_handle != NULL) {
1804                         callout_stop(timer->k_handle);
1805                         free(timer->k_handle, M_NDIS);
1806                         timer->k_handle = NULL;
1807                 }
1808                 if (timer->k_dpc != NULL)
1809                         ntoskrnl_dequeue_dpc(timer->k_dpc);
1810                 pending = TRUE;
1811         } else
1812                 pending = FALSE;
1813
1814
1815         return(pending);
1816 }
1817
1818 __stdcall uint8_t
1819 ntoskrnl_read_timer(timer)
1820         ktimer                  *timer;
1821 {
1822         return(timer->k_header.dh_sigstate);
1823 }
1824
1825 __stdcall static void
1826 dummy()
1827 {
1828         printf ("ntoskrnl dummy called...\n");
1829         return;
1830 }
1831
1832
1833 image_patch_table ntoskrnl_functbl[] = {
1834         { "RtlCompareMemory",           (FUNC)ntoskrnl_memcmp },
1835         { "RtlEqualUnicodeString",      (FUNC)ntoskrnl_unicode_equal },
1836         { "RtlCopyUnicodeString",       (FUNC)ntoskrnl_unicode_copy },
1837         { "RtlUnicodeStringToAnsiString", (FUNC)ntoskrnl_unicode_to_ansi },
1838         { "RtlAnsiStringToUnicodeString", (FUNC)ntoskrnl_ansi_to_unicode },
1839         { "RtlInitAnsiString",          (FUNC)ntoskrnl_init_ansi_string },
1840         { "RtlInitUnicodeString",       (FUNC)ntoskrnl_init_unicode_string },
1841         { "RtlFreeAnsiString",          (FUNC)ntoskrnl_free_ansi_string },
1842         { "RtlFreeUnicodeString",       (FUNC)ntoskrnl_free_unicode_string },
1843         { "RtlUnicodeStringToInteger",  (FUNC)ntoskrnl_unicode_to_int },
1844         { "sprintf",                    (FUNC)sprintf },
1845         { "vsprintf",                   (FUNC)vsprintf },
1846         { "_snprintf",                  (FUNC)snprintf },
1847         { "_vsnprintf",                 (FUNC)vsnprintf },
1848         { "DbgPrint",                   (FUNC)ntoskrnl_dbgprint },
1849         { "DbgBreakPoint",              (FUNC)ntoskrnl_debugger },
1850         { "strncmp",                    (FUNC)strncmp },
1851         { "strcmp",                     (FUNC)strcmp },
1852         { "strncpy",                    (FUNC)strncpy },
1853         { "strcpy",                     (FUNC)strcpy },
1854         { "strlen",                     (FUNC)strlen },
1855         { "memcpy",                     (FUNC)memcpy },
1856         { "memmove",                    (FUNC)memcpy },
1857         { "memset",                     (FUNC)memset },
1858         { "IofCallDriver",              (FUNC)ntoskrnl_iofcalldriver },
1859         { "IofCompleteRequest",         (FUNC)ntoskrnl_iofcompletereq },
1860         { "IoBuildSynchronousFsdRequest", (FUNC)ntoskrnl_iobuildsynchfsdreq },
1861         { "KeWaitForSingleObject",      (FUNC)ntoskrnl_waitforobj },
1862         { "KeWaitForMultipleObjects",   (FUNC)ntoskrnl_waitforobjs },
1863         { "_allmul",                    (FUNC)_allmul },
1864         { "_alldiv",                    (FUNC)_alldiv },
1865         { "_allrem",                    (FUNC)_allrem },
1866         { "_allshr",                    (FUNC)_allshr },
1867         { "_allshl",                    (FUNC)_allshl },
1868         { "_aullmul",                   (FUNC)_aullmul },
1869         { "_aulldiv",                   (FUNC)_aulldiv },
1870         { "_aullrem",                   (FUNC)_aullrem },
1871         { "_aullshr",                   (FUNC)_aullshr },
1872         { "_aullshl",                   (FUNC)_aullshl },
1873         { "atoi",                       (FUNC)atoi },
1874         { "atol",                       (FUNC)atol },
1875         { "rand",                       (FUNC)rand },
1876         { "WRITE_REGISTER_USHORT",      (FUNC)ntoskrnl_writereg_ushort },
1877         { "READ_REGISTER_USHORT",       (FUNC)ntoskrnl_readreg_ushort },
1878         { "WRITE_REGISTER_ULONG",       (FUNC)ntoskrnl_writereg_ulong },
1879         { "READ_REGISTER_ULONG",        (FUNC)ntoskrnl_readreg_ulong },
1880         { "READ_REGISTER_UCHAR",        (FUNC)ntoskrnl_readreg_uchar },
1881         { "WRITE_REGISTER_UCHAR",       (FUNC)ntoskrnl_writereg_uchar },
1882         { "ExInitializePagedLookasideList", (FUNC)ntoskrnl_init_lookaside },
1883         { "ExDeletePagedLookasideList", (FUNC)ntoskrnl_delete_lookaside },
1884         { "ExInitializeNPagedLookasideList", (FUNC)ntoskrnl_init_nplookaside },
1885         { "ExDeleteNPagedLookasideList", (FUNC)ntoskrnl_delete_nplookaside },
1886         { "InterlockedPopEntrySList",   (FUNC)ntoskrnl_pop_slist },
1887         { "InterlockedPushEntrySList",  (FUNC)ntoskrnl_push_slist },
1888         { "ExInterlockedPopEntrySList", (FUNC)ntoskrnl_pop_slist_ex },
1889         { "ExInterlockedPushEntrySList",(FUNC)ntoskrnl_push_slist_ex },
1890         { "KefAcquireSpinLockAtDpcLevel", (FUNC)ntoskrnl_lock_dpc },
1891         { "KefReleaseSpinLockFromDpcLevel", (FUNC)ntoskrnl_unlock_dpc },
1892         { "InterlockedIncrement",       (FUNC)ntoskrnl_interlock_inc },
1893         { "InterlockedDecrement",       (FUNC)ntoskrnl_interlock_dec },
1894         { "ExInterlockedAddLargeStatistic",
1895                                         (FUNC)ntoskrnl_interlock_addstat },
1896         { "IoFreeMdl",                  (FUNC)ntoskrnl_freemdl },
1897         { "MmSizeOfMdl",                (FUNC)ntoskrnl_sizeofmdl },
1898         { "MmMapLockedPages",           (FUNC)ntoskrnl_mmaplockedpages },
1899         { "MmMapLockedPagesSpecifyCache",
1900                                         (FUNC)ntoskrnl_mmaplockedpages_cache },
1901         { "MmUnmapLockedPages",         (FUNC)ntoskrnl_munmaplockedpages },
1902         { "MmBuildMdlForNonPagedPool",  (FUNC)ntoskrnl_build_npaged_mdl },
1903         { "KeInitializeSpinLock",       (FUNC)ntoskrnl_init_lock },
1904         { "IoIsWdmVersionAvailable",    (FUNC)ntoskrnl_wdmver },
1905         { "IoGetDeviceProperty",        (FUNC)ntoskrnl_devprop },
1906         { "KeInitializeMutex",          (FUNC)ntoskrnl_init_mutex },
1907         { "KeReleaseMutex",             (FUNC)ntoskrnl_release_mutex },
1908         { "KeReadStateMutex",           (FUNC)ntoskrnl_read_mutex },
1909         { "KeInitializeEvent",          (FUNC)ntoskrnl_init_event },
1910         { "KeSetEvent",                 (FUNC)ntoskrnl_set_event },
1911         { "KeResetEvent",               (FUNC)ntoskrnl_reset_event },
1912         { "KeClearEvent",               (FUNC)ntoskrnl_clear_event },
1913         { "KeReadStateEvent",           (FUNC)ntoskrnl_read_event },
1914         { "KeInitializeTimer",          (FUNC)ntoskrnl_init_timer },
1915         { "KeInitializeTimerEx",        (FUNC)ntoskrnl_init_timer_ex },
1916         { "KeSetTimer",                 (FUNC)ntoskrnl_set_timer },
1917         { "KeSetTimerEx",               (FUNC)ntoskrnl_set_timer_ex },
1918         { "KeCancelTimer",              (FUNC)ntoskrnl_cancel_timer },
1919         { "KeReadStateTimer",           (FUNC)ntoskrnl_read_timer },
1920         { "KeInitializeDpc",            (FUNC)ntoskrnl_init_dpc },
1921         { "KeInsertQueueDpc",           (FUNC)ntoskrnl_queue_dpc },
1922         { "KeRemoveQueueDpc",           (FUNC)ntoskrnl_dequeue_dpc },
1923         { "ObReferenceObjectByHandle",  (FUNC)ntoskrnl_objref },
1924         { "ObfDereferenceObject",       (FUNC)ntoskrnl_objderef },
1925         { "ZwClose",                    (FUNC)ntoskrnl_zwclose },
1926         { "PsCreateSystemThread",       (FUNC)ntoskrnl_create_thread },
1927         { "PsTerminateSystemThread",    (FUNC)ntoskrnl_thread_exit },
1928
1929         /*
1930          * This last entry is a catch-all for any function we haven't
1931          * implemented yet. The PE import list patching routine will
1932          * use it for any function that doesn't have an explicit match
1933          * in this table.
1934          */
1935
1936         { NULL, (FUNC)dummy },
1937
1938         /* End of list. */
1939
1940         { NULL, NULL },
1941 };