From 8258a4bfcb815a4c18d0bd06c4c85dc50dfa6872 Mon Sep 17 00:00:00 2001 From: Luke Usher Date: Sat, 8 Oct 2016 22:39:46 +0100 Subject: [PATCH] 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 --- src/CxbxKrnl/EmuX86.cpp | 196 ++++++++++++++++++++++++---------------- src/CxbxKrnl/EmuX86.h | 19 ++++ 2 files changed, 135 insertions(+), 80 deletions(-) diff --git a/src/CxbxKrnl/EmuX86.cpp b/src/CxbxKrnl/EmuX86.cpp index 27afa31ba..1d87a29b3 100644 --- a/src/CxbxKrnl/EmuX86.cpp +++ b/src/CxbxKrnl/EmuX86.cpp @@ -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; diff --git a/src/CxbxKrnl/EmuX86.h b/src/CxbxKrnl/EmuX86.h index 95ce1615a..9d30da906 100644 --- a/src/CxbxKrnl/EmuX86.h +++ b/src/CxbxKrnl/EmuX86.h @@ -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