it was reason for workaround rules already, and it's somewhat ugly:
util/x86emu is the only part of coreboot that is linked into coreboot itself that lives in util/. It's not a utility and it does not really belong where it lives. ---> svn mv util/x86emu src/devices/oprom plus necessary Makefile changes to get it building again Signed-off-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Ronald G. Minnich <rminnich@gmail.com> Acked-by: Peter Stuge <peter@stuge.se> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5228 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
committed by
Stefan Reinauer
parent
11b1eb994c
commit
859e94a304
@@ -1,25 +0,0 @@
|
||||
##
|
||||
## This file is part of the coreboot project.
|
||||
##
|
||||
## Copyright (C) 2007-2010 coresystems GmbH
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; version 2 of the License.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
##
|
||||
|
||||
obj-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86.o
|
||||
obj-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86_asm.o
|
||||
obj-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86_interrupts.o
|
||||
|
||||
subdirs-$(CONFIG_PCI_OPTION_ROM_RUN_YABEL) += x86emu
|
||||
subdirs-$(CONFIG_PCI_OPTION_ROM_RUN_YABEL) += yabel
|
@@ -1,115 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 FPU register definitions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __X86EMU_FPU_REGS_H
|
||||
#define __X86EMU_FPU_REGS_H
|
||||
|
||||
#ifdef X86_FPU_SUPPORT
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* Basic 8087 register can hold any of the following values: */
|
||||
|
||||
union x86_fpu_reg_u {
|
||||
s8 tenbytes[10];
|
||||
double dval;
|
||||
float fval;
|
||||
s16 sval;
|
||||
s32 lval;
|
||||
};
|
||||
|
||||
struct x86_fpu_reg {
|
||||
union x86_fpu_reg_u reg;
|
||||
char tag;
|
||||
};
|
||||
|
||||
/*
|
||||
* Since we are not going to worry about the problems of aliasing
|
||||
* registers, every time a register is modified, its result type is
|
||||
* set in the tag fields for that register. If some operation
|
||||
* attempts to access the type in a way inconsistent with its current
|
||||
* storage format, then we flag the operation. If common, we'll
|
||||
* attempt the conversion.
|
||||
*/
|
||||
|
||||
#define X86_FPU_VALID 0x80
|
||||
#define X86_FPU_REGTYP(r) ((r) & 0x7F)
|
||||
|
||||
#define X86_FPU_WORD 0x0
|
||||
#define X86_FPU_SHORT 0x1
|
||||
#define X86_FPU_LONG 0x2
|
||||
#define X86_FPU_FLOAT 0x3
|
||||
#define X86_FPU_DOUBLE 0x4
|
||||
#define X86_FPU_LDBL 0x5
|
||||
#define X86_FPU_BSD 0x6
|
||||
|
||||
#define X86_FPU_STKTOP 0
|
||||
|
||||
struct x86_fpu_registers {
|
||||
struct x86_fpu_reg x86_fpu_stack[8];
|
||||
int x86_fpu_flags;
|
||||
int x86_fpu_config; /* rounding modes, etc. */
|
||||
short x86_fpu_tos, x86_fpu_bos;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/*
|
||||
* There are two versions of the following macro.
|
||||
*
|
||||
* One version is for opcode D9, for which there are more than 32
|
||||
* instructions encoded in the second byte of the opcode.
|
||||
*
|
||||
* The other version, deals with all the other 7 i87 opcodes, for
|
||||
* which there are only 32 strings needed to describe the
|
||||
* instructions.
|
||||
*/
|
||||
|
||||
#endif /* X86_FPU_SUPPORT */
|
||||
|
||||
#if CONFIG_X86EMU_DEBUG
|
||||
# define DECODE_PRINTINSTR32(t,mod,rh,rl) \
|
||||
DECODE_PRINTF(t[(mod<<3)+(rh)]);
|
||||
# define DECODE_PRINTINSTR256(t,mod,rh,rl) \
|
||||
DECODE_PRINTF(t[(mod<<6)+(rh<<3)+(rl)]);
|
||||
#else
|
||||
# define DECODE_PRINTINSTR32(t,mod,rh,rl)
|
||||
# define DECODE_PRINTINSTR256(t,mod,rh,rl)
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_FPU_REGS_H */
|
@@ -1,372 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
/* $XFree86: xc/extras/x86emu/include/x86emu/regs.h,v 1.3 2001/10/28 03:32:25 tsi Exp $ */
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
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
|
||||
//phueper: for REP(E|NE) Instructions, we need to decide wether it should be using
|
||||
//the 32bit ECX register as or the 16bit CX register as count register
|
||||
#define SYSMODE_32BIT_REP 0x00000800
|
||||
#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 | \
|
||||
SYSMODE_32BIT_REP)
|
||||
|
||||
#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
|
||||
*/
|
||||
u32 mode;
|
||||
volatile int intr; /* mask of pending interrupts */
|
||||
volatile int debug;
|
||||
#if 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
|
||||
u8 intno;
|
||||
u8 __pad[3];
|
||||
} X86EMU_regs;
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Structure maintaining the emulator machine state.
|
||||
|
||||
MEMBERS:
|
||||
mem_base - Base real mode memory for the emulator
|
||||
abseg - Base for the absegment
|
||||
mem_size - Size of the real mode memory block for the emulator
|
||||
private - private data pointer
|
||||
x86 - X86 registers
|
||||
****************************************************************************/
|
||||
typedef struct {
|
||||
unsigned long mem_base;
|
||||
unsigned long mem_size;
|
||||
unsigned long abseg;
|
||||
void* private;
|
||||
X86EMU_regs x86;
|
||||
} 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
|
||||
|
||||
#define X86_EAX M.x86.R_EAX
|
||||
#define X86_EBX M.x86.R_EBX
|
||||
#define X86_ECX M.x86.R_ECX
|
||||
#define X86_EDX M.x86.R_EDX
|
||||
#define X86_ESI M.x86.R_ESI
|
||||
#define X86_EDI M.x86.R_EDI
|
||||
#define X86_EBP M.x86.R_EBP
|
||||
#define X86_EIP M.x86.R_EIP
|
||||
#define X86_ESP M.x86.R_ESP
|
||||
#define X86_EFLAGS M.x86.R_EFLG
|
||||
|
||||
#define X86_FLAGS M.x86.R_FLG
|
||||
#define X86_AX M.x86.R_AX
|
||||
#define X86_BX M.x86.R_BX
|
||||
#define X86_CX M.x86.R_CX
|
||||
#define X86_DX M.x86.R_DX
|
||||
#define X86_SI M.x86.R_SI
|
||||
#define X86_DI M.x86.R_DI
|
||||
#define X86_BP M.x86.R_BP
|
||||
#define X86_IP M.x86.R_IP
|
||||
#define X86_SP M.x86.R_SP
|
||||
#define X86_CS M.x86.R_CS
|
||||
#define X86_DS M.x86.R_DS
|
||||
#define X86_ES M.x86.R_ES
|
||||
#define X86_SS M.x86.R_SS
|
||||
#define X86_FS M.x86.R_FS
|
||||
#define X86_GS M.x86.R_GS
|
||||
|
||||
#define X86_AL M.x86.R_AL
|
||||
#define X86_BL M.x86.R_BL
|
||||
#define X86_CL M.x86.R_CL
|
||||
#define X86_DL M.x86.R_DL
|
||||
|
||||
#define X86_AH M.x86.R_AH
|
||||
#define X86_BH M.x86.R_BH
|
||||
#define X86_CH M.x86.R_CH
|
||||
#define X86_DH M.x86.R_DH
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of "C" linkage for C++ */
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_REGS_H */
|
@@ -1,89 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 emulator type definitions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* $XFree86: xc/extras/x86emu/include/x86emu/types.h,v 1.4 2000/09/26 15:56:44 tsi Exp $ */
|
||||
|
||||
#ifndef __X86EMU_TYPES_H
|
||||
#define __X86EMU_TYPES_H
|
||||
|
||||
//#ifndef IN_MODULE
|
||||
//#include <sys/types.h>
|
||||
//#endif
|
||||
|
||||
/*
|
||||
* The following kludge is an attempt to work around typedef conflicts with
|
||||
* <sys/types.h>.
|
||||
*/
|
||||
#define u8 x86emuu8
|
||||
#define u16 x86emuu16
|
||||
#define u32 x86emuu32
|
||||
#define u64 x86emuu64
|
||||
#define s8 x86emus8
|
||||
#define s16 x86emus16
|
||||
#define s32 x86emus32
|
||||
#define s64 x86emus64
|
||||
#define uint x86emuuint
|
||||
#define sint x86emusint
|
||||
|
||||
/*---------------------- Macros and type definitions ----------------------*/
|
||||
|
||||
/* Currently only for Linux/32bit */
|
||||
#if defined(__GNUC__) && !defined(NO_LONG_LONG)
|
||||
#define __HAS_LONG_LONG__
|
||||
#endif
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
#ifdef __HAS_LONG_LONG__
|
||||
typedef unsigned long long u64;
|
||||
#endif
|
||||
|
||||
typedef signed char s8;
|
||||
typedef signed short s16;
|
||||
typedef signed int s32;
|
||||
#ifdef __HAS_LONG_LONG__
|
||||
typedef signed long long s64;
|
||||
#endif
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef signed int sint;
|
||||
|
||||
typedef u16 X86EMU_pioAddr;
|
||||
|
||||
#endif /* __X86EMU_TYPES_H */
|
@@ -1,197 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 public specific functions.
|
||||
* Any application linking against us should only
|
||||
* include this header
|
||||
*
|
||||
****************************************************************************/
|
||||
/* $XFree86: xc/extras/x86emu/include/x86emu.h,v 1.2 2000/11/21 23:10:25 tsi Exp $ */
|
||||
|
||||
#ifndef __X86EMU_X86EMU_H
|
||||
#define __X86EMU_X86EMU_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <console/console.h>
|
||||
#if CONFIG_X86EMU_DEBUG
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#define X86API
|
||||
#define X86APIP *
|
||||
#include "regs.h"
|
||||
|
||||
/*---------------------- Macros and type definitions ----------------------*/
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Data structure containing ponters to programmed I/O functions used by the
|
||||
emulator. This is used so that the user program can hook all programmed
|
||||
I/O for the emulator to handled as necessary by the user program. By
|
||||
default the emulator contains simple functions that do not do access the
|
||||
hardware in any way. To allow the emualtor access the hardware, you will
|
||||
need to override the programmed I/O functions using the X86EMU_setupPioFuncs
|
||||
function.
|
||||
|
||||
HEADER:
|
||||
x86emu.h
|
||||
|
||||
MEMBERS:
|
||||
inb - Function to read a byte from an I/O port
|
||||
inw - Function to read a word from an I/O port
|
||||
inl - Function to read a dword from an I/O port
|
||||
outb - Function to write a byte to an I/O port
|
||||
outw - Function to write a word to an I/O port
|
||||
outl - Function to write a dword to an I/O port
|
||||
****************************************************************************/
|
||||
typedef struct {
|
||||
u8 (X86APIP inb)(X86EMU_pioAddr addr);
|
||||
u16 (X86APIP inw)(X86EMU_pioAddr addr);
|
||||
u32 (X86APIP inl)(X86EMU_pioAddr addr);
|
||||
void (X86APIP outb)(X86EMU_pioAddr addr, u8 val);
|
||||
void (X86APIP outw)(X86EMU_pioAddr addr, u16 val);
|
||||
void (X86APIP outl)(X86EMU_pioAddr addr, u32 val);
|
||||
} X86EMU_pioFuncs;
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Data structure containing ponters to memory access functions used by the
|
||||
emulator. This is used so that the user program can hook all memory
|
||||
access functions as necessary for the emulator. By default the emulator
|
||||
contains simple functions that only access the internal memory of the
|
||||
emulator. If you need specialised functions to handle access to different
|
||||
types of memory (ie: hardware framebuffer accesses and BIOS memory access
|
||||
etc), you will need to override this using the X86EMU_setupMemFuncs
|
||||
function.
|
||||
|
||||
HEADER:
|
||||
x86emu.h
|
||||
|
||||
MEMBERS:
|
||||
rdb - Function to read a byte from an address
|
||||
rdw - Function to read a word from an address
|
||||
rdl - Function to read a dword from an address
|
||||
wrb - Function to write a byte to an address
|
||||
wrw - Function to write a word to an address
|
||||
wrl - Function to write a dword to an address
|
||||
****************************************************************************/
|
||||
typedef struct {
|
||||
u8 (X86APIP rdb)(u32 addr);
|
||||
u16 (X86APIP rdw)(u32 addr);
|
||||
u32 (X86APIP rdl)(u32 addr);
|
||||
void (X86APIP wrb)(u32 addr, u8 val);
|
||||
void (X86APIP wrw)(u32 addr, u16 val);
|
||||
void (X86APIP wrl)(u32 addr, u32 val);
|
||||
} X86EMU_memFuncs;
|
||||
|
||||
/****************************************************************************
|
||||
Here are the default memory read and write
|
||||
function in case they are needed as fallbacks.
|
||||
***************************************************************************/
|
||||
extern u8 X86API rdb(u32 addr);
|
||||
extern u16 X86API rdw(u32 addr);
|
||||
extern u32 X86API rdl(u32 addr);
|
||||
extern void X86API wrb(u32 addr, u8 val);
|
||||
extern void X86API wrw(u32 addr, u16 val);
|
||||
extern void X86API wrl(u32 addr, u32 val);
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/*--------------------- type definitions -----------------------------------*/
|
||||
|
||||
typedef void (X86APIP X86EMU_intrFuncs)(int num);
|
||||
extern X86EMU_intrFuncs _X86EMU_intrTab[256];
|
||||
|
||||
/*-------------------------- Function Prototypes --------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Use "C" linkage when in C++ mode */
|
||||
#endif
|
||||
|
||||
void X86EMU_setupMemFuncs(X86EMU_memFuncs *funcs);
|
||||
void X86EMU_setupPioFuncs(X86EMU_pioFuncs *funcs);
|
||||
void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]);
|
||||
void X86EMU_prepareForInt(int num);
|
||||
|
||||
void X86EMU_setMemBase(void *base, size_t size);
|
||||
|
||||
/* decode.c */
|
||||
|
||||
void X86EMU_exec(void);
|
||||
void X86EMU_halt_sys(void);
|
||||
|
||||
#if CONFIG_X86EMU_DEBUG
|
||||
#define HALT_SYS() \
|
||||
printf("halt_sys: in %s\n", __func__); \
|
||||
X86EMU_halt_sys();
|
||||
#else
|
||||
#define HALT_SYS() X86EMU_halt_sys()
|
||||
#endif
|
||||
|
||||
/* Debug options */
|
||||
|
||||
#define DEBUG_DECODE_F 0x000001 /* print decoded instruction */
|
||||
#define DEBUG_TRACE_F 0x000002 /* dump regs before/after execution */
|
||||
#define DEBUG_STEP_F 0x000004
|
||||
#define DEBUG_DISASSEMBLE_F 0x000008
|
||||
#define DEBUG_BREAK_F 0x000010
|
||||
#define DEBUG_SVC_F 0x000020
|
||||
#define DEBUG_FS_F 0x000080
|
||||
#define DEBUG_PROC_F 0x000100
|
||||
#define DEBUG_SYSINT_F 0x000200 /* bios system interrupts. */
|
||||
#define DEBUG_TRACECALL_F 0x000400
|
||||
#define DEBUG_INSTRUMENT_F 0x000800
|
||||
#define DEBUG_MEM_TRACE_F 0x001000
|
||||
#define DEBUG_IO_TRACE_F 0x002000
|
||||
#define DEBUG_TRACECALL_REGS_F 0x004000
|
||||
#define DEBUG_DECODE_NOPRINT_F 0x008000
|
||||
#define DEBUG_SAVE_IP_CS_F 0x010000
|
||||
#define DEBUG_TRACEJMP_F 0x020000
|
||||
#define DEBUG_TRACEJMP_REGS_F 0x040000
|
||||
#define DEBUG_SYS_F (DEBUG_SVC_F|DEBUG_FS_F|DEBUG_PROC_F)
|
||||
|
||||
void X86EMU_trace_regs(void);
|
||||
void X86EMU_trace_xregs(void);
|
||||
void X86EMU_dump_memory(u16 seg, u16 off, u32 amt);
|
||||
int X86EMU_trace_on(void);
|
||||
int X86EMU_trace_off(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of "C" linkage for C++ */
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_X86EMU_H */
|
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <device/pci.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch/io.h>
|
||||
#include <arch/registers.h>
|
||||
#include <console/console.h>
|
||||
#include <arch/interrupt.h>
|
||||
|
||||
#define REALMODE_BASE ((void *)0x600)
|
||||
|
||||
struct realmode_idt {
|
||||
u16 offset, cs;
|
||||
};
|
||||
|
||||
void x86_exception(struct eregs *info);
|
||||
|
||||
extern unsigned char __idt_handler, __idt_handler_size;
|
||||
extern unsigned char __realmode_code, __realmode_code_size;
|
||||
extern unsigned char __run_optionrom, __run_interrupt;
|
||||
|
||||
void (*run_optionrom)(u32 devfn) __attribute__((regparm(0))) = (void *)&__run_optionrom;
|
||||
void (*vga_enable_console)(void) __attribute__((regparm(0))) = (void *)&__run_interrupt;
|
||||
|
||||
int (*intXX_handler[256])(struct eregs *regs) = { NULL };
|
||||
|
||||
static int intXX_exception_handler(struct eregs *regs)
|
||||
{
|
||||
printk(BIOS_INFO, "Oops, exception %d while executing option rom\n",
|
||||
regs->vector);
|
||||
x86_exception(regs); // Call coreboot exception handler
|
||||
|
||||
return 0; // Never returns?
|
||||
}
|
||||
|
||||
static int intXX_unknown_handler(struct eregs *regs)
|
||||
{
|
||||
printk(BIOS_INFO, "Unsupported software interrupt #0x%x\n",
|
||||
regs->vector);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* setup interrupt handlers for mainboard */
|
||||
void mainboard_interrupt_handlers(int intXX, void *intXX_func)
|
||||
{
|
||||
intXX_handler[intXX] = intXX_func;
|
||||
}
|
||||
|
||||
int int12_handler(struct eregs *regs);
|
||||
int int15_handler(struct eregs *regs);
|
||||
int int1a_handler(struct eregs *regs);
|
||||
|
||||
static void setup_interrupt_handlers(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* The first 16 intXX functions are not BIOS services,
|
||||
* but the CPU-generated exceptions ("hardware interrupts")
|
||||
*/
|
||||
for (i = 0; i < 0x10; i++)
|
||||
intXX_handler[i] = &intXX_exception_handler;
|
||||
|
||||
/* Mark all other intXX calls as unknown first */
|
||||
for (i = 0x10; i < 0x100; i++)
|
||||
{
|
||||
/* If the mainboard_interrupt_handler isn't called first.
|
||||
*/
|
||||
if(!intXX_handler[i])
|
||||
{
|
||||
/* Now set the default functions that are actually
|
||||
* needed to initialize the option roms. This is very
|
||||
* slick, as it allows us to implement mainboard specific
|
||||
* interrupt handlers, such as the int15
|
||||
*/
|
||||
switch (i) {
|
||||
case 0x12:
|
||||
intXX_handler[0x12] = &int12_handler;
|
||||
break;
|
||||
case 0x15:
|
||||
intXX_handler[0x15] = &int15_handler;
|
||||
break;
|
||||
case 0x1a:
|
||||
intXX_handler[0x1a] = &int1a_handler;
|
||||
break;
|
||||
default:
|
||||
intXX_handler[i] = &intXX_unknown_handler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write_idt_stub(void *target, u8 intnum)
|
||||
{
|
||||
unsigned char *codeptr;
|
||||
codeptr = (unsigned char *) target;
|
||||
memcpy(codeptr, &__idt_handler, (size_t)&__idt_handler_size);
|
||||
codeptr[3] = intnum; /* modify int# in the code stub. */
|
||||
}
|
||||
|
||||
static void setup_realmode_idt(void)
|
||||
{
|
||||
struct realmode_idt *idts = (struct realmode_idt *) 0;
|
||||
int i;
|
||||
|
||||
/* Copy IDT stub code for each interrupt. This might seem wasteful
|
||||
* but it is really simple
|
||||
*/
|
||||
for (i = 0; i < 256; i++) {
|
||||
idts[i].cs = 0;
|
||||
idts[i].offset = 0x1000 + (i * (u32)&__idt_handler_size);
|
||||
write_idt_stub((void *)((u32 )idts[i].offset), i);
|
||||
}
|
||||
|
||||
/* Many option ROMs use the hard coded interrupt entry points in the
|
||||
* system bios. So install them at the known locations.
|
||||
* Only need int10 so far.
|
||||
*/
|
||||
|
||||
/* int42 is the relocated int10 */
|
||||
write_idt_stub((void *)0xff065, 0x42);
|
||||
}
|
||||
|
||||
void run_bios(struct device *dev, unsigned long addr)
|
||||
{
|
||||
/* clear vga bios data area */
|
||||
memset((void *)0x400, 0, 0x200);
|
||||
|
||||
/* Set up C interrupt handlers */
|
||||
setup_interrupt_handlers();
|
||||
|
||||
/* Setting up realmode IDT */
|
||||
setup_realmode_idt();
|
||||
|
||||
memcpy(REALMODE_BASE, &__realmode_code, (size_t)&__realmode_code_size);
|
||||
printk(BIOS_SPEW, "Real mode stub @%p: %d bytes\n", REALMODE_BASE,
|
||||
(u32)&__realmode_code_size);
|
||||
|
||||
printk(BIOS_DEBUG, "Calling Option ROM...\n");
|
||||
run_optionrom((dev->bus->secondary << 8) | dev->path.pci.devfn);
|
||||
printk(BIOS_DEBUG, "... Option ROM returned.\n");
|
||||
}
|
||||
|
||||
int __attribute__((regparm(0))) interrupt_handler(u32 intnumber,
|
||||
u32 gsfs, u32 dses,
|
||||
u32 edi, u32 esi,
|
||||
u32 ebp, u32 esp,
|
||||
u32 ebx, u32 edx,
|
||||
u32 ecx, u32 eax,
|
||||
u32 cs_ip, u16 stackflags);
|
||||
|
||||
int __attribute__((regparm(0))) interrupt_handler(u32 intnumber,
|
||||
u32 gsfs, u32 dses,
|
||||
u32 edi, u32 esi,
|
||||
u32 ebp, u32 esp,
|
||||
u32 ebx, u32 edx,
|
||||
u32 ecx, u32 eax,
|
||||
u32 cs_ip, u16 stackflags)
|
||||
{
|
||||
u32 ip;
|
||||
u32 cs;
|
||||
u32 flags;
|
||||
int ret = -1;
|
||||
struct eregs reg_info;
|
||||
|
||||
ip = cs_ip & 0xffff;
|
||||
cs = cs_ip >> 16;
|
||||
flags = stackflags;
|
||||
|
||||
printk(BIOS_DEBUG, "oprom: INT# 0x%x\n", intnumber);
|
||||
printk(BIOS_DEBUG, "oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n",
|
||||
eax, ebx, ecx, edx);
|
||||
printk(BIOS_DEBUG, "oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n",
|
||||
ebp, esp, edi, esi);
|
||||
printk(BIOS_DEBUG, "oprom: ip: %04x cs: %04x flags: %08x\n",
|
||||
ip, cs, flags);
|
||||
|
||||
// Fetch arguments from the stack and put them into
|
||||
// a structure that we want to pass on to our sub interrupt
|
||||
// handlers.
|
||||
reg_info = (struct eregs) {
|
||||
.eax=eax,
|
||||
.ecx=ecx,
|
||||
.edx=edx,
|
||||
.ebx=ebx,
|
||||
.esp=esp,
|
||||
.ebp=ebp,
|
||||
.esi=esi,
|
||||
.edi=edi,
|
||||
.vector=intnumber,
|
||||
.error_code=0, // ??
|
||||
.eip=ip,
|
||||
.cs=cs,
|
||||
.eflags=flags // ??
|
||||
};
|
||||
|
||||
// Call the interrupt handler for this int#
|
||||
ret = intXX_handler[intnumber](®_info);
|
||||
|
||||
// Put registers back on the stack. The assembler code
|
||||
// will later pop them.
|
||||
// What happens here is that we force (volatile!) changing
|
||||
// the values of the parameters of this function. We do this
|
||||
// because we know that they stay alive on the stack after
|
||||
// we leave this function. Don't say this is bollocks.
|
||||
*(volatile u32 *)&eax = reg_info.eax;
|
||||
*(volatile u32 *)&ecx = reg_info.ecx;
|
||||
*(volatile u32 *)&edx = reg_info.edx;
|
||||
*(volatile u32 *)&ebx = reg_info.ebx;
|
||||
*(volatile u32 *)&esi = reg_info.esi;
|
||||
*(volatile u32 *)&edi = reg_info.edi;
|
||||
flags = reg_info.eflags;
|
||||
|
||||
/* Pass errors back to our caller via the CARRY flag */
|
||||
if (ret) {
|
||||
printk(BIOS_DEBUG,"error!\n");
|
||||
flags |= 1; // error: set carry
|
||||
}else{
|
||||
flags &= ~1; // no error: clear carry
|
||||
}
|
||||
*(volatile u16 *)&stackflags = flags;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -1,347 +0,0 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 coresystems GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define REALMODE_BASE 0x600
|
||||
#define RELOCATED(x) (x - __realmode_code + REALMODE_BASE)
|
||||
|
||||
/* CR0 bits */
|
||||
#define PE (1 << 0)
|
||||
|
||||
/* This is the intXX interrupt handler stub code. It gets copied
|
||||
* to the IDT and to some fixed addresses in the F segment. Before
|
||||
* the code can used, it gets patched up by the C function copying
|
||||
* it: byte 3 (the $0 in movb $0, %al) is overwritten with the int#.
|
||||
*/
|
||||
|
||||
.code16
|
||||
.globl __idt_handler
|
||||
__idt_handler:
|
||||
pushal
|
||||
movb $0, %al /* This instruction gets modified */
|
||||
ljmp $0, $__interrupt_handler_16bit
|
||||
.globl __idt_handler_size
|
||||
__idt_handler_size = ( . - __idt_handler)
|
||||
|
||||
|
||||
/* In order to be independent of coreboot's position in RAM
|
||||
* we relocate a part of the code to the low megabyte, so the
|
||||
* CPU can use it in real-mode. This code lives at __realmode_code.
|
||||
*/
|
||||
.globl __realmode_code
|
||||
__realmode_code:
|
||||
|
||||
/* Realmode IDT pointer structure. */
|
||||
.globl __realmode_idt
|
||||
__realmode_idt = RELOCATED(.)
|
||||
.word 1023 /* 16-bit limit */
|
||||
.long 0 /* 24-bit base */
|
||||
.word 0
|
||||
|
||||
/* Preserve old stack */
|
||||
__stack = RELOCATED(.)
|
||||
.long 0
|
||||
|
||||
.code32
|
||||
.globl __run_optionrom
|
||||
__run_optionrom = RELOCATED(.)
|
||||
/* save all registers to the stack */
|
||||
pushal
|
||||
|
||||
/* Move the protected mode stack to a safe place */
|
||||
mov %esp, __stack
|
||||
|
||||
/* Get devfn into %ecx */
|
||||
movl %esp, %ebp
|
||||
/* This function is called with regparm=0 and we have
|
||||
* to skip the 32 byte from pushal:
|
||||
*/
|
||||
movl 36(%ebp), %ecx
|
||||
|
||||
/* Activate the right segment descriptor real mode. */
|
||||
ljmp $0x28, $RELOCATED(1f)
|
||||
1:
|
||||
.code16
|
||||
/* 16 bit code from here on... */
|
||||
|
||||
/* Load the segment registers w/ properly configured
|
||||
* segment descriptors. They will retain these
|
||||
* configurations (limits, writability, etc.) once
|
||||
* protected mode is turned off.
|
||||
*/
|
||||
mov $0x30, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
/* Turn off protection */
|
||||
movl %cr0, %eax
|
||||
andl $~PE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Now really going into real mode */
|
||||
ljmp $0, $RELOCATED(1f)
|
||||
1:
|
||||
/* Setup a stack: Put the stack at the end of page zero.
|
||||
* That way we can easily share it between real and
|
||||
* protected, since the 16-bit ESP at segment 0 will
|
||||
* work for any case. */
|
||||
mov $0x0, %ax
|
||||
mov %ax, %ss
|
||||
movl $0x1000, %eax
|
||||
movl %eax, %esp
|
||||
|
||||
/* Load our 16 bit idt */
|
||||
xor %ax, %ax
|
||||
mov %ax, %ds
|
||||
lidt __realmode_idt
|
||||
|
||||
/* Set all segments to 0x0000, ds to 0x0040 */
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov $0x40, %ax
|
||||
mov %ax, %ds
|
||||
mov %cx, %ax // restore ax
|
||||
|
||||
/* ************************************ */
|
||||
// TODO this will not work for non-VGA option ROMs
|
||||
/* run VGA BIOS at 0xc000:0003 */
|
||||
lcall $0xc000, $0x0003
|
||||
/* ************************************ */
|
||||
|
||||
/* If we got here, just about done.
|
||||
* Need to get back to protected mode
|
||||
*/
|
||||
movl %cr0, %eax
|
||||
orl $PE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Now that we are in protected mode
|
||||
* jump to a 32 bit code segment.
|
||||
*/
|
||||
data32 ljmp $0x10, $RELOCATED(1f)
|
||||
1:
|
||||
.code32
|
||||
movw $0x18, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
/* restore proper idt */
|
||||
lidt idtarg
|
||||
|
||||
/* and exit */
|
||||
mov __stack, %esp
|
||||
popal
|
||||
ret
|
||||
|
||||
.globl __run_interrupt
|
||||
__run_interrupt = RELOCATED(.)
|
||||
|
||||
/* paranoia -- does ecx get saved? not sure. This is
|
||||
* the easiest safe thing to do. */
|
||||
pushal
|
||||
/* save the stack */
|
||||
mov %esp, __stack
|
||||
|
||||
|
||||
/* This configures CS properly for real mode. */
|
||||
ljmp $0x28, $RELOCATED(1f)
|
||||
1:
|
||||
.code16 /* 16 bit code from here on... */
|
||||
|
||||
// DEBUG
|
||||
movb $0xec, %al
|
||||
outb %al, $0x80
|
||||
|
||||
/* Load the segment registers w/ properly configured segment
|
||||
* descriptors. They will retain these configurations (limits,
|
||||
* writability, etc.) once protected mode is turned off.
|
||||
*/
|
||||
mov $0x30, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
/* Turn off protected mode */
|
||||
movl %cr0, %eax
|
||||
andl $~PE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Now really going into real mode */
|
||||
data32 ljmp $0, $RELOCATED(1f)
|
||||
1:
|
||||
|
||||
/* put the stack at the end of page zero.
|
||||
* that way we can easily share it between real and protected,
|
||||
* since the 16-bit ESP at segment 0 will work for any case.
|
||||
*/
|
||||
/* setup a stack */
|
||||
mov $0x0, %ax
|
||||
mov %ax, %ss
|
||||
movl $0x1000, %eax
|
||||
movl %eax, %esp
|
||||
|
||||
/* Load 16-bit intXX IDT */
|
||||
xor %ax, %ax
|
||||
mov %ax, %ds
|
||||
lidt __realmode_idt
|
||||
|
||||
/* Set all segments to 0x0000 */
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
|
||||
/* Call VGA BIOS int10 function 0x4f14 to enable main console
|
||||
* Epia-M does not always autosence the main console so forcing
|
||||
* it on is good.
|
||||
*/
|
||||
|
||||
/* Ask VGA option rom to enable main console */
|
||||
movw $0x4f14,%ax
|
||||
movw $0x8003,%bx
|
||||
movw $1, %cx
|
||||
movw $0, %dx
|
||||
movw $0, %di
|
||||
int $0x10
|
||||
|
||||
/* Ok, the job is done, now go back to protected mode coreboot */
|
||||
movl %cr0, %eax
|
||||
orl $PE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Now that we are in protected mode jump to a 32-bit code segment. */
|
||||
data32 ljmp $0x10, $RELOCATED(1f)
|
||||
1:
|
||||
.code32
|
||||
movw $0x18, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
/* restore coreboot's 32-bit IDT */
|
||||
lidt idtarg
|
||||
|
||||
/* Exit */
|
||||
mov __stack, %esp
|
||||
popal
|
||||
ret
|
||||
|
||||
/* This is the 16-bit interrupt entry point called by the IDT stub code.
|
||||
* Before this code code is called, %eax is pushed to the stack, and the
|
||||
* interrupt number is loaded into %al
|
||||
*/
|
||||
.code16
|
||||
__interrupt_handler_16bit = RELOCATED(.)
|
||||
push %ds
|
||||
push %es
|
||||
push %fs
|
||||
push %gs
|
||||
|
||||
/* Clean up the interrupt number. We could have done this in the stub,
|
||||
* but it would have cost 2 more bytes per stub entry.
|
||||
*/
|
||||
andl $0xff, %eax
|
||||
pushl %eax /* ... and make it the first parameter */
|
||||
|
||||
/* Switch to protected mode */
|
||||
movl %cr0, %eax
|
||||
orl $PE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* ... and jump to a 32 bit code segment. */
|
||||
data32 ljmp $0x10, $RELOCATED(1f)
|
||||
1:
|
||||
.code32
|
||||
movw $0x18, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
lidt idtarg
|
||||
|
||||
/* Call the C interrupt handler */
|
||||
movl $interrupt_handler, %eax
|
||||
call *%eax
|
||||
|
||||
/* Now return to real mode ... */
|
||||
ljmp $0x28, $RELOCATED(1f)
|
||||
1:
|
||||
.code16
|
||||
/* Load the segment registers with properly configured segment
|
||||
* descriptors. They will retain these configurations (limits,
|
||||
* writability, etc.) once protected mode is turned off.
|
||||
*/
|
||||
mov $0x30, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
/* Disable Protected Mode */
|
||||
movl %cr0, %eax
|
||||
andl $~PE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Now really going into real mode */
|
||||
ljmp $0, $RELOCATED(1f)
|
||||
1:
|
||||
/* Restore real-mode stack segment */
|
||||
mov $0x0, %ax
|
||||
mov %ax, %ss
|
||||
|
||||
/* Restore 16-bit IDT */
|
||||
xor %ax, %ax
|
||||
mov %ax, %ds
|
||||
lidt __realmode_idt
|
||||
|
||||
/* Set up our segment registers to segment 0x0000 */
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov $0x40, %ax
|
||||
mov %ax, %ds
|
||||
|
||||
/* Restore all registers, including those
|
||||
* manipulated by the C handler
|
||||
*/
|
||||
popl %eax
|
||||
pop %gs
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popal
|
||||
iret
|
||||
|
||||
.globl __realmode_code_size
|
||||
__realmode_code_size = (. - __realmode_code)
|
||||
|
||||
.code32
|
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2001 Ronald G. Minnich
|
||||
* Copyright (C) 2005 Nick.Barker9@btinternet.com
|
||||
* Copyright (C) 2007-2009 coresystems GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <string.h>
|
||||
#include <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include <arch/registers.h>
|
||||
|
||||
enum {
|
||||
PCIBIOS_CHECK = 0xb101,
|
||||
PCIBIOS_FINDDEV = 0xb102,
|
||||
PCIBIOS_READCONFBYTE = 0xb108,
|
||||
PCIBIOS_READCONFWORD = 0xb109,
|
||||
PCIBIOS_READCONFDWORD = 0xb10a,
|
||||
PCIBIOS_WRITECONFBYTE = 0xb10b,
|
||||
PCIBIOS_WRITECONFWORD = 0xb10c,
|
||||
PCIBIOS_WRITECONFDWORD = 0xb10d
|
||||
};
|
||||
|
||||
// errors go in AH. Just set these up so that word assigns
|
||||
// will work. KISS.
|
||||
enum {
|
||||
PCIBIOS_SUCCESSFUL = 0x0000,
|
||||
PCIBIOS_UNSUPPORTED = 0x8100,
|
||||
PCIBIOS_BADVENDOR = 0x8300,
|
||||
PCIBIOS_NODEV = 0x8600,
|
||||
PCIBIOS_BADREG = 0x8700
|
||||
};
|
||||
|
||||
int int12_handler(struct eregs *regs);
|
||||
int int1a_handler(struct eregs *regs);
|
||||
int int15_handler(struct eregs *regs);
|
||||
|
||||
int int12_handler(struct eregs *regs)
|
||||
{
|
||||
regs->eax = 64 * 1024;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int int1a_handler(struct eregs *regs)
|
||||
{
|
||||
unsigned short func = (unsigned short)regs->eax;
|
||||
int retval = 0;
|
||||
unsigned short devid, vendorid, devfn;
|
||||
/* Use short to get rid of gabage in upper half of 32-bit register */
|
||||
short devindex;
|
||||
unsigned char bus;
|
||||
struct device *dev;
|
||||
u32 dword;
|
||||
u16 word;
|
||||
u8 byte, reg;
|
||||
|
||||
switch (func) {
|
||||
case PCIBIOS_CHECK:
|
||||
regs->edx = 0x20494350; /* ' ICP' */
|
||||
regs->edi = 0x00000000; /* protected mode entry */
|
||||
retval = 0;
|
||||
break;
|
||||
case PCIBIOS_FINDDEV:
|
||||
devid = regs->ecx;
|
||||
vendorid = regs->edx;
|
||||
devindex = regs->esi;
|
||||
dev = 0;
|
||||
while ((dev = dev_find_device(vendorid, devid, dev))) {
|
||||
if (devindex <= 0)
|
||||
break;
|
||||
devindex--;
|
||||
}
|
||||
if (dev) {
|
||||
unsigned short busdevfn;
|
||||
regs->eax = 0;
|
||||
// busnum is an unsigned char;
|
||||
// devfn is an int, so we mask it off.
|
||||
busdevfn = (dev->bus->secondary << 8)
|
||||
| (dev->path.pci.devfn & 0xff);
|
||||
printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn);
|
||||
regs->ebx = busdevfn;
|
||||
retval = 0;
|
||||
} else {
|
||||
regs->eax = PCIBIOS_NODEV;
|
||||
retval = -1;
|
||||
}
|
||||
break;
|
||||
case PCIBIOS_READCONFDWORD:
|
||||
case PCIBIOS_READCONFWORD:
|
||||
case PCIBIOS_READCONFBYTE:
|
||||
case PCIBIOS_WRITECONFDWORD:
|
||||
case PCIBIOS_WRITECONFWORD:
|
||||
case PCIBIOS_WRITECONFBYTE:
|
||||
devfn = regs->ebx & 0xff;
|
||||
bus = regs->ebx >> 8;
|
||||
reg = regs->edi;
|
||||
dev = dev_find_slot(bus, devfn);
|
||||
if (!dev) {
|
||||
printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
|
||||
// idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
|
||||
regs->eax = PCIBIOS_BADREG;
|
||||
retval = -1;
|
||||
return retval;
|
||||
}
|
||||
switch (func) {
|
||||
case PCIBIOS_READCONFBYTE:
|
||||
byte = pci_read_config8(dev, reg);
|
||||
regs->ecx = byte;
|
||||
break;
|
||||
case PCIBIOS_READCONFWORD:
|
||||
word = pci_read_config16(dev, reg);
|
||||
regs->ecx = word;
|
||||
break;
|
||||
case PCIBIOS_READCONFDWORD:
|
||||
dword = pci_read_config32(dev, reg);
|
||||
regs->ecx = dword;
|
||||
break;
|
||||
case PCIBIOS_WRITECONFBYTE:
|
||||
byte = regs->ecx;
|
||||
pci_write_config8(dev, reg, byte);
|
||||
break;
|
||||
case PCIBIOS_WRITECONFWORD:
|
||||
word = regs->ecx;
|
||||
pci_write_config16(dev, reg, word);
|
||||
break;
|
||||
case PCIBIOS_WRITECONFDWORD:
|
||||
dword = regs->ecx;
|
||||
pci_write_config32(dev, reg, dword);
|
||||
break;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n",
|
||||
func, bus, devfn, reg, regs->ecx);
|
||||
regs->eax = 0;
|
||||
retval = 0;
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int int15_handler(struct eregs *regs)
|
||||
{
|
||||
int res = -1;
|
||||
|
||||
/* This int15 handler is VIA Tech. specific. Other chipsets need other
|
||||
* handlers. The right way to do this is to move this handler code into
|
||||
* the mainboard or northbridge code.
|
||||
*/
|
||||
switch (regs->eax & 0xffff) {
|
||||
case 0x5f19:
|
||||
break;
|
||||
case 0x5f18:
|
||||
regs->eax = 0x5f;
|
||||
// MCLK = 133, 32M frame buffer, 256 M main memory
|
||||
regs->ebx = 0x545;
|
||||
regs->ecx = 0x060;
|
||||
res = 0;
|
||||
break;
|
||||
case 0x5f00:
|
||||
regs->eax = 0x8600;
|
||||
break;
|
||||
case 0x5f01:
|
||||
regs->eax = 0x5f;
|
||||
regs->ecx = (regs->ecx & 0xffffff00 ) | 2; // panel type = 2 = 1024 * 768
|
||||
res = 0;
|
||||
break;
|
||||
case 0x5f02:
|
||||
regs->eax = 0x5f;
|
||||
regs->ebx = (regs->ebx & 0xffff0000) | 2;
|
||||
regs->ecx = (regs->ecx & 0xffff0000) | 0x401; // PAL + crt only
|
||||
regs->edx = (regs->edx & 0xffff0000) | 0; // TV Layout - default
|
||||
res = 0;
|
||||
break;
|
||||
case 0x5f0f:
|
||||
regs->eax = 0x860f;
|
||||
break;
|
||||
/* And now Intel IGD code */
|
||||
#define BOOT_DISPLAY_DEFAULT 0
|
||||
#define BOOT_DISPLAY_CRT (1 << 0)
|
||||
#define BOOT_DISPLAY_TV (1 << 1)
|
||||
#define BOOT_DISPLAY_EFP (1 << 2)
|
||||
#define BOOT_DISPLAY_LCD (1 << 3)
|
||||
#define BOOT_DISPLAY_CRT2 (1 << 4)
|
||||
#define BOOT_DISPLAY_TV2 (1 << 5)
|
||||
#define BOOT_DISPLAY_EFP2 (1 << 6)
|
||||
#define BOOT_DISPLAY_LCD2 (1 << 7)
|
||||
|
||||
case 0x5f35:
|
||||
regs->eax = 0x5f;
|
||||
regs->ecx = BOOT_DISPLAY_DEFAULT;
|
||||
res = 0;
|
||||
break;
|
||||
case 0x5f40:
|
||||
regs->eax = 0x5f;
|
||||
regs->ecx = 3; // This is mainboard specific
|
||||
printk(BIOS_DEBUG, "DISPLAY=%x\n", regs->ecx);
|
||||
res = 0;
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "Unknown INT15 function %04x!\n",
|
||||
regs->eax & 0xffff);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@@ -1,17 +0,0 @@
|
||||
License information
|
||||
-------------------
|
||||
|
||||
The x86emu library is under a BSD style license, comaptible
|
||||
with the XFree86 and X licenses used by XFree86. The
|
||||
original x86emu libraries were under the GNU General Public
|
||||
License. Due to license incompatibilities between the GPL
|
||||
and the XFree86 license, the original authors of the code
|
||||
decided to allow a license change. If you have submitted
|
||||
code to the original x86emu project, and you don't agree
|
||||
with the license change, please contact us and let you
|
||||
know. Your code will be removed to comply with your wishes.
|
||||
|
||||
If you have any questions about this, please send email to
|
||||
x86emu@linuxlabs.com or KendallB@scitechsoft.com for
|
||||
clarification.
|
||||
|
@@ -1,7 +0,0 @@
|
||||
obj-y += debug.o
|
||||
obj-y += decode.o
|
||||
obj-y += fpu.o
|
||||
obj-y += ops.o
|
||||
obj-y += ops2.o
|
||||
obj-y += prim_ops.o
|
||||
obj-y += sys.o
|
@@ -1,434 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* 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: This file contains the code to handle debugging of the
|
||||
* emulator.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "x86emui.h"
|
||||
|
||||
/*----------------------------- Implementation ----------------------------*/
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static void print_encoded_bytes (u16 s, u16 o);
|
||||
static void print_decoded_instruction (void);
|
||||
int parse_line (char *s, int *ps, int *n);
|
||||
|
||||
/* should look something like debug's output. */
|
||||
void X86EMU_trace_regs (void)
|
||||
{
|
||||
if (DEBUG_TRACE()) {
|
||||
if (M.x86.mode & (SYSMODE_PREFIX_DATA | SYSMODE_PREFIX_ADDR)) {
|
||||
x86emu_dump_xregs();
|
||||
} else {
|
||||
x86emu_dump_regs();
|
||||
}
|
||||
}
|
||||
if (DEBUG_DECODE() && ! DEBUG_DECODE_NOPRINT()) {
|
||||
printf("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip);
|
||||
print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip);
|
||||
print_decoded_instruction();
|
||||
}
|
||||
}
|
||||
|
||||
void X86EMU_trace_xregs (void)
|
||||
{
|
||||
if (DEBUG_TRACE()) {
|
||||
x86emu_dump_xregs();
|
||||
}
|
||||
}
|
||||
|
||||
void x86emu_just_disassemble (void)
|
||||
{
|
||||
/*
|
||||
* This routine called if the flag DEBUG_DISASSEMBLE is set kind
|
||||
* of a hack!
|
||||
*/
|
||||
printf("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip);
|
||||
print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip);
|
||||
print_decoded_instruction();
|
||||
}
|
||||
|
||||
void disassemble_forward (u16 seg, u16 off, int n)
|
||||
{
|
||||
X86EMU_sysEnv tregs;
|
||||
int i;
|
||||
u8 op1;
|
||||
/*
|
||||
* hack, hack, hack. What we do is use the exact machinery set up
|
||||
* for execution, except that now there is an additional state
|
||||
* flag associated with the "execution", and we are using a copy
|
||||
* of the register struct. All the major opcodes, once fully
|
||||
* decoded, have the following two steps: TRACE_REGS(r,m);
|
||||
* SINGLE_STEP(r,m); which disappear if DEBUG is not defined to
|
||||
* the preprocessor. The TRACE_REGS macro expands to:
|
||||
*
|
||||
* if (debug&DEBUG_DISASSEMBLE)
|
||||
* {just_disassemble(); goto EndOfInstruction;}
|
||||
* if (debug&DEBUG_TRACE) trace_regs(r,m);
|
||||
*
|
||||
* ...... and at the last line of the routine.
|
||||
*
|
||||
* EndOfInstruction: end_instr();
|
||||
*
|
||||
* Up to the point where TRACE_REG is expanded, NO modifications
|
||||
* are done to any register EXCEPT the IP register, for fetch and
|
||||
* decoding purposes.
|
||||
*
|
||||
* This was done for an entirely different reason, but makes a
|
||||
* nice way to get the system to help debug codes.
|
||||
*/
|
||||
tregs = M;
|
||||
tregs.x86.R_IP = off;
|
||||
tregs.x86.R_CS = seg;
|
||||
|
||||
/* reset the decoding buffers */
|
||||
tregs.x86.enc_str_pos = 0;
|
||||
tregs.x86.enc_pos = 0;
|
||||
|
||||
/* turn on the "disassemble only, no execute" flag */
|
||||
tregs.x86.debug |= DEBUG_DISASSEMBLE_F;
|
||||
|
||||
/* DUMP NEXT n instructions to screen in straight_line fashion */
|
||||
/*
|
||||
* This looks like the regular instruction fetch stream, except
|
||||
* that when this occurs, each fetched opcode, upon seeing the
|
||||
* DEBUG_DISASSEMBLE flag set, exits immediately after decoding
|
||||
* the instruction. XXX --- CHECK THAT MEM IS NOT AFFECTED!!!
|
||||
* Note the use of a copy of the register structure...
|
||||
*/
|
||||
for (i=0; i<n; i++) {
|
||||
op1 = (*sys_rdb)(((u32)M.x86.R_CS<<4) + (M.x86.R_IP++));
|
||||
(x86emu_optab[op1])(op1);
|
||||
}
|
||||
/* end major hack mode. */
|
||||
}
|
||||
|
||||
void x86emu_check_ip_access (void)
|
||||
{
|
||||
/* NULL as of now */
|
||||
}
|
||||
|
||||
void x86emu_check_sp_access (void)
|
||||
{
|
||||
}
|
||||
|
||||
void x86emu_check_mem_access (u32 dummy)
|
||||
{
|
||||
/* check bounds, etc */
|
||||
}
|
||||
|
||||
void x86emu_check_data_access (uint dummy1, uint dummy2)
|
||||
{
|
||||
/* check bounds, etc */
|
||||
}
|
||||
|
||||
void x86emu_inc_decoded_inst_len (int x)
|
||||
{
|
||||
M.x86.enc_pos += x;
|
||||
}
|
||||
|
||||
void x86emu_decode_printf (const char *x)
|
||||
{
|
||||
sprintf(M.x86.decoded_buf+M.x86.enc_str_pos,"%s",x);
|
||||
M.x86.enc_str_pos += strlen(x);
|
||||
}
|
||||
|
||||
void x86emu_decode_printf2 (const char *x, int y)
|
||||
{
|
||||
char temp[100];
|
||||
sprintf(temp,x,y);
|
||||
sprintf(M.x86.decoded_buf+M.x86.enc_str_pos,"%s",temp);
|
||||
M.x86.enc_str_pos += strlen(temp);
|
||||
}
|
||||
|
||||
void x86emu_end_instr (void)
|
||||
{
|
||||
M.x86.enc_str_pos = 0;
|
||||
M.x86.enc_pos = 0;
|
||||
}
|
||||
|
||||
static void print_encoded_bytes (u16 s, u16 o)
|
||||
{
|
||||
int i;
|
||||
char buf1[64];
|
||||
for (i=0; i< M.x86.enc_pos; i++) {
|
||||
sprintf(buf1+2*i,"%02x", fetch_data_byte_abs(s,o+i));
|
||||
}
|
||||
printf("%-20s ",buf1);
|
||||
}
|
||||
|
||||
static void print_decoded_instruction (void)
|
||||
{
|
||||
printf("%s", M.x86.decoded_buf);
|
||||
}
|
||||
|
||||
void x86emu_print_int_vect (u16 iv)
|
||||
{
|
||||
u16 seg,off;
|
||||
|
||||
if (iv > 256) return;
|
||||
seg = fetch_data_word_abs(0,iv*4);
|
||||
off = fetch_data_word_abs(0,iv*4+2);
|
||||
printf("%04x:%04x ", seg, off);
|
||||
}
|
||||
|
||||
void X86EMU_dump_memory (u16 seg, u16 off, u32 amt)
|
||||
{
|
||||
u32 start = off & 0xfffffff0;
|
||||
u32 end = (off+16) & 0xfffffff0;
|
||||
u32 i;
|
||||
u32 current;
|
||||
|
||||
current = start;
|
||||
while (end <= off + amt) {
|
||||
printf("%04x:%04x ", seg, start);
|
||||
for (i=start; i< off; i++)
|
||||
printf(" ");
|
||||
for ( ; i< end; i++)
|
||||
printf("%02x ", fetch_data_byte_abs(seg,i));
|
||||
printf("\n");
|
||||
start = end;
|
||||
end = start + 16;
|
||||
}
|
||||
}
|
||||
|
||||
void x86emu_single_step (void)
|
||||
{
|
||||
#if 0
|
||||
char s[1024];
|
||||
int ps[10];
|
||||
int ntok;
|
||||
int cmd;
|
||||
int done;
|
||||
int segment;
|
||||
int offset;
|
||||
static int breakpoint;
|
||||
static int noDecode = 1;
|
||||
|
||||
char *p;
|
||||
|
||||
if (DEBUG_BREAK()) {
|
||||
if (M.x86.saved_ip != breakpoint) {
|
||||
return;
|
||||
} else {
|
||||
M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
|
||||
M.x86.debug |= DEBUG_TRACE_F;
|
||||
M.x86.debug &= ~DEBUG_BREAK_F;
|
||||
print_decoded_instruction ();
|
||||
X86EMU_trace_regs();
|
||||
}
|
||||
}
|
||||
done=0;
|
||||
offset = M.x86.saved_ip;
|
||||
while (!done) {
|
||||
printf("-");
|
||||
p = fgets(s, 1023, stdin);
|
||||
cmd = parse_line(s, ps, &ntok);
|
||||
switch(cmd) {
|
||||
case 'u':
|
||||
disassemble_forward(M.x86.saved_cs,(u16)offset,10);
|
||||
break;
|
||||
case 'd':
|
||||
if (ntok == 2) {
|
||||
segment = M.x86.saved_cs;
|
||||
offset = ps[1];
|
||||
X86EMU_dump_memory(segment,(u16)offset,16);
|
||||
offset += 16;
|
||||
} else if (ntok == 3) {
|
||||
segment = ps[1];
|
||||
offset = ps[2];
|
||||
X86EMU_dump_memory(segment,(u16)offset,16);
|
||||
offset += 16;
|
||||
} else {
|
||||
segment = M.x86.saved_cs;
|
||||
X86EMU_dump_memory(segment,(u16)offset,16);
|
||||
offset += 16;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
M.x86.debug ^= DEBUG_TRACECALL_F;
|
||||
break;
|
||||
case 's':
|
||||
M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F;
|
||||
break;
|
||||
case 'r':
|
||||
X86EMU_trace_regs();
|
||||
break;
|
||||
case 'x':
|
||||
X86EMU_trace_xregs();
|
||||
break;
|
||||
case 'g':
|
||||
if (ntok == 2) {
|
||||
breakpoint = ps[1];
|
||||
if (noDecode) {
|
||||
M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
|
||||
} else {
|
||||
M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
|
||||
}
|
||||
M.x86.debug &= ~DEBUG_TRACE_F;
|
||||
M.x86.debug |= DEBUG_BREAK_F;
|
||||
done = 1;
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
M.x86.debug |= DEBUG_EXIT;
|
||||
return;
|
||||
case 'P':
|
||||
noDecode = (noDecode)?0:1;
|
||||
printf("Toggled decoding to %s\n",(noDecode)?"FALSE":"TRUE");
|
||||
break;
|
||||
case 't':
|
||||
case 0:
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int X86EMU_trace_on(void)
|
||||
{
|
||||
return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F;
|
||||
}
|
||||
|
||||
int X86EMU_trace_off(void)
|
||||
{
|
||||
return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F);
|
||||
}
|
||||
|
||||
int parse_line (char *s, int *ps, int *n)
|
||||
{
|
||||
#if 0
|
||||
int cmd;
|
||||
|
||||
*n = 0;
|
||||
while(*s == ' ' || *s == '\t') s++;
|
||||
ps[*n] = *s;
|
||||
switch (*s) {
|
||||
case '\n':
|
||||
*n += 1;
|
||||
return 0;
|
||||
default:
|
||||
cmd = *s;
|
||||
*n += 1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (*s != ' ' && *s != '\t' && *s != '\n') s++;
|
||||
|
||||
if (*s == '\n')
|
||||
return cmd;
|
||||
|
||||
while(*s == ' ' || *s == '\t') s++;
|
||||
|
||||
sscanf(s,"%x",&ps[*n]);
|
||||
*n += 1;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
void x86emu_dump_regs (void)
|
||||
{
|
||||
printf("\tAX=%04x ", M.x86.R_AX );
|
||||
printf("BX=%04x ", M.x86.R_BX );
|
||||
printf("CX=%04x ", M.x86.R_CX );
|
||||
printf("DX=%04x ", M.x86.R_DX );
|
||||
printf("SP=%04x ", M.x86.R_SP );
|
||||
printf("BP=%04x ", M.x86.R_BP );
|
||||
printf("SI=%04x ", M.x86.R_SI );
|
||||
printf("DI=%04x\n", M.x86.R_DI );
|
||||
printf("\tDS=%04x ", M.x86.R_DS );
|
||||
printf("ES=%04x ", M.x86.R_ES );
|
||||
printf("SS=%04x ", M.x86.R_SS );
|
||||
printf("CS=%04x ", M.x86.R_CS );
|
||||
printf("IP=%04x ", M.x86.R_IP );
|
||||
if (ACCESS_FLAG(F_OF)) printf("OV "); /* CHECKED... */
|
||||
else printf("NV ");
|
||||
if (ACCESS_FLAG(F_DF)) printf("DN ");
|
||||
else printf("UP ");
|
||||
if (ACCESS_FLAG(F_IF)) printf("EI ");
|
||||
else printf("DI ");
|
||||
if (ACCESS_FLAG(F_SF)) printf("NG ");
|
||||
else printf("PL ");
|
||||
if (ACCESS_FLAG(F_ZF)) printf("ZR ");
|
||||
else printf("NZ ");
|
||||
if (ACCESS_FLAG(F_AF)) printf("AC ");
|
||||
else printf("NA ");
|
||||
if (ACCESS_FLAG(F_PF)) printf("PE ");
|
||||
else printf("PO ");
|
||||
if (ACCESS_FLAG(F_CF)) printf("CY ");
|
||||
else printf("NC ");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void x86emu_dump_xregs (void)
|
||||
{
|
||||
printf("\tEAX=%08x ", M.x86.R_EAX );
|
||||
printf("EBX=%08x ", M.x86.R_EBX );
|
||||
printf("ECX=%08x ", M.x86.R_ECX );
|
||||
printf("EDX=%08x \n", M.x86.R_EDX );
|
||||
printf("\tESP=%08x ", M.x86.R_ESP );
|
||||
printf("EBP=%08x ", M.x86.R_EBP );
|
||||
printf("ESI=%08x ", M.x86.R_ESI );
|
||||
printf("EDI=%08x\n", M.x86.R_EDI );
|
||||
printf("\tDS=%04x ", M.x86.R_DS );
|
||||
printf("ES=%04x ", M.x86.R_ES );
|
||||
printf("SS=%04x ", M.x86.R_SS );
|
||||
printf("CS=%04x ", M.x86.R_CS );
|
||||
printf("EIP=%08x\n\t", M.x86.R_EIP );
|
||||
if (ACCESS_FLAG(F_OF)) printf("OV "); /* CHECKED... */
|
||||
else printf("NV ");
|
||||
if (ACCESS_FLAG(F_DF)) printf("DN ");
|
||||
else printf("UP ");
|
||||
if (ACCESS_FLAG(F_IF)) printf("EI ");
|
||||
else printf("DI ");
|
||||
if (ACCESS_FLAG(F_SF)) printf("NG ");
|
||||
else printf("PL ");
|
||||
if (ACCESS_FLAG(F_ZF)) printf("ZR ");
|
||||
else printf("NZ ");
|
||||
if (ACCESS_FLAG(F_AF)) printf("AC ");
|
||||
else printf("NA ");
|
||||
if (ACCESS_FLAG(F_PF)) printf("PE ");
|
||||
else printf("PO ");
|
||||
if (ACCESS_FLAG(F_CF)) printf("CY ");
|
||||
else printf("NC ");
|
||||
printf("\n");
|
||||
}
|
@@ -1,226 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 debug definitions.
|
||||
*
|
||||
****************************************************************************/
|
||||
/* $XFree86: xc/extras/x86emu/src/x86emu/x86emu/debug.h,v 1.4 2000/11/21 23:10:27 tsi Exp $ */
|
||||
|
||||
#ifndef __X86EMU_DEBUG_H
|
||||
#define __X86EMU_DEBUG_H
|
||||
|
||||
/*---------------------- Macros and type definitions ----------------------*/
|
||||
|
||||
/* printf is not available in coreboot... use printk */
|
||||
#define printf(x...) printk(BIOS_DEBUG, x)
|
||||
|
||||
/* checks to be enabled for "runtime" */
|
||||
|
||||
#define CHECK_IP_FETCH_F 0x1
|
||||
#define CHECK_SP_ACCESS_F 0x2
|
||||
#define CHECK_MEM_ACCESS_F 0x4 /*using regular linear pointer */
|
||||
#define CHECK_DATA_ACCESS_F 0x8 /*using segment:offset*/
|
||||
|
||||
#ifdef DEBUG
|
||||
# define CHECK_IP_FETCH() (M.x86.check & CHECK_IP_FETCH_F)
|
||||
# define CHECK_SP_ACCESS() (M.x86.check & CHECK_SP_ACCESS_F)
|
||||
# define CHECK_MEM_ACCESS() (M.x86.check & CHECK_MEM_ACCESS_F)
|
||||
# define CHECK_DATA_ACCESS() (M.x86.check & CHECK_DATA_ACCESS_F)
|
||||
#else
|
||||
# define CHECK_IP_FETCH()
|
||||
# define CHECK_SP_ACCESS()
|
||||
# define CHECK_MEM_ACCESS()
|
||||
# define CHECK_DATA_ACCESS()
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
# define DEBUG_INSTRUMENT() (M.x86.debug & DEBUG_INSTRUMENT_F)
|
||||
# define DEBUG_DECODE() (M.x86.debug & DEBUG_DECODE_F)
|
||||
# define DEBUG_TRACE() (M.x86.debug & DEBUG_TRACE_F)
|
||||
# define DEBUG_STEP() (M.x86.debug & DEBUG_STEP_F)
|
||||
# define DEBUG_DISASSEMBLE() (M.x86.debug & DEBUG_DISASSEMBLE_F)
|
||||
# define DEBUG_BREAK() (M.x86.debug & DEBUG_BREAK_F)
|
||||
# define DEBUG_SVC() (M.x86.debug & DEBUG_SVC_F)
|
||||
# define DEBUG_SAVE_IP_CS() (M.x86.debug & DEBUG_SAVE_IP_CS_F)
|
||||
|
||||
# define DEBUG_FS() (M.x86.debug & DEBUG_FS_F)
|
||||
# define DEBUG_PROC() (M.x86.debug & DEBUG_PROC_F)
|
||||
# define DEBUG_SYSINT() (M.x86.debug & DEBUG_SYSINT_F)
|
||||
# define DEBUG_TRACECALL() (M.x86.debug & DEBUG_TRACECALL_F)
|
||||
# define DEBUG_TRACECALLREGS() (M.x86.debug & DEBUG_TRACECALL_REGS_F)
|
||||
# define DEBUG_TRACEJMP() (M.x86.debug & DEBUG_TRACEJMP_F)
|
||||
# define DEBUG_TRACEJMPREGS() (M.x86.debug & DEBUG_TRACEJMP_REGS_F)
|
||||
# define DEBUG_SYS() (M.x86.debug & DEBUG_SYS_F)
|
||||
# define DEBUG_MEM_TRACE() (M.x86.debug & DEBUG_MEM_TRACE_F)
|
||||
# define DEBUG_IO_TRACE() (M.x86.debug & DEBUG_IO_TRACE_F)
|
||||
# define DEBUG_DECODE_NOPRINT() (M.x86.debug & DEBUG_DECODE_NOPRINT_F)
|
||||
#else
|
||||
# define DEBUG_INSTRUMENT() 0
|
||||
# define DEBUG_DECODE() 0
|
||||
# define DEBUG_TRACE() 0
|
||||
# define DEBUG_STEP() 0
|
||||
# define DEBUG_DISASSEMBLE() 0
|
||||
# define DEBUG_BREAK() 0
|
||||
# define DEBUG_SVC() 0
|
||||
# define DEBUG_SAVE_IP_CS() 0
|
||||
# define DEBUG_FS() 0
|
||||
# define DEBUG_PROC() 0
|
||||
# define DEBUG_SYSINT() 0
|
||||
# define DEBUG_TRACECALL() 0
|
||||
# define DEBUG_TRACECALLREGS() 0
|
||||
# define DEBUG_TRACEJMP() 0
|
||||
# define DEBUG_TRACEJMPREGS() 0
|
||||
# define DEBUG_SYS() 0
|
||||
# define DEBUG_MEM_TRACE() 0
|
||||
# define DEBUG_IO_TRACE() 0
|
||||
# define DEBUG_DECODE_NOPRINT() 0
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
# define DECODE_PRINTF(x) if (DEBUG_DECODE()) \
|
||||
x86emu_decode_printf(x)
|
||||
# define DECODE_PRINTF2(x,y) if (DEBUG_DECODE()) \
|
||||
x86emu_decode_printf2(x,y)
|
||||
|
||||
/*
|
||||
* The following allow us to look at the bytes of an instruction. The
|
||||
* first INCR_INSTRN_LEN, is called everytime bytes are consumed in
|
||||
* the decoding process. The SAVE_IP_CS is called initially when the
|
||||
* major opcode of the instruction is accessed.
|
||||
*/
|
||||
#define INC_DECODED_INST_LEN(x) \
|
||||
if (DEBUG_DECODE()) \
|
||||
x86emu_inc_decoded_inst_len(x)
|
||||
|
||||
#define SAVE_IP_CS(x,y) \
|
||||
if (DEBUG_DECODE() | DEBUG_TRACECALL() | DEBUG_BREAK() \
|
||||
| DEBUG_IO_TRACE() | DEBUG_SAVE_IP_CS()) { \
|
||||
M.x86.saved_cs = x; \
|
||||
M.x86.saved_ip = y; \
|
||||
}
|
||||
#else
|
||||
# define INC_DECODED_INST_LEN(x)
|
||||
# define DECODE_PRINTF(x)
|
||||
# define DECODE_PRINTF2(x,y)
|
||||
# define SAVE_IP_CS(x,y)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define TRACE_REGS() \
|
||||
if (DEBUG_DISASSEMBLE()) { \
|
||||
x86emu_just_disassemble(); \
|
||||
goto EndOfTheInstructionProcedure; \
|
||||
} \
|
||||
if (DEBUG_TRACE() || DEBUG_DECODE()) X86EMU_trace_regs()
|
||||
#else
|
||||
# define TRACE_REGS()
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
# define SINGLE_STEP() if (DEBUG_STEP()) x86emu_single_step()
|
||||
#else
|
||||
# define SINGLE_STEP()
|
||||
#endif
|
||||
|
||||
#define TRACE_AND_STEP() \
|
||||
TRACE_REGS(); \
|
||||
SINGLE_STEP()
|
||||
|
||||
#ifdef DEBUG
|
||||
# define START_OF_INSTR()
|
||||
# define END_OF_INSTR() EndOfTheInstructionProcedure: x86emu_end_instr();
|
||||
# define END_OF_INSTR_NO_TRACE() x86emu_end_instr();
|
||||
#else
|
||||
# define START_OF_INSTR()
|
||||
# define END_OF_INSTR()
|
||||
# define END_OF_INSTR_NO_TRACE()
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
# define CALL_TRACE(u,v,w,x,s) \
|
||||
if (DEBUG_TRACECALLREGS()) \
|
||||
x86emu_dump_regs(); \
|
||||
if (DEBUG_TRACECALL()) \
|
||||
printf("%04x:%04x: CALL %s%04x:%04x\n", u , v, s, w, x);
|
||||
# define RETURN_TRACE(u,v,w,x,s) \
|
||||
if (DEBUG_TRACECALLREGS()) \
|
||||
x86emu_dump_regs(); \
|
||||
if (DEBUG_TRACECALL()) \
|
||||
printf("%04x:%04x: RET %s %04x:%04x\n",u,v,s,w,x);
|
||||
# define JMP_TRACE(u,v,w,x,s) \
|
||||
if (DEBUG_TRACEJMPREGS()) \
|
||||
x86emu_dump_regs(); \
|
||||
if (DEBUG_TRACEJMP()) \
|
||||
printf("%04x:%04x: JMP %s%04x:%04x\n", u , v, s, w, x);
|
||||
#else
|
||||
# define CALL_TRACE(u,v,w,x,s)
|
||||
# define RETURN_TRACE(u,v,w,x,s)
|
||||
# define JMP_TRACE(u,v,w,x,s)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DB(x) x
|
||||
#else
|
||||
#define DB(x)
|
||||
#endif
|
||||
|
||||
/*-------------------------- Function Prototypes --------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Use "C" linkage when in C++ mode */
|
||||
#endif
|
||||
|
||||
void x86emu_inc_decoded_inst_len (int x);
|
||||
void x86emu_decode_printf (const char *x);
|
||||
void x86emu_decode_printf2 (const char *x, int y);
|
||||
void x86emu_just_disassemble (void);
|
||||
void x86emu_single_step (void);
|
||||
void x86emu_end_instr (void);
|
||||
void x86emu_dump_regs (void);
|
||||
void x86emu_dump_xregs (void);
|
||||
void x86emu_print_int_vect (u16 iv);
|
||||
void x86emu_instrument_instruction (void);
|
||||
void x86emu_check_ip_access (void);
|
||||
void x86emu_check_sp_access (void);
|
||||
void x86emu_check_mem_access (u32 p);
|
||||
void x86emu_check_data_access (uint s, uint o);
|
||||
|
||||
void disassemble_forward (u16 seg, u16 off, int n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of "C" linkage for C++ */
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_DEBUG_H */
|
File diff suppressed because it is too large
Load Diff
@@ -1,88 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 instruction decoding logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __X86EMU_DECODE_H
|
||||
#define __X86EMU_DECODE_H
|
||||
|
||||
/*---------------------- Macros and type definitions ----------------------*/
|
||||
|
||||
/* Instruction Decoding Stuff */
|
||||
|
||||
#define FETCH_DECODE_MODRM(mod,rh,rl) fetch_decode_modrm(&mod,&rh,&rl)
|
||||
#define DECODE_RM_BYTE_REGISTER(r) decode_rm_byte_register(r)
|
||||
#define DECODE_RM_WORD_REGISTER(r) decode_rm_word_register(r)
|
||||
#define DECODE_RM_LONG_REGISTER(r) decode_rm_long_register(r)
|
||||
#define DECODE_CLEAR_SEGOVR() M.x86.mode &= ~SYSMODE_CLRMASK
|
||||
|
||||
/*-------------------------- Function Prototypes --------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Use "C" linkage when in C++ mode */
|
||||
#endif
|
||||
|
||||
void x86emu_intr_raise (u8 type);
|
||||
void fetch_decode_modrm (int *mod,int *regh,int *regl);
|
||||
u8 fetch_byte_imm (void);
|
||||
u16 fetch_word_imm (void);
|
||||
u32 fetch_long_imm (void);
|
||||
u8 fetch_data_byte (uint offset);
|
||||
u8 fetch_data_byte_abs (uint segment, uint offset);
|
||||
u16 fetch_data_word (uint offset);
|
||||
u16 fetch_data_word_abs (uint segment, uint offset);
|
||||
u32 fetch_data_long (uint offset);
|
||||
u32 fetch_data_long_abs (uint segment, uint offset);
|
||||
void store_data_byte (uint offset, u8 val);
|
||||
void store_data_byte_abs (uint segment, uint offset, u8 val);
|
||||
void store_data_word (uint offset, u16 val);
|
||||
void store_data_word_abs (uint segment, uint offset, u16 val);
|
||||
void store_data_long (uint offset, u32 val);
|
||||
void store_data_long_abs (uint segment, uint offset, u32 val);
|
||||
u8* decode_rm_byte_register(int reg);
|
||||
u16* decode_rm_word_register(int reg);
|
||||
u32* decode_rm_long_register(int reg);
|
||||
u16* decode_rm_seg_register(int reg);
|
||||
unsigned decode_rm00_address(int rm);
|
||||
unsigned decode_rm01_address(int rm);
|
||||
unsigned decode_rm10_address(int rm);
|
||||
unsigned decode_rmXX_address(int mod, int rm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of "C" linkage for C++ */
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_DECODE_H */
|
@@ -1,945 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* 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: This file contains the code to implement the decoding and
|
||||
* emulation of the FPU instructions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "x86emui.h"
|
||||
|
||||
/*----------------------------- Implementation ----------------------------*/
|
||||
|
||||
/* opcode=0xd8 */
|
||||
void x86emuOp_esc_coprocess_d8(u8 X86EMU_UNUSED(op1))
|
||||
{
|
||||
START_OF_INSTR();
|
||||
DECODE_PRINTF("ESC D8\n");
|
||||
DECODE_CLEAR_SEGOVR();
|
||||
END_OF_INSTR_NO_TRACE();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static const char *x86emu_fpu_op_d9_tab[] = {
|
||||
"FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
|
||||
"FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
|
||||
|
||||
"FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
|
||||
"FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
|
||||
|
||||
"FLD\tDWORD PTR ", "ESC_D9\t", "FST\tDWORD PTR ", "FSTP\tDWORD PTR ",
|
||||
"FLDENV\t", "FLDCW\t", "FSTENV\t", "FSTCW\t",
|
||||
};
|
||||
|
||||
static const char *x86emu_fpu_op_d9_tab1[] = {
|
||||
"FLD\t", "FLD\t", "FLD\t", "FLD\t",
|
||||
"FLD\t", "FLD\t", "FLD\t", "FLD\t",
|
||||
|
||||
"FXCH\t", "FXCH\t", "FXCH\t", "FXCH\t",
|
||||
"FXCH\t", "FXCH\t", "FXCH\t", "FXCH\t",
|
||||
|
||||
"FNOP", "ESC_D9", "ESC_D9", "ESC_D9",
|
||||
"ESC_D9", "ESC_D9", "ESC_D9", "ESC_D9",
|
||||
|
||||
"FSTP\t", "FSTP\t", "FSTP\t", "FSTP\t",
|
||||
"FSTP\t", "FSTP\t", "FSTP\t", "FSTP\t",
|
||||
|
||||
"FCHS", "FABS", "ESC_D9", "ESC_D9",
|
||||
"FTST", "FXAM", "ESC_D9", "ESC_D9",
|
||||
|
||||
"FLD1", "FLDL2T", "FLDL2E", "FLDPI",
|
||||
"FLDLG2", "FLDLN2", "FLDZ", "ESC_D9",
|
||||
|
||||
"F2XM1", "FYL2X", "FPTAN", "FPATAN",
|
||||
"FXTRACT", "ESC_D9", "FDECSTP", "FINCSTP",
|
||||
|
||||
"FPREM", "FYL2XP1", "FSQRT", "ESC_D9",
|
||||
"FRNDINT", "FSCALE", "ESC_D9", "ESC_D9",
|
||||
};
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* opcode=0xd9 */
|
||||
void x86emuOp_esc_coprocess_d9(u8 X86EMU_UNUSED(op1))
|
||||
{
|
||||
int mod, rl, rh;
|
||||
uint destoffset;
|
||||
u8 stkelem;
|
||||
|
||||
START_OF_INSTR();
|
||||
FETCH_DECODE_MODRM(mod, rh, rl);
|
||||
#ifdef DEBUG
|
||||
if (mod != 3) {
|
||||
DECODE_PRINTINSTR32(x86emu_fpu_op_d9_tab, mod, rh, rl);
|
||||
} else {
|
||||
DECODE_PRINTF(x86emu_fpu_op_d9_tab1[(rh << 3) + rl]);
|
||||
}
|
||||
#endif
|
||||
switch (mod) {
|
||||
case 0:
|
||||
destoffset = decode_rm00_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 1:
|
||||
destoffset = decode_rm01_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 2:
|
||||
destoffset = decode_rm10_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 3: /* register to register */
|
||||
stkelem = (u8)rl;
|
||||
if (rh < 4) {
|
||||
DECODE_PRINTF2("ST(%d)\n", stkelem);
|
||||
} else {
|
||||
DECODE_PRINTF("\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef X86EMU_FPU_PRESENT
|
||||
/* execute */
|
||||
switch (mod) {
|
||||
case 3:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_R_fld(X86EMU_FPU_STKTOP, stkelem);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fxch(X86EMU_FPU_STKTOP, stkelem);
|
||||
break;
|
||||
case 2:
|
||||
switch (rl) {
|
||||
case 0:
|
||||
x86emu_fpu_R_nop();
|
||||
break;
|
||||
default:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
x86emu_fpu_R_fstp(X86EMU_FPU_STKTOP, stkelem);
|
||||
break;
|
||||
case 4:
|
||||
switch (rl) {
|
||||
case 0:
|
||||
x86emu_fpu_R_fchs(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fabs(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_R_ftst(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_R_fxam(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
default:
|
||||
/* 2,3,6,7 */
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
switch (rl) {
|
||||
case 0:
|
||||
x86emu_fpu_R_fld1(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fldl2t(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_R_fldl2e(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_R_fldpi(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_R_fldlg2(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_R_fldln2(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_R_fldz(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
default:
|
||||
/* 7 */
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
switch (rl) {
|
||||
case 0:
|
||||
x86emu_fpu_R_f2xm1(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fyl2x(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_R_fptan(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_R_fpatan(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_R_fxtract(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_R_decstp();
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_R_incstp();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
switch (rl) {
|
||||
case 0:
|
||||
x86emu_fpu_R_fprem(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fyl2xp1(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_R_fsqrt(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_R_frndint(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_R_fscale(X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
default:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_M_fld(X86EMU_FPU_FLOAT, destoffset);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_M_fst(X86EMU_FPU_FLOAT, destoffset);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_M_fstp(X86EMU_FPU_FLOAT, destoffset);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_M_fldenv(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_M_fldcw(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_M_fstenv(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_M_fstcw(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* X86EMU_FPU_PRESENT */
|
||||
DECODE_CLEAR_SEGOVR();
|
||||
END_OF_INSTR_NO_TRACE();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static const char *x86emu_fpu_op_da_tab[] = {
|
||||
"FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
|
||||
"FICOMP\tDWORD PTR ",
|
||||
"FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
|
||||
"FIDIVR\tDWORD PTR ",
|
||||
|
||||
"FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
|
||||
"FICOMP\tDWORD PTR ",
|
||||
"FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
|
||||
"FIDIVR\tDWORD PTR ",
|
||||
|
||||
"FIADD\tDWORD PTR ", "FIMUL\tDWORD PTR ", "FICOM\tDWORD PTR ",
|
||||
"FICOMP\tDWORD PTR ",
|
||||
"FISUB\tDWORD PTR ", "FISUBR\tDWORD PTR ", "FIDIV\tDWORD PTR ",
|
||||
"FIDIVR\tDWORD PTR ",
|
||||
|
||||
"ESC_DA ", "ESC_DA ", "ESC_DA ", "ESC_DA ",
|
||||
"ESC_DA ", "ESC_DA ", "ESC_DA ", "ESC_DA ",
|
||||
};
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* opcode=0xda */
|
||||
void x86emuOp_esc_coprocess_da(u8 X86EMU_UNUSED(op1))
|
||||
{
|
||||
int mod, rl, rh;
|
||||
uint destoffset;
|
||||
u8 stkelem;
|
||||
|
||||
START_OF_INSTR();
|
||||
FETCH_DECODE_MODRM(mod, rh, rl);
|
||||
DECODE_PRINTINSTR32(x86emu_fpu_op_da_tab, mod, rh, rl);
|
||||
switch (mod) {
|
||||
case 0:
|
||||
destoffset = decode_rm00_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 1:
|
||||
destoffset = decode_rm01_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 2:
|
||||
destoffset = decode_rm10_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 3: /* register to register */
|
||||
stkelem = (u8)rl;
|
||||
DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
|
||||
break;
|
||||
}
|
||||
#ifdef X86EMU_FPU_PRESENT
|
||||
switch (mod) {
|
||||
case 3:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
default:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_M_iadd(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_M_imul(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_M_icom(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_M_icomp(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_M_isub(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_M_isubr(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_M_idiv(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_M_idivr(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DECODE_CLEAR_SEGOVR();
|
||||
END_OF_INSTR_NO_TRACE();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static const char *x86emu_fpu_op_db_tab[] = {
|
||||
"FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
|
||||
"ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
|
||||
|
||||
"FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
|
||||
"ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
|
||||
|
||||
"FILD\tDWORD PTR ", "ESC_DB\t19", "FIST\tDWORD PTR ", "FISTP\tDWORD PTR ",
|
||||
"ESC_DB\t1C", "FLD\tTBYTE PTR ", "ESC_DB\t1E", "FSTP\tTBYTE PTR ",
|
||||
};
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* opcode=0xdb */
|
||||
void x86emuOp_esc_coprocess_db(u8 X86EMU_UNUSED(op1))
|
||||
{
|
||||
int mod, rl, rh;
|
||||
uint destoffset;
|
||||
|
||||
START_OF_INSTR();
|
||||
FETCH_DECODE_MODRM(mod, rh, rl);
|
||||
#ifdef DEBUG
|
||||
if (mod != 3) {
|
||||
DECODE_PRINTINSTR32(x86emu_fpu_op_db_tab, mod, rh, rl);
|
||||
} else if (rh == 4) { /* === 11 10 0 nnn */
|
||||
switch (rl) {
|
||||
case 0:
|
||||
DECODE_PRINTF("FENI\n");
|
||||
break;
|
||||
case 1:
|
||||
DECODE_PRINTF("FDISI\n");
|
||||
break;
|
||||
case 2:
|
||||
DECODE_PRINTF("FCLEX\n");
|
||||
break;
|
||||
case 3:
|
||||
DECODE_PRINTF("FINIT\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DECODE_PRINTF2("ESC_DB %0x\n", (mod << 6) + (rh << 3) + (rl));
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
switch (mod) {
|
||||
case 0:
|
||||
destoffset = decode_rm00_address(rl);
|
||||
break;
|
||||
case 1:
|
||||
destoffset = decode_rm01_address(rl);
|
||||
break;
|
||||
case 2:
|
||||
destoffset = decode_rm10_address(rl);
|
||||
break;
|
||||
case 3: /* register to register */
|
||||
break;
|
||||
}
|
||||
#ifdef X86EMU_FPU_PRESENT
|
||||
/* execute */
|
||||
switch (mod) {
|
||||
case 3:
|
||||
switch (rh) {
|
||||
case 4:
|
||||
switch (rl) {
|
||||
case 0:
|
||||
x86emu_fpu_R_feni();
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fdisi();
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_R_fclex();
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_R_finit();
|
||||
break;
|
||||
default:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_M_fild(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_M_fist(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_M_fistp(X86EMU_FPU_SHORT, destoffset);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_M_fld(X86EMU_FPU_LDBL, destoffset);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_M_fstp(X86EMU_FPU_LDBL, destoffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DECODE_CLEAR_SEGOVR();
|
||||
END_OF_INSTR_NO_TRACE();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static const char *x86emu_fpu_op_dc_tab[] = {
|
||||
"FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
|
||||
"FCOMP\tQWORD PTR ",
|
||||
"FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
|
||||
"FDIVR\tQWORD PTR ",
|
||||
|
||||
"FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
|
||||
"FCOMP\tQWORD PTR ",
|
||||
"FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
|
||||
"FDIVR\tQWORD PTR ",
|
||||
|
||||
"FADD\tQWORD PTR ", "FMUL\tQWORD PTR ", "FCOM\tQWORD PTR ",
|
||||
"FCOMP\tQWORD PTR ",
|
||||
"FSUB\tQWORD PTR ", "FSUBR\tQWORD PTR ", "FDIV\tQWORD PTR ",
|
||||
"FDIVR\tQWORD PTR ",
|
||||
|
||||
"FADD\t", "FMUL\t", "FCOM\t", "FCOMP\t",
|
||||
"FSUBR\t", "FSUB\t", "FDIVR\t", "FDIV\t",
|
||||
};
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* opcode=0xdc */
|
||||
void x86emuOp_esc_coprocess_dc(u8 X86EMU_UNUSED(op1))
|
||||
{
|
||||
int mod, rl, rh;
|
||||
uint destoffset;
|
||||
u8 stkelem;
|
||||
|
||||
START_OF_INSTR();
|
||||
FETCH_DECODE_MODRM(mod, rh, rl);
|
||||
DECODE_PRINTINSTR32(x86emu_fpu_op_dc_tab, mod, rh, rl);
|
||||
switch (mod) {
|
||||
case 0:
|
||||
destoffset = decode_rm00_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 1:
|
||||
destoffset = decode_rm01_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 2:
|
||||
destoffset = decode_rm10_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 3: /* register to register */
|
||||
stkelem = (u8)rl;
|
||||
DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
|
||||
break;
|
||||
}
|
||||
#ifdef X86EMU_FPU_PRESENT
|
||||
/* execute */
|
||||
switch (mod) {
|
||||
case 3:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_R_fadd(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fmul(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_R_fcom(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_R_fcomp(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_R_fsubr(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_R_fsub(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_R_fdivr(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_R_fdiv(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_M_fadd(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_M_fmul(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_M_fcom(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_M_fcomp(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_M_fsub(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_M_fsubr(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_M_fdiv(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_M_fdivr(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DECODE_CLEAR_SEGOVR();
|
||||
END_OF_INSTR_NO_TRACE();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static const char *x86emu_fpu_op_dd_tab[] = {
|
||||
"FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
|
||||
"FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
|
||||
|
||||
"FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
|
||||
"FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
|
||||
|
||||
"FLD\tQWORD PTR ", "ESC_DD\t29,", "FST\tQWORD PTR ", "FSTP\tQWORD PTR ",
|
||||
"FRSTOR\t", "ESC_DD\t2D,", "FSAVE\t", "FSTSW\t",
|
||||
|
||||
"FFREE\t", "FXCH\t", "FST\t", "FSTP\t",
|
||||
"ESC_DD\t2C,", "ESC_DD\t2D,", "ESC_DD\t2E,", "ESC_DD\t2F,",
|
||||
};
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* opcode=0xdd */
|
||||
void x86emuOp_esc_coprocess_dd(u8 X86EMU_UNUSED(op1))
|
||||
{
|
||||
int mod, rl, rh;
|
||||
uint destoffset;
|
||||
u8 stkelem;
|
||||
|
||||
START_OF_INSTR();
|
||||
FETCH_DECODE_MODRM(mod, rh, rl);
|
||||
DECODE_PRINTINSTR32(x86emu_fpu_op_dd_tab, mod, rh, rl);
|
||||
switch (mod) {
|
||||
case 0:
|
||||
destoffset = decode_rm00_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 1:
|
||||
destoffset = decode_rm01_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 2:
|
||||
destoffset = decode_rm10_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 3: /* register to register */
|
||||
stkelem = (u8)rl;
|
||||
DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
|
||||
break;
|
||||
}
|
||||
#ifdef X86EMU_FPU_PRESENT
|
||||
switch (mod) {
|
||||
case 3:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_R_ffree(stkelem);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fxch(stkelem);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_R_fst(stkelem); /* register version */
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_R_fstp(stkelem); /* register version */
|
||||
break;
|
||||
default:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_M_fld(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_M_fst(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_M_fstp(X86EMU_FPU_DOUBLE, destoffset);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_M_frstor(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_M_fsave(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_M_fstsw(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DECODE_CLEAR_SEGOVR();
|
||||
END_OF_INSTR_NO_TRACE();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static const char *x86emu_fpu_op_de_tab[] =
|
||||
{
|
||||
"FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
|
||||
"FICOMP\tWORD PTR ",
|
||||
"FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
|
||||
"FIDIVR\tWORD PTR ",
|
||||
|
||||
"FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
|
||||
"FICOMP\tWORD PTR ",
|
||||
"FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
|
||||
"FIDIVR\tWORD PTR ",
|
||||
|
||||
"FIADD\tWORD PTR ", "FIMUL\tWORD PTR ", "FICOM\tWORD PTR ",
|
||||
"FICOMP\tWORD PTR ",
|
||||
"FISUB\tWORD PTR ", "FISUBR\tWORD PTR ", "FIDIV\tWORD PTR ",
|
||||
"FIDIVR\tWORD PTR ",
|
||||
|
||||
"FADDP\t", "FMULP\t", "FCOMP\t", "FCOMPP\t",
|
||||
"FSUBRP\t", "FSUBP\t", "FDIVRP\t", "FDIVP\t",
|
||||
};
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* opcode=0xde */
|
||||
void x86emuOp_esc_coprocess_de(u8 X86EMU_UNUSED(op1))
|
||||
{
|
||||
int mod, rl, rh;
|
||||
uint destoffset;
|
||||
u8 stkelem;
|
||||
|
||||
START_OF_INSTR();
|
||||
FETCH_DECODE_MODRM(mod, rh, rl);
|
||||
DECODE_PRINTINSTR32(x86emu_fpu_op_de_tab, mod, rh, rl);
|
||||
switch (mod) {
|
||||
case 0:
|
||||
destoffset = decode_rm00_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 1:
|
||||
destoffset = decode_rm01_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 2:
|
||||
destoffset = decode_rm10_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 3: /* register to register */
|
||||
stkelem = (u8)rl;
|
||||
DECODE_PRINTF2("\tST(%d),ST\n", stkelem);
|
||||
break;
|
||||
}
|
||||
#ifdef X86EMU_FPU_PRESENT
|
||||
switch (mod) {
|
||||
case 3:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_R_faddp(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fmulp(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_R_fcomp(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 3:
|
||||
if (stkelem == 1)
|
||||
x86emu_fpu_R_fcompp(stkelem, X86EMU_FPU_STKTOP);
|
||||
else
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_R_fsubrp(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_R_fsubp(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_R_fdivrp(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_R_fdivp(stkelem, X86EMU_FPU_STKTOP);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_M_fiadd(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_M_fimul(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_M_ficom(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_M_ficomp(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_M_fisub(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_M_fisubr(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_M_fidiv(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_M_fidivr(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DECODE_CLEAR_SEGOVR();
|
||||
END_OF_INSTR_NO_TRACE();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static const char *x86emu_fpu_op_df_tab[] = {
|
||||
/* mod == 00 */
|
||||
"FILD\tWORD PTR ", "ESC_DF\t39\n", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
|
||||
"FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
|
||||
"FISTP\tQWORD PTR ",
|
||||
|
||||
/* mod == 01 */
|
||||
"FILD\tWORD PTR ", "ESC_DF\t39 ", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
|
||||
"FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
|
||||
"FISTP\tQWORD PTR ",
|
||||
|
||||
/* mod == 10 */
|
||||
"FILD\tWORD PTR ", "ESC_DF\t39 ", "FIST\tWORD PTR ", "FISTP\tWORD PTR ",
|
||||
"FBLD\tTBYTE PTR ", "FILD\tQWORD PTR ", "FBSTP\tTBYTE PTR ",
|
||||
"FISTP\tQWORD PTR ",
|
||||
|
||||
/* mod == 11 */
|
||||
"FFREE\t", "FXCH\t", "FST\t", "FSTP\t",
|
||||
"ESC_DF\t3C,", "ESC_DF\t3D,", "ESC_DF\t3E,", "ESC_DF\t3F,"
|
||||
};
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* opcode=0xdf */
|
||||
void x86emuOp_esc_coprocess_df(u8 X86EMU_UNUSED(op1))
|
||||
{
|
||||
int mod, rl, rh;
|
||||
uint destoffset;
|
||||
u8 stkelem;
|
||||
|
||||
START_OF_INSTR();
|
||||
FETCH_DECODE_MODRM(mod, rh, rl);
|
||||
DECODE_PRINTINSTR32(x86emu_fpu_op_df_tab, mod, rh, rl);
|
||||
switch (mod) {
|
||||
case 0:
|
||||
destoffset = decode_rm00_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 1:
|
||||
destoffset = decode_rm01_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 2:
|
||||
destoffset = decode_rm10_address(rl);
|
||||
DECODE_PRINTF("\n");
|
||||
break;
|
||||
case 3: /* register to register */
|
||||
stkelem = (u8)rl;
|
||||
DECODE_PRINTF2("\tST(%d)\n", stkelem);
|
||||
break;
|
||||
}
|
||||
#ifdef X86EMU_FPU_PRESENT
|
||||
switch (mod) {
|
||||
case 3:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_R_ffree(stkelem);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_R_fxch(stkelem);
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_R_fst(stkelem); /* register version */
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_R_fstp(stkelem); /* register version */
|
||||
break;
|
||||
default:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (rh) {
|
||||
case 0:
|
||||
x86emu_fpu_M_fild(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 1:
|
||||
x86emu_fpu_illegal();
|
||||
break;
|
||||
case 2:
|
||||
x86emu_fpu_M_fist(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 3:
|
||||
x86emu_fpu_M_fistp(X86EMU_FPU_WORD, destoffset);
|
||||
break;
|
||||
case 4:
|
||||
x86emu_fpu_M_fbld(X86EMU_FPU_BSD, destoffset);
|
||||
break;
|
||||
case 5:
|
||||
x86emu_fpu_M_fild(X86EMU_FPU_LONG, destoffset);
|
||||
break;
|
||||
case 6:
|
||||
x86emu_fpu_M_fbstp(X86EMU_FPU_BSD, destoffset);
|
||||
break;
|
||||
case 7:
|
||||
x86emu_fpu_M_fistp(X86EMU_FPU_LONG, destoffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DECODE_CLEAR_SEGOVR();
|
||||
END_OF_INSTR_NO_TRACE();
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 FPU instruction decoding.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __X86EMU_FPU_H
|
||||
#define __X86EMU_FPU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Use "C" linkage when in C++ mode */
|
||||
#endif
|
||||
|
||||
/* these have to be defined, whether 8087 support compiled in or not. */
|
||||
|
||||
extern void x86emuOp_esc_coprocess_d8 (u8 op1);
|
||||
extern void x86emuOp_esc_coprocess_d9 (u8 op1);
|
||||
extern void x86emuOp_esc_coprocess_da (u8 op1);
|
||||
extern void x86emuOp_esc_coprocess_db (u8 op1);
|
||||
extern void x86emuOp_esc_coprocess_dc (u8 op1);
|
||||
extern void x86emuOp_esc_coprocess_dd (u8 op1);
|
||||
extern void x86emuOp_esc_coprocess_de (u8 op1);
|
||||
extern void x86emuOp_esc_coprocess_df (u8 op1);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of "C" linkage for C++ */
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_FPU_H */
|
File diff suppressed because it is too large
Load Diff
@@ -1,47 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 operand decoding functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __X86EMU_OPS_H
|
||||
#define __X86EMU_OPS_H
|
||||
|
||||
extern void (*x86emu_optab[0x100])(u8 op1);
|
||||
extern void (*x86emu_optab2[0x100])(u8 op2);
|
||||
|
||||
int x86emu_check_jump_condition(u8 op);
|
||||
|
||||
#endif /* __X86EMU_OPS_H */
|
File diff suppressed because it is too large
Load Diff
@@ -1,971 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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: Watcom C++ 10.6 or later
|
||||
* Environment: Any
|
||||
* Developer: Kendall Bennett
|
||||
*
|
||||
* Description: Inline assembler versions of the primitive operand
|
||||
* functions for faster performance. At the moment this is
|
||||
* x86 inline assembler, but these functions could be replaced
|
||||
* with native inline assembler for each supported processor
|
||||
* platform.
|
||||
*
|
||||
****************************************************************************/
|
||||
/* $XFree86: xc/extras/x86emu/src/x86emu/x86emu/prim_asm.h,v 1.3 2000/04/19 15:48:15 tsi Exp $ */
|
||||
|
||||
#ifndef __X86EMU_PRIM_ASM_H
|
||||
#define __X86EMU_PRIM_ASM_H
|
||||
|
||||
#ifdef __WATCOMC__
|
||||
|
||||
#ifndef VALIDATE
|
||||
#define __HAVE_INLINE_ASSEMBLER__
|
||||
#endif
|
||||
|
||||
u32 get_flags_asm(void);
|
||||
#pragma aux get_flags_asm = \
|
||||
"pushf" \
|
||||
"pop eax" \
|
||||
value [eax] \
|
||||
modify exact [eax];
|
||||
|
||||
u16 aaa_word_asm(u32 *flags,u16 d);
|
||||
#pragma aux aaa_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"aaa" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] \
|
||||
value [ax] \
|
||||
modify exact [ax];
|
||||
|
||||
u16 aas_word_asm(u32 *flags,u16 d);
|
||||
#pragma aux aas_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"aas" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] \
|
||||
value [ax] \
|
||||
modify exact [ax];
|
||||
|
||||
u16 aad_word_asm(u32 *flags,u16 d);
|
||||
#pragma aux aad_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"aad" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] \
|
||||
value [ax] \
|
||||
modify exact [ax];
|
||||
|
||||
u16 aam_word_asm(u32 *flags,u8 d);
|
||||
#pragma aux aam_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"aam" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] \
|
||||
value [ax] \
|
||||
modify exact [ax];
|
||||
|
||||
u8 adc_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux adc_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"adc al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
value [al] \
|
||||
modify exact [al bl];
|
||||
|
||||
u16 adc_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux adc_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"adc ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
value [ax] \
|
||||
modify exact [ax bx];
|
||||
|
||||
u32 adc_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux adc_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"adc eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
value [eax] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
u8 add_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux add_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"add al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
value [al] \
|
||||
modify exact [al bl];
|
||||
|
||||
u16 add_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux add_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"add ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
value [ax] \
|
||||
modify exact [ax bx];
|
||||
|
||||
u32 add_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux add_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"add eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
value [eax] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
u8 and_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux and_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"and al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
value [al] \
|
||||
modify exact [al bl];
|
||||
|
||||
u16 and_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux and_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"and ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
value [ax] \
|
||||
modify exact [ax bx];
|
||||
|
||||
u32 and_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux and_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"and eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
value [eax] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
u8 cmp_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux cmp_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"cmp al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
value [al] \
|
||||
modify exact [al bl];
|
||||
|
||||
u16 cmp_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux cmp_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"cmp ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
value [ax] \
|
||||
modify exact [ax bx];
|
||||
|
||||
u32 cmp_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux cmp_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"cmp eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
value [eax] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
u8 daa_byte_asm(u32 *flags,u8 d);
|
||||
#pragma aux daa_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"daa" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] \
|
||||
value [al] \
|
||||
modify exact [al];
|
||||
|
||||
u8 das_byte_asm(u32 *flags,u8 d);
|
||||
#pragma aux das_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"das" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] \
|
||||
value [al] \
|
||||
modify exact [al];
|
||||
|
||||
u8 dec_byte_asm(u32 *flags,u8 d);
|
||||
#pragma aux dec_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"dec al" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] \
|
||||
value [al] \
|
||||
modify exact [al];
|
||||
|
||||
u16 dec_word_asm(u32 *flags,u16 d);
|
||||
#pragma aux dec_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"dec ax" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] \
|
||||
value [ax] \
|
||||
modify exact [ax];
|
||||
|
||||
u32 dec_long_asm(u32 *flags,u32 d);
|
||||
#pragma aux dec_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"dec eax" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] \
|
||||
value [eax] \
|
||||
modify exact [eax];
|
||||
|
||||
u8 inc_byte_asm(u32 *flags,u8 d);
|
||||
#pragma aux inc_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"inc al" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] \
|
||||
value [al] \
|
||||
modify exact [al];
|
||||
|
||||
u16 inc_word_asm(u32 *flags,u16 d);
|
||||
#pragma aux inc_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"inc ax" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] \
|
||||
value [ax] \
|
||||
modify exact [ax];
|
||||
|
||||
u32 inc_long_asm(u32 *flags,u32 d);
|
||||
#pragma aux inc_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"inc eax" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] \
|
||||
value [eax] \
|
||||
modify exact [eax];
|
||||
|
||||
u8 or_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux or_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"or al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
value [al] \
|
||||
modify exact [al bl];
|
||||
|
||||
u16 or_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux or_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"or ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
value [ax] \
|
||||
modify exact [ax bx];
|
||||
|
||||
u32 or_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux or_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"or eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
value [eax] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
u8 neg_byte_asm(u32 *flags,u8 d);
|
||||
#pragma aux neg_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"neg al" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] \
|
||||
value [al] \
|
||||
modify exact [al];
|
||||
|
||||
u16 neg_word_asm(u32 *flags,u16 d);
|
||||
#pragma aux neg_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"neg ax" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] \
|
||||
value [ax] \
|
||||
modify exact [ax];
|
||||
|
||||
u32 neg_long_asm(u32 *flags,u32 d);
|
||||
#pragma aux neg_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"neg eax" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] \
|
||||
value [eax] \
|
||||
modify exact [eax];
|
||||
|
||||
u8 not_byte_asm(u32 *flags,u8 d);
|
||||
#pragma aux not_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"not al" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] \
|
||||
value [al] \
|
||||
modify exact [al];
|
||||
|
||||
u16 not_word_asm(u32 *flags,u16 d);
|
||||
#pragma aux not_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"not ax" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] \
|
||||
value [ax] \
|
||||
modify exact [ax];
|
||||
|
||||
u32 not_long_asm(u32 *flags,u32 d);
|
||||
#pragma aux not_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"not eax" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] \
|
||||
value [eax] \
|
||||
modify exact [eax];
|
||||
|
||||
u8 rcl_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux rcl_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rcl al,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [cl] \
|
||||
value [al] \
|
||||
modify exact [al cl];
|
||||
|
||||
u16 rcl_word_asm(u32 *flags,u16 d, u8 s);
|
||||
#pragma aux rcl_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rcl ax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax cl];
|
||||
|
||||
u32 rcl_long_asm(u32 *flags,u32 d, u8 s);
|
||||
#pragma aux rcl_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rcl eax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax cl];
|
||||
|
||||
u8 rcr_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux rcr_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rcr al,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [cl] \
|
||||
value [al] \
|
||||
modify exact [al cl];
|
||||
|
||||
u16 rcr_word_asm(u32 *flags,u16 d, u8 s);
|
||||
#pragma aux rcr_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rcr ax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax cl];
|
||||
|
||||
u32 rcr_long_asm(u32 *flags,u32 d, u8 s);
|
||||
#pragma aux rcr_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rcr eax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax cl];
|
||||
|
||||
u8 rol_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux rol_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rol al,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [cl] \
|
||||
value [al] \
|
||||
modify exact [al cl];
|
||||
|
||||
u16 rol_word_asm(u32 *flags,u16 d, u8 s);
|
||||
#pragma aux rol_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rol ax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax cl];
|
||||
|
||||
u32 rol_long_asm(u32 *flags,u32 d, u8 s);
|
||||
#pragma aux rol_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"rol eax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax cl];
|
||||
|
||||
u8 ror_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux ror_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"ror al,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [cl] \
|
||||
value [al] \
|
||||
modify exact [al cl];
|
||||
|
||||
u16 ror_word_asm(u32 *flags,u16 d, u8 s);
|
||||
#pragma aux ror_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"ror ax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax cl];
|
||||
|
||||
u32 ror_long_asm(u32 *flags,u32 d, u8 s);
|
||||
#pragma aux ror_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"ror eax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax cl];
|
||||
|
||||
u8 shl_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux shl_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shl al,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [cl] \
|
||||
value [al] \
|
||||
modify exact [al cl];
|
||||
|
||||
u16 shl_word_asm(u32 *flags,u16 d, u8 s);
|
||||
#pragma aux shl_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shl ax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax cl];
|
||||
|
||||
u32 shl_long_asm(u32 *flags,u32 d, u8 s);
|
||||
#pragma aux shl_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shl eax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax cl];
|
||||
|
||||
u8 shr_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux shr_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shr al,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [cl] \
|
||||
value [al] \
|
||||
modify exact [al cl];
|
||||
|
||||
u16 shr_word_asm(u32 *flags,u16 d, u8 s);
|
||||
#pragma aux shr_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shr ax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax cl];
|
||||
|
||||
u32 shr_long_asm(u32 *flags,u32 d, u8 s);
|
||||
#pragma aux shr_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shr eax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax cl];
|
||||
|
||||
u8 sar_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux sar_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sar al,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [cl] \
|
||||
value [al] \
|
||||
modify exact [al cl];
|
||||
|
||||
u16 sar_word_asm(u32 *flags,u16 d, u8 s);
|
||||
#pragma aux sar_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sar ax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax cl];
|
||||
|
||||
u32 sar_long_asm(u32 *flags,u32 d, u8 s);
|
||||
#pragma aux sar_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sar eax,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax cl];
|
||||
|
||||
u16 shld_word_asm(u32 *flags,u16 d, u16 fill, u8 s);
|
||||
#pragma aux shld_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shld ax,dx,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [dx] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax dx cl];
|
||||
|
||||
u32 shld_long_asm(u32 *flags,u32 d, u32 fill, u8 s);
|
||||
#pragma aux shld_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shld eax,edx,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [edx] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax edx cl];
|
||||
|
||||
u16 shrd_word_asm(u32 *flags,u16 d, u16 fill, u8 s);
|
||||
#pragma aux shrd_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shrd ax,dx,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [dx] [cl] \
|
||||
value [ax] \
|
||||
modify exact [ax dx cl];
|
||||
|
||||
u32 shrd_long_asm(u32 *flags,u32 d, u32 fill, u8 s);
|
||||
#pragma aux shrd_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"shrd eax,edx,cl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [edx] [cl] \
|
||||
value [eax] \
|
||||
modify exact [eax edx cl];
|
||||
|
||||
u8 sbb_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux sbb_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sbb al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
value [al] \
|
||||
modify exact [al bl];
|
||||
|
||||
u16 sbb_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux sbb_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sbb ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
value [ax] \
|
||||
modify exact [ax bx];
|
||||
|
||||
u32 sbb_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux sbb_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sbb eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
value [eax] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
u8 sub_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux sub_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sub al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
value [al] \
|
||||
modify exact [al bl];
|
||||
|
||||
u16 sub_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux sub_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sub ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
value [ax] \
|
||||
modify exact [ax bx];
|
||||
|
||||
u32 sub_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux sub_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"sub eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
value [eax] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
void test_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux test_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"test al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
modify exact [al bl];
|
||||
|
||||
void test_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux test_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"test ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
modify exact [ax bx];
|
||||
|
||||
void test_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux test_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"test eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
u8 xor_byte_asm(u32 *flags,u8 d, u8 s);
|
||||
#pragma aux xor_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"xor al,bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [al] [bl] \
|
||||
value [al] \
|
||||
modify exact [al bl];
|
||||
|
||||
u16 xor_word_asm(u32 *flags,u16 d, u16 s);
|
||||
#pragma aux xor_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"xor ax,bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [ax] [bx] \
|
||||
value [ax] \
|
||||
modify exact [ax bx];
|
||||
|
||||
u32 xor_long_asm(u32 *flags,u32 d, u32 s);
|
||||
#pragma aux xor_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"xor eax,ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
parm [edi] [eax] [ebx] \
|
||||
value [eax] \
|
||||
modify exact [eax ebx];
|
||||
|
||||
void imul_byte_asm(u32 *flags,u16 *ax,u8 d,u8 s);
|
||||
#pragma aux imul_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"imul bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],ax" \
|
||||
parm [edi] [esi] [al] [bl] \
|
||||
modify exact [esi ax bl];
|
||||
|
||||
void imul_word_asm(u32 *flags,u16 *ax,u16 *dx,u16 d,u16 s);
|
||||
#pragma aux imul_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"imul bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],ax" \
|
||||
"mov [ecx],dx" \
|
||||
parm [edi] [esi] [ecx] [ax] [bx]\
|
||||
modify exact [esi edi ax bx dx];
|
||||
|
||||
void imul_long_asm(u32 *flags,u32 *eax,u32 *edx,u32 d,u32 s);
|
||||
#pragma aux imul_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"imul ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],eax" \
|
||||
"mov [ecx],edx" \
|
||||
parm [edi] [esi] [ecx] [eax] [ebx] \
|
||||
modify exact [esi edi eax ebx edx];
|
||||
|
||||
void mul_byte_asm(u32 *flags,u16 *ax,u8 d,u8 s);
|
||||
#pragma aux mul_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"mul bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],ax" \
|
||||
parm [edi] [esi] [al] [bl] \
|
||||
modify exact [esi ax bl];
|
||||
|
||||
void mul_word_asm(u32 *flags,u16 *ax,u16 *dx,u16 d,u16 s);
|
||||
#pragma aux mul_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"mul bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],ax" \
|
||||
"mov [ecx],dx" \
|
||||
parm [edi] [esi] [ecx] [ax] [bx]\
|
||||
modify exact [esi edi ax bx dx];
|
||||
|
||||
void mul_long_asm(u32 *flags,u32 *eax,u32 *edx,u32 d,u32 s);
|
||||
#pragma aux mul_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"mul ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],eax" \
|
||||
"mov [ecx],edx" \
|
||||
parm [edi] [esi] [ecx] [eax] [ebx] \
|
||||
modify exact [esi edi eax ebx edx];
|
||||
|
||||
void idiv_byte_asm(u32 *flags,u8 *al,u8 *ah,u16 d,u8 s);
|
||||
#pragma aux idiv_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"idiv bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],al" \
|
||||
"mov [ecx],ah" \
|
||||
parm [edi] [esi] [ecx] [ax] [bl]\
|
||||
modify exact [esi edi ax bl];
|
||||
|
||||
void idiv_word_asm(u32 *flags,u16 *ax,u16 *dx,u16 dlo,u16 dhi,u16 s);
|
||||
#pragma aux idiv_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"idiv bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],ax" \
|
||||
"mov [ecx],dx" \
|
||||
parm [edi] [esi] [ecx] [ax] [dx] [bx]\
|
||||
modify exact [esi edi ax dx bx];
|
||||
|
||||
void idiv_long_asm(u32 *flags,u32 *eax,u32 *edx,u32 dlo,u32 dhi,u32 s);
|
||||
#pragma aux idiv_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"idiv ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],eax" \
|
||||
"mov [ecx],edx" \
|
||||
parm [edi] [esi] [ecx] [eax] [edx] [ebx]\
|
||||
modify exact [esi edi eax edx ebx];
|
||||
|
||||
void div_byte_asm(u32 *flags,u8 *al,u8 *ah,u16 d,u8 s);
|
||||
#pragma aux div_byte_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"div bl" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],al" \
|
||||
"mov [ecx],ah" \
|
||||
parm [edi] [esi] [ecx] [ax] [bl]\
|
||||
modify exact [esi edi ax bl];
|
||||
|
||||
void div_word_asm(u32 *flags,u16 *ax,u16 *dx,u16 dlo,u16 dhi,u16 s);
|
||||
#pragma aux div_word_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"div bx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],ax" \
|
||||
"mov [ecx],dx" \
|
||||
parm [edi] [esi] [ecx] [ax] [dx] [bx]\
|
||||
modify exact [esi edi ax dx bx];
|
||||
|
||||
void div_long_asm(u32 *flags,u32 *eax,u32 *edx,u32 dlo,u32 dhi,u32 s);
|
||||
#pragma aux div_long_asm = \
|
||||
"push [edi]" \
|
||||
"popf" \
|
||||
"div ebx" \
|
||||
"pushf" \
|
||||
"pop [edi]" \
|
||||
"mov [esi],eax" \
|
||||
"mov [ecx],edx" \
|
||||
parm [edi] [esi] [ecx] [eax] [edx] [ebx]\
|
||||
modify exact [esi edi eax edx ebx];
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_PRIM_ASM_H */
|
File diff suppressed because it is too large
Load Diff
@@ -1,232 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 primitive operation functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __X86EMU_PRIM_OPS_H
|
||||
#define __X86EMU_PRIM_OPS_H
|
||||
|
||||
#include "prim_asm.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Use "C" linkage when in C++ mode */
|
||||
#endif
|
||||
|
||||
u16 aaa_word (u16 d);
|
||||
u16 aas_word (u16 d);
|
||||
u16 aad_word (u16 d);
|
||||
u16 aam_word (u8 d);
|
||||
u8 adc_byte (u8 d, u8 s);
|
||||
u16 adc_word (u16 d, u16 s);
|
||||
u32 adc_long (u32 d, u32 s);
|
||||
u8 add_byte (u8 d, u8 s);
|
||||
u16 add_word (u16 d, u16 s);
|
||||
u32 add_long (u32 d, u32 s);
|
||||
u8 and_byte (u8 d, u8 s);
|
||||
u16 and_word (u16 d, u16 s);
|
||||
u32 and_long (u32 d, u32 s);
|
||||
u8 cmp_byte (u8 d, u8 s);
|
||||
u16 cmp_word (u16 d, u16 s);
|
||||
u32 cmp_long (u32 d, u32 s);
|
||||
u8 daa_byte (u8 d);
|
||||
u8 das_byte (u8 d);
|
||||
u8 dec_byte (u8 d);
|
||||
u16 dec_word (u16 d);
|
||||
u32 dec_long (u32 d);
|
||||
u8 inc_byte (u8 d);
|
||||
u16 inc_word (u16 d);
|
||||
u32 inc_long (u32 d);
|
||||
u8 or_byte (u8 d, u8 s);
|
||||
u16 or_word (u16 d, u16 s);
|
||||
u32 or_long (u32 d, u32 s);
|
||||
u8 neg_byte (u8 s);
|
||||
u16 neg_word (u16 s);
|
||||
u32 neg_long (u32 s);
|
||||
u8 not_byte (u8 s);
|
||||
u16 not_word (u16 s);
|
||||
u32 not_long (u32 s);
|
||||
u8 rcl_byte (u8 d, u8 s);
|
||||
u16 rcl_word (u16 d, u8 s);
|
||||
u32 rcl_long (u32 d, u8 s);
|
||||
u8 rcr_byte (u8 d, u8 s);
|
||||
u16 rcr_word (u16 d, u8 s);
|
||||
u32 rcr_long (u32 d, u8 s);
|
||||
u8 rol_byte (u8 d, u8 s);
|
||||
u16 rol_word (u16 d, u8 s);
|
||||
u32 rol_long (u32 d, u8 s);
|
||||
u8 ror_byte (u8 d, u8 s);
|
||||
u16 ror_word (u16 d, u8 s);
|
||||
u32 ror_long (u32 d, u8 s);
|
||||
u8 shl_byte (u8 d, u8 s);
|
||||
u16 shl_word (u16 d, u8 s);
|
||||
u32 shl_long (u32 d, u8 s);
|
||||
u8 shr_byte (u8 d, u8 s);
|
||||
u16 shr_word (u16 d, u8 s);
|
||||
u32 shr_long (u32 d, u8 s);
|
||||
u8 sar_byte (u8 d, u8 s);
|
||||
u16 sar_word (u16 d, u8 s);
|
||||
u32 sar_long (u32 d, u8 s);
|
||||
u16 shld_word (u16 d, u16 fill, u8 s);
|
||||
u32 shld_long (u32 d, u32 fill, u8 s);
|
||||
u16 shrd_word (u16 d, u16 fill, u8 s);
|
||||
u32 shrd_long (u32 d, u32 fill, u8 s);
|
||||
u8 sbb_byte (u8 d, u8 s);
|
||||
u16 sbb_word (u16 d, u16 s);
|
||||
u32 sbb_long (u32 d, u32 s);
|
||||
u8 sub_byte (u8 d, u8 s);
|
||||
u16 sub_word (u16 d, u16 s);
|
||||
u32 sub_long (u32 d, u32 s);
|
||||
void test_byte (u8 d, u8 s);
|
||||
void test_word (u16 d, u16 s);
|
||||
void test_long (u32 d, u32 s);
|
||||
u8 xor_byte (u8 d, u8 s);
|
||||
u16 xor_word (u16 d, u16 s);
|
||||
u32 xor_long (u32 d, u32 s);
|
||||
void imul_byte (u8 s);
|
||||
void imul_word (u16 s);
|
||||
void imul_long (u32 s);
|
||||
void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s);
|
||||
void mul_byte (u8 s);
|
||||
void mul_word (u16 s);
|
||||
void mul_long (u32 s);
|
||||
void idiv_byte (u8 s);
|
||||
void idiv_word (u16 s);
|
||||
void idiv_long (u32 s);
|
||||
void div_byte (u8 s);
|
||||
void div_word (u16 s);
|
||||
void div_long (u32 s);
|
||||
void ins (int size);
|
||||
void outs (int size);
|
||||
u16 mem_access_word (int addr);
|
||||
void push_word (u16 w);
|
||||
void push_long (u32 w);
|
||||
u16 pop_word (void);
|
||||
u32 pop_long (void);
|
||||
void x86emu_cpuid (void);
|
||||
|
||||
#if defined(__HAVE_INLINE_ASSEMBLER__) && !defined(PRIM_OPS_NO_REDEFINE_ASM)
|
||||
|
||||
#define aaa_word(d) aaa_word_asm(&M.x86.R_EFLG,d)
|
||||
#define aas_word(d) aas_word_asm(&M.x86.R_EFLG,d)
|
||||
#define aad_word(d) aad_word_asm(&M.x86.R_EFLG,d)
|
||||
#define aam_word(d) aam_word_asm(&M.x86.R_EFLG,d)
|
||||
#define adc_byte(d,s) adc_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define adc_word(d,s) adc_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define adc_long(d,s) adc_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define add_byte(d,s) add_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define add_word(d,s) add_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define add_long(d,s) add_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define and_byte(d,s) and_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define and_word(d,s) and_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define and_long(d,s) and_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define cmp_byte(d,s) cmp_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define cmp_word(d,s) cmp_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define cmp_long(d,s) cmp_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define daa_byte(d) daa_byte_asm(&M.x86.R_EFLG,d)
|
||||
#define das_byte(d) das_byte_asm(&M.x86.R_EFLG,d)
|
||||
#define dec_byte(d) dec_byte_asm(&M.x86.R_EFLG,d)
|
||||
#define dec_word(d) dec_word_asm(&M.x86.R_EFLG,d)
|
||||
#define dec_long(d) dec_long_asm(&M.x86.R_EFLG,d)
|
||||
#define inc_byte(d) inc_byte_asm(&M.x86.R_EFLG,d)
|
||||
#define inc_word(d) inc_word_asm(&M.x86.R_EFLG,d)
|
||||
#define inc_long(d) inc_long_asm(&M.x86.R_EFLG,d)
|
||||
#define or_byte(d,s) or_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define or_word(d,s) or_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define or_long(d,s) or_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define neg_byte(s) neg_byte_asm(&M.x86.R_EFLG,s)
|
||||
#define neg_word(s) neg_word_asm(&M.x86.R_EFLG,s)
|
||||
#define neg_long(s) neg_long_asm(&M.x86.R_EFLG,s)
|
||||
#define not_byte(s) not_byte_asm(&M.x86.R_EFLG,s)
|
||||
#define not_word(s) not_word_asm(&M.x86.R_EFLG,s)
|
||||
#define not_long(s) not_long_asm(&M.x86.R_EFLG,s)
|
||||
#define rcl_byte(d,s) rcl_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define rcl_word(d,s) rcl_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define rcl_long(d,s) rcl_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define rcr_byte(d,s) rcr_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define rcr_word(d,s) rcr_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define rcr_long(d,s) rcr_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define rol_byte(d,s) rol_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define rol_word(d,s) rol_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define rol_long(d,s) rol_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define ror_byte(d,s) ror_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define ror_word(d,s) ror_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define ror_long(d,s) ror_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define shl_byte(d,s) shl_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define shl_word(d,s) shl_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define shl_long(d,s) shl_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define shr_byte(d,s) shr_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define shr_word(d,s) shr_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define shr_long(d,s) shr_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define sar_byte(d,s) sar_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define sar_word(d,s) sar_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define sar_long(d,s) sar_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define shld_word(d,fill,s) shld_word_asm(&M.x86.R_EFLG,d,fill,s)
|
||||
#define shld_long(d,fill,s) shld_long_asm(&M.x86.R_EFLG,d,fill,s)
|
||||
#define shrd_word(d,fill,s) shrd_word_asm(&M.x86.R_EFLG,d,fill,s)
|
||||
#define shrd_long(d,fill,s) shrd_long_asm(&M.x86.R_EFLG,d,fill,s)
|
||||
#define sbb_byte(d,s) sbb_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define sbb_word(d,s) sbb_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define sbb_long(d,s) sbb_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define sub_byte(d,s) sub_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define sub_word(d,s) sub_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define sub_long(d,s) sub_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define test_byte(d,s) test_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define test_word(d,s) test_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define test_long(d,s) test_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define xor_byte(d,s) xor_byte_asm(&M.x86.R_EFLG,d,s)
|
||||
#define xor_word(d,s) xor_word_asm(&M.x86.R_EFLG,d,s)
|
||||
#define xor_long(d,s) xor_long_asm(&M.x86.R_EFLG,d,s)
|
||||
#define imul_byte(s) imul_byte_asm(&M.x86.R_EFLG,&M.x86.R_AX,M.x86.R_AL,s)
|
||||
#define imul_word(s) imul_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,s)
|
||||
#define imul_long(s) imul_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s)
|
||||
#define imul_long_direct(res_lo,res_hi,d,s) imul_long_asm(&M.x86.R_EFLG,res_lo,res_hi,d,s)
|
||||
#define mul_byte(s) mul_byte_asm(&M.x86.R_EFLG,&M.x86.R_AX,M.x86.R_AL,s)
|
||||
#define mul_word(s) mul_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,s)
|
||||
#define mul_long(s) mul_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s)
|
||||
#define idiv_byte(s) idiv_byte_asm(&M.x86.R_EFLG,&M.x86.R_AL,&M.x86.R_AH,M.x86.R_AX,s)
|
||||
#define idiv_word(s) idiv_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,M.x86.R_DX,s)
|
||||
#define idiv_long(s) idiv_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,M.x86.R_EDX,s)
|
||||
#define div_byte(s) div_byte_asm(&M.x86.R_EFLG,&M.x86.R_AL,&M.x86.R_AH,M.x86.R_AX,s)
|
||||
#define div_word(s) div_word_asm(&M.x86.R_EFLG,&M.x86.R_AX,&M.x86.R_DX,M.x86.R_AX,M.x86.R_DX,s)
|
||||
#define div_long(s) div_long_asm(&M.x86.R_EFLG,&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,M.x86.R_EDX,s)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of "C" linkage for C++ */
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_PRIM_OPS_H */
|
@@ -1,406 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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: This file includes subroutines which are related to
|
||||
* programmed I/O and memory access. Included in this module
|
||||
* are default functions with limited usefulness. For real
|
||||
* uses these functions will most likely be overriden by the
|
||||
* user library.
|
||||
*
|
||||
****************************************************************************/
|
||||
/* $XFree86: xc/extras/x86emu/src/x86emu/sys.c,v 1.5 2000/08/23 22:10:01 tsi Exp $ */
|
||||
|
||||
#include <arch/io.h>
|
||||
#include <x86emu/x86emu.h>
|
||||
#include <x86emu/regs.h>
|
||||
#include "debug.h"
|
||||
#include "prim_ops.h"
|
||||
|
||||
#ifdef IN_MODULE
|
||||
#include "xf86_ansic.h"
|
||||
#else
|
||||
#include <string.h>
|
||||
#endif
|
||||
/*------------------------- Global Variables ------------------------------*/
|
||||
|
||||
X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */
|
||||
X86EMU_intrFuncs _X86EMU_intrTab[256];
|
||||
|
||||
/*----------------------------- Implementation ----------------------------*/
|
||||
|
||||
/* compute a pointer. This replaces code scattered all over the place! */
|
||||
static u8 *mem_ptr(u32 addr, int size)
|
||||
{
|
||||
u8 *retaddr = 0;
|
||||
|
||||
if (addr > M.mem_size - size) {
|
||||
DB(printf("mem_ptr: address %#x out of range!\n", addr);)
|
||||
HALT_SYS();
|
||||
}
|
||||
if (addr < 0x200) {
|
||||
//printf("%x:%x updating int vector 0x%x\n",
|
||||
// M.x86.R_CS, M.x86.R_IP, addr >> 2);
|
||||
}
|
||||
retaddr = (u8 *) (M.mem_base + addr);
|
||||
|
||||
return retaddr;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - Emulator memory address to read
|
||||
|
||||
RETURNS:
|
||||
Byte value read from emulator memory.
|
||||
|
||||
REMARKS:
|
||||
Reads a byte value from the emulator memory.
|
||||
****************************************************************************/
|
||||
u8 X86API rdb(u32 addr)
|
||||
{
|
||||
u8 val;
|
||||
u8 *ptr;
|
||||
|
||||
ptr = mem_ptr(addr, 1);
|
||||
|
||||
val = *ptr;
|
||||
DB(if (DEBUG_MEM_TRACE())
|
||||
printf("%#08x 1 -> %#x\n", addr, val);)
|
||||
return val;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - Emulator memory address to read
|
||||
|
||||
RETURNS:
|
||||
Word value read from emulator memory.
|
||||
|
||||
REMARKS:
|
||||
Reads a word value from the emulator memory.
|
||||
****************************************************************************/
|
||||
u16 X86API rdw(u32 addr)
|
||||
{
|
||||
u16 val = 0;
|
||||
u8 *ptr;
|
||||
|
||||
ptr = mem_ptr(addr, 2);
|
||||
val = *(u16 *) (ptr);
|
||||
|
||||
DB(if (DEBUG_MEM_TRACE())
|
||||
printf("%#08x 2 -> %#x\n", addr, val);)
|
||||
return val;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - Emulator memory address to read
|
||||
|
||||
RETURNS:
|
||||
Long value read from emulator memory.
|
||||
REMARKS:
|
||||
Reads a long value from the emulator memory.
|
||||
****************************************************************************/
|
||||
u32 X86API rdl(u32 addr)
|
||||
{
|
||||
u32 val = 0;
|
||||
u8 *ptr;
|
||||
|
||||
ptr = mem_ptr(addr, 4);
|
||||
val = *(u32 *) (ptr);
|
||||
|
||||
DB(if (DEBUG_MEM_TRACE())
|
||||
printf("%#08x 4 -> %#x\n", addr, val);)
|
||||
return val;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - Emulator memory address to read
|
||||
val - Value to store
|
||||
|
||||
REMARKS:
|
||||
Writes a byte value to emulator memory.
|
||||
****************************************************************************/
|
||||
void X86API wrb(u32 addr, u8 val)
|
||||
{
|
||||
u8 *ptr;
|
||||
|
||||
ptr = mem_ptr(addr, 1);
|
||||
*(u8 *) (ptr) = val;
|
||||
|
||||
DB(if (DEBUG_MEM_TRACE())
|
||||
printf("%#08x 1 <- %#x\n", addr, val);)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - Emulator memory address to read
|
||||
val - Value to store
|
||||
|
||||
REMARKS:
|
||||
Writes a word value to emulator memory.
|
||||
****************************************************************************/
|
||||
void X86API wrw(u32 addr, u16 val)
|
||||
{
|
||||
u8 *ptr;
|
||||
|
||||
ptr = mem_ptr(addr, 2);
|
||||
*(u16 *) (ptr) = val;
|
||||
|
||||
DB(if (DEBUG_MEM_TRACE())
|
||||
printf("%#08x 2 <- %#x\n", addr, val);)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - Emulator memory address to read
|
||||
val - Value to store
|
||||
|
||||
REMARKS:
|
||||
Writes a long value to emulator memory.
|
||||
****************************************************************************/
|
||||
void X86API wrl(u32 addr, u32 val)
|
||||
{
|
||||
u8 *ptr;
|
||||
|
||||
ptr = mem_ptr(addr, 4);
|
||||
*(u32 *) (ptr) = val;
|
||||
|
||||
DB(if (DEBUG_MEM_TRACE())
|
||||
printf("%#08x 4 <- %#x\n", addr, val);)
|
||||
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - PIO address to read
|
||||
RETURN:
|
||||
0
|
||||
REMARKS:
|
||||
Default PIO byte read function. Doesn't perform real inb.
|
||||
****************************************************************************/
|
||||
static u8 X86API p_inb(X86EMU_pioAddr addr)
|
||||
{
|
||||
DB(if (DEBUG_IO_TRACE())
|
||||
printf("inb %#04x \n", addr);)
|
||||
return inb(addr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - PIO address to read
|
||||
RETURN:
|
||||
0
|
||||
REMARKS:
|
||||
Default PIO word read function. Doesn't perform real inw.
|
||||
****************************************************************************/
|
||||
static u16 X86API p_inw(X86EMU_pioAddr addr)
|
||||
{
|
||||
DB(if (DEBUG_IO_TRACE())
|
||||
printf("inw %#04x \n", addr);)
|
||||
return inw(addr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - PIO address to read
|
||||
RETURN:
|
||||
0
|
||||
REMARKS:
|
||||
Default PIO long read function. Doesn't perform real inl.
|
||||
****************************************************************************/
|
||||
static u32 X86API p_inl(X86EMU_pioAddr addr)
|
||||
{
|
||||
DB(if (DEBUG_IO_TRACE())
|
||||
printf("inl %#04x \n", addr);)
|
||||
return inl(addr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - PIO address to write
|
||||
val - Value to store
|
||||
REMARKS:
|
||||
Default PIO byte write function. Doesn't perform real outb.
|
||||
****************************************************************************/
|
||||
static void X86API p_outb(X86EMU_pioAddr addr, u8 val)
|
||||
{
|
||||
DB(if (DEBUG_IO_TRACE())
|
||||
printf("outb %#02x -> %#04x \n", val, addr);)
|
||||
outb(val, addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - PIO address to write
|
||||
val - Value to store
|
||||
REMARKS:
|
||||
Default PIO word write function. Doesn't perform real outw.
|
||||
****************************************************************************/
|
||||
static void X86API p_outw(X86EMU_pioAddr addr, u16 val)
|
||||
{
|
||||
DB(if (DEBUG_IO_TRACE())
|
||||
printf("outw %#04x -> %#04x \n", val, addr);)
|
||||
outw(val, addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
addr - PIO address to write
|
||||
val - Value to store
|
||||
REMARKS:
|
||||
Default PIO ;ong write function. Doesn't perform real outl.
|
||||
****************************************************************************/
|
||||
static void X86API p_outl(X86EMU_pioAddr addr, u32 val)
|
||||
{
|
||||
DB(if (DEBUG_IO_TRACE())
|
||||
printf("outl %#08x -> %#04x \n", val, addr);)
|
||||
|
||||
outl(val, addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/*------------------------- Global Variables ------------------------------*/
|
||||
|
||||
u8(X86APIP sys_rdb) (u32 addr) = rdb;
|
||||
u16(X86APIP sys_rdw) (u32 addr) = rdw;
|
||||
u32(X86APIP sys_rdl) (u32 addr) = rdl;
|
||||
void (X86APIP sys_wrb) (u32 addr, u8 val) = wrb;
|
||||
void (X86APIP sys_wrw) (u32 addr, u16 val) = wrw;
|
||||
void (X86APIP sys_wrl) (u32 addr, u32 val) = wrl;
|
||||
u8(X86APIP sys_inb) (X86EMU_pioAddr addr) = p_inb;
|
||||
u16(X86APIP sys_inw) (X86EMU_pioAddr addr) = p_inw;
|
||||
u32(X86APIP sys_inl) (X86EMU_pioAddr addr) = p_inl;
|
||||
void (X86APIP sys_outb) (X86EMU_pioAddr addr, u8 val) = p_outb;
|
||||
void (X86APIP sys_outw) (X86EMU_pioAddr addr, u16 val) = p_outw;
|
||||
void (X86APIP sys_outl) (X86EMU_pioAddr addr, u32 val) = p_outl;
|
||||
|
||||
/*----------------------------- Setup -------------------------------------*/
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
funcs - New memory function pointers to make active
|
||||
|
||||
REMARKS:
|
||||
This function is used to set the pointers to functions which access
|
||||
memory space, allowing the user application to override these functions
|
||||
and hook them out as necessary for their application.
|
||||
****************************************************************************/
|
||||
void X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs)
|
||||
{
|
||||
sys_rdb = funcs->rdb;
|
||||
sys_rdw = funcs->rdw;
|
||||
sys_rdl = funcs->rdl;
|
||||
sys_wrb = funcs->wrb;
|
||||
sys_wrw = funcs->wrw;
|
||||
sys_wrl = funcs->wrl;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
funcs - New programmed I/O function pointers to make active
|
||||
|
||||
REMARKS:
|
||||
This function is used to set the pointers to functions which access
|
||||
I/O space, allowing the user application to override these functions
|
||||
and hook them out as necessary for their application.
|
||||
****************************************************************************/
|
||||
void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs)
|
||||
{
|
||||
sys_inb = funcs->inb;
|
||||
sys_inw = funcs->inw;
|
||||
sys_inl = funcs->inl;
|
||||
sys_outb = funcs->outb;
|
||||
sys_outw = funcs->outw;
|
||||
sys_outl = funcs->outl;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
funcs - New interrupt vector table to make active
|
||||
|
||||
REMARKS:
|
||||
This function is used to set the pointers to functions which handle
|
||||
interrupt processing in the emulator, allowing the user application to
|
||||
hook interrupts as necessary for their application. Any interrupts that
|
||||
are not hooked by the user application, and reflected and handled internally
|
||||
in the emulator via the interrupt vector table. This allows the application
|
||||
to get control when the code being emulated executes specific software
|
||||
interrupts.
|
||||
****************************************************************************/
|
||||
void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
_X86EMU_intrTab[i] = NULL;
|
||||
if (funcs) {
|
||||
for (i = 0; i < 256; i++)
|
||||
_X86EMU_intrTab[i] = funcs[i];
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
PARAMETERS:
|
||||
int - New software interrupt to prepare for
|
||||
|
||||
REMARKS:
|
||||
This function is used to set up the emulator state to exceute a software
|
||||
interrupt. This can be used by the user application code to allow an
|
||||
interrupt to be hooked, examined and then reflected back to the emulator
|
||||
so that the code in the emulator will continue processing the software
|
||||
interrupt as per normal. This essentially allows system code to actively
|
||||
hook and handle certain software interrupts as necessary.
|
||||
****************************************************************************/
|
||||
void X86EMU_prepareForInt(int num)
|
||||
{
|
||||
push_word((u16) M.x86.R_FLG);
|
||||
CLEAR_FLAG(F_IF);
|
||||
CLEAR_FLAG(F_TF);
|
||||
push_word(M.x86.R_CS);
|
||||
M.x86.R_CS = mem_access_word(num * 4 + 2);
|
||||
push_word(M.x86.R_IP);
|
||||
M.x86.R_IP = mem_access_word(num * 4);
|
||||
M.x86.intr = 0;
|
||||
}
|
||||
|
||||
void X86EMU_setMemBase(void *base, size_t size)
|
||||
{
|
||||
M.mem_base = (unsigned long) base;
|
||||
M.mem_size = size;
|
||||
}
|
@@ -1,103 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Realmode X86 Emulator Library
|
||||
*
|
||||
* Copyright (C) 1996-1999 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 system specific functions. These functions
|
||||
* are always compiled and linked in the OS depedent libraries,
|
||||
* and never in a binary portable driver.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* $XFree86: xc/extras/x86emu/src/x86emu/x86emu/x86emui.h,v 1.4 2001/04/01 13:59:58 tsi Exp $ */
|
||||
|
||||
#ifndef __X86EMU_X86EMUI_H
|
||||
#define __X86EMU_X86EMUI_H
|
||||
|
||||
/* If we are compiling in C++ mode, we can compile some functions as
|
||||
* inline to increase performance (however the code size increases quite
|
||||
* dramatically in this case).
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus) && !defined(_NO_INLINE)
|
||||
#define _INLINE inline
|
||||
#else
|
||||
#define _INLINE static
|
||||
#endif
|
||||
|
||||
/* Get rid of unused parameters in C++ compilation mode */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define X86EMU_UNUSED(v)
|
||||
#else
|
||||
#define X86EMU_UNUSED(v) v
|
||||
#endif
|
||||
|
||||
#include "x86emu/x86emu.h"
|
||||
#include "x86emu/regs.h"
|
||||
#include "debug.h"
|
||||
#include "decode.h"
|
||||
#include "ops.h"
|
||||
#include "prim_ops.h"
|
||||
#include "fpu.h"
|
||||
#include "x86emu/fpu_regs.h"
|
||||
|
||||
#ifdef IN_MODULE
|
||||
#include <xf86_ansic.h>
|
||||
#else
|
||||
#include <string.h>
|
||||
#endif
|
||||
/*--------------------------- Inline Functions ----------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Use "C" linkage when in C++ mode */
|
||||
#endif
|
||||
|
||||
extern u8 (X86APIP sys_rdb)(u32 addr);
|
||||
extern u16 (X86APIP sys_rdw)(u32 addr);
|
||||
extern u32 (X86APIP sys_rdl)(u32 addr);
|
||||
extern void (X86APIP sys_wrb)(u32 addr,u8 val);
|
||||
extern void (X86APIP sys_wrw)(u32 addr,u16 val);
|
||||
extern void (X86APIP sys_wrl)(u32 addr,u32 val);
|
||||
|
||||
extern u8 (X86APIP sys_inb)(X86EMU_pioAddr addr);
|
||||
extern u16 (X86APIP sys_inw)(X86EMU_pioAddr addr);
|
||||
extern u32 (X86APIP sys_inl)(X86EMU_pioAddr addr);
|
||||
extern void (X86APIP sys_outb)(X86EMU_pioAddr addr,u8 val);
|
||||
extern void (X86APIP sys_outw)(X86EMU_pioAddr addr,u16 val);
|
||||
extern void (X86APIP sys_outl)(X86EMU_pioAddr addr,u32 val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of "C" linkage for C++ */
|
||||
#endif
|
||||
|
||||
#endif /* __X86EMU_X86EMUI_H */
|
@@ -1,9 +0,0 @@
|
||||
obj-y += biosemu.o
|
||||
obj-y += debug.o
|
||||
obj-y += device.o
|
||||
obj-y += interrupt.o
|
||||
obj-y += io.o
|
||||
obj-y += mem.o
|
||||
obj-y += pmm.o
|
||||
obj-y += vbe.o
|
||||
subdirs-y += compat
|
@@ -1,386 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* Copyright (c) 2010 coresystems GmbH
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <types.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <x86emu/x86emu.h>
|
||||
#include <x86emu/regs.h>
|
||||
#include "../x86emu/prim_ops.h"
|
||||
|
||||
#include "biosemu.h"
|
||||
#include "io.h"
|
||||
#include "mem.h"
|
||||
#include "interrupt.h"
|
||||
#include "device.h"
|
||||
#include "pmm.h"
|
||||
|
||||
#include <device/device.h>
|
||||
#include "compat/rtas.h"
|
||||
|
||||
static X86EMU_memFuncs my_mem_funcs = {
|
||||
my_rdb, my_rdw, my_rdl,
|
||||
my_wrb, my_wrw, my_wrl
|
||||
};
|
||||
|
||||
static X86EMU_pioFuncs my_pio_funcs = {
|
||||
my_inb, my_inw, my_inl,
|
||||
my_outb, my_outw, my_outl
|
||||
};
|
||||
|
||||
/* interrupt function override array (see biosemu.h) */
|
||||
yabel_handleIntFunc yabel_intFuncArray[256];
|
||||
|
||||
/* main entry into YABEL biosemu, arguments are:
|
||||
* *biosmem = pointer to virtual memory
|
||||
* biosmem_size = size of the virtual memory
|
||||
* *dev = pointer to the device to be initialised
|
||||
* rom_addr = address of the OptionROM to be executed, if this is = 0, YABEL
|
||||
* will look for an ExpansionROM BAR and use the code from there.
|
||||
*/
|
||||
u32
|
||||
biosemu(u8 *biosmem, u32 biosmem_size, struct device * dev, unsigned long rom_addr)
|
||||
{
|
||||
u8 *rom_image;
|
||||
int i = 0;
|
||||
#if CONFIG_X86EMU_DEBUG
|
||||
debug_flags = 0;
|
||||
#if defined(CONFIG_X86EMU_DEBUG_JMP) && CONFIG_X86EMU_DEBUG_JMP
|
||||
debug_flags |= DEBUG_JMP;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_TRACE) && CONFIG_X86EMU_DEBUG_TRACE
|
||||
debug_flags |= DEBUG_TRACE_X86EMU;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_PNP) && CONFIG_X86EMU_DEBUG_PNP
|
||||
debug_flags |= DEBUG_PNP;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_DISK) && CONFIG_X86EMU_DEBUG_DISK
|
||||
debug_flags |= DEBUG_DISK;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_PMM) && CONFIG_X86EMU_DEBUG_PMM
|
||||
debug_flags |= DEBUG_PMM;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_VBE) && CONFIG_X86EMU_DEBUG_VBE
|
||||
debug_flags |= DEBUG_VBE;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_INT10) && CONFIG_X86EMU_DEBUG_INT10
|
||||
debug_flags |= DEBUG_PRINT_INT10;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_INTERRUPTS) && CONFIG_X86EMU_DEBUG_INTERRUPTS
|
||||
debug_flags |= DEBUG_INTR;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_CHECK_VMEM_ACCESS) && CONFIG_X86EMU_DEBUG_CHECK_VMEM_ACCESS
|
||||
debug_flags |= DEBUG_CHECK_VMEM_ACCESS;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_MEM) && CONFIG_X86EMU_DEBUG_MEM
|
||||
debug_flags |= DEBUG_MEM;
|
||||
#endif
|
||||
#if defined(CONFIG_X86EMU_DEBUG_IO) && CONFIG_X86EMU_DEBUG_IO
|
||||
debug_flags |= DEBUG_IO;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) {
|
||||
printf("Error: Not enough virtual memory: %x, required: %x!\n",
|
||||
biosmem_size, MIN_REQUIRED_VMEM_SIZE);
|
||||
return -1;
|
||||
}
|
||||
if (biosemu_dev_init(dev) != 0) {
|
||||
printf("Error initializing device!\n");
|
||||
return -1;
|
||||
}
|
||||
if (biosemu_dev_check_exprom(rom_addr) != 0) {
|
||||
printf("Error: Device Expansion ROM invalid!\n");
|
||||
return -1;
|
||||
}
|
||||
rom_image = (u8 *) bios_device.img_addr;
|
||||
DEBUG_PRINTF("executing rom_image from %p\n", rom_image);
|
||||
DEBUG_PRINTF("biosmem at %p\n", biosmem);
|
||||
|
||||
DEBUG_PRINTF("Image Size: %d\n", bios_device.img_size);
|
||||
|
||||
// in case we jump somewhere unexpected, or execution is finished,
|
||||
// fill the biosmem with hlt instructions (0xf4)
|
||||
// But we have to be careful: If biosmem is 0x00000000 we're running
|
||||
// in the lower 1MB and we must not wipe memory like that.
|
||||
if (biosmem) {
|
||||
DEBUG_PRINTF("Clearing biosmem\n");
|
||||
memset(biosmem, 0xf4, biosmem_size);
|
||||
}
|
||||
|
||||
X86EMU_setMemBase(biosmem, biosmem_size);
|
||||
|
||||
DEBUG_PRINTF("membase set: %08x, size: %08x\n", (int) M.mem_base,
|
||||
(int) M.mem_size);
|
||||
|
||||
// copy expansion ROM image to segment OPTION_ROM_CODE_SEGMENT
|
||||
// NOTE: this sometimes fails, some bytes are 0x00... so we compare
|
||||
// after copying and do some retries...
|
||||
u8 *mem_img = biosmem + (OPTION_ROM_CODE_SEGMENT << 4);
|
||||
u8 copy_count = 0;
|
||||
u8 cmp_result = 0;
|
||||
do {
|
||||
#if 0
|
||||
set_ci();
|
||||
memcpy(mem_img, rom_image, len);
|
||||
clr_ci();
|
||||
#else
|
||||
// memcpy fails... try copy byte-by-byte with set/clr_ci
|
||||
u8 c;
|
||||
for (i = 0; i < bios_device.img_size; i++) {
|
||||
set_ci();
|
||||
c = *(rom_image + i);
|
||||
if (c != *(rom_image + i)) {
|
||||
clr_ci();
|
||||
printf("Copy failed at: %x/%x\n", i,
|
||||
bios_device.img_size);
|
||||
printf("rom_image(%x): %x, mem_img(%x): %x\n",
|
||||
i, *(rom_image + i), i, *(mem_img + i));
|
||||
break;
|
||||
}
|
||||
clr_ci();
|
||||
*(mem_img + i) = c;
|
||||
}
|
||||
#endif
|
||||
copy_count++;
|
||||
set_ci();
|
||||
cmp_result = memcmp(mem_img, rom_image, bios_device.img_size);
|
||||
clr_ci();
|
||||
}
|
||||
while ((copy_count < 5) && (cmp_result != 0));
|
||||
if (cmp_result != 0) {
|
||||
printf
|
||||
("\nCopying Expansion ROM Image to Memory failed after %d retries! (%x)\n",
|
||||
copy_count, cmp_result);
|
||||
dump(rom_image, 0x20);
|
||||
dump(mem_img, 0x20);
|
||||
return 0;
|
||||
}
|
||||
// setup default Interrupt Vectors
|
||||
// some expansion ROMs seem to check for these addresses..
|
||||
// each handler is only an IRET (0xCF) instruction
|
||||
// ROM BIOS Int 10 Handler F000:F065
|
||||
my_wrl(0x10 * 4, 0xf000f065);
|
||||
my_wrb(0x000ff065, 0xcf);
|
||||
// ROM BIOS Int 11 Handler F000:F84D
|
||||
my_wrl(0x11 * 4, 0xf000f84d);
|
||||
my_wrb(0x000ff84d, 0xcf);
|
||||
// ROM BIOS Int 12 Handler F000:F841
|
||||
my_wrl(0x12 * 4, 0xf000f841);
|
||||
my_wrb(0x000ff841, 0xcf);
|
||||
// ROM BIOS Int 13 Handler F000:EC59
|
||||
my_wrl(0x13 * 4, 0xf000ec59);
|
||||
my_wrb(0x000fec59, 0xcf);
|
||||
// ROM BIOS Int 14 Handler F000:E739
|
||||
my_wrl(0x14 * 4, 0xf000e739);
|
||||
my_wrb(0x000fe739, 0xcf);
|
||||
// ROM BIOS Int 15 Handler F000:F859
|
||||
my_wrl(0x15 * 4, 0xf000f859);
|
||||
my_wrb(0x000ff859, 0xcf);
|
||||
// ROM BIOS Int 16 Handler F000:E82E
|
||||
my_wrl(0x16 * 4, 0xf000e82e);
|
||||
my_wrb(0x000fe82e, 0xcf);
|
||||
// ROM BIOS Int 17 Handler F000:EFD2
|
||||
my_wrl(0x17 * 4, 0xf000efd2);
|
||||
my_wrb(0x000fefd2, 0xcf);
|
||||
// ROM BIOS Int 1A Handler F000:FE6E
|
||||
my_wrl(0x1a * 4, 0xf000fe6e);
|
||||
my_wrb(0x000ffe6e, 0xcf);
|
||||
|
||||
// setup BIOS Data Area (0000:04xx, or 0040:00xx)
|
||||
// we currently 0 this area, meaning "we dont have
|
||||
// any hardware" :-) no serial/parallel ports, floppys, ...
|
||||
memset(biosmem + 0x400, 0x0, 0x100);
|
||||
|
||||
// at offset 13h in BDA is the memory size in kbytes
|
||||
my_wrw(0x413, biosmem_size / 1024);
|
||||
// at offset 0eh in BDA is the segment of the Extended BIOS Data Area
|
||||
// see setup further down
|
||||
my_wrw(0x40e, INITIAL_EBDA_SEGMENT);
|
||||
// TODO: setup BDA Video Data ( offset 49h-66h)
|
||||
// e.g. to store video mode, cursor position, ...
|
||||
// in int10 (done) handler and VBE Functions
|
||||
|
||||
// TODO: setup BDA Fixed Disk Data
|
||||
// 74h: Fixed Disk Last Operation Status
|
||||
// 75h: Fixed Disk Number of Disk Drives
|
||||
|
||||
// TODO: check BDA for further needed data...
|
||||
|
||||
//setup Extended BIOS Data Area
|
||||
//we currently 0 this area
|
||||
memset(biosmem + (INITIAL_EBDA_SEGMENT << 4), 0, INITIAL_EBDA_SIZE);
|
||||
// at offset 0h in EBDA is the size of the EBDA in KB
|
||||
my_wrw((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024);
|
||||
//TODO: check for further needed EBDA data...
|
||||
|
||||
// setup original ROM BIOS Area (F000:xxxx)
|
||||
const char *date = "06/11/99";
|
||||
for (i = 0; date[i]; i++)
|
||||
my_wrb(0xffff5 + i, date[i]);
|
||||
// set up eisa ident string
|
||||
const char *ident = "PCI_ISA";
|
||||
for (i = 0; ident[i]; i++)
|
||||
my_wrb(0xfffd9 + i, ident[i]);
|
||||
|
||||
// write system model id for IBM-AT
|
||||
// according to "Ralf Browns Interrupt List" Int15 AH=C0 Table 515,
|
||||
// model FC is the original AT and also used in all DOSEMU Versions.
|
||||
my_wrb(0xFFFFE, 0xfc);
|
||||
|
||||
//setup interrupt handler
|
||||
X86EMU_intrFuncs intrFuncs[256];
|
||||
for (i = 0; i < 256; i++)
|
||||
intrFuncs[i] = handleInterrupt;
|
||||
X86EMU_setupIntrFuncs(intrFuncs);
|
||||
X86EMU_setupPioFuncs(&my_pio_funcs);
|
||||
X86EMU_setupMemFuncs(&my_mem_funcs);
|
||||
|
||||
//setup PMM struct in BIOS_DATA_SEGMENT, offset 0x0
|
||||
u8 pmm_length = pmm_setup(BIOS_DATA_SEGMENT, 0x0);
|
||||
if (pmm_length <= 0) {
|
||||
printf ("\nYABEL: Warning: PMM Area could not be setup. PMM not available (%x)\n",
|
||||
pmm_length);
|
||||
return 0;
|
||||
} else {
|
||||
CHECK_DBG(DEBUG_PMM) {
|
||||
/* test the PMM */
|
||||
pmm_test();
|
||||
/* and clean it again by calling pmm_setup... */
|
||||
pmm_length = pmm_setup(BIOS_DATA_SEGMENT, 0x0);
|
||||
}
|
||||
}
|
||||
// setup the CPU
|
||||
M.x86.R_AH = bios_device.bus;
|
||||
M.x86.R_AL = bios_device.devfn;
|
||||
M.x86.R_DX = 0x80;
|
||||
M.x86.R_EIP = 3;
|
||||
M.x86.R_CS = OPTION_ROM_CODE_SEGMENT;
|
||||
|
||||
// Initialize stack and data segment
|
||||
M.x86.R_SS = STACK_SEGMENT;
|
||||
M.x86.R_SP = STACK_START_OFFSET;
|
||||
M.x86.R_DS = DATA_SEGMENT;
|
||||
|
||||
// push a HLT instruction and a pointer to it onto the stack
|
||||
// any return will pop the pointer and jump to the HLT, thus
|
||||
// exiting (more or less) cleanly
|
||||
push_word(0xf4f4); // F4=HLT
|
||||
push_word(M.x86.R_SS);
|
||||
push_word(M.x86.R_SP + 2);
|
||||
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
#if 0
|
||||
} else {
|
||||
M.x86.debug |= DEBUG_SAVE_IP_CS_F;
|
||||
M.x86.debug |= DEBUG_DECODE_F;
|
||||
M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
|
||||
#endif
|
||||
}
|
||||
CHECK_DBG(DEBUG_JMP) {
|
||||
M.x86.debug |= DEBUG_TRACEJMP_F;
|
||||
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
||||
M.x86.debug |= DEBUG_TRACECALL_F;
|
||||
M.x86.debug |= DEBUG_TRACECALL_REGS_F;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("Executing Initialization Vector...\n");
|
||||
X86EMU_exec();
|
||||
DEBUG_PRINTF("done\n");
|
||||
|
||||
/* According to the PNP BIOS Spec, Option ROMs should upon exit, return
|
||||
* some boot device status in AX (see PNP BIOS Spec Section 3.3
|
||||
*/
|
||||
DEBUG_PRINTF_CS_IP("Option ROM Exit Status: %04x\n", M.x86.R_AX);
|
||||
#if defined(CONFIG_X86EMU_DEBUG) && CONFIG_X86EMU_DEBUG
|
||||
DEBUG_PRINTF("Exit Status Decode:\n");
|
||||
if (M.x86.R_AX & 0x100) { // bit 8
|
||||
DEBUG_PRINTF
|
||||
(" IPL Device supporting INT 13h Block Device Format:\n");
|
||||
switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4
|
||||
case 0:
|
||||
DEBUG_PRINTF(" No IPL Device attached\n");
|
||||
break;
|
||||
case 1:
|
||||
DEBUG_PRINTF(" IPL Device status unknown\n");
|
||||
break;
|
||||
case 2:
|
||||
DEBUG_PRINTF(" IPL Device attached\n");
|
||||
break;
|
||||
case 3:
|
||||
DEBUG_PRINTF(" IPL Device status RESERVED!!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (M.x86.R_AX & 0x80) { // bit 7
|
||||
DEBUG_PRINTF
|
||||
(" Output Device supporting INT 10h Character Output:\n");
|
||||
switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4
|
||||
case 0:
|
||||
DEBUG_PRINTF(" No Display Device attached\n");
|
||||
break;
|
||||
case 1:
|
||||
DEBUG_PRINTF(" Display Device status unknown\n");
|
||||
break;
|
||||
case 2:
|
||||
DEBUG_PRINTF(" Display Device attached\n");
|
||||
break;
|
||||
case 3:
|
||||
DEBUG_PRINTF(" Display Device status RESERVED!!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (M.x86.R_AX & 0x40) { // bit 6
|
||||
DEBUG_PRINTF
|
||||
(" Input Device supporting INT 9h Character Input:\n");
|
||||
switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4
|
||||
case 0:
|
||||
DEBUG_PRINTF(" No Input Device attached\n");
|
||||
break;
|
||||
case 1:
|
||||
DEBUG_PRINTF(" Input Device status unknown\n");
|
||||
break;
|
||||
case 2:
|
||||
DEBUG_PRINTF(" Input Device attached\n");
|
||||
break;
|
||||
case 3:
|
||||
DEBUG_PRINTF(" Input Device status RESERVED!!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Check whether the stack is "clean" i.e. containing the HLT
|
||||
* instruction we pushed before executing and pointing to the original
|
||||
* stack address... indicating that the initialization probably was
|
||||
* successful
|
||||
*/
|
||||
if ((pop_word() == 0xf4f4) && (M.x86.R_SS == STACK_SEGMENT)
|
||||
&& (M.x86.R_SP == STACK_START_OFFSET)) {
|
||||
DEBUG_PRINTF("Stack is clean, initialization successfull!\n");
|
||||
} else {
|
||||
printf("Stack unclean, initialization probably NOT COMPLETE!\n");
|
||||
DEBUG_PRINTF("SS:SP = %04x:%04x, expected: %04x:%04x\n",
|
||||
M.x86.R_SS, M.x86.R_SP, STACK_SEGMENT,
|
||||
STACK_START_OFFSET);
|
||||
}
|
||||
|
||||
// TODO: according to the BIOS Boot Spec initializations may be ended using INT18h and setting
|
||||
// the status.
|
||||
// We need to implement INT18 accordingly, pseudo code is in specsbbs101.pdf page 30
|
||||
// (also for Int19)
|
||||
return 0;
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _BIOSEMU_BIOSEMU_H_
|
||||
#define _BIOSEMU_BIOSEMU_H_
|
||||
|
||||
#define MIN_REQUIRED_VMEM_SIZE 0x100000 // 1MB
|
||||
|
||||
//define default segments for different components
|
||||
#define STACK_SEGMENT 0x1000 //1000:xxxx
|
||||
#define STACK_START_OFFSET 0xfffe
|
||||
|
||||
#define DATA_SEGMENT 0x2000
|
||||
#define VBE_SEGMENT 0x3000
|
||||
|
||||
#define PMM_CONV_SEGMENT 0x4000 // 4000:xxxx is PMM conventional memory area, extended memory area
|
||||
// will be anything beyound MIN_REQUIRED_MEMORY_SIZE
|
||||
#define PNP_DATA_SEGMENT 0x5000
|
||||
|
||||
#define OPTION_ROM_CODE_SEGMENT 0xc000
|
||||
|
||||
#define BIOS_DATA_SEGMENT 0xF000
|
||||
// both EBDA values are _initial_ values, they may (and will be) changed at runtime by option ROMs!!
|
||||
#define INITIAL_EBDA_SEGMENT 0xF600 // segment of the Extended BIOS Data Area
|
||||
#define INITIAL_EBDA_SIZE 0x400 // size of the EBDA (at least 1KB!! since size is stored in KB!)
|
||||
|
||||
#define PMM_INT_NUM 0xFC // we misuse INT FC for PMM functionality, at the PMM Entry Point
|
||||
// Address, there will only be a call to this INT and a RETF
|
||||
#define PNP_INT_NUM 0xFD
|
||||
|
||||
/* array of funtion pointers to override generic interrupt handlers
|
||||
* a YABEL caller can add functions to this array before calling YABEL
|
||||
* if a interrupt occurs, YABEL checks wether a function is set in
|
||||
* this array and only runs the generic interrupt handler code, if
|
||||
* the function pointer is NULL */
|
||||
typedef int (* yabel_handleIntFunc)(void);
|
||||
extern yabel_handleIntFunc yabel_intFuncArray[256];
|
||||
|
||||
struct device;
|
||||
|
||||
u32 biosemu(u8 *biosmem, u32 biosmem_size, struct device *dev, unsigned long rom_addr);
|
||||
#endif
|
@@ -1 +0,0 @@
|
||||
obj-y += functions.o
|
@@ -1,69 +0,0 @@
|
||||
/****************************************************************************
|
||||
* YABEL BIOS Emulator
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Copyright (c) 2008 Pattrick Hueper <phueper@hueper.net>
|
||||
****************************************************************************/
|
||||
|
||||
/* this file contains functions provided by SLOF, that the current biosemu implementation needs
|
||||
* they should go away inthe future...
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <device/device.h>
|
||||
#include "../debug.h"
|
||||
#include "../biosemu.h"
|
||||
#include "../compat/time.h"
|
||||
|
||||
#define VMEM_SIZE (1024 * 1024) /* 1 MB */
|
||||
|
||||
#if !defined(CONFIG_YABEL_DIRECTHW) || (!CONFIG_YABEL_DIRECTHW)
|
||||
#ifdef CONFIG_YABEL_VIRTMEM_LOCATION
|
||||
u8* vmem = (u8 *) CONFIG_YABEL_VIRTMEM_LOCATION;
|
||||
#else
|
||||
u8* vmem = (u8 *) (16*1024*1024); /* default to 16MB */
|
||||
#endif
|
||||
#else
|
||||
u8* vmem = NULL;
|
||||
#endif
|
||||
|
||||
#if CONFIG_BOOTSPLASH
|
||||
void vbe_set_graphics(void);
|
||||
#endif
|
||||
|
||||
void run_bios(struct device * dev, unsigned long addr)
|
||||
{
|
||||
|
||||
biosemu(vmem, VMEM_SIZE, dev, addr);
|
||||
|
||||
#if CONFIG_BOOTSPLASH
|
||||
vbe_set_graphics();
|
||||
#endif
|
||||
|
||||
if (vmem != NULL) {
|
||||
printf("Copying legacy memory from %p to the lower 1MB\n", vmem);
|
||||
memcpy((void *)0x00000, vmem + 0x00000, 0x400); // IVT
|
||||
memcpy((void *)0x00400, vmem + 0x00400, 0x100); // BDA
|
||||
memcpy((void *)0xc0000, vmem + 0xc0000, 0x10000); // VGA OPROM
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long tb_freq = 0;
|
||||
|
||||
u64 get_time(void)
|
||||
{
|
||||
u64 act;
|
||||
u32 eax, edx;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"rdtsc"
|
||||
: "=a"(eax), "=d"(edx)
|
||||
: /* no inputs, no clobber */);
|
||||
act = ((u64) edx << 32) | eax;
|
||||
return act;
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef OF_H
|
||||
#define OF_H
|
||||
#define p32 int
|
||||
#define p32cast (int) (unsigned long) (void*)
|
||||
|
||||
#define phandle_t p32
|
||||
#define ihandle_t p32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int serv;
|
||||
int nargs;
|
||||
int nrets;
|
||||
unsigned int args[16];
|
||||
} of_arg_t;
|
||||
|
||||
|
||||
phandle_t of_finddevice (const char *);
|
||||
phandle_t of_peer (phandle_t);
|
||||
phandle_t of_child (phandle_t);
|
||||
phandle_t of_parent (phandle_t);
|
||||
int of_getprop (phandle_t, const char *, void *, int);
|
||||
void * of_call_method_3 (const char *, ihandle_t, int);
|
||||
|
||||
|
||||
ihandle_t of_open (const char *);
|
||||
void of_close(ihandle_t);
|
||||
int of_read (ihandle_t , void*, int);
|
||||
int of_write (ihandle_t, void*, int);
|
||||
int of_seek (ihandle_t, int, int);
|
||||
|
||||
void * of_claim(void *, unsigned int , unsigned int );
|
||||
void of_release(void *, unsigned int );
|
||||
|
||||
int of_yield(void);
|
||||
void * of_set_callback(void *);
|
||||
|
||||
int vpd_read(unsigned int , unsigned int , char *);
|
||||
int vpd_write(unsigned int , unsigned int , char *);
|
||||
int write_mm_log(char *, unsigned int , unsigned short );
|
||||
|
||||
#endif
|
@@ -1,45 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef RTAS_H
|
||||
#define RTAS_H
|
||||
|
||||
#include "of.h"
|
||||
|
||||
typedef struct dtime {
|
||||
unsigned int year;
|
||||
unsigned int month;
|
||||
unsigned int day;
|
||||
unsigned int hour;
|
||||
unsigned int minute;
|
||||
unsigned int second;
|
||||
unsigned int nano;
|
||||
} dtime;
|
||||
|
||||
typedef void (*thread_t) (int);
|
||||
|
||||
int rtas_token(const char *);
|
||||
int rtas_call(int, int, int, int *, ...);
|
||||
void rtas_init(void);
|
||||
int rtas_pci_config_read (long long, int, int, int, int);
|
||||
int rtas_pci_config_write (long long, int, int, int, int, int);
|
||||
int rtas_set_time_of_day(dtime *);
|
||||
int rtas_get_time_of_day(dtime *);
|
||||
int rtas_ibm_update_flash_64(long long, long long);
|
||||
int rtas_ibm_update_flash_64_and_reboot(long long, long long);
|
||||
int rtas_system_reboot(void);
|
||||
int rtas_start_cpu (int, thread_t, int);
|
||||
int rtas_stop_self (void);
|
||||
int rtas_ibm_manage_flash(int);
|
||||
|
||||
#endif
|
@@ -1,18 +0,0 @@
|
||||
/****************************************************************************
|
||||
* YABEL BIOS Emulator
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Copyright (c) 2008 Pattrick Hueper <phueper@hueper.net>
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _BIOSEMU_COMPAT_TIME_H
|
||||
#define _BIOSEMU_COMPAT_TIME_H
|
||||
|
||||
/* TODO: check how this works in x86 */
|
||||
extern unsigned long tb_freq;
|
||||
u64 get_time(void);
|
||||
#endif
|
@@ -1,54 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
u32 debug_flags = 0;
|
||||
|
||||
void
|
||||
dump(u8 * addr, u32 len)
|
||||
{
|
||||
printf("\n%s(%p, %x):\n", __func__, addr, len);
|
||||
while (len) {
|
||||
unsigned int tmpCnt = len;
|
||||
unsigned char x;
|
||||
if (tmpCnt > 8)
|
||||
tmpCnt = 8;
|
||||
printf("\n%p: ", addr);
|
||||
// print hex
|
||||
while (tmpCnt--) {
|
||||
set_ci();
|
||||
x = *addr++;
|
||||
clr_ci();
|
||||
printf("%02x ", x);
|
||||
}
|
||||
tmpCnt = len;
|
||||
if (tmpCnt > 8)
|
||||
tmpCnt = 8;
|
||||
len -= tmpCnt;
|
||||
//reset addr ptr to print ascii
|
||||
addr = addr - tmpCnt;
|
||||
// print ascii
|
||||
while (tmpCnt--) {
|
||||
set_ci();
|
||||
x = *addr++;
|
||||
clr_ci();
|
||||
if ((x < 32) || (x >= 127)) {
|
||||
//non-printable char
|
||||
x = '.';
|
||||
}
|
||||
printf("%c", x);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
@@ -1,105 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
#ifndef _BIOSEMU_DEBUG_H_
|
||||
#define _BIOSEMU_DEBUG_H_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
extern u32 debug_flags;
|
||||
// from x86emu...needed for debugging
|
||||
extern void x86emu_dump_xregs(void);
|
||||
|
||||
/* printf is not available in coreboot... use printk */
|
||||
#include <console/console.h>
|
||||
#include "x86emu/x86emu.h"
|
||||
#define printf(x...) printk(BIOS_DEBUG, x)
|
||||
|
||||
/* PH: empty versions of set/clr_ci
|
||||
* TODO: remove! */
|
||||
static inline void clr_ci(void) {};
|
||||
static inline void set_ci(void) {};
|
||||
|
||||
/* debug_flags is a binary switch that allows you to select the following items
|
||||
* to debug. 1=on 0=off. After you decide what you want to debug create the
|
||||
* binary value, convert to hex and set the option. These options can be
|
||||
* selected in Kconfig.
|
||||
*
|
||||
* |-DEBUG_JMP - print info about JMP and RETF opcodes from x86emu
|
||||
* ||-DEBUG_TRACE_X86EMU - print _all_ opcodes that are executed by x86emu (WARNING: this will produce a LOT of output)
|
||||
* |||-Currently unused
|
||||
* ||||-Currently unused
|
||||
* |||||-Currently unused
|
||||
* ||||||-DEBUG_PNP - Print Plug And Play access made by option rom
|
||||
* |||||||-DEBUG_DISK - Print Disk I/O related messages, currently unused
|
||||
* ||||||||-DEBUG_PMM - Print messages related to POST Memory Manager (PMM)
|
||||
* |||||||||-DEBUG_VBE - Print messages related to VESA BIOS Extension (VBE) functions
|
||||
* ||||||||||-DEBUG_PRINT_INT10 - let INT10 (i.e. character output) calls print messages to Debug output
|
||||
* |||||||||||-DEBUG_INTR - Print messages related to interrupt handling
|
||||
* ||||||||||||-DEBUG_CHECK_VMEM_ACCESS - Print messages related to accesse to certain areas of the virtual Memory (e.g. BDA (BIOS Data Area) or Interrupt Vectors)
|
||||
* |||||||||||||-DEBUG_MEM - Print memory access made by option rom (NOTE: this also includes accesses to fetch instructions)
|
||||
* ||||||||||||||-DEBUG_IO - Print I/O access made by option rom
|
||||
* 11000111111111 - Max Binary Value, Debug All (WARNING: - This could run for hours)
|
||||
*/
|
||||
|
||||
#define DEBUG_IO 0x1
|
||||
#define DEBUG_MEM 0x2
|
||||
// set this to print messages for certain virtual memory accesses (Interrupt Vectors, ...)
|
||||
#define DEBUG_CHECK_VMEM_ACCESS 0x4
|
||||
#define DEBUG_INTR 0x8
|
||||
#define DEBUG_PRINT_INT10 0x10 // set to have the INT10 routine print characters
|
||||
#define DEBUG_VBE 0x20
|
||||
#define DEBUG_PMM 0x40
|
||||
#define DEBUG_DISK 0x80
|
||||
#define DEBUG_PNP 0x100
|
||||
|
||||
#define DEBUG_TRACE_X86EMU 0x1000
|
||||
// set to enable tracing of JMPs in x86emu
|
||||
#define DEBUG_JMP 0x2000
|
||||
|
||||
#if defined(CONFIG_X86EMU_DEBUG) && CONFIG_X86EMU_DEBUG
|
||||
|
||||
#define CHECK_DBG(_flag) if (debug_flags & _flag)
|
||||
|
||||
#define DEBUG_PRINTF(_x...) printf(_x);
|
||||
// prints the CS:IP before the printout, NOTE: actually its CS:IP of the _next_ instruction
|
||||
// to be executed, since the x86emu advances CS:IP _before_ actually executing an instruction
|
||||
#define DEBUG_PRINTF_CS_IP(_x...) DEBUG_PRINTF("%x:%x ", M.x86.R_CS, M.x86.R_IP); DEBUG_PRINTF(_x);
|
||||
|
||||
#define DEBUG_PRINTF_IO(_x...) CHECK_DBG(DEBUG_IO) { DEBUG_PRINTF_CS_IP(_x) }
|
||||
#define DEBUG_PRINTF_MEM(_x...) CHECK_DBG(DEBUG_MEM) { DEBUG_PRINTF_CS_IP(_x) }
|
||||
#define DEBUG_PRINTF_INTR(_x...) CHECK_DBG(DEBUG_INTR) { DEBUG_PRINTF_CS_IP(_x) }
|
||||
#define DEBUG_PRINTF_VBE(_x...) CHECK_DBG(DEBUG_VBE) { DEBUG_PRINTF_CS_IP(_x) }
|
||||
#define DEBUG_PRINTF_PMM(_x...) CHECK_DBG(DEBUG_PMM) { DEBUG_PRINTF_CS_IP(_x) }
|
||||
#define DEBUG_PRINTF_DISK(_x...) CHECK_DBG(DEBUG_DISK) { DEBUG_PRINTF_CS_IP(_x) }
|
||||
#define DEBUG_PRINTF_PNP(_x...) CHECK_DBG(DEBUG_PNP) { DEBUG_PRINTF_CS_IP(_x) }
|
||||
|
||||
#else
|
||||
|
||||
#define CHECK_DBG(_flag) if (0)
|
||||
|
||||
#define DEBUG_PRINTF(_x...)
|
||||
#define DEBUG_PRINTF_CS_IP(_x...)
|
||||
|
||||
#define DEBUG_PRINTF_IO(_x...)
|
||||
#define DEBUG_PRINTF_MEM(_x...)
|
||||
#define DEBUG_PRINTF_INTR(_x...)
|
||||
#define DEBUG_PRINTF_VBE(_x...)
|
||||
#define DEBUG_PRINTF_PMM(_x...)
|
||||
#define DEBUG_PRINTF_DISK(_x...)
|
||||
#define DEBUG_PRINTF_PNP(_x...)
|
||||
|
||||
#endif //DEBUG
|
||||
|
||||
void dump(u8 * addr, u32 len);
|
||||
|
||||
#endif
|
@@ -1,453 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "device.h"
|
||||
#include "compat/rtas.h"
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
|
||||
#include <device/device.h>
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ops.h>
|
||||
#include <device/resource.h>
|
||||
|
||||
/* the device we are working with... */
|
||||
biosemu_device_t bios_device;
|
||||
//max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges
|
||||
translate_address_t translate_address_array[11];
|
||||
u8 taa_last_entry;
|
||||
|
||||
typedef struct {
|
||||
u8 info;
|
||||
u8 bus;
|
||||
u8 devfn;
|
||||
u8 cfg_space_offset;
|
||||
u64 address;
|
||||
u64 size;
|
||||
} __attribute__ ((__packed__)) assigned_address_t;
|
||||
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
/* coreboot version */
|
||||
|
||||
static void
|
||||
biosemu_dev_get_addr_info(void)
|
||||
{
|
||||
int taa_index = 0;
|
||||
int i = 0;
|
||||
struct resource *r;
|
||||
u8 bus = bios_device.dev->bus->link;
|
||||
u16 devfn = bios_device.dev->path.pci.devfn;
|
||||
|
||||
bios_device.bus = bus;
|
||||
bios_device.devfn = devfn;
|
||||
|
||||
DEBUG_PRINTF("bus: %x, devfn: %x\n", bus, devfn);
|
||||
for (i = 0; i < bios_device.dev->resources; i++) {
|
||||
r = &bios_device.dev->resource[i];
|
||||
translate_address_array[taa_index].info = r->flags;
|
||||
translate_address_array[taa_index].bus = bus;
|
||||
translate_address_array[taa_index].devfn = devfn;
|
||||
translate_address_array[taa_index].cfg_space_offset =
|
||||
r->index;
|
||||
translate_address_array[taa_index].address = r->base;
|
||||
translate_address_array[taa_index].size = r->size;
|
||||
/* dont translate addresses... all addresses are 1:1 */
|
||||
translate_address_array[taa_index].address_offset = 0;
|
||||
taa_index++;
|
||||
}
|
||||
/* Expansion ROM */
|
||||
translate_address_array[taa_index].info = IORESOURCE_MEM | IORESOURCE_READONLY;
|
||||
translate_address_array[taa_index].bus = bus;
|
||||
translate_address_array[taa_index].devfn = devfn;
|
||||
translate_address_array[taa_index].cfg_space_offset = 0x30;
|
||||
translate_address_array[taa_index].address = bios_device.img_addr;
|
||||
translate_address_array[taa_index].size = 0; /* TODO: do we need the size? */
|
||||
/* dont translate addresses... all addresses are 1:1 */
|
||||
translate_address_array[taa_index].address_offset = 0;
|
||||
taa_index++;
|
||||
/* legacy ranges if its a VGA card... */
|
||||
if ((bios_device.dev->class & 0xFF0000) == 0x030000) {
|
||||
DEBUG_PRINTF("%s: VGA device found, adding legacy resources... \n", __func__);
|
||||
/* I/O 0x3B0-0x3BB */
|
||||
translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_IO;
|
||||
translate_address_array[taa_index].bus = bus;
|
||||
translate_address_array[taa_index].devfn = devfn;
|
||||
translate_address_array[taa_index].cfg_space_offset = 0;
|
||||
translate_address_array[taa_index].address = 0x3b0;
|
||||
translate_address_array[taa_index].size = 0xc;
|
||||
/* dont translate addresses... all addresses are 1:1 */
|
||||
translate_address_array[taa_index].address_offset = 0;
|
||||
taa_index++;
|
||||
/* I/O 0x3C0-0x3DF */
|
||||
translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_IO;
|
||||
translate_address_array[taa_index].bus = bus;
|
||||
translate_address_array[taa_index].devfn = devfn;
|
||||
translate_address_array[taa_index].cfg_space_offset = 0;
|
||||
translate_address_array[taa_index].address = 0x3c0;
|
||||
translate_address_array[taa_index].size = 0x20;
|
||||
/* dont translate addresses... all addresses are 1:1 */
|
||||
translate_address_array[taa_index].address_offset = 0;
|
||||
taa_index++;
|
||||
/* Mem 0xA0000-0xBFFFF */
|
||||
translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_MEM;
|
||||
translate_address_array[taa_index].bus = bus;
|
||||
translate_address_array[taa_index].devfn = devfn;
|
||||
translate_address_array[taa_index].cfg_space_offset = 0;
|
||||
translate_address_array[taa_index].address = 0xa0000;
|
||||
translate_address_array[taa_index].size = 0x20000;
|
||||
/* dont translate addresses... all addresses are 1:1 */
|
||||
translate_address_array[taa_index].address_offset = 0;
|
||||
taa_index++;
|
||||
}
|
||||
// store last entry index of translate_address_array
|
||||
taa_last_entry = taa_index - 1;
|
||||
#if defined(CONFIG_X86EMU_DEBUG) && CONFIG_X86EMU_DEBUG
|
||||
//dump translate_address_array
|
||||
printf("translate_address_array: \n");
|
||||
translate_address_t ta;
|
||||
for (i = 0; i <= taa_last_entry; i++) {
|
||||
ta = translate_address_array[i];
|
||||
printf
|
||||
("%d: info: %08lx bus: %02x devfn: %02x cfg_space_offset: %02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
|
||||
i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
|
||||
ta.address, ta.address_offset, ta.size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
// use translate_address_dev and get_puid from net-snk's net_support.c
|
||||
void translate_address_dev(u64 *, phandle_t);
|
||||
u64 get_puid(phandle_t node);
|
||||
|
||||
|
||||
// scan all adresses assigned to the device ("assigned-addresses" and "reg")
|
||||
// store in translate_address_array for faster translation using dev_translate_address
|
||||
void
|
||||
biosemu_dev_get_addr_info(void)
|
||||
{
|
||||
// get bus/dev/fn from assigned-addresses
|
||||
int32_t len;
|
||||
//max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges
|
||||
assigned_address_t buf[11];
|
||||
len =
|
||||
of_getprop(bios_device.phandle, "assigned-addresses", buf,
|
||||
sizeof(buf));
|
||||
bios_device.bus = buf[0].bus;
|
||||
bios_device.devfn = buf[0].devfn;
|
||||
DEBUG_PRINTF("bus: %x, devfn: %x\n", bios_device.bus,
|
||||
bios_device.devfn);
|
||||
//store address translations for all assigned-addresses and regs in
|
||||
//translate_address_array for faster translation later on...
|
||||
int i = 0;
|
||||
// index to insert data into translate_address_array
|
||||
int taa_index = 0;
|
||||
u64 address_offset;
|
||||
for (i = 0; i < (len / sizeof(assigned_address_t)); i++, taa_index++) {
|
||||
//copy all info stored in assigned-addresses
|
||||
translate_address_array[taa_index].info = buf[i].info;
|
||||
translate_address_array[taa_index].bus = buf[i].bus;
|
||||
translate_address_array[taa_index].devfn = buf[i].devfn;
|
||||
translate_address_array[taa_index].cfg_space_offset =
|
||||
buf[i].cfg_space_offset;
|
||||
translate_address_array[taa_index].address = buf[i].address;
|
||||
translate_address_array[taa_index].size = buf[i].size;
|
||||
// translate first address and store it as address_offset
|
||||
address_offset = buf[i].address;
|
||||
translate_address_dev(&address_offset, bios_device.phandle);
|
||||
translate_address_array[taa_index].address_offset =
|
||||
address_offset - buf[i].address;
|
||||
}
|
||||
//get "reg" property
|
||||
len = of_getprop(bios_device.phandle, "reg", buf, sizeof(buf));
|
||||
for (i = 0; i < (len / sizeof(assigned_address_t)); i++) {
|
||||
if ((buf[i].size == 0) || (buf[i].cfg_space_offset != 0)) {
|
||||
// we dont care for ranges with size 0 and
|
||||
// BARs and Expansion ROM must be in assigned-addresses... so in reg
|
||||
// we only look for those without config space offset set...
|
||||
// i.e. the legacy ranges
|
||||
continue;
|
||||
}
|
||||
//copy all info stored in assigned-addresses
|
||||
translate_address_array[taa_index].info = buf[i].info;
|
||||
translate_address_array[taa_index].bus = buf[i].bus;
|
||||
translate_address_array[taa_index].devfn = buf[i].devfn;
|
||||
translate_address_array[taa_index].cfg_space_offset =
|
||||
buf[i].cfg_space_offset;
|
||||
translate_address_array[taa_index].address = buf[i].address;
|
||||
translate_address_array[taa_index].size = buf[i].size;
|
||||
// translate first address and store it as address_offset
|
||||
address_offset = buf[i].address;
|
||||
translate_address_dev(&address_offset, bios_device.phandle);
|
||||
translate_address_array[taa_index].address_offset =
|
||||
address_offset - buf[i].address;
|
||||
taa_index++;
|
||||
}
|
||||
// store last entry index of translate_address_array
|
||||
taa_last_entry = taa_index - 1;
|
||||
#if defined(CONFIG_X86EMU_DEBUG) && CONFIG_X86EMU_DEBUG
|
||||
//dump translate_address_array
|
||||
printf("translate_address_array: \n");
|
||||
translate_address_t ta;
|
||||
for (i = 0; i <= taa_last_entry; i++) {
|
||||
ta = translate_address_array[i];
|
||||
printf
|
||||
("%d: %02x%02x%02x%02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
|
||||
i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
|
||||
ta.address, ta.address_offset, ta.size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
// to simulate accesses to legacy VGA Memory (0xA0000-0xBFFFF)
|
||||
// we look for the first prefetchable memory BAR, if no prefetchable BAR found,
|
||||
// we use the first memory BAR
|
||||
// dev_translate_addr will translate accesses to the legacy VGA Memory into the found vmem BAR
|
||||
static void
|
||||
biosemu_dev_find_vmem_addr(void)
|
||||
{
|
||||
int i = 0;
|
||||
translate_address_t ta;
|
||||
s8 tai_np = -1, tai_p = -1; // translate_address_array index for non-prefetchable and prefetchable memory
|
||||
//search backwards to find first entry
|
||||
for (i = taa_last_entry; i >= 0; i--) {
|
||||
ta = translate_address_array[i];
|
||||
if ((ta.cfg_space_offset >= 0x10)
|
||||
&& (ta.cfg_space_offset <= 0x24)) {
|
||||
//only BARs
|
||||
if ((ta.info & 0x03) >= 0x02) {
|
||||
//32/64bit memory
|
||||
tai_np = i;
|
||||
if ((ta.info & 0x40) != 0) {
|
||||
// prefetchable
|
||||
tai_p = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tai_p != -1) {
|
||||
ta = translate_address_array[tai_p];
|
||||
bios_device.vmem_addr = ta.address;
|
||||
bios_device.vmem_size = ta.size;
|
||||
DEBUG_PRINTF
|
||||
("%s: Found prefetchable Virtual Legacy Memory BAR: %llx, size: %llx\n",
|
||||
__func__, bios_device.vmem_addr,
|
||||
bios_device.vmem_size);
|
||||
} else if (tai_np != -1) {
|
||||
ta = translate_address_array[tai_np];
|
||||
bios_device.vmem_addr = ta.address;
|
||||
bios_device.vmem_size = ta.size;
|
||||
DEBUG_PRINTF
|
||||
("%s: Found non-prefetchable Virtual Legacy Memory BAR: %llx, size: %llx",
|
||||
__func__, bios_device.vmem_addr,
|
||||
bios_device.vmem_size);
|
||||
}
|
||||
// disable vmem
|
||||
//bios_device.vmem_size = 0;
|
||||
}
|
||||
|
||||
void
|
||||
biosemu_dev_get_puid(void)
|
||||
{
|
||||
// get puid
|
||||
bios_device.puid = get_puid(bios_device.phandle);
|
||||
DEBUG_PRINTF("puid: 0x%llx\n", bios_device.puid);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
biosemu_dev_get_device_vendor_id(void)
|
||||
{
|
||||
|
||||
u32 pci_config_0;
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
pci_config_0 = pci_read_config32(bios_device.dev, 0x0);
|
||||
#else
|
||||
pci_config_0 =
|
||||
rtas_pci_config_read(bios_device.puid, 4, bios_device.bus,
|
||||
bios_device.devfn, 0x0);
|
||||
#endif
|
||||
bios_device.pci_device_id =
|
||||
(u16) ((pci_config_0 & 0xFFFF0000) >> 16);
|
||||
bios_device.pci_vendor_id = (u16) (pci_config_0 & 0x0000FFFF);
|
||||
DEBUG_PRINTF("PCI Device ID: %04x, PCI Vendor ID: %x\n",
|
||||
bios_device.pci_device_id, bios_device.pci_vendor_id);
|
||||
}
|
||||
|
||||
/* Check whether the device has a valid Expansion ROM and search the PCI Data
|
||||
* Structure and any Expansion ROM Header (using dev_scan_exp_header()) for
|
||||
* needed information. If the rom_addr parameter is != 0, it is the address of
|
||||
* the Expansion ROM image and will be used, if it is == 0, the Expansion ROM
|
||||
* BAR address will be used.
|
||||
*/
|
||||
u8
|
||||
biosemu_dev_check_exprom(unsigned long rom_base_addr)
|
||||
{
|
||||
int i = 0;
|
||||
translate_address_t ta;
|
||||
u16 pci_ds_offset;
|
||||
pci_data_struct_t pci_ds;
|
||||
if (rom_base_addr == 0) {
|
||||
// check for ExpROM Address (Offset 30) in taa
|
||||
for (i = 0; i <= taa_last_entry; i++) {
|
||||
ta = translate_address_array[i];
|
||||
if (ta.cfg_space_offset == 0x30) {
|
||||
//translated address
|
||||
rom_base_addr = ta.address + ta.address_offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* In the ROM there could be multiple Expansion ROM Images... start
|
||||
* searching them for an x86 image.
|
||||
*/
|
||||
do {
|
||||
if (rom_base_addr == 0) {
|
||||
printf("Error: no Expansion ROM address found!\n");
|
||||
return -1;
|
||||
}
|
||||
set_ci();
|
||||
u16 rom_signature = in16le((void *) rom_base_addr);
|
||||
clr_ci();
|
||||
if (rom_signature != 0xaa55) {
|
||||
printf
|
||||
("Error: invalid Expansion ROM signature: %02x!\n",
|
||||
*((u16 *) rom_base_addr));
|
||||
return -1;
|
||||
}
|
||||
set_ci();
|
||||
// at offset 0x18 is the (16bit little-endian) pointer to the PCI Data Structure
|
||||
pci_ds_offset = in16le((void *) (rom_base_addr + 0x18));
|
||||
//copy the PCI Data Structure
|
||||
memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset),
|
||||
sizeof(pci_ds));
|
||||
clr_ci();
|
||||
#if defined(CONFIG_X86EMU_DEBUG) && CONFIG_X86EMU_DEBUG
|
||||
DEBUG_PRINTF("PCI Data Structure @%lx:\n",
|
||||
rom_base_addr + pci_ds_offset);
|
||||
dump((void *) &pci_ds, sizeof(pci_ds));
|
||||
#endif
|
||||
if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) {
|
||||
printf("Invalid PCI Data Structure found!\n");
|
||||
break;
|
||||
}
|
||||
//little-endian conversion
|
||||
pci_ds.vendor_id = in16le(&pci_ds.vendor_id);
|
||||
pci_ds.device_id = in16le(&pci_ds.device_id);
|
||||
pci_ds.img_length = in16le(&pci_ds.img_length);
|
||||
pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length);
|
||||
if (pci_ds.vendor_id != bios_device.pci_vendor_id) {
|
||||
printf
|
||||
("Image has invalid Vendor ID: %04x, expected: %04x\n",
|
||||
pci_ds.vendor_id, bios_device.pci_vendor_id);
|
||||
break;
|
||||
}
|
||||
if (pci_ds.device_id != bios_device.pci_device_id) {
|
||||
printf
|
||||
("Image has invalid Device ID: %04x, expected: %04x\n",
|
||||
pci_ds.device_id, bios_device.pci_device_id);
|
||||
break;
|
||||
}
|
||||
DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512);
|
||||
DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type);
|
||||
if (pci_ds.code_type == 0) {
|
||||
//x86 image
|
||||
//store image address and image length in bios_device struct
|
||||
bios_device.img_addr = rom_base_addr;
|
||||
bios_device.img_size = pci_ds.img_length * 512;
|
||||
// we found the image, exit the loop
|
||||
break;
|
||||
} else {
|
||||
// no x86 image, check next image (if any)
|
||||
rom_base_addr += pci_ds.img_length * 512;
|
||||
}
|
||||
if ((pci_ds.indicator & 0x80) == 0x80) {
|
||||
//last image found, exit the loop
|
||||
DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (bios_device.img_addr == 0);
|
||||
// in case we did not find a valid x86 Expansion ROM Image
|
||||
if (bios_device.img_addr == 0) {
|
||||
printf("Error: no valid x86 Expansion ROM Image found!\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8
|
||||
biosemu_dev_init(struct device * device)
|
||||
{
|
||||
u8 rval = 0;
|
||||
//init bios_device struct
|
||||
DEBUG_PRINTF("%s\n", __func__);
|
||||
memset(&bios_device, 0, sizeof(bios_device));
|
||||
|
||||
#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
bios_device.ihandle = of_open(device_name);
|
||||
if (bios_device.ihandle == 0) {
|
||||
DEBUG_PRINTF("%s is no valid device!\n", device_name);
|
||||
return -1;
|
||||
}
|
||||
bios_device.phandle = of_finddevice(device_name);
|
||||
#else
|
||||
bios_device.dev = device;
|
||||
#endif
|
||||
biosemu_dev_get_addr_info();
|
||||
#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
biosemu_dev_find_vmem_addr();
|
||||
biosemu_dev_get_puid();
|
||||
#endif
|
||||
biosemu_dev_get_device_vendor_id();
|
||||
return rval;
|
||||
}
|
||||
|
||||
// translate address function using translate_address_array assembled
|
||||
// by dev_get_addr_info... MUCH faster than calling translate_address_dev
|
||||
// and accessing client interface for every translation...
|
||||
// returns: 0 if addr not found in translate_address_array, 1 if found.
|
||||
u8
|
||||
biosemu_dev_translate_address(unsigned long * addr)
|
||||
{
|
||||
int i = 0;
|
||||
translate_address_t ta;
|
||||
#ifndef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
/* we dont need this hack for coreboot... we can access legacy areas */
|
||||
//check if it is an access to legacy VGA Mem... if it is, map the address
|
||||
//to the vmem BAR and then translate it...
|
||||
// (translation info provided by Ben Herrenschmidt)
|
||||
// NOTE: the translation seems to only work for NVIDIA cards... but it is needed
|
||||
// to make some NVIDIA cards work at all...
|
||||
if ((bios_device.vmem_size > 0)
|
||||
&& ((*addr >= 0xA0000) && (*addr < 0xB8000))) {
|
||||
*addr = (*addr - 0xA0000) * 4 + 2 + bios_device.vmem_addr;
|
||||
}
|
||||
if ((bios_device.vmem_size > 0)
|
||||
&& ((*addr >= 0xB8000) && (*addr < 0xC0000))) {
|
||||
u8 shift = *addr & 1;
|
||||
*addr &= 0xfffffffe;
|
||||
*addr = (*addr - 0xB8000) * 4 + shift + bios_device.vmem_addr;
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i <= taa_last_entry; i++) {
|
||||
ta = translate_address_array[i];
|
||||
if ((*addr >= ta.address) && (*addr <= (ta.address + ta.size))) {
|
||||
*addr += ta.address_offset;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
@@ -1,182 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef DEVICE_LIB_H
|
||||
#define DEVICE_LIB_H
|
||||
|
||||
#include <types.h>
|
||||
#include <arch/byteorder.h>
|
||||
#include "compat/of.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
// a Expansion Header Struct as defined in Plug and Play BIOS Spec 1.0a Chapter 3.2
|
||||
typedef struct {
|
||||
char signature[4]; // signature
|
||||
u8 structure_revision;
|
||||
u8 length; // in 16 byte blocks
|
||||
u16 next_header_offset; // offset to next Expansion Header as 16bit little-endian value, as offset from the start of the Expansion ROM
|
||||
u8 reserved;
|
||||
u8 checksum; // the sum of all bytes of the Expansion Header must be 0
|
||||
u32 device_id; // PnP Device ID as 32bit little-endian value
|
||||
u16 p_manufacturer_string; //16bit little-endian offset from start of Expansion ROM
|
||||
u16 p_product_string; //16bit little-endian offset from start of Expansion ROM
|
||||
u8 device_base_type;
|
||||
u8 device_sub_type;
|
||||
u8 device_if_type;
|
||||
u8 device_indicators;
|
||||
// the following vectors are all 16bit little-endian offsets from start of Expansion ROM
|
||||
u16 bcv; // Boot Connection Vector
|
||||
u16 dv; // Disconnect Vector
|
||||
u16 bev; // Bootstrap Entry Vector
|
||||
u16 reserved_2;
|
||||
u16 sriv; // Static Resource Information Vector
|
||||
} __attribute__ ((__packed__)) exp_header_struct_t;
|
||||
|
||||
// a PCI Data Struct as defined in PCI 2.3 Spec Chapter 6.3.1.2
|
||||
typedef struct {
|
||||
u8 signature[4]; // signature, the String "PCIR"
|
||||
u16 vendor_id;
|
||||
u16 device_id;
|
||||
u16 reserved;
|
||||
u16 pci_ds_length; // PCI Data Structure Length, 16bit little-endian value
|
||||
u8 pci_ds_revision;
|
||||
u8 class_code[3];
|
||||
u16 img_length; // length of the Exp.ROM Image, 16bit little-endian value in 512 bytes
|
||||
u16 img_revision;
|
||||
u8 code_type;
|
||||
u8 indicator;
|
||||
u16 reserved_2;
|
||||
} __attribute__ ((__packed__)) pci_data_struct_t;
|
||||
|
||||
typedef struct {
|
||||
u8 bus;
|
||||
u8 devfn;
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
struct device* dev;
|
||||
#else
|
||||
u64 puid;
|
||||
phandle_t phandle;
|
||||
ihandle_t ihandle;
|
||||
#endif
|
||||
// store the address of the BAR that is used to simulate
|
||||
// legacy VGA memory accesses
|
||||
u64 vmem_addr;
|
||||
u64 vmem_size;
|
||||
// used to buffer I/O Accesses, that do not access the I/O Range of the device...
|
||||
// 64k might be overkill, but we can buffer all I/O accesses...
|
||||
u8 io_buffer[64 * 1024];
|
||||
u16 pci_vendor_id;
|
||||
u16 pci_device_id;
|
||||
// translated address of the "PC-Compatible" Expansion ROM Image for this device
|
||||
unsigned long img_addr;
|
||||
u32 img_size; // size of the Expansion ROM Image (read from the PCI Data Structure)
|
||||
} biosemu_device_t;
|
||||
|
||||
typedef struct {
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
unsigned long info;
|
||||
#else
|
||||
u8 info;
|
||||
#endif
|
||||
u8 bus;
|
||||
u8 devfn;
|
||||
u8 cfg_space_offset;
|
||||
u64 address;
|
||||
u64 address_offset;
|
||||
u64 size;
|
||||
} __attribute__ ((__packed__)) translate_address_t;
|
||||
|
||||
// array to store address translations for this
|
||||
// device. Needed for faster address translation, so
|
||||
// not every I/O or Memory Access needs to call translate_address_dev
|
||||
// and access the device tree
|
||||
// 6 BARs, 1 Exp. ROM, 1 Cfg.Space, and 3 Legacy
|
||||
// translations are supported... this should be enough for
|
||||
// most devices... for VGA it is enough anyways...
|
||||
extern translate_address_t translate_address_array[11];
|
||||
|
||||
// index of last translate_address_array entry
|
||||
// set by get_dev_addr_info function
|
||||
extern u8 taa_last_entry;
|
||||
|
||||
/* the device we are working with... */
|
||||
extern biosemu_device_t bios_device;
|
||||
|
||||
u8 biosemu_dev_init(struct device * device);
|
||||
// NOTE: for dev_check_exprom to work, biosemu_dev_init MUST be called first!
|
||||
u8 biosemu_dev_check_exprom(unsigned long rom_base_addr);
|
||||
|
||||
u8 biosemu_dev_translate_address(unsigned long * addr);
|
||||
|
||||
/* endianness swap functions for 16 and 32 bit words
|
||||
* copied from axon_pciconfig.c
|
||||
*/
|
||||
static inline void
|
||||
out32le(void *addr, u32 val)
|
||||
{
|
||||
#ifdef __i386
|
||||
*((u32*) addr) = cpu_to_le32(val);
|
||||
#else
|
||||
asm volatile ("stwbrx %0, 0, %1"::"r" (val), "r"(addr));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u32
|
||||
in32le(void *addr)
|
||||
{
|
||||
u32 val;
|
||||
#ifdef __i386
|
||||
val = cpu_to_le32(*((u32 *) addr));
|
||||
#else
|
||||
asm volatile ("lwbrx %0, 0, %1":"=r" (val):"r"(addr));
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
out16le(void *addr, u16 val)
|
||||
{
|
||||
#ifdef __i386
|
||||
*((u16*) addr) = cpu_to_le16(val);
|
||||
#else
|
||||
asm volatile ("sthbrx %0, 0, %1"::"r" (val), "r"(addr));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u16
|
||||
in16le(void *addr)
|
||||
{
|
||||
u16 val;
|
||||
#ifdef __i386
|
||||
val = cpu_to_le16(*((u16*) addr));
|
||||
#else
|
||||
asm volatile ("lhbrx %0, 0, %1":"=r" (val):"r"(addr));
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
/* debug function, dumps HID1 and HID4 to detect whether caches are on/off */
|
||||
static inline void
|
||||
dumpHID(void)
|
||||
{
|
||||
u64 hid;
|
||||
//HID1 = 1009
|
||||
__asm__ __volatile__("mfspr %0, 1009":"=r"(hid));
|
||||
printf("HID1: %016llx\n", hid);
|
||||
//HID4 = 1012
|
||||
__asm__ __volatile__("mfspr %0, 1012":"=r"(hid));
|
||||
printf("HID4: %016llx\n", hid);
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,677 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2008, 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#include <types.h>
|
||||
#include "compat/rtas.h"
|
||||
|
||||
#include "biosemu.h"
|
||||
#include "mem.h"
|
||||
#include "device.h"
|
||||
#include "debug.h"
|
||||
#include "pmm.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#include <x86emu/x86emu.h>
|
||||
#include "../x86emu/prim_ops.h"
|
||||
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ops.h>
|
||||
#endif
|
||||
|
||||
|
||||
//setup to run the code at the address, that the Interrupt Vector points to...
|
||||
static void
|
||||
setupInt(int intNum)
|
||||
{
|
||||
DEBUG_PRINTF_INTR("%s(%x): executing interrupt handler @%08x\n",
|
||||
__func__, intNum, my_rdl(intNum * 4));
|
||||
// push current R_FLG... will be popped by IRET
|
||||
push_word((u16) M.x86.R_FLG);
|
||||
CLEAR_FLAG(F_IF);
|
||||
CLEAR_FLAG(F_TF);
|
||||
// push current CS:IP to the stack, will be popped by IRET
|
||||
push_word(M.x86.R_CS);
|
||||
push_word(M.x86.R_IP);
|
||||
// set CS:IP to the interrupt handler address... so the next executed instruction will
|
||||
// be the interrupt handler
|
||||
M.x86.R_CS = my_rdw(intNum * 4 + 2);
|
||||
M.x86.R_IP = my_rdw(intNum * 4);
|
||||
}
|
||||
|
||||
// handle int10 (VGA BIOS Interrupt)
|
||||
static void
|
||||
handleInt10(void)
|
||||
{
|
||||
// the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h
|
||||
// function number in AH
|
||||
//DEBUG_PRINTF_CS_IP("%s:\n", __func__);
|
||||
//x86emu_dump_xregs();
|
||||
//if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){
|
||||
//X86EMU_trace_on();
|
||||
//M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
|
||||
//}
|
||||
switch (M.x86.R_AH) {
|
||||
case 0x00:
|
||||
// set video mode
|
||||
// BDA offset 49h is current video mode
|
||||
my_wrb(0x449, M.x86.R_AL);
|
||||
if (M.x86.R_AL > 7)
|
||||
M.x86.R_AL = 0x20;
|
||||
else if (M.x86.R_AL == 6)
|
||||
M.x86.R_AL = 0x3f;
|
||||
else
|
||||
M.x86.R_AL = 0x30;
|
||||
break;
|
||||
case 0x01:
|
||||
// set cursor shape
|
||||
// ignore
|
||||
break;
|
||||
case 0x02:
|
||||
// set cursor position
|
||||
// BH: pagenumber, DX: cursor_pos (DH:row, DL:col)
|
||||
// BDA offset 50h-60h are 8 cursor position words for
|
||||
// eight possible video pages
|
||||
my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX);
|
||||
break;
|
||||
case 0x03:
|
||||
//get cursor position
|
||||
// BH: pagenumber
|
||||
// BDA offset 50h-60h are 8 cursor position words for
|
||||
// eight possible video pages
|
||||
M.x86.R_AX = 0;
|
||||
M.x86.R_CH = 0; // start scan line ???
|
||||
M.x86.R_CL = 0; // end scan line ???
|
||||
M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2));
|
||||
break;
|
||||
case 0x05:
|
||||
// set active page
|
||||
// BDA offset 62h is current page number
|
||||
my_wrb(0x462, M.x86.R_AL);
|
||||
break;
|
||||
case 0x06:
|
||||
//scroll up windows
|
||||
break;
|
||||
case 0x07:
|
||||
//scroll down windows
|
||||
break;
|
||||
case 0x08:
|
||||
//read character and attribute at position
|
||||
M.x86.R_AH = 0x07; // white-on-black
|
||||
M.x86.R_AL = 0x20; // a space...
|
||||
break;
|
||||
case 0x09:
|
||||
// write character and attribute
|
||||
//AL: char, BH: page number, BL: attribute, CX: number of times to write
|
||||
//BDA offset 62h is current page number
|
||||
CHECK_DBG(DEBUG_PRINT_INT10) {
|
||||
u32 i = 0;
|
||||
if (M.x86.R_BH == my_rdb(0x462)) {
|
||||
for (i = 0; i < M.x86.R_CX; i++)
|
||||
printf("%c", M.x86.R_AL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0a:
|
||||
// write character
|
||||
//AL: char, BH: page number, BL: attribute, CX: number of times to write
|
||||
//BDA offset 62h is current page number
|
||||
CHECK_DBG(DEBUG_PRINT_INT10) {
|
||||
u32 i = 0;
|
||||
if (M.x86.R_BH == my_rdb(0x462)) {
|
||||
for (i = 0; i < M.x86.R_CX; i++)
|
||||
printf("%c", M.x86.R_AL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0e:
|
||||
// teletype output: write character and advance cursor...
|
||||
//AL: char, BH: page number, BL: attribute
|
||||
//BDA offset 62h is current page number
|
||||
CHECK_DBG(DEBUG_PRINT_INT10) {
|
||||
// we ignore the pagenumber on this call...
|
||||
//if (M.x86.R_BH == my_rdb(0x462))
|
||||
{
|
||||
printf("%c", M.x86.R_AL);
|
||||
// for debugging, to read all lines
|
||||
//if (M.x86.R_AL == 0xd) // carriage return
|
||||
// printf("\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0f:
|
||||
// get video mode
|
||||
// BDA offset 49h is current video mode
|
||||
// BDA offset 62h is current page number
|
||||
// BDA offset 4ah is columns on screen
|
||||
M.x86.R_AH = 80; //number of character columns... we hardcode it to 80
|
||||
M.x86.R_AL = my_rdb(0x449);
|
||||
M.x86.R_BH = my_rdb(0x462);
|
||||
break;
|
||||
default:
|
||||
printf("%s(): unknown function (%x) for int10 handler.\n",
|
||||
__func__, M.x86.R_AH);
|
||||
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
||||
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
||||
M.x86.R_DX);
|
||||
HALT_SYS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this table translates ASCII chars into their XT scan codes:
|
||||
static u8 keycode_table[256] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 - 7
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8 - 15
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 23
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24 - 31
|
||||
0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, // 32 - 39
|
||||
0x0a, 0x0b, 0x09, 0x2b, 0x33, 0x0d, 0x34, 0x35, // 40 - 47
|
||||
0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 48 - 55
|
||||
0x09, 0x0a, 0x27, 0x27, 0x33, 0x2b, 0x34, 0x35, // 56 - 63
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 64 - 71
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 72 - 79
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 87
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 95
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 103
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 104 - 111
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 112 - 119
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120 - 127
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
static void
|
||||
translate_keycode(u64 * keycode)
|
||||
{
|
||||
u8 scan_code = 0;
|
||||
u8 char_code = 0;
|
||||
if (*keycode < 256) {
|
||||
scan_code = keycode_table[*keycode];
|
||||
char_code = (u8) * keycode & 0xff;
|
||||
} else {
|
||||
switch (*keycode) {
|
||||
case 0x1b50:
|
||||
// F1
|
||||
scan_code = 0x3b;
|
||||
char_code = 0x0;
|
||||
break;
|
||||
default:
|
||||
printf("%s(): unknown multibyte keycode: %llx\n",
|
||||
__func__, *keycode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//assemble scan/char code in keycode
|
||||
*keycode = (u64) ((((u16) scan_code) << 8) | char_code);
|
||||
}
|
||||
|
||||
// handle int16 (Keyboard BIOS Interrupt)
|
||||
static void
|
||||
handleInt16(void)
|
||||
{
|
||||
// keyboard buffer is in BIOS Memory Area:
|
||||
// offset 0x1a (WORD) pointer to next char in keybuffer
|
||||
// offset 0x1c (WORD) pointer to next insert slot in keybuffer
|
||||
// offset 0x1e-0x3e: 16 WORD Ring Buffer
|
||||
// since we currently always read the char from the FW buffer,
|
||||
// we misuse the ring buffer, we use it as pointer to a u64 that stores
|
||||
// multi-byte keys (e.g. special keys in VT100 terminal)
|
||||
// and as long as a key is available (not 0) we dont read further keys
|
||||
u64 *keycode = (u64 *) (M.mem_base + 0x41e);
|
||||
s8 c;
|
||||
// function number in AH
|
||||
DEBUG_PRINTF_INTR("%s(): Keyboard Interrupt: function: %x.\n",
|
||||
__func__, M.x86.R_AH);
|
||||
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX,
|
||||
M.x86.R_BX, M.x86.R_CX, M.x86.R_DX);
|
||||
switch (M.x86.R_AH) {
|
||||
case 0x00:
|
||||
// get keystroke
|
||||
if (*keycode) {
|
||||
M.x86.R_AX = (u16) * keycode;
|
||||
// clear keycode
|
||||
*keycode = 0;
|
||||
} else {
|
||||
M.x86.R_AH = 0x61; // scancode for space key
|
||||
M.x86.R_AL = 0x20; // a space
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
// check keystroke
|
||||
// ZF set = no keystroke
|
||||
// read first byte of key code
|
||||
if (*keycode) {
|
||||
// already read, but not yet taken
|
||||
CLEAR_FLAG(F_ZF);
|
||||
M.x86.R_AX = (u16) * keycode;
|
||||
} else {
|
||||
/* TODO: we need getchar... */
|
||||
c = -1; //getchar();
|
||||
if (c == -1) {
|
||||
// no key available
|
||||
SET_FLAG(F_ZF);
|
||||
} else {
|
||||
*keycode = c;
|
||||
|
||||
// since after an ESC it may take a while to receive the next char,
|
||||
// we send something that is not shown on the screen, and then try to get
|
||||
// the next char
|
||||
// TODO: only after ESC?? what about other multibyte keys
|
||||
printf("tt%c%c", 0x08, 0x08); // 0x08 == Backspace
|
||||
|
||||
/* TODO: we need getchar... */
|
||||
while ((c = -1 /*getchar()*/) != -1) {
|
||||
*keycode = (*keycode << 8) | c;
|
||||
DEBUG_PRINTF(" key read: %0llx\n",
|
||||
*keycode);
|
||||
}
|
||||
translate_keycode(keycode);
|
||||
DEBUG_PRINTF(" translated key: %0llx\n",
|
||||
*keycode);
|
||||
if (*keycode == 0) {
|
||||
//not found
|
||||
SET_FLAG(F_ZF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
M.x86.R_AX = (u16) * keycode;
|
||||
//X86EMU_trace_on();
|
||||
//M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("%s(): unknown function (%x) for int16 handler.\n",
|
||||
__func__, M.x86.R_AH);
|
||||
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
||||
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
||||
M.x86.R_DX);
|
||||
HALT_SYS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// handle int1a (PCI BIOS Interrupt)
|
||||
static void
|
||||
handleInt1a(void)
|
||||
{
|
||||
// function number in AX
|
||||
u8 bus, devfn, offs;
|
||||
struct device* dev;
|
||||
switch (M.x86.R_AX) {
|
||||
case 0xb101:
|
||||
// Installation check
|
||||
CLEAR_FLAG(F_CF); // clear CF
|
||||
M.x86.R_EDX = 0x20494350; // " ICP" endian swapped "PCI "
|
||||
M.x86.R_AL = 0x1; // Config Space Mechanism 1 supported
|
||||
M.x86.R_BX = 0x0210; // PCI Interface Level Version 2.10
|
||||
M.x86.R_CL = 0xff; // number of last PCI Bus in system TODO: check!
|
||||
break;
|
||||
case 0xb102:
|
||||
// Find PCI Device
|
||||
// device_id in CX, vendor_id in DX
|
||||
// device index in SI (i.e. if multiple devices with same vendor/device id
|
||||
// are connected). We currently only support device index 0
|
||||
//
|
||||
DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n",
|
||||
__func__, M.x86.R_AX);
|
||||
/* FixME: support SI != 0 */
|
||||
#if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
|
||||
dev = dev_find_device(M.x86.R_DX, M.x86.R_CX, 0);
|
||||
if (dev != 0) {
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(): function %x: PCI Find Device --> 0x%04x\n",
|
||||
__func__, M.x86.R_AX, M.x86.R_BX);
|
||||
|
||||
M.x86.R_BH = dev->bus->secondary;
|
||||
M.x86.R_BL = dev->path.pci.devfn;
|
||||
M.x86.R_AH = 0x00; // return code: success
|
||||
CLEAR_FLAG(F_CF);
|
||||
#else
|
||||
// only allow the device to find itself...
|
||||
if ((M.x86.R_CX == bios_device.pci_device_id)
|
||||
&& (M.x86.R_DX == bios_device.pci_vendor_id)
|
||||
// device index must be 0
|
||||
&& (M.x86.R_SI == 0)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
M.x86.R_AH = 0x00; // return code: success
|
||||
M.x86.R_BH = bios_device.bus;
|
||||
M.x86.R_BL = bios_device.devfn;
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/00) \n",
|
||||
__func__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX,
|
||||
M.x86.R_SI, bios_device.pci_device_id,
|
||||
bios_device.pci_vendor_id);
|
||||
|
||||
SET_FLAG(F_CF);
|
||||
M.x86.R_AH = 0x86; // return code: device not found
|
||||
}
|
||||
break;
|
||||
case 0xb108: //read configuration byte
|
||||
case 0xb109: //read configuration word
|
||||
case 0xb10a: //read configuration dword
|
||||
bus = M.x86.R_BH;
|
||||
devfn = M.x86.R_BL;
|
||||
offs = M.x86.R_DI;
|
||||
DEBUG_PRINTF_INTR("%s(): function: %x: PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
|
||||
__func__, M.x86.R_AX, bus, devfn, offs);
|
||||
#if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
|
||||
dev = dev_find_slot(bus, devfn);
|
||||
DEBUG_PRINTF_INTR("%s(): function: %x: dev_find_slot() returned: %s\n",
|
||||
__func__, M.x86.R_AX, dev_path(dev));
|
||||
if (dev == 0) {
|
||||
// fail accesses to non-existent devices...
|
||||
#else
|
||||
dev = bios_device.dev;
|
||||
if ((bus != bios_device.bus)
|
||||
|| (devfn != bios_device.devfn)) {
|
||||
// fail accesses to any device but ours...
|
||||
#endif
|
||||
printf
|
||||
("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
|
||||
__func__, bus, bios_device.bus, devfn,
|
||||
bios_device.devfn, offs);
|
||||
SET_FLAG(F_CF);
|
||||
M.x86.R_AH = 0x87; //return code: bad pci register
|
||||
HALT_SYS();
|
||||
return;
|
||||
} else {
|
||||
switch (M.x86.R_AX) {
|
||||
case 0xb108:
|
||||
M.x86.R_CL =
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
pci_read_config8(dev, offs);
|
||||
#else
|
||||
(u8) rtas_pci_config_read(bios_device.
|
||||
puid, 1,
|
||||
bus, devfn,
|
||||
offs);
|
||||
#endif
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n",
|
||||
__func__, M.x86.R_AX, offs,
|
||||
M.x86.R_CL);
|
||||
break;
|
||||
case 0xb109:
|
||||
M.x86.R_CX =
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
pci_read_config16(dev, offs);
|
||||
#else
|
||||
(u16) rtas_pci_config_read(bios_device.
|
||||
puid, 2,
|
||||
bus, devfn,
|
||||
offs);
|
||||
#endif
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n",
|
||||
__func__, M.x86.R_AX, offs,
|
||||
M.x86.R_CX);
|
||||
break;
|
||||
case 0xb10a:
|
||||
M.x86.R_ECX =
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
pci_read_config32(dev, offs);
|
||||
#else
|
||||
(u32) rtas_pci_config_read(bios_device.
|
||||
puid, 4,
|
||||
bus, devfn,
|
||||
offs);
|
||||
#endif
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n",
|
||||
__func__, M.x86.R_AX, offs,
|
||||
M.x86.R_ECX);
|
||||
break;
|
||||
}
|
||||
CLEAR_FLAG(F_CF);
|
||||
M.x86.R_AH = 0x0; // return code: success
|
||||
}
|
||||
break;
|
||||
case 0xb10b: //write configuration byte
|
||||
case 0xb10c: //write configuration word
|
||||
case 0xb10d: //write configuration dword
|
||||
bus = M.x86.R_BH;
|
||||
devfn = M.x86.R_BL;
|
||||
offs = M.x86.R_DI;
|
||||
if ((bus != bios_device.bus)
|
||||
|| (devfn != bios_device.devfn)) {
|
||||
// fail accesses to any device but ours...
|
||||
printf
|
||||
("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n",
|
||||
__func__, bus, bios_device.bus, devfn,
|
||||
bios_device.devfn, offs);
|
||||
SET_FLAG(F_CF);
|
||||
M.x86.R_AH = 0x87; //return code: bad pci register
|
||||
HALT_SYS();
|
||||
return;
|
||||
} else {
|
||||
switch (M.x86.R_AX) {
|
||||
case 0xb10b:
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
pci_write_config8(bios_device.dev, offs, M.x86.R_CL);
|
||||
#else
|
||||
rtas_pci_config_write(bios_device.puid, 1, bus,
|
||||
devfn, offs, M.x86.R_CL);
|
||||
#endif
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n",
|
||||
__func__, M.x86.R_AX, offs,
|
||||
M.x86.R_CL);
|
||||
break;
|
||||
case 0xb10c:
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
pci_write_config16(bios_device.dev, offs, M.x86.R_CX);
|
||||
#else
|
||||
rtas_pci_config_write(bios_device.puid, 2, bus,
|
||||
devfn, offs, M.x86.R_CX);
|
||||
#endif
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n",
|
||||
__func__, M.x86.R_AX, offs,
|
||||
M.x86.R_CX);
|
||||
break;
|
||||
case 0xb10d:
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
pci_write_config32(bios_device.dev, offs, M.x86.R_ECX);
|
||||
#else
|
||||
rtas_pci_config_write(bios_device.puid, 4, bus,
|
||||
devfn, offs, M.x86.R_ECX);
|
||||
#endif
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n",
|
||||
__func__, M.x86.R_AX, offs,
|
||||
M.x86.R_ECX);
|
||||
break;
|
||||
}
|
||||
CLEAR_FLAG(F_CF);
|
||||
M.x86.R_AH = 0x0; // return code: success
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("%s(): unknown function (%x) for int1a handler.\n",
|
||||
__func__, M.x86.R_AX);
|
||||
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
||||
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
||||
M.x86.R_DX);
|
||||
HALT_SYS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// main Interrupt Handler routine, should be registered as x86emu interrupt handler
|
||||
void
|
||||
handleInterrupt(int intNum)
|
||||
{
|
||||
u8 int_handled = 0;
|
||||
#ifndef DEBUG_PRINT_INT10
|
||||
// this printf makes output by int 10 unreadable...
|
||||
// so we only enable it, if int10 print is disabled
|
||||
DEBUG_PRINTF_INTR("%s(%x)\n", __func__, intNum);
|
||||
#endif
|
||||
|
||||
/* check wether this interrupt has a function pointer set in yabel_intFuncArray and run that */
|
||||
if (yabel_intFuncArray[intNum]) {
|
||||
DEBUG_PRINTF_INTR("%s(%x) intHandler overridden, calling it...\n", __func__, intNum);
|
||||
int_handled = (*yabel_intFuncArray[intNum])();
|
||||
} else {
|
||||
switch (intNum) {
|
||||
case 0x10: //BIOS video interrupt
|
||||
case 0x42: // INT 10h relocated by EGA/VGA BIOS
|
||||
case 0x6d: // INT 10h relocated by VGA BIOS
|
||||
// get interrupt vector from IDT (4 bytes per Interrupt starting at address 0
|
||||
if ((my_rdl(intNum * 4) == 0xF000F065) || //F000:F065 is default BIOS interrupt handler address
|
||||
(my_rdl(intNum * 4) == 0xF4F4F4F4)) //invalid
|
||||
{
|
||||
#if 0
|
||||
// ignore interrupt...
|
||||
DEBUG_PRINTF_INTR
|
||||
("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n",
|
||||
__func__, intNum, my_rdl(intNum * 4));
|
||||
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
||||
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
||||
M.x86.R_DX);
|
||||
//HALT_SYS();
|
||||
#endif
|
||||
handleInt10();
|
||||
int_handled = 1;
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
// Keyboard BIOS Interrupt
|
||||
handleInt16();
|
||||
int_handled = 1;
|
||||
break;
|
||||
case 0x1a:
|
||||
// PCI BIOS Interrupt
|
||||
handleInt1a();
|
||||
int_handled = 1;
|
||||
break;
|
||||
case PMM_INT_NUM:
|
||||
/* the selfdefined PMM INT number, this is called by the code in PMM struct, it
|
||||
* is handled by pmm_handleInt()
|
||||
*/
|
||||
pmm_handleInt();
|
||||
int_handled = 1;
|
||||
break;
|
||||
default:
|
||||
printf("Interrupt %#x (Vector: %x) not implemented\n", intNum,
|
||||
my_rdl(intNum * 4));
|
||||
DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
|
||||
M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
|
||||
M.x86.R_DX);
|
||||
int_handled = 1;
|
||||
HALT_SYS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if we did not handle the interrupt, jump to the interrupt vector...
|
||||
if (!int_handled) {
|
||||
setupInt(intNum);
|
||||
}
|
||||
}
|
||||
|
||||
// prepare and execute Interrupt 10 (VGA Interrupt)
|
||||
void
|
||||
runInt10(void)
|
||||
{
|
||||
// Initialize stack and data segment
|
||||
M.x86.R_SS = STACK_SEGMENT;
|
||||
M.x86.R_DS = DATA_SEGMENT;
|
||||
M.x86.R_SP = STACK_START_OFFSET;
|
||||
|
||||
// push a HLT instruction and a pointer to it onto the stack
|
||||
// any return will pop the pointer and jump to the HLT, thus
|
||||
// exiting (more or less) cleanly
|
||||
push_word(0xf4f4); //F4=HLT
|
||||
//push_word(M.x86.R_SS);
|
||||
//push_word(M.x86.R_SP + 2);
|
||||
|
||||
// setupInt will push the current CS and IP to the stack to return to it,
|
||||
// but we want to halt, so set CS:IP to the HLT instruction we just pushed
|
||||
// to the stack
|
||||
M.x86.R_CS = M.x86.R_SS;
|
||||
M.x86.R_IP = M.x86.R_SP; // + 4;
|
||||
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
CHECK_DBG(DEBUG_JMP) {
|
||||
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
||||
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
||||
M.x86.debug |= DEBUG_TRACECALL_F;
|
||||
M.x86.debug |= DEBUG_TRACECALL_REGS_F;
|
||||
}
|
||||
setupInt(0x10);
|
||||
DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n",
|
||||
__func__);
|
||||
X86EMU_exec();
|
||||
DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
|
||||
}
|
||||
|
||||
// prepare and execute Interrupt 13 (Disk Interrupt)
|
||||
void
|
||||
runInt13(void)
|
||||
{
|
||||
// Initialize stack and data segment
|
||||
M.x86.R_SS = STACK_SEGMENT;
|
||||
M.x86.R_DS = DATA_SEGMENT;
|
||||
M.x86.R_SP = STACK_START_OFFSET;
|
||||
|
||||
// push a HLT instruction and a pointer to it onto the stack
|
||||
// any return will pop the pointer and jump to the HLT, thus
|
||||
// exiting (more or less) cleanly
|
||||
push_word(0xf4f4); //F4=HLT
|
||||
//push_word(M.x86.R_SS);
|
||||
//push_word(M.x86.R_SP + 2);
|
||||
|
||||
// setupInt will push the current CS and IP to the stack to return to it,
|
||||
// but we want to halt, so set CS:IP to the HLT instruction we just pushed
|
||||
// to the stack
|
||||
M.x86.R_CS = M.x86.R_SS;
|
||||
M.x86.R_IP = M.x86.R_SP;
|
||||
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
CHECK_DBG(DEBUG_JMP) {
|
||||
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
||||
M.x86.debug |= DEBUG_TRACEJMP_REGS_F;
|
||||
M.x86.debug |= DEBUG_TRACECALL_F;
|
||||
M.x86.debug |= DEBUG_TRACECALL_REGS_F;
|
||||
}
|
||||
|
||||
setupInt(0x13);
|
||||
DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n",
|
||||
__func__);
|
||||
X86EMU_exec();
|
||||
DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__);
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
#ifndef _BIOSEMU_INTERRUPT_H_
|
||||
#define _BIOSEMU_INTERRUPT_H_
|
||||
|
||||
void handleInterrupt(int intNum);
|
||||
|
||||
void runInt10(void);
|
||||
|
||||
void runInt13(void);
|
||||
|
||||
#endif
|
@@ -1,574 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#include <types.h>
|
||||
#include "compat/rtas.h"
|
||||
#include "compat/time.h"
|
||||
#include "device.h"
|
||||
#include "debug.h"
|
||||
#include <x86emu/x86emu.h>
|
||||
#include "io.h"
|
||||
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ops.h>
|
||||
#endif
|
||||
|
||||
static unsigned int
|
||||
read_io(void *addr, size_t sz)
|
||||
{
|
||||
unsigned int ret;
|
||||
/* since we are using inb instructions, we need the port number as 16bit value */
|
||||
u16 port = (u16)(u32) addr;
|
||||
|
||||
switch (sz) {
|
||||
case 1:
|
||||
asm volatile ("inb %1, %b0" : "=a"(ret) : "d" (port));
|
||||
break;
|
||||
case 2:
|
||||
asm volatile ("inw %1, %w0" : "=a"(ret) : "d" (port));
|
||||
break;
|
||||
case 4:
|
||||
asm volatile ("inl %1, %0" : "=a"(ret) : "d" (port));
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
write_io(void *addr, unsigned int value, size_t sz)
|
||||
{
|
||||
u16 port = (u16)(u32) addr;
|
||||
switch (sz) {
|
||||
/* since we are using inb instructions, we need the port number as 16bit value */
|
||||
case 1:
|
||||
asm volatile ("outb %b0, %1" : : "a"(value), "d" (port));
|
||||
break;
|
||||
case 2:
|
||||
asm volatile ("outw %w0, %1" : : "a"(value), "d" (port));
|
||||
break;
|
||||
case 4:
|
||||
asm volatile ("outl %0, %1" : : "a"(value), "d" (port));
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_X86
|
||||
#include <arch/io.h>
|
||||
#else
|
||||
// these are not used, only needed for linking, must be overridden using X86emu_setupPioFuncs
|
||||
// with the functions and struct below
|
||||
void
|
||||
outb(u8 val, u16 port)
|
||||
{
|
||||
printf("WARNING: outb not implemented!\n");
|
||||
HALT_SYS();
|
||||
}
|
||||
|
||||
void
|
||||
outw(u16 val, u16 port)
|
||||
{
|
||||
printf("WARNING: outw not implemented!\n");
|
||||
HALT_SYS();
|
||||
}
|
||||
|
||||
void
|
||||
outl(u32 val, u16 port)
|
||||
{
|
||||
printf("WARNING: outl not implemented!\n");
|
||||
HALT_SYS();
|
||||
}
|
||||
|
||||
u8
|
||||
inb(u16 port)
|
||||
{
|
||||
printf("WARNING: inb not implemented!\n");
|
||||
HALT_SYS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16
|
||||
inw(u16 port)
|
||||
{
|
||||
printf("WARNING: inw not implemented!\n");
|
||||
HALT_SYS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32
|
||||
inl(u16 port)
|
||||
{
|
||||
printf("WARNING: inl not implemented!\n");
|
||||
HALT_SYS();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_YABEL_DIRECTHW) && (CONFIG_YABEL_DIRECTHW == 1)
|
||||
u8 my_inb(X86EMU_pioAddr addr)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
val = inb(addr);
|
||||
DEBUG_PRINTF_IO("inb(0x%04x) = 0x%02x\n", addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
u16 my_inw(X86EMU_pioAddr addr)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
val = inw(addr);
|
||||
DEBUG_PRINTF_IO("inw(0x%04x) = 0x%04x\n", addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
u32 my_inl(X86EMU_pioAddr addr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = inl(addr);
|
||||
DEBUG_PRINTF_IO("inl(0x%04x) = 0x%08x\n", addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void my_outb(X86EMU_pioAddr addr, u8 val)
|
||||
{
|
||||
DEBUG_PRINTF_IO("outb(0x%02x, 0x%04x)\n", val, addr);
|
||||
outb(val, addr);
|
||||
}
|
||||
|
||||
void my_outw(X86EMU_pioAddr addr, u16 val)
|
||||
{
|
||||
DEBUG_PRINTF_IO("outw(0x%04x, 0x%04x)\n", val, addr);
|
||||
outw(val, addr);
|
||||
}
|
||||
|
||||
void my_outl(X86EMU_pioAddr addr, u32 val)
|
||||
{
|
||||
DEBUG_PRINTF_IO("outl(0x%08x, 0x%04x)\n", val, addr);
|
||||
outl(val, addr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size);
|
||||
void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size);
|
||||
u8 handle_port_61h(void);
|
||||
|
||||
u8
|
||||
my_inb(X86EMU_pioAddr addr)
|
||||
{
|
||||
u8 rval = 0xFF;
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access Device I/O (BAR or Legacy...)
|
||||
DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
|
||||
addr);
|
||||
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
rval = read_io((void *)translated_addr, 1);
|
||||
DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __func__,
|
||||
addr, rval);
|
||||
return rval;
|
||||
} else {
|
||||
switch (addr) {
|
||||
case 0x61:
|
||||
//8254 KB Controller / Timer Port
|
||||
// rval = handle_port_61h();
|
||||
rval = inb(0x61);
|
||||
//DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __func__, addr, rval);
|
||||
return rval;
|
||||
break;
|
||||
case 0xCFC:
|
||||
case 0xCFD:
|
||||
case 0xCFE:
|
||||
case 0xCFF:
|
||||
// PCI Config Mechanism 1 Ports
|
||||
return (u8) pci_cfg_read(addr, 1);
|
||||
break;
|
||||
case 0x0a:
|
||||
CHECK_DBG(DEBUG_INTR) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
|
||||
//HALT_SYS();
|
||||
// no break, intentional fall-through to default!!
|
||||
default:
|
||||
DEBUG_PRINTF_IO
|
||||
("%s(%04x) reading from bios_device.io_buffer\n",
|
||||
__func__, addr);
|
||||
rval = *((u8 *) (bios_device.io_buffer + addr));
|
||||
DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n",
|
||||
__func__, addr, rval);
|
||||
return rval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u16
|
||||
my_inw(X86EMU_pioAddr addr)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access Device I/O (BAR or Legacy...)
|
||||
DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
|
||||
addr);
|
||||
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
u16 rval;
|
||||
if ((translated_addr & (u64) 0x1) == 0) {
|
||||
// 16 bit aligned access...
|
||||
u16 tempval = read_io((void *)translated_addr, 2);
|
||||
//little endian conversion
|
||||
rval = in16le((void *) &tempval);
|
||||
} else {
|
||||
// unaligned access, read single bytes, little-endian
|
||||
rval = (read_io((void *)translated_addr, 1) << 8)
|
||||
| (read_io((void *)(translated_addr + 1), 1));
|
||||
}
|
||||
DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __func__,
|
||||
addr, rval);
|
||||
return rval;
|
||||
} else {
|
||||
switch (addr) {
|
||||
case 0xCFC:
|
||||
case 0xCFE:
|
||||
//PCI Config Mechanism 1
|
||||
return (u16) pci_cfg_read(addr, 2);
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTF_IO
|
||||
("%s(%04x) reading from bios_device.io_buffer\n",
|
||||
__func__, addr);
|
||||
u16 rval =
|
||||
in16le((void *) bios_device.io_buffer + addr);
|
||||
DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n",
|
||||
__func__, addr, rval);
|
||||
return rval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32
|
||||
my_inl(X86EMU_pioAddr addr)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access Device I/O (BAR or Legacy...)
|
||||
DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __func__,
|
||||
addr);
|
||||
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
u32 rval;
|
||||
if ((translated_addr & (u64) 0x3) == 0) {
|
||||
// 32 bit aligned access...
|
||||
u32 tempval = read_io((void *) translated_addr, 4);
|
||||
//little endian conversion
|
||||
rval = in32le((void *) &tempval);
|
||||
} else {
|
||||
// unaligned access, read single bytes, little-endian
|
||||
rval = (read_io((void *)(translated_addr), 1) << 24)
|
||||
| (read_io((void *)(translated_addr + 1), 1) << 16)
|
||||
| (read_io((void *)(translated_addr + 2), 1) << 8)
|
||||
| (read_io((void *)(translated_addr + 3), 1));
|
||||
}
|
||||
DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __func__,
|
||||
addr, rval);
|
||||
return rval;
|
||||
} else {
|
||||
switch (addr) {
|
||||
case 0xCFC:
|
||||
//PCI Config Mechanism 1
|
||||
return pci_cfg_read(addr, 4);
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTF_IO
|
||||
("%s(%04x) reading from bios_device.io_buffer\n",
|
||||
__func__, addr);
|
||||
u32 rval =
|
||||
in32le((void *) bios_device.io_buffer + addr);
|
||||
DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n",
|
||||
__func__, addr, rval);
|
||||
return rval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
my_outb(X86EMU_pioAddr addr, u8 val)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access Device I/O (BAR or Legacy...)
|
||||
DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
|
||||
__func__, addr, val);
|
||||
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
write_io((void *) translated_addr, val, 1);
|
||||
DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __func__,
|
||||
addr, val);
|
||||
} else {
|
||||
switch (addr) {
|
||||
case 0xCFC:
|
||||
case 0xCFD:
|
||||
case 0xCFE:
|
||||
case 0xCFF:
|
||||
// PCI Config Mechanism 1 Ports
|
||||
pci_cfg_write(addr, val, 1);
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTF_IO
|
||||
("%s(%04x,%02x) writing to bios_device.io_buffer\n",
|
||||
__func__, addr, val);
|
||||
*((u8 *) (bios_device.io_buffer + addr)) = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
my_outw(X86EMU_pioAddr addr, u16 val)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access Device I/O (BAR or Legacy...)
|
||||
DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
|
||||
__func__, addr, val);
|
||||
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
if ((translated_addr & (u64) 0x1) == 0) {
|
||||
// little-endian conversion
|
||||
u16 tempval = in16le((void *) &val);
|
||||
// 16 bit aligned access...
|
||||
write_io((void *) translated_addr, tempval, 2);
|
||||
} else {
|
||||
// unaligned access, write single bytes, little-endian
|
||||
write_io(((void *) (translated_addr + 1)),
|
||||
(u8) ((val & 0xFF00) >> 8), 1);
|
||||
write_io(((void *) translated_addr),
|
||||
(u8) (val & 0x00FF), 1);
|
||||
}
|
||||
DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __func__,
|
||||
addr, val);
|
||||
} else {
|
||||
switch (addr) {
|
||||
case 0xCFC:
|
||||
case 0xCFE:
|
||||
// PCI Config Mechanism 1 Ports
|
||||
pci_cfg_write(addr, val, 2);
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTF_IO
|
||||
("%s(%04x,%04x) writing to bios_device.io_buffer\n",
|
||||
__func__, addr, val);
|
||||
out16le((void *) bios_device.io_buffer + addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
my_outl(X86EMU_pioAddr addr, u32 val)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access Device I/O (BAR or Legacy...)
|
||||
DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n",
|
||||
__func__, addr, val);
|
||||
//DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
if ((translated_addr & (u64) 0x3) == 0) {
|
||||
// little-endian conversion
|
||||
u32 tempval = in32le((void *) &val);
|
||||
// 32 bit aligned access...
|
||||
write_io((void *) translated_addr, tempval, 4);
|
||||
} else {
|
||||
// unaligned access, write single bytes, little-endian
|
||||
write_io(((void *) translated_addr + 3),
|
||||
(u8) ((val & 0xFF000000) >> 24), 1);
|
||||
write_io(((void *) translated_addr + 2),
|
||||
(u8) ((val & 0x00FF0000) >> 16), 1);
|
||||
write_io(((void *) translated_addr + 1),
|
||||
(u8) ((val & 0x0000FF00) >> 8), 1);
|
||||
write_io(((void *) translated_addr),
|
||||
(u8) (val & 0x000000FF), 1);
|
||||
}
|
||||
DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __func__,
|
||||
addr, val);
|
||||
} else {
|
||||
switch (addr) {
|
||||
case 0xCFC:
|
||||
// PCI Config Mechanism 1 Ports
|
||||
pci_cfg_write(addr, val, 4);
|
||||
break;
|
||||
default:
|
||||
DEBUG_PRINTF_IO
|
||||
("%s(%04x,%08x) writing to bios_device.io_buffer\n",
|
||||
__func__, addr, val);
|
||||
out32le((void *) bios_device.io_buffer + addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32
|
||||
pci_cfg_read(X86EMU_pioAddr addr, u8 size)
|
||||
{
|
||||
u32 rval = 0xFFFFFFFF;
|
||||
struct device * dev;
|
||||
if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
|
||||
// PCI Configuration Mechanism 1 step 1
|
||||
// write to 0xCF8, sets bus, device, function and Config Space offset
|
||||
// later read from 0xCFC-0xCFF returns the value...
|
||||
u8 bus, devfn, offs;
|
||||
u32 port_cf8_val = my_inl(0xCF8);
|
||||
if ((port_cf8_val & 0x80000000) != 0) {
|
||||
//highest bit enables config space mapping
|
||||
bus = (port_cf8_val & 0x00FF0000) >> 16;
|
||||
devfn = (port_cf8_val & 0x0000FF00) >> 8;
|
||||
offs = (port_cf8_val & 0x000000FF);
|
||||
offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
|
||||
DEBUG_PRINTF_INTR("%s(): PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n",
|
||||
__func__, bus, devfn, offs);
|
||||
#if defined(CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES) && CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES==1
|
||||
dev = dev_find_slot(bus, devfn);
|
||||
DEBUG_PRINTF_INTR("%s(): dev_find_slot() returned: %s\n",
|
||||
__func__, dev_path(dev));
|
||||
if (dev == 0) {
|
||||
// fail accesses to non-existent devices...
|
||||
#else
|
||||
dev = bios_device.dev;
|
||||
if ((bus != bios_device.bus)
|
||||
|| (devfn != bios_device.devfn)) {
|
||||
// fail accesses to any device but ours...
|
||||
#endif
|
||||
printf
|
||||
("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n",
|
||||
__func__, bus, bios_device.bus, devfn,
|
||||
bios_device.devfn, offs);
|
||||
SET_FLAG(F_CF);
|
||||
HALT_SYS();
|
||||
return 0;
|
||||
} else {
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
switch (size) {
|
||||
case 1:
|
||||
rval = pci_read_config8(dev, offs);
|
||||
break;
|
||||
case 2:
|
||||
rval = pci_read_config16(dev, offs);
|
||||
break;
|
||||
case 4:
|
||||
rval = pci_read_config32(dev, offs);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
rval =
|
||||
(u32) rtas_pci_config_read(bios_device.
|
||||
puid, size,
|
||||
bus, devfn,
|
||||
offs);
|
||||
#endif
|
||||
DEBUG_PRINTF_IO
|
||||
("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n",
|
||||
__func__, addr, offs, size, rval);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
void
|
||||
pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size)
|
||||
{
|
||||
if ((addr >= 0xCFC) && ((addr + size) <= 0xD00)) {
|
||||
// PCI Configuration Mechanism 1 step 1
|
||||
// write to 0xCF8, sets bus, device, function and Config Space offset
|
||||
// later write to 0xCFC-0xCFF sets the value...
|
||||
u8 bus, devfn, offs;
|
||||
u32 port_cf8_val = my_inl(0xCF8);
|
||||
if ((port_cf8_val & 0x80000000) != 0) {
|
||||
//highest bit enables config space mapping
|
||||
bus = (port_cf8_val & 0x00FF0000) >> 16;
|
||||
devfn = (port_cf8_val & 0x0000FF00) >> 8;
|
||||
offs = (port_cf8_val & 0x000000FF);
|
||||
offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly
|
||||
if ((bus != bios_device.bus)
|
||||
|| (devfn != bios_device.devfn)) {
|
||||
// fail accesses to any device but ours...
|
||||
printf
|
||||
("Config write access invalid! PCI device %x:%x.%x, offs: %x\n",
|
||||
bus, devfn >> 3, devfn & 7, offs);
|
||||
HALT_SYS();
|
||||
} else {
|
||||
#ifdef CONFIG_PCI_OPTION_ROM_RUN_YABEL
|
||||
switch (size) {
|
||||
case 1:
|
||||
pci_write_config8(bios_device.dev, offs, val);
|
||||
break;
|
||||
case 2:
|
||||
pci_write_config16(bios_device.dev, offs, val);
|
||||
break;
|
||||
case 4:
|
||||
pci_write_config32(bios_device.dev, offs, val);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
rtas_pci_config_write(bios_device.puid,
|
||||
size, bus, devfn, offs,
|
||||
val);
|
||||
#endif
|
||||
DEBUG_PRINTF_IO
|
||||
("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n",
|
||||
__func__, addr, offs, size, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8
|
||||
handle_port_61h(void)
|
||||
{
|
||||
static u64 last_time = 0;
|
||||
u64 curr_time = get_time();
|
||||
u64 time_diff; // time since last call
|
||||
u32 period_ticks; // length of a period in ticks
|
||||
u32 nr_periods; //number of periods passed since last call
|
||||
// bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??)
|
||||
time_diff = curr_time - last_time;
|
||||
// at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second)
|
||||
// TODO: as long as the frequency does not change, we should not calculate this every time
|
||||
period_ticks = (15 * tb_freq) / 1000000;
|
||||
nr_periods = time_diff / period_ticks;
|
||||
// if the number if ticks passed since last call is odd, we toggle bit 4
|
||||
if ((nr_periods % 2) != 0) {
|
||||
*((u8 *) (bios_device.io_buffer + 0x61)) ^= 0x10;
|
||||
}
|
||||
//finally read the value from the io_buffer
|
||||
return *((u8 *) (bios_device.io_buffer + 0x61));
|
||||
}
|
||||
#endif
|
@@ -1,30 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _BIOSEMU_IO_H_
|
||||
#define _BIOSEMU_IO_H_
|
||||
#include <x86emu/x86emu.h>
|
||||
#include <types.h>
|
||||
|
||||
u8 my_inb(X86EMU_pioAddr addr);
|
||||
|
||||
u16 my_inw(X86EMU_pioAddr addr);
|
||||
|
||||
u32 my_inl(X86EMU_pioAddr addr);
|
||||
|
||||
void my_outb(X86EMU_pioAddr addr, u8 val);
|
||||
|
||||
void my_outw(X86EMU_pioAddr addr, u16 val);
|
||||
|
||||
void my_outl(X86EMU_pioAddr addr, u32 val);
|
||||
|
||||
#endif
|
@@ -1,493 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#include <types.h>
|
||||
#include "debug.h"
|
||||
#include "device.h"
|
||||
#include "x86emu/x86emu.h"
|
||||
#include "biosemu.h"
|
||||
#include "mem.h"
|
||||
#include "compat/time.h"
|
||||
|
||||
// define a check for access to certain (virtual) memory regions (interrupt handlers, BIOS Data Area, ...)
|
||||
#if CONFIG_X86EMU_DEBUG
|
||||
static u8 in_check = 0; // to avoid recursion...
|
||||
u16 ebda_segment;
|
||||
u32 ebda_size;
|
||||
|
||||
//TODO: these macros have grown so large, that they should be changed to an inline function,
|
||||
//just for the sake of readability...
|
||||
|
||||
#define DEBUG_CHECK_VMEM_READ(_addr, _rval) \
|
||||
if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \
|
||||
in_check = 1; \
|
||||
/* determine ebda_segment and size \
|
||||
* since we are using my_rdx calls, make sure, this is after setting in_check! */ \
|
||||
/* offset 03 in BDA is EBDA segment */ \
|
||||
ebda_segment = my_rdw(0x40e); \
|
||||
/* first value in ebda is size in KB */ \
|
||||
ebda_size = my_rdb(ebda_segment << 4) * 1024; \
|
||||
/* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \
|
||||
if (_addr < 0x400) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: read from Interrupt Vector %x --> %x\n", \
|
||||
__func__, _addr / 4, _rval); \
|
||||
} \
|
||||
/* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \
|
||||
else if ((_addr >= 0x400) && (addr < 0x500)) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Area: addr: %x --> %x\n", \
|
||||
__func__, _addr, _rval); \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* access to first 64k of memory... */ \
|
||||
else if (_addr < 0x10000) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: read from segment 0000h: addr: %x --> %x\n", \
|
||||
__func__, _addr, _rval); \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* read from PMM_CONV_SEGMENT */ \
|
||||
else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: read from PMM Segment %04xh: addr: %x --> %x\n", \
|
||||
__func__, PMM_CONV_SEGMENT, _addr, _rval); \
|
||||
/* HALT_SYS(); */ \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* read from PNP_DATA_SEGMENT */ \
|
||||
else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: read from PnP Data Segment %04xh: addr: %x --> %x\n", \
|
||||
__func__, PNP_DATA_SEGMENT, _addr, _rval); \
|
||||
/* HALT_SYS(); */ \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* read from EBDA Segment */ \
|
||||
else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: read from Extended BIOS Data Area %04xh, size: %04x: addr: %x --> %x\n", \
|
||||
__func__, ebda_segment, ebda_size, _addr, _rval); \
|
||||
} \
|
||||
/* read from BIOS_DATA_SEGMENT */ \
|
||||
else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Segment %04xh: addr: %x --> %x\n", \
|
||||
__func__, BIOS_DATA_SEGMENT, _addr, _rval); \
|
||||
/* for PMM debugging */ \
|
||||
/*if (_addr == BIOS_DATA_SEGMENT << 4) { \
|
||||
X86EMU_trace_on(); \
|
||||
M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; \
|
||||
}*/ \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
in_check = 0; \
|
||||
}
|
||||
#define DEBUG_CHECK_VMEM_WRITE(_addr, _val) \
|
||||
if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \
|
||||
in_check = 1; \
|
||||
/* determine ebda_segment and size \
|
||||
* since we are using my_rdx calls, make sure, this is after setting in_check! */ \
|
||||
/* offset 03 in BDA is EBDA segment */ \
|
||||
ebda_segment = my_rdw(0x40e); \
|
||||
/* first value in ebda is size in KB */ \
|
||||
ebda_size = my_rdb(ebda_segment << 4) * 1024; \
|
||||
/* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \
|
||||
if (_addr < 0x400) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n", \
|
||||
__func__, _addr / 4, _val); \
|
||||
} \
|
||||
/* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \
|
||||
else if ((_addr >= 0x400) && (addr < 0x500)) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Area: addr: %x <-- %x\n", \
|
||||
__func__, _addr, _val); \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* access to first 64k of memory...*/ \
|
||||
else if (_addr < 0x10000) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n", \
|
||||
__func__, _addr, _val); \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* write to PMM_CONV_SEGMENT... */ \
|
||||
else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: write to PMM Segment %04xh: addr: %x <-- %x\n", \
|
||||
__func__, PMM_CONV_SEGMENT, _addr, _val); \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* write to PNP_DATA_SEGMENT... */ \
|
||||
else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: write to PnP Data Segment %04xh: addr: %x <-- %x\n", \
|
||||
__func__, PNP_DATA_SEGMENT, _addr, _val); \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* write to EBDA Segment... */ \
|
||||
else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: write to Extended BIOS Data Area %04xh, size: %04x: addr: %x <-- %x\n", \
|
||||
__func__, ebda_segment, ebda_size, _addr, _val); \
|
||||
} \
|
||||
/* write to BIOS_DATA_SEGMENT... */ \
|
||||
else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Segment %04xh: addr: %x <-- %x\n", \
|
||||
__func__, BIOS_DATA_SEGMENT, _addr, _val); \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
/* write to current CS segment... */ \
|
||||
else if ((_addr < ((M.x86.R_CS << 4) | 0xffff)) && (_addr > (M.x86.R_CS << 4))) { \
|
||||
DEBUG_PRINTF_CS_IP("%s: write to CS segment %04xh: addr: %x <-- %x\n", \
|
||||
__func__, M.x86.R_CS, _addr, _val); \
|
||||
/* dump registers */ \
|
||||
/* x86emu_dump_xregs(); */ \
|
||||
} \
|
||||
in_check = 0; \
|
||||
}
|
||||
#else
|
||||
#define DEBUG_CHECK_VMEM_READ(_addr, _rval)
|
||||
#define DEBUG_CHECK_VMEM_WRITE(_addr, _val)
|
||||
#endif
|
||||
|
||||
void update_time(u32);
|
||||
|
||||
#if !defined(CONFIG_YABEL_DIRECTHW) || (!CONFIG_YABEL_DIRECTHW)
|
||||
// read byte from memory
|
||||
u8
|
||||
my_rdb(u32 addr)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
u8 rval;
|
||||
if (translated != 0) {
|
||||
//translation successfull, access VGA Memory (BAR or Legacy...)
|
||||
DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
|
||||
__func__, addr);
|
||||
//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
set_ci();
|
||||
rval = *((u8 *) translated_addr);
|
||||
clr_ci();
|
||||
DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __func__, addr,
|
||||
rval);
|
||||
return rval;
|
||||
} else if (addr > M.mem_size) {
|
||||
DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
|
||||
__func__, addr);
|
||||
//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
|
||||
HALT_SYS();
|
||||
} else {
|
||||
/* read from virtual memory */
|
||||
rval = *((u8 *) (M.mem_base + addr));
|
||||
DEBUG_CHECK_VMEM_READ(addr, rval);
|
||||
return rval;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//read word from memory
|
||||
u16
|
||||
my_rdw(u32 addr)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
u16 rval;
|
||||
if (translated != 0) {
|
||||
//translation successfull, access VGA Memory (BAR or Legacy...)
|
||||
DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n",
|
||||
__func__, addr);
|
||||
//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
// check for legacy memory, because of the remapping to BARs, the reads must
|
||||
// be byte reads...
|
||||
if ((addr >= 0xa0000) && (addr < 0xc0000)) {
|
||||
//read bytes a using my_rdb, because of the remapping to BARs
|
||||
//words may not be contiguous in memory, so we need to translate
|
||||
//every address...
|
||||
rval = ((u8) my_rdb(addr)) |
|
||||
(((u8) my_rdb(addr + 1)) << 8);
|
||||
} else {
|
||||
if ((translated_addr & (u64) 0x1) == 0) {
|
||||
// 16 bit aligned access...
|
||||
set_ci();
|
||||
rval = in16le((void *) translated_addr);
|
||||
clr_ci();
|
||||
} else {
|
||||
// unaligned access, read single bytes
|
||||
set_ci();
|
||||
rval = (*((u8 *) translated_addr)) |
|
||||
(*((u8 *) translated_addr + 1) << 8);
|
||||
clr_ci();
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF_MEM("%s(%08x) VGA --> %04x\n", __func__, addr,
|
||||
rval);
|
||||
return rval;
|
||||
} else if (addr > M.mem_size) {
|
||||
DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
|
||||
__func__, addr);
|
||||
//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
|
||||
HALT_SYS();
|
||||
} else {
|
||||
/* read from virtual memory */
|
||||
rval = in16le((void *) (M.mem_base + addr));
|
||||
DEBUG_CHECK_VMEM_READ(addr, rval);
|
||||
return rval;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//read long from memory
|
||||
u32
|
||||
my_rdl(u32 addr)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
u32 rval;
|
||||
if (translated != 0) {
|
||||
//translation successfull, access VGA Memory (BAR or Legacy...)
|
||||
DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n",
|
||||
__func__, addr);
|
||||
//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
// check for legacy memory, because of the remapping to BARs, the reads must
|
||||
// be byte reads...
|
||||
if ((addr >= 0xa0000) && (addr < 0xc0000)) {
|
||||
//read bytes a using my_rdb, because of the remapping to BARs
|
||||
//dwords may not be contiguous in memory, so we need to translate
|
||||
//every address...
|
||||
rval = ((u8) my_rdb(addr)) |
|
||||
(((u8) my_rdb(addr + 1)) << 8) |
|
||||
(((u8) my_rdb(addr + 2)) << 16) |
|
||||
(((u8) my_rdb(addr + 3)) << 24);
|
||||
} else {
|
||||
if ((translated_addr & (u64) 0x3) == 0) {
|
||||
// 32 bit aligned access...
|
||||
set_ci();
|
||||
rval = in32le((void *) translated_addr);
|
||||
clr_ci();
|
||||
} else {
|
||||
// unaligned access, read single bytes
|
||||
set_ci();
|
||||
rval = (*((u8 *) translated_addr)) |
|
||||
(*((u8 *) translated_addr + 1) << 8) |
|
||||
(*((u8 *) translated_addr + 2) << 16) |
|
||||
(*((u8 *) translated_addr + 3) << 24);
|
||||
clr_ci();
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF_MEM("%s(%08x) VGA --> %08x\n", __func__, addr,
|
||||
rval);
|
||||
//HALT_SYS();
|
||||
return rval;
|
||||
} else if (addr > M.mem_size) {
|
||||
DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
|
||||
__func__, addr);
|
||||
//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
|
||||
HALT_SYS();
|
||||
} else {
|
||||
/* read from virtual memory */
|
||||
rval = in32le((void *) (M.mem_base + addr));
|
||||
switch (addr) {
|
||||
case 0x46c:
|
||||
//BDA Time Data, update it, before reading
|
||||
update_time(rval);
|
||||
rval = in32le((void *) (M.mem_base + addr));
|
||||
break;
|
||||
}
|
||||
DEBUG_CHECK_VMEM_READ(addr, rval);
|
||||
return rval;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//write byte to memory
|
||||
void
|
||||
my_wrb(u32 addr, u8 val)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access VGA Memory (BAR or Legacy...)
|
||||
DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
|
||||
__func__, addr, val);
|
||||
//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
set_ci();
|
||||
*((u8 *) translated_addr) = val;
|
||||
clr_ci();
|
||||
} else if (addr > M.mem_size) {
|
||||
DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
|
||||
__func__, addr);
|
||||
//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
|
||||
HALT_SYS();
|
||||
} else {
|
||||
/* write to virtual memory */
|
||||
DEBUG_CHECK_VMEM_WRITE(addr, val);
|
||||
*((u8 *) (M.mem_base + addr)) = val;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
my_wrw(u32 addr, u16 val)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access VGA Memory (BAR or Legacy...)
|
||||
DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
|
||||
__func__, addr, val);
|
||||
//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
// check for legacy memory, because of the remapping to BARs, the reads must
|
||||
// be byte reads...
|
||||
if ((addr >= 0xa0000) && (addr < 0xc0000)) {
|
||||
//read bytes a using my_rdb, because of the remapping to BARs
|
||||
//words may not be contiguous in memory, so we need to translate
|
||||
//every address...
|
||||
my_wrb(addr, (u8) (val & 0x00FF));
|
||||
my_wrb(addr + 1, (u8) ((val & 0xFF00) >> 8));
|
||||
} else {
|
||||
if ((translated_addr & (u64) 0x1) == 0) {
|
||||
// 16 bit aligned access...
|
||||
set_ci();
|
||||
out16le((void *) translated_addr, val);
|
||||
clr_ci();
|
||||
} else {
|
||||
// unaligned access, write single bytes
|
||||
set_ci();
|
||||
*((u8 *) translated_addr) =
|
||||
(u8) (val & 0x00FF);
|
||||
*((u8 *) translated_addr + 1) =
|
||||
(u8) ((val & 0xFF00) >> 8);
|
||||
clr_ci();
|
||||
}
|
||||
}
|
||||
} else if (addr > M.mem_size) {
|
||||
DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
|
||||
__func__, addr);
|
||||
//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
|
||||
HALT_SYS();
|
||||
} else {
|
||||
/* write to virtual memory */
|
||||
DEBUG_CHECK_VMEM_WRITE(addr, val);
|
||||
out16le((void *) (M.mem_base + addr), val);
|
||||
}
|
||||
}
|
||||
void
|
||||
my_wrl(u32 addr, u32 val)
|
||||
{
|
||||
unsigned long translated_addr = addr;
|
||||
u8 translated = biosemu_dev_translate_address(&translated_addr);
|
||||
if (translated != 0) {
|
||||
//translation successfull, access VGA Memory (BAR or Legacy...)
|
||||
DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n",
|
||||
__func__, addr, val);
|
||||
//DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __func__, addr, translated_addr);
|
||||
// check for legacy memory, because of the remapping to BARs, the reads must
|
||||
// be byte reads...
|
||||
if ((addr >= 0xa0000) && (addr < 0xc0000)) {
|
||||
//read bytes a using my_rdb, because of the remapping to BARs
|
||||
//words may not be contiguous in memory, so we need to translate
|
||||
//every address...
|
||||
my_wrb(addr, (u8) (val & 0x000000FF));
|
||||
my_wrb(addr + 1, (u8) ((val & 0x0000FF00) >> 8));
|
||||
my_wrb(addr + 2, (u8) ((val & 0x00FF0000) >> 16));
|
||||
my_wrb(addr + 3, (u8) ((val & 0xFF000000) >> 24));
|
||||
} else {
|
||||
if ((translated_addr & (u64) 0x3) == 0) {
|
||||
// 32 bit aligned access...
|
||||
set_ci();
|
||||
out32le((void *) translated_addr, val);
|
||||
clr_ci();
|
||||
} else {
|
||||
// unaligned access, write single bytes
|
||||
set_ci();
|
||||
*((u8 *) translated_addr) =
|
||||
(u8) (val & 0x000000FF);
|
||||
*((u8 *) translated_addr + 1) =
|
||||
(u8) ((val & 0x0000FF00) >> 8);
|
||||
*((u8 *) translated_addr + 2) =
|
||||
(u8) ((val & 0x00FF0000) >> 16);
|
||||
*((u8 *) translated_addr + 3) =
|
||||
(u8) ((val & 0xFF000000) >> 24);
|
||||
clr_ci();
|
||||
}
|
||||
}
|
||||
} else if (addr > M.mem_size) {
|
||||
DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n",
|
||||
__func__, addr);
|
||||
//disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1);
|
||||
HALT_SYS();
|
||||
} else {
|
||||
/* write to virtual memory */
|
||||
DEBUG_CHECK_VMEM_WRITE(addr, val);
|
||||
out32le((void *) (M.mem_base + addr), val);
|
||||
}
|
||||
}
|
||||
#else
|
||||
u8
|
||||
my_rdb(u32 addr)
|
||||
{
|
||||
return rdb(addr);
|
||||
}
|
||||
|
||||
u16
|
||||
my_rdw(u32 addr)
|
||||
{
|
||||
return rdw(addr);
|
||||
}
|
||||
|
||||
u32
|
||||
my_rdl(u32 addr)
|
||||
{
|
||||
return rdl(addr);
|
||||
}
|
||||
|
||||
void
|
||||
my_wrb(u32 addr, u8 val)
|
||||
{
|
||||
wrb(addr, val);
|
||||
}
|
||||
|
||||
void
|
||||
my_wrw(u32 addr, u16 val)
|
||||
{
|
||||
wrw(addr, val);
|
||||
}
|
||||
|
||||
void
|
||||
my_wrl(u32 addr, u32 val)
|
||||
{
|
||||
wrl(addr, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
//update time in BIOS Data Area
|
||||
//DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz
|
||||
//byte at 0x70 is timer overflow (set if midnight passed since last call to interrupt 1a function 00
|
||||
//cur_val is the current value, of offset 6c...
|
||||
void
|
||||
update_time(u32 cur_val)
|
||||
{
|
||||
//for convenience, we let the start of timebase be at midnight, we currently dont support
|
||||
//real daytime anyway...
|
||||
u64 ticks_per_day = tb_freq * 60 * 24;
|
||||
// at 18Hz a period is ~55ms, converted to ticks (tb_freq is ticks/second)
|
||||
u32 period_ticks = (55 * tb_freq) / 1000;
|
||||
u64 curr_time = get_time();
|
||||
u64 ticks_since_midnight = curr_time % ticks_per_day;
|
||||
u32 periods_since_midnight = ticks_since_midnight / period_ticks;
|
||||
// if periods since midnight is smaller than last value, set overflow
|
||||
// at BDA Offset 0x70
|
||||
if (periods_since_midnight < cur_val) {
|
||||
my_wrb(0x470, 1);
|
||||
}
|
||||
// store periods since midnight at BDA offset 0x6c
|
||||
my_wrl(0x46c, periods_since_midnight);
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _BIOSEMU_MEM_H_
|
||||
#define _BIOSEMU_MEM_H_
|
||||
#include <x86emu/x86emu.h>
|
||||
#include <types.h>
|
||||
|
||||
// read byte from memory
|
||||
u8 my_rdb(u32 addr);
|
||||
|
||||
//read word from memory
|
||||
u16 my_rdw(u32 addr);
|
||||
|
||||
//read long from memory
|
||||
u32 my_rdl(u32 addr);
|
||||
|
||||
//write byte to memory
|
||||
void my_wrb(u32 addr, u8 val);
|
||||
|
||||
//write word to memory
|
||||
void my_wrw(u32 addr, u16 val);
|
||||
|
||||
//write long to memory
|
||||
void my_wrl(u32 addr, u32 val);
|
||||
|
||||
#endif
|
@@ -1,442 +0,0 @@
|
||||
/****************************************************************************
|
||||
* YABEL BIOS Emulator
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Copyright (c) 2008 Pattrick Hueper <phueper@hueper.net>
|
||||
****************************************************************************/
|
||||
|
||||
#include <x86emu/x86emu.h>
|
||||
#include "../x86emu/prim_ops.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "biosemu.h"
|
||||
#include "pmm.h"
|
||||
#include "debug.h"
|
||||
#include "device.h"
|
||||
|
||||
/* this struct is used to remember which PMM spaces
|
||||
* have been assigned. MAX_PMM_AREAS defines how many
|
||||
* PMM areas we can assign.
|
||||
* All areas are assigned in PMM_CONV_SEGMENT
|
||||
*/
|
||||
typedef struct {
|
||||
u32 handle; /* handle that is returned to PMM caller */
|
||||
u32 offset; /* in PMM_CONV_SEGMENT */
|
||||
u32 length; /* length of this area */
|
||||
} pmm_allocation_t;
|
||||
|
||||
#define MAX_PMM_AREAS 10
|
||||
|
||||
/* array to store the above structs */
|
||||
static pmm_allocation_t pmm_allocation_array[MAX_PMM_AREAS];
|
||||
|
||||
/* index into pmm_allocation_array */
|
||||
static u32 curr_pmm_allocation_index = 0;
|
||||
|
||||
/* This function is used to setup the PMM struct in virtual memory
|
||||
* at a certain offset, the length of the PMM struct is returned */
|
||||
u8 pmm_setup(u16 segment, u16 offset)
|
||||
{
|
||||
/* setup the PMM structure */
|
||||
pmm_information_t *pis =
|
||||
(pmm_information_t *) (M.mem_base + (((u32) segment) << 4) +
|
||||
offset);
|
||||
memset(pis, 0, sizeof(pmm_information_t));
|
||||
/* set signature to $PMM */
|
||||
pis->signature[0] = '$';
|
||||
pis->signature[1] = 'P';
|
||||
pis->signature[2] = 'M';
|
||||
pis->signature[3] = 'M';
|
||||
/* revision as specified */
|
||||
pis->struct_rev = 0x01;
|
||||
/* internal length, excluding code */
|
||||
pis->length = ((void *)&(pis->code) - (void *)&(pis->signature));
|
||||
/* the code to be executed, pointed to by entry_point_offset */
|
||||
pis->code[0] = 0xCD; /* INT */
|
||||
pis->code[1] = PMM_INT_NUM; /* my selfdefined PMM INT number */
|
||||
pis->code[2] = 0xCB; /* RETF */
|
||||
/* set the entry_point_offset, it should point to pis->code, segment is the segment of
|
||||
* this struct. Since pis->length is the length of the struct excluding code, offset+pis->length
|
||||
* points to the code... it's that simple ;-)
|
||||
*/
|
||||
out32le(&(pis->entry_point_offset),
|
||||
(u32) segment << 16 | (u32) (offset + pis->length));
|
||||
/* checksum calculation */
|
||||
u8 i;
|
||||
u8 checksum = 0;
|
||||
for (i = 0; i < pis->length; i++) {
|
||||
checksum += *(((u8 *) pis) + i);
|
||||
}
|
||||
pis->checksum = ((u8) 0) - checksum;
|
||||
CHECK_DBG(DEBUG_PMM) {
|
||||
DEBUG_PRINTF_PMM("PMM Structure:\n");
|
||||
dump((void *)pis, sizeof(pmm_information_t));
|
||||
}
|
||||
return sizeof(pmm_information_t);
|
||||
}
|
||||
|
||||
/* handle the selfdefined interrupt, this is executed, when the PMM Entry Point
|
||||
* is executed, it must handle all PMM requests
|
||||
*/
|
||||
void pmm_handleInt()
|
||||
{
|
||||
u32 rval = 0;
|
||||
u16 function, flags;
|
||||
u32 handle, length;
|
||||
u32 i, j;
|
||||
u32 buffer;
|
||||
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* according to the PMM Spec "the flags and all registers, except DX and AX
|
||||
* are preserved across calls to PMM"
|
||||
* so we save M.x86 and in :exit label we restore it, however, this means that no
|
||||
* returns must be used in this function, any exit must use goto exit!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*/
|
||||
X86EMU_regs backup_regs = M.x86;
|
||||
pop_long(); /* pop the return address, this is already saved in INT handler, we don't need
|
||||
to remember this. */
|
||||
function = pop_word();
|
||||
switch (function) {
|
||||
case 0:
|
||||
/* function pmmAllocate */
|
||||
length = pop_long();
|
||||
length *= 16; /* length is passed in "paragraphs" of 16 bytes each */
|
||||
handle = pop_long();
|
||||
flags = pop_word();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmAllocate: Length: %x, Handle: %x, Flags: %x\n",
|
||||
__func__, length, handle, flags);
|
||||
if ((flags & 0x1) != 0) {
|
||||
/* request to allocate in conventional memory */
|
||||
if (curr_pmm_allocation_index >= MAX_PMM_AREAS) {
|
||||
printf
|
||||
("%s: pmmAllocate: Maximum Number of allocatable areas reached (%d), cannot allocate more memory!\n",
|
||||
__func__, MAX_PMM_AREAS);
|
||||
rval = 0;
|
||||
goto exit;
|
||||
}
|
||||
/* some ROMs seem to be confused by offset 0, so lets start at 0x100 */
|
||||
u32 next_offset = 0x100;
|
||||
pmm_allocation_t *pmm_alloc =
|
||||
&(pmm_allocation_array[curr_pmm_allocation_index]);
|
||||
if (curr_pmm_allocation_index != 0) {
|
||||
/* we have already allocated... get the new next_offset
|
||||
* from the previous pmm_allocation_t */
|
||||
next_offset =
|
||||
pmm_allocation_array
|
||||
[curr_pmm_allocation_index - 1].offset +
|
||||
pmm_allocation_array
|
||||
[curr_pmm_allocation_index - 1].length;
|
||||
}
|
||||
DEBUG_PRINTF_PMM("%s: next_offset: 0x%x\n",
|
||||
__func__, next_offset);
|
||||
if (length == 0) {
|
||||
/* largest possible block size requested, we have on segment
|
||||
* to allocate, so largest possible is segment size (0xFFFF)
|
||||
* minus next_offset
|
||||
*/
|
||||
rval = 0xFFFF - next_offset;
|
||||
goto exit;
|
||||
}
|
||||
u32 align = 0;
|
||||
if (((flags & 0x4) != 0) && (length > 0)) {
|
||||
/* align to least significant bit set in length param */
|
||||
u8 lsb = 0;
|
||||
while (((length >> lsb) & 0x1) == 0) {
|
||||
lsb++;
|
||||
}
|
||||
align = 1 << lsb;
|
||||
}
|
||||
/* always align at least to paragraph (16byte) boundary
|
||||
* hm... since the length is always in paragraphs, we cannot
|
||||
* align outside of paragraphs anyway... so this check might
|
||||
* be unnecessary...*/
|
||||
if (align < 0x10) {
|
||||
align = 0x10;
|
||||
}
|
||||
DEBUG_PRINTF_PMM("%s: align: 0x%x\n", __func__,
|
||||
align);
|
||||
if ((next_offset & (align - 1)) != 0) {
|
||||
/* not yet aligned... align! */
|
||||
next_offset += align;
|
||||
next_offset &= ~(align - 1);
|
||||
}
|
||||
if ((next_offset + length) > 0xFFFF) {
|
||||
rval = 0;
|
||||
printf
|
||||
("%s: pmmAllocate: Not enough memory available for allocation!\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
curr_pmm_allocation_index++;
|
||||
/* remember the values in pmm_allocation_array */
|
||||
pmm_alloc->handle = handle;
|
||||
pmm_alloc->offset = next_offset;
|
||||
pmm_alloc->length = length;
|
||||
/* return the 32bit "physical" address, i.e. combination of segment and offset */
|
||||
rval = ((u32) (PMM_CONV_SEGMENT << 16)) | next_offset;
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmAllocate: allocated memory at %x\n",
|
||||
__func__, rval);
|
||||
} else {
|
||||
rval = 0;
|
||||
printf
|
||||
("%s: pmmAllocate: allocation in extended memory not supported!\n",
|
||||
__func__);
|
||||
}
|
||||
goto exit;
|
||||
case 1:
|
||||
/* function pmmFind */
|
||||
handle = pop_long(); /* the handle to lookup */
|
||||
DEBUG_PRINTF_PMM("%s: pmmFind: Handle: %x\n", __func__,
|
||||
handle);
|
||||
i = 0;
|
||||
for (i = 0; i < curr_pmm_allocation_index; i++) {
|
||||
if (pmm_allocation_array[i].handle == handle) {
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmFind: found allocated memory at %x\n",
|
||||
__func__, rval);
|
||||
/* return the 32bit "physical" address, i.e. combination of segment and offset */
|
||||
rval =
|
||||
((u32) (PMM_CONV_SEGMENT << 16)) |
|
||||
pmm_allocation_array[i].offset;
|
||||
}
|
||||
}
|
||||
if (rval == 0) {
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmFind: handle (%x) not found!\n",
|
||||
__func__, handle);
|
||||
}
|
||||
goto exit;
|
||||
case 2:
|
||||
/* function pmmDeallocate */
|
||||
buffer = pop_long();
|
||||
/* since argument is the address of the PMM block (including the segment,
|
||||
* we need to remove the segment to get the offset
|
||||
*/
|
||||
buffer = buffer ^ ((u32) PMM_CONV_SEGMENT << 16);
|
||||
DEBUG_PRINTF_PMM("%s: pmmDeallocate: PMM segment offset: %x\n",
|
||||
__func__, buffer);
|
||||
i = 0;
|
||||
/* rval = 0 means we deallocated the buffer, so set it to 1 in case we dont find it and
|
||||
* thus cannot deallocate
|
||||
*/
|
||||
rval = 1;
|
||||
for (i = 0; i < curr_pmm_allocation_index; i++) {
|
||||
DEBUG_PRINTF_PMM("%d: %x\n", i,
|
||||
pmm_allocation_array[i].handle);
|
||||
if (pmm_allocation_array[i].offset == buffer) {
|
||||
/* we found the requested buffer, rval = 0 */
|
||||
rval = 0;
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmDeallocate: found allocated memory at index: %d\n",
|
||||
__func__, i);
|
||||
/* copy the remaining elements in pmm_allocation_array one position up */
|
||||
j = i;
|
||||
for (; j < curr_pmm_allocation_index; j++) {
|
||||
pmm_allocation_array[j] =
|
||||
pmm_allocation_array[j + 1];
|
||||
}
|
||||
/* move curr_pmm_allocation_index one up, too */
|
||||
curr_pmm_allocation_index--;
|
||||
/* finally clean last element */
|
||||
pmm_allocation_array[curr_pmm_allocation_index].
|
||||
handle = 0;
|
||||
pmm_allocation_array[curr_pmm_allocation_index].
|
||||
offset = 0;
|
||||
pmm_allocation_array[curr_pmm_allocation_index].
|
||||
length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rval != 0) {
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: pmmDeallocate: offset (%x) not found, cannot deallocate!\n",
|
||||
__func__, buffer);
|
||||
}
|
||||
goto exit;
|
||||
default:
|
||||
/* invalid/unimplemented function */
|
||||
printf("%s: invalid PMM function (0x%04x) called!\n",
|
||||
__func__, function);
|
||||
/* PMM spec says if function is invalid, return 0xFFFFFFFF */
|
||||
rval = 0xFFFFFFFF;
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
/* exit handler of this function, restore registers, put return value in DX:AX */
|
||||
M.x86 = backup_regs;
|
||||
M.x86.R_DX = (u16) ((rval >> 16) & 0xFFFF);
|
||||
M.x86.R_AX = (u16) (rval & 0xFFFF);
|
||||
CHECK_DBG(DEBUG_PMM) {
|
||||
DEBUG_PRINTF_PMM("%s: dump of pmm_allocation_array:\n",
|
||||
__func__);
|
||||
for (i = 0; i < MAX_PMM_AREAS; i++) {
|
||||
DEBUG_PRINTF_PMM
|
||||
("%d:\n\thandle: %x\n\toffset: %x\n\tlength: %x\n",
|
||||
i, pmm_allocation_array[i].handle,
|
||||
pmm_allocation_array[i].offset,
|
||||
pmm_allocation_array[i].length);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* This function tests the pmm_handleInt() function above. */
|
||||
void pmm_test(void)
|
||||
{
|
||||
u32 handle, length, addr;
|
||||
u16 function, flags;
|
||||
/*-------------------- Test simple allocation/find/deallocation ----------------------------- */
|
||||
function = 0; /* pmmAllocate */
|
||||
handle = 0xdeadbeef;
|
||||
length = 16; /* in 16byte paragraphs, so we allocate 256 bytes... */
|
||||
flags = 0x1; /* conventional memory, unaligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __func__,
|
||||
M.x86.R_DX, M.x86.R_AX);
|
||||
function = 1; /* pmmFind */
|
||||
push_long(handle);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM("%s: found memory at: %04x:%04x (expected: %08x)\n",
|
||||
__func__, M.x86.R_DX, M.x86.R_AX, addr);
|
||||
function = 2; /* pmmDeallocate */
|
||||
push_long(addr);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n",
|
||||
__func__, M.x86.R_DX, M.x86.R_AX);
|
||||
/*-------------------- Test aligned allocation/deallocation ----------------------------- */
|
||||
function = 0; /* pmmAllocate */
|
||||
handle = 0xdeadbeef;
|
||||
length = 257; /* in 16byte paragraphs, so we allocate 4KB + 16 bytes... */
|
||||
flags = 0x1; /* conventional memory, unaligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __func__,
|
||||
M.x86.R_DX, M.x86.R_AX);
|
||||
function = 0; /* pmmAllocate */
|
||||
handle = 0xf00d4b0b;
|
||||
length = 128; /* in 16byte paragraphs, so we allocate 2KB... */
|
||||
flags = 0x5; /* conventional memory, aligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
/* the address should be aligned to 0x800, so probably it is at offset 0x1800... */
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __func__,
|
||||
M.x86.R_DX, M.x86.R_AX);
|
||||
function = 1; /* pmmFind */
|
||||
push_long(handle);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
function = 2; /* pmmDeallocate */
|
||||
push_long(addr);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n",
|
||||
__func__, M.x86.R_DX, M.x86.R_AX);
|
||||
handle = 0xdeadbeef;
|
||||
function = 1; /* pmmFind */
|
||||
push_long(handle);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
function = 2; /* pmmDeallocate */
|
||||
push_long(addr);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n",
|
||||
__func__, M.x86.R_DX, M.x86.R_AX);
|
||||
/*-------------------- Test out of memory allocation ----------------------------- */
|
||||
function = 0; /* pmmAllocate */
|
||||
handle = 0xdeadbeef;
|
||||
length = 0; /* length zero means, give me the largest possible block */
|
||||
flags = 0x1; /* conventional memory, unaligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
length = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
length /= 16; /* length in paragraphs */
|
||||
DEBUG_PRINTF_PMM("%s: largest possible length: %08x\n", __func__,
|
||||
length);
|
||||
function = 0; /* pmmAllocate */
|
||||
flags = 0x1; /* conventional memory, aligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM("%s: allocated memory at: %04x:%04x\n", __func__,
|
||||
M.x86.R_DX, M.x86.R_AX);
|
||||
function = 0; /* pmmAllocate */
|
||||
length = 1;
|
||||
handle = 0xf00d4b0b;
|
||||
flags = 0x1; /* conventional memory, aligned */
|
||||
/* setup stack for call to pmm_handleInt() */
|
||||
push_word(flags);
|
||||
push_long(handle);
|
||||
push_long(length);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
/* this should fail, so 0x0 should be returned */
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: allocated memory at: %04x:%04x expected: 0000:0000\n",
|
||||
__func__, M.x86.R_DX, M.x86.R_AX);
|
||||
handle = 0xdeadbeef;
|
||||
function = 1; /* pmmFind */
|
||||
push_long(handle);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
addr = ((u32) M.x86.R_DX << 16) | M.x86.R_AX;
|
||||
function = 2; /* pmmDeallocate */
|
||||
push_long(addr);
|
||||
push_word(function);
|
||||
push_long(0); /* This is the return address for the ABI, unused in this implementation */
|
||||
pmm_handleInt();
|
||||
DEBUG_PRINTF_PMM
|
||||
("%s: freed memory rval: %04x:%04x (expected: 0000:0000)\n",
|
||||
__func__, M.x86.R_DX, M.x86.R_AX);
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
/****************************************************************************
|
||||
* YABEL BIOS Emulator
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Copyright (c) 2008 Pattrick Hueper <phueper@hueper.net>
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _YABEL_PMM_H_
|
||||
#define _YABEL_PMM_H_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/* PMM Structure see PMM Spec Version 1.01 Chapter 3.1.1
|
||||
* (search web for specspmm101.pdf)
|
||||
*/
|
||||
typedef struct {
|
||||
u8 signature[4];
|
||||
u8 struct_rev;
|
||||
u8 length;
|
||||
u8 checksum;
|
||||
u32 entry_point_offset;
|
||||
u8 reserved[5];
|
||||
/* Code is not part of the speced PMM struct, however, since I cannot
|
||||
* put the handling of PMM in the virtual memory (I dont want to hack it
|
||||
* together in x86 assembly ;-)) this code array is pointed to by
|
||||
* entry_point_offset, in code there is only a INT call and a RETF,
|
||||
* thus every PMM call will issue a PMM INT (only defined in YABEL,
|
||||
* see interrupt.c) and the INT Handler will do the actual PMM work.
|
||||
*/
|
||||
u8 code[3];
|
||||
} __attribute__ ((__packed__)) pmm_information_t;
|
||||
|
||||
/* This function is used to setup the PMM struct in virtual memory
|
||||
* at a certain offset */
|
||||
u8 pmm_setup(u16 segment, u16 offset);
|
||||
|
||||
/* This is the INT Handler mentioned above, called by my special PMM INT. */
|
||||
void pmm_handleInt(void);
|
||||
|
||||
void pmm_test(void);
|
||||
|
||||
#endif // _YABEL_PMM_H
|
@@ -1,852 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <types.h>
|
||||
#if CONFIG_BOOTSPLASH
|
||||
#include <boot/coreboot_tables.h>
|
||||
#endif
|
||||
|
||||
#include <arch/byteorder.h>
|
||||
#define ntohl(x) be32_to_cpu(x)
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <x86emu/x86emu.h>
|
||||
#include <x86emu/regs.h>
|
||||
#include "../x86emu/prim_ops.h"
|
||||
|
||||
#include "biosemu.h"
|
||||
#include "io.h"
|
||||
#include "mem.h"
|
||||
#include "interrupt.h"
|
||||
#include "device.h"
|
||||
|
||||
#include <cbfs.h>
|
||||
|
||||
#include <delay.h>
|
||||
#include "../../src/lib/jpeg.h"
|
||||
|
||||
// pointer to VBEInfoBuffer, set by vbe_prepare
|
||||
u8 *vbe_info_buffer = 0;
|
||||
|
||||
// virtual BIOS Memory
|
||||
u8 *biosmem;
|
||||
u32 biosmem_size;
|
||||
|
||||
// these structs are for input from and output to OF
|
||||
typedef struct {
|
||||
u8 display_type; // 0=NONE, 1= analog, 2=digital
|
||||
u16 screen_width;
|
||||
u16 screen_height;
|
||||
u16 screen_linebytes; // bytes per line in framebuffer, may be more than screen_width
|
||||
u8 color_depth; // color depth in bpp
|
||||
u32 framebuffer_address;
|
||||
u8 edid_block_zero[128];
|
||||
} __attribute__ ((__packed__)) screen_info_t;
|
||||
|
||||
typedef struct {
|
||||
u8 signature[4];
|
||||
u16 size_reserved;
|
||||
u8 monitor_number;
|
||||
u16 max_screen_width;
|
||||
u8 color_depth;
|
||||
} __attribute__ ((__packed__)) screen_info_input_t;
|
||||
|
||||
// these structs only store a subset of the VBE defined fields
|
||||
// only those needed.
|
||||
typedef struct {
|
||||
char signature[4];
|
||||
u16 version;
|
||||
u8 *oem_string_ptr;
|
||||
u32 capabilities;
|
||||
u16 video_mode_list[256]; // lets hope we never have more than 256 video modes...
|
||||
u16 total_memory;
|
||||
} vbe_info_t;
|
||||
|
||||
typedef struct {
|
||||
u16 mode_attributes; // 00
|
||||
u8 win_a_attributes; // 02
|
||||
u8 win_b_attributes; // 03
|
||||
u16 win_granularity; // 04
|
||||
u16 win_size; // 06
|
||||
u16 win_a_segment; // 08
|
||||
u16 win_b_segment; // 0a
|
||||
u32 win_func_ptr; // 0c
|
||||
u16 bytes_per_scanline; // 10
|
||||
u16 x_resolution; // 12
|
||||
u16 y_resolution; // 14
|
||||
u8 x_charsize; // 16
|
||||
u8 y_charsize; // 17
|
||||
u8 number_of_planes; // 18
|
||||
u8 bits_per_pixel; // 19
|
||||
u8 number_of_banks; // 20
|
||||
u8 memory_model; // 21
|
||||
u8 bank_size; // 22
|
||||
u8 number_of_image_pages; // 23
|
||||
u8 reserved_page;
|
||||
u8 red_mask_size;
|
||||
u8 red_mask_pos;
|
||||
u8 green_mask_size;
|
||||
u8 green_mask_pos;
|
||||
u8 blue_mask_size;
|
||||
u8 blue_mask_pos;
|
||||
u8 reserved_mask_size;
|
||||
u8 reserved_mask_pos;
|
||||
u8 direct_color_mode_info;
|
||||
u32 phys_base_ptr;
|
||||
u32 offscreen_mem_offset;
|
||||
u16 offscreen_mem_size;
|
||||
u8 reserved[206];
|
||||
} __attribute__ ((__packed__)) vesa_mode_info_t;
|
||||
|
||||
typedef struct {
|
||||
u16 video_mode;
|
||||
union {
|
||||
vesa_mode_info_t vesa;
|
||||
u8 mode_info_block[256];
|
||||
};
|
||||
// our crap
|
||||
//u16 attributes;
|
||||
//u16 linebytes;
|
||||
//u16 x_resolution;
|
||||
//u16 y_resolution;
|
||||
//u8 x_charsize;
|
||||
//u8 y_charsize;
|
||||
//u8 bits_per_pixel;
|
||||
//u8 memory_model;
|
||||
//u32 framebuffer_address;
|
||||
} vbe_mode_info_t;
|
||||
|
||||
typedef struct {
|
||||
u8 port_number; // i.e. monitor number
|
||||
u8 edid_transfer_time;
|
||||
u8 ddc_level;
|
||||
u8 edid_block_zero[128];
|
||||
} vbe_ddc_info_t;
|
||||
|
||||
static inline u8
|
||||
vbe_prepare(void)
|
||||
{
|
||||
vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
|
||||
//clear buffer
|
||||
memset(vbe_info_buffer, 0, 512);
|
||||
//set VbeSignature to "VBE2" to indicate VBE 2.0+ request
|
||||
vbe_info_buffer[0] = 'V';
|
||||
vbe_info_buffer[0] = 'B';
|
||||
vbe_info_buffer[0] = 'E';
|
||||
vbe_info_buffer[0] = '2';
|
||||
// ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
|
||||
M.x86.R_EDI = 0x0;
|
||||
M.x86.R_ES = VBE_SEGMENT;
|
||||
|
||||
return 0; // successfull init
|
||||
}
|
||||
|
||||
// VBE Function 00h
|
||||
static u8
|
||||
vbe_info(vbe_info_t * info)
|
||||
{
|
||||
vbe_prepare();
|
||||
// call VBE function 00h (Info Function)
|
||||
M.x86.R_EAX = 0x4f00;
|
||||
|
||||
// enable trace
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
// run VESA Interrupt
|
||||
runInt10();
|
||||
|
||||
if (M.x86.R_AL != 0x4f) {
|
||||
DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
|
||||
__func__, M.x86.R_AL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.x86.R_AH != 0x0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
|
||||
__func__, M.x86.R_AH);
|
||||
return M.x86.R_AH;
|
||||
}
|
||||
//printf("VBE Info Dump:");
|
||||
//dump(vbe_info_buffer, 64);
|
||||
|
||||
//offset 0: signature
|
||||
info->signature[0] = vbe_info_buffer[0];
|
||||
info->signature[1] = vbe_info_buffer[1];
|
||||
info->signature[2] = vbe_info_buffer[2];
|
||||
info->signature[3] = vbe_info_buffer[3];
|
||||
|
||||
// offset 4: 16bit le containing VbeVersion
|
||||
info->version = in16le(vbe_info_buffer + 4);
|
||||
|
||||
// offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
|
||||
info->oem_string_ptr =
|
||||
biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
|
||||
in16le(vbe_info_buffer + 6));
|
||||
|
||||
// offset 10: 32bit le capabilities
|
||||
info->capabilities = in32le(vbe_info_buffer + 10);
|
||||
|
||||
// offset 14: 32 bit le containing segment:offset of supported video mode table
|
||||
u16 *video_mode_ptr;
|
||||
video_mode_ptr =
|
||||
(u16 *) (biosmem +
|
||||
((in16le(vbe_info_buffer + 16) << 4) +
|
||||
in16le(vbe_info_buffer + 14)));
|
||||
u32 i = 0;
|
||||
do {
|
||||
info->video_mode_list[i] = in16le(video_mode_ptr + i);
|
||||
i++;
|
||||
}
|
||||
while ((i <
|
||||
(sizeof(info->video_mode_list) /
|
||||
sizeof(info->video_mode_list[0])))
|
||||
&& (info->video_mode_list[i - 1] != 0xFFFF));
|
||||
|
||||
//offset 18: 16bit le total memory in 64KB blocks
|
||||
info->total_memory = in16le(vbe_info_buffer + 18);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VBE Function 01h
|
||||
static u8
|
||||
vbe_get_mode_info(vbe_mode_info_t * mode_info)
|
||||
{
|
||||
vbe_prepare();
|
||||
// call VBE function 01h (Return VBE Mode Info Function)
|
||||
M.x86.R_EAX = 0x4f01;
|
||||
M.x86.R_CX = mode_info->video_mode;
|
||||
|
||||
// enable trace
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
// run VESA Interrupt
|
||||
runInt10();
|
||||
|
||||
if (M.x86.R_AL != 0x4f) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
|
||||
__func__, M.x86.R_AL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.x86.R_AH != 0x0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
|
||||
__func__, mode_info->video_mode, M.x86.R_AH);
|
||||
return M.x86.R_AH;
|
||||
}
|
||||
|
||||
//pointer to mode_info_block is in ES:DI
|
||||
memcpy(mode_info->mode_info_block,
|
||||
biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
|
||||
sizeof(mode_info->mode_info_block));
|
||||
|
||||
//printf("Mode Info Dump:");
|
||||
//dump(mode_info_block, 64);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VBE Function 02h
|
||||
static u8
|
||||
vbe_set_mode(vbe_mode_info_t * mode_info)
|
||||
{
|
||||
vbe_prepare();
|
||||
// call VBE function 02h (Set VBE Mode Function)
|
||||
M.x86.R_EAX = 0x4f02;
|
||||
M.x86.R_BX = mode_info->video_mode;
|
||||
M.x86.R_BX |= 0x4000; // set bit 14 to request linear framebuffer mode
|
||||
M.x86.R_BX &= 0x7FFF; // clear bit 15 to request clearing of framebuffer
|
||||
|
||||
DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
|
||||
M.x86.R_BX);
|
||||
|
||||
// enable trace
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
// run VESA Interrupt
|
||||
runInt10();
|
||||
|
||||
if (M.x86.R_AL != 0x4f) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Set Mode Function NOT supported! AL=%x\n",
|
||||
__func__, M.x86.R_AL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.x86.R_AH != 0x0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
|
||||
__func__, mode_info->video_mode, M.x86.R_AH);
|
||||
return M.x86.R_AH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//VBE Function 08h
|
||||
static u8
|
||||
vbe_set_palette_format(u8 format)
|
||||
{
|
||||
vbe_prepare();
|
||||
// call VBE function 09h (Set/Get Palette Data Function)
|
||||
M.x86.R_EAX = 0x4f08;
|
||||
M.x86.R_BL = 0x00; // set format
|
||||
M.x86.R_BH = format;
|
||||
|
||||
DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
|
||||
format);
|
||||
|
||||
// enable trace
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
// run VESA Interrupt
|
||||
runInt10();
|
||||
|
||||
if (M.x86.R_AL != 0x4f) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
|
||||
__func__, M.x86.R_AL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.x86.R_AH != 0x0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
|
||||
__func__, M.x86.R_AH);
|
||||
return M.x86.R_AH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VBE Function 09h
|
||||
static u8
|
||||
vbe_set_color(u16 color_number, u32 color_value)
|
||||
{
|
||||
vbe_prepare();
|
||||
// call VBE function 09h (Set/Get Palette Data Function)
|
||||
M.x86.R_EAX = 0x4f09;
|
||||
M.x86.R_BL = 0x00; // set color
|
||||
M.x86.R_CX = 0x01; // set only one entry
|
||||
M.x86.R_DX = color_number;
|
||||
// ES:DI is address where color_value is stored, we store it at 2000:0000
|
||||
M.x86.R_ES = 0x2000;
|
||||
M.x86.R_DI = 0x0;
|
||||
|
||||
// store color value at ES:DI
|
||||
out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
|
||||
|
||||
DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
|
||||
color_number, color_value);
|
||||
|
||||
// enable trace
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
// run VESA Interrupt
|
||||
runInt10();
|
||||
|
||||
if (M.x86.R_AL != 0x4f) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Set Palette Function NOT supported! AL=%x\n",
|
||||
__func__, M.x86.R_AL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.x86.R_AH != 0x0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
|
||||
__func__, M.x86.R_AH);
|
||||
return M.x86.R_AH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8
|
||||
vbe_get_color(u16 color_number, u32 * color_value)
|
||||
{
|
||||
vbe_prepare();
|
||||
// call VBE function 09h (Set/Get Palette Data Function)
|
||||
M.x86.R_EAX = 0x4f09;
|
||||
M.x86.R_BL = 0x00; // get color
|
||||
M.x86.R_CX = 0x01; // get only one entry
|
||||
M.x86.R_DX = color_number;
|
||||
// ES:DI is address where color_value is stored, we store it at 2000:0000
|
||||
M.x86.R_ES = 0x2000;
|
||||
M.x86.R_DI = 0x0;
|
||||
|
||||
// enable trace
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
// run VESA Interrupt
|
||||
runInt10();
|
||||
|
||||
if (M.x86.R_AL != 0x4f) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Set Palette Function NOT supported! AL=%x\n",
|
||||
__func__, M.x86.R_AL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.x86.R_AH != 0x0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
|
||||
__func__, M.x86.R_AH);
|
||||
return M.x86.R_AH;
|
||||
}
|
||||
// read color value from ES:DI
|
||||
*color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
|
||||
|
||||
DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
|
||||
color_number, *color_value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VBE Function 15h
|
||||
static u8
|
||||
vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
|
||||
{
|
||||
vbe_prepare();
|
||||
// call VBE function 15h (DDC Info Function)
|
||||
M.x86.R_EAX = 0x4f15;
|
||||
M.x86.R_BL = 0x00; // get DDC Info
|
||||
M.x86.R_CX = ddc_info->port_number;
|
||||
M.x86.R_ES = 0x0;
|
||||
M.x86.R_DI = 0x0;
|
||||
|
||||
// enable trace
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
// run VESA Interrupt
|
||||
runInt10();
|
||||
|
||||
if (M.x86.R_AL != 0x4f) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
|
||||
__func__, M.x86.R_AL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.x86.R_AH != 0x0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
|
||||
__func__, ddc_info->port_number, M.x86.R_AH);
|
||||
return M.x86.R_AH;
|
||||
}
|
||||
// BH = approx. time in seconds to transfer one EDID block
|
||||
ddc_info->edid_transfer_time = M.x86.R_BH;
|
||||
// BL = DDC Level
|
||||
ddc_info->ddc_level = M.x86.R_BL;
|
||||
|
||||
vbe_prepare();
|
||||
// call VBE function 15h (DDC Info Function)
|
||||
M.x86.R_EAX = 0x4f15;
|
||||
M.x86.R_BL = 0x01; // read EDID
|
||||
M.x86.R_CX = ddc_info->port_number;
|
||||
M.x86.R_DX = 0x0; // block number
|
||||
// ES:DI is address where EDID is stored, we store it at 2000:0000
|
||||
M.x86.R_ES = 0x2000;
|
||||
M.x86.R_DI = 0x0;
|
||||
|
||||
// enable trace
|
||||
CHECK_DBG(DEBUG_TRACE_X86EMU) {
|
||||
X86EMU_trace_on();
|
||||
}
|
||||
// run VESA Interrupt
|
||||
runInt10();
|
||||
|
||||
if (M.x86.R_AL != 0x4f) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: VBE Read EDID Function NOT supported! AL=%x\n",
|
||||
__func__, M.x86.R_AL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (M.x86.R_AH != 0x0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
|
||||
__func__, ddc_info->port_number, M.x86.R_AH);
|
||||
return M.x86.R_AH;
|
||||
}
|
||||
|
||||
memcpy(ddc_info->edid_block_zero,
|
||||
biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
|
||||
sizeof(ddc_info->edid_block_zero));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32
|
||||
vbe_get_info(void)
|
||||
{
|
||||
u8 rval;
|
||||
int i;
|
||||
|
||||
// XXX FIXME these need to be filled with sane values
|
||||
|
||||
// get a copy of input struct...
|
||||
screen_info_input_t input;
|
||||
// output is pointer to the address passed as argv[4]
|
||||
screen_info_t local_output;
|
||||
screen_info_t *output = &local_output;
|
||||
// zero input
|
||||
memset(&input, 0, sizeof(screen_info_input_t));
|
||||
// zero output
|
||||
memset(&output, 0, sizeof(screen_info_t));
|
||||
|
||||
vbe_info_t info;
|
||||
rval = vbe_info(&info);
|
||||
if (rval != 0)
|
||||
return rval;
|
||||
|
||||
DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
|
||||
DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
|
||||
DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
|
||||
DEBUG_PRINTF_VBE("Capabilities:\n");
|
||||
DEBUG_PRINTF_VBE("\tDAC: %s\n",
|
||||
(info.capabilities & 0x1) ==
|
||||
0 ? "fixed 6bit" : "switchable 6/8bit");
|
||||
DEBUG_PRINTF_VBE("\tVGA: %s\n",
|
||||
(info.capabilities & 0x2) ==
|
||||
0 ? "compatible" : "not compatible");
|
||||
DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
|
||||
(info.capabilities & 0x4) ==
|
||||
0 ? "normal" : "use blank bit in Function 09h");
|
||||
|
||||
// argv[4] may be a pointer with enough space to return screen_info_t
|
||||
// as input, it must contain a screen_info_input_t with the following content:
|
||||
// byte[0:3] = "DDC\0" (zero-terminated signature header)
|
||||
// byte[4:5] = reserved space for the return struct... just in case we ever change
|
||||
// the struct and dont have reserved enough memory (and let's hope the struct
|
||||
// never gets larger than 64KB)
|
||||
// byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
|
||||
// byte[7:8] = max. screen width (OF may want to limit this)
|
||||
// byte[9] = required color depth in bpp
|
||||
if (strncmp((char *) input.signature, "DDC", 4) != 0) {
|
||||
printf
|
||||
("%s: Invalid input signature! expected: %s, is: %s\n",
|
||||
__func__, "DDC", input.signature);
|
||||
return -1;
|
||||
}
|
||||
if (input.size_reserved != sizeof(screen_info_t)) {
|
||||
printf
|
||||
("%s: Size of return struct is wrong, required: %d, available: %d\n",
|
||||
__func__, (int) sizeof(screen_info_t),
|
||||
input.size_reserved);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vbe_ddc_info_t ddc_info;
|
||||
ddc_info.port_number = input.monitor_number;
|
||||
vbe_get_ddc_info(&ddc_info);
|
||||
|
||||
#if 0
|
||||
DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
|
||||
ddc_info.edid_transfer_time);
|
||||
DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
|
||||
DEBUG_PRINTF_VBE("DDC: EDID: \n");
|
||||
CHECK_DBG(DEBUG_VBE) {
|
||||
dump(ddc_info.edid_block_zero,
|
||||
sizeof(ddc_info.edid_block_zero));
|
||||
}
|
||||
#endif
|
||||
/* This could fail because of alignment issues, so use a longer form.
|
||||
*((u64 *) ddc_info.edid_block_zero) != (u64) 0x00FFFFFFFFFFFF00ULL
|
||||
*/
|
||||
if (ddc_info.edid_block_zero[0] != 0x00 ||
|
||||
ddc_info.edid_block_zero[1] != 0xFF ||
|
||||
ddc_info.edid_block_zero[2] != 0xFF ||
|
||||
ddc_info.edid_block_zero[3] != 0xFF ||
|
||||
ddc_info.edid_block_zero[4] != 0xFF ||
|
||||
ddc_info.edid_block_zero[5] != 0xFF ||
|
||||
ddc_info.edid_block_zero[6] != 0xFF ||
|
||||
ddc_info.edid_block_zero[7] != 0x00 ) {
|
||||
// invalid EDID signature... probably no monitor
|
||||
|
||||
output->display_type = 0x0;
|
||||
return 0;
|
||||
} else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
|
||||
// digital display
|
||||
output->display_type = 2;
|
||||
} else {
|
||||
// analog
|
||||
output->display_type = 1;
|
||||
}
|
||||
DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
|
||||
memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
|
||||
sizeof(ddc_info.edid_block_zero));
|
||||
i = 0;
|
||||
vbe_mode_info_t mode_info;
|
||||
vbe_mode_info_t best_mode_info;
|
||||
// initialize best_mode to 0
|
||||
memset(&best_mode_info, 0, sizeof(best_mode_info));
|
||||
while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
|
||||
//DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
|
||||
vbe_get_mode_info(&mode_info);
|
||||
|
||||
// FIXME all these values are little endian!
|
||||
|
||||
DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
|
||||
mode_info.video_mode,
|
||||
(le16_to_cpu(mode_info.vesa.mode_attributes) & 0x1) ==
|
||||
0 ? "not supported" : "supported");
|
||||
DEBUG_PRINTF_VBE("\tTTY: %s\n",
|
||||
(le16_to_cpu(mode_info.vesa.mode_attributes) & 0x4) ==
|
||||
0 ? "no" : "yes");
|
||||
DEBUG_PRINTF_VBE("\tMode: %s %s\n",
|
||||
(le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) ==
|
||||
0 ? "monochrome" : "color",
|
||||
(le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) ==
|
||||
0 ? "text" : "graphics");
|
||||
DEBUG_PRINTF_VBE("\tVGA: %s\n",
|
||||
(le16_to_cpu(mode_info.vesa.mode_attributes) & 0x20) ==
|
||||
0 ? "compatible" : "not compatible");
|
||||
DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
|
||||
(le16_to_cpu(mode_info.vesa.mode_attributes) & 0x40) ==
|
||||
0 ? "yes" : "no");
|
||||
DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
|
||||
(le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) ==
|
||||
0 ? "no" : "yes");
|
||||
DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
|
||||
le16_to_cpu(mode_info.vesa.x_resolution),
|
||||
le16_to_cpu(mode_info.vesa.y_resolution));
|
||||
DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
|
||||
mode_info.vesa.x_charsize, mode_info.vesa.y_charsize);
|
||||
DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
|
||||
mode_info.vesa.bits_per_pixel);
|
||||
DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
|
||||
mode_info.vesa.memory_model);
|
||||
DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
|
||||
le32_to_cpu(mode_info.vesa.phys_base_ptr));
|
||||
|
||||
if ((mode_info.vesa.bits_per_pixel == input.color_depth)
|
||||
&& (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width)
|
||||
&& ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0) // framebuffer mode
|
||||
&& ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0) // graphics
|
||||
&& ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0) // color
|
||||
&& (le16_to_cpu(mode_info.vesa.x_resolution) > le16_to_cpu(best_mode_info.vesa.x_resolution))) // better than previous best_mode
|
||||
{
|
||||
// yiiiihaah... we found a new best mode
|
||||
memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (best_mode_info.video_mode != 0) {
|
||||
DEBUG_PRINTF_VBE
|
||||
("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
|
||||
best_mode_info.video_mode,
|
||||
best_mode_info.vesa.x_resolution,
|
||||
best_mode_info.vesa.y_resolution,
|
||||
best_mode_info.vesa.bits_per_pixel,
|
||||
le32_to_cpu(best_mode_info.vesa.phys_base_ptr));
|
||||
|
||||
//printf("Mode Info Dump:");
|
||||
//dump(best_mode_info.mode_info_block, 64);
|
||||
|
||||
// set the video mode
|
||||
vbe_set_mode(&best_mode_info);
|
||||
|
||||
if ((info.capabilities & 0x1) != 0) {
|
||||
// switch to 8 bit palette format
|
||||
vbe_set_palette_format(8);
|
||||
}
|
||||
// setup a palette:
|
||||
// - first 216 colors are mixed colors for each component in 6 steps
|
||||
// (6*6*6=216)
|
||||
// - then 10 shades of the three primary colors
|
||||
// - then 10 shades of grey
|
||||
// -------
|
||||
// = 256 colors
|
||||
//
|
||||
// - finally black is color 0 and white color FF (because SLOF expects it
|
||||
// this way...)
|
||||
// this resembles the palette that the kernel/X Server seems to expect...
|
||||
|
||||
u8 mixed_color_values[6] =
|
||||
{ 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
|
||||
u8 primary_color_values[10] =
|
||||
{ 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
|
||||
0x27
|
||||
};
|
||||
u8 mc_size = sizeof(mixed_color_values);
|
||||
u8 prim_size = sizeof(primary_color_values);
|
||||
|
||||
u8 curr_color_index;
|
||||
u32 curr_color;
|
||||
|
||||
u8 r, g, b;
|
||||
// 216 mixed colors
|
||||
for (r = 0; r < mc_size; r++) {
|
||||
for (g = 0; g < mc_size; g++) {
|
||||
for (b = 0; b < mc_size; b++) {
|
||||
curr_color_index =
|
||||
(r * mc_size * mc_size) +
|
||||
(g * mc_size) + b;
|
||||
curr_color = 0;
|
||||
curr_color |= ((u32) mixed_color_values[r]) << 16; //red value
|
||||
curr_color |= ((u32) mixed_color_values[g]) << 8; //green value
|
||||
curr_color |= (u32) mixed_color_values[b]; //blue value
|
||||
vbe_set_color(curr_color_index,
|
||||
curr_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 10 shades of each primary color
|
||||
// red
|
||||
for (r = 0; r < prim_size; r++) {
|
||||
curr_color_index = mc_size * mc_size * mc_size + r;
|
||||
curr_color = ((u32) primary_color_values[r]) << 16;
|
||||
vbe_set_color(curr_color_index, curr_color);
|
||||
}
|
||||
//green
|
||||
for (g = 0; g < prim_size; g++) {
|
||||
curr_color_index =
|
||||
mc_size * mc_size * mc_size + prim_size + g;
|
||||
curr_color = ((u32) primary_color_values[g]) << 8;
|
||||
vbe_set_color(curr_color_index, curr_color);
|
||||
}
|
||||
//blue
|
||||
for (b = 0; b < prim_size; b++) {
|
||||
curr_color_index =
|
||||
mc_size * mc_size * mc_size + prim_size * 2 + b;
|
||||
curr_color = (u32) primary_color_values[b];
|
||||
vbe_set_color(curr_color_index, curr_color);
|
||||
}
|
||||
// 10 shades of grey
|
||||
for (i = 0; i < prim_size; i++) {
|
||||
curr_color_index =
|
||||
mc_size * mc_size * mc_size + prim_size * 3 + i;
|
||||
curr_color = 0;
|
||||
curr_color |= ((u32) primary_color_values[i]) << 16; //red
|
||||
curr_color |= ((u32) primary_color_values[i]) << 8; //green
|
||||
curr_color |= ((u32) primary_color_values[i]); //blue
|
||||
vbe_set_color(curr_color_index, curr_color);
|
||||
}
|
||||
|
||||
// SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
|
||||
vbe_set_color(0x00, 0x00000000);
|
||||
vbe_set_color(0xFF, 0x00FFFFFF);
|
||||
|
||||
output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution);
|
||||
output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution);
|
||||
output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline);
|
||||
output->color_depth = best_mode_info.vesa.bits_per_pixel;
|
||||
output->framebuffer_address =
|
||||
le32_to_cpu(best_mode_info.vesa.phys_base_ptr);
|
||||
} else {
|
||||
printf("%s: No suitable video mode found!\n", __func__);
|
||||
//unset display_type...
|
||||
output->display_type = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_BOOTSPLASH
|
||||
vbe_mode_info_t mode_info;
|
||||
|
||||
void vbe_set_graphics(void)
|
||||
{
|
||||
u8 rval;
|
||||
int i;
|
||||
|
||||
vbe_info_t info;
|
||||
rval = vbe_info(&info);
|
||||
if (rval != 0)
|
||||
return;
|
||||
|
||||
DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
|
||||
DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
|
||||
DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
|
||||
DEBUG_PRINTF_VBE("Capabilities:\n");
|
||||
DEBUG_PRINTF_VBE("\tDAC: %s\n",
|
||||
(info.capabilities & 0x1) ==
|
||||
0 ? "fixed 6bit" : "switchable 6/8bit");
|
||||
DEBUG_PRINTF_VBE("\tVGA: %s\n",
|
||||
(info.capabilities & 0x2) ==
|
||||
0 ? "compatible" : "not compatible");
|
||||
DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
|
||||
(info.capabilities & 0x4) ==
|
||||
0 ? "normal" : "use blank bit in Function 09h");
|
||||
|
||||
mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE;
|
||||
vbe_get_mode_info(&mode_info);
|
||||
unsigned char *framebuffer =
|
||||
(unsigned char *) le32_to_cpu(mode_info.vesa.phys_base_ptr);
|
||||
DEBUG_PRINTF_VBE("FRAMEBUFFER: 0x%08x\n", framebuffer);
|
||||
vbe_set_mode(&mode_info);
|
||||
|
||||
struct jpeg_decdata *decdata;
|
||||
decdata = malloc(sizeof(*decdata));
|
||||
|
||||
/* Switching Intel IGD to 1MB video memory will break this. Who
|
||||
* cares. */
|
||||
int imagesize = 1024*768*2;
|
||||
|
||||
unsigned char *jpeg = cbfs_find_file("bootsplash.jpg", CBFS_TYPE_BOOTSPLASH);
|
||||
if (!jpeg) {
|
||||
DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n");
|
||||
return;
|
||||
}
|
||||
DEBUG_PRINTF_VBE("Splash at %08x ...\n", jpeg);
|
||||
dump(jpeg, 64);
|
||||
|
||||
int ret = 0;
|
||||
DEBUG_PRINTF_VBE("Decompressing boot splash screen...\n");
|
||||
ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata);
|
||||
DEBUG_PRINTF_VBE("returns %x\n", ret);
|
||||
}
|
||||
|
||||
void fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
|
||||
{
|
||||
framebuffer->physical_address = le32_to_cpu(mode_info.vesa.phys_base_ptr);
|
||||
|
||||
framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution);
|
||||
framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution);
|
||||
framebuffer->bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline);
|
||||
framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel;
|
||||
|
||||
framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos;
|
||||
framebuffer->red_mask_size = mode_info.vesa.red_mask_size;
|
||||
|
||||
framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos;
|
||||
framebuffer->green_mask_size = mode_info.vesa.green_mask_size;
|
||||
|
||||
framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos;
|
||||
framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size;
|
||||
|
||||
framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos;
|
||||
framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size;
|
||||
}
|
||||
|
||||
void vbe_textmode_console(void)
|
||||
{
|
||||
/* Wait, just a little bit more, pleeeease ;-) */
|
||||
delay(2);
|
||||
|
||||
M.x86.R_EAX = 0x0003;
|
||||
runInt10();
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,16 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the BSD License
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial implementation
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _BIOSEMU_VBE_H_
|
||||
#define _BIOSEMU_VBE_H_
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user