added x86 emulator (for Radeon BIOS)

This commit is contained in:
Markus Fröschle
2013-12-29 00:33:45 +00:00
parent e0a2ba8af3
commit 1dfbedac64
4 changed files with 1317 additions and 1 deletions

View File

@@ -43,7 +43,7 @@ TRGTDIRS= ./firebee ./m5484lite
OBJDIRS=$(patsubst %, %/objs,$(TRGTDIRS)) OBJDIRS=$(patsubst %, %/objs,$(TRGTDIRS))
TOOLDIR=util TOOLDIR=util
VPATH=dma exe flash fs if kbd pci spi sys usb net util video radeon xhdi VPATH=dma exe flash fs if kbd pci spi sys usb net util video radeon x86emu xhdi
# Linker control file. The final $(LDCFILE) is intermediate only (preprocessed version of $(LDCSRC) # Linker control file. The final $(LDCFILE) is intermediate only (preprocessed version of $(LDCSRC)
LDCFILE=bas.lk LDCFILE=bas.lk
@@ -113,6 +113,8 @@ CSRCS= \
radeon_cursor.c \ radeon_cursor.c \
radeon_monitor.c \ radeon_monitor.c \
\ \
biosemu.c \
\
basflash.c \ basflash.c \
basflash_start.c basflash_start.c

200
include/x86emu.h Normal file
View File

@@ -0,0 +1,200 @@
/****************************************************************************
*
* 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
#ifdef SCITECH
#include "scitech.h"
#define X86API _ASMAPI
#define X86APIP _ASMAPIP
typedef int X86EMU_pioAddr;
#else
#include "bas_types.h"
#define X86API
#define X86APIP *
#endif
#include "x86regs.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
{
uint8_t (X86APIP inb)(X86EMU_pioAddr addr);
uint16_t (X86APIP inw)(X86EMU_pioAddr addr);
uint32_t (X86APIP inl)(X86EMU_pioAddr addr);
void (X86APIP outb)(X86EMU_pioAddr addr, uint8_t val);
void (X86APIP outw)(X86EMU_pioAddr addr, uint16_t val);
void (X86APIP outl)(X86EMU_pioAddr addr, uint32_t 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 {
uint8_t (X86APIP rdb)(uint32_t addr);
uint16_t (X86APIP rdw)(uint32_t addr);
uint32_t (X86APIP rdl)(uint32_t addr);
void (X86APIP wrb)(uint32_t addr, uint8_t val);
void (X86APIP wrw)(uint32_t addr, uint16_t val);
void (X86APIP wrl)(uint32_t addr, uint32_t val);
} X86EMU_memFuncs;
/****************************************************************************
Here are the default memory read and write
function in case they are needed as fallbacks.
***************************************************************************/
extern uint8_t X86API rdb(uint32_t addr);
extern uint16_t X86API rdw(uint32_t addr);
extern uint32_t X86API rdl(uint32_t addr);
extern void X86API wrb(uint32_t addr, uint8_t val);
extern void X86API wrw(uint32_t addr, uint16_t val);
extern void X86API wrl(uint32_t addr, uint32_t 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);
/* decode.c */
void X86EMU_exec(void);
void X86EMU_halt_sys(void);
#ifdef DEBUG
#define HALT_SYS() \
DPRINT("halt_sys: file "); \
DPRINT(__FILE__); \
DPRINTVAL(", line ", __LINE__); \
DPRINT("\r\n"); \
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_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(uint16_t seg, uint16_t off, uint32_t amt);
int X86EMU_trace_on(void);
int X86EMU_trace_off(void);
int X86EMU_set_debug(int debug);
void X86EMU_setMemBase(void *base, unsigned long size);
#ifdef __cplusplus
} /* End of "C" linkage for C++ */
#endif
#endif /* __X86EMU_X86EMU_H */

373
include/x86regs.h Normal file
View File

@@ -0,0 +1,373 @@
/****************************************************************************
*
* 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 {
uint32_t e_reg;
} I32_reg_t;
typedef struct {
uint16_t filler0, x_reg;
} I16_reg_t;
typedef struct {
uint8_t filler0, filler1, h_reg, l_reg;
} I8_reg_t;
#else /* !__BIG_ENDIAN__ */
typedef struct {
uint32_t e_reg;
} I32_reg_t;
typedef struct {
uint16_t x_reg;
} I16_reg_t;
typedef struct {
uint8_t 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;
uint32_t FLAGS;
};
/*
* Segment registers here represent the 16 bit quantities
* CS, DS, ES, SS.
*/
struct i386_segment_regs {
uint16_t CS, DS, SS, ES, FS, GS;
};
/* 8 bit registers */
#define R_AH gen.A.I8_reg.h_reg
#define R_AL gen.A.I8_reg.l_reg
#define R_BH gen.B.I8_reg.h_reg
#define R_BL gen.B.I8_reg.l_reg
#define R_CH gen.C.I8_reg.h_reg
#define R_CL gen.C.I8_reg.l_reg
#define R_DH gen.D.I8_reg.h_reg
#define R_DL gen.D.I8_reg.l_reg
/* 16 bit registers */
#define R_AX gen.A.I16_reg.x_reg
#define R_BX gen.B.I16_reg.x_reg
#define R_CX gen.C.I16_reg.x_reg
#define R_DX gen.D.I16_reg.x_reg
/* 32 bit extended registers */
#define R_EAX gen.A.I32_reg.e_reg
#define R_EBX gen.B.I32_reg.e_reg
#define R_ECX gen.C.I32_reg.e_reg
#define R_EDX gen.D.I32_reg.e_reg
/* special registers */
#define R_SP spc.SP.I16_reg.x_reg
#define R_BP spc.BP.I16_reg.x_reg
#define R_SI spc.SI.I16_reg.x_reg
#define R_DI spc.DI.I16_reg.x_reg
#define R_IP spc.IP.I16_reg.x_reg
#define R_FLG spc.FLAGS
/* special registers */
#define R_SP spc.SP.I16_reg.x_reg
#define R_BP spc.BP.I16_reg.x_reg
#define R_SI spc.SI.I16_reg.x_reg
#define R_DI spc.DI.I16_reg.x_reg
#define R_IP spc.IP.I16_reg.x_reg
#define R_FLG spc.FLAGS
/* special registers */
#define R_ESP spc.SP.I32_reg.e_reg
#define R_EBP spc.BP.I32_reg.e_reg
#define R_ESI spc.SI.I32_reg.e_reg
#define R_EDI spc.DI.I32_reg.e_reg
#define R_EIP spc.IP.I32_reg.e_reg
#define R_EFLG spc.FLAGS
/* segment registers */
#define R_CS seg.CS
#define R_DS seg.DS
#define R_SS seg.SS
#define R_ES seg.ES
#define R_FS seg.FS
#define R_GS seg.GS
/* flag conditions */
#define FB_CF 0x0001 /* CARRY flag */
#define FB_PF 0x0004 /* PARITY flag */
#define FB_AF 0x0010 /* AUX flag */
#define FB_ZF 0x0040 /* ZERO flag */
#define FB_SF 0x0080 /* SIGN flag */
#define FB_TF 0x0100 /* TRAP flag */
#define FB_IF 0x0200 /* INTERRUPT ENABLE flag */
#define FB_DF 0x0400 /* DIR flag */
#define FB_OF 0x0800 /* OVERFLOW flag */
/* 80286 and above always have bit#1 set */
#define F_ALWAYS_ON (0x0002) /* flag bits always on */
/*
* Define a mask for only those flag bits we will ever pass back
* (via PUSHF)
*/
#define F_MSK (FB_CF|FB_PF|FB_AF|FB_ZF|FB_SF|FB_TF|FB_IF|FB_DF|FB_OF)
/* following bits masked in to a 16bit quantity */
#define F_CF 0x0001 /* CARRY flag */
#define F_PF 0x0004 /* PARITY flag */
#define F_AF 0x0010 /* AUX flag */
#define F_ZF 0x0040 /* ZERO flag */
#define F_SF 0x0080 /* SIGN flag */
#define F_TF 0x0100 /* TRAP flag */
#define F_IF 0x0200 /* INTERRUPT ENABLE flag */
#define F_DF 0x0400 /* DIR flag */
#define F_OF 0x0800 /* OVERFLOW flag */
#define TOGGLE_FLAG(flag) (M.x86.R_FLG ^= (flag))
#define SET_FLAG(flag) (M.x86.R_FLG |= (flag))
#define CLEAR_FLAG(flag) (M.x86.R_FLG &= ~(flag))
#define ACCESS_FLAG(flag) (M.x86.R_FLG & (flag))
#define CLEARALL_FLAG(m) (M.x86.R_FLG = 0)
#define CONDITIONAL_SET_FLAG(COND,FLAG) \
if (COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG)
#define F_PF_CALC 0x010000 /* PARITY flag has been calced */
#define F_ZF_CALC 0x020000 /* ZERO flag has been calced */
#define F_SF_CALC 0x040000 /* SIGN flag has been calced */
#define F_ALL_CALC 0xff0000 /* All have been calced */
/*
* Emulator machine state.
* Segment usage control.
*/
#define SYSMODE_SEG_DS_SS 0x00000001
#define SYSMODE_SEGOVR_CS 0x00000002
#define SYSMODE_SEGOVR_DS 0x00000004
#define SYSMODE_SEGOVR_ES 0x00000008
#define SYSMODE_SEGOVR_FS 0x00000010
#define SYSMODE_SEGOVR_GS 0x00000020
#define SYSMODE_SEGOVR_SS 0x00000040
#define SYSMODE_PREFIX_REPE 0x00000080
#define SYSMODE_PREFIX_REPNE 0x00000100
#define SYSMODE_PREFIX_DATA 0x00000200
#define SYSMODE_PREFIX_ADDR 0x00000400
#define SYSMODE_INTR_PENDING 0x10000000
#define SYSMODE_EXTRN_INTR 0x20000000
#define SYSMODE_HALTED 0x40000000
#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | \
SYSMODE_SEGOVR_CS | \
SYSMODE_SEGOVR_DS | \
SYSMODE_SEGOVR_ES | \
SYSMODE_SEGOVR_FS | \
SYSMODE_SEGOVR_GS | \
SYSMODE_SEGOVR_SS)
#define SYSMODE_CLRMASK (SYSMODE_SEG_DS_SS | \
SYSMODE_SEGOVR_CS | \
SYSMODE_SEGOVR_DS | \
SYSMODE_SEGOVR_ES | \
SYSMODE_SEGOVR_FS | \
SYSMODE_SEGOVR_GS | \
SYSMODE_SEGOVR_SS | \
SYSMODE_PREFIX_DATA | \
SYSMODE_PREFIX_ADDR)
#define INTR_SYNCH 0x1
#define INTR_ASYNCH 0x2
#define INTR_HALTED 0x4
typedef struct {
struct i386_general_regs gen;
struct i386_special_regs spc;
struct i386_segment_regs seg;
/*
* MODE contains information on:
* REPE prefix 2 bits repe,repne
* SEGMENT overrides 5 bits normal,DS,SS,CS,ES
* Delayed flag set 3 bits (zero, signed, parity)
* reserved 6 bits
* interrupt # 8 bits instruction raised interrupt
* BIOS video segregs 4 bits
* Interrupt Pending 1 bits
* Extern interrupt 1 bits
* Halted 1 bits
*/
uint32_t mode;
volatile int intr; /* mask of pending interrupts */
int debug;
#ifdef DEBUG
int check;
uint16_t saved_ip;
uint16_t saved_cs;
int enc_pos;
int enc_str_pos;
// char decode_buf[32]; /* encoded byte stream */
char decoded_buf[256]; /* disassembled strings */
#endif
uint8_t intno;
uint8_t __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
/*-------------------------- Function Prototypes --------------------------*/
/* Function to log information at runtime */
#ifdef __cplusplus
} /* End of "C" linkage for C++ */
#endif
#endif /* __X86EMU_REGS_H */

741
x86emu/biosemu.c Normal file
View File

@@ -0,0 +1,741 @@
#define RINFO_ONLY
#include "radeonfb.h"
#include "bas_string.h"
#include "x86emu.h"
#include "pci.h"
#include "pci_ids.h"
// #include "vgatables.h"
#define USE_SDRAM
#define DIRECT_ACCESS
#define MEM_WB(where, what) wrb(where, what)
#define MEM_WW(where, what) wrw(where, what)
#define MEM_WL(where, what) wrl(where, what)
#define MEM_RB(where) rdb(where)
#define MEM_RW(where) rdw(where)
#define MEM_RL(where) rdl(where)
#define PCI_VGA_RAM_IMAGE_START 0xC0000
#define PCI_RAM_IMAGE_START 0xD0000
#define SYS_BIOS 0xF0000
#define SIZE_EMU 0x100000
#ifdef DIRECT_ACCESS
extern uint16_t swpw(uint16_t val);
extern uint32_t swap_long(uint32_t val);
#endif
typedef struct
{
long ident;
union
{
long l;
short i[2];
char c[4];
} v;
} COOKIE;
struct rom_header
{
uint16_t signature;
uint8_t size;
uint8_t init[3];
uint8_t reserved[0x12];
uint16_t data;
};
struct pci_data
{
uint32_t signature;
uint16_t vendor;
uint16_t device;
uint16_t reserved_1;
uint16_t dlen;
uint8_t drevision;
uint8_t class_lo;
uint16_t class_hi;
uint16_t ilen;
uint16_t irevision;
uint8_t type;
uint8_t indicator;
uint16_t reserved_2;
};
struct radeonfb_info *rinfo_biosemu;
uint16_t offset_port;
uint32_t offset_mem;
static uint32_t offset_io;
static uint32_t config_address_reg;
extern int pcibios_handler();
extern COOKIE *get_cookie(long id);
extern short restart, os_magic;
/* general software interrupt handler */
uint32_t getIntVect(int num)
{
return MEM_RW(num << 2) + (MEM_RW((num << 2) + 2) << 4);
}
/* FixME: There is already a push_word() in the emulator */
void pushw(uint16_t val)
{
X86_ESP -= 2;
MEM_WW(((uint32_t) X86_SS << 4) + X86_SP, val);
}
int run_bios_int(int num)
{
uint32_t eflags;
eflags = X86_EFLAGS;
pushw(eflags);
pushw(X86_CS);
pushw(X86_IP);
X86_CS = MEM_RW((num << 2) + 2);
X86_IP = MEM_RW(num << 2);
return 1;
}
static uint8_t inb(uint16_t port)
{
uint8_t val = 0;
if ((port >= offset_port) && (port <= offset_port+0xFF))
{
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("inb(", port);
#endif
val = *(uint8_t *)(offset_io+(uint32_t)port);
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
}
return val;
}
static uint16_t inw(uint16_t port)
{
uint16_t val = 0;
if ((port >= offset_port) && (port <= offset_port+0xFF))
{
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("inw(", port);
#endif
val = swpw(*(uint16_t *)(offset_io+(uint32_t)port));
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
}
return val;
}
static uint32_t inl(uint16_t port)
{
uint32_t val = 0;
if ((port >= offset_port) && (port <= offset_port+0xFF))
{
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("inl(", port);
#endif
val = swpl(*(uint32_t *)(offset_io+(uint32_t)port));
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
}
else if (port == 0xCF8)
{
val = config_address_reg;
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("inl(", port);
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
}
else if ((port == 0xCFC) && ((config_address_reg & 0x80000000) !=0))
{
switch(config_address_reg & 0xFC)
{
case PCIIDR:
val = ((uint32_t) rinfo_biosemu->chipset << 16) + PCI_VENDOR_ID_ATI;
break;
case PCIBAR1:
val = (uint32_t) offset_port + 1;
break;
default:
val = pci_read_config_longword(rinfo_biosemu->handle, config_address_reg & 0xFC);
break;
}
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("inl(", port);
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
}
return val;
}
void outb(uint8_t val, uint16_t port)
{
if ((port >= offset_port) && (port <= offset_port+0xFF))
{
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("outb(", port);
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
*(uint8_t *)(offset_io + (uint32_t) port) = val;
}
}
void outw(uint16_t val, uint16_t port)
{
if ((port >= offset_port) && (port <= offset_port+0xFF))
{
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("outw(", port);
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
*(uint16_t *)(offset_io + (uint32_t) port) = swpw(val);
}
}
void outl(uint32_t val, uint16_t port)
{
if ((port >= offset_port) && (port <= offset_port+0xFF))
{
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("outl(", port);
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
*(uint32_t *)(offset_io + (uint32_t) port) = swpl(val);
}
else if (port == 0xCF8)
{
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("outl(", port);
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
config_address_reg = val;
}
else if ((port == 0xCFC) && ((config_address_reg & 0x80000000) !=0))
{
if ((config_address_reg & 0xFC) == PCIBAR1)
offset_port = (uint16_t)val & 0xFFFC;
else
{
#ifdef DEBUG_X86EMU_PCI
DPRINTVALHEX("outl(", port);
DPRINTVALHEX(") = ", val);
DPRINT("\r\n");
#endif
pci_write_config_longword(rinfo_biosemu->handle, config_address_reg & 0xFC, val);
}
}
}
/* Interrupt multiplexer */
void do_int(int num)
{
int ret = 0;
// DPRINTVAL("int ", num);
// DPRINTVALHEX(" vector at ", getIntVect(num));
// DPRINT("\r\n");
switch (num)
{
#ifndef _PC
case 0x10:
case 0x42:
case 0x6D:
if (getIntVect(num) == 0x0000)
DPRINT("un-inited int vector\r\n");
if (getIntVect(num) == 0xFF065)
{
//ret = int42_handler();
ret = 1;
}
break;
#endif
case 0x15:
//ret = int15_handler();
ret = 1;
break;
case 0x16:
//ret = int16_handler();
ret = 0;
break;
case 0x1A:
ret = pcibios_handler();
ret = 1;
break;
case 0xe6:
//ret = intE6_handler();
ret = 0;
break;
default:
break;
}
if (!ret)
ret = run_bios_int(num);
}
#if 0
void reset_int_vect(void)
{
/*
* This table is normally located at 0xF000:0xF0A4. However, int 0x42,
* function 0 (Mode Set) expects it (or a copy) somewhere in the bottom
* 64kB. Note that because this data doesn't survive POST, int 0x42 should
* only be used during EGA/VGA BIOS initialisation.
*/
static const uint8_t VideoParms[] = {
/* Timing for modes 0x00 & 0x01 */
0x38, 0x28, 0x2d, 0x0a, 0x1f, 0x06, 0x19, 0x1c,
0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
/* Timing for modes 0x02 & 0x03 */
0x71, 0x50, 0x5a, 0x0a, 0x1f, 0x06, 0x19, 0x1c,
0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
/* Timing for modes 0x04, 0x05 & 0x06 */
0x38, 0x28, 0x2d, 0x0a, 0x7f, 0x06, 0x64, 0x70,
0x02, 0x01, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
/* Timing for mode 0x07 */
0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19,
0x02, 0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
/* Display page lengths in little endian order */
0x00, 0x08, /* Modes 0x00 and 0x01 */
0x00, 0x10, /* Modes 0x02 and 0x03 */
0x00, 0x40, /* Modes 0x04 and 0x05 */
0x00, 0x40, /* Modes 0x06 and 0x07 */
/* Number of columns for each mode */
40, 40, 80, 80, 40, 40, 80, 80,
/* CGA Mode register value for each mode */
0x2c, 0x28, 0x2d, 0x29, 0x2a, 0x2e, 0x1e, 0x29,
/* Padding */
0x00, 0x00, 0x00, 0x00
};
int i;
for(i = 0; i < sizeof(VideoParms); i++)
MEM_WB(i + (0x1000 - sizeof(VideoParms)), VideoParms[i]);
MEM_WW(0x1d << 2, 0x1000 - sizeof(VideoParms));
MEM_WW((0x1d << 2) + 2, 0);
DPRINT("SETUP INT\r\n");
MEM_WW(0x10 << 2, 0xf065);
MEM_WW((0x10 << 2) + 2, SYS_BIOS >> 4);
MEM_WW(0x42 << 2, 0xf065);
MEM_WW((0x42 << 2) + 2, SYS_BIOS >> 4);
MEM_WW(0x6D << 2, 0xf065);
MEM_WW((0x6D << 2) + 2, SYS_BIOS >> 4);
}
/*
* here we are really paranoid about faking a "real"
* BIOS. Most of this information was pulled from
* dosemu.
*/
void setup_int_vect(void)
{
int i;
/* let the int vects point to the SYS_BIOS seg */
for(i = 0; i < 0x80; i++)
{
MEM_WW(i << 2, 0);
MEM_WW((i << 2) + 2, SYS_BIOS >> 4);
}
reset_int_vect();
/* font tables default location (int 1F) */
MEM_WW(0x1f << 2, 0xfa6e);
/* int 11 default location (Get Equipment Configuration) */
MEM_WW(0x11 << 2, 0xf84d);
/* int 12 default location (Get Conventional Memory Size) */
MEM_WW(0x12 << 2, 0xf841);
/* int 15 default location (I/O System Extensions) */
MEM_WW(0x15 << 2, 0xf859);
/* int 1A default location (RTC, PCI and others) */
MEM_WW(0x1a << 2, 0xff6e);
/* int 05 default location (Bound Exceeded) */
MEM_WW(0x05 << 2, 0xff54);
/* int 08 default location (Double Fault) */
MEM_WW(0x08 << 2, 0xfea5);
/* int 13 default location (Disk) */
MEM_WW(0x13 << 2, 0xec59);
/* int 0E default location (Page Fault) */
MEM_WW(0x0e << 2, 0xef57);
/* int 17 default location (Parallel Port) */
MEM_WW(0x17 << 2, 0xefd2);
/* fdd table default location (int 1e) */
MEM_WW(0x1e << 2, 0xefc7);
/* Set Equipment flag to VGA */
i = MEM_RB(0x0410) & 0xCF;
MEM_WB(0x0410, i);
/* XXX Perhaps setup more of the BDA here. See also int42(0x00). */
}
#endif
static int setup_system_bios(void *base_addr)
{
char *base = (char *) base_addr;
int i;
/*
* we trap the "industry standard entry points" to the BIOS
* and all other locations by filling them with "hlt"
* TODO: implement hlt-handler for these
*/
// for(i=0; i<0x10000; base[i++]=0xF4);
for(i=0; i<SIZE_EMU; base[i++]=0xF4);
/* set bios date */
//strcpy(base + 0x0FFF5, "06/11/99");
/* set up eisa ident string */
//strcpy(base + 0x0FFD9, "PCI_ISA");
/* write system model id for IBM-AT */
//*((unsigned char *) (base + 0x0FFFE)) = 0xfc;
return(1);
}
#if 0
static void memsetw(uint32_t addr, uint16_t value, uint16_t count)
{
while(--count)
{
wrw(addr, value);
addr += 2;
}
}
static uint8_t find_vga_entry(uint8_t mode)
{
uint8_t i,line=0xFF;
for(i=0;i<=MODE_MAX;i++)
{
if (vga_modes[i].svgamode==mode)
{
line=i;
break;
}
}
return(line);
}
void biosfn_set_video_mode(uint8_t mode)
{
uint8_t line,mmask,*palette=0,vpti;
uint16_t i,twidth,theightm1,cheight;
uint8_t modeset_ctl=0;
uint16_t crtc_addr;
// find the entry in the video modes
line=find_vga_entry(mode);
if (line==0xFF)
return;
vpti=line_to_vpti[line];
twidth=video_param_table[vpti].twidth;
theightm1=video_param_table[vpti].theightm1;
cheight=video_param_table[vpti].cheight;
// if palette loading (bit 3 of modeset ctl = 0)
if ((modeset_ctl&0x08)==0)
{
// Set the PEL mask
outb(vga_modes[line].pelmask,VGAREG_PEL_MASK);
// Set the whole dac always, from 0
outb(0x00,VGAREG_DAC_WRITE_ADDRESS);
// From which palette
switch(vga_modes[line].dacmodel)
{
case 0: palette=palette0; break;
case 1: palette=palette1; break;
case 2: palette=palette2; break;
case 3: palette=palette3; break;
}
// Always 256*3 values
for(i=0;i<0x0100;i++)
{
if (i<=dac_regs[vga_modes[line].dacmodel])
{
outb(palette[(i*3)+0],VGAREG_DAC_DATA);
outb(palette[(i*3)+1],VGAREG_DAC_DATA);
outb(palette[(i*3)+2],VGAREG_DAC_DATA);
}
else
{
outb(0,VGAREG_DAC_DATA);
outb(0,VGAREG_DAC_DATA);
outb(0,VGAREG_DAC_DATA);
}
}
if ((modeset_ctl&0x02)==0x02)
{
uint8_t r,g,b;
uint16_t i;
uint16_t index,start=0;
inb(VGAREG_ACTL_RESET);
outb(0x00,VGAREG_ACTL_ADDRESS);
for(index = 0; index < 0x100; index++)
{
// set read address and switch to read mode
outb(start,VGAREG_DAC_READ_ADDRESS);
// get 6-bit wide RGB data values
r=inb(VGAREG_DAC_DATA);
g=inb(VGAREG_DAC_DATA);
b=inb(VGAREG_DAC_DATA);
// intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
i = ((77*r + 151*g + 28*b) + 0x80) >> 8;
if (i>0x3f)
i=0x3f;
// set write address and switch to write mode
outb(start,VGAREG_DAC_WRITE_ADDRESS);
// write new intensity value
outb(i & 0xff,VGAREG_DAC_DATA);
outb(i & 0xff,VGAREG_DAC_DATA);
outb(i & 0xff,VGAREG_DAC_DATA);
start++;
}
inb(VGAREG_ACTL_RESET);
outb(0x20,VGAREG_ACTL_ADDRESS);
}
}
// Reset Attribute Ctl flip-flop
inb(VGAREG_ACTL_RESET);
// Set Attribute Ctl
for(i=0;i<=0x13;i++)
{
outb(i,VGAREG_ACTL_ADDRESS);
outb(video_param_table[vpti].actl_regs[i],VGAREG_ACTL_WRITE_DATA);
}
outb(0x14,VGAREG_ACTL_ADDRESS);
outb(0x00,VGAREG_ACTL_WRITE_DATA);
// Set Sequencer Ctl
outb(0,VGAREG_SEQU_ADDRESS);
outb(0x03,VGAREG_SEQU_DATA);
for(i=1;i<=4;i++)
{
outb(i,VGAREG_SEQU_ADDRESS);
outb(video_param_table[vpti].sequ_regs[i - 1],VGAREG_SEQU_DATA);
}
// Set Grafx Ctl
for(i=0;i<=8;i++)
{
outb(i,VGAREG_GRDC_ADDRESS);
outb(video_param_table[vpti].grdc_regs[i],VGAREG_GRDC_DATA);
}
// Set CRTC address VGA
crtc_addr=VGAREG_VGA_CRTC_ADDRESS;
// Disable CRTC write protection
outw(crtc_addr,0x0011);
// Set CRTC regs
for(i=0;i<=0x18;i++)
{
outb(i,crtc_addr);
outb(video_param_table[vpti].crtc_regs[i],crtc_addr+1);
}
// Set the misc register
outb(video_param_table[vpti].miscreg,VGAREG_WRITE_MISC_OUTPUT);
// Enable video
outb(0x20,VGAREG_ACTL_ADDRESS);
inb(VGAREG_ACTL_RESET);
if (mode<0x0d)
memsetw(vga_modes[line].sstart,0x0000,0x4000); // 32k
else
{
outb(0x02,VGAREG_SEQU_ADDRESS);
mmask = inb( VGAREG_SEQU_DATA );
outb(0x0f,VGAREG_SEQU_DATA); // all planes
memsetw(vga_modes[line].sstart,0x0000,0x8000); // 64k
outb(mmask,VGAREG_SEQU_DATA);
}
}
#endif
void run_bios(struct radeonfb_info *rinfo)
{
long i, j;
unsigned char *ptr;
struct rom_header *rom_header;
struct pci_data *rom_data;
unsigned long rom_size=0;
unsigned long image_size=0;
unsigned long biosmem=0x01000000; /* when run_bios() is called, SDRAM is valid but not added to the system */
unsigned long addr;
unsigned short initialcs;
unsigned short initialip;
unsigned short devfn = (unsigned short)( ((rinfo->handle & 0xFF) << 3) + ((((rinfo->handle >> 16) / PCI_MAX_FUNCTION) & 0xFF) << 8)); // was dev->bus->secondary << 8 | dev->path.u.pci.devfn;
X86EMU_intrFuncs intFuncs[256];
if ((rinfo->mmio_base == NULL) || (rinfo->io_base == NULL))
return;
#ifndef COLDFIRE
/* try to not init the board with the X86 VGA BIOS, too long on CT60 (more than 20 seconds, 2 seconds on Coldfire) */
if (os_magic)
return;
if (restart /* CTRL-ALT-DEL else 0 if reset */
&& (*memvalid == MEMVALID_MAGIC) && (*memval2 == MEMVAL2_MAGIC)
&& (*((unsigned long *) 0x51AL) == 0x5555AAAA)) /* memval3 */
return;
#endif
rinfo_biosemu = rinfo;
config_address_reg = 0;
offset_port = 0x300;
#ifdef DIRECT_ACCESS
offset_io = (uint32_t)rinfo->io_base-(uint32_t)offset_port;
offset_mem = (uint32_t)rinfo->fb_base-0xA0000;
#else
offset_io = rinfo->io_base_phys-(uint32_t)offset_port;
offset_mem = rinfo->fb_base_phys-0xA0000;
#endif
rom_header = (struct rom_header *)0;
do
{
rom_header = (struct rom_header *)((unsigned long)rom_header + image_size); // get next image
rom_data = (struct pci_data *)((unsigned long)rom_header + (unsigned long)BIOS_IN16((long)&rom_header->data));
image_size = (unsigned long)BIOS_IN16((long)&rom_data->ilen) * 512;
}
while((BIOS_IN8((long)&rom_data->type) != 0) && (BIOS_IN8((long)&rom_data->indicator) != 0)); // make sure we got x86 version
if (BIOS_IN8((long)&rom_data->type) != 0)
return;
rom_size = (unsigned long)BIOS_IN8((long)&rom_header->size) * 512;
if (PCI_CLASS_DISPLAY_VGA == BIOS_IN16((long)&rom_data->class_hi))
{
#ifdef USE_SDRAM
#if 0
if (os_magic)
{
biosmem = Mxalloc(SIZE_EMU, 3);
if (biosmem == 0)
return;
}
#endif
#else
biosmem = Mxalloc(SIZE_EMU, 0);
if (biosmem == 0)
return;
#endif /* USE_SDRAM */
memset((char *)biosmem, 0, SIZE_EMU);
setup_system_bios((char *)biosmem);
DPRINTVALHEX("Copying VGA ROM Image from ", (long)rinfo->bios_seg+(long)rom_header);
DPRINTVALHEX(" to ", biosmem+PCI_VGA_RAM_IMAGE_START);
DPRINTVALHEX(", ", rom_size);
DPRINT(" bytes\r\n");
#if 0 // 8 bits copy
ptr = (char *)biosmem;
for(i = (long)rom_header, j = PCI_VGA_RAM_IMAGE_START; i < (long)rom_header+rom_size; ptr[j++] = BIOS_IN8(i++));
#else // 32 bits copy
{
long bytes_align = (long)rom_header & 3;
ptr = (unsigned char *)biosmem;
i = (long)rom_header;
j = PCI_VGA_RAM_IMAGE_START;
if (bytes_align)
for(; i < 4 - bytes_align; ptr[j++] = BIOS_IN8(i++));
for(; i < (long)rom_header+rom_size; *((unsigned long *)&ptr[j]) = swpl(BIOS_IN32(i)), i+=4, j+=4);
}
#endif
addr = PCI_VGA_RAM_IMAGE_START;
}
else
{
#ifdef USE_SDRAM
#if 0
if (os_magic)
{
biosmem = Mxalloc(SIZE_EMU, 3);
if (biosmem == 0)
return;
}
#endif
#else
biosmem = Mxalloc(SIZE_EMU, 0);
if (biosmem == 0)
return;
#endif /* USE_SDRAM */
setup_system_bios((char *)biosmem);
memset((char *)biosmem, 0, SIZE_EMU);
DPRINTVALHEX("Copying non-VGA ROM Image from ", (long)rinfo->bios_seg+(long)rom_header);
DPRINTVALHEX(" to ", biosmem+PCI_RAM_IMAGE_START);
DPRINTVALHEX(", ", rom_size);
DPRINT(" bytes\r\n");
ptr = (unsigned char *)biosmem;
for(i = (long)rom_header, j = PCI_RAM_IMAGE_START; i < (long)rom_header+rom_size; ptr[j++] = BIOS_IN8(i++));
addr = PCI_RAM_IMAGE_START;
}
initialcs = (addr & 0xF0000) >> 4;
initialip = (addr + 3) & 0xFFFF;
X86EMU_setMemBase((void *)biosmem, SIZE_EMU);
for(i = 0; i < 256; i++)
intFuncs[i] = do_int;
X86EMU_setupIntrFuncs(intFuncs);
{
char *date = "01/01/99";
for(i = 0; date[i]; i++)
wrb(0xffff5 + i, date[i]);
wrb(0xffff7, '/');
wrb(0xffffa, '/');
}
{
/* FixME: move PIT init to its own file */
outb(0x36, 0x43);
outb(0x00, 0x40);
outb(0x00, 0x40);
}
// setup_int_vect();
/* cpu setup */
X86_AX = devfn ? devfn : 0xff;
X86_DX = 0x80;
X86_EIP = initialip;
X86_CS = initialcs;
/* Initialize stack and data segment */
X86_SS = initialcs;
X86_SP = 0xfffe;
X86_DS = 0x0040;
X86_ES = 0x0000;
/* We need a sane way to return from bios
* execution. A hlt instruction and a pointer
* to it, both kept on the stack, will do.
*/
pushw(0xf4f4); /* hlt; hlt */
// pushw(0x10cd); /* int #0x10 */
// pushw(0x0013); /* 320 x 200 x 256 colors */
// // pushw(0x000F); /* 640 x 350 x mono */
// pushw(0xb890); /* nop, mov ax,#0x13 */
pushw(X86_SS);
pushw(X86_SP + 2);
#ifdef DEBUG_X86EMU
X86EMU_trace_on();
X86EMU_set_debug(DEBUG_DECODE_F | DEBUG_TRACE_F);
#endif
DPRINT("X86EMU entering emulator\r\n");
*vblsem = 0;
X86EMU_exec();
*vblsem = 1;
DPRINT("X86EMU halted\r\n");
// biosfn_set_video_mode(0x13); /* 320 x 200 x 256 colors */
#ifdef USE_SDRAM
#if 0
if (os_magic)
{
memset((char *)biosmem, 0, SIZE_EMU);
Mfree(biosmem);
}
#endif
#else
memset((char *)biosmem, 0, SIZE_EMU);
Mfree(biosmem);
#endif /* USE_SDRAM */
}