1 /****************************************************************************
3 * Realmode X86 Emulator Library
5 * Copyright (C) 1996-1999 SciTech Software, Inc.
6 * Copyright (C) David Mosberger-Tang
7 * Copyright (C) 1999 Egbert Eich
9 * ========================================================================
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.
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.
29 * ========================================================================
33 * Developer: Kendall Bennett
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
41 ****************************************************************************/
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
55 /* Define some packed structures to use with unaligned accesses */
57 struct __una_u64 { u64 x __attribute__((packed)); };
58 struct __una_u32 { u32 x __attribute__((packed)); };
59 struct __una_u16 { u16 x __attribute__((packed)); };
61 /* Elemental unaligned loads */
63 static __inline__ u64 ldq_u(u64 *p)
65 const struct __una_u64 *ptr = (const struct __una_u64 *) p;
69 static __inline__ u32 ldl_u(u32 *p)
71 const struct __una_u32 *ptr = (const struct __una_u32 *) p;
75 static __inline__ u16 ldw_u(u16 *p)
77 const struct __una_u16 *ptr = (const struct __una_u16 *) p;
81 /* Elemental unaligned stores */
83 static __inline__ void stq_u(u64 val, u64 *p)
85 struct __una_u64 *ptr = (struct __una_u64 *) p;
89 static __inline__ void stl_u(u32 val, u32 *p)
91 struct __una_u32 *ptr = (struct __una_u32 *) p;
95 static __inline__ void stw_u(u16 val, u16 *p)
97 struct __una_u16 *ptr = (struct __una_u16 *) p;
100 # else /* !__GNUC__ */
102 static __inline__ u64 ldq_u(u64 *p)
105 memmove(&ret, p, sizeof(*p));
109 static __inline__ u32 ldl_u(u32 *p)
112 memmove(&ret, p, sizeof(*p));
116 static __inline__ u16 ldw_u(u16 *p)
119 memmove(&ret, p, sizeof(*p));
123 static __inline__ void stq_u(u64 val, u64 *p)
126 memmove(p, &tmp, sizeof(*p));
129 static __inline__ void stl_u(u32 val, u32 *p)
132 memmove(p, &tmp, sizeof(*p));
135 static __inline__ void stw_u(u16 val, u16 *p)
138 memmove(p, &tmp, sizeof(*p));
141 # endif /* __GNUC__ */
142 # endif /* NO_INLINE */
143 /*------------------------- Global Variables ------------------------------*/
145 X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */
146 X86EMU_intrFuncs _X86EMU_intrTab[256];
148 /*----------------------------- Implementation ----------------------------*/
150 /****************************************************************************
152 addr - Emulator memory address to read
155 Byte value read from emulator memory.
158 Reads a byte value from the emulator memory.
159 ****************************************************************************/
165 if (addr > M.mem_size - 1) {
166 DB(printk("mem_read: address %#lx out of range!\n", addr);)
169 val = *(u8*)(M.mem_base + addr);
170 DB( if (DEBUG_MEM_TRACE())
171 printk("%#08x 1 -> %#x\n", addr, val);)
175 /****************************************************************************
177 addr - Emulator memory address to read
180 Word value read from emulator memory.
183 Reads a word value from the emulator memory.
184 ****************************************************************************/
190 if (addr > M.mem_size - 2) {
191 DB(printk("mem_read: address %#lx out of range!\n", addr);)
194 #ifdef __BIG_ENDIAN__
196 val = (*(u8*)(M.mem_base + addr) |
197 (*(u8*)(M.mem_base + addr + 1) << 8));
201 val = ldw_u((u16*)(M.mem_base + addr));
202 DB( if (DEBUG_MEM_TRACE())
203 printk("%#08x 2 -> %#x\n", addr, val);)
207 /****************************************************************************
209 addr - Emulator memory address to read
212 Long value read from emulator memory.
214 Reads a long value from the emulator memory.
215 ****************************************************************************/
221 if (addr > M.mem_size - 4) {
222 DB(printk("mem_read: address %#lx out of range!\n", addr);)
225 #ifdef __BIG_ENDIAN__
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));
234 val = ldl_u((u32*)(M.mem_base + addr));
235 DB( if (DEBUG_MEM_TRACE())
236 printk("%#08x 4 -> %#x\n", addr, val);)
240 /****************************************************************************
242 addr - Emulator memory address to read
246 Writes a byte value to emulator memory.
247 ****************************************************************************/
252 DB( 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);)
258 *(u8*)(M.mem_base + addr) = val;
261 /****************************************************************************
263 addr - Emulator memory address to read
267 Writes a word value to emulator memory.
268 ****************************************************************************/
273 DB( 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);)
279 #ifdef __BIG_ENDIAN__
281 *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff;
282 *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff;
286 stw_u(val,(u16*)(M.mem_base + addr));
289 /****************************************************************************
291 addr - Emulator memory address to read
295 Writes a long value to emulator memory.
296 ****************************************************************************/
301 DB( 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);)
307 #ifdef __BIG_ENDIAN__
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;
316 stl_u(val,(u32*)(M.mem_base + addr));
319 /****************************************************************************
321 addr - PIO address to read
325 Default PIO byte read function. Doesn't perform real inb.
326 ****************************************************************************/
327 static u8 X86API p_inb(
330 DB( if (DEBUG_IO_TRACE())
331 printk("inb %#04x \n", addr);)
335 /****************************************************************************
337 addr - PIO address to read
341 Default PIO word read function. Doesn't perform real inw.
342 ****************************************************************************/
343 static u16 X86API p_inw(
346 DB( if (DEBUG_IO_TRACE())
347 printk("inw %#04x \n", addr);)
351 /****************************************************************************
353 addr - PIO address to read
357 Default PIO long read function. Doesn't perform real inl.
358 ****************************************************************************/
359 static u32 X86API p_inl(
362 DB( if (DEBUG_IO_TRACE())
363 printk("inl %#04x \n", addr);)
367 /****************************************************************************
369 addr - PIO address to write
372 Default PIO byte write function. Doesn't perform real outb.
373 ****************************************************************************/
374 static void X86API p_outb(
378 DB( if (DEBUG_IO_TRACE())
379 printk("outb %#02x -> %#04x \n", val, addr);)
383 /****************************************************************************
385 addr - PIO address to write
388 Default PIO word write function. Doesn't perform real outw.
389 ****************************************************************************/
390 static void X86API p_outw(
394 DB( if (DEBUG_IO_TRACE())
395 printk("outw %#04x -> %#04x \n", val, addr);)
399 /****************************************************************************
401 addr - PIO address to write
404 Default PIO ;ong write function. Doesn't perform real outl.
405 ****************************************************************************/
406 static void X86API p_outl(
410 DB( if (DEBUG_IO_TRACE())
411 printk("outl %#08x -> %#04x \n", val, addr);)
415 /*------------------------- Global Variables ------------------------------*/
417 u8 (X86APIP sys_rdb)(u32 addr) = rdb;
418 u16 (X86APIP sys_rdw)(u32 addr) = rdw;
419 u32 (X86APIP sys_rdl)(u32 addr) = rdl;
420 void (X86APIP sys_wrb)(u32 addr,u8 val) = wrb;
421 void (X86APIP sys_wrw)(u32 addr,u16 val) = wrw;
422 void (X86APIP sys_wrl)(u32 addr,u32 val) = wrl;
423 u8 (X86APIP sys_inb)(X86EMU_pioAddr addr) = p_inb;
424 u16 (X86APIP sys_inw)(X86EMU_pioAddr addr) = p_inw;
425 u32 (X86APIP sys_inl)(X86EMU_pioAddr addr) = p_inl;
426 void (X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) = p_outb;
427 void (X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val) = p_outw;
428 void (X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val) = p_outl;
430 /*----------------------------- Setup -------------------------------------*/
432 /****************************************************************************
434 funcs - New memory function pointers to make active
437 This function is used to set the pointers to functions which access
438 memory space, allowing the user application to override these functions
439 and hook them out as necessary for their application.
440 ****************************************************************************/
441 void X86EMU_setupMemFuncs(
442 X86EMU_memFuncs *funcs)
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;
452 /****************************************************************************
454 funcs - New programmed I/O function pointers to make active
457 This function is used to set the pointers to functions which access
458 I/O space, allowing the user application to override these functions
459 and hook them out as necessary for their application.
460 ****************************************************************************/
461 void X86EMU_setupPioFuncs(
462 X86EMU_pioFuncs *funcs)
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;
472 /****************************************************************************
474 funcs - New interrupt vector table to make active
477 This function is used to set the pointers to functions which handle
478 interrupt processing in the emulator, allowing the user application to
479 hook interrupts as necessary for their application. Any interrupts that
480 are not hooked by the user application, and reflected and handled internally
481 in the emulator via the interrupt vector table. This allows the application
482 to get control when the code being emulated executes specific software
484 ****************************************************************************/
485 void X86EMU_setupIntrFuncs(
486 X86EMU_intrFuncs funcs[])
490 for (i=0; i < 256; i++)
491 _X86EMU_intrTab[i] = NULL;
493 for (i = 0; i < 256; i++)
494 _X86EMU_intrTab[i] = funcs[i];
498 /****************************************************************************
500 int - New software interrupt to prepare for
503 This function is used to set up the emulator state to exceute a software
504 interrupt. This can be used by the user application code to allow an
505 interrupt to be hooked, examined and then reflected back to the emulator
506 so that the code in the emulator will continue processing the software
507 interrupt as per normal. This essentially allows system code to actively
508 hook and handle certain software interrupts as necessary.
509 ****************************************************************************/
510 void X86EMU_prepareForInt(
513 push_word((u16)M.x86.R_FLG);
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);