1139743Simp/*- 2123474Swpaul * Copyright (c) 2003 3123474Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4123474Swpaul * 5123474Swpaul * Redistribution and use in source and binary forms, with or without 6123474Swpaul * modification, are permitted provided that the following conditions 7123474Swpaul * are met: 8123474Swpaul * 1. Redistributions of source code must retain the above copyright 9123474Swpaul * notice, this list of conditions and the following disclaimer. 10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11123474Swpaul * notice, this list of conditions and the following disclaimer in the 12123474Swpaul * documentation and/or other materials provided with the distribution. 13123474Swpaul * 3. All advertising materials mentioning features or use of this software 14123474Swpaul * must display the following acknowledgement: 15123474Swpaul * This product includes software developed by Bill Paul. 16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17123474Swpaul * may be used to endorse or promote products derived from this software 18123474Swpaul * without specific prior written permission. 19123474Swpaul * 20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23123474Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31123474Swpaul */ 32123474Swpaul 33123474Swpaul#include <sys/cdefs.h> 34123474Swpaul__FBSDID("$FreeBSD$"); 35123474Swpaul 36123474Swpaul#include <sys/param.h> 37123474Swpaul#include <sys/types.h> 38123474Swpaul#include <sys/errno.h> 39123474Swpaul 40123474Swpaul#include <sys/callout.h> 41123474Swpaul#include <sys/kernel.h> 42124094Swpaul#include <sys/lock.h> 43124094Swpaul#include <sys/mutex.h> 44128229Swpaul#include <sys/proc.h> 45128229Swpaul#include <sys/sched.h> 46141524Swpaul#include <sys/module.h> 47123474Swpaul 48123474Swpaul#include <sys/systm.h> 49123474Swpaul#include <machine/bus.h> 50123474Swpaul 51123474Swpaul#include <sys/bus.h> 52123474Swpaul#include <sys/rman.h> 53123474Swpaul 54123474Swpaul#include <compat/ndis/pe_var.h> 55145485Swpaul#include <compat/ndis/resource_var.h> 56145485Swpaul#include <compat/ndis/cfg_var.h> 57132973Swpaul#include <compat/ndis/ntoskrnl_var.h> 58123474Swpaul#include <compat/ndis/hal_var.h> 59123474Swpaul 60144888Swpaulstatic void KeStallExecutionProcessor(uint32_t); 61144888Swpaulstatic void WRITE_PORT_BUFFER_ULONG(uint32_t *, 62124097Swpaul uint32_t *, uint32_t); 63144888Swpaulstatic void WRITE_PORT_BUFFER_USHORT(uint16_t *, 64124097Swpaul uint16_t *, uint32_t); 65144888Swpaulstatic void WRITE_PORT_BUFFER_UCHAR(uint8_t *, 66124097Swpaul uint8_t *, uint32_t); 67144888Swpaulstatic void WRITE_PORT_ULONG(uint32_t *, uint32_t); 68144888Swpaulstatic void WRITE_PORT_USHORT(uint16_t *, uint16_t); 69144888Swpaulstatic void WRITE_PORT_UCHAR(uint8_t *, uint8_t); 70144888Swpaulstatic uint32_t READ_PORT_ULONG(uint32_t *); 71144888Swpaulstatic uint16_t READ_PORT_USHORT(uint16_t *); 72144888Swpaulstatic uint8_t READ_PORT_UCHAR(uint8_t *); 73144888Swpaulstatic void READ_PORT_BUFFER_ULONG(uint32_t *, 74124097Swpaul uint32_t *, uint32_t); 75144888Swpaulstatic void READ_PORT_BUFFER_USHORT(uint16_t *, 76124097Swpaul uint16_t *, uint32_t); 77144888Swpaulstatic void READ_PORT_BUFFER_UCHAR(uint8_t *, 78124097Swpaul uint8_t *, uint32_t); 79144888Swpaulstatic uint64_t KeQueryPerformanceCounter(uint64_t *); 80152136Swpaulstatic void _KeLowerIrql(uint8_t); 81152136Swpaulstatic uint8_t KeRaiseIrqlToDpcLevel(void); 82144888Swpaulstatic void dummy (void); 83123474Swpaul 84151207Swpaul#define NDIS_MAXCPUS 64 85151207Swpaulstatic struct mtx disp_lock[NDIS_MAXCPUS]; 86124409Swpaul 87141963Swpaulint 88141963Swpaulhal_libinit() 89141963Swpaul{ 90141963Swpaul image_patch_table *patch; 91151207Swpaul int i; 92141963Swpaul 93151207Swpaul for (i = 0; i < NDIS_MAXCPUS; i++) 94151207Swpaul mtx_init(&disp_lock[i], "HAL preemption lock", 95151207Swpaul "HAL lock", MTX_RECURSE|MTX_DEF); 96151207Swpaul 97141963Swpaul patch = hal_functbl; 98141963Swpaul while (patch->ipt_func != NULL) { 99141963Swpaul windrv_wrap((funcptr)patch->ipt_func, 100144888Swpaul (funcptr *)&patch->ipt_wrap, 101144888Swpaul patch->ipt_argcnt, patch->ipt_ftype); 102141963Swpaul patch++; 103141963Swpaul } 104141963Swpaul 105198786Srpaulo return (0); 106141963Swpaul} 107141963Swpaul 108141963Swpaulint 109141963Swpaulhal_libfini() 110141963Swpaul{ 111141963Swpaul image_patch_table *patch; 112151207Swpaul int i; 113141963Swpaul 114151207Swpaul for (i = 0; i < NDIS_MAXCPUS; i++) 115151207Swpaul mtx_destroy(&disp_lock[i]); 116151207Swpaul 117141963Swpaul patch = hal_functbl; 118141963Swpaul while (patch->ipt_func != NULL) { 119141963Swpaul windrv_unwrap(patch->ipt_wrap); 120141963Swpaul patch++; 121141963Swpaul } 122141963Swpaul 123198786Srpaulo return (0); 124141963Swpaul} 125141963Swpaul 126144888Swpaulstatic void 127140751SwpaulKeStallExecutionProcessor(usecs) 128123474Swpaul uint32_t usecs; 129123474Swpaul{ 130123474Swpaul DELAY(usecs); 131123474Swpaul} 132123474Swpaul 133144888Swpaulstatic void 134140751SwpaulWRITE_PORT_ULONG(port, val) 135123474Swpaul uint32_t *port; 136123474Swpaul uint32_t val; 137123474Swpaul{ 138124574Sobrien bus_space_write_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); 139123474Swpaul} 140123474Swpaul 141144888Swpaulstatic void 142189004SrdivackyWRITE_PORT_USHORT(uint16_t *port, uint16_t val) 143123474Swpaul{ 144124574Sobrien bus_space_write_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); 145123474Swpaul} 146123474Swpaul 147144888Swpaulstatic void 148189004SrdivackyWRITE_PORT_UCHAR(uint8_t *port, uint8_t val) 149123474Swpaul{ 150124574Sobrien bus_space_write_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port, val); 151123474Swpaul} 152123474Swpaul 153144888Swpaulstatic void 154140751SwpaulWRITE_PORT_BUFFER_ULONG(port, val, cnt) 155124097Swpaul uint32_t *port; 156124097Swpaul uint32_t *val; 157124097Swpaul uint32_t cnt; 158124097Swpaul{ 159124574Sobrien bus_space_write_multi_4(NDIS_BUS_SPACE_IO, 0x0, 160124097Swpaul (bus_size_t)port, val, cnt); 161124097Swpaul} 162124097Swpaul 163144888Swpaulstatic void 164140751SwpaulWRITE_PORT_BUFFER_USHORT(port, val, cnt) 165124097Swpaul uint16_t *port; 166124097Swpaul uint16_t *val; 167124097Swpaul uint32_t cnt; 168124097Swpaul{ 169124574Sobrien bus_space_write_multi_2(NDIS_BUS_SPACE_IO, 0x0, 170124097Swpaul (bus_size_t)port, val, cnt); 171124097Swpaul} 172124097Swpaul 173144888Swpaulstatic void 174140751SwpaulWRITE_PORT_BUFFER_UCHAR(port, val, cnt) 175124097Swpaul uint8_t *port; 176124097Swpaul uint8_t *val; 177124097Swpaul uint32_t cnt; 178124097Swpaul{ 179124574Sobrien bus_space_write_multi_1(NDIS_BUS_SPACE_IO, 0x0, 180124097Swpaul (bus_size_t)port, val, cnt); 181124097Swpaul} 182124097Swpaul 183144888Swpaulstatic uint16_t 184140751SwpaulREAD_PORT_USHORT(port) 185123474Swpaul uint16_t *port; 186123474Swpaul{ 187198786Srpaulo return (bus_space_read_2(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); 188123474Swpaul} 189123474Swpaul 190144888Swpaulstatic uint32_t 191140751SwpaulREAD_PORT_ULONG(port) 192123474Swpaul uint32_t *port; 193123474Swpaul{ 194198786Srpaulo return (bus_space_read_4(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); 195123474Swpaul} 196123474Swpaul 197144888Swpaulstatic uint8_t 198140751SwpaulREAD_PORT_UCHAR(port) 199123474Swpaul uint8_t *port; 200123474Swpaul{ 201198786Srpaulo return (bus_space_read_1(NDIS_BUS_SPACE_IO, 0x0, (bus_size_t)port)); 202123474Swpaul} 203123474Swpaul 204144888Swpaulstatic void 205140751SwpaulREAD_PORT_BUFFER_ULONG(port, val, cnt) 206124097Swpaul uint32_t *port; 207124097Swpaul uint32_t *val; 208124097Swpaul uint32_t cnt; 209124097Swpaul{ 210124574Sobrien bus_space_read_multi_4(NDIS_BUS_SPACE_IO, 0x0, 211124097Swpaul (bus_size_t)port, val, cnt); 212124097Swpaul} 213124097Swpaul 214144888Swpaulstatic void 215140751SwpaulREAD_PORT_BUFFER_USHORT(port, val, cnt) 216124097Swpaul uint16_t *port; 217124097Swpaul uint16_t *val; 218124097Swpaul uint32_t cnt; 219124097Swpaul{ 220124574Sobrien bus_space_read_multi_2(NDIS_BUS_SPACE_IO, 0x0, 221124097Swpaul (bus_size_t)port, val, cnt); 222124097Swpaul} 223124097Swpaul 224144888Swpaulstatic void 225140751SwpaulREAD_PORT_BUFFER_UCHAR(port, val, cnt) 226124097Swpaul uint8_t *port; 227124097Swpaul uint8_t *val; 228124097Swpaul uint32_t cnt; 229124097Swpaul{ 230124574Sobrien bus_space_read_multi_1(NDIS_BUS_SPACE_IO, 0x0, 231124097Swpaul (bus_size_t)port, val, cnt); 232124097Swpaul} 233124097Swpaul 234128229Swpaul/* 235128229Swpaul * The spinlock implementation in Windows differs from that of FreeBSD. 236128229Swpaul * The basic operation of spinlocks involves two steps: 1) spin in a 237128229Swpaul * tight loop while trying to acquire a lock, 2) after obtaining the 238128229Swpaul * lock, disable preemption. (Note that on uniprocessor systems, you're 239128229Swpaul * allowed to skip the first step and just lock out pre-emption, since 240128229Swpaul * it's not possible for you to be in contention with another running 241128229Swpaul * thread.) Later, you release the lock then re-enable preemption. 242128229Swpaul * The difference between Windows and FreeBSD lies in how preemption 243128229Swpaul * is disabled. In FreeBSD, it's done using critical_enter(), which on 244128229Swpaul * the x86 arch translates to a cli instruction. This masks off all 245128229Swpaul * interrupts, and effectively stops the scheduler from ever running 246128229Swpaul * so _nothing_ can execute except the current thread. In Windows, 247128229Swpaul * preemption is disabled by raising the processor IRQL to DISPATCH_LEVEL. 248128229Swpaul * This stops other threads from running, but does _not_ block device 249128229Swpaul * interrupts. This means ISRs can still run, and they can make other 250128229Swpaul * threads runable, but those other threads won't be able to execute 251128229Swpaul * until the current thread lowers the IRQL to something less than 252128229Swpaul * DISPATCH_LEVEL. 253128229Swpaul * 254141524Swpaul * There's another commonly used IRQL in Windows, which is APC_LEVEL. 255141524Swpaul * An APC is an Asynchronous Procedure Call, which differs from a DPC 256141524Swpaul * (Defered Procedure Call) in that a DPC is queued up to run in 257141524Swpaul * another thread, while an APC runs in the thread that scheduled 258141524Swpaul * it (similar to a signal handler in a UNIX process). We don't 259141524Swpaul * actually support the notion of APCs in FreeBSD, so for now, the 260141524Swpaul * only IRQLs we're interested in are DISPATCH_LEVEL and PASSIVE_LEVEL. 261128229Swpaul * 262141524Swpaul * To simulate DISPATCH_LEVEL, we raise the current thread's priority 263141524Swpaul * to PI_REALTIME, which is the highest we can give it. This should, 264141524Swpaul * if I understand things correctly, prevent anything except for an 265141524Swpaul * interrupt thread from preempting us. PASSIVE_LEVEL is basically 266141524Swpaul * everything else. 267128229Swpaul * 268128229Swpaul * Be aware that, at least on the x86 arch, the Windows spinlock 269128229Swpaul * functions are divided up in peculiar ways. The actual spinlock 270128229Swpaul * functions are KfAcquireSpinLock() and KfReleaseSpinLock(), and 271128229Swpaul * they live in HAL.dll. Meanwhile, KeInitializeSpinLock(), 272128229Swpaul * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel() 273128229Swpaul * live in ntoskrnl.exe. Most Windows source code will call 274128229Swpaul * KeAcquireSpinLock() and KeReleaseSpinLock(), but these are just 275128229Swpaul * macros that call KfAcquireSpinLock() and KfReleaseSpinLock(). 276128229Swpaul * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel() 277128229Swpaul * perform the lock aquisition/release functions without doing the 278128229Swpaul * IRQL manipulation, and are used when one is already running at 279128229Swpaul * DISPATCH_LEVEL. Make sense? Good. 280128229Swpaul * 281128229Swpaul * According to the Microsoft documentation, any thread that calls 282128229Swpaul * KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If 283128229Swpaul * we detect someone trying to acquire a spinlock from DEVICE_LEVEL 284128229Swpaul * or HIGH_LEVEL, we panic. 285151207Swpaul * 286151207Swpaul * Alternate sleep-lock-based spinlock implementation 287151207Swpaul * -------------------------------------------------- 288151207Swpaul * 289151207Swpaul * The earlier spinlock implementation was arguably a bit of a hack 290151207Swpaul * and presented several problems. It was basically designed to provide 291151207Swpaul * the functionality of spinlocks without incurring the wrath of 292151207Swpaul * WITNESS. We could get away with using both our spinlock implementation 293151207Swpaul * and FreeBSD sleep locks at the same time, but if WITNESS knew what 294151207Swpaul * we were really up to, it would have spanked us rather severely. 295151207Swpaul * 296151207Swpaul * There's another method we can use based entirely on sleep locks. 297151207Swpaul * First, it's important to realize that everything we're locking 298151207Swpaul * resides inside Project Evil itself: any critical data being locked 299151207Swpaul * by drivers belongs to the drivers, and should not be referenced 300151207Swpaul * by any other OS code outside of the NDISulator. The priority-based 301151207Swpaul * locking scheme has system-wide effects, just like real spinlocks 302151207Swpaul * (blocking preemption affects the whole CPU), but since we keep all 303151207Swpaul * our critical data private, we can use a simpler mechanism that 304151207Swpaul * affects only code/threads directly related to Project Evil. 305151207Swpaul * 306151207Swpaul * The idea is to create a sleep lock mutex for each CPU in the system. 307151207Swpaul * When a CPU running in the NDISulator wants to acquire a spinlock, it 308151207Swpaul * does the following: 309151207Swpaul * - Pin ourselves to the current CPU 310151207Swpaul * - Acquire the mutex for the current CPU 311151207Swpaul * - Spin on the spinlock variable using atomic test and set, just like 312151207Swpaul * a real spinlock. 313151207Swpaul * - Once we have the lock, we execute our critical code 314151207Swpaul * 315151207Swpaul * To give up the lock, we do: 316151207Swpaul * - Clear the spinlock variable with an atomic op 317151207Swpaul * - Release the per-CPU mutex 318151207Swpaul * - Unpin ourselves from the current CPU. 319151207Swpaul * 320151207Swpaul * On a uniprocessor system, this means all threads that access protected 321151207Swpaul * data are serialized through the per-CPU mutex. After one thread 322151207Swpaul * acquires the 'spinlock,' any other thread that uses a spinlock on the 323151207Swpaul * current CPU will block on the per-CPU mutex, which has the same general 324151207Swpaul * effect of blocking pre-emption, but _only_ for those threads that are 325151207Swpaul * running NDISulator code. 326151207Swpaul * 327151207Swpaul * On a multiprocessor system, threads on different CPUs all block on 328151207Swpaul * their respective per-CPU mutex, and the atomic test/set operation 329151207Swpaul * on the spinlock variable provides inter-CPU synchronization, though 330151207Swpaul * only for threads running NDISulator code. 331151207Swpaul * 332151207Swpaul * This method solves an important problem. In Windows, you're allowed 333151207Swpaul * to do an ExAllocatePoolWithTag() with a spinlock held, provided you 334151207Swpaul * allocate from NonPagedPool. This implies an atomic heap allocation 335151207Swpaul * that will not cause the current thread to sleep. (You can't sleep 336151207Swpaul * while holding real spinlock: clowns will eat you.) But in FreeBSD, 337151207Swpaul * malloc(9) _always_ triggers the acquisition of a sleep lock, even 338151207Swpaul * when you use M_NOWAIT. This is not a problem for FreeBSD native 339151207Swpaul * code: you're allowed to sleep in things like interrupt threads. But 340151207Swpaul * it is a problem with the old priority-based spinlock implementation: 341151207Swpaul * even though we get away with it most of the time, we really can't 342151207Swpaul * do a malloc(9) after doing a KeAcquireSpinLock() or KeRaiseIrql(). 343151207Swpaul * With the new implementation, it's not a problem: you're allowed to 344151207Swpaul * acquire more than one sleep lock (as long as you avoid lock order 345151207Swpaul * reversals). 346151207Swpaul * 347151207Swpaul * The one drawback to this approach is that now we have a lot of 348151207Swpaul * contention on one per-CPU mutex within the NDISulator code. Whether 349151207Swpaul * or not this is preferable to the expected Windows spinlock behavior 350151207Swpaul * of blocking pre-emption is debatable. 351128229Swpaul */ 352128229Swpaul 353144888Swpauluint8_t 354144888SwpaulKfAcquireSpinLock(lock) 355144888Swpaul kspin_lock *lock; 356124094Swpaul{ 357128229Swpaul uint8_t oldirql; 358124094Swpaul 359151529Swpaul KeRaiseIrql(DISPATCH_LEVEL, &oldirql); 360144250Swpaul KeAcquireSpinLockAtDpcLevel(lock); 361128295Swpaul 362198786Srpaulo return (oldirql); 363124094Swpaul} 364124094Swpaul 365144888Swpaulvoid 366189004SrdivackyKfReleaseSpinLock(kspin_lock *lock, uint8_t newirql) 367124094Swpaul{ 368144250Swpaul KeReleaseSpinLockFromDpcLevel(lock); 369144250Swpaul KeLowerIrql(newirql); 370124094Swpaul} 371124094Swpaul 372151207Swpauluint8_t 373144888SwpaulKeGetCurrentIrql() 374124094Swpaul{ 375151207Swpaul if (mtx_owned(&disp_lock[curthread->td_oncpu])) 376198786Srpaulo return (DISPATCH_LEVEL); 377198786Srpaulo return (PASSIVE_LEVEL); 378124094Swpaul} 379124094Swpaul 380144888Swpaulstatic uint64_t 381140751SwpaulKeQueryPerformanceCounter(freq) 382125551Swpaul uint64_t *freq; 383125551Swpaul{ 384125551Swpaul if (freq != NULL) 385125551Swpaul *freq = hz; 386125551Swpaul 387198786Srpaulo return ((uint64_t)ticks); 388125551Swpaul} 389125551Swpaul 390144888Swpauluint8_t 391189004SrdivackyKfRaiseIrql(uint8_t irql) 392125628Swpaul{ 393128229Swpaul uint8_t oldirql; 394125628Swpaul 395232509Sbrucec sched_pin(); 396151207Swpaul oldirql = KeGetCurrentIrql(); 397152136Swpaul 398152136Swpaul /* I am so going to hell for this. */ 399152136Swpaul if (oldirql > irql) 400232509Sbrucec panic("IRQL_NOT_LESS_THAN_OR_EQUAL"); 401128229Swpaul 402232509Sbrucec if (oldirql != DISPATCH_LEVEL) 403151207Swpaul mtx_lock(&disp_lock[curthread->td_oncpu]); 404232509Sbrucec else 405232509Sbrucec sched_unpin(); 406232509Sbrucec 407152136Swpaul/*printf("RAISE IRQL: %d %d\n", irql, oldirql);*/ 408128447Swpaul 409198786Srpaulo return (oldirql); 410125628Swpaul} 411125628Swpaul 412189488Sweongyovoid 413189004SrdivackyKfLowerIrql(uint8_t oldirql) 414125628Swpaul{ 415128447Swpaul if (oldirql == DISPATCH_LEVEL) 416128447Swpaul return; 417128447Swpaul 418140751Swpaul if (KeGetCurrentIrql() != DISPATCH_LEVEL) 419128295Swpaul panic("IRQL_NOT_GREATER_THAN"); 420128229Swpaul 421151207Swpaul mtx_unlock(&disp_lock[curthread->td_oncpu]); 422151207Swpaul sched_unpin(); 423125628Swpaul} 424125628Swpaul 425152136Swpaulstatic uint8_t 426152136SwpaulKeRaiseIrqlToDpcLevel(void) 427152136Swpaul{ 428152136Swpaul uint8_t irql; 429152136Swpaul 430152136Swpaul KeRaiseIrql(DISPATCH_LEVEL, &irql); 431198786Srpaulo return (irql); 432152136Swpaul} 433152136Swpaul 434152136Swpaulstatic void 435189004Srdivacky_KeLowerIrql(uint8_t oldirql) 436152136Swpaul{ 437152136Swpaul KeLowerIrql(oldirql); 438152136Swpaul} 439152136Swpaul 440123474Swpaulstatic void dummy() 441123474Swpaul{ 442198786Srpaulo printf("hal dummy called...\n"); 443123474Swpaul} 444123474Swpaul 445123474Swpaulimage_patch_table hal_functbl[] = { 446144888Swpaul IMPORT_SFUNC(KeStallExecutionProcessor, 1), 447144888Swpaul IMPORT_SFUNC(WRITE_PORT_ULONG, 2), 448144888Swpaul IMPORT_SFUNC(WRITE_PORT_USHORT, 2), 449144888Swpaul IMPORT_SFUNC(WRITE_PORT_UCHAR, 2), 450144888Swpaul IMPORT_SFUNC(WRITE_PORT_BUFFER_ULONG, 3), 451144888Swpaul IMPORT_SFUNC(WRITE_PORT_BUFFER_USHORT, 3), 452144888Swpaul IMPORT_SFUNC(WRITE_PORT_BUFFER_UCHAR, 3), 453144888Swpaul IMPORT_SFUNC(READ_PORT_ULONG, 1), 454144888Swpaul IMPORT_SFUNC(READ_PORT_USHORT, 1), 455144888Swpaul IMPORT_SFUNC(READ_PORT_UCHAR, 1), 456146015Swpaul IMPORT_SFUNC(READ_PORT_BUFFER_ULONG, 3), 457146015Swpaul IMPORT_SFUNC(READ_PORT_BUFFER_USHORT, 3), 458146015Swpaul IMPORT_SFUNC(READ_PORT_BUFFER_UCHAR, 3), 459144888Swpaul IMPORT_FFUNC(KfAcquireSpinLock, 1), 460144888Swpaul IMPORT_FFUNC(KfReleaseSpinLock, 1), 461144888Swpaul IMPORT_SFUNC(KeGetCurrentIrql, 0), 462144888Swpaul IMPORT_SFUNC(KeQueryPerformanceCounter, 1), 463144888Swpaul IMPORT_FFUNC(KfLowerIrql, 1), 464144888Swpaul IMPORT_FFUNC(KfRaiseIrql, 1), 465152136Swpaul IMPORT_SFUNC(KeRaiseIrqlToDpcLevel, 0), 466152136Swpaul#undef KeLowerIrql 467152136Swpaul IMPORT_SFUNC_MAP(KeLowerIrql, _KeLowerIrql, 1), 468123474Swpaul 469123474Swpaul /* 470123474Swpaul * This last entry is a catch-all for any function we haven't 471123474Swpaul * implemented yet. The PE import list patching routine will 472123474Swpaul * use it for any function that doesn't have an explicit match 473123474Swpaul * in this table. 474123474Swpaul */ 475123474Swpaul 476145895Swpaul { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL }, 477123474Swpaul 478123474Swpaul /* End of list. */ 479123474Swpaul 480141963Swpaul { NULL, NULL, NULL } 481123474Swpaul}; 482