From d16db4ebde1befa672798230cfaf5d7b8b5030eb Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 21 Mar 2022 21:28:35 -0700 Subject: [PATCH] OpcodeDispatcher: Fixes SIGILL on unsupported host instructions If the host doesn't support the instructions required for implementing an instruction then don't even add them to the opcodedispatcher. This means that we will never try emitting instructions that the host doesn't support (For these instructions anyway) and successfully passes the guest SIGILL for these particular instructions. Fixes #1631 --- .../Source/Interface/Core/HostFeatures.cpp | 10 ++ .../Interface/Core/OpcodeDispatcher.cpp | 110 ++++++++++++++---- .../Source/Interface/Core/OpcodeDispatcher.h | 2 + unittests/ASM/Disabled_Tests_x64 | 3 + 4 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 unittests/ASM/Disabled_Tests_x64 diff --git a/External/FEXCore/Source/Interface/Core/HostFeatures.cpp b/External/FEXCore/Source/Interface/Core/HostFeatures.cpp index dba07a84f..3555e9c21 100644 --- a/External/FEXCore/Source/Interface/Core/HostFeatures.cpp +++ b/External/FEXCore/Source/Interface/Core/HostFeatures.cpp @@ -84,6 +84,16 @@ HostFeatures::HostFeatures() { SupportsCRC = Features.has(Xbyak::util::Cpu::tSSE42); SupportsRAND = Features.has(Xbyak::util::Cpu::tRDRAND) && Features.has(Xbyak::util::Cpu::tRDSEED); + // xbyak doesn't know how to check for CLZero + uint32_t eax, ebx, ecx, edx; + // First ensure we support a new enough extended CPUID function range + __cpuid(0x8000'0000, eax, ebx, ecx, edx); + if (eax >= 0x8000'0008U) { + // CLZero defined in 8000_00008_EBX[bit 0] + __cpuid(0x8000'0008, eax, ebx, ecx, edx); + SupportsCLZERO = ebx & 1; + } + SupportsFlushInputsToZero = true; SupportsFloatExceptions = true; #else diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 22059a382..e5ee8237d 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -4888,6 +4888,7 @@ void OpDispatchBuilder::StoreResult(FEXCore::IR::RegisterClassType Class, FEXCor OpDispatchBuilder::OpDispatchBuilder(FEXCore::Context::Context *ctx) : CTX {ctx} { ResetWorkingList(); + InstallHostSpecificOpcodeHandlers(); } void OpDispatchBuilder::ResetWorkingList() { @@ -5233,6 +5234,91 @@ void OpDispatchBuilder::InvalidOp(OpcodeArgs) { #undef OpcodeArgs + +void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { + static bool Initialized = false; + if (!CTX || Initialized) { + // IRCompaction doesn't set a CTX and doesn't need this anyway + return; + } +#define OPD(prefix, opcode) (((prefix) << 8) | opcode) + constexpr uint16_t PF_38_66 = (1U << 0); + constexpr uint16_t PF_38_F2 = (1U << 1); + + constexpr std::tuple H0F38_AES[] = { + {OPD(PF_38_66, 0xDB), 1, &OpDispatchBuilder::AESImcOp}, + {OPD(PF_38_66, 0xDC), 1, &OpDispatchBuilder::AESEncOp}, + {OPD(PF_38_66, 0xDD), 1, &OpDispatchBuilder::AESEncLastOp}, + {OPD(PF_38_66, 0xDE), 1, &OpDispatchBuilder::AESDecOp}, + {OPD(PF_38_66, 0xDF), 1, &OpDispatchBuilder::AESDecLastOp}, + }; + constexpr std::tuple H0F38_CRC[] = { + {OPD(PF_38_F2, 0xF0), 1, &OpDispatchBuilder::CRC32}, + {OPD(PF_38_F2, 0xF1), 1, &OpDispatchBuilder::CRC32}, + + {OPD(PF_38_66 | PF_38_F2, 0xF0), 1, &OpDispatchBuilder::CRC32}, + {OPD(PF_38_66 | PF_38_F2, 0xF1), 1, &OpDispatchBuilder::CRC32}, + }; +#undef OPD + +#define OPD(REX, prefix, opcode) ((REX << 9) | (prefix << 8) | opcode) +#define PF_3A_NONE 0 +#define PF_3A_66 1 + constexpr std::tuple H0F3A_AES[] = { + {OPD(0, PF_3A_66, 0xDF), 1, &OpDispatchBuilder::AESKeyGenAssist}, + }; +#undef PF_3A_NONE +#undef PF_3A_66 +#undef OPD + +#define OPD(group, prefix, Reg) (((group - FEXCore::X86Tables::TYPE_GROUP_6) << 5) | (prefix) << 3 | (Reg)) + constexpr uint16_t PF_NONE = 0; + constexpr uint16_t PF_66 = 2; + + constexpr std::tuple SecondaryExtensionOp_RDRAND[] = { + // GROUP 9 + {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 6), 1, &OpDispatchBuilder::RDRANDOp}, + {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 7), 1, &OpDispatchBuilder::RDRANDOp}, + + {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 6), 1, &OpDispatchBuilder::RDRANDOp}, + {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 7), 1, &OpDispatchBuilder::RDRANDOp}, + }; +#undef OPD + + constexpr std::tuple SecondaryModRMExtensionOp_CLZero[] = { + {((3 << 3) | 4), 1, &OpDispatchBuilder::CLZeroOp}, + }; + + auto InstallToTable = [](auto& FinalTable, auto& LocalTable) { + for (auto Op : LocalTable) { + auto OpNum = std::get<0>(Op); + auto Dispatcher = std::get<2>(Op); + for (uint8_t i = 0; i < std::get<1>(Op); ++i) { + LOGMAN_THROW_A_FMT(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry"); + FinalTable[OpNum + i].OpcodeDispatcher = Dispatcher; + } + } + }; + + if (CTX->HostFeatures.SupportsCRC) { + InstallToTable(FEXCore::X86Tables::H0F38TableOps, H0F38_CRC); + } + + if (CTX->HostFeatures.SupportsAES) { + InstallToTable(FEXCore::X86Tables::H0F38TableOps, H0F38_AES); + InstallToTable(FEXCore::X86Tables::H0F3ATableOps, H0F3A_AES); + } + + if (CTX->HostFeatures.SupportsCLZERO) { + InstallToTable(FEXCore::X86Tables::SecondModRMTableOps, SecondaryModRMExtensionOp_CLZero); + } + + if (CTX->HostFeatures.SupportsRAND) { + InstallToTable(FEXCore::X86Tables::SecondInstGroupOps, SecondaryExtensionOp_RDRAND); + } + Initialized = true; +} + void InstallOpcodeHandlers(Context::OperatingMode Mode) { constexpr std::tuple BaseOpTable[] = { // Instructions @@ -5794,15 +5880,8 @@ constexpr uint16_t PF_F2 = 3; // GROUP 9 {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 1), 1, &OpDispatchBuilder::CMPXCHGPairOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 6), 1, &OpDispatchBuilder::RDRANDOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 7), 1, &OpDispatchBuilder::RDRANDOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_F3, 1), 1, &OpDispatchBuilder::CMPXCHGPairOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 1), 1, &OpDispatchBuilder::CMPXCHGPairOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 6), 1, &OpDispatchBuilder::RDRANDOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 7), 1, &OpDispatchBuilder::RDRANDOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_F2, 1), 1, &OpDispatchBuilder::CMPXCHGPairOp}, // GROUP 12 @@ -5868,7 +5947,6 @@ constexpr uint16_t PF_F2 = 3; // REG /7 {((3 << 3) | 1), 1, &OpDispatchBuilder::RDTSCPOp}, - {((3 << 3) | 4), 1, &OpDispatchBuilder::CLZeroOp}, }; // Top bit indicating if it needs to be repeated with {0x40, 0x80} or'd in @@ -6110,7 +6188,6 @@ constexpr uint16_t PF_F2 = 3; #define OPD(prefix, opcode) (((prefix) << 8) | opcode) constexpr uint16_t PF_38_NONE = 0; constexpr uint16_t PF_38_66 = (1U << 0); - constexpr uint16_t PF_38_F2 = (1U << 1); constexpr uint16_t PF_38_F3 = (1U << 2); constexpr std::tuple H0F38Table[] = { @@ -6176,24 +6253,13 @@ constexpr uint16_t PF_F2 = 3; {OPD(PF_38_66, 0x40), 1, &OpDispatchBuilder::VectorALUOp}, {OPD(PF_38_66, 0x41), 1, &OpDispatchBuilder::PHMINPOSUWOp}, - {OPD(PF_38_66, 0xDB), 1, &OpDispatchBuilder::AESImcOp}, - {OPD(PF_38_66, 0xDC), 1, &OpDispatchBuilder::AESEncOp}, - {OPD(PF_38_66, 0xDD), 1, &OpDispatchBuilder::AESEncLastOp}, - {OPD(PF_38_66, 0xDE), 1, &OpDispatchBuilder::AESDecOp}, - {OPD(PF_38_66, 0xDF), 1, &OpDispatchBuilder::AESDecLastOp}, - {OPD(PF_38_NONE, 0xF0), 2, &OpDispatchBuilder::MOVBEOp}, {OPD(PF_38_66, 0xF0), 2, &OpDispatchBuilder::MOVBEOp}, - {OPD(PF_38_F2, 0xF0), 1, &OpDispatchBuilder::CRC32}, - {OPD(PF_38_F2, 0xF1), 1, &OpDispatchBuilder::CRC32}, - - {OPD(PF_38_66 | PF_38_F2, 0xF0), 1, &OpDispatchBuilder::CRC32}, - {OPD(PF_38_66 | PF_38_F2, 0xF1), 1, &OpDispatchBuilder::CRC32}, - {OPD(PF_38_66, 0xF6), 1, &OpDispatchBuilder::ADXOp}, {OPD(PF_38_F3, 0xF6), 1, &OpDispatchBuilder::ADXOp}, }; + #undef OPD #define OPD(REX, prefix, opcode) ((REX << 9) | (prefix << 8) | opcode) @@ -6225,8 +6291,6 @@ constexpr uint16_t PF_F2 = 3; {OPD(0, PF_3A_66, 0x40), 1, &OpDispatchBuilder::DPPOp<4>}, {OPD(0, PF_3A_66, 0x41), 1, &OpDispatchBuilder::DPPOp<8>}, {OPD(0, PF_3A_66, 0x42), 1, &OpDispatchBuilder::MPSADBWOp}, - - {OPD(0, PF_3A_66, 0xDF), 1, &OpDispatchBuilder::AESKeyGenAssist}, }; #undef PF_3A_NONE #undef PF_3A_66 diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 4d679e5db..1682affda 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -1175,6 +1175,8 @@ private: else return _LoadMem(Class, Size, ssa0, Invalid(), Align, MEM_OFFSET_SXTX, 1); } + + void InstallHostSpecificOpcodeHandlers(); }; void InstallOpcodeHandlers(Context::OperatingMode Mode); diff --git a/unittests/ASM/Disabled_Tests_x64 b/unittests/ASM/Disabled_Tests_x64 new file mode 100644 index 000000000..36e42b872 --- /dev/null +++ b/unittests/ASM/Disabled_Tests_x64 @@ -0,0 +1,3 @@ +# Intel doesn't support CLZero, which the CI uses +Test_SecondaryModRM/Reg_7_4.asm +Test_SecondaryModRM/Reg_7_4_2.asm