From 77aedc8cbd4f194eaa1dbd1bb9230a374d7e7dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Fr=C3=B6schle?= Date: Sun, 29 Dec 2013 00:33:45 +0000 Subject: [PATCH] added x86 emulator (for Radeon BIOS) --- BaS_gcc/Makefile | 4 +- BaS_gcc/include/x86emu.h | 200 ++++++++++ BaS_gcc/include/x86regs.h | 373 +++++++++++++++++++ BaS_gcc/x86emu/biosemu.c | 741 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 1317 insertions(+), 1 deletion(-) create mode 100644 BaS_gcc/include/x86emu.h create mode 100644 BaS_gcc/include/x86regs.h create mode 100644 BaS_gcc/x86emu/biosemu.c diff --git a/BaS_gcc/Makefile b/BaS_gcc/Makefile index f194af8..ebb8ab9 100644 --- a/BaS_gcc/Makefile +++ b/BaS_gcc/Makefile @@ -43,7 +43,7 @@ TRGTDIRS= ./firebee ./m5484lite OBJDIRS=$(patsubst %, %/objs,$(TRGTDIRS)) 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) LDCFILE=bas.lk @@ -113,6 +113,8 @@ CSRCS= \ radeon_cursor.c \ radeon_monitor.c \ \ + biosemu.c \ + \ basflash.c \ basflash_start.c diff --git a/BaS_gcc/include/x86emu.h b/BaS_gcc/include/x86emu.h new file mode 100644 index 0000000..445dfd4 --- /dev/null +++ b/BaS_gcc/include/x86emu.h @@ -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 */ diff --git a/BaS_gcc/include/x86regs.h b/BaS_gcc/include/x86regs.h new file mode 100644 index 0000000..a5a73bc --- /dev/null +++ b/BaS_gcc/include/x86regs.h @@ -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 */ diff --git a/BaS_gcc/x86emu/biosemu.c b/BaS_gcc/x86emu/biosemu.c new file mode 100644 index 0000000..5cef33f --- /dev/null +++ b/BaS_gcc/x86emu/biosemu.c @@ -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> 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 */ +}