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