EmuX86: MOV now works with most operand types

EmuX86: TEST has been implemented for REGISTER, IMMEDIATE addressing mode

Most tiles now hang polling NV2A memory space, looks like it's time to start implementing that
This commit is contained in:
Luke Usher 2016-10-08 22:39:46 +01:00
parent c9b02799b7
commit 8258a4bfcb
2 changed files with 135 additions and 80 deletions

View File

@ -61,44 +61,70 @@ void EmuX86_Write32(uint32_t addr, uint32_t value)
EmuWarning("EmuX86_Write32: Unknown Write Address %08X", addr);
}
bool EmuX86_GetRegisterValue(uint32_t* output, LPEXCEPTION_POINTERS e, Zydis::Register reg)
{
uint32_t value = 0;
switch (reg) {
case Zydis::Register::EAX:
value = e->ContextRecord->Eax;
break;
case Zydis::Register::EBX:
value = e->ContextRecord->Ebx;
break;
case Zydis::Register::ECX:
value = e->ContextRecord->Ecx;
break;
case Zydis::Register::EDX:
value = e->ContextRecord->Edx;
break;
case Zydis::Register::EDI:
value = e->ContextRecord->Edi;
break;
case Zydis::Register::ESI:
value = e->ContextRecord->Esi;
break;
case Zydis::Register::NONE:
value = 0;
break;
default:
return false;
}
*output = value;
return true;
}
DWORD* EmuX86_GetRegisterPointer(LPEXCEPTION_POINTERS e, Zydis::Register reg)
{
switch (reg) {
case Zydis::Register::EAX:
return &e->ContextRecord->Eax;
case Zydis::Register::EBX:
return &e->ContextRecord->Ebx;
case Zydis::Register::ECX:
return &e->ContextRecord->Ecx;
case Zydis::Register::EDX:
return &e->ContextRecord->Edx;
case Zydis::Register::EDI:
return &e->ContextRecord->Edi;
case Zydis::Register::ESI:
return &e->ContextRecord->Esi;
}
return nullptr;
}
bool EmuX86_DecodeMemoryOperand(uint32_t* output, LPEXCEPTION_POINTERS e, Zydis::OperandInfo& operand)
{
uint32_t base = 0;
uint32_t index = 0;
switch (operand.base) {
case Zydis::Register::EAX:
base = e->ContextRecord->Eax;
break;
case Zydis::Register::EBX:
base = e->ContextRecord->Ebx;
break;
case Zydis::Register::ECX:
base = e->ContextRecord->Ecx;
break;
case Zydis::Register::EDX:
base = e->ContextRecord->Edx;
break;
case Zydis::Register::NONE:
break;
default:
return false;
if (!EmuX86_GetRegisterValue(&base, e, operand.base) || !EmuX86_GetRegisterValue(&index, e, operand.base)) {
return false;
}
switch (operand.index) {
case Zydis::Register::EDI:
index = e->ContextRecord->Edi;
break;
case Zydis::Register::ESI:
index = e->ContextRecord->Esi;
break;
case Zydis::Register::NONE:
break;
default:
return false;
}
*output = base + index + operand.lval.udword;
*output = base + (index * operand.scale) + operand.lval.udword;
return true;
}
@ -109,27 +135,9 @@ bool EmuX86_MOV(LPEXCEPTION_POINTERS e, Zydis::InstructionInfo& info)
DWORD* pDstReg = nullptr;
uint32_t srcAddr = 0;
switch (info.operand[0].base) {
case Zydis::Register::EAX:
pDstReg = &e->ContextRecord->Eax;
break;
case Zydis::Register::EBX:
pDstReg = &e->ContextRecord->Ebx;
break;
case Zydis::Register::ECX:
pDstReg = &e->ContextRecord->Ecx;
break;
case Zydis::Register::EDX:
pDstReg = &e->ContextRecord->Edx;
break;
case Zydis::Register::EDI:
pDstReg = &e->ContextRecord->Edi;
break;
case Zydis::Register::ESI:
pDstReg = &e->ContextRecord->Esi;
break;
default:
return false;
pDstReg = EmuX86_GetRegisterPointer(e, info.operand[0].base);
if (pDstReg == nullptr) {
return false;
}
if (!EmuX86_DecodeMemoryOperand(&srcAddr, e, info.operand[1])) {
@ -147,27 +155,8 @@ bool EmuX86_MOV(LPEXCEPTION_POINTERS e, Zydis::InstructionInfo& info)
return false;
}
switch (info.operand[1].base) {
case Zydis::Register::EAX:
value = e->ContextRecord->Eax;
break;
case Zydis::Register::EBX:
value = e->ContextRecord->Ebx;
break;
case Zydis::Register::ECX:
value = e->ContextRecord->Ecx;
break;
case Zydis::Register::EDX:
value = e->ContextRecord->Edx;
break;
case Zydis::Register::EDI:
value = e->ContextRecord->Edi;
break;
case Zydis::Register::ESI:
value = e->ContextRecord->Esi;
break;
default:
return false;
if (!EmuX86_GetRegisterValue(&value, e, info.operand[1].base)) {
return false;
}
EmuX86_Write32(addr, value);
@ -177,13 +166,50 @@ bool EmuX86_MOV(LPEXCEPTION_POINTERS e, Zydis::InstructionInfo& info)
{
uint32_t addr = 0;
if (!EmuX86_DecodeMemoryOperand(&addr, e, info.operand[1])) {
if (!EmuX86_DecodeMemoryOperand(&addr, e, info.operand[0])) {
return false;
}
EmuX86_Write32(addr, info.operand[1].lval.udword);
return true;
}
return false;
}
void EmuX86_SetFlag(LPEXCEPTION_POINTERS e, int flag, int value)
{
e->ContextRecord->EFlags ^= (-value ^ e->ContextRecord->EFlags) & (1 << flag);
}
bool EmuX86_TEST(LPEXCEPTION_POINTERS e, Zydis::InstructionInfo& info)
{
if (info.operand[0].type == Zydis::OperandType::MEMORY && info.operand[1].type == Zydis::OperandType::IMMEDIATE)
{
uint32_t addr = 0;
if (!EmuX86_DecodeMemoryOperand(&addr, e, info.operand[0])) {
return false;
}
uint32_t value = EmuX86_Read32(addr);
// Perform bitwise AND
uint32_t result = value & info.operand[1].lval.udword;
// Set CF/OF to 0
EmuX86_SetFlag(e, EMUX86_EFLAG_CF, 0);
EmuX86_SetFlag(e, EMUX86_EFLAG_OF, 0);
EmuX86_SetFlag(e, EMUX86_EFLAG_SF, result >> 31);
EmuX86_SetFlag(e, EMUX86_EFLAG_ZF, result == 0 ? 1 : 0);
// TODO: Parity Flag
return true;
}
return false;
}
bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
@ -210,22 +236,32 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
}
else
{
DbgPrintf("EmuX86: 0x%08X: %s\n", e->ContextRecord->Eip, formatter.formatInstruction(info));
switch (info.mnemonic)
{
case Zydis::InstructionMnemonic::MOV:
if (EmuX86_MOV(e, info)) {
break;
}
default:
EmuWarning("EmuX86: 0x%08X: %s Not Implemented\n", e->ContextRecord->Eip, formatter.formatInstruction(info));
e->ContextRecord->Eip += info.length;
return false;
goto unimplemented_opcode;
case Zydis::InstructionMnemonic::TEST:
if (EmuX86_TEST(e, info)) {
break;
}
goto unimplemented_opcode;
case Zydis::InstructionMnemonic::WBINVD:
// We can safely ignore this
break;
}
e->ContextRecord->Eip += info.length;
return true;
unimplemented_opcode:
EmuWarning("EmuX86: 0x%08X: %s Not Implemented\n", e->ContextRecord->Eip, formatter.formatInstruction(info));
e->ContextRecord->Eip += info.length;
return false;
}
return false;

View File

@ -34,6 +34,25 @@
#ifndef EMUX86_H
#define EMUX86_H
#define EMUX86_EFLAG_CF 0
#define EMUX86_EFLAG_PF 2
#define EMUX86_EFLAG_AF 4
#define EMUX86_EFLAG_ZF 6
#define EMUX86_EFLAG_SF 7
#define EMUX86_EFLAG_TF 8
#define EMUX86_EFLAG_IF 9
#define EMUX86_EFLAG_DF 10
#define EMUX86_EFLAG_OF 11
#define EMUX86_EFLAG_IOPL1 12
#define EMUX86_EFLAG_IOPL2 13
#define EMUX86_EFLAG_NT 14
#define EMUX86_EFLAG_RF 16
#define EMUX86_EFLAG_VM 17
#define EMUX86_EFLAG_AC 18
#define EMUX86_EFLAG_VIF 19
#define EMUX86_EFLAG_VIP 20
#define EMUX86_EFLAG_ID 21
bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e);
#endif