Beginning of a real mode x86 emulator for BIOS calls.

svn path=/branches/ros-amd64-bringup/; revision=45464
This commit is contained in:
Timo Kreuzer 2010-02-06 19:13:54 +00:00
parent 6bfc56886a
commit b63bed2d38
8 changed files with 850 additions and 0 deletions

View file

@ -0,0 +1,12 @@
VOID
FORCEINLINE
Opcode_3D_CMP(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
USHORT Value;
Value = *(USHORT*)(IntructionPointer + 1);
VmState_CMP16(VmState, VmState->Registers.Eax, Value);
VmState_AdvanceIp(VmState, 3);
DPRINT("CMP AX, 0x%x\n", Value);
}

View file

@ -0,0 +1,39 @@
VOID
FORCEINLINE
Opcode_E9_JMP16(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
SHORT Offset;
Offset = *(PSHORT)(IntructionPointer + 1);
DPRINT("JMP %04x\n", VmState->Registers.Ip + Offset + 3);
VmState_AdvanceIp(VmState, Offset + 3);
}
VOID
FORCEINLINE
Opcode_75_JNZ8(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("JNZ %04x\n", VmState->Registers.Ip + IntructionPointer[1] + 2);
if (!VmState->Registers.Eflags.Zf)
{
VmState_AdvanceIp(VmState, IntructionPointer[1] + 2);
}
else
VmState_AdvanceIp(VmState, 2);
}
VOID
FORCEINLINE
Opcode_74_JZ8(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("JZ %04x\n", VmState->Registers.Ip + IntructionPointer[1] + 2);
if (VmState->Registers.Eflags.Zf)
{
VmState_AdvanceIp(VmState, IntructionPointer[1] + 2);
}
else
VmState_AdvanceIp(VmState, 2);
}

View file

@ -0,0 +1,45 @@
VOID
FORCEINLINE
Opcode_BB_MOV(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
USHORT Value;
Value = *(USHORT*)(IntructionPointer + 1);
VmState->Registers.Bx = Value;
VmState_AdvanceIp(VmState, 3);
DPRINT("MOV BX, 0x%x\n", Value);
}
VOID
FORCEINLINE
Opcode_8E_MOV(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
MODRM ModRm;
UCHAR Value;
ModRm.Byte = IntructionPointer[1];
if (ModRm.mod == 3)
{
DPRINT("MOV ??, ??\n", IntructionPointer[2]);
Value = VmState_GetVal8(VmState, ModRm);
// ...
VmState_AdvanceIp(VmState, 2);
return;
}
DPRINT1("UNKNOWN\n");
}
VOID
FORCEINLINE
Opcode_89_MOV(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
MODRM ModRm;
USHORT Value;
ModRm.Byte = IntructionPointer[1];
Value = VmState_GetRegVal16(VmState, ModRm);
VmState_AdvanceIp(VmState, 2);
}

View file

@ -0,0 +1,110 @@
VOID
FORCEINLINE
Opcode_9C_PUSHF(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("PUSHF\n");
VmState_Push(VmState, VmState->Registers.Eflags.Short);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_9D_POPF(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("POPF\n");
VmState->Registers.Eflags.Short = VmState_Pop(VmState);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_1E_PUSH_DS(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("PUSH DS\n");
VmState_Push(VmState, VmState->Registers.SegDs);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_1F_POP_DS(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("POP DS\n");
VmState->Registers.SegDs = VmState_Pop(VmState);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_06_PUSH_ES(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("PUSH ES\n");
VmState_Push(VmState, VmState->Registers.SegEs);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_07_POP_ES(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("POP ES\n");
VmState->Registers.SegEs = VmState_Pop(VmState);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_60_PUSHA(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
USHORT OrigSp;
DPRINT("PUSHA\n");
OrigSp = VmState->Registers.Sp;
VmState_Push(VmState, VmState->Registers.Ax);
VmState_Push(VmState, VmState->Registers.Cx);
VmState_Push(VmState, VmState->Registers.Dx);
VmState_Push(VmState, VmState->Registers.Bx);
VmState_Push(VmState, OrigSp);
VmState_Push(VmState, VmState->Registers.Bp);
VmState_Push(VmState, VmState->Registers.Si);
VmState_Push(VmState, VmState->Registers.Di);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_61_POPA(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
USHORT OrigSp;
DPRINT("POPA\n");
VmState->Registers.Di = VmState_Pop(VmState);
VmState->Registers.Si = VmState_Pop(VmState);
VmState->Registers.Bp = VmState_Pop(VmState);
OrigSp = VmState_Pop(VmState);
VmState->Registers.Bx = VmState_Pop(VmState);
VmState->Registers.Dx = VmState_Pop(VmState);
VmState->Registers.Cx = VmState_Pop(VmState);
VmState->Registers.Ax = VmState_Pop(VmState);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_55_PUSH_BP(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("PUSH BP\n");
VmState_Push(VmState, VmState->Registers.Bp);
VmState_AdvanceIp(VmState, 1);
}
VOID
FORCEINLINE
Opcode_xx_POP_BP(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
DPRINT("POP BP\n");
VmState->Registers.Bp = VmState_Pop(VmState);
VmState_AdvanceIp(VmState, 1);
}

View file

@ -0,0 +1,108 @@
UCHAR
FORCEINLINE
VmState_GetRegVal8(PX86_VM_STATE VmState, MODRM ModRm)
{
PUCHAR Pointer;
Pointer = (PUCHAR)&VmState->Registers + RegisterTable[0][ModRm.reg];
return *Pointer;
}
UCHAR
FORCEINLINE
VmState_GetRegVal16(PX86_VM_STATE VmState, MODRM ModRm)
{
return VmState->IndexedRegisters[ModRm.reg].Word;
}
VOID
FORCEINLINE
VmState_EnablePrefix(PX86_VM_STATE VmState, ULONG Prefix)
{
//DPRINT("_EnablePrefix\n");
}
VOID
FORCEINLINE
VmState_ClearPrefixes(PX86_VM_STATE VmState)
{
//DPRINT1("_ClearPrefixes\n");
}
FORCEINLINE
VOID
VmState_AdvanceIp(PX86_VM_STATE VmState, SHORT Advance)
{
VmState->Registers.Ip += Advance;
}
FORCEINLINE
VOID
VmState_SetIp(PX86_VM_STATE VmState, USHORT Value)
{
VmState->Registers.Ip = Value;
}
FORCEINLINE
PCHAR
VmState_GetIp(PX86_VM_STATE VmState)
{
return (PCHAR)VmState->MemBuffer +
VmState->Registers.ShiftedCs +
VmState->Registers.Eip;
}
FORCEINLINE
VOID
VmState_Push(PX86_VM_STATE VmState, USHORT Value)
{
PUSHORT StackPointer;
//DPRINT1("Pushing %x %x %x\n", Value, VmState->Registers.ShiftedSs, VmState->Registers.Sp);
StackPointer = (PVOID)((PCHAR)VmState->MemBuffer +
VmState->Registers.ShiftedSs +
VmState->Registers.Sp); // FIXME: overflow
*StackPointer = Value;
VmState->Registers.Sp--;
}
FORCEINLINE
USHORT
VmState_Pop(PX86_VM_STATE VmState)
{
PUSHORT StackPointer;
//DPRINT1("Popping %x\n", Value);
StackPointer = (PVOID)((PCHAR)VmState->MemBuffer +
VmState->Registers.ShiftedSs +
VmState->Registers.Sp);
VmState->Registers.Sp--;
return *StackPointer;
}
UCHAR
FORCEINLINE
VmState_GetVal8(PX86_VM_STATE VmState, MODRM ModRm)
{
return 0;
}
FORCEINLINE
VOID
VmState_CMP8(PX86_VM_STATE VmState, UCHAR Value1, UCHAR Value2)
{
VmState->Registers.Eflags.Zf = ((Value1 - Value2) == 0);
VmState->Registers.Eflags.Cf = ((Value1 - Value2) > Value1);
VmState->Registers.Eflags.Sf = ((CHAR)(Value1 - Value2) < 0);
VmState->Registers.Eflags.Of = ((CHAR)(Value1 - Value2) > (CHAR)Value1);
}
FORCEINLINE
VOID
VmState_CMP16(PX86_VM_STATE VmState, USHORT Value1, USHORT Value2)
{
VmState->Registers.Eflags.Zf = ((Value1 - Value2) == 0);
VmState->Registers.Eflags.Cf = ((Value1 - Value2) > Value1);
VmState->Registers.Eflags.Sf = ((SHORT)(Value1 - Value2) < 0);
VmState->Registers.Eflags.Of = ((SHORT)(Value1 - Value2) > (SHORT)Value1);
}

299
reactos/lib/x86emu/x86emu.c Normal file
View file

@ -0,0 +1,299 @@
/*
* PROJECT: x86 CPU emulator
* LICENSE: GPL, See COPYING in the top level directory
* FILE: lib/x86emu/x86emu.c
* PURPOSE:
* PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <x86emu.h>
//#define NDEBUG
#include <debug.h>
#undef DPRINT
#define DPRINT DbgPrint
/* GLOBALS *******************************************************************/
static const ULONG RegisterTable[3][8] =
{
{
FIELD_OFFSET(X86_REGISTERS, Al),
FIELD_OFFSET(X86_REGISTERS, Cl),
FIELD_OFFSET(X86_REGISTERS, Dl),
FIELD_OFFSET(X86_REGISTERS, Bl),
FIELD_OFFSET(X86_REGISTERS, Ah),
FIELD_OFFSET(X86_REGISTERS, Ch),
FIELD_OFFSET(X86_REGISTERS, Dh),
FIELD_OFFSET(X86_REGISTERS, Bh),
},
{
FIELD_OFFSET(X86_REGISTERS, Ax),
FIELD_OFFSET(X86_REGISTERS, Cx),
FIELD_OFFSET(X86_REGISTERS, Dx),
FIELD_OFFSET(X86_REGISTERS, Bx),
FIELD_OFFSET(X86_REGISTERS, Sp),
FIELD_OFFSET(X86_REGISTERS, Bp),
FIELD_OFFSET(X86_REGISTERS, Si),
FIELD_OFFSET(X86_REGISTERS, Di),
},
{
FIELD_OFFSET(X86_REGISTERS, Eax),
FIELD_OFFSET(X86_REGISTERS, Ecx),
FIELD_OFFSET(X86_REGISTERS, Edx),
FIELD_OFFSET(X86_REGISTERS, Ebx),
FIELD_OFFSET(X86_REGISTERS, Esp),
FIELD_OFFSET(X86_REGISTERS, Ebp),
FIELD_OFFSET(X86_REGISTERS, Esi),
FIELD_OFFSET(X86_REGISTERS, Edi),
}
};
/* INLINE FUNCTONS ***********************************************************/
#include "vmstate.h"
#include "op_cmp.h"
#include "op_stack.h"
#include "op_jump.h"
#include "op_mov.h"
VOID
FORCEINLINE
Opcode_E8_CALL16(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
SHORT Offset;
Offset = *(PSHORT)(IntructionPointer + 1) + 3;
DPRINT("CALL %x\n", VmState->Registers.Ip + Offset);
VmState_Push(VmState, VmState->Registers.Ip + 3);
VmState_AdvanceIp(VmState, Offset);
}
VOID
FORCEINLINE
Opcode_80(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
MODRM ModRm;
UCHAR Value;
ModRm.Byte = IntructionPointer[1];
if (ModRm.reg == 7)
{
/* We have an 8 bit CMP */
DPRINT("CMP ??. 0x%x\n", IntructionPointer[2]);
Value = VmState_GetVal8(VmState, ModRm);
VmState_CMP8(VmState, Value, IntructionPointer[2]);
VmState_AdvanceIp(VmState, 3);
return;
}
DPRINT1("UNKNOWN\n");
}
VOID
FORCEINLINE
Opcode_F3_REP(PX86_VM_STATE VmState, PCHAR IntructionPointer)
{
UCHAR ByteVal;
ByteVal = IntructionPointer[1];
switch (ByteVal)
{
case 0x6C: /* REP INSB */
case 0x6D: /* REP INSW/D */
case 0xAC: /* REP LODSB */
case 0xAD: /* REP LODSWDQ */
case 0xA4: /* REP MOVSB */
case 0xA5: /* REP MOVSW/D/Q */
case 0x6E: /* REP OUTSB */
case 0x6F: /* REP OUTSW/D */
case 0xAA: /* REP STOSB */
case 0xAB: /* REP STOSW/D/Q */
break;
}
}
VOID
NTAPI
x86Emulator(PX86_VM_STATE VmState)
{
PCHAR InstructionPointer;
UCHAR ByteVal;
// x86EmuInitializeState();
for (;;)
{
InstructionPointer = VmState_GetIp(VmState);
ByteVal = *InstructionPointer;
DPRINT("%04x:%04x %02x ", VmState->Registers.SegCs, VmState->Registers.Eip, ByteVal);
switch (ByteVal)
{
case 0x06: /* PUSH ES */
Opcode_06_PUSH_ES(VmState, InstructionPointer);
break;
case 0x07: /* POP ES */
Opcode_07_POP_ES(VmState, InstructionPointer);
break;
// case 0x14: /* ADC AL, imm8 */
// VmState_AdvanceIp(VmState, 2);
// break;
case 0x15: /* ADC AX, imm16 */
//_OpcodeADC16(&VmState->Registers.Al, WORD(&InstructionPointer[1]));
VmState_AdvanceIp(VmState, 3);
break;
case 0x1E: /* PUSH DS */
Opcode_1E_PUSH_DS(VmState, InstructionPointer);
break;
case 0x1F: /* POP DS */
Opcode_1F_POP_DS(VmState, InstructionPointer);
break;
case 0x26: /* Force ES segment */
case 0x2e: /* Force CS segment */
VmState_EnablePrefix(VmState, PREFIX_SEGMENT_CS);
VmState_AdvanceIp(VmState, 1);
continue;
case 0x36: /* Force SS segment */
VmState->Registers.ShiftedMs = VmState->Registers.ShiftedSs;
VmState_AdvanceIp(VmState, 1);
continue;
case 0x37: /* AAA */
case 0x3D: /* CMP (E)AX, imm16/32 */
Opcode_3D_CMP(VmState, InstructionPointer);
break;
case 0x3E: /* Force DS segment */
VmState->Registers.ShiftedMs = VmState->Registers.ShiftedDs;
VmState_AdvanceIp(VmState, 1);
continue;
case 0x3F: /* AAS */
VmState_AdvanceIp(VmState, 1);
break;
/* 0x40 ... 0x4F are REX prefixes */
case 0x55: /* PUSH BP */
Opcode_55_PUSH_BP(VmState, InstructionPointer);
break;
case 0x60: /* PUSHA */
Opcode_60_PUSHA(VmState, InstructionPointer);
break;
case 0x61: /* POPA */
Opcode_61_POPA(VmState, InstructionPointer);
break;
case 0x64: /* Force FS segment */
case 0x65: /* Force GS segment */
case 0x66: /* Operand size override */
VmState_EnablePrefix(VmState, PREFIX_SIZE_OVERRIDE);
VmState_AdvanceIp(VmState, 1);
continue;
case 0x67: /* Address size prefix */
VmState_EnablePrefix(VmState, PREFIX_ADDRESS_OVERRIDE);
VmState_AdvanceIp(VmState, 1);
continue;
case 0x74: /* JZ */
Opcode_74_JZ8(VmState, InstructionPointer);
break;
case 0x75: /* JNZ */
Opcode_75_JNZ8(VmState, InstructionPointer);
break;
case 0x80: /* ... */
Opcode_80(VmState, InstructionPointer);
break;
case 0x89: /* MOV regmem16, reg16 */
Opcode_89_MOV(VmState, InstructionPointer);
break;
case 0x8E: /* MOV seg, reg16 */
Opcode_8E_MOV(VmState, InstructionPointer);
break;
case 0x9C: /* PUSHF */
Opcode_9C_PUSHF(VmState, InstructionPointer);
break;
case 0x9D: /* POPF */
Opcode_9D_POPF(VmState, InstructionPointer);
break;
case 0xBB: /* MOV BX, imm16 */
Opcode_BB_MOV(VmState, InstructionPointer);
break;
case 0xCF: /* IRET */
DPRINT("IRET\n");
return;
case 0xD4: /* AAM */
/* Check for D4 0A */
case 0xD5: /* AAD */
/* Check for D5 0A */
case 0xE8:
Opcode_E8_CALL16(VmState, InstructionPointer);
break;
case 0xE9: /* JMP off16 */
Opcode_E9_JMP16(VmState, InstructionPointer);
break;
case 0xF0: /* LOCK (ignored) */
DPRINT("LOCK ");
VmState_AdvanceIp(VmState, 1);
continue;
case 0xF2: /* REPNZ/REPNE */
DPRINT("REPNE ");
VmState_EnablePrefix(VmState, PREFIX_REP);
VmState_AdvanceIp(VmState, 1);
continue;
case 0xF3: /* REP */
Opcode_F3_REP(VmState, InstructionPointer);
break;
default:
DPRINT("Unknown opcode 0x%x\n", ByteVal);
VmState_AdvanceIp(VmState, 1);
//x86EmuRaiseException(EXCEPTION_INVALID_OPCODE, ByteVal);
//return;
}
/* Clear prefixes and continue with next intruction */
VmState_ClearPrefixes(VmState);
//ResetMs:
VmState->Registers.ShiftedMs = VmState->Registers.ShiftedDs;
}
}

230
reactos/lib/x86emu/x86emu.h Normal file
View file

@ -0,0 +1,230 @@
#ifndef _X86EMU_H_
#define _X86EMU_H_
#include <ntifs.h>
#include <ntndk.h>
typedef union
{
USHORT Short;
ULONG Long;
struct
{
ULONG Cf:1;
ULONG Pf:1;
ULONG Af:1;
ULONG Zf:1;
ULONG Sf:1;
ULONG Tf:1;
ULONG If:1;
ULONG Df:1;
ULONG Of:1;
ULONG Iopl:3;
ULONG Nt:1;
ULONG Rf:1;
ULONG Vm:1;
ULONG Ac:1;
ULONG Vif:1;
ULONG Vip:1;
ULONG Id:1;
};
} EFLAGS;
typedef union
{
ULONG Dword;
USHORT Word;
UCHAR Byte;
struct
{
UCHAR Low;
UCHAR High;
};
} REGU;
typedef union
{
struct
{
UCHAR mod:2;
UCHAR reg:3;
UCHAR rm:3;
};
UCHAR Byte;
} MODRM;
typedef struct
{
union
{
ULONG Eax;
USHORT Ax;
struct
{
UCHAR Al;
UCHAR Ah;
};
};
union
{
ULONG Ecx;
USHORT Cx;
struct
{
UCHAR Cl;
UCHAR Ch;
};
};
union
{
ULONG Edx;
USHORT Dx;
struct
{
UCHAR Dl;
UCHAR Dh;
};
};
union
{
ULONG Ebx;
USHORT Bx;
struct
{
UCHAR Bl;
UCHAR Bh;
};
};
union
{
ULONG Ebp;
USHORT Bp;
};
union
{
ULONG Esi;
USHORT Si;
};
union
{
ULONG Edi;
USHORT Di;
};
union
{
struct
{
ULONG ReservedDsMBZ:4;
ULONG SegDs:16;
};
ULONG ShiftedDs;
};
union
{
struct
{
ULONG ReservedEsMBZ:4;
ULONG SegEs:16;
};
ULONG ShiftedEs;
};
/* Extended */
union
{
struct
{
ULONG ReservedCsMBZ:4;
ULONG SegCs:16;
};
ULONG ShiftedCs;
};
union
{
struct
{
ULONG ReservedSsMBZ:4;
ULONG SegSs:16;
};
ULONG ShiftedSs;
};
union
{
struct
{
ULONG ReservedMsMBZ:4;
ULONG SegMs:16;
};
ULONG ShiftedMs;
};
union
{
ULONG Eip;
USHORT Ip;
};
union
{
ULONG Esp;
USHORT Sp;
};
EFLAGS Eflags;
} X86_REGISTERS, *PX86_REGISTERS;
enum
{
X86_VMFLAGS_RETURN_ON_IRET = 1,
};
typedef struct
{
union
{
X86_BIOS_REGISTERS BiosRegisters;
X86_REGISTERS Registers;
REGU IndexedRegisters[8];
};
struct
{
ULONG ReturnOnIret:1;
} Flags;
PVOID MemBuffer;
#if 1
PCHAR Mnemonic;
PCHAR DstReg;
PCHAR SrcReg;
ULONG SrcEncodung;
ULONG DstEncoding;
ULONG Length;
#endif
} X86_VM_STATE, *PX86_VM_STATE;
enum
{
PREFIX_SIZE_OVERRIDE = 0x010001,
PREFIX_ADDRESS_OVERRIDE = 0x020002,
PREFIX_SEGMENT_CS = 0x040004,
PREFIX_SEGMENT_DS = 0x040008,
PREFIX_SEGMENT_ES = 0x040010,
PREFIX_SEGMNET_FS = 0x040020,
PREFIX_SEGMENT_GS = 0x040040,
PREFIX_SEGMENT_SS = 0x040080,
PREFIX_LOCK = 0x080100,
PREFIX_REP = 0x100200,
} PREFIX_STATE;
VOID
NTAPI
x86Emulator(PX86_VM_STATE VmState);
#endif

View file

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
<module name="x86emu" type="staticlibrary">
<define name="_X86BIOS_" />
<include base="x86emu">.</include>
<file>x86emu.c</file>
</module>