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/regs.h"
45 #include "x86emu/debug.h"
46 #include "x86emu/prim_ops.h"
49 /*------------------------- Global Variables ------------------------------*/
51 X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */
52 X86EMU_intrFuncs _X86EMU_intrTab[256];
54 /*----------------------------- Implementation ----------------------------*/
56 /* to cope with broken egcs-1.1.2 :-(((( */
59 * inline functions to do unaligned accesses
60 * from linux/include/asm-alpha/unaligned.h
64 * EGCS 1.1 knows about arbitrary unaligned loads. Define some
65 * packed structures to talk about such things with.
68 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
69 struct __una_u64 { unsigned long x __attribute__((packed)); };
70 struct __una_u32 { unsigned int x __attribute__((packed)); };
71 struct __una_u16 { unsigned short x __attribute__((packed)); };
74 static __inline__ unsigned long ldq_u(unsigned long * r11)
76 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
77 const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
81 __asm__("ldq_u %0,%3\n\t"
85 :"=&r" (r1), "=&r" (r2)
88 "m" (*(const unsigned long *)(7+(char *) r11)));
93 static __inline__ unsigned long ldl_u(unsigned int * r11)
95 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
96 const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
100 __asm__("ldq_u %0,%3\n\t"
104 :"=&r" (r1), "=&r" (r2)
107 "m" (*(const unsigned long *)(3+(char *) r11)));
112 static __inline__ unsigned long ldw_u(unsigned short * r11)
114 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
115 const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
119 __asm__("ldq_u %0,%3\n\t"
123 :"=&r" (r1), "=&r" (r2)
126 "m" (*(const unsigned long *)(1+(char *) r11)));
132 * Elemental unaligned stores
135 static __inline__ void stq_u(unsigned long r5, unsigned long * r11)
137 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
138 struct __una_u64 *ptr = (struct __una_u64 *) r11;
141 unsigned long r1,r2,r3,r4;
143 __asm__("ldq_u %3,%1\n\t"
154 "=m" (*(unsigned long *)(7+(char *) r11)),
155 "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
156 :"r" (r5), "r" (r11));
160 static __inline__ void stl_u(unsigned long r5, unsigned int * r11)
162 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
163 struct __una_u32 *ptr = (struct __una_u32 *) r11;
166 unsigned long r1,r2,r3,r4;
168 __asm__("ldq_u %3,%1\n\t"
179 "=m" (*(unsigned long *)(3+(char *) r11)),
180 "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
181 :"r" (r5), "r" (r11));
185 static __inline__ void stw_u(unsigned long r5, unsigned short * r11)
187 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
188 struct __una_u16 *ptr = (struct __una_u16 *) r11;
191 unsigned long r1,r2,r3,r4;
193 __asm__("ldq_u %3,%1\n\t"
204 "=m" (*(unsigned long *)(1+(char *) r11)),
205 "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
206 :"r" (r5), "r" (r11));
210 #elif defined (__ia64__)
212 * EGCS 1.1 knows about arbitrary unaligned loads. Define some
213 * packed structures to talk about such things with.
215 struct __una_u64 { unsigned long x __attribute__((packed)); };
216 struct __una_u32 { unsigned int x __attribute__((packed)); };
217 struct __una_u16 { unsigned short x __attribute__((packed)); };
219 static __inline__ unsigned long
220 __uldq (const unsigned long * r11)
222 const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
226 static __inline__ unsigned long
227 uldl (const unsigned int * r11)
229 const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
233 static __inline__ unsigned long
234 uldw (const unsigned short * r11)
236 const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
240 static __inline__ void
241 ustq (unsigned long r5, unsigned long * r11)
243 struct __una_u64 *ptr = (struct __una_u64 *) r11;
247 static __inline__ void
248 ustl (unsigned long r5, unsigned int * r11)
250 struct __una_u32 *ptr = (struct __una_u32 *) r11;
254 static __inline__ void
255 ustw (unsigned long r5, unsigned short * r11)
257 struct __una_u16 *ptr = (struct __una_u16 *) r11;
263 /****************************************************************************
265 addr - Emulator memory address to read
268 Byte value read from emulator memory.
271 Reads a byte value from the emulator memory.
272 ****************************************************************************/
278 if (addr > M.mem_size - 1) {
279 DB(printk("mem_read: address %#lx out of range!\n", addr);)
282 val = *(u8*)(M.mem_base + addr);
283 DB( if (DEBUG_MEM_TRACE())
284 printk("%#08x 1 -> %#x\n", addr, val);)
288 /****************************************************************************
290 addr - Emulator memory address to read
293 Word value read from emulator memory.
296 Reads a word value from the emulator memory.
297 ****************************************************************************/
303 if (addr > M.mem_size - 2) {
304 DB(printk("mem_read: address %#lx out of range!\n", addr);)
307 #ifdef __BIG_ENDIAN__
309 val = (*(u8*)(M.mem_base + addr) |
310 (*(u8*)(M.mem_base + addr + 1) << 8));
315 val = ldw_u((u16*)(M.mem_base + addr));
316 #elif defined (__ia64__)
317 val = uldw((u16*)(M.mem_base + addr));
319 val = *(u16*)(M.mem_base + addr);
321 DB( if (DEBUG_MEM_TRACE())
322 printk("%#08x 2 -> %#x\n", addr, val);)
326 /****************************************************************************
328 addr - Emulator memory address to read
331 Long value read from emulator memory.
333 Reads a long value from the emulator memory.
334 ****************************************************************************/
340 if (addr > M.mem_size - 4) {
341 DB(printk("mem_read: address %#lx out of range!\n", addr);)
344 #ifdef __BIG_ENDIAN__
346 val = (*(u8*)(M.mem_base + addr + 0) |
347 (*(u8*)(M.mem_base + addr + 1) << 8) |
348 (*(u8*)(M.mem_base + addr + 2) << 16) |
349 (*(u8*)(M.mem_base + addr + 3) << 24));
354 val = ldl_u((u32*)(M.mem_base + addr));
355 #elif defined (__ia64__)
356 val = uldl((u32*)(M.mem_base + addr));
358 val = *(u32*)(M.mem_base + addr);
360 DB( if (DEBUG_MEM_TRACE())
361 printk("%#08x 4 -> %#x\n", addr, val);)
365 /****************************************************************************
367 addr - Emulator memory address to read
371 Writes a byte value to emulator memory.
372 ****************************************************************************/
377 DB( if (DEBUG_MEM_TRACE())
378 printk("%#08x 1 <- %#x\n", addr, val);)
379 if (addr > M.mem_size - 1) {
380 DB(printk("mem_write: address %#lx out of range!\n", addr);)
383 *(u8*)(M.mem_base + addr) = val;
386 /****************************************************************************
388 addr - Emulator memory address to read
392 Writes a word value to emulator memory.
393 ****************************************************************************/
398 DB( if (DEBUG_MEM_TRACE())
399 printk("%#08x 2 <- %#x\n", addr, val);)
400 if (addr > M.mem_size - 2) {
401 DB(printk("mem_write: address %#lx out of range!\n", addr);)
404 #ifdef __BIG_ENDIAN__
406 *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff;
407 *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff;
412 stw_u(val,(u16*)(M.mem_base + addr));
413 #elif defined (__ia64__)
414 ustw(val,(u16*)(M.mem_base + addr));
416 *(u16*)(M.mem_base + addr) = val;
420 /****************************************************************************
422 addr - Emulator memory address to read
426 Writes a long value to emulator memory.
427 ****************************************************************************/
432 DB( if (DEBUG_MEM_TRACE())
433 printk("%#08x 4 <- %#x\n", addr, val);)
434 if (addr > M.mem_size - 4) {
435 DB(printk("mem_write: address %#lx out of range!\n", addr);)
438 #ifdef __BIG_ENDIAN__
440 *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff;
441 *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff;
442 *(u8*)(M.mem_base + addr + 2) = (val >> 16) & 0xff;
443 *(u8*)(M.mem_base + addr + 3) = (val >> 24) & 0xff;
448 stl_u(val,(u32*)(M.mem_base + addr));
449 #elif defined (__ia64__)
450 ustl(val,(u32*)(M.mem_base + addr));
452 *(u32*)(M.mem_base + addr) = val;
456 /****************************************************************************
458 addr - PIO address to read
462 Default PIO byte read function. Doesn't perform real inb.
463 ****************************************************************************/
464 static u8 X86API p_inb(
467 DB( if (DEBUG_IO_TRACE())
468 printk("inb %#04x \n", addr);)
472 /****************************************************************************
474 addr - PIO address to read
478 Default PIO word read function. Doesn't perform real inw.
479 ****************************************************************************/
480 static u16 X86API p_inw(
483 DB( if (DEBUG_IO_TRACE())
484 printk("inw %#04x \n", addr);)
488 /****************************************************************************
490 addr - PIO address to read
494 Default PIO long read function. Doesn't perform real inl.
495 ****************************************************************************/
496 static u32 X86API p_inl(
499 DB( if (DEBUG_IO_TRACE())
500 printk("inl %#04x \n", addr);)
504 /****************************************************************************
506 addr - PIO address to write
509 Default PIO byte write function. Doesn't perform real outb.
510 ****************************************************************************/
511 static void X86API p_outb(
515 DB( if (DEBUG_IO_TRACE())
516 printk("outb %#02x -> %#04x \n", val, addr);)
520 /****************************************************************************
522 addr - PIO address to write
525 Default PIO word write function. Doesn't perform real outw.
526 ****************************************************************************/
527 static void X86API p_outw(
531 DB( if (DEBUG_IO_TRACE())
532 printk("outw %#04x -> %#04x \n", val, addr);)
536 /****************************************************************************
538 addr - PIO address to write
541 Default PIO ;ong write function. Doesn't perform real outl.
542 ****************************************************************************/
543 static void X86API p_outl(
547 DB( if (DEBUG_IO_TRACE())
548 printk("outl %#08x -> %#04x \n", val, addr);)
552 /*------------------------- Global Variables ------------------------------*/
554 u8 (X86APIP sys_rdb)(u32 addr) = rdb;
555 u16 (X86APIP sys_rdw)(u32 addr) = rdw;
556 u32 (X86APIP sys_rdl)(u32 addr) = rdl;
557 void (X86APIP sys_wrb)(u32 addr,u8 val) = wrb;
558 void (X86APIP sys_wrw)(u32 addr,u16 val) = wrw;
559 void (X86APIP sys_wrl)(u32 addr,u32 val) = wrl;
560 u8 (X86APIP sys_inb)(X86EMU_pioAddr addr) = p_inb;
561 u16 (X86APIP sys_inw)(X86EMU_pioAddr addr) = p_inw;
562 u32 (X86APIP sys_inl)(X86EMU_pioAddr addr) = p_inl;
563 void (X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) = p_outb;
564 void (X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val) = p_outw;
565 void (X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val) = p_outl;
567 /*----------------------------- Setup -------------------------------------*/
569 /****************************************************************************
571 funcs - New memory function pointers to make active
574 This function is used to set the pointers to functions which access
575 memory space, allowing the user application to override these functions
576 and hook them out as necessary for their application.
577 ****************************************************************************/
578 void X86EMU_setupMemFuncs(
579 X86EMU_memFuncs *funcs)
581 sys_rdb = funcs->rdb;
582 sys_rdw = funcs->rdw;
583 sys_rdl = funcs->rdl;
584 sys_wrb = funcs->wrb;
585 sys_wrw = funcs->wrw;
586 sys_wrl = funcs->wrl;
589 /****************************************************************************
591 funcs - New programmed I/O function pointers to make active
594 This function is used to set the pointers to functions which access
595 I/O space, allowing the user application to override these functions
596 and hook them out as necessary for their application.
597 ****************************************************************************/
598 void X86EMU_setupPioFuncs(
599 X86EMU_pioFuncs *funcs)
601 sys_inb = funcs->inb;
602 sys_inw = funcs->inw;
603 sys_inl = funcs->inl;
604 sys_outb = funcs->outb;
605 sys_outw = funcs->outw;
606 sys_outl = funcs->outl;
609 /****************************************************************************
611 funcs - New interrupt vector table to make active
614 This function is used to set the pointers to functions which handle
615 interrupt processing in the emulator, allowing the user application to
616 hook interrupts as necessary for their application. Any interrupts that
617 are not hooked by the user application, and reflected and handled internally
618 in the emulator via the interrupt vector table. This allows the application
619 to get control when the code being emulated executes specific software
621 ****************************************************************************/
622 void X86EMU_setupIntrFuncs(
623 X86EMU_intrFuncs funcs[])
627 for (i=0; i < 256; i++)
628 _X86EMU_intrTab[i] = NULL;
630 for (i = 0; i < 256; i++)
631 _X86EMU_intrTab[i] = funcs[i];
635 /****************************************************************************
637 int - New software interrupt to prepare for
640 This function is used to set up the emulator state to exceute a software
641 interrupt. This can be used by the user application code to allow an
642 interrupt to be hooked, examined and then reflected back to the emulator
643 so that the code in the emulator will continue processing the software
644 interrupt as per normal. This essentially allows system code to actively
645 hook and handle certain software interrupts as necessary.
646 ****************************************************************************/
647 void X86EMU_prepareForInt(
650 push_word((u16)M.x86.R_FLG);
653 push_word(M.x86.R_CS);
654 M.x86.R_CS = mem_access_word(num * 4 + 2);
655 push_word(M.x86.R_IP);
656 M.x86.R_IP = mem_access_word(num * 4);