306 lines
6.8 KiB
C
306 lines
6.8 KiB
C
/*
|
|
* Copyright 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.
|
|
*/
|
|
#include "debug.h"
|
|
|
|
#define IF_MASK 0x00000200
|
|
#define VIF_MASK 0x00080000 /* virtual interrupt flag */
|
|
#define VIP_MASK 0x00100000 /* virtual interrupt pending */
|
|
|
|
#include </usr/include/unistd.h>
|
|
#include <errno.h>
|
|
#include <asm/unistd.h>
|
|
/*#include <syscall-list.h> */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#ifdef __alpha__
|
|
#include <sys/io.h>
|
|
#endif
|
|
#include <signal.h>
|
|
#include <setjmp.h>
|
|
#include "AsmMacros.h"
|
|
#include "v86bios.h"
|
|
# define DEBUG
|
|
#include "x86emu.h"
|
|
#undef DEBUG
|
|
|
|
#define M _X86EMU_env
|
|
#define CPU_REG(reg) M.x86.R_##reg
|
|
|
|
struct pio P;
|
|
|
|
void
|
|
setup_io(void)
|
|
{
|
|
if (!Config.PrintPort && !Config.IoStatistics) {
|
|
|
|
#if defined (__i386__)
|
|
P.inb = (u8(*)(u16))inb;
|
|
P.inw = (u16(*)(u16))inw;
|
|
P.outb = (void(*)(u16,u8))outb;
|
|
P.outw = (void(*)(u16,u16))outw;
|
|
#else
|
|
P.inb = p_inb;
|
|
P.inw = p_inw;
|
|
P.outb = p_outb;
|
|
P.outw = p_outw;
|
|
#endif
|
|
#if defined (__i386__) && ! defined(NEED_PCI_IO)
|
|
P.inl = (u32(*)(u16))inl;
|
|
P.outl = (void(*)(u16,u32))outl;
|
|
#else
|
|
P.inl = p_inl;
|
|
P.outl = p_outl;
|
|
#endif
|
|
} else {
|
|
P.inb = p_inb;
|
|
P.inw = p_inw;
|
|
P.inl = p_inl;
|
|
P.outb = p_outb;
|
|
P.outw = p_outw;
|
|
P.outl = p_outl;
|
|
}
|
|
}
|
|
|
|
void
|
|
x86emu_do_int(int num)
|
|
{
|
|
struct regs86 regs;
|
|
|
|
i_printf("int 0x%x received: ax:0x%x",num,CPU_REG(AX));
|
|
if (Config.PrintIp)
|
|
i_printf(" at: 0x%x\n",getIP());
|
|
else
|
|
i_printf("\n");
|
|
|
|
/* try to run bios interrupt */
|
|
|
|
/* if not installed fall back */
|
|
#define COPY(x,y) regs.y = M.x86.x
|
|
#define COPY_R(x,y) M.x86.x = regs.y
|
|
|
|
COPY(R_EAX,eax);
|
|
COPY(R_EBX,ebx);
|
|
COPY(R_ECX,ecx);
|
|
COPY(R_EDX,edx);
|
|
COPY(R_ESI,esi);
|
|
COPY(R_EDI,edi);
|
|
COPY(R_EBP,ebp);
|
|
COPY(R_EIP,eip);
|
|
COPY(R_ESP,esp);
|
|
COPY(R_CS,cs);
|
|
COPY(R_SS,ss);
|
|
COPY(R_DS,ds);
|
|
COPY(R_ES,es);
|
|
COPY(R_FS,fs);
|
|
COPY(R_GS,gs);
|
|
COPY(R_EFLG,eflags);
|
|
|
|
if (!(int_handler(num,®s))) {
|
|
if (!run_bios_int(num,®s))
|
|
goto unknown_int;
|
|
else
|
|
return;
|
|
}
|
|
|
|
COPY_R(R_EAX,eax);
|
|
COPY_R(R_EBX,ebx);
|
|
COPY_R(R_ECX,ecx);
|
|
COPY_R(R_EDX,edx);
|
|
COPY_R(R_ESI,esi);
|
|
COPY_R(R_EDI,edi);
|
|
COPY_R(R_EBP,ebp);
|
|
COPY_R(R_EIP,eip);
|
|
COPY_R(R_ESP,esp);
|
|
COPY_R(R_CS,cs);
|
|
COPY_R(R_SS,ss);
|
|
COPY_R(R_DS,ds);
|
|
COPY_R(R_ES,es);
|
|
COPY_R(R_FS,fs);
|
|
COPY_R(R_GS,gs);
|
|
COPY_R(R_EFLG,eflags);
|
|
return;
|
|
|
|
unknown_int:
|
|
fprintf(stderr,"\nUnknown vm86_int: %X\n\n",num);
|
|
X86EMU_halt_sys();
|
|
return;
|
|
|
|
#undef COPY
|
|
#undef COPY_R
|
|
}
|
|
|
|
void
|
|
setup_x86emu(unsigned long bios_start, i86biosRegsPtr regs)
|
|
{
|
|
int i;
|
|
CARD32 eip;
|
|
CARD16 cs;
|
|
X86EMU_intrFuncs intFuncs[256];
|
|
|
|
X86EMU_pioFuncs pioFuncs = {
|
|
(u8(*)(u16))P.inb,
|
|
(u16(*)(u16))P.inw,
|
|
(u32(*)(u16))P.inl,
|
|
(void(*)(u16,u8))P.outb,
|
|
(void(*)(u16,u16))P.outw,
|
|
(void(*)(u16,u32))P.outl
|
|
};
|
|
#ifdef __alpha__
|
|
X86EMU_memFuncs memFuncs = {
|
|
(u8(*)(u32))mem_rb,
|
|
(u16(*)(u32))mem_rw,
|
|
(u32(*)(u32))mem_rl,
|
|
(void(*)(u32,u8))mem_wb,
|
|
(void(*)(u32,u16))mem_ww,
|
|
(void(*)(u32,u32))mem_wl
|
|
};
|
|
#endif
|
|
M.mem_base = 0;
|
|
M.mem_size = 1024*1024 + 1024;
|
|
/* M.x86.debug = DEBUG_DISASSEMBLE_F | DEBUG_TRACE_F | DEBUG_DECODE_F; */
|
|
/* M.x86.debug |= DEBUG_DECODE_F | DEBUG_TRACE_F; */
|
|
/*
|
|
* For single step tracing compile x86emu with option -DDEBUG
|
|
*/
|
|
M.x86.debug = 0;
|
|
if (Config.PrintIp)
|
|
M.x86.debug = DEBUG_SAVE_CS_IP;
|
|
|
|
if (Config.Trace)
|
|
X86EMU_trace_on();
|
|
|
|
X86EMU_setupPioFuncs(&pioFuncs);
|
|
#ifdef __alpha__
|
|
X86EMU_setupMemFuncs(&memFuncs);
|
|
#endif
|
|
for (i=0;i<256;i++)
|
|
intFuncs[i] = x86emu_do_int;
|
|
X86EMU_setupIntrFuncs(intFuncs);
|
|
|
|
eip = bios_start & 0xFFFF;
|
|
cs = (bios_start & 0xFF0000) >> 4;
|
|
|
|
CPU_REG(EAX) = regs->ax;
|
|
CPU_REG(EBX) = regs->bx;
|
|
CPU_REG(ECX) = regs->cx;
|
|
CPU_REG(EDX) = regs->dx;
|
|
CPU_REG(ESI) = regs->si;
|
|
CPU_REG(EDI) = regs->di;
|
|
CPU_REG(EBP) = 0;
|
|
CPU_REG(EIP) = eip;
|
|
CPU_REG(CS) = cs;
|
|
CPU_REG(SP) = 0x100;
|
|
CPU_REG(SS) = 0x30; /* This is the standard pc bios stack */
|
|
CPU_REG(ES) = regs->es;
|
|
CPU_REG(DS) = regs->ds;
|
|
CPU_REG(FS) = 0;
|
|
CPU_REG(GS) = 0;
|
|
CPU_REG(EFLG) |= (VIF_MASK | VIP_MASK | IF_MASK | 0x2);
|
|
}
|
|
|
|
void
|
|
collect_bios_regs(i86biosRegsPtr regs)
|
|
{
|
|
regs->ax = CPU_REG(EAX);
|
|
regs->bx = CPU_REG(EBX);
|
|
regs->cx = CPU_REG(ECX);
|
|
regs->dx = CPU_REG(EDX);
|
|
regs->es = CPU_REG(ES);
|
|
regs->ds = CPU_REG(DS);
|
|
regs->di = CPU_REG(EDI);
|
|
regs->si = CPU_REG(ESI);
|
|
}
|
|
|
|
static void
|
|
do_x86emu(void)
|
|
{
|
|
X86EMU_exec();
|
|
}
|
|
|
|
static jmp_buf x86_esc;
|
|
static void
|
|
vmexit(int unused)
|
|
{
|
|
longjmp(x86_esc,1);
|
|
}
|
|
|
|
void
|
|
do_x86(unsigned long bios_start, i86biosRegsPtr regs)
|
|
{
|
|
static void (*org_handler)(int);
|
|
|
|
setup_x86emu(bios_start,regs);
|
|
if (setjmp(x86_esc) == 0) {
|
|
org_handler = signal(2,vmexit);
|
|
do_x86emu();
|
|
signal(2,org_handler);
|
|
collect_bios_regs(regs);
|
|
} else {
|
|
signal(2,org_handler);
|
|
printf("interrupted at 0x%x\n",((CARD16)CPU_REG(CS)) << 4
|
|
| (CARD16)CPU_REG(EIP));
|
|
}
|
|
}
|
|
|
|
int
|
|
run_bios_int(int num, struct regs86 *regs)
|
|
{
|
|
#ifdef V86BIOS_DEBUG
|
|
static int firsttime = 1;
|
|
#endif
|
|
/* check if bios vector is initialized */
|
|
if (((CARD16*)0)[(num<<1)+1] == 0x0000) { /* SYS_BIOS_SEG ?*/
|
|
#ifdef V86BIOS_DEBUG
|
|
i_printf("card BIOS not loaded\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#ifdef V86BIOS_DEBUG
|
|
if (firsttime) {
|
|
dprint(0,0x3D0);
|
|
firsttime = 0;
|
|
}
|
|
#endif
|
|
|
|
i_printf("calling card BIOS at: ");
|
|
i_printf("0x%x:%x\n",((CARD16 *) 0)[(num << 1) + 1],
|
|
(CARD32)((CARD16 *) 0)[num << 1]);
|
|
X86EMU_prepareForInt(num);
|
|
|
|
return 1;
|
|
}
|
|
|
|
CARD32
|
|
getIntVect(int num)
|
|
{
|
|
return ((CARD32*)0)[num];
|
|
}
|
|
|
|
CARD32
|
|
getIP(void)
|
|
{
|
|
return (M.x86.saved_cs << 4) + M.x86.saved_ip;
|
|
}
|