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