Ports -> pkgsrc
[dragonfly.git] / sys / emulation / ndis / subr_hal.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_hal.c,v 1.12 2004/04/19 22:39:04 wpaul Exp $
33  * $DragonFly: src/sys/emulation/ndis/subr_hal.c,v 1.2 2005/12/10 16:06:20 swildner Exp $
34  */
35
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/errno.h>
39
40 #include <sys/callout.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/proc.h>
44
45 #include <sys/systm.h>
46 #include <machine/clock.h>
47 #include <machine/bus_memio.h>
48 #include <machine/bus_pio.h>
49 #include <machine/bus.h>
50
51 #include <sys/bus.h>
52 #include <sys/rman.h>
53 #include <sys/thread2.h>
54
55 #include "regcall.h"
56 #include "pe_var.h"
57 #include "resource_var.h"
58 #include "ntoskrnl_var.h"
59 #include "ndis_var.h"
60 #include "hal_var.h"
61
62 #define FUNC void(*)(void)
63
64 __stdcall static void hal_stall_exec_cpu(uint32_t);
65 __stdcall static void hal_writeport_buf_ulong(uint32_t *,
66         uint32_t *, uint32_t);
67 __stdcall static void hal_writeport_buf_ushort(uint16_t *,
68         uint16_t *, uint32_t);
69 __stdcall static void hal_writeport_buf_uchar(uint8_t *,
70         uint8_t *, uint32_t);
71 __stdcall static void hal_writeport_ulong(uint32_t *, uint32_t);
72 __stdcall static void hal_writeport_ushort(uint16_t *, uint16_t);
73 __stdcall static void hal_writeport_uchar(uint8_t *, uint8_t);
74 __stdcall static uint32_t hal_readport_ulong(uint32_t *);
75 __stdcall static uint16_t hal_readport_ushort(uint16_t *);
76 __stdcall static uint8_t hal_readport_uchar(uint8_t *);
77 __stdcall static void hal_readport_buf_ulong(uint32_t *,
78         uint32_t *, uint32_t);
79 __stdcall static void hal_readport_buf_ushort(uint16_t *,
80         uint16_t *, uint32_t);
81 __stdcall static void hal_readport_buf_uchar(uint8_t *,
82         uint8_t *, uint32_t);
83 __stdcall static uint64_t hal_perfcount(uint64_t *);
84 __stdcall static void dummy (void);
85
86 extern struct mtx_pool *ndis_mtxpool;
87
88 __stdcall static void
89 hal_stall_exec_cpu(uint32_t usecs)
90 {
91         DELAY(usecs);
92         return;
93 }
94
95 __stdcall static void
96 hal_writeport_ulong(uint32_t *port, uint32_t val)
97 {
98         bus_space_write_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
99         return;
100 }
101
102 __stdcall static void
103 hal_writeport_ushort(uint16_t *port, uint16_t val)
104 {
105         bus_space_write_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
106         return;
107 }
108
109 __stdcall static void
110 hal_writeport_uchar(uint8_t *port, uint8_t val)
111 {
112         bus_space_write_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
113         return;
114 }
115
116 __stdcall static void
117 hal_writeport_buf_ulong(uint32_t *port, uint32_t *val, uint32_t cnt)
118 {
119         bus_space_write_multi_4(NDIS_BUS_SPACE_IO, 0x0,
120             (bus_size_t)port, val, cnt);
121         return;
122 }
123
124 __stdcall static void
125 hal_writeport_buf_ushort(uint16_t *port, uint16_t *val, uint32_t cnt)
126 {
127         bus_space_write_multi_2(NDIS_BUS_SPACE_IO, 0x0,
128             (bus_size_t)port, val, cnt);
129         return;
130 }
131
132 __stdcall static void
133 hal_writeport_buf_uchar(uint8_t *port, uint8_t *val, uint32_t cnt)
134 {
135         bus_space_write_multi_1(NDIS_BUS_SPACE_IO, 0x0,
136             (bus_size_t)port, val, cnt);
137         return;
138 }
139
140 __stdcall static uint16_t
141 hal_readport_ushort(uint16_t *port)
142 {
143         return(bus_space_read_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
144 }
145
146 __stdcall static uint32_t
147 hal_readport_ulong(uint32_t *port)
148 {
149         return(bus_space_read_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
150 }
151
152 __stdcall static uint8_t
153 hal_readport_uchar(uint8_t *port)
154 {
155         return(bus_space_read_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
156 }
157
158 __stdcall static void
159 hal_readport_buf_ulong(uint32_t *port, uint32_t *val, uint32_t cnt)
160 {
161         bus_space_read_multi_4(NDIS_BUS_SPACE_IO, 0x0,
162             (bus_size_t)port, val, cnt);
163         return;
164 }
165
166 __stdcall static void
167 hal_readport_buf_ushort(uint16_t *port, uint16_t *val, uint32_t cnt)
168 {
169         bus_space_read_multi_2(NDIS_BUS_SPACE_IO, 0x0,
170             (bus_size_t)port, val, cnt);
171         return;
172 }
173
174 __stdcall static void
175 hal_readport_buf_uchar(uint8_t *port, uint8_t *val, uint32_t cnt)
176 {
177         bus_space_read_multi_1(NDIS_BUS_SPACE_IO, 0x0,
178             (bus_size_t)port, val, cnt);
179         return;
180 }
181
182 /*
183  * The spinlock implementation in Windows differs from that of FreeBSD.
184  * The basic operation of spinlocks involves two steps: 1) spin in a
185  * tight loop while trying to acquire a lock, 2) after obtaining the
186  * lock, disable preemption. (Note that on uniprocessor systems, you're
187  * allowed to skip the first step and just lock out pre-emption, since
188  * it's not possible for you to be in contention with another running
189  * thread.) Later, you release the lock then re-enable preemption.
190  * The difference between Windows and FreeBSD lies in how preemption
191  * is disabled. In FreeBSD, it's done using critical_enter(), which on
192  * the x86 arch translates to a cli instruction. This masks off all
193  * interrupts, and effectively stops the scheduler from ever running
194  * so _nothing_ can execute except the current thread. In Windows,
195  * preemption is disabled by raising the processor IRQL to DISPATCH_LEVEL.
196  * This stops other threads from running, but does _not_ block device
197  * interrupts. This means ISRs can still run, and they can make other
198  * threads runable, but those other threads won't be able to execute
199  * until the current thread lowers the IRQL to something less than
200  * DISPATCH_LEVEL.
201  *
202  * In FreeBSD, ISRs run in interrupt threads, so to duplicate the
203  * Windows notion of IRQLs, we use the following rules:
204  *
205  * PASSIVE_LEVEL == normal kernel thread priority
206  * DISPATCH_LEVEL == lowest interrupt thread priotity (PI_SOFT)
207  * DEVICE_LEVEL == highest interrupt thread priority  (PI_REALTIME)
208  * HIGH_LEVEL == interrupts disabled (critical_enter())
209  *
210  * Be aware that, at least on the x86 arch, the Windows spinlock
211  * functions are divided up in peculiar ways. The actual spinlock
212  * functions are KfAcquireSpinLock() and KfReleaseSpinLock(), and
213  * they live in HAL.dll. Meanwhile, KeInitializeSpinLock(),
214  * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel()
215  * live in ntoskrnl.exe. Most Windows source code will call
216  * KeAcquireSpinLock() and KeReleaseSpinLock(), but these are just
217  * macros that call KfAcquireSpinLock() and KfReleaseSpinLock().
218  * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel()
219  * perform the lock aquisition/release functions without doing the
220  * IRQL manipulation, and are used when one is already running at
221  * DISPATCH_LEVEL. Make sense? Good.
222  *
223  * According to the Microsoft documentation, any thread that calls
224  * KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If
225  * we detect someone trying to acquire a spinlock from DEVICE_LEVEL
226  * or HIGH_LEVEL, we panic.
227  */
228
229 __stdcall __regcall uint8_t
230 hal_lock(REGARGS1(kspin_lock *lock))
231 {
232         uint8_t                 oldirql;
233
234         /* I am so going to hell for this. */
235         if (hal_irql() > DISPATCH_LEVEL)
236                 panic("IRQL_NOT_LESS_THAN_OR_EQUAL");
237
238         oldirql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
239         FASTCALL1(ntoskrnl_lock_dpc, lock);
240
241         return(oldirql);
242 }
243
244 __stdcall __regcall void
245 hal_unlock(REGARGS2(kspin_lock *lock, uint8_t newirql))
246 {
247         FASTCALL1(ntoskrnl_unlock_dpc, lock);
248         FASTCALL1(hal_lower_irql, newirql);
249
250         return;
251 }
252
253 __stdcall uint8_t
254 hal_irql(void)
255 {
256         if (AT_DISPATCH_LEVEL(curthread))
257                 return(DISPATCH_LEVEL);
258         return(PASSIVE_LEVEL);
259 }
260
261 __stdcall static uint64_t
262 hal_perfcount(uint64_t *freq)
263 {
264         if (freq != NULL)
265                 *freq = hz;
266
267         return((uint64_t)ticks);
268 }
269
270 __stdcall __regcall uint8_t
271 hal_raise_irql(REGARGS1(uint8_t irql))
272 {
273         uint8_t                 oldirql;
274
275         if (irql < hal_irql())
276                 panic("IRQL_NOT_LESS_THAN");
277
278         if (hal_irql() == DISPATCH_LEVEL)
279                 return(DISPATCH_LEVEL);
280
281         oldirql = lwkt_getpri_self();
282         lwkt_setpri_self(TDPRI_INT_HIGH);
283
284         return(oldirql);
285 }
286
287 __stdcall __regcall void 
288 hal_lower_irql(REGARGS1(uint8_t oldirql))
289 {
290         if (oldirql == DISPATCH_LEVEL)
291                 return;
292
293         if (hal_irql() != DISPATCH_LEVEL)
294                 panic("IRQL_NOT_GREATER_THAN");
295
296         lwkt_setpri_self(oldirql);
297 }
298
299 __stdcall
300 static void dummy(void)
301 {
302         printf ("hal dummy called...\n");
303         return;
304 }
305
306 image_patch_table hal_functbl[] = {
307         { "KeStallExecutionProcessor",  (FUNC)hal_stall_exec_cpu },
308         { "WRITE_PORT_ULONG",           (FUNC)hal_writeport_ulong },
309         { "WRITE_PORT_USHORT",          (FUNC)hal_writeport_ushort },
310         { "WRITE_PORT_UCHAR",           (FUNC)hal_writeport_uchar },
311         { "WRITE_PORT_BUFFER_ULONG",    (FUNC)hal_writeport_buf_ulong },
312         { "WRITE_PORT_BUFFER_USHORT",   (FUNC)hal_writeport_buf_ushort },
313         { "WRITE_PORT_BUFFER_UCHAR",    (FUNC)hal_writeport_buf_uchar },
314         { "READ_PORT_ULONG",            (FUNC)hal_readport_ulong },
315         { "READ_PORT_USHORT",           (FUNC)hal_readport_ushort },
316         { "READ_PORT_UCHAR",            (FUNC)hal_readport_uchar },
317         { "READ_PORT_BUFFER_ULONG",     (FUNC)hal_readport_buf_ulong },
318         { "READ_PORT_BUFFER_USHORT",    (FUNC)hal_readport_buf_ushort },
319         { "READ_PORT_BUFFER_UCHAR",     (FUNC)hal_readport_buf_uchar },
320         { "KfAcquireSpinLock",          (FUNC)hal_lock },
321         { "KfReleaseSpinLock",          (FUNC)hal_unlock },
322         { "KeGetCurrentIrql",           (FUNC)hal_irql },
323         { "KeQueryPerformanceCounter",  (FUNC)hal_perfcount },
324         { "KfLowerIrql",                (FUNC)hal_lower_irql },
325         { "KfRaiseIrql",                (FUNC)hal_raise_irql },
326
327         /*
328          * This last entry is a catch-all for any function we haven't
329          * implemented yet. The PE import list patching routine will
330          * use it for any function that doesn't have an explicit match
331          * in this table.
332          */
333
334         { NULL, (FUNC)dummy },
335
336         /* End of list. */
337
338         { NULL, NULL },
339 };