Merge from vendor branch OPENSSL:
[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.2 2004/07/29 21:35:57 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 int
187 ntoskrnl_libinit()
188 {
189         lwkt_token_init(&ntoskrnl_dispatchtoken);
190         ntoskrnl_init_lock(&ntoskrnl_global);
191         TAILQ_INIT(&ntoskrnl_reflist);
192         return(0);
193 }
194
195 int
196 ntoskrnl_libfini()
197 {
198         lwkt_token_uninit(&ntoskrnl_dispatchtoken);
199         return(0);
200 }
201
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;
207 {
208         int                     i;
209
210         if (str1->nus_len != str2->nus_len)
211                 return(FALSE);
212
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)))
217                                 return(FALSE);
218                 } else {
219                         if (str1->nus_buf[i] != str2->nus_buf[i])
220                                 return(FALSE);
221                 }
222         }
223
224         return(TRUE);
225 }
226
227 __stdcall static void
228 ntoskrnl_unicode_copy(dest, src)
229         ndis_unicode_string     *dest;
230         ndis_unicode_string     *src;
231 {
232
233         if (dest->nus_maxlen >= src->nus_len)
234                 dest->nus_len = src->nus_len;
235         else
236                 dest->nus_len = dest->nus_maxlen;
237         memcpy(dest->nus_buf, src->nus_buf, dest->nus_len);
238         return;
239 }
240
241 __stdcall static ndis_status
242 ntoskrnl_unicode_to_ansi(dest, src, allocate)
243         ndis_ansi_string        *dest;
244         ndis_unicode_string     *src;
245         uint8_t                 allocate;
246 {
247         char                    *astr = NULL;
248
249         if (dest == NULL || src == NULL)
250                 return(NDIS_STATUS_FAILURE);
251
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);
257         } else {
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,
262                     &dest->nas_buf);
263         }
264         return (NDIS_STATUS_SUCCESS);
265 }
266
267 __stdcall static ndis_status
268 ntoskrnl_ansi_to_unicode(dest, src, allocate)
269         ndis_unicode_string     *dest;
270         ndis_ansi_string        *src;
271         uint8_t                 allocate;
272 {
273         uint16_t                *ustr = NULL;
274
275         if (dest == NULL || src == NULL)
276                 return(NDIS_STATUS_FAILURE);
277
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;
283         } else {
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);
288         }
289         return (NDIS_STATUS_SUCCESS);
290 }
291
292 __stdcall static void *
293 ntoskrnl_iobuildsynchfsdreq(func, dobj, buf, len, off, event, status)
294         uint32_t                func;
295         void                    *dobj;
296         void                    *buf;
297         uint32_t                len;
298         uint32_t                *off;
299         void                    *event;
300         void                    *status;
301 {
302         return(NULL);
303 }
304         
305 __stdcall __regcall static uint32_t
306 ntoskrnl_iofcalldriver(REGARGS2(void *dobj, void *irp))
307 {
308         return(0);
309 }
310
311 __stdcall __regcall static void
312 ntoskrnl_iofcompletereq(REGARGS2(void *irp, uint8_t prioboost))
313 {
314 }
315
316 static void
317 ntoskrnl_wakeup(arg)
318         void                    *arg;
319 {
320         nt_dispatch_header      *obj;
321         wait_block              *w;
322         list_entry              *e;
323         struct thread           *td;
324         struct lwkt_tokref      tokref;
325
326         obj = arg;
327
328         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
329         obj->dh_sigstate = TRUE;
330         e = obj->dh_waitlisthead.nle_flink;
331         while (e != &obj->dh_waitlisthead) {
332                 w = (wait_block *)e;
333                 td = w->wb_kthread;
334                 ndis_thresume(td);
335                 /*
336                  * For synchronization objects, only wake up
337                  * the first waiter.
338                  */
339                 if (obj->dh_type == EVENT_TYPE_SYNC)
340                         break;
341                 e = e->nle_flink;
342         }
343         lwkt_reltoken(&tokref);
344
345         return;
346 }
347
348 static void 
349 ntoskrnl_time(tval)
350         uint64_t                *tval;
351 {
352         struct timespec         ts;
353
354         nanotime(&ts);
355         *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
356             11644473600LL;
357
358         return;
359 }
360
361 /*
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.
368  *
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.
379  *
380  * KeWaitForSingleObject() may do different things for different kinds
381  * of objects:
382  *
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.
388  *
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.
396  *
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
401  *   events.
402  *
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.
406  *
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.
411  */
412
413 __stdcall uint32_t
414 ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime)
415         nt_dispatch_header      *obj;
416         uint32_t                reason;
417         uint32_t                mode;
418         uint8_t                 alertable;
419         int64_t                 *duetime;
420 {
421         struct thread           *td = curthread;
422         kmutant                 *km;
423         wait_block              w;
424         struct timeval          tv;
425         int                     error = 0;
426         int                     ticks;
427         uint64_t                curtime;
428         struct lwkt_tokref      tokref;
429
430         if (obj == NULL)
431                 return(STATUS_INVALID_PARAMETER);
432
433         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
434
435         /*
436          * See if the object is a mutex. If so, and we already own
437          * it, then just increment the acquisition count and return.
438          *
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
442          * unsignalled.
443          */
444
445         if (obj->dh_size == OTYPE_MUTEX) {
446                 km = (kmutant *)obj;
447                 if (km->km_ownerthread == NULL ||
448                     km->km_ownerthread == curthread->td_proc) {
449                         obj->dh_sigstate = FALSE;
450                         km->km_acquirecnt++;
451                         km->km_ownerthread = curthread->td_proc;
452                         lwkt_reltoken(&tokref);
453                         return (STATUS_SUCCESS);
454                 }
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);
460         }
461
462         w.wb_object = obj;
463         w.wb_kthread = td;
464
465         INSERT_LIST_TAIL((&obj->dh_waitlisthead), (&w.wb_waitlist));
466
467         /*
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.
474          */
475
476         if (duetime != NULL) {
477                 if (*duetime < 0) {
478                         tv.tv_sec = - (*duetime) / 10000000;
479                         tv.tv_usec = (- (*duetime) / 10) -
480                             (tv.tv_sec * 1000000);
481                 } else {
482                         ntoskrnl_time(&curtime);
483                         if (*duetime < curtime)
484                                 tv.tv_sec = tv.tv_usec = 0;
485                         else {
486                                 tv.tv_sec = ((*duetime) - curtime) / 10000000;
487                                 tv.tv_usec = ((*duetime) - curtime) / 10 -
488                                     (tv.tv_sec * 1000000);
489                         }
490                 }
491         }
492
493         lwkt_reltoken(&tokref);
494
495         ticks = 1 + tv.tv_sec * hz + tv.tv_usec * hz / 1000000;
496         error = ndis_thsuspend(td, duetime == NULL ? 0 : ticks);
497
498         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
499
500         /* We timed out. Leave the object alone and return status. */
501
502         if (error == EWOULDBLOCK) {
503                 REMOVE_LIST_ENTRY((&w.wb_waitlist));
504                 lwkt_reltoken(&tokref);
505                 return(STATUS_TIMEOUT);
506         }
507
508         /*
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,
512          * grab it.
513          */
514
515         if (obj->dh_size == OTYPE_MUTEX) {
516                 km = (kmutant *)obj;
517                 if (km->km_ownerthread == NULL) {
518                         km->km_ownerthread = curthread->td_proc;
519                         km->km_acquirecnt++;
520                 }
521         }
522
523         if (obj->dh_type == EVENT_TYPE_SYNC)
524                 obj->dh_sigstate = FALSE;
525         REMOVE_LIST_ENTRY((&w.wb_waitlist));
526
527         lwkt_reltoken(&tokref);
528
529         return(STATUS_SUCCESS);
530 }
531
532 __stdcall static uint32_t
533 ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode,
534         alertable, duetime, wb_array)
535         uint32_t                cnt;
536         nt_dispatch_header      *obj[];
537         uint32_t                wtype;
538         uint32_t                reason;
539         uint32_t                mode;
540         uint8_t                 alertable;
541         int64_t                 *duetime;
542         wait_block              *wb_array;
543 {
544         struct thread           *td = curthread;
545         kmutant                 *km;
546         wait_block              _wb_array[THREAD_WAIT_OBJECTS];
547         wait_block              *w;
548         struct timeval          tv;
549         int                     i, wcnt = 0, widx = 0, error = 0;
550         uint64_t                curtime;
551         struct timespec         t1, t2;
552         struct lwkt_tokref      tokref;
553
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);
558
559         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
560
561         if (wb_array == NULL)
562                 w = &_wb_array[0];
563         else
564                 w = wb_array;
565
566         /* First pass: see if we can satisfy any waits immediately. */
567
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;
574                                 km->km_acquirecnt++;
575                                 km->km_ownerthread = curthread->td_proc;
576                                 if (wtype == WAITTYPE_ANY) {
577                                         lwkt_reltoken(&tokref);
578                                         return (STATUS_WAIT_0 + i);
579                                 }
580                         }
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);
587                         }
588                 }
589         }
590
591         /*
592          * Second pass: set up wait for anything we can't
593          * satisfy immediately.
594          */
595
596         for (i = 0; i < cnt; i++) {
597                 if (obj[i]->dh_sigstate == TRUE)
598                         continue;
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];
603                 wcnt++;
604         }
605
606         if (duetime != NULL) {
607                 if (*duetime < 0) {
608                         tv.tv_sec = - (*duetime) / 10000000;
609                         tv.tv_usec = (- (*duetime) / 10) -
610                             (tv.tv_sec * 1000000);
611                 } else {
612                         ntoskrnl_time(&curtime);
613                         if (*duetime < curtime)
614                                 tv.tv_sec = tv.tv_usec = 0;
615                         else {
616                                 tv.tv_sec = ((*duetime) - curtime) / 10000000;
617                                 tv.tv_usec = ((*duetime) - curtime) / 10 -
618                                     (tv.tv_sec * 1000000);
619                         }
620                 }
621         }
622
623         while (wcnt) {
624                 nanotime(&t1);
625                 lwkt_reltoken(&tokref);
626
627                 ticks = 1 + tv.tv_sec * hz + tv.tv_usec * hz / 1000000;
628
629                 error = ndis_thsuspend(td, duetime == NULL ? 0 : ticks);
630
631                 lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
632                 nanotime(&t2);
633
634                 for (i = 0; i < cnt; i++) {
635                         if (obj[i]->dh_size == OTYPE_MUTEX) {
636                                 km = (kmutant *)obj;
637                                 if (km->km_ownerthread == NULL) {
638                                         km->km_ownerthread =
639                                             curthread->td_proc;
640                                         km->km_acquirecnt++;
641                                 }
642                         }
643                         if (obj[i]->dh_sigstate == TRUE) {
644                                 widx = i;
645                                 if (obj[i]->dh_type == EVENT_TYPE_SYNC)
646                                         obj[i]->dh_sigstate = FALSE;
647                                 REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
648                                 wcnt--;
649                         }
650                 }
651
652                 if (error || wtype == WAITTYPE_ANY)
653                         break;
654
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;
658                 }
659         }
660
661         if (wcnt) {
662                 for (i = 0; i < cnt; i++)
663                         REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
664         }
665
666         if (error == EWOULDBLOCK) {
667                 lwkt_reltoken(&tokref);
668                 return(STATUS_TIMEOUT);
669         }
670
671         if (wtype == WAITTYPE_ANY && wcnt) {
672                 lwkt_reltoken(&tokref);
673                 return(STATUS_WAIT_0 + widx);
674         }
675
676         lwkt_reltoken(&tokref);
677
678         return(STATUS_SUCCESS);
679 }
680
681 __stdcall static void
682 ntoskrnl_writereg_ushort(reg, val)
683         uint16_t                *reg;
684         uint16_t                val;
685 {
686         bus_space_write_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
687         return;
688 }
689
690 __stdcall static uint16_t
691 ntoskrnl_readreg_ushort(reg)
692         uint16_t                *reg;
693 {
694         return(bus_space_read_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
695 }
696
697 __stdcall static void
698 ntoskrnl_writereg_ulong(reg, val)
699         uint32_t                *reg;
700         uint32_t                val;
701 {
702         bus_space_write_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
703         return;
704 }
705
706 __stdcall static uint32_t
707 ntoskrnl_readreg_ulong(reg)
708         uint32_t                *reg;
709 {
710         return(bus_space_read_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
711 }
712
713 __stdcall static uint8_t
714 ntoskrnl_readreg_uchar(reg)
715         uint8_t                 *reg;
716 {
717         return(bus_space_read_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
718 }
719
720 __stdcall static void
721 ntoskrnl_writereg_uchar(reg, val)
722         uint8_t                 *reg;
723         uint8_t                 val;
724 {
725         bus_space_write_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
726         return;
727 }
728
729 __stdcall static int64_t
730 _allmul(a, b)
731         int64_t                 a;
732         int64_t                 b;
733 {
734         return (a * b);
735 }
736
737 __stdcall static int64_t
738 _alldiv(a, b)
739         int64_t                 a;
740         int64_t                 b;
741 {
742         return (a / b);
743 }
744
745 __stdcall static int64_t
746 _allrem(a, b)
747         int64_t                 a;
748         int64_t                 b;
749 {
750         return (a % b);
751 }
752
753 __stdcall static uint64_t
754 _aullmul(a, b)
755         uint64_t                a;
756         uint64_t                b;
757 {
758         return (a * b);
759 }
760
761 __stdcall static uint64_t
762 _aulldiv(a, b)
763         uint64_t                a;
764         uint64_t                b;
765 {
766         return (a / b);
767 }
768
769 __stdcall static uint64_t
770 _aullrem(a, b)
771         uint64_t                a;
772         uint64_t                b;
773 {
774         return (a % b);
775 }
776
777 __regparm static int64_t
778 _allshl(a, b)
779         int64_t                 a;
780         uint8_t                 b;
781 {
782         return (a << b);
783 }
784
785 __regparm static uint64_t
786 _aullshl(a, b)
787         uint64_t                a;
788         uint8_t                 b;
789 {
790         return (a << b);
791 }
792
793 __regparm static int64_t
794 _allshr(a, b)
795         int64_t                 a;
796         uint8_t                 b;
797 {
798         return (a >> b);
799 }
800
801 __regparm static uint64_t
802 _aullshr(a, b)
803         uint64_t                a;
804         uint8_t                 b;
805 {
806         return (a >> b);
807 }
808
809 static slist_entry *
810 ntoskrnl_pushsl(head, entry)
811         slist_header            *head;
812         slist_entry             *entry;
813 {
814         slist_entry             *oldhead;
815
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++;
821
822         return(oldhead);
823 }
824
825 static slist_entry *
826 ntoskrnl_popsl(head)
827         slist_header            *head;
828 {
829         slist_entry             *first;
830
831         first = head->slh_list.slh_next;
832         if (first != NULL) {
833                 head->slh_list.slh_next = first->sl_next;
834                 head->slh_list.slh_depth--;
835                 head->slh_list.slh_seq++;
836         }
837
838         return(first);
839 }
840
841 __stdcall static void *
842 ntoskrnl_allocfunc(pooltype, size, tag)
843         uint32_t                pooltype;
844         size_t                  size;
845         uint32_t                tag;
846 {
847         return(malloc(size, M_DEVBUF, M_NOWAIT));
848 }
849
850 __stdcall static void
851 ntoskrnl_freefunc(buf)
852         void                    *buf;
853 {
854         free(buf, M_DEVBUF);
855         return;
856 }
857
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;
864         uint32_t                flags;
865         size_t                  size;
866         uint32_t                tag;
867         uint16_t                depth;
868 {
869         bzero((char *)lookaside, sizeof(paged_lookaside_list));
870
871         if (size < sizeof(slist_entry))
872                 lookaside->nll_l.gl_size = sizeof(slist_entry);
873         else
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;
878         else
879                 lookaside->nll_l.gl_allocfunc = allocfunc;
880
881         if (freefunc == NULL)
882                 lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc;
883         else
884                 lookaside->nll_l.gl_freefunc = freefunc;
885
886         ntoskrnl_init_lock(&lookaside->nll_obsoletelock);
887
888         lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH;
889         lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
890
891         return;
892 }
893
894 __stdcall static void
895 ntoskrnl_delete_lookaside(lookaside)
896         paged_lookaside_list   *lookaside;
897 {
898         void                    *buf;
899         __stdcall void          (*freefunc)(void *);
900
901         freefunc = lookaside->nll_l.gl_freefunc;
902         while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
903                 freefunc(buf);
904
905         return;
906 }
907
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;
914         uint32_t                flags;
915         size_t                  size;
916         uint32_t                tag;
917         uint16_t                depth;
918 {
919         bzero((char *)lookaside, sizeof(npaged_lookaside_list));
920
921         if (size < sizeof(slist_entry))
922                 lookaside->nll_l.gl_size = sizeof(slist_entry);
923         else
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;
928         else
929                 lookaside->nll_l.gl_allocfunc = allocfunc;
930
931         if (freefunc == NULL)
932                 lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc;
933         else
934                 lookaside->nll_l.gl_freefunc = freefunc;
935
936         ntoskrnl_init_lock(&lookaside->nll_obsoletelock);
937
938         lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH;
939         lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
940
941         return;
942 }
943
944 __stdcall static void
945 ntoskrnl_delete_nplookaside(lookaside)
946         npaged_lookaside_list   *lookaside;
947 {
948         void                    *buf;
949         __stdcall void          (*freefunc)(void *);
950
951         freefunc = lookaside->nll_l.gl_freefunc;
952         while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
953                 freefunc(buf);
954
955         return;
956 }
957
958 /*
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.
964  */
965
966 __stdcall __regcall static slist_entry *
967 ntoskrnl_push_slist(REGARGS2(slist_header *head, slist_entry *entry))
968 {
969         slist_entry             *oldhead;
970
971         oldhead = (slist_entry *)FASTCALL3(ntoskrnl_push_slist_ex,
972             head, entry, &ntoskrnl_global);
973
974         return(oldhead);
975 }
976
977 __stdcall __regcall static slist_entry *
978 ntoskrnl_pop_slist(REGARGS1(slist_header *head))
979 {
980         slist_entry             *first;
981
982         first = (slist_entry *)FASTCALL2(ntoskrnl_pop_slist_ex,
983             head, &ntoskrnl_global);
984
985         return(first);
986 }
987
988 __stdcall __regcall static slist_entry *
989 ntoskrnl_push_slist_ex(REGARGS2(slist_header *head, slist_entry *entry), kspin_lock *lock)
990 {
991         slist_entry             *oldhead;
992         uint8_t                 irql;
993
994         irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL);
995         oldhead = ntoskrnl_pushsl(head, entry);
996         FASTCALL2(hal_unlock, lock, irql);
997
998         return(oldhead);
999 }
1000
1001 __stdcall __regcall static slist_entry *
1002 ntoskrnl_pop_slist_ex(REGARGS2(slist_header *head, kspin_lock *lock))
1003 {
1004         slist_entry             *first;
1005         uint8_t                 irql;
1006
1007         irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL);
1008         first = ntoskrnl_popsl(head);
1009         FASTCALL2(hal_unlock, lock, irql);
1010
1011         return(first);
1012 }
1013
1014 __stdcall __regcall void
1015 ntoskrnl_lock_dpc(REGARGS1(kspin_lock *lock))
1016 {
1017         while (atomic_poll_acquire_int((volatile u_int *)lock) == 0)
1018                 /* sit and spin */;
1019 }
1020
1021 __stdcall __regcall void
1022 ntoskrnl_unlock_dpc(REGARGS1(kspin_lock *lock))
1023 {
1024         atomic_poll_release_int((volatile u_int *)lock);
1025 }
1026
1027 __stdcall __regcall static uint32_t
1028 ntoskrnl_interlock_inc(REGARGS1(volatile uint32_t *addend))
1029 {
1030         atomic_add_long((volatile u_long *)addend, 1);
1031         return(*addend);
1032 }
1033
1034 __stdcall __regcall static uint32_t
1035 ntoskrnl_interlock_dec(REGARGS1(volatile uint32_t *addend))
1036 {
1037         atomic_subtract_long((volatile u_long *)addend, 1);
1038         return(*addend);
1039 }
1040
1041 __stdcall __regcall static void
1042 ntoskrnl_interlock_addstat(REGARGS2(uint64_t *addend, uint32_t inc))
1043 {
1044         uint8_t                 irql;
1045
1046         irql = FASTCALL2(hal_lock, &ntoskrnl_global, DISPATCH_LEVEL);
1047         *addend += inc;
1048         FASTCALL2(hal_unlock, &ntoskrnl_global, irql);
1049
1050         return;
1051 };
1052
1053 __stdcall static void
1054 ntoskrnl_freemdl(mdl)
1055         ndis_buffer             *mdl;
1056 {
1057         ndis_buffer             *head;
1058
1059         if (mdl == NULL || mdl->nb_process == NULL)
1060                 return;
1061
1062         head = mdl->nb_process;
1063
1064         if (head->nb_flags != 0x1)
1065                 return;
1066
1067         mdl->nb_next = head->nb_next;
1068         head->nb_next = mdl;
1069
1070         /* Decrement count of busy buffers. */
1071
1072         head->nb_bytecount--;
1073
1074         /*
1075          * If the pool has been marked for deletion and there are
1076          * no more buffers outstanding, nuke the pool.
1077          */
1078
1079         if (head->nb_byteoffset && head->nb_bytecount == 0)
1080                 free(head, M_DEVBUF);
1081
1082         return;
1083 }
1084
1085 __stdcall static uint32_t
1086 ntoskrnl_sizeofmdl(vaddr, len)
1087         void                    *vaddr;
1088         size_t                  len;
1089 {
1090         uint32_t                l;
1091
1092         l = sizeof(struct ndis_buffer) +
1093             (sizeof(uint32_t) * SPAN_PAGES(vaddr, len));
1094
1095         return(l);
1096 }
1097
1098 __stdcall static void
1099 ntoskrnl_build_npaged_mdl(mdl)
1100         ndis_buffer             *mdl;
1101 {
1102         mdl->nb_mappedsystemva = (char *)mdl->nb_startva + mdl->nb_byteoffset;
1103         return;
1104 }
1105
1106 __stdcall static void *
1107 ntoskrnl_mmaplockedpages(buf, accessmode)
1108         ndis_buffer             *buf;
1109         uint8_t                 accessmode;
1110 {
1111         return(MDL_VA(buf));
1112 }
1113
1114 __stdcall static void *
1115 ntoskrnl_mmaplockedpages_cache(buf, accessmode, cachetype, vaddr,
1116     bugcheck, prio)
1117         ndis_buffer             *buf;
1118         uint8_t                 accessmode;
1119         uint32_t                cachetype;
1120         void                    *vaddr;
1121         uint32_t                bugcheck;
1122         uint32_t                prio;
1123 {
1124         return(MDL_VA(buf));
1125 }
1126
1127 __stdcall static void
1128 ntoskrnl_munmaplockedpages(vaddr, buf)
1129         void                    *vaddr;
1130         ndis_buffer             *buf;
1131 {
1132         return;
1133 }
1134
1135 /*
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.
1141  */
1142 __stdcall static void
1143 ntoskrnl_init_lock(lock)
1144         kspin_lock              *lock;
1145 {
1146         *lock = 0;
1147
1148         return;
1149 }
1150
1151 __stdcall static size_t
1152 ntoskrnl_memcmp(s1, s2, len)
1153         const void              *s1;
1154         const void              *s2;
1155         size_t                  len;
1156 {
1157         size_t                  i, total = 0;
1158         uint8_t                 *m1, *m2;
1159
1160         m1 = __DECONST(char *, s1);
1161         m2 = __DECONST(char *, s2);
1162
1163         for (i = 0; i < len; i++) {
1164                 if (m1[i] == m2[i])
1165                         total++;
1166         }
1167         return(total);
1168 }
1169
1170 __stdcall static void
1171 ntoskrnl_init_ansi_string(dst, src)
1172         ndis_ansi_string        *dst;
1173         char                    *src;
1174 {
1175         ndis_ansi_string        *a;
1176
1177         a = dst;
1178         if (a == NULL)
1179                 return;
1180         if (src == NULL) {
1181                 a->nas_len = a->nas_maxlen = 0;
1182                 a->nas_buf = NULL;
1183         } else {
1184                 a->nas_buf = src;
1185                 a->nas_len = a->nas_maxlen = strlen(src);
1186         }
1187
1188         return;
1189 }
1190
1191 __stdcall static void
1192 ntoskrnl_init_unicode_string(dst, src)
1193         ndis_unicode_string     *dst;
1194         uint16_t                *src;
1195 {
1196         ndis_unicode_string     *u;
1197         int                     i;
1198
1199         u = dst;
1200         if (u == NULL)
1201                 return;
1202         if (src == NULL) {
1203                 u->nus_len = u->nus_maxlen = 0;
1204                 u->nus_buf = NULL;
1205         } else {
1206                 i = 0;
1207                 while(src[i] != 0)
1208                         i++;
1209                 u->nus_buf = src;
1210                 u->nus_len = u->nus_maxlen = i * 2;
1211         }
1212
1213         return;
1214 }
1215
1216 __stdcall ndis_status
1217 ntoskrnl_unicode_to_int(ustr, base, val)
1218         ndis_unicode_string     *ustr;
1219         uint32_t                base;
1220         uint32_t                *val;
1221 {
1222         uint16_t                *uchr;
1223         int                     len, neg = 0;
1224         char                    abuf[64];
1225         char                    *astr;
1226
1227         uchr = ustr->nus_buf;
1228         len = ustr->nus_len;
1229         bzero(abuf, sizeof(abuf));
1230
1231         if ((char)((*uchr) & 0xFF) == '-') {
1232                 neg = 1;
1233                 uchr++;
1234                 len -= 2;
1235         } else if ((char)((*uchr) & 0xFF) == '+') {
1236                 neg = 0;
1237                 uchr++;
1238                 len -= 2;
1239         }
1240
1241         if (base == 0) {
1242                 if ((char)((*uchr) & 0xFF) == 'b') {
1243                         base = 2;
1244                         uchr++;
1245                         len -= 2;
1246                 } else if ((char)((*uchr) & 0xFF) == 'o') {
1247                         base = 8;
1248                         uchr++;
1249                         len -= 2;
1250                 } else if ((char)((*uchr) & 0xFF) == 'x') {
1251                         base = 16;
1252                         uchr++;
1253                         len -= 2;
1254                 } else
1255                         base = 10;
1256         }
1257
1258         astr = abuf;
1259         if (neg) {
1260                 strcpy(astr, "-");
1261                 astr++;
1262         }
1263
1264         ndis_unicode_to_ascii(uchr, len, &astr);
1265         *val = strtoul(abuf, NULL, base);
1266
1267         return(NDIS_STATUS_SUCCESS);
1268 }
1269
1270 __stdcall static void
1271 ntoskrnl_free_unicode_string(ustr)
1272         ndis_unicode_string     *ustr;
1273 {
1274         if (ustr->nus_buf == NULL)
1275                 return;
1276         free(ustr->nus_buf, M_DEVBUF);
1277         ustr->nus_buf = NULL;
1278         return;
1279 }
1280
1281 __stdcall static void
1282 ntoskrnl_free_ansi_string(astr)
1283         ndis_ansi_string        *astr;
1284 {
1285         if (astr->nas_buf == NULL)
1286                 return;
1287         free(astr->nas_buf, M_DEVBUF);
1288         astr->nas_buf = NULL;
1289         return;
1290 }
1291
1292 static int
1293 atoi(str)
1294         const char              *str;
1295 {
1296         return (int)strtol(str, (char **)NULL, 10);
1297 }
1298
1299 static long
1300 atol(str)
1301         const char              *str;
1302 {
1303         return strtol(str, (char **)NULL, 10);
1304 }
1305
1306 static int
1307 rand(void)
1308 {
1309         struct timeval          tv;
1310
1311         microtime(&tv);
1312         srandom(tv.tv_usec);
1313         return((int)random());
1314 }
1315
1316 __stdcall static uint8_t
1317 ntoskrnl_wdmver(major, minor)
1318         uint8_t                 major;
1319         uint8_t                 minor;
1320 {
1321         if (major == WDM_MAJOR && minor == WDM_MINOR_WINXP)
1322                 return(TRUE);
1323         return(FALSE);
1324 }
1325
1326 __stdcall static ndis_status
1327 ntoskrnl_devprop(devobj, regprop, buflen, prop, reslen)
1328         device_object           *devobj;
1329         uint32_t                regprop;
1330         uint32_t                buflen;
1331         void                    *prop;
1332         uint32_t                *reslen;
1333 {
1334         ndis_miniport_block     *block;
1335
1336         block = devobj->do_rsvd;
1337
1338         switch (regprop) {
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;
1343                 break;
1344         default:
1345                 return(STATUS_INVALID_PARAMETER_2);
1346                 break;
1347         }
1348
1349         return(STATUS_SUCCESS);
1350 }
1351
1352 __stdcall static void
1353 ntoskrnl_init_mutex(kmutex, level)
1354         kmutant                 *kmutex;
1355         uint32_t                level;
1356 {
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;
1365         return;
1366 }
1367
1368 __stdcall static uint32_t
1369 ntoskrnl_release_mutex(kmutex, kwait)
1370         kmutant                 *kmutex;
1371         uint8_t                 kwait;
1372 {
1373         struct lwkt_tokref      tokref;
1374
1375         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
1376         if (kmutex->km_ownerthread != curthread->td_proc) {
1377                 lwkt_reltoken(&tokref);
1378                 return(STATUS_MUTANT_NOT_OWNED);
1379         }
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);
1385         } else
1386                 lwkt_reltoken(&tokref);
1387
1388         return(kmutex->km_acquirecnt);
1389 }
1390
1391 __stdcall static uint32_t
1392 ntoskrnl_read_mutex(kmutex)
1393         kmutant                 *kmutex;
1394 {
1395         return(kmutex->km_header.dh_sigstate);
1396 }
1397
1398 __stdcall void
1399 ntoskrnl_init_event(kevent, type, state)
1400         nt_kevent               *kevent;
1401         uint32_t                type;
1402         uint8_t                 state;
1403 {
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;
1408         return;
1409 }
1410
1411 __stdcall uint32_t
1412 ntoskrnl_reset_event(kevent)
1413         nt_kevent               *kevent;
1414 {
1415         uint32_t                prevstate;
1416         struct lwkt_tokref      tokref;
1417
1418         lwkt_gettoken(&tokref, &ntoskrnl_dispatchtoken);
1419         prevstate = kevent->k_header.dh_sigstate;
1420         kevent->k_header.dh_sigstate = FALSE;
1421         lwkt_reltoken(&tokref);
1422
1423         return(prevstate);
1424 }
1425
1426 __stdcall uint32_t
1427 ntoskrnl_set_event(kevent, increment, kwait)
1428         nt_kevent               *kevent;
1429         uint32_t                increment;
1430         uint8_t                 kwait;
1431 {
1432         uint32_t                prevstate;
1433
1434         prevstate = kevent->k_header.dh_sigstate;
1435         ntoskrnl_wakeup(&kevent->k_header);
1436
1437         return(prevstate);
1438 }
1439
1440 __stdcall void
1441 ntoskrnl_clear_event(kevent)
1442         nt_kevent               *kevent;
1443 {
1444         kevent->k_header.dh_sigstate = FALSE;
1445         return;
1446 }
1447
1448 __stdcall uint32_t
1449 ntoskrnl_read_event(kevent)
1450         nt_kevent               *kevent;
1451 {
1452         return(kevent->k_header.dh_sigstate);
1453 }
1454
1455 __stdcall static ndis_status
1456 ntoskrnl_objref(handle, reqaccess, otype, accessmode, object, handleinfo)
1457         ndis_handle             handle;
1458         uint32_t                reqaccess;
1459         void                    *otype;
1460         uint8_t                 accessmode;
1461         void                    **object;
1462         void                    **handleinfo;
1463 {
1464         nt_objref               *nr;
1465
1466         nr = malloc(sizeof(nt_objref), M_DEVBUF, M_NOWAIT|M_ZERO);
1467         if (nr == NULL)
1468                 return(NDIS_STATUS_FAILURE);
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_NOWAIT);
1539         if (tc == NULL)
1540                 return(NDIS_STATUS_FAILURE);
1541
1542         tc->tc_thrctx = thrctx;
1543         tc->tc_thrfunc = thrfunc;
1544
1545         sprintf(tname, "windows kthread %d", ntoskrnl_kth);
1546         error = kthread_create_stk(ntoskrnl_thrfunc, tc, &td,
1547             NDIS_KSTACK_PAGES * PAGE_SIZE, tname);
1548         *handle = td;
1549
1550         ntoskrnl_kth++;
1551
1552         return(error);
1553 }
1554
1555 /*
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
1561  * them.
1562  */
1563 __stdcall static ndis_status
1564 ntoskrnl_thread_exit(status)
1565         ndis_status             status;
1566 {
1567         struct nt_objref        *nr;
1568
1569         TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) {
1570                 if (nr->no_obj != curthread)
1571                         continue;
1572                 ntoskrnl_wakeup(&nr->no_dh);
1573                 break;
1574         }
1575
1576         ntoskrnl_kth--;
1577
1578         kthread_exit();
1579         return(0);      /* notreached */
1580 }
1581
1582 static uint32_t
1583 ntoskrnl_dbgprint(char *fmt, ...)
1584 {
1585         __va_list                       ap;
1586
1587         if (bootverbose) {
1588                 __va_start(ap, fmt);
1589                 vprintf(fmt, ap);
1590         }
1591
1592         return(STATUS_SUCCESS);
1593 }
1594
1595 __stdcall static void
1596 ntoskrnl_debugger(void)
1597 {
1598
1599 #if __FreeBSD_version < 502113
1600         Debugger("ntoskrnl_debugger(): breakpoint");
1601 #else
1602         kdb_enter("ntoskrnl_debugger(): breakpoint");
1603 #endif
1604 }
1605
1606 static void
1607 ntoskrnl_timercall(arg)
1608         void                    *arg;
1609 {
1610         ktimer                  *timer;
1611
1612         timer = arg;
1613
1614         timer->k_header.dh_inserted = FALSE;
1615
1616         /*
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.
1623          */
1624
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);
1629         }
1630
1631         if (timer->k_dpc != NULL)
1632                 ntoskrnl_queue_dpc(timer->k_dpc, NULL, NULL);
1633
1634         ntoskrnl_wakeup(&timer->k_header);
1635 }
1636
1637 __stdcall void
1638 ntoskrnl_init_timer(timer)
1639         ktimer                  *timer;
1640 {
1641         if (timer == NULL)
1642                 return;
1643
1644         ntoskrnl_init_timer_ex(timer,  EVENT_TYPE_NOTIFY);
1645 }
1646
1647 __stdcall void
1648 ntoskrnl_init_timer_ex(timer, type)
1649         ktimer                  *timer;
1650         uint32_t                type;
1651 {
1652         if (timer == NULL)
1653                 return;
1654
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);
1661
1662         return;
1663 }
1664
1665 /*
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.
1670  */
1671 static void
1672 ntoskrnl_run_dpc(arg)
1673         void                    *arg;
1674 {
1675         kdpc_func               dpcfunc;
1676         kdpc                    *dpc;
1677         uint8_t                 irql;
1678
1679         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);
1684
1685         return;
1686 }
1687
1688 __stdcall void
1689 ntoskrnl_init_dpc(dpc, dpcfunc, dpcctx)
1690         kdpc                    *dpc;
1691         void                    *dpcfunc;
1692         void                    *dpcctx;
1693 {
1694         if (dpc == NULL)
1695                 return;
1696
1697         dpc->k_deferedfunc = dpcfunc;
1698         dpc->k_deferredctx = dpcctx;
1699
1700         return;
1701 }
1702
1703 __stdcall uint8_t
1704 ntoskrnl_queue_dpc(dpc, sysarg1, sysarg2)
1705         kdpc                    *dpc;
1706         void                    *sysarg1;
1707         void                    *sysarg2;
1708 {
1709         dpc->k_sysarg1 = sysarg1;
1710         dpc->k_sysarg2 = sysarg2;
1711         if (ndis_sched(ntoskrnl_run_dpc, dpc, NDIS_SWI))
1712                 return(FALSE);
1713
1714         return(TRUE);
1715 }
1716
1717 __stdcall uint8_t
1718 ntoskrnl_dequeue_dpc(dpc)
1719         kdpc                    *dpc;
1720 {
1721         if (ndis_unsched(ntoskrnl_run_dpc, dpc, NDIS_SWI))
1722                 return(FALSE);
1723
1724         return(TRUE);
1725 }
1726
1727 __stdcall uint8_t
1728 ntoskrnl_set_timer_ex(timer, duetime, period, dpc)
1729         ktimer                  *timer;
1730         int64_t                 duetime;
1731         uint32_t                period;
1732         kdpc                    *dpc;
1733 {
1734         struct timeval          tv;
1735         uint64_t                curtime;
1736         uint8_t                 pending;
1737         int                     ticks;
1738
1739         if (timer == NULL)
1740                 return(FALSE);
1741
1742         if (timer->k_header.dh_inserted == TRUE) {
1743                 untimeout(ntoskrnl_timercall, timer, timer->k_handle);
1744                 timer->k_header.dh_inserted = FALSE;
1745                 pending = TRUE;
1746         } else
1747                 pending = FALSE;
1748
1749         timer->k_duetime = duetime;
1750         timer->k_period = period;
1751         timer->k_header.dh_sigstate = FALSE;
1752         timer->k_dpc = dpc;
1753
1754         if (duetime < 0) {
1755                 tv.tv_sec = - (duetime) / 10000000;
1756                 tv.tv_usec = (- (duetime) / 10) -
1757                     (tv.tv_sec * 1000000);
1758         } else {
1759                 ntoskrnl_time(&curtime);
1760                 if (duetime < curtime)
1761                         tv.tv_sec = tv.tv_usec = 0;
1762                 else {
1763                         tv.tv_sec = ((duetime) - curtime) / 10000000;
1764                         tv.tv_usec = ((duetime) - curtime) / 10 -
1765                             (tv.tv_sec * 1000000);
1766                 }
1767         }
1768
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);
1772
1773         return(pending);
1774 }
1775
1776 __stdcall uint8_t
1777 ntoskrnl_set_timer(timer, duetime, dpc)
1778         ktimer                  *timer;
1779         int64_t                 duetime;
1780         kdpc                    *dpc;
1781 {
1782         return (ntoskrnl_set_timer_ex(timer, duetime, 0, dpc));
1783 }
1784
1785 __stdcall uint8_t
1786 ntoskrnl_cancel_timer(timer)
1787         ktimer                  *timer;
1788 {
1789         uint8_t                 pending;
1790
1791         if (timer == NULL)
1792                 return(FALSE);
1793
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);
1798                 pending = TRUE;
1799         } else
1800                 pending = FALSE;
1801
1802
1803         return(pending);
1804 }
1805
1806 __stdcall uint8_t
1807 ntoskrnl_read_timer(timer)
1808         ktimer                  *timer;
1809 {
1810         return(timer->k_header.dh_sigstate);
1811 }
1812
1813 __stdcall static void
1814 dummy()
1815 {
1816         printf ("ntoskrnl dummy called...\n");
1817         return;
1818 }
1819
1820
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 },
1916
1917         /*
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
1921          * in this table.
1922          */
1923
1924         { NULL, (FUNC)dummy },
1925
1926         /* End of list. */
1927
1928         { NULL, NULL },
1929 };