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#ifdef __GNUC__ 53 54/* Define some packed structures to use with unaligned accesses */ 55 56struct __una_u64 { 57 u64 x __attribute__ ((packed)); 58}; 59struct __una_u32 { 60 u32 x __attribute__ ((packed)); 61}; 62struct __una_u16 { 63 u16 x __attribute__ ((packed)); 64}; 65 66/* Elemental unaligned loads */ 67 68static __inline__ u64 69ldq_u(u64 * p) 70{ 71 const struct __una_u64 *ptr = (const struct __una_u64 *) p; 72 73 return ptr->x; 74} 75 76static __inline__ u32 77ldl_u(u32 * p) 78{ 79 const struct __una_u32 *ptr = (const struct __una_u32 *) p; 80 81 return ptr->x; 82} 83 84static __inline__ u16 85ldw_u(u16 * p) 86{ 87 const struct __una_u16 *ptr = (const struct __una_u16 *) p; 88 89 return ptr->x; 90} 91 92/* Elemental unaligned stores */ 93 94static __inline__ void 95stq_u(u64 val, u64 * p) 96{ 97 struct __una_u64 *ptr = (struct __una_u64 *) p; 98 99 ptr->x = val; 100} 101 102static __inline__ void 103stl_u(u32 val, u32 * p) 104{ 105 struct __una_u32 *ptr = (struct __una_u32 *) p; 106 107 ptr->x = val; 108} 109 110static __inline__ void 111stw_u(u16 val, u16 * p) 112{ 113 struct __una_u16 *ptr = (struct __una_u16 *) p; 114 115 ptr->x = val; 116} 117#else /* !__GNUC__ */ 118 119static __inline__ u64 120ldq_u(u64 * p) 121{ 122 u64 ret; 123 124 memmove(&ret, p, sizeof(*p)); 125 return ret; 126} 127 128static __inline__ u32 129ldl_u(u32 * p) 130{ 131 u32 ret; 132 133 memmove(&ret, p, sizeof(*p)); 134 return ret; 135} 136 137static __inline__ u16 138ldw_u(u16 * p) 139{ 140 u16 ret; 141 142 memmove(&ret, p, sizeof(*p)); 143 return ret; 144} 145 146static __inline__ void 147stq_u(u64 val, u64 * p) 148{ 149 u64 tmp = val; 150 151 memmove(p, &tmp, sizeof(*p)); 152} 153 154static __inline__ void 155stl_u(u32 val, u32 * p) 156{ 157 u32 tmp = val; 158 159 memmove(p, &tmp, sizeof(*p)); 160} 161 162static __inline__ void 163stw_u(u16 val, u16 * p) 164{ 165 u16 tmp = val; 166 167 memmove(p, &tmp, sizeof(*p)); 168} 169 170#endif /* __GNUC__ */ 171/*------------------------- Global Variables ------------------------------*/ 172 173X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */ 174X86EMU_intrFuncs _X86EMU_intrTab[256]; 175 176/*----------------------------- Implementation ----------------------------*/ 177 178/**************************************************************************** 179PARAMETERS: 180addr - Emulator memory address to read 181 182RETURNS: 183Byte value read from emulator memory. 184 185REMARKS: 186Reads a byte value from the emulator memory. 187****************************************************************************/ 188u8 X86API 189rdb(u32 addr) 190{ 191 u8 val; 192 193 if (addr > M.mem_size - 1) { 194 DB(printk("mem_read: address %#x out of range!\n", addr); 195 ) 196 HALT_SYS(); 197 } 198 val = *(u8 *) (M.mem_base + addr); 199 DB(if (DEBUG_MEM_TRACE()) 200 printk("%#08x 1 -> %#x\n", addr, val);) 201 return val; 202} 203 204/**************************************************************************** 205PARAMETERS: 206addr - Emulator memory address to read 207 208RETURNS: 209Word value read from emulator memory. 210 211REMARKS: 212Reads a word value from the emulator memory. 213****************************************************************************/ 214u16 X86API 215rdw(u32 addr) 216{ 217 u16 val = 0; 218 219 if (addr > M.mem_size - 2) { 220 DB(printk("mem_read: address %#x out of range!\n", addr); 221 ) 222 HALT_SYS(); 223 } 224#ifdef __BIG_ENDIAN__ 225 if (addr & 0x1) { 226 val = (*(u8 *) (M.mem_base + addr) | 227 (*(u8 *) (M.mem_base + addr + 1) << 8)); 228 } 229 else 230#endif 231 val = ldw_u((u16 *) (M.mem_base + addr)); 232 DB(if (DEBUG_MEM_TRACE()) 233 printk("%#08x 2 -> %#x\n", addr, val);) 234 return val; 235} 236 237/**************************************************************************** 238PARAMETERS: 239addr - Emulator memory address to read 240 241RETURNS: 242Long value read from emulator memory. 243REMARKS: 244Reads a long value from the emulator memory. 245****************************************************************************/ 246u32 X86API 247rdl(u32 addr) 248{ 249 u32 val = 0; 250 251 if (addr > M.mem_size - 4) { 252 DB(printk("mem_read: address %#x out of range!\n", addr); 253 ) 254 HALT_SYS(); 255 } 256#ifdef __BIG_ENDIAN__ 257 if (addr & 0x3) { 258 val = (*(u8 *) (M.mem_base + addr + 0) | 259 (*(u8 *) (M.mem_base + addr + 1) << 8) | 260 (*(u8 *) (M.mem_base + addr + 2) << 16) | 261 (*(u8 *) (M.mem_base + addr + 3) << 24)); 262 } 263 else 264#endif 265 val = ldl_u((u32 *) (M.mem_base + addr)); 266 DB(if (DEBUG_MEM_TRACE()) 267 printk("%#08x 4 -> %#x\n", addr, val);) 268 return val; 269} 270 271/**************************************************************************** 272PARAMETERS: 273addr - Emulator memory address to read 274val - Value to store 275 276REMARKS: 277Writes a byte value to emulator memory. 278****************************************************************************/ 279void X86API 280wrb(u32 addr, u8 val) 281{ 282 DB(if (DEBUG_MEM_TRACE()) 283 printk("%#08x 1 <- %#x\n", addr, val);) 284 if (addr > M.mem_size - 1) { 285 DB(printk("mem_write: address %#x out of range!\n", addr); 286 ) 287 HALT_SYS(); 288 } 289 *(u8 *) (M.mem_base + addr) = val; 290} 291 292/**************************************************************************** 293PARAMETERS: 294addr - Emulator memory address to read 295val - Value to store 296 297REMARKS: 298Writes a word value to emulator memory. 299****************************************************************************/ 300void X86API 301wrw(u32 addr, u16 val) 302{ 303 DB(if (DEBUG_MEM_TRACE()) 304 printk("%#08x 2 <- %#x\n", addr, val);) 305 if (addr > M.mem_size - 2) { 306 DB(printk("mem_write: address %#x out of range!\n", addr); 307 ) 308 HALT_SYS(); 309 } 310#ifdef __BIG_ENDIAN__ 311 if (addr & 0x1) { 312 *(u8 *) (M.mem_base + addr + 0) = (val >> 0) & 0xff; 313 *(u8 *) (M.mem_base + addr + 1) = (val >> 8) & 0xff; 314 } 315 else 316#endif 317 stw_u(val, (u16 *) (M.mem_base + addr)); 318} 319 320/**************************************************************************** 321PARAMETERS: 322addr - Emulator memory address to read 323val - Value to store 324 325REMARKS: 326Writes a long value to emulator memory. 327****************************************************************************/ 328void X86API 329wrl(u32 addr, u32 val) 330{ 331 DB(if (DEBUG_MEM_TRACE()) 332 printk("%#08x 4 <- %#x\n", addr, val);) 333 if (addr > M.mem_size - 4) { 334 DB(printk("mem_write: address %#x out of range!\n", addr); 335 ) 336 HALT_SYS(); 337 } 338#ifdef __BIG_ENDIAN__ 339 if (addr & 0x1) { 340 *(u8 *) (M.mem_base + addr + 0) = (val >> 0) & 0xff; 341 *(u8 *) (M.mem_base + addr + 1) = (val >> 8) & 0xff; 342 *(u8 *) (M.mem_base + addr + 2) = (val >> 16) & 0xff; 343 *(u8 *) (M.mem_base + addr + 3) = (val >> 24) & 0xff; 344 } 345 else 346#endif 347 stl_u(val, (u32 *) (M.mem_base + addr)); 348} 349 350/**************************************************************************** 351PARAMETERS: 352addr - PIO address to read 353RETURN: 3540 355REMARKS: 356Default PIO byte read function. Doesn't perform real inb. 357****************************************************************************/ 358static u8 X86API 359p_inb(X86EMU_pioAddr addr) 360{ 361 DB(if (DEBUG_IO_TRACE()) 362 printk("inb %#04x \n", addr);) 363 return 0; 364} 365 366/**************************************************************************** 367PARAMETERS: 368addr - PIO address to read 369RETURN: 3700 371REMARKS: 372Default PIO word read function. Doesn't perform real inw. 373****************************************************************************/ 374static u16 X86API 375p_inw(X86EMU_pioAddr addr) 376{ 377 DB(if (DEBUG_IO_TRACE()) 378 printk("inw %#04x \n", addr);) 379 return 0; 380} 381 382/**************************************************************************** 383PARAMETERS: 384addr - PIO address to read 385RETURN: 3860 387REMARKS: 388Default PIO long read function. Doesn't perform real inl. 389****************************************************************************/ 390static u32 X86API 391p_inl(X86EMU_pioAddr addr) 392{ 393 DB(if (DEBUG_IO_TRACE()) 394 printk("inl %#04x \n", addr);) 395 return 0; 396} 397 398/**************************************************************************** 399PARAMETERS: 400addr - PIO address to write 401val - Value to store 402REMARKS: 403Default PIO byte write function. Doesn't perform real outb. 404****************************************************************************/ 405static void X86API 406p_outb(X86EMU_pioAddr addr, u8 val) 407{ 408 DB(if (DEBUG_IO_TRACE()) 409 printk("outb %#02x -> %#04x \n", val, addr);) 410 return; 411} 412 413/**************************************************************************** 414PARAMETERS: 415addr - PIO address to write 416val - Value to store 417REMARKS: 418Default PIO word write function. Doesn't perform real outw. 419****************************************************************************/ 420static void X86API 421p_outw(X86EMU_pioAddr addr, u16 val) 422{ 423 DB(if (DEBUG_IO_TRACE()) 424 printk("outw %#04x -> %#04x \n", val, addr);) 425 return; 426} 427 428/**************************************************************************** 429PARAMETERS: 430addr - PIO address to write 431val - Value to store 432REMARKS: 433Default PIO ;ong write function. Doesn't perform real outl. 434****************************************************************************/ 435static void X86API 436p_outl(X86EMU_pioAddr addr, u32 val) 437{ 438 DB(if (DEBUG_IO_TRACE()) 439 printk("outl %#08x -> %#04x \n", val, addr);) 440 return; 441} 442 443/*------------------------- Global Variables ------------------------------*/ 444 445u8(X86APIP sys_rdb) (u32 addr) = rdb; 446u16(X86APIP sys_rdw) (u32 addr) = rdw; 447u32(X86APIP sys_rdl) (u32 addr) = rdl; 448void (X86APIP sys_wrb) (u32 addr, u8 val) = wrb; 449void (X86APIP sys_wrw) (u32 addr, u16 val) = wrw; 450void (X86APIP sys_wrl) (u32 addr, u32 val) = wrl; 451 452u8(X86APIP sys_inb) (X86EMU_pioAddr addr) = p_inb; 453u16(X86APIP sys_inw) (X86EMU_pioAddr addr) = p_inw; 454u32(X86APIP sys_inl) (X86EMU_pioAddr addr) = p_inl; 455void (X86APIP sys_outb) (X86EMU_pioAddr addr, u8 val) = p_outb; 456void (X86APIP sys_outw) (X86EMU_pioAddr addr, u16 val) = p_outw; 457void (X86APIP sys_outl) (X86EMU_pioAddr addr, u32 val) = p_outl; 458 459/*----------------------------- Setup -------------------------------------*/ 460 461/**************************************************************************** 462PARAMETERS: 463funcs - New memory function pointers to make active 464 465REMARKS: 466This function is used to set the pointers to functions which access 467memory space, allowing the user application to override these functions 468and hook them out as necessary for their application. 469****************************************************************************/ 470void 471X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs) 472{ 473 sys_rdb = funcs->rdb; 474 sys_rdw = funcs->rdw; 475 sys_rdl = funcs->rdl; 476 sys_wrb = funcs->wrb; 477 sys_wrw = funcs->wrw; 478 sys_wrl = funcs->wrl; 479} 480 481/**************************************************************************** 482PARAMETERS: 483funcs - New programmed I/O function pointers to make active 484 485REMARKS: 486This function is used to set the pointers to functions which access 487I/O space, allowing the user application to override these functions 488and hook them out as necessary for their application. 489****************************************************************************/ 490void 491X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs) 492{ 493 sys_inb = funcs->inb; 494 sys_inw = funcs->inw; 495 sys_inl = funcs->inl; 496 sys_outb = funcs->outb; 497 sys_outw = funcs->outw; 498 sys_outl = funcs->outl; 499} 500 501/**************************************************************************** 502PARAMETERS: 503funcs - New interrupt vector table to make active 504 505REMARKS: 506This function is used to set the pointers to functions which handle 507interrupt processing in the emulator, allowing the user application to 508hook interrupts as necessary for their application. Any interrupts that 509are not hooked by the user application, and reflected and handled internally 510in the emulator via the interrupt vector table. This allows the application 511to get control when the code being emulated executes specific software 512interrupts. 513****************************************************************************/ 514void 515X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]) 516{ 517 int i; 518 519 for (i = 0; i < 256; i++) 520 _X86EMU_intrTab[i] = NULL; 521 if (funcs) { 522 for (i = 0; i < 256; i++) 523 _X86EMU_intrTab[i] = funcs[i]; 524 } 525} 526 527/**************************************************************************** 528PARAMETERS: 529int - New software interrupt to prepare for 530 531REMARKS: 532This function is used to set up the emulator state to exceute a software 533interrupt. This can be used by the user application code to allow an 534interrupt to be hooked, examined and then reflected back to the emulator 535so that the code in the emulator will continue processing the software 536interrupt as per normal. This essentially allows system code to actively 537hook and handle certain software interrupts as necessary. 538****************************************************************************/ 539void 540X86EMU_prepareForInt(int num) 541{ 542 push_word((u16) M.x86.R_FLG); 543 CLEAR_FLAG(F_IF); 544 CLEAR_FLAG(F_TF); 545 push_word(M.x86.R_CS); 546 M.x86.R_CS = mem_access_word(num * 4 + 2); 547 push_word(M.x86.R_IP); 548 M.x86.R_IP = mem_access_word(num * 4); 549 M.x86.intr = 0; 550} 551