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.5 2000/08/23 22:10:01 tsi Exp $ */
45 #include "x86emu/regs.h"
46 #include "x86emu/debug.h"
47 #include "x86emu/prim_ops.h"
49 #include "xf86_ansic.h"
51 /*#include <string.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 :-(((( */
64 * inline functions to do unaligned accesses
65 * from linux/include/asm-alpha/unaligned.h
69 * EGCS 1.1 knows about arbitrary unaligned loads. Define some
70 * packed structures to talk about such things with.
73 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
74 struct __una_u64
{ unsigned long x
__attribute__((packed
)); };
75 struct __una_u32
{ unsigned int x
__attribute__((packed
)); };
76 struct __una_u16
{ unsigned short x
__attribute__((packed
)); };
79 static __inline__
unsigned long ldq_u(unsigned long * r11
)
81 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
82 const struct __una_u64
*ptr
= (const struct __una_u64
*) r11
;
86 __asm__("ldq_u %0,%3\n\t"
90 :"=&r" (r1
), "=&r" (r2
)
93 "m" (*(const unsigned long *)(7+(char *) r11
)));
98 static __inline__
unsigned long ldl_u(unsigned int * r11
)
100 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
101 const struct __una_u32
*ptr
= (const struct __una_u32
*) r11
;
105 __asm__("ldq_u %0,%3\n\t"
109 :"=&r" (r1
), "=&r" (r2
)
112 "m" (*(const unsigned long *)(3+(char *) r11
)));
117 static __inline__
unsigned long ldw_u(unsigned short * r11
)
119 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
120 const struct __una_u16
*ptr
= (const struct __una_u16
*) r11
;
124 __asm__("ldq_u %0,%3\n\t"
128 :"=&r" (r1
), "=&r" (r2
)
131 "m" (*(const unsigned long *)(1+(char *) r11
)));
137 * Elemental unaligned stores
140 static __inline__
void stq_u(unsigned long r5
, unsigned long * r11
)
142 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
143 struct __una_u64
*ptr
= (struct __una_u64
*) r11
;
146 unsigned long r1
,r2
,r3
,r4
;
148 __asm__("ldq_u %3,%1\n\t"
159 "=m" (*(unsigned long *)(7+(char *) r11
)),
160 "=&r" (r1
), "=&r" (r2
), "=&r" (r3
), "=&r" (r4
)
161 :"r" (r5
), "r" (r11
));
165 static __inline__
void stl_u(unsigned long r5
, unsigned int * r11
)
167 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
168 struct __una_u32
*ptr
= (struct __una_u32
*) r11
;
171 unsigned long r1
,r2
,r3
,r4
;
173 __asm__("ldq_u %3,%1\n\t"
184 "=m" (*(unsigned long *)(3+(char *) r11
)),
185 "=&r" (r1
), "=&r" (r2
), "=&r" (r3
), "=&r" (r4
)
186 :"r" (r5
), "r" (r11
));
190 static __inline__
void stw_u(unsigned long r5
, unsigned short * r11
)
192 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
193 struct __una_u16
*ptr
= (struct __una_u16
*) r11
;
196 unsigned long r1
,r2
,r3
,r4
;
198 __asm__("ldq_u %3,%1\n\t"
209 "=m" (*(unsigned long *)(1+(char *) r11
)),
210 "=&r" (r1
), "=&r" (r2
), "=&r" (r3
), "=&r" (r4
)
211 :"r" (r5
), "r" (r11
));
216 /****************************************************************************
218 addr - Emulator memory address to read
221 Byte value read from emulator memory.
224 Reads a byte value from the emulator memory.
225 ****************************************************************************/
231 if (addr
> M
.mem_size
- 1) {
232 DB(printk("mem_read: address %#lx out of range!\n", addr
);)
235 val
= *(u8
*)(M
.mem_base
+ addr
);
236 DB( if (DEBUG_MEM_TRACE())
237 printk("%#08x 1 -> %#x\n", addr
, val
);)
241 /****************************************************************************
243 addr - Emulator memory address to read
246 Word value read from emulator memory.
249 Reads a word value from the emulator memory.
250 ****************************************************************************/
256 if (addr
> M
.mem_size
- 2) {
257 DB(printk("mem_read: address %#lx out of range!\n", addr
);)
260 #ifdef __BIG_ENDIAN__
262 val
= (*(u8
*)(M
.mem_base
+ addr
) |
263 (*(u8
*)(M
.mem_base
+ addr
+ 1) << 8));
267 #if defined(__alpha__) || defined(__alpha)
268 val
= ldw_u((u16
*)(M
.mem_base
+ addr
));
270 val
= *(u16
*)(M
.mem_base
+ addr
);
272 DB( if (DEBUG_MEM_TRACE())
273 printk("%#08x 2 -> %#x\n", addr
, val
);)
277 /****************************************************************************
279 addr - Emulator memory address to read
282 Long value read from emulator memory.
284 Reads a long value from the emulator memory.
285 ****************************************************************************/
291 if (addr
> M
.mem_size
- 4) {
292 DB(printk("mem_read: address %#lx out of range!\n", addr
);)
295 #ifdef __BIG_ENDIAN__
297 val
= (*(u8
*)(M
.mem_base
+ addr
+ 0) |
298 (*(u8
*)(M
.mem_base
+ addr
+ 1) << 8) |
299 (*(u8
*)(M
.mem_base
+ addr
+ 2) << 16) |
300 (*(u8
*)(M
.mem_base
+ addr
+ 3) << 24));
304 #if defined(__alpha__) || defined(__alpha)
305 val
= ldl_u((u32
*)(M
.mem_base
+ addr
));
307 val
= *(u32
*)(M
.mem_base
+ addr
);
309 DB( if (DEBUG_MEM_TRACE())
310 printk("%#08x 4 -> %#x\n", addr
, val
);)
314 /****************************************************************************
316 addr - Emulator memory address to read
320 Writes a byte value to emulator memory.
321 ****************************************************************************/
326 DB( if (DEBUG_MEM_TRACE())
327 printk("%#08x 1 <- %#x\n", addr
, val
);)
328 if (addr
> M
.mem_size
- 1) {
329 DB(printk("mem_write: address %#lx out of range!\n", addr
);)
332 *(u8
*)(M
.mem_base
+ addr
) = val
;
335 /****************************************************************************
337 addr - Emulator memory address to read
341 Writes a word value to emulator memory.
342 ****************************************************************************/
347 DB( if (DEBUG_MEM_TRACE())
348 printk("%#08x 2 <- %#x\n", addr
, val
);)
349 if (addr
> M
.mem_size
- 2) {
350 DB(printk("mem_write: address %#lx out of range!\n", addr
);)
353 #ifdef __BIG_ENDIAN__
355 *(u8
*)(M
.mem_base
+ addr
+ 0) = (val
>> 0) & 0xff;
356 *(u8
*)(M
.mem_base
+ addr
+ 1) = (val
>> 8) & 0xff;
360 #if defined(__alpha__) || defined(__alpha)
361 stw_u(val
,(u16
*)(M
.mem_base
+ addr
));
363 *(u16
*)(M
.mem_base
+ addr
) = val
;
367 /****************************************************************************
369 addr - Emulator memory address to read
373 Writes a long value to emulator memory.
374 ****************************************************************************/
379 DB( if (DEBUG_MEM_TRACE())
380 printk("%#08x 4 <- %#x\n", addr
, val
);)
381 if (addr
> M
.mem_size
- 4) {
382 DB(printk("mem_write: address %#lx out of range!\n", addr
);)
385 #ifdef __BIG_ENDIAN__
387 *(u8
*)(M
.mem_base
+ addr
+ 0) = (val
>> 0) & 0xff;
388 *(u8
*)(M
.mem_base
+ addr
+ 1) = (val
>> 8) & 0xff;
389 *(u8
*)(M
.mem_base
+ addr
+ 2) = (val
>> 16) & 0xff;
390 *(u8
*)(M
.mem_base
+ addr
+ 3) = (val
>> 24) & 0xff;
394 #if defined(__alpha__) || defined(__alpha)
395 stl_u(val
,(u32
*)(M
.mem_base
+ addr
));
397 *(u32
*)(M
.mem_base
+ addr
) = val
;
401 /****************************************************************************
403 addr - PIO address to read
407 Default PIO byte read function. Doesn't perform real inb.
408 ****************************************************************************/
409 static u8 X86API
p_inb(
412 DB( if (DEBUG_IO_TRACE())
413 printk("inb %#04x \n", addr
);)
417 /****************************************************************************
419 addr - PIO address to read
423 Default PIO word read function. Doesn't perform real inw.
424 ****************************************************************************/
425 static u16 X86API
p_inw(
428 DB( if (DEBUG_IO_TRACE())
429 printk("inw %#04x \n", addr
);)
433 /****************************************************************************
435 addr - PIO address to read
439 Default PIO long read function. Doesn't perform real inl.
440 ****************************************************************************/
441 static u32 X86API
p_inl(
444 DB( if (DEBUG_IO_TRACE())
445 printk("inl %#04x \n", addr
);)
449 /****************************************************************************
451 addr - PIO address to write
454 Default PIO byte write function. Doesn't perform real outb.
455 ****************************************************************************/
456 static void X86API
p_outb(
460 DB( if (DEBUG_IO_TRACE())
461 printk("outb %#02x -> %#04x \n", val
, addr
);)
465 /****************************************************************************
467 addr - PIO address to write
470 Default PIO word write function. Doesn't perform real outw.
471 ****************************************************************************/
472 static void X86API
p_outw(
476 DB( if (DEBUG_IO_TRACE())
477 printk("outw %#04x -> %#04x \n", val
, addr
);)
481 /****************************************************************************
483 addr - PIO address to write
486 Default PIO ;ong write function. Doesn't perform real outl.
487 ****************************************************************************/
488 static void X86API
p_outl(
492 DB( if (DEBUG_IO_TRACE())
493 printk("outl %#08x -> %#04x \n", val
, addr
);)
497 /*------------------------- Global Variables ------------------------------*/
499 u8 (X86APIP sys_rdb
)(u32 addr
) = rdb
;
500 u16 (X86APIP sys_rdw
)(u32 addr
) = rdw
;
501 u32 (X86APIP sys_rdl
)(u32 addr
) = rdl
;
502 void (X86APIP sys_wrb
)(u32 addr
,u8 val
) = wrb
;
503 void (X86APIP sys_wrw
)(u32 addr
,u16 val
) = wrw
;
504 void (X86APIP sys_wrl
)(u32 addr
,u32 val
) = wrl
;
505 u8 (X86APIP sys_inb
)(X86EMU_pioAddr addr
) = p_inb
;
506 u16 (X86APIP sys_inw
)(X86EMU_pioAddr addr
) = p_inw
;
507 u32 (X86APIP sys_inl
)(X86EMU_pioAddr addr
) = p_inl
;
508 void (X86APIP sys_outb
)(X86EMU_pioAddr addr
, u8 val
) = p_outb
;
509 void (X86APIP sys_outw
)(X86EMU_pioAddr addr
, u16 val
) = p_outw
;
510 void (X86APIP sys_outl
)(X86EMU_pioAddr addr
, u32 val
) = p_outl
;
512 /*----------------------------- Setup -------------------------------------*/
514 /****************************************************************************
516 funcs - New memory function pointers to make active
519 This function is used to set the pointers to functions which access
520 memory space, allowing the user application to override these functions
521 and hook them out as necessary for their application.
522 ****************************************************************************/
523 void X86EMU_setupMemFuncs(
524 X86EMU_memFuncs
*funcs
)
526 sys_rdb
= funcs
->rdb
;
527 sys_rdw
= funcs
->rdw
;
528 sys_rdl
= funcs
->rdl
;
529 sys_wrb
= funcs
->wrb
;
530 sys_wrw
= funcs
->wrw
;
531 sys_wrl
= funcs
->wrl
;
534 /****************************************************************************
536 funcs - New programmed I/O function pointers to make active
539 This function is used to set the pointers to functions which access
540 I/O space, allowing the user application to override these functions
541 and hook them out as necessary for their application.
542 ****************************************************************************/
543 void X86EMU_setupPioFuncs(
544 X86EMU_pioFuncs
*funcs
)
546 sys_inb
= funcs
->inb
;
547 sys_inw
= funcs
->inw
;
548 sys_inl
= funcs
->inl
;
549 sys_outb
= funcs
->outb
;
550 sys_outw
= funcs
->outw
;
551 sys_outl
= funcs
->outl
;
554 /****************************************************************************
556 funcs - New interrupt vector table to make active
559 This function is used to set the pointers to functions which handle
560 interrupt processing in the emulator, allowing the user application to
561 hook interrupts as necessary for their application. Any interrupts that
562 are not hooked by the user application, and reflected and handled internally
563 in the emulator via the interrupt vector table. This allows the application
564 to get control when the code being emulated executes specific software
566 ****************************************************************************/
567 void X86EMU_setupIntrFuncs(
568 X86EMU_intrFuncs funcs
[])
572 for (i
=0; i
< 256; i
++)
573 _X86EMU_intrTab
[i
] = NULL
;
575 for (i
= 0; i
< 256; i
++)
576 _X86EMU_intrTab
[i
] = funcs
[i
];
580 /****************************************************************************
582 int - New software interrupt to prepare for
585 This function is used to set up the emulator state to exceute a software
586 interrupt. This can be used by the user application code to allow an
587 interrupt to be hooked, examined and then reflected back to the emulator
588 so that the code in the emulator will continue processing the software
589 interrupt as per normal. This essentially allows system code to actively
590 hook and handle certain software interrupts as necessary.
591 ****************************************************************************/
592 void X86EMU_prepareForInt(
595 push_word((u16
)M
.x86
.R_FLG
);
598 push_word(M
.x86
.R_CS
);
599 M
.x86
.R_CS
= mem_access_word(num
* 4 + 2);
600 push_word(M
.x86
.R_IP
);
601 M
.x86
.R_IP
= mem_access_word(num
* 4);