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
54 /* Define some packed structures to use with unaligned accesses */
57 u64 x
__attribute__ ((packed
));
60 u32 x
__attribute__ ((packed
));
63 u16 x
__attribute__ ((packed
));
66 /* Elemental unaligned loads */
71 const struct __una_u64
*ptr
= (const struct __una_u64
*) p
;
79 const struct __una_u32
*ptr
= (const struct __una_u32
*) p
;
87 const struct __una_u16
*ptr
= (const struct __una_u16
*) p
;
92 /* Elemental unaligned stores */
94 static __inline__
void
95 stq_u(u64 val
, u64
* p
)
97 struct __una_u64
*ptr
= (struct __una_u64
*) p
;
102 static __inline__
void
103 stl_u(u32 val
, u32
* p
)
105 struct __una_u32
*ptr
= (struct __una_u32
*) p
;
110 static __inline__
void
111 stw_u(u16 val
, u16
* p
)
113 struct __una_u16
*ptr
= (struct __una_u16
*) p
;
117 #else /* !__GNUC__ */
119 static __inline__ u64
124 memmove(&ret
, p
, sizeof(*p
));
128 static __inline__ u32
133 memmove(&ret
, p
, sizeof(*p
));
137 static __inline__ u16
142 memmove(&ret
, p
, sizeof(*p
));
146 static __inline__
void
147 stq_u(u64 val
, u64
* p
)
151 memmove(p
, &tmp
, sizeof(*p
));
154 static __inline__
void
155 stl_u(u32 val
, u32
* p
)
159 memmove(p
, &tmp
, sizeof(*p
));
162 static __inline__
void
163 stw_u(u16 val
, u16
* p
)
167 memmove(p
, &tmp
, sizeof(*p
));
170 #endif /* __GNUC__ */
171 /*------------------------- Global Variables ------------------------------*/
173 X86EMU_sysEnv _X86EMU_env
; /* Global emulator machine state */
174 X86EMU_intrFuncs _X86EMU_intrTab
[256];
176 /*----------------------------- Implementation ----------------------------*/
178 /****************************************************************************
180 addr - Emulator memory address to read
183 Byte value read from emulator memory.
186 Reads a byte value from the emulator memory.
187 ****************************************************************************/
193 if (addr
> M
.mem_size
- 1) {
194 DB(printk("mem_read: address %#x out of range!\n", addr
);
198 val
= *(u8
*) (M
.mem_base
+ addr
);
199 DB(if (DEBUG_MEM_TRACE())
200 printk("%#08x 1 -> %#x\n", addr
, val
);)
204 /****************************************************************************
206 addr - Emulator memory address to read
209 Word value read from emulator memory.
212 Reads a word value from the emulator memory.
213 ****************************************************************************/
219 if (addr
> M
.mem_size
- 2) {
220 DB(printk("mem_read: address %#x out of range!\n", addr
);
224 #ifdef __BIG_ENDIAN__
226 val
= (*(u8
*) (M
.mem_base
+ addr
) |
227 (*(u8
*) (M
.mem_base
+ addr
+ 1) << 8));
231 val
= ldw_u((u16
*) (M
.mem_base
+ addr
));
232 DB(if (DEBUG_MEM_TRACE())
233 printk("%#08x 2 -> %#x\n", addr
, val
);)
237 /****************************************************************************
239 addr - Emulator memory address to read
242 Long value read from emulator memory.
244 Reads a long value from the emulator memory.
245 ****************************************************************************/
251 if (addr
> M
.mem_size
- 4) {
252 DB(printk("mem_read: address %#x out of range!\n", addr
);
256 #ifdef __BIG_ENDIAN__
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));
265 val
= ldl_u((u32
*) (M
.mem_base
+ addr
));
266 DB(if (DEBUG_MEM_TRACE())
267 printk("%#08x 4 -> %#x\n", addr
, val
);)
271 /****************************************************************************
273 addr - Emulator memory address to read
277 Writes a byte value to emulator memory.
278 ****************************************************************************/
280 wrb(u32 addr
, u8 val
)
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
);
289 *(u8
*) (M
.mem_base
+ addr
) = val
;
292 /****************************************************************************
294 addr - Emulator memory address to read
298 Writes a word value to emulator memory.
299 ****************************************************************************/
301 wrw(u32 addr
, u16 val
)
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
);
310 #ifdef __BIG_ENDIAN__
312 *(u8
*) (M
.mem_base
+ addr
+ 0) = (val
>> 0) & 0xff;
313 *(u8
*) (M
.mem_base
+ addr
+ 1) = (val
>> 8) & 0xff;
317 stw_u(val
, (u16
*) (M
.mem_base
+ addr
));
320 /****************************************************************************
322 addr - Emulator memory address to read
326 Writes a long value to emulator memory.
327 ****************************************************************************/
329 wrl(u32 addr
, u32 val
)
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
);
338 #ifdef __BIG_ENDIAN__
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;
347 stl_u(val
, (u32
*) (M
.mem_base
+ addr
));
350 /****************************************************************************
352 addr - PIO address to read
356 Default PIO byte read function. Doesn't perform real inb.
357 ****************************************************************************/
359 p_inb(X86EMU_pioAddr addr
)
361 DB(if (DEBUG_IO_TRACE())
362 printk("inb %#04x \n", addr
);)
366 /****************************************************************************
368 addr - PIO address to read
372 Default PIO word read function. Doesn't perform real inw.
373 ****************************************************************************/
375 p_inw(X86EMU_pioAddr addr
)
377 DB(if (DEBUG_IO_TRACE())
378 printk("inw %#04x \n", addr
);)
382 /****************************************************************************
384 addr - PIO address to read
388 Default PIO long read function. Doesn't perform real inl.
389 ****************************************************************************/
391 p_inl(X86EMU_pioAddr addr
)
393 DB(if (DEBUG_IO_TRACE())
394 printk("inl %#04x \n", addr
);)
398 /****************************************************************************
400 addr - PIO address to write
403 Default PIO byte write function. Doesn't perform real outb.
404 ****************************************************************************/
406 p_outb(X86EMU_pioAddr addr
, u8 val
)
408 DB(if (DEBUG_IO_TRACE())
409 printk("outb %#02x -> %#04x \n", val
, addr
);)
413 /****************************************************************************
415 addr - PIO address to write
418 Default PIO word write function. Doesn't perform real outw.
419 ****************************************************************************/
421 p_outw(X86EMU_pioAddr addr
, u16 val
)
423 DB(if (DEBUG_IO_TRACE())
424 printk("outw %#04x -> %#04x \n", val
, addr
);)
428 /****************************************************************************
430 addr - PIO address to write
433 Default PIO ;ong write function. Doesn't perform real outl.
434 ****************************************************************************/
436 p_outl(X86EMU_pioAddr addr
, u32 val
)
438 DB(if (DEBUG_IO_TRACE())
439 printk("outl %#08x -> %#04x \n", val
, addr
);)
443 /*------------------------- Global Variables ------------------------------*/
445 u8(X86APIP sys_rdb
) (u32 addr
) = rdb
;
446 u16(X86APIP sys_rdw
) (u32 addr
) = rdw
;
447 u32(X86APIP sys_rdl
) (u32 addr
) = rdl
;
448 void (X86APIP sys_wrb
) (u32 addr
, u8 val
) = wrb
;
449 void (X86APIP sys_wrw
) (u32 addr
, u16 val
) = wrw
;
450 void (X86APIP sys_wrl
) (u32 addr
, u32 val
) = wrl
;
452 u8(X86APIP sys_inb
) (X86EMU_pioAddr addr
) = p_inb
;
453 u16(X86APIP sys_inw
) (X86EMU_pioAddr addr
) = p_inw
;
454 u32(X86APIP sys_inl
) (X86EMU_pioAddr addr
) = p_inl
;
455 void (X86APIP sys_outb
) (X86EMU_pioAddr addr
, u8 val
) = p_outb
;
456 void (X86APIP sys_outw
) (X86EMU_pioAddr addr
, u16 val
) = p_outw
;
457 void (X86APIP sys_outl
) (X86EMU_pioAddr addr
, u32 val
) = p_outl
;
459 /*----------------------------- Setup -------------------------------------*/
461 /****************************************************************************
463 funcs - New memory function pointers to make active
466 This function is used to set the pointers to functions which access
467 memory space, allowing the user application to override these functions
468 and hook them out as necessary for their application.
469 ****************************************************************************/
471 X86EMU_setupMemFuncs(X86EMU_memFuncs
* funcs
)
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
;
481 /****************************************************************************
483 funcs - New programmed I/O function pointers to make active
486 This function is used to set the pointers to functions which access
487 I/O space, allowing the user application to override these functions
488 and hook them out as necessary for their application.
489 ****************************************************************************/
491 X86EMU_setupPioFuncs(X86EMU_pioFuncs
* funcs
)
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
;
501 /****************************************************************************
503 funcs - New interrupt vector table to make active
506 This function is used to set the pointers to functions which handle
507 interrupt processing in the emulator, allowing the user application to
508 hook interrupts as necessary for their application. Any interrupts that
509 are not hooked by the user application, and reflected and handled internally
510 in the emulator via the interrupt vector table. This allows the application
511 to get control when the code being emulated executes specific software
513 ****************************************************************************/
515 X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs
[])
519 for (i
= 0; i
< 256; i
++)
520 _X86EMU_intrTab
[i
] = NULL
;
522 for (i
= 0; i
< 256; i
++)
523 _X86EMU_intrTab
[i
] = funcs
[i
];
527 /****************************************************************************
529 int - New software interrupt to prepare for
532 This function is used to set up the emulator state to exceute a software
533 interrupt. This can be used by the user application code to allow an
534 interrupt to be hooked, examined and then reflected back to the emulator
535 so that the code in the emulator will continue processing the software
536 interrupt as per normal. This essentially allows system code to actively
537 hook and handle certain software interrupts as necessary.
538 ****************************************************************************/
540 X86EMU_prepareForInt(int num
)
542 push_word((u16
) M
.x86
.R_FLG
);
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);