Annotation of src/sys/compat/ndis/subr_hal.c, Revision 1.3.50.1
1.1 rittera 1: /*-
2: * Copyright (c) 2003
3: * Bill Paul <wpaul@windriver.com>. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by Bill Paul.
16: * 4. Neither the name of the author nor the names of any co-contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30: * THE POSSIBILITY OF SUCH DAMAGE.
31: */
32:
33: #include <sys/cdefs.h>
1.2 rittera 34: #ifdef __FreeBSD__
1.1 rittera 35: __FBSDID("$FreeBSD: src/sys/compat/ndis/subr_hal.c,v 1.13.2.3 2005/03/31 04:24:35 wpaul Exp $");
1.2 rittera 36: #endif
37: #ifdef __NetBSD__
38: __KERNEL_RCSID(0, "$NetBSD$");
39: #endif
1.1 rittera 40:
41: #include <sys/param.h>
42: #include <sys/types.h>
43: #include <sys/errno.h>
44:
45: #include <sys/callout.h>
46: #include <sys/kernel.h>
47: #include <sys/lock.h>
1.2 rittera 48: #ifdef __FreeBSD__
1.1 rittera 49: #include <sys/mutex.h>
1.2 rittera 50: #endif
1.1 rittera 51: #include <sys/proc.h>
52: #include <sys/sched.h>
1.2 rittera 53: #ifdef __FreeBSD__
1.1 rittera 54: #include <sys/module.h>
1.2 rittera 55: #endif
1.1 rittera 56:
57: #include <sys/systm.h>
1.2 rittera 58: #ifdef __NetBSD__
59: #include <sys/lkm.h>
60: #endif
61: #ifdef __FreeBSD__
1.1 rittera 62: #include <machine/clock.h>
63: #include <machine/bus_memio.h>
64: #include <machine/bus_pio.h>
1.2 rittera 65: #endif
1.3.50.1! bouyer 66: #include <sys/bus.h>
1.1 rittera 67:
1.2 rittera 68: #ifdef __FreeBSD__
1.1 rittera 69: #include <sys/bus.h>
70: #include <sys/rman.h>
1.2 rittera 71: #endif
1.1 rittera 72:
73: #include <compat/ndis/pe_var.h>
74: #include <compat/ndis/ntoskrnl_var.h>
75: #include <compat/ndis/hal_var.h>
76:
77: __stdcall static void KeStallExecutionProcessor(uint32_t);
78: __stdcall static void WRITE_PORT_BUFFER_ULONG(uint32_t *,
79: uint32_t *, uint32_t);
80: __stdcall static void WRITE_PORT_BUFFER_USHORT(uint16_t *,
81: uint16_t *, uint32_t);
82: __stdcall static void WRITE_PORT_BUFFER_UCHAR(uint8_t *,
83: uint8_t *, uint32_t);
84: __stdcall static void WRITE_PORT_ULONG(uint32_t *, uint32_t);
85: __stdcall static void WRITE_PORT_USHORT(uint16_t *, uint16_t);
86: __stdcall static void WRITE_PORT_UCHAR(uint8_t *, uint8_t);
87: __stdcall static uint32_t READ_PORT_ULONG(uint32_t *);
88: __stdcall static uint16_t READ_PORT_USHORT(uint16_t *);
89: __stdcall static uint8_t READ_PORT_UCHAR(uint8_t *);
90: __stdcall static void READ_PORT_BUFFER_ULONG(uint32_t *,
91: uint32_t *, uint32_t);
92: __stdcall static void READ_PORT_BUFFER_USHORT(uint16_t *,
93: uint16_t *, uint32_t);
94: __stdcall static void READ_PORT_BUFFER_UCHAR(uint8_t *,
95: uint8_t *, uint32_t);
96: __stdcall static uint64_t KeQueryPerformanceCounter(uint64_t *);
97: __stdcall static void dummy (void);
98:
99: extern struct mtx_pool *ndis_mtxpool;
100:
101: int
102: hal_libinit()
103: {
104: image_patch_table *patch;
105:
106: patch = hal_functbl;
107: while (patch->ipt_func != NULL) {
108: windrv_wrap((funcptr)patch->ipt_func,
109: (funcptr *)&patch->ipt_wrap);
110: patch++;
111: }
112:
113: return(0);
114: }
115:
116: int
117: hal_libfini()
118: {
119: image_patch_table *patch;
120:
121: patch = hal_functbl;
122: while (patch->ipt_func != NULL) {
123: windrv_unwrap(patch->ipt_wrap);
124: patch++;
125: }
126:
127: return(0);
128: }
129:
130: __stdcall static void
131: KeStallExecutionProcessor(usecs)
132: uint32_t usecs;
133: {
134: DELAY(usecs);
135: return;
136: }
137:
138: __stdcall static void
139: WRITE_PORT_ULONG(port, val)
140: uint32_t *port;
141: uint32_t val;
142: {
143: bus_space_write_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
144: return;
145: }
146:
147: __stdcall static void
148: WRITE_PORT_USHORT(port, val)
149: uint16_t *port;
150: uint16_t val;
151: {
152: bus_space_write_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
153: return;
154: }
155:
156: __stdcall static void
157: WRITE_PORT_UCHAR(port, val)
158: uint8_t *port;
159: uint8_t val;
160: {
161: bus_space_write_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
162: return;
163: }
164:
165: __stdcall static void
166: WRITE_PORT_BUFFER_ULONG(port, val, cnt)
167: uint32_t *port;
168: uint32_t *val;
169: uint32_t cnt;
170: {
171: bus_space_write_multi_4(NDIS_BUS_SPACE_IO, 0x0,
172: (bus_size_t)port, val, cnt);
173: return;
174: }
175:
176: __stdcall static void
177: WRITE_PORT_BUFFER_USHORT(port, val, cnt)
178: uint16_t *port;
179: uint16_t *val;
180: uint32_t cnt;
181: {
182: bus_space_write_multi_2(NDIS_BUS_SPACE_IO, 0x0,
183: (bus_size_t)port, val, cnt);
184: return;
185: }
186:
187: __stdcall static void
188: WRITE_PORT_BUFFER_UCHAR(port, val, cnt)
189: uint8_t *port;
190: uint8_t *val;
191: uint32_t cnt;
192: {
193: bus_space_write_multi_1(NDIS_BUS_SPACE_IO, 0x0,
194: (bus_size_t)port, val, cnt);
195: return;
196: }
197:
198: __stdcall static uint16_t
199: READ_PORT_USHORT(port)
200: uint16_t *port;
201: {
202: return(bus_space_read_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
203: }
204:
205: __stdcall static uint32_t
206: READ_PORT_ULONG(port)
207: uint32_t *port;
208: {
209: return(bus_space_read_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
210: }
211:
212: __stdcall static uint8_t
213: READ_PORT_UCHAR(port)
214: uint8_t *port;
215: {
216: return(bus_space_read_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
217: }
218:
219: __stdcall static void
220: READ_PORT_BUFFER_ULONG(port, val, cnt)
221: uint32_t *port;
222: uint32_t *val;
223: uint32_t cnt;
224: {
225: bus_space_read_multi_4(NDIS_BUS_SPACE_IO, 0x0,
226: (bus_size_t)port, val, cnt);
227: return;
228: }
229:
230: __stdcall static void
231: READ_PORT_BUFFER_USHORT(port, val, cnt)
232: uint16_t *port;
233: uint16_t *val;
234: uint32_t cnt;
235: {
236: bus_space_read_multi_2(NDIS_BUS_SPACE_IO, 0x0,
237: (bus_size_t)port, val, cnt);
238: return;
239: }
240:
241: __stdcall static void
242: READ_PORT_BUFFER_UCHAR(port, val, cnt)
243: uint8_t *port;
244: uint8_t *val;
245: uint32_t cnt;
246: {
247: bus_space_read_multi_1(NDIS_BUS_SPACE_IO, 0x0,
248: (bus_size_t)port, val, cnt);
249: return;
250: }
251:
252: /*
253: * The spinlock implementation in Windows differs from that of FreeBSD.
254: * The basic operation of spinlocks involves two steps: 1) spin in a
255: * tight loop while trying to acquire a lock, 2) after obtaining the
256: * lock, disable preemption. (Note that on uniprocessor systems, you're
257: * allowed to skip the first step and just lock out pre-emption, since
258: * it's not possible for you to be in contention with another running
259: * thread.) Later, you release the lock then re-enable preemption.
260: * The difference between Windows and FreeBSD lies in how preemption
261: * is disabled. In FreeBSD, it's done using critical_enter(), which on
262: * the x86 arch translates to a cli instruction. This masks off all
263: * interrupts, and effectively stops the scheduler from ever running
264: * so _nothing_ can execute except the current thread. In Windows,
265: * preemption is disabled by raising the processor IRQL to DISPATCH_LEVEL.
266: * This stops other threads from running, but does _not_ block device
267: * interrupts. This means ISRs can still run, and they can make other
268: * threads runable, but those other threads won't be able to execute
269: * until the current thread lowers the IRQL to something less than
270: * DISPATCH_LEVEL.
271: *
272: * There's another commonly used IRQL in Windows, which is APC_LEVEL.
273: * An APC is an Asynchronous Procedure Call, which differs from a DPC
274: * (Defered Procedure Call) in that a DPC is queued up to run in
275: * another thread, while an APC runs in the thread that scheduled
276: * it (similar to a signal handler in a UNIX process). We don't
277: * actually support the notion of APCs in FreeBSD, so for now, the
278: * only IRQLs we're interested in are DISPATCH_LEVEL and PASSIVE_LEVEL.
279: *
280: * To simulate DISPATCH_LEVEL, we raise the current thread's priority
281: * to PI_REALTIME, which is the highest we can give it. This should,
282: * if I understand things correctly, prevent anything except for an
283: * interrupt thread from preempting us. PASSIVE_LEVEL is basically
284: * everything else.
285: *
286: * Be aware that, at least on the x86 arch, the Windows spinlock
287: * functions are divided up in peculiar ways. The actual spinlock
288: * functions are KfAcquireSpinLock() and KfReleaseSpinLock(), and
289: * they live in HAL.dll. Meanwhile, KeInitializeSpinLock(),
290: * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel()
291: * live in ntoskrnl.exe. Most Windows source code will call
292: * KeAcquireSpinLock() and KeReleaseSpinLock(), but these are just
293: * macros that call KfAcquireSpinLock() and KfReleaseSpinLock().
294: * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel()
295: * perform the lock aquisition/release functions without doing the
296: * IRQL manipulation, and are used when one is already running at
297: * DISPATCH_LEVEL. Make sense? Good.
298: *
299: * According to the Microsoft documentation, any thread that calls
300: * KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If
301: * we detect someone trying to acquire a spinlock from DEVICE_LEVEL
302: * or HIGH_LEVEL, we panic.
303: */
304:
305: __fastcall uint8_t
306: KfAcquireSpinLock(REGARGS1(kspin_lock *lock))
307: {
308: uint8_t oldirql;
309:
310: /* I am so going to hell for this. */
311: if (KeGetCurrentIrql() > DISPATCH_LEVEL)
312: panic("IRQL_NOT_LESS_THAN_OR_EQUAL");
313:
314: oldirql = KeRaiseIrql(DISPATCH_LEVEL);
315: KeAcquireSpinLockAtDpcLevel(lock);
316:
317: return(oldirql);
318: }
319:
320: __fastcall void
321: KfReleaseSpinLock(REGARGS2(kspin_lock *lock, uint8_t newirql))
322: {
323: KeReleaseSpinLockFromDpcLevel(lock);
324: KeLowerIrql(newirql);
325:
326: return;
327: }
328:
329: __stdcall uint8_t
330: KeGetCurrentIrql(void)
331: {
332: if (AT_DISPATCH_LEVEL(curthread))
333: return(DISPATCH_LEVEL);
334: return(PASSIVE_LEVEL);
335: }
336:
337: __stdcall static uint64_t
338: KeQueryPerformanceCounter(freq)
339: uint64_t *freq;
340: {
341: if (freq != NULL)
342: *freq = hz;
343:
344: return((uint64_t)ticks);
345: }
346:
1.3 rittera 347:
348: static int old_ipl;
349: static int ipl_raised = FALSE;
350:
1.1 rittera 351: __fastcall uint8_t
352: KfRaiseIrql(REGARGS1(uint8_t irql))
353: {
1.3 rittera 354: uint8_t oldirql = 0;
355: //#ifdef __NetBSD__
356: // uint8_t s;
357: //#endif
1.1 rittera 358:
359: if (irql < KeGetCurrentIrql())
360: panic("IRQL_NOT_LESS_THAN");
361:
362: if (KeGetCurrentIrql() == DISPATCH_LEVEL)
363: return(DISPATCH_LEVEL);
1.2 rittera 364: #ifdef __NetBSD__
1.3 rittera 365: if(irql >= DISPATCH_LEVEL && !ipl_raised) {
366: old_ipl = splsoftclock();
367: ipl_raised = TRUE;
368: oldirql = win_irql;
369: win_irql = irql;
370: }
371: #else /* __FreeBSD__ */
1.1 rittera 372: mtx_lock_spin(&sched_lock);
373: oldirql = curthread->td_base_pri;
374: sched_prio(curthread, PI_REALTIME);
375: #if __FreeBSD_version < 600000
376: curthread->td_base_pri = PI_REALTIME;
377: #endif
378: mtx_unlock_spin(&sched_lock);
1.3 rittera 379: #endif /* __FreeBSD__ */
1.1 rittera 380:
381: return(oldirql);
382: }
383:
384: __fastcall void
385: KfLowerIrql(REGARGS1(uint8_t oldirql))
386: {
1.3 rittera 387: //#ifdef __NetBSD__
388: // uint8_t s;
389: //#endif
1.2 rittera 390:
1.1 rittera 391: if (oldirql == DISPATCH_LEVEL)
392: return;
393:
1.3 rittera 394: #ifdef __FreeBSD__
1.1 rittera 395: if (KeGetCurrentIrql() != DISPATCH_LEVEL)
396: panic("IRQL_NOT_GREATER_THAN");
1.3 rittera 397: #else /* __NetBSD__ */
398: if (KeGetCurrentIrql() < oldirql)
399: panic("IRQL_NOT_GREATER_THAN");
400: #endif
1.1 rittera 401:
1.2 rittera 402: #ifdef __NetBSD__
1.3 rittera 403: if(oldirql < DISPATCH_LEVEL && ipl_raised) {
404: splx(old_ipl);
405: ipl_raised = FALSE;
406: win_irql = oldirql;
407: }
1.2 rittera 408: #else
1.1 rittera 409: mtx_lock_spin(&sched_lock);
410: #if __FreeBSD_version < 600000
411: curthread->td_base_pri = oldirql;
412: #endif
413: sched_prio(curthread, oldirql);
414: mtx_unlock_spin(&sched_lock);
1.2 rittera 415: #endif /* __NetBSD__ */
1.1 rittera 416:
417: return;
418: }
419:
420: __stdcall
421: static void dummy()
422: {
423: printf ("hal dummy called...\n");
424: return;
425: }
426:
427: image_patch_table hal_functbl[] = {
428: IMPORT_FUNC(KeStallExecutionProcessor),
429: IMPORT_FUNC(WRITE_PORT_ULONG),
430: IMPORT_FUNC(WRITE_PORT_USHORT),
431: IMPORT_FUNC(WRITE_PORT_UCHAR),
432: IMPORT_FUNC(WRITE_PORT_BUFFER_ULONG),
433: IMPORT_FUNC(WRITE_PORT_BUFFER_USHORT),
434: IMPORT_FUNC(WRITE_PORT_BUFFER_UCHAR),
435: IMPORT_FUNC(READ_PORT_ULONG),
436: IMPORT_FUNC(READ_PORT_USHORT),
437: IMPORT_FUNC(READ_PORT_UCHAR),
438: IMPORT_FUNC(READ_PORT_BUFFER_ULONG),
439: IMPORT_FUNC(READ_PORT_BUFFER_USHORT),
440: IMPORT_FUNC(READ_PORT_BUFFER_UCHAR),
441: IMPORT_FUNC(KfAcquireSpinLock),
442: IMPORT_FUNC(KfReleaseSpinLock),
443: IMPORT_FUNC(KeGetCurrentIrql),
444: IMPORT_FUNC(KeQueryPerformanceCounter),
445: IMPORT_FUNC(KfLowerIrql),
446: IMPORT_FUNC(KfRaiseIrql),
447:
448: /*
449: * This last entry is a catch-all for any function we haven't
450: * implemented yet. The PE import list patching routine will
451: * use it for any function that doesn't have an explicit match
452: * in this table.
453: */
454:
455: { NULL, (FUNC)dummy, NULL },
456:
457: /* End of list. */
458:
459: { NULL, NULL, NULL }
460: };
CVSweb <webmaster@jp.NetBSD.org>