1/**************************************************************************** 2* 3* Realmode X86 Emulator Library 4* 5* Copyright (C) 1996-1999 SciTech Software, Inc. 6* Copyright (C) David Mosberger-Tang 7* Copyright (C) 1999 Egbert Eich 8* 9* ======================================================================== 10* 11* Permission to use, copy, modify, distribute, and sell this software and 12* its documentation for any purpose is hereby granted without fee, 13* provided that the above copyright notice appear in all copies and that 14* both that copyright notice and this permission notice appear in 15* supporting documentation, and that the name of the authors not be used 16* in advertising or publicity pertaining to distribution of the software 17* without specific, written prior permission. The authors makes no 18* representations about the suitability of this software for any purpose. 19* It is provided "as is" without express or implied warranty. 20* 21* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 22* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 23* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 24* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 25* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 26* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 27* PERFORMANCE OF THIS SOFTWARE. 28* 29* ======================================================================== 30* 31* Language: ANSI C 32* Environment: Any 33* Developer: Kendall Bennett 34* 35* Description: This file includes subroutines which are related to 36* programmed I/O and memory access. Included in this module 37* are default functions with limited usefulness. For real 38* uses these functions will most likely be overriden by the 39* user library. 40* 41****************************************************************************/ 42 43#include "x86emu.h" 44#include "x86emu/x86emui.h" 45#include "x86emu/regs.h" 46#include "x86emu/debug.h" 47#include "x86emu/prim_ops.h" 48#ifndef NO_SYS_HEADERS 49#include <string.h> 50#endif 51 52# ifndef NO_INLINE 53# ifdef __GNUC__ 54 55/* Define some packed structures to use with unaligned accesses */ 56 57struct __una_u64 { u64 x __attribute__((packed)); }; 58struct __una_u32 { u32 x __attribute__((packed)); }; 59struct __una_u16 { u16 x __attribute__((packed)); }; 60 61/* Elemental unaligned loads */ 62 63static __inline__ u64 ldq_u(u64 *p) 64{ 65 const struct __una_u64 *ptr = (const struct __una_u64 *) p; 66 return ptr->x; 67} 68 69static __inline__ u32 ldl_u(u32 *p) 70{ 71 const struct __una_u32 *ptr = (const struct __una_u32 *) p; 72 return ptr->x; 73} 74 75static __inline__ u16 ldw_u(u16 *p) 76{ 77 const struct __una_u16 *ptr = (const struct __una_u16 *) p; 78 return ptr->x; 79} 80 81/* Elemental unaligned stores */ 82 83static __inline__ void stq_u(u64 val, u64 *p) 84{ 85 struct __una_u64 *ptr = (struct __una_u64 *) p; 86 ptr->x = val; 87} 88 89static __inline__ void stl_u(u32 val, u32 *p) 90{ 91 struct __una_u32 *ptr = (struct __una_u32 *) p; 92 ptr->x = val; 93} 94 95static __inline__ void stw_u(u16 val, u16 *p) 96{ 97 struct __una_u16 *ptr = (struct __una_u16 *) p; 98 ptr->x = val; 99} 100# else /* !__GNUC__ */ 101 102static __inline__ u64 ldq_u(u64 *p) 103{ 104 u64 ret; 105 memmove(&ret, p, sizeof(*p)); 106 return ret; 107} 108 109static __inline__ u32 ldl_u(u32 *p) 110{ 111 u32 ret; 112 memmove(&ret, p, sizeof(*p)); 113 return ret; 114} 115 116static __inline__ u16 ldw_u(u16 *p) 117{ 118 u16 ret; 119 memmove(&ret, p, sizeof(*p)); 120 return ret; 121} 122 123static __inline__ void stq_u(u64 val, u64 *p) 124{ 125 u64 tmp = val; 126 memmove(p, &tmp, sizeof(*p)); 127} 128 129static __inline__ void stl_u(u32 val, u32 *p) 130{ 131 u32 tmp = val; 132 memmove(p, &tmp, sizeof(*p)); 133} 134 135static __inline__ void stw_u(u16 val, u16 *p) 136{ 137 u16 tmp = val; 138 memmove(p, &tmp, sizeof(*p)); 139} 140 141# endif /* __GNUC__ */ 142# endif /* NO_INLINE */ 143/*------------------------- Global Variables ------------------------------*/ 144 145X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */ 146X86EMU_intrFuncs _X86EMU_intrTab[256]; 147 148/*----------------------------- Implementation ----------------------------*/ 149 150/**************************************************************************** 151PARAMETERS: 152addr - Emulator memory address to read 153 154RETURNS: 155Byte value read from emulator memory. 156 157REMARKS: 158Reads a byte value from the emulator memory. 159****************************************************************************/ 160u8 X86API rdb( 161 u32 addr) 162{ 163 u8 val; 164 165 if (addr > M.mem_size - 1) { 166 DB(printk("mem_read: address %#lx out of range!\n", addr);) 167 HALT_SYS(); 168 } 169 val = *(u8*)(M.mem_base + addr); 170DB( if (DEBUG_MEM_TRACE()) 171 printk("%#08x 1 -> %#x\n", addr, val);) 172 return val; 173} 174 175/**************************************************************************** 176PARAMETERS: 177addr - Emulator memory address to read 178 179RETURNS: 180Word value read from emulator memory. 181 182REMARKS: 183Reads a word value from the emulator memory. 184****************************************************************************/ 185u16 X86API rdw( 186 u32 addr) 187{ 188 u16 val = 0; 189 190 if (addr > M.mem_size - 2) { 191 DB(printk("mem_read: address %#lx out of range!\n", addr);) 192 HALT_SYS(); 193 } 194#ifdef __BIG_ENDIAN__ 195 if (addr & 0x1) { 196 val = (*(u8*)(M.mem_base + addr) | 197 (*(u8*)(M.mem_base + addr + 1) << 8)); 198 } 199 else 200#endif 201 val = ldw_u((u16*)(M.mem_base + addr)); 202 DB( if (DEBUG_MEM_TRACE()) 203 printk("%#08x 2 -> %#x\n", addr, val);) 204 return val; 205} 206 207/**************************************************************************** 208PARAMETERS: 209addr - Emulator memory address to read 210 211RETURNS: 212Long value read from emulator memory. 213REMARKS: 214Reads a long value from the emulator memory. 215****************************************************************************/ 216u32 X86API rdl( 217 u32 addr) 218{ 219 u32 val = 0; 220 221 if (addr > M.mem_size - 4) { 222 DB(printk("mem_read: address %#lx out of range!\n", addr);) 223 HALT_SYS(); 224 } 225#ifdef __BIG_ENDIAN__ 226 if (addr & 0x3) { 227 val = (*(u8*)(M.mem_base + addr + 0) | 228 (*(u8*)(M.mem_base + addr + 1) << 8) | 229 (*(u8*)(M.mem_base + addr + 2) << 16) | 230 (*(u8*)(M.mem_base + addr + 3) << 24)); 231 } 232 else 233#endif 234 val = ldl_u((u32*)(M.mem_base + addr)); 235DB( if (DEBUG_MEM_TRACE()) 236 printk("%#08x 4 -> %#x\n", addr, val);) 237 return val; 238} 239 240/**************************************************************************** 241PARAMETERS: 242addr - Emulator memory address to read 243val - Value to store 244 245REMARKS: 246Writes a byte value to emulator memory. 247****************************************************************************/ 248void X86API wrb( 249 u32 addr, 250 u8 val) 251{ 252DB( if (DEBUG_MEM_TRACE()) 253 printk("%#08x 1 <- %#x\n", addr, val);) 254 if (addr > M.mem_size - 1) { 255 DB(printk("mem_write: address %#lx out of range!\n", addr);) 256 HALT_SYS(); 257 } 258 *(u8*)(M.mem_base + addr) = val; 259} 260 261/**************************************************************************** 262PARAMETERS: 263addr - Emulator memory address to read 264val - Value to store 265 266REMARKS: 267Writes a word value to emulator memory. 268****************************************************************************/ 269void X86API wrw( 270 u32 addr, 271 u16 val) 272{ 273DB( if (DEBUG_MEM_TRACE()) 274 printk("%#08x 2 <- %#x\n", addr, val);) 275 if (addr > M.mem_size - 2) { 276 DB(printk("mem_write: address %#lx out of range!\n", addr);) 277 HALT_SYS(); 278 } 279#ifdef __BIG_ENDIAN__ 280 if (addr & 0x1) { 281 *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff; 282 *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff; 283 } 284 else 285#endif 286 stw_u(val,(u16*)(M.mem_base + addr)); 287} 288 289/**************************************************************************** 290PARAMETERS: 291addr - Emulator memory address to read 292val - Value to store 293 294REMARKS: 295Writes a long value to emulator memory. 296****************************************************************************/ 297void X86API wrl( 298 u32 addr, 299 u32 val) 300{ 301DB( if (DEBUG_MEM_TRACE()) 302 printk("%#08x 4 <- %#x\n", addr, val);) 303 if (addr > M.mem_size - 4) { 304 DB(printk("mem_write: address %#lx out of range!\n", addr);) 305 HALT_SYS(); 306 } 307#ifdef __BIG_ENDIAN__ 308 if (addr & 0x1) { 309 *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff; 310 *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff; 311 *(u8*)(M.mem_base + addr + 2) = (val >> 16) & 0xff; 312 *(u8*)(M.mem_base + addr + 3) = (val >> 24) & 0xff; 313 } 314 else 315#endif 316 stl_u(val,(u32*)(M.mem_base + addr)); 317} 318 319/**************************************************************************** 320PARAMETERS: 321addr - PIO address to read 322RETURN: 3230 324REMARKS: 325Default PIO byte read function. Doesn't perform real inb. 326****************************************************************************/ 327static u8 X86API p_inb( 328 X86EMU_pioAddr addr) 329{ 330DB( if (DEBUG_IO_TRACE()) 331 printk("inb %#04x \n", addr);) 332 return 0; 333} 334 335/**************************************************************************** 336PARAMETERS: 337addr - PIO address to read 338RETURN: 3390 340REMARKS: 341Default PIO word read function. Doesn't perform real inw. 342****************************************************************************/ 343static u16 X86API p_inw( 344 X86EMU_pioAddr addr) 345{ 346DB( if (DEBUG_IO_TRACE()) 347 printk("inw %#04x \n", addr);) 348 return 0; 349} 350 351/**************************************************************************** 352PARAMETERS: 353addr - PIO address to read 354RETURN: 3550 356REMARKS: 357Default PIO long read function. Doesn't perform real inl. 358****************************************************************************/ 359static u32 X86API p_inl( 360 X86EMU_pioAddr addr) 361{ 362DB( if (DEBUG_IO_TRACE()) 363 printk("inl %#04x \n", addr);) 364 return 0; 365} 366 367/**************************************************************************** 368PARAMETERS: 369addr - PIO address to write 370val - Value to store 371REMARKS: 372Default PIO byte write function. Doesn't perform real outb. 373****************************************************************************/ 374static void X86API p_outb( 375 X86EMU_pioAddr addr, 376 u8 val) 377{ 378DB( if (DEBUG_IO_TRACE()) 379 printk("outb %#02x -> %#04x \n", val, addr);) 380 return; 381} 382 383/**************************************************************************** 384PARAMETERS: 385addr - PIO address to write 386val - Value to store 387REMARKS: 388Default PIO word write function. Doesn't perform real outw. 389****************************************************************************/ 390static void X86API p_outw( 391 X86EMU_pioAddr addr, 392 u16 val) 393{ 394DB( if (DEBUG_IO_TRACE()) 395 printk("outw %#04x -> %#04x \n", val, addr);) 396 return; 397} 398 399/**************************************************************************** 400PARAMETERS: 401addr - PIO address to write 402val - Value to store 403REMARKS: 404Default PIO ;ong write function. Doesn't perform real outl. 405****************************************************************************/ 406static void X86API p_outl( 407 X86EMU_pioAddr addr, 408 u32 val) 409{ 410DB( if (DEBUG_IO_TRACE()) 411 printk("outl %#08x -> %#04x \n", val, addr);) 412 return; 413} 414 415/*------------------------- Global Variables ------------------------------*/ 416 417u8 (X86APIP sys_rdb)(u32 addr) = rdb; 418u16 (X86APIP sys_rdw)(u32 addr) = rdw; 419u32 (X86APIP sys_rdl)(u32 addr) = rdl; 420void (X86APIP sys_wrb)(u32 addr,u8 val) = wrb; 421void (X86APIP sys_wrw)(u32 addr,u16 val) = wrw; 422void (X86APIP sys_wrl)(u32 addr,u32 val) = wrl; 423u8 (X86APIP sys_inb)(X86EMU_pioAddr addr) = p_inb; 424u16 (X86APIP sys_inw)(X86EMU_pioAddr addr) = p_inw; 425u32 (X86APIP sys_inl)(X86EMU_pioAddr addr) = p_inl; 426void (X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) = p_outb; 427void (X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val) = p_outw; 428void (X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val) = p_outl; 429 430/*----------------------------- Setup -------------------------------------*/ 431 432/**************************************************************************** 433PARAMETERS: 434funcs - New memory function pointers to make active 435 436REMARKS: 437This function is used to set the pointers to functions which access 438memory space, allowing the user application to override these functions 439and hook them out as necessary for their application. 440****************************************************************************/ 441void X86EMU_setupMemFuncs( 442 X86EMU_memFuncs *funcs) 443{ 444 sys_rdb = funcs->rdb; 445 sys_rdw = funcs->rdw; 446 sys_rdl = funcs->rdl; 447 sys_wrb = funcs->wrb; 448 sys_wrw = funcs->wrw; 449 sys_wrl = funcs->wrl; 450} 451 452/**************************************************************************** 453PARAMETERS: 454funcs - New programmed I/O function pointers to make active 455 456REMARKS: 457This function is used to set the pointers to functions which access 458I/O space, allowing the user application to override these functions 459and hook them out as necessary for their application. 460****************************************************************************/ 461void X86EMU_setupPioFuncs( 462 X86EMU_pioFuncs *funcs) 463{ 464 sys_inb = funcs->inb; 465 sys_inw = funcs->inw; 466 sys_inl = funcs->inl; 467 sys_outb = funcs->outb; 468 sys_outw = funcs->outw; 469 sys_outl = funcs->outl; 470} 471 472/**************************************************************************** 473PARAMETERS: 474funcs - New interrupt vector table to make active 475 476REMARKS: 477This function is used to set the pointers to functions which handle 478interrupt processing in the emulator, allowing the user application to 479hook interrupts as necessary for their application. Any interrupts that 480are not hooked by the user application, and reflected and handled internally 481in the emulator via the interrupt vector table. This allows the application 482to get control when the code being emulated executes specific software 483interrupts. 484****************************************************************************/ 485void X86EMU_setupIntrFuncs( 486 X86EMU_intrFuncs funcs[]) 487{ 488 int i; 489 490 for (i=0; i < 256; i++) 491 _X86EMU_intrTab[i] = NULL; 492 if (funcs) { 493 for (i = 0; i < 256; i++) 494 _X86EMU_intrTab[i] = funcs[i]; 495 } 496} 497 498/**************************************************************************** 499PARAMETERS: 500int - New software interrupt to prepare for 501 502REMARKS: 503This function is used to set up the emulator state to exceute a software 504interrupt. This can be used by the user application code to allow an 505interrupt to be hooked, examined and then reflected back to the emulator 506so that the code in the emulator will continue processing the software 507interrupt as per normal. This essentially allows system code to actively 508hook and handle certain software interrupts as necessary. 509****************************************************************************/ 510void X86EMU_prepareForInt( 511 int num) 512{ 513 push_word((u16)M.x86.R_FLG); 514 CLEAR_FLAG(F_IF); 515 CLEAR_FLAG(F_TF); 516 push_word(M.x86.R_CS); 517 M.x86.R_CS = mem_access_word(num * 4 + 2); 518 push_word(M.x86.R_IP); 519 M.x86.R_IP = mem_access_word(num * 4); 520 M.x86.intr = 0; 521} 522