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 ****************************************************************************/
42 /* $XFree86: xc/extras/x86emu/src/x86emu/sys.c,v 1.6 2002/09/16 18:05:18 eich Exp $ */
45 #include "x86emu/x86emui.h"
46 #include "x86emu/regs.h"
47 #include "x86emu/debug.h"
48 #include "x86emu/prim_ops.h"
50 #include "xf86_ansic.h"
54 /*------------------------- Global Variables ------------------------------*/
56 X86EMU_sysEnv _X86EMU_env
; /* Global emulator machine state */
57 X86EMU_intrFuncs _X86EMU_intrTab
[256];
59 /*----------------------------- Implementation ----------------------------*/
60 #if defined(__alpha__) || defined(__alpha)
61 /* to cope with broken egcs-1.1.2 :-(((( */
65 * inline functions to do unaligned accesses
66 * from linux/include/asm-alpha/unaligned.h
70 * EGCS 1.1 knows about arbitrary unaligned loads. Define some
71 * packed structures to talk about such things with.
74 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
75 struct __una_u64
{ unsigned long x
__attribute__((packed
)); };
76 struct __una_u32
{ unsigned int x
__attribute__((packed
)); };
77 struct __una_u16
{ unsigned short x
__attribute__((packed
)); };
80 static __inline__
unsigned long ldq_u(unsigned long * r11
)
82 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
83 const struct __una_u64
*ptr
= (const struct __una_u64
*) r11
;
87 __asm__("ldq_u %0,%3\n\t"
91 :"=&r" (r1
), "=&r" (r2
)
94 "m" (*(const unsigned long *)(7+(char *) r11
)));
99 static __inline__
unsigned long ldl_u(unsigned int * r11
)
101 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
102 const struct __una_u32
*ptr
= (const struct __una_u32
*) r11
;
106 __asm__("ldq_u %0,%3\n\t"
110 :"=&r" (r1
), "=&r" (r2
)
113 "m" (*(const unsigned long *)(3+(char *) r11
)));
118 static __inline__
unsigned long ldw_u(unsigned short * r11
)
120 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
121 const struct __una_u16
*ptr
= (const struct __una_u16
*) r11
;
125 __asm__("ldq_u %0,%3\n\t"
129 :"=&r" (r1
), "=&r" (r2
)
132 "m" (*(const unsigned long *)(1+(char *) r11
)));
138 * Elemental unaligned stores
141 static __inline__
void stq_u(unsigned long r5
, unsigned long * r11
)
143 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
144 struct __una_u64
*ptr
= (struct __una_u64
*) r11
;
147 unsigned long r1
,r2
,r3
,r4
;
149 __asm__("ldq_u %3,%1\n\t"
160 "=m" (*(unsigned long *)(7+(char *) r11
)),
161 "=&r" (r1
), "=&r" (r2
), "=&r" (r3
), "=&r" (r4
)
162 :"r" (r5
), "r" (r11
));
166 static __inline__
void stl_u(unsigned long r5
, unsigned int * r11
)
168 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
169 struct __una_u32
*ptr
= (struct __una_u32
*) r11
;
172 unsigned long r1
,r2
,r3
,r4
;
174 __asm__("ldq_u %3,%1\n\t"
185 "=m" (*(unsigned long *)(3+(char *) r11
)),
186 "=&r" (r1
), "=&r" (r2
), "=&r" (r3
), "=&r" (r4
)
187 :"r" (r5
), "r" (r11
));
191 static __inline__
void stw_u(unsigned long r5
, unsigned short * r11
)
193 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
194 struct __una_u16
*ptr
= (struct __una_u16
*) r11
;
197 unsigned long r1
,r2
,r3
,r4
;
199 __asm__("ldq_u %3,%1\n\t"
210 "=m" (*(unsigned long *)(1+(char *) r11
)),
211 "=&r" (r1
), "=&r" (r2
), "=&r" (r3
), "=&r" (r4
)
212 :"r" (r5
), "r" (r11
));
216 #elif defined(__GNUC__) && ((__GNUC__ < 3)) && \
217 (defined (__ia64__) || defined (ia64__))
220 * EGCS 1.1 knows about arbitrary unaligned loads. Define some
221 * packed structures to talk about such things with.
223 struct __una_u64
{ unsigned long x
__attribute__((packed
)); };
224 struct __una_u32
{ unsigned int x
__attribute__((packed
)); };
225 struct __una_u16
{ unsigned short x
__attribute__((packed
)); };
227 static __inline__
unsigned long
228 __uldq (const unsigned long * r11
)
230 const struct __una_u64
*ptr
= (const struct __una_u64
*) r11
;
234 static __inline__
unsigned long
235 uldl (const unsigned int * r11
)
237 const struct __una_u32
*ptr
= (const struct __una_u32
*) r11
;
241 static __inline__
unsigned long
242 uldw (const unsigned short * r11
)
244 const struct __una_u16
*ptr
= (const struct __una_u16
*) r11
;
248 static __inline__
void
249 ustq (unsigned long r5
, unsigned long * r11
)
251 struct __una_u64
*ptr
= (struct __una_u64
*) r11
;
255 static __inline__
void
256 ustl (unsigned long r5
, unsigned int * r11
)
258 struct __una_u32
*ptr
= (struct __una_u32
*) r11
;
262 static __inline__
void
263 ustw (unsigned long r5
, unsigned short * r11
)
265 struct __una_u16
*ptr
= (struct __una_u16
*) r11
;
271 /****************************************************************************
273 addr - Emulator memory address to read
276 Byte value read from emulator memory.
279 Reads a byte value from the emulator memory.
280 ****************************************************************************/
286 if (addr
> M
.mem_size
- 1) {
287 DB(printk("mem_read: address %#lx out of range!\n", addr
);)
290 val
= *(u8
*)(M
.mem_base
+ addr
);
291 DB( if (DEBUG_MEM_TRACE())
292 printk("%#08x 1 -> %#x\n", addr
, val
);)
296 /****************************************************************************
298 addr - Emulator memory address to read
301 Word value read from emulator memory.
304 Reads a word value from the emulator memory.
305 ****************************************************************************/
311 if (addr
> M
.mem_size
- 2) {
312 DB(printk("mem_read: address %#lx out of range!\n", addr
);)
315 #ifdef __BIG_ENDIAN__
317 val
= (*(u8
*)(M
.mem_base
+ addr
) |
318 (*(u8
*)(M
.mem_base
+ addr
+ 1) << 8));
322 #if defined(ALPHA_UALOADS)
323 val
= ldw_u((u16
*)(M
.mem_base
+ addr
));
324 #elif defined(IA64_UALOADS)
325 val
= uldw((u16
*)(M
.mem_base
+ addr
));
327 val
= *(u16
*)(M
.mem_base
+ addr
);
329 DB( if (DEBUG_MEM_TRACE())
330 printk("%#08x 2 -> %#x\n", addr
, val
);)
334 /****************************************************************************
336 addr - Emulator memory address to read
339 Long value read from emulator memory.
341 Reads a long value from the emulator memory.
342 ****************************************************************************/
348 if (addr
> M
.mem_size
- 4) {
349 DB(printk("mem_read: address %#lx out of range!\n", addr
);)
352 #ifdef __BIG_ENDIAN__
354 val
= (*(u8
*)(M
.mem_base
+ addr
+ 0) |
355 (*(u8
*)(M
.mem_base
+ addr
+ 1) << 8) |
356 (*(u8
*)(M
.mem_base
+ addr
+ 2) << 16) |
357 (*(u8
*)(M
.mem_base
+ addr
+ 3) << 24));
361 #if defined(ALPHA_UALOADS)
362 val
= ldl_u((u32
*)(M
.mem_base
+ addr
));
363 #elif defined(IA64_UALOADS)
364 val
= uldl((u32
*)(M
.mem_base
+ addr
));
366 val
= *(u32
*)(M
.mem_base
+ addr
);
368 DB( if (DEBUG_MEM_TRACE())
369 printk("%#08x 4 -> %#x\n", addr
, val
);)
373 /****************************************************************************
375 addr - Emulator memory address to read
379 Writes a byte value to emulator memory.
380 ****************************************************************************/
385 DB( if (DEBUG_MEM_TRACE())
386 printk("%#08x 1 <- %#x\n", addr
, val
);)
387 if (addr
> M
.mem_size
- 1) {
388 DB(printk("mem_write: address %#lx out of range!\n", addr
);)
391 *(u8
*)(M
.mem_base
+ addr
) = val
;
394 /****************************************************************************
396 addr - Emulator memory address to read
400 Writes a word value to emulator memory.
401 ****************************************************************************/
406 DB( if (DEBUG_MEM_TRACE())
407 printk("%#08x 2 <- %#x\n", addr
, val
);)
408 if (addr
> M
.mem_size
- 2) {
409 DB(printk("mem_write: address %#lx out of range!\n", addr
);)
412 #ifdef __BIG_ENDIAN__
414 *(u8
*)(M
.mem_base
+ addr
+ 0) = (val
>> 0) & 0xff;
415 *(u8
*)(M
.mem_base
+ addr
+ 1) = (val
>> 8) & 0xff;
419 #if defined(ALPHA_UALOADS)
420 stw_u(val
,(u16
*)(M
.mem_base
+ addr
));
421 #elif defined(IA64_UALOADS)
422 ustw(val
,(u16
*)(M
.mem_base
+ addr
));
424 *(u16
*)(M
.mem_base
+ addr
) = val
;
428 /****************************************************************************
430 addr - Emulator memory address to read
434 Writes a long value to emulator memory.
435 ****************************************************************************/
440 DB( if (DEBUG_MEM_TRACE())
441 printk("%#08x 4 <- %#x\n", addr
, val
);)
442 if (addr
> M
.mem_size
- 4) {
443 DB(printk("mem_write: address %#lx out of range!\n", addr
);)
446 #ifdef __BIG_ENDIAN__
448 *(u8
*)(M
.mem_base
+ addr
+ 0) = (val
>> 0) & 0xff;
449 *(u8
*)(M
.mem_base
+ addr
+ 1) = (val
>> 8) & 0xff;
450 *(u8
*)(M
.mem_base
+ addr
+ 2) = (val
>> 16) & 0xff;
451 *(u8
*)(M
.mem_base
+ addr
+ 3) = (val
>> 24) & 0xff;
455 #if defined(ALPHA_UALOADS)
456 stl_u(val
,(u32
*)(M
.mem_base
+ addr
));
457 #elif defined(IA64_UALOADS)
458 ustl(val
,(u32
*)(M
.mem_base
+ addr
));
460 *(u32
*)(M
.mem_base
+ addr
) = val
;
464 /****************************************************************************
466 addr - PIO address to read
470 Default PIO byte read function. Doesn't perform real inb.
471 ****************************************************************************/
472 static u8 X86API
p_inb(
475 DB( if (DEBUG_IO_TRACE())
476 printk("inb %#04x \n", addr
);)
480 /****************************************************************************
482 addr - PIO address to read
486 Default PIO word read function. Doesn't perform real inw.
487 ****************************************************************************/
488 static u16 X86API
p_inw(
491 DB( if (DEBUG_IO_TRACE())
492 printk("inw %#04x \n", addr
);)
496 /****************************************************************************
498 addr - PIO address to read
502 Default PIO long read function. Doesn't perform real inl.
503 ****************************************************************************/
504 static u32 X86API
p_inl(
507 DB( if (DEBUG_IO_TRACE())
508 printk("inl %#04x \n", addr
);)
512 /****************************************************************************
514 addr - PIO address to write
517 Default PIO byte write function. Doesn't perform real outb.
518 ****************************************************************************/
519 static void X86API
p_outb(
523 DB( if (DEBUG_IO_TRACE())
524 printk("outb %#02x -> %#04x \n", val
, addr
);)
528 /****************************************************************************
530 addr - PIO address to write
533 Default PIO word write function. Doesn't perform real outw.
534 ****************************************************************************/
535 static void X86API
p_outw(
539 DB( if (DEBUG_IO_TRACE())
540 printk("outw %#04x -> %#04x \n", val
, addr
);)
544 /****************************************************************************
546 addr - PIO address to write
549 Default PIO ;ong write function. Doesn't perform real outl.
550 ****************************************************************************/
551 static void X86API
p_outl(
555 DB( if (DEBUG_IO_TRACE())
556 printk("outl %#08x -> %#04x \n", val
, addr
);)
560 /*------------------------- Global Variables ------------------------------*/
562 u8 (X86APIP sys_rdb
)(u32 addr
) = rdb
;
563 u16 (X86APIP sys_rdw
)(u32 addr
) = rdw
;
564 u32 (X86APIP sys_rdl
)(u32 addr
) = rdl
;
565 void (X86APIP sys_wrb
)(u32 addr
,u8 val
) = wrb
;
566 void (X86APIP sys_wrw
)(u32 addr
,u16 val
) = wrw
;
567 void (X86APIP sys_wrl
)(u32 addr
,u32 val
) = wrl
;
568 u8 (X86APIP sys_inb
)(X86EMU_pioAddr addr
) = p_inb
;
569 u16 (X86APIP sys_inw
)(X86EMU_pioAddr addr
) = p_inw
;
570 u32 (X86APIP sys_inl
)(X86EMU_pioAddr addr
) = p_inl
;
571 void (X86APIP sys_outb
)(X86EMU_pioAddr addr
, u8 val
) = p_outb
;
572 void (X86APIP sys_outw
)(X86EMU_pioAddr addr
, u16 val
) = p_outw
;
573 void (X86APIP sys_outl
)(X86EMU_pioAddr addr
, u32 val
) = p_outl
;
575 /*----------------------------- Setup -------------------------------------*/
577 /****************************************************************************
579 funcs - New memory function pointers to make active
582 This function is used to set the pointers to functions which access
583 memory space, allowing the user application to override these functions
584 and hook them out as necessary for their application.
585 ****************************************************************************/
586 void X86EMU_setupMemFuncs(
587 X86EMU_memFuncs
*funcs
)
589 sys_rdb
= funcs
->rdb
;
590 sys_rdw
= funcs
->rdw
;
591 sys_rdl
= funcs
->rdl
;
592 sys_wrb
= funcs
->wrb
;
593 sys_wrw
= funcs
->wrw
;
594 sys_wrl
= funcs
->wrl
;
597 /****************************************************************************
599 funcs - New programmed I/O function pointers to make active
602 This function is used to set the pointers to functions which access
603 I/O space, allowing the user application to override these functions
604 and hook them out as necessary for their application.
605 ****************************************************************************/
606 void X86EMU_setupPioFuncs(
607 X86EMU_pioFuncs
*funcs
)
609 sys_inb
= funcs
->inb
;
610 sys_inw
= funcs
->inw
;
611 sys_inl
= funcs
->inl
;
612 sys_outb
= funcs
->outb
;
613 sys_outw
= funcs
->outw
;
614 sys_outl
= funcs
->outl
;
617 /****************************************************************************
619 funcs - New interrupt vector table to make active
622 This function is used to set the pointers to functions which handle
623 interrupt processing in the emulator, allowing the user application to
624 hook interrupts as necessary for their application. Any interrupts that
625 are not hooked by the user application, and reflected and handled internally
626 in the emulator via the interrupt vector table. This allows the application
627 to get control when the code being emulated executes specific software
629 ****************************************************************************/
630 void X86EMU_setupIntrFuncs(
631 X86EMU_intrFuncs funcs
[])
635 for (i
=0; i
< 256; i
++)
636 _X86EMU_intrTab
[i
] = NULL
;
638 for (i
= 0; i
< 256; i
++)
639 _X86EMU_intrTab
[i
] = funcs
[i
];
643 /****************************************************************************
645 int - New software interrupt to prepare for
648 This function is used to set up the emulator state to exceute a software
649 interrupt. This can be used by the user application code to allow an
650 interrupt to be hooked, examined and then reflected back to the emulator
651 so that the code in the emulator will continue processing the software
652 interrupt as per normal. This essentially allows system code to actively
653 hook and handle certain software interrupts as necessary.
654 ****************************************************************************/
655 void X86EMU_prepareForInt(
658 push_word((u16
)M
.x86
.R_FLG
);
661 push_word(M
.x86
.R_CS
);
662 M
.x86
.R_CS
= mem_access_word(num
* 4 + 2);
663 push_word(M
.x86
.R_IP
);
664 M
.x86
.R_IP
= mem_access_word(num
* 4);