kernel - NFS - fix deadlock in NFS client-side readdirplus (part 2)
[dragonfly.git] / sys / emulation / ndis / subr_hal.c
blob5c482668e70e214dd4367cb8630823c9a9cc0721
1 /*
2 * Copyright (c) 2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
32 * $FreeBSD: src/sys/compat/ndis/subr_hal.c,v 1.12 2004/04/19 22:39:04 wpaul Exp $
33 * $DragonFly: src/sys/emulation/ndis/subr_hal.c,v 1.4 2006/12/23 00:27:02 swildner Exp $
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/errno.h>
40 #include <sys/callout.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/proc.h>
45 #include <sys/systm.h>
46 #include <sys/bus.h>
47 #include <sys/rman.h>
48 #include <sys/thread2.h>
50 #include <machine/clock.h>
52 #include "regcall.h"
53 #include "pe_var.h"
54 #include "resource_var.h"
55 #include "ntoskrnl_var.h"
56 #include "ndis_var.h"
57 #include "hal_var.h"
59 #define FUNC void(*)(void)
61 __stdcall static void hal_stall_exec_cpu(uint32_t);
62 __stdcall static void hal_writeport_buf_ulong(uint32_t *,
63 uint32_t *, uint32_t);
64 __stdcall static void hal_writeport_buf_ushort(uint16_t *,
65 uint16_t *, uint32_t);
66 __stdcall static void hal_writeport_buf_uchar(uint8_t *,
67 uint8_t *, uint32_t);
68 __stdcall static void hal_writeport_ulong(uint32_t *, uint32_t);
69 __stdcall static void hal_writeport_ushort(uint16_t *, uint16_t);
70 __stdcall static void hal_writeport_uchar(uint8_t *, uint8_t);
71 __stdcall static uint32_t hal_readport_ulong(uint32_t *);
72 __stdcall static uint16_t hal_readport_ushort(uint16_t *);
73 __stdcall static uint8_t hal_readport_uchar(uint8_t *);
74 __stdcall static void hal_readport_buf_ulong(uint32_t *,
75 uint32_t *, uint32_t);
76 __stdcall static void hal_readport_buf_ushort(uint16_t *,
77 uint16_t *, uint32_t);
78 __stdcall static void hal_readport_buf_uchar(uint8_t *,
79 uint8_t *, uint32_t);
80 __stdcall static uint64_t hal_perfcount(uint64_t *);
81 __stdcall static void dummy (void);
83 extern struct mtx_pool *ndis_mtxpool;
85 __stdcall static void
86 hal_stall_exec_cpu(uint32_t usecs)
88 DELAY(usecs);
89 return;
92 __stdcall static void
93 hal_writeport_ulong(uint32_t *port, uint32_t val)
95 bus_space_write_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
96 return;
99 __stdcall static void
100 hal_writeport_ushort(uint16_t *port, uint16_t val)
102 bus_space_write_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
103 return;
106 __stdcall static void
107 hal_writeport_uchar(uint8_t *port, uint8_t val)
109 bus_space_write_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val);
110 return;
113 __stdcall static void
114 hal_writeport_buf_ulong(uint32_t *port, uint32_t *val, uint32_t cnt)
116 bus_space_write_multi_4(NDIS_BUS_SPACE_IO, 0x0,
117 (bus_size_t)port, val, cnt);
118 return;
121 __stdcall static void
122 hal_writeport_buf_ushort(uint16_t *port, uint16_t *val, uint32_t cnt)
124 bus_space_write_multi_2(NDIS_BUS_SPACE_IO, 0x0,
125 (bus_size_t)port, val, cnt);
126 return;
129 __stdcall static void
130 hal_writeport_buf_uchar(uint8_t *port, uint8_t *val, uint32_t cnt)
132 bus_space_write_multi_1(NDIS_BUS_SPACE_IO, 0x0,
133 (bus_size_t)port, val, cnt);
134 return;
137 __stdcall static uint16_t
138 hal_readport_ushort(uint16_t *port)
140 return(bus_space_read_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
143 __stdcall static uint32_t
144 hal_readport_ulong(uint32_t *port)
146 return(bus_space_read_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
149 __stdcall static uint8_t
150 hal_readport_uchar(uint8_t *port)
152 return(bus_space_read_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port));
155 __stdcall static void
156 hal_readport_buf_ulong(uint32_t *port, uint32_t *val, uint32_t cnt)
158 bus_space_read_multi_4(NDIS_BUS_SPACE_IO, 0x0,
159 (bus_size_t)port, val, cnt);
160 return;
163 __stdcall static void
164 hal_readport_buf_ushort(uint16_t *port, uint16_t *val, uint32_t cnt)
166 bus_space_read_multi_2(NDIS_BUS_SPACE_IO, 0x0,
167 (bus_size_t)port, val, cnt);
168 return;
171 __stdcall static void
172 hal_readport_buf_uchar(uint8_t *port, uint8_t *val, uint32_t cnt)
174 bus_space_read_multi_1(NDIS_BUS_SPACE_IO, 0x0,
175 (bus_size_t)port, val, cnt);
176 return;
180 * The spinlock implementation in Windows differs from that of FreeBSD.
181 * The basic operation of spinlocks involves two steps: 1) spin in a
182 * tight loop while trying to acquire a lock, 2) after obtaining the
183 * lock, disable preemption. (Note that on uniprocessor systems, you're
184 * allowed to skip the first step and just lock out pre-emption, since
185 * it's not possible for you to be in contention with another running
186 * thread.) Later, you release the lock then re-enable preemption.
187 * The difference between Windows and FreeBSD lies in how preemption
188 * is disabled. In FreeBSD, it's done using critical_enter(), which on
189 * the x86 arch translates to a cli instruction. This masks off all
190 * interrupts, and effectively stops the scheduler from ever running
191 * so _nothing_ can execute except the current thread. In Windows,
192 * preemption is disabled by raising the processor IRQL to DISPATCH_LEVEL.
193 * This stops other threads from running, but does _not_ block device
194 * interrupts. This means ISRs can still run, and they can make other
195 * threads runable, but those other threads won't be able to execute
196 * until the current thread lowers the IRQL to something less than
197 * DISPATCH_LEVEL.
199 * In FreeBSD, ISRs run in interrupt threads, so to duplicate the
200 * Windows notion of IRQLs, we use the following rules:
202 * PASSIVE_LEVEL == normal kernel thread priority
203 * DISPATCH_LEVEL == lowest interrupt thread priotity (PI_SOFT)
204 * DEVICE_LEVEL == highest interrupt thread priority (PI_REALTIME)
205 * HIGH_LEVEL == interrupts disabled (critical_enter())
207 * Be aware that, at least on the x86 arch, the Windows spinlock
208 * functions are divided up in peculiar ways. The actual spinlock
209 * functions are KfAcquireSpinLock() and KfReleaseSpinLock(), and
210 * they live in HAL.dll. Meanwhile, KeInitializeSpinLock(),
211 * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel()
212 * live in ntoskrnl.exe. Most Windows source code will call
213 * KeAcquireSpinLock() and KeReleaseSpinLock(), but these are just
214 * macros that call KfAcquireSpinLock() and KfReleaseSpinLock().
215 * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel()
216 * perform the lock aquisition/release functions without doing the
217 * IRQL manipulation, and are used when one is already running at
218 * DISPATCH_LEVEL. Make sense? Good.
220 * According to the Microsoft documentation, any thread that calls
221 * KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If
222 * we detect someone trying to acquire a spinlock from DEVICE_LEVEL
223 * or HIGH_LEVEL, we panic.
226 __stdcall __regcall uint8_t
227 hal_lock(REGARGS1(kspin_lock *lock))
229 uint8_t oldirql;
231 /* I am so going to hell for this. */
232 if (hal_irql() > DISPATCH_LEVEL)
233 panic("IRQL_NOT_LESS_THAN_OR_EQUAL");
235 oldirql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
236 FASTCALL1(ntoskrnl_lock_dpc, lock);
238 return(oldirql);
241 __stdcall __regcall void
242 hal_unlock(REGARGS2(kspin_lock *lock, uint8_t newirql))
244 FASTCALL1(ntoskrnl_unlock_dpc, lock);
245 FASTCALL1(hal_lower_irql, newirql);
247 return;
250 __stdcall uint8_t
251 hal_irql(void)
253 if (AT_DISPATCH_LEVEL(curthread))
254 return(DISPATCH_LEVEL);
255 return(PASSIVE_LEVEL);
258 __stdcall static uint64_t
259 hal_perfcount(uint64_t *freq)
261 if (freq != NULL)
262 *freq = hz;
264 return((uint64_t)ticks);
267 __stdcall __regcall uint8_t
268 hal_raise_irql(REGARGS1(uint8_t irql))
270 uint8_t oldirql;
272 if (irql < hal_irql())
273 panic("IRQL_NOT_LESS_THAN");
275 if (hal_irql() == DISPATCH_LEVEL)
276 return(DISPATCH_LEVEL);
278 oldirql = lwkt_getpri_self();
279 lwkt_setpri_self(TDPRI_INT_HIGH);
281 return(oldirql);
284 __stdcall __regcall void
285 hal_lower_irql(REGARGS1(uint8_t oldirql))
287 if (oldirql == DISPATCH_LEVEL)
288 return;
290 if (hal_irql() != DISPATCH_LEVEL)
291 panic("IRQL_NOT_GREATER_THAN");
293 lwkt_setpri_self(oldirql);
296 __stdcall
297 static void dummy(void)
299 kprintf ("hal dummy called...\n");
300 return;
303 image_patch_table hal_functbl[] = {
304 { "KeStallExecutionProcessor", (FUNC)hal_stall_exec_cpu },
305 { "WRITE_PORT_ULONG", (FUNC)hal_writeport_ulong },
306 { "WRITE_PORT_USHORT", (FUNC)hal_writeport_ushort },
307 { "WRITE_PORT_UCHAR", (FUNC)hal_writeport_uchar },
308 { "WRITE_PORT_BUFFER_ULONG", (FUNC)hal_writeport_buf_ulong },
309 { "WRITE_PORT_BUFFER_USHORT", (FUNC)hal_writeport_buf_ushort },
310 { "WRITE_PORT_BUFFER_UCHAR", (FUNC)hal_writeport_buf_uchar },
311 { "READ_PORT_ULONG", (FUNC)hal_readport_ulong },
312 { "READ_PORT_USHORT", (FUNC)hal_readport_ushort },
313 { "READ_PORT_UCHAR", (FUNC)hal_readport_uchar },
314 { "READ_PORT_BUFFER_ULONG", (FUNC)hal_readport_buf_ulong },
315 { "READ_PORT_BUFFER_USHORT", (FUNC)hal_readport_buf_ushort },
316 { "READ_PORT_BUFFER_UCHAR", (FUNC)hal_readport_buf_uchar },
317 { "KfAcquireSpinLock", (FUNC)hal_lock },
318 { "KfReleaseSpinLock", (FUNC)hal_unlock },
319 { "KeGetCurrentIrql", (FUNC)hal_irql },
320 { "KeQueryPerformanceCounter", (FUNC)hal_perfcount },
321 { "KfLowerIrql", (FUNC)hal_lower_irql },
322 { "KfRaiseIrql", (FUNC)hal_raise_irql },
325 * This last entry is a catch-all for any function we haven't
326 * implemented yet. The PE import list patching routine will
327 * use it for any function that doesn't have an explicit match
328 * in this table.
331 { NULL, (FUNC)dummy },
333 /* End of list. */
335 { NULL, NULL },