mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-19 11:18:28 +00:00
b3521f2e49
At present there are DEBUG options spread around the place. If you enable one and not another you can end up with an emulator that does not work, since each file can have a different view of what the registers look like. To fix this, create a global CONFIG_X86EMU_DEBUG option that keeps everything consistent. Signed-off-by: Simon Glass <sjg@chromium.org>
340 lines
9.2 KiB
C
340 lines
9.2 KiB
C
/****************************************************************************
|
|
*
|
|
* Realmode X86 Emulator Library
|
|
*
|
|
* Copyright (C) 1991-2004 SciTech Software, Inc.
|
|
* Copyright (C) David Mosberger-Tang
|
|
* Copyright (C) 1999 Egbert Eich
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
* its documentation for any purpose is hereby granted without fee,
|
|
* provided that the above copyright notice appear in all copies and that
|
|
* both that copyright notice and this permission notice appear in
|
|
* supporting documentation, and that the name of the authors not be used
|
|
* in advertising or publicity pertaining to distribution of the software
|
|
* without specific, written prior permission. The authors makes no
|
|
* representations about the suitability of this software for any purpose.
|
|
* It is provided "as is" without express or implied warranty.
|
|
*
|
|
* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
|
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Language: ANSI C
|
|
* Environment: Any
|
|
* Developer: Kendall Bennett
|
|
*
|
|
* Description: Header file for x86 register definitions.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef __X86EMU_REGS_H
|
|
#define __X86EMU_REGS_H
|
|
|
|
/*---------------------- Macros and type definitions ----------------------*/
|
|
|
|
#pragma pack(1)
|
|
|
|
/*
|
|
* General EAX, EBX, ECX, EDX type registers. Note that for
|
|
* portability, and speed, the issue of byte swapping is not addressed
|
|
* in the registers. All registers are stored in the default format
|
|
* available on the host machine. The only critical issue is that the
|
|
* registers should line up EXACTLY in the same manner as they do in
|
|
* the 386. That is:
|
|
*
|
|
* EAX & 0xff === AL
|
|
* EAX & 0xffff == AX
|
|
*
|
|
* etc. The result is that alot of the calculations can then be
|
|
* done using the native instruction set fully.
|
|
*/
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
|
|
typedef struct {
|
|
u32 e_reg;
|
|
} I32_reg_t;
|
|
|
|
typedef struct {
|
|
u16 filler0, x_reg;
|
|
} I16_reg_t;
|
|
|
|
typedef struct {
|
|
u8 filler0, filler1, h_reg, l_reg;
|
|
} I8_reg_t;
|
|
|
|
#else /* !__BIG_ENDIAN__ */
|
|
|
|
typedef struct {
|
|
u32 e_reg;
|
|
} I32_reg_t;
|
|
|
|
typedef struct {
|
|
u16 x_reg;
|
|
} I16_reg_t;
|
|
|
|
typedef struct {
|
|
u8 l_reg, h_reg;
|
|
} I8_reg_t;
|
|
|
|
#endif /* BIG_ENDIAN */
|
|
|
|
typedef union {
|
|
I32_reg_t I32_reg;
|
|
I16_reg_t I16_reg;
|
|
I8_reg_t I8_reg;
|
|
} i386_general_register;
|
|
|
|
struct i386_general_regs {
|
|
i386_general_register A, B, C, D;
|
|
};
|
|
|
|
typedef struct i386_general_regs Gen_reg_t;
|
|
|
|
struct i386_special_regs {
|
|
i386_general_register SP, BP, SI, DI, IP;
|
|
u32 FLAGS;
|
|
};
|
|
|
|
/*
|
|
* Segment registers here represent the 16 bit quantities
|
|
* CS, DS, ES, SS.
|
|
*/
|
|
|
|
#undef CS
|
|
#undef DS
|
|
#undef SS
|
|
#undef ES
|
|
#undef FS
|
|
#undef GS
|
|
|
|
struct i386_segment_regs {
|
|
u16 CS, DS, SS, ES, FS, GS;
|
|
};
|
|
|
|
/* 8 bit registers */
|
|
#define R_AH gen.A.I8_reg.h_reg
|
|
#define R_AL gen.A.I8_reg.l_reg
|
|
#define R_BH gen.B.I8_reg.h_reg
|
|
#define R_BL gen.B.I8_reg.l_reg
|
|
#define R_CH gen.C.I8_reg.h_reg
|
|
#define R_CL gen.C.I8_reg.l_reg
|
|
#define R_DH gen.D.I8_reg.h_reg
|
|
#define R_DL gen.D.I8_reg.l_reg
|
|
|
|
/* 16 bit registers */
|
|
#define R_AX gen.A.I16_reg.x_reg
|
|
#define R_BX gen.B.I16_reg.x_reg
|
|
#define R_CX gen.C.I16_reg.x_reg
|
|
#define R_DX gen.D.I16_reg.x_reg
|
|
|
|
/* 32 bit extended registers */
|
|
#define R_EAX gen.A.I32_reg.e_reg
|
|
#define R_EBX gen.B.I32_reg.e_reg
|
|
#define R_ECX gen.C.I32_reg.e_reg
|
|
#define R_EDX gen.D.I32_reg.e_reg
|
|
|
|
/* special registers */
|
|
#define R_SP spc.SP.I16_reg.x_reg
|
|
#define R_BP spc.BP.I16_reg.x_reg
|
|
#define R_SI spc.SI.I16_reg.x_reg
|
|
#define R_DI spc.DI.I16_reg.x_reg
|
|
#define R_IP spc.IP.I16_reg.x_reg
|
|
#define R_FLG spc.FLAGS
|
|
|
|
/* special registers */
|
|
#define R_SP spc.SP.I16_reg.x_reg
|
|
#define R_BP spc.BP.I16_reg.x_reg
|
|
#define R_SI spc.SI.I16_reg.x_reg
|
|
#define R_DI spc.DI.I16_reg.x_reg
|
|
#define R_IP spc.IP.I16_reg.x_reg
|
|
#define R_FLG spc.FLAGS
|
|
|
|
/* special registers */
|
|
#define R_ESP spc.SP.I32_reg.e_reg
|
|
#define R_EBP spc.BP.I32_reg.e_reg
|
|
#define R_ESI spc.SI.I32_reg.e_reg
|
|
#define R_EDI spc.DI.I32_reg.e_reg
|
|
#define R_EIP spc.IP.I32_reg.e_reg
|
|
#define R_EFLG spc.FLAGS
|
|
|
|
/* segment registers */
|
|
#define R_CS seg.CS
|
|
#define R_DS seg.DS
|
|
#define R_SS seg.SS
|
|
#define R_ES seg.ES
|
|
#define R_FS seg.FS
|
|
#define R_GS seg.GS
|
|
|
|
/* flag conditions */
|
|
#define FB_CF 0x0001 /* CARRY flag */
|
|
#define FB_PF 0x0004 /* PARITY flag */
|
|
#define FB_AF 0x0010 /* AUX flag */
|
|
#define FB_ZF 0x0040 /* ZERO flag */
|
|
#define FB_SF 0x0080 /* SIGN flag */
|
|
#define FB_TF 0x0100 /* TRAP flag */
|
|
#define FB_IF 0x0200 /* INTERRUPT ENABLE flag */
|
|
#define FB_DF 0x0400 /* DIR flag */
|
|
#define FB_OF 0x0800 /* OVERFLOW flag */
|
|
|
|
/* 80286 and above always have bit#1 set */
|
|
#define F_ALWAYS_ON (0x0002) /* flag bits always on */
|
|
|
|
/*
|
|
* Define a mask for only those flag bits we will ever pass back
|
|
* (via PUSHF)
|
|
*/
|
|
#define F_MSK (FB_CF|FB_PF|FB_AF|FB_ZF|FB_SF|FB_TF|FB_IF|FB_DF|FB_OF)
|
|
|
|
/* following bits masked in to a 16bit quantity */
|
|
|
|
#define F_CF 0x0001 /* CARRY flag */
|
|
#define F_PF 0x0004 /* PARITY flag */
|
|
#define F_AF 0x0010 /* AUX flag */
|
|
#define F_ZF 0x0040 /* ZERO flag */
|
|
#define F_SF 0x0080 /* SIGN flag */
|
|
#define F_TF 0x0100 /* TRAP flag */
|
|
#define F_IF 0x0200 /* INTERRUPT ENABLE flag */
|
|
#define F_DF 0x0400 /* DIR flag */
|
|
#define F_OF 0x0800 /* OVERFLOW flag */
|
|
|
|
#define TOGGLE_FLAG(flag) (M.x86.R_FLG ^= (flag))
|
|
#define SET_FLAG(flag) (M.x86.R_FLG |= (flag))
|
|
#define CLEAR_FLAG(flag) (M.x86.R_FLG &= ~(flag))
|
|
#define ACCESS_FLAG(flag) (M.x86.R_FLG & (flag))
|
|
#define CLEARALL_FLAG(m) (M.x86.R_FLG = 0)
|
|
|
|
#define CONDITIONAL_SET_FLAG(COND,FLAG) \
|
|
if (COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG)
|
|
|
|
#define F_PF_CALC 0x010000 /* PARITY flag has been calced */
|
|
#define F_ZF_CALC 0x020000 /* ZERO flag has been calced */
|
|
#define F_SF_CALC 0x040000 /* SIGN flag has been calced */
|
|
|
|
#define F_ALL_CALC 0xff0000 /* All have been calced */
|
|
|
|
/*
|
|
* Emulator machine state.
|
|
* Segment usage control.
|
|
*/
|
|
#define SYSMODE_SEG_DS_SS 0x00000001
|
|
#define SYSMODE_SEGOVR_CS 0x00000002
|
|
#define SYSMODE_SEGOVR_DS 0x00000004
|
|
#define SYSMODE_SEGOVR_ES 0x00000008
|
|
#define SYSMODE_SEGOVR_FS 0x00000010
|
|
#define SYSMODE_SEGOVR_GS 0x00000020
|
|
#define SYSMODE_SEGOVR_SS 0x00000040
|
|
#define SYSMODE_PREFIX_REPE 0x00000080
|
|
#define SYSMODE_PREFIX_REPNE 0x00000100
|
|
#define SYSMODE_PREFIX_DATA 0x00000200
|
|
#define SYSMODE_PREFIX_ADDR 0x00000400
|
|
#define SYSMODE_INTR_PENDING 0x10000000
|
|
#define SYSMODE_EXTRN_INTR 0x20000000
|
|
#define SYSMODE_HALTED 0x40000000
|
|
|
|
#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | \
|
|
SYSMODE_SEGOVR_CS | \
|
|
SYSMODE_SEGOVR_DS | \
|
|
SYSMODE_SEGOVR_ES | \
|
|
SYSMODE_SEGOVR_FS | \
|
|
SYSMODE_SEGOVR_GS | \
|
|
SYSMODE_SEGOVR_SS)
|
|
#define SYSMODE_CLRMASK (SYSMODE_SEG_DS_SS | \
|
|
SYSMODE_SEGOVR_CS | \
|
|
SYSMODE_SEGOVR_DS | \
|
|
SYSMODE_SEGOVR_ES | \
|
|
SYSMODE_SEGOVR_FS | \
|
|
SYSMODE_SEGOVR_GS | \
|
|
SYSMODE_SEGOVR_SS | \
|
|
SYSMODE_PREFIX_DATA | \
|
|
SYSMODE_PREFIX_ADDR)
|
|
|
|
#define INTR_SYNCH 0x1
|
|
#define INTR_ASYNCH 0x2
|
|
#define INTR_HALTED 0x4
|
|
|
|
typedef struct {
|
|
struct i386_general_regs gen;
|
|
struct i386_special_regs spc;
|
|
struct i386_segment_regs seg;
|
|
/*
|
|
* MODE contains information on:
|
|
* REPE prefix 2 bits repe,repne
|
|
* SEGMENT overrides 5 bits normal,DS,SS,CS,ES
|
|
* Delayed flag set 3 bits (zero, signed, parity)
|
|
* reserved 6 bits
|
|
* interrupt # 8 bits instruction raised interrupt
|
|
* BIOS video segregs 4 bits
|
|
* Interrupt Pending 1 bits
|
|
* Extern interrupt 1 bits
|
|
* Halted 1 bits
|
|
*/
|
|
long mode;
|
|
u8 intno;
|
|
volatile int intr; /* mask of pending interrupts */
|
|
int debug;
|
|
#ifdef CONFIG_X86EMU_DEBUG
|
|
int check;
|
|
u16 saved_ip;
|
|
u16 saved_cs;
|
|
int enc_pos;
|
|
int enc_str_pos;
|
|
char decode_buf[32]; /* encoded byte stream */
|
|
char decoded_buf[256]; /* disassembled strings */
|
|
#endif
|
|
} X86EMU_regs;
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Structure maintaining the emulator machine state.
|
|
|
|
MEMBERS:
|
|
x86 - X86 registers
|
|
mem_base - Base real mode memory for the emulator
|
|
mem_size - Size of the real mode memory block for the emulator
|
|
****************************************************************************/
|
|
#undef x86
|
|
typedef struct {
|
|
X86EMU_regs x86;
|
|
u8 *mem_base;
|
|
u32 mem_size;
|
|
void *private;
|
|
} X86EMU_sysEnv;
|
|
|
|
#pragma pack()
|
|
|
|
/*----------------------------- Global Variables --------------------------*/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" { /* Use "C" linkage when in C++ mode */
|
|
#endif
|
|
|
|
/* Global emulator machine state.
|
|
*
|
|
* We keep it global to avoid pointer dereferences in the code for speed.
|
|
*/
|
|
|
|
extern X86EMU_sysEnv _X86EMU_env;
|
|
#define M _X86EMU_env
|
|
|
|
/*-------------------------- Function Prototypes --------------------------*/
|
|
|
|
/* Function to log information at runtime */
|
|
|
|
#ifndef __KERNEL__
|
|
void printk(const char *fmt, ...);
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
} /* End of "C" linkage for C++ */
|
|
#endif
|
|
#endif /* __X86EMU_REGS_H */
|