diff --git a/External/FEXCore/Source/Interface/Core/Frontend.cpp b/External/FEXCore/Source/Interface/Core/Frontend.cpp index fdf4ca2fd..23dcb1518 100644 --- a/External/FEXCore/Source/Interface/Core/Frontend.cpp +++ b/External/FEXCore/Source/Interface/Core/Frontend.cpp @@ -641,6 +641,30 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16 uint8_t EVEXOp = ReadByte(); return NormalOp(&EVEXTableOps[EVEXOp], EVEXOp); } + else if (Info->Type == FEXCore::X86Tables::TYPE_REX_PREFIX) { + LogMan::Throw::A(CTX->Config.Is64BitMode, "Got REX prefix in 32bit mode"); + DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX; + + // Widening displacement + if (Op & 0b1000) { + DecodeInst->Flags |= DecodeFlags::FLAG_REX_WIDENING; + DecodeInst->Flags = (DecodeInst->Flags & ~DecodeFlags::FLAG_OPADDR_MASK) | DecodeFlags::FLAG_WIDENING_SIZE_LAST; + } + + // XGPR_B bit set + if (Op & 0b0001) + DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_B; + + // XGPR_X bit set + if (Op & 0b0010) + DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_X; + + // XGPR_R bit set + if (Op & 0b0100) + DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_R; + + return false; + } return NormalOp(Info, Op); } @@ -649,13 +673,12 @@ bool Decoder::DecodeInstruction(uint64_t PC) { InstructionSize = 0; Instruction.fill(0); bool InstructionDecoded = false; - bool ErrorDuringDecoding = false; DecodeInst = &DecodedBuffer[DecodedSize]; memset(DecodeInst, 0, sizeof(DecodedInst)); DecodeInst->PC = PC; - while (!InstructionDecoded && !ErrorDuringDecoding) { + while (!InstructionDecoded) { uint8_t Op = ReadByte(); switch (Op) { case 0x0F: {// Escape Op @@ -777,49 +800,29 @@ bool Decoder::DecodeInstruction(uint64_t PC) { DecodeInst->Flags |= DecodeFlags::FLAG_ADDRESS_SIZE; break; case 0x26: // ES legacy prefix + if (!CTX->Config.Is64BitMode) { + DecodeInst->Flags |= DecodeFlags::FLAG_ES_PREFIX; + } + break; case 0x2E: // CS legacy prefix + if (!CTX->Config.Is64BitMode) { + DecodeInst->Flags |= DecodeFlags::FLAG_CS_PREFIX; + } + break; + case 0x36: // SS legacy prefix + if (!CTX->Config.Is64BitMode) { + DecodeInst->Flags |= DecodeFlags::FLAG_SS_PREFIX; + } + break; case 0x3E: // DS legacy prefix // Annoyingly GCC generates NOP ops with these prefixes // Just ignore them for now // eg. 66 2e 0f 1f 84 00 00 00 00 00 nop WORD PTR cs:[rax+rax*1+0x0] - break; - case 0x40: // REX - 0x40-0x4F - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: { - DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX; - - // Widening displacement - if (Op & 0b1000) { - DecodeInst->Flags |= DecodeFlags::FLAG_REX_WIDENING; - DecodeInst->Flags = (DecodeInst->Flags & ~DecodeFlags::FLAG_OPADDR_MASK) | DecodeFlags::FLAG_WIDENING_SIZE_LAST; + if (!CTX->Config.Is64BitMode) { + DecodeInst->Flags |= DecodeFlags::FLAG_DS_PREFIX; } - - // XGPR_B bit set - if (Op & 0b0001) - DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_B; - - // XGPR_X bit set - if (Op & 0b0010) - DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_X; - - // XGPR_R bit set - if (Op & 0b0100) - DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_R; + break; break; - } case 0xF0: // LOCK prefix DecodeInst->Flags |= DecodeFlags::FLAG_LOCK; break; @@ -841,16 +844,13 @@ bool Decoder::DecodeInstruction(uint64_t PC) { if (NormalOpHeader(&FEXCore::X86Tables::BaseOps[Op], Op)) { InstructionDecoded = true; } - else { - LogMan::Msg::E("Error during instruction decoding"); - ErrorDuringDecoding = true; - } break; } } } - return !ErrorDuringDecoding; + + return true; } void Decoder::BranchTargetInMultiblockRange() { diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 8e1437b4b..a38d5d6b8 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -6824,6 +6824,11 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0xFC, 2, &OpDispatchBuilder::FLAGControlOp}, }; + const std::vector> BaseOpTable_32 = { + {0x40, 8, &OpDispatchBuilder::INCOp}, + {0x48, 8, &OpDispatchBuilder::DECOp}, + }; + const std::vector> TwoByteOpTable = { // Instructions {0x00, 1, nullptr}, // GROUP 6 @@ -7750,6 +7755,9 @@ constexpr uint16_t PF_F2 = 3; }; InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable); + if (Mode == Context::MODE_32BIT) { + InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable_32); + } InstallToTable(FEXCore::X86Tables::SecondBaseOps, TwoByteOpTable); InstallToTable(FEXCore::X86Tables::PrimaryInstGroupOps, PrimaryGroupOpTable); diff --git a/External/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp b/External/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp index 9415aa7cc..dcf315d4e 100644 --- a/External/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp +++ b/External/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp @@ -9,22 +9,19 @@ void InitializeBaseTables(Context::OperatingMode Mode) { const U8U8InfoStruct BaseOpTable[] = { // Prefixes // Operand size overide - {0x66, 1, X86InstInfo{"", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, + {0x66, 1, X86InstInfo{"", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}}, // Address size override - {0x67, 1, X86InstInfo{"", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, - {0x2E, 1, X86InstInfo{"CS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, - {0x3E, 1, X86InstInfo{"DS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, + {0x67, 1, X86InstInfo{"", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}}, {0x26, 1, X86InstInfo{"ES", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, + {0x2E, 1, X86InstInfo{"CS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, + {0x36, 1, X86InstInfo{"SS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, + {0x3E, 1, X86InstInfo{"DS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, // These are still invalid on 64bit {0x64, 1, X86InstInfo{"FS", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}}, {0x65, 1, X86InstInfo{"GS", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}}, - {0x36, 1, X86InstInfo{"SS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, - {0xF0, 1, X86InstInfo{"LOCK", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, - {0xF2, 1, X86InstInfo{"REPNE", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, - {0xF3, 1, X86InstInfo{"REP", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}}, - - // REX - {0x40, 16, X86InstInfo{"", TYPE_REX_PREFIX, FLAGS_NONE, 0, nullptr}}, + {0xF0, 1, X86InstInfo{"LOCK", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}}, + {0xF2, 1, X86InstInfo{"REPNE", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}}, + {0xF3, 1, X86InstInfo{"REP", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}}, // Instructions {0x00, 1, X86InstInfo{"ADD", TYPE_INST, GenFlagsSameSize(SIZE_8BIT) | FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}}, @@ -135,9 +132,9 @@ void InitializeBaseTables(Context::OperatingMode Mode) { {0x89, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}}, {0x8A, 1, X86InstInfo{"MOV", TYPE_INST, GenFlagsSameSize(SIZE_8BIT) | FLAGS_MODRM, 0, nullptr}}, {0x8B, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_MODRM, 0, nullptr}}, - {0x8C, 1, X86InstInfo{"MOV", TYPE_INVALID, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}}, + {0x8C, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}}, {0x8D, 1, X86InstInfo{"LEA", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_MODRM, 0, nullptr}}, - {0x8E, 1, X86InstInfo{"MOV", TYPE_INVALID, FLAGS_MODRM, 0, nullptr}}, // MOV seg, modrM == invalid on x86-64 + {0x8E, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_MODRM, 0, nullptr}}, // MOV seg, modrM == invalid on x86-64 {0x8F, 1, X86InstInfo{"POP", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_MODRM | FLAGS_SF_MOD_DST | FLAGS_DEBUG_MEM_ACCESS, 0, nullptr}}, {0x90, 8, X86InstInfo{"XCHG", TYPE_INST, FLAGS_SF_REX_IN_BYTE | FLAGS_SF_SRC_RAX, 0, nullptr}}, {0x98, 1, X86InstInfo{"CDQE", TYPE_INST, FLAGS_SF_DST_RAX | FLAGS_SF_SRC_RAX, 0, nullptr}}, @@ -246,7 +243,24 @@ void InitializeBaseTables(Context::OperatingMode Mode) { {0xC4, 2, X86InstInfo{"", TYPE_VEX_TABLE_PREFIX, FLAGS_NONE, 0, nullptr}}, }; + const U8U8InfoStruct BaseOpTable_64[] = { + // REX + {0x40, 16, X86InstInfo{"", TYPE_REX_PREFIX, FLAGS_NONE, 0, nullptr}}, + }; + + const U8U8InfoStruct BaseOpTable_32[] = { + {0x40, 8, X86InstInfo{"INC", TYPE_INST, FLAGS_SF_REX_IN_BYTE, 0, nullptr}}, + {0x48, 8, X86InstInfo{"DEC", TYPE_INST, FLAGS_SF_REX_IN_BYTE, 0, nullptr}}, + }; + GenerateTable(BaseOps, BaseOpTable, sizeof(BaseOpTable) / sizeof(BaseOpTable[0])); + + if (Mode == Context::MODE_64BIT) { + GenerateTable(BaseOps, BaseOpTable_64, sizeof(BaseOpTable_64) / sizeof(BaseOpTable_64[0])); + } + else { + GenerateTable(BaseOps, BaseOpTable_32, sizeof(BaseOpTable_32) / sizeof(BaseOpTable_32[0])); + } } } diff --git a/External/FEXCore/include/FEXCore/Debug/X86Tables.h b/External/FEXCore/include/FEXCore/Debug/X86Tables.h index a6e9a05c9..05c12d748 100644 --- a/External/FEXCore/include/FEXCore/Debug/X86Tables.h +++ b/External/FEXCore/include/FEXCore/Debug/X86Tables.h @@ -28,12 +28,16 @@ constexpr uint32_t FLAG_REX_WIDENING = (1 << 7); constexpr uint32_t FLAG_REX_XGPR_B = (1 << 8); constexpr uint32_t FLAG_REX_XGPR_X = (1 << 9); constexpr uint32_t FLAG_REX_XGPR_R = (1 << 10); -constexpr uint32_t FLAG_FS_PREFIX = (1 << 11); -constexpr uint32_t FLAG_GS_PREFIX = (1 << 12); -constexpr uint32_t FLAG_REP_PREFIX = (1 << 13); -constexpr uint32_t FLAG_REPNE_PREFIX = (1 << 14); +constexpr uint32_t FLAG_ES_PREFIX = (1 << 11); +constexpr uint32_t FLAG_CS_PREFIX = (1 << 12); +constexpr uint32_t FLAG_SS_PREFIX = (1 << 13); +constexpr uint32_t FLAG_DS_PREFIX = (1 << 14); +constexpr uint32_t FLAG_FS_PREFIX = (1 << 15); +constexpr uint32_t FLAG_GS_PREFIX = (1 << 16); +constexpr uint32_t FLAG_REP_PREFIX = (1 << 17); +constexpr uint32_t FLAG_REPNE_PREFIX = (1 << 18); // Size flags -constexpr uint32_t FLAG_SIZE_DST_OFF = 15; +constexpr uint32_t FLAG_SIZE_DST_OFF = 19; constexpr uint32_t FLAG_SIZE_SRC_OFF = FLAG_SIZE_DST_OFF + 3; constexpr uint32_t SIZE_MASK = 0b111; constexpr uint32_t SIZE_DEF = 0b000; // This should be invalid past decoding diff --git a/Scripts/json_config_parse.py b/Scripts/json_config_parse.py index 95216a54c..bc508ff79 100644 --- a/Scripts/json_config_parse.py +++ b/Scripts/json_config_parse.py @@ -58,6 +58,10 @@ class ABI(Flag) : ABI_WIN64 = 1 ABI_NONE = 2 +class Mode(Flag) : + MODE_32 = 0 + MODE_64 = 1 + RegStringLookup = { "NONE": Regs.REG_NONE, "RAX": Regs.REG_RAX, @@ -114,11 +118,17 @@ ABIStringLookup = { "NONE": ABI.ABI_NONE, } +ModeStringLookup = { + "32BIT": Mode.MODE_32, + "64BIT": Mode.MODE_64, +} + def parse_json(json_text, output_file): # Default options OptionMatch = Regs.REG_INVALID OptionIgnore = Regs.REG_NONE OptionABI = ABI.ABI_SYSTEMV + OptionMode = Mode.MODE_64 OptionStackSize = 4096 OptionEntryPoint = 1 OptionRegData = {} @@ -164,6 +174,13 @@ def parse_json(json_text, output_file): sys.exit("Invalid ABI") OptionABI = ABIStringLookup[data] + if ("MODE" in json_object): + data = json_object["MODE"] + data = data.upper() + if not (data in ModeStringLookup): + sys.exit("Invalid Mode") + OptionMode = ModeStringLookup[data] + if ("STACKSIZE" in json_object): data = json_object["STACKSIZE"] OptionStackSize = int(data, 0) @@ -212,6 +229,7 @@ def parse_json(json_text, output_file): config_file.write(struct.pack('Q', OptionStackSize)) config_file.write(struct.pack('Q', OptionEntryPoint)) config_file.write(struct.pack('I', OptionABI.value)) + config_file.write(struct.pack('I', OptionMode.value)) # Number of memory regions config_file.write(struct.pack('I', len(OptionMemoryRegions))) diff --git a/Source/Tests/HarnessHelpers.h b/Source/Tests/HarnessHelpers.h index 8fd376eb5..4b02c6739 100644 --- a/Source/Tests/HarnessHelpers.h +++ b/Source/Tests/HarnessHelpers.h @@ -263,6 +263,8 @@ namespace FEX::HarnessHelper { return Matches; } + bool Is64BitMode() const { return BaseConfig.OptionMode == 1; } + private: FEX::Config::Value ConfigDumpGPRs{"DumpGPRs", false}; @@ -272,6 +274,7 @@ namespace FEX::HarnessHelper { uint64_t OptionStackSize; uint64_t OptionEntryPoint; uint32_t OptionABI; + uint32_t OptionMode; uint32_t OptionMemoryRegionCount; uint32_t OptionRegDataCount; uint8_t AdditionalData[]; @@ -366,6 +369,8 @@ namespace FEX::HarnessHelper { return Config.CompareStates(State1, State2); } + bool Is64BitMode() const { return Config.Is64BitMode(); } + private: constexpr static uint64_t STACK_SIZE = PAGE_SIZE; // Zero is special case to know when we are done diff --git a/Source/Tests/TestHarnessRunner.cpp b/Source/Tests/TestHarnessRunner.cpp index e5370b70c..870e072ec 100644 --- a/Source/Tests/TestHarnessRunner.cpp +++ b/Source/Tests/TestHarnessRunner.cpp @@ -69,21 +69,21 @@ int main(int argc, char **argv, char **const envp) { auto SHM = FEXCore::SHM::AllocateSHMRegion(1ULL << 34); auto CTX = FEXCore::Context::CreateNewContext(); + FEX::HarnessHelper::HarnessCodeLoader Loader{Args[0], Args[1].c_str()}; + FEXCore::Context::SetCustomCPUBackendFactory(CTX, VMFactory::CPUCreationFactory); FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_UNIFIED_MEMORY, 0); // ensure TestHarnessRunner doesn't enable UnifiedMemory. FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_DEFAULTCORE, CoreConfig() > 3 ? FEXCore::Config::CONFIG_CUSTOM : CoreConfig()); FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_MULTIBLOCK, MultiblockConfig()); FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_SINGLESTEP, SingleStepConfig()); FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_MAXBLOCKINST, BlockSizeConfig()); - FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, true); + FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode()); FEXCore::Context::SetCustomCPUBackendFactory(CTX, VMFactory::CPUCreationFactory); FEXCore::Context::AddGuestMemoryRegion(CTX, SHM); FEXCore::Context::InitializeContext(CTX); - FEX::HarnessHelper::HarnessCodeLoader Loader{Args[0], Args[1].c_str()}; - bool Result1 = FEXCore::Context::InitCore(CTX, &Loader); if (!Result1) diff --git a/unittests/ASM/CMakeLists.txt b/unittests/ASM/CMakeLists.txt index bc248c5d6..c35a976b5 100644 --- a/unittests/ASM/CMakeLists.txt +++ b/unittests/ASM/CMakeLists.txt @@ -25,6 +25,7 @@ foreach(ASM_SRC ${ASM_SOURCES}) add_custom_command(OUTPUT ${OUTPUT_CONFIG_NAME} DEPENDS "${ASM_SRC}" + DEPENDS "${CMAKE_SOURCE_DIR}/Scripts/json_asm_config_parse.py" COMMAND "python3" ARGS "${CMAKE_SOURCE_DIR}/Scripts/json_asm_config_parse.py" "${ASM_SRC}" "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_CONFIG_NAME}") list(APPEND ASM_DEPENDS "${OUTPUT_NAME};${OUTPUT_CONFIG_NAME}")