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
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>
45 #include <sys/systm.h>
48 #include <sys/thread2.h>
50 #include <machine/clock.h>
54 #include "resource_var.h"
55 #include "ntoskrnl_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 *,
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 *,
80 __stdcall
static uint64_t hal_perfcount(uint64_t *);
81 __stdcall
static void dummy (void);
83 extern struct mtx_pool
*ndis_mtxpool
;
86 hal_stall_exec_cpu(uint32_t usecs
)
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
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
))
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
);
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
);
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
)
264 return((uint64_t)ticks
);
267 __stdcall __regcall
uint8_t
268 hal_raise_irql(REGARGS1(uint8_t irql
))
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
);
284 __stdcall __regcall
void
285 hal_lower_irql(REGARGS1(uint8_t oldirql
))
287 if (oldirql
== DISPATCH_LEVEL
)
290 if (hal_irql() != DISPATCH_LEVEL
)
291 panic("IRQL_NOT_GREATER_THAN");
293 lwkt_setpri_self(oldirql
);
297 static void dummy(void)
299 kprintf ("hal dummy called...\n");
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
331 { NULL
, (FUNC
)dummy
},