From 465395dede08bbcff03f1ef15de4e96f8ea4d12e Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 22 Oct 2026 15:29:16 -0700 Subject: [PATCH] OpcodeDispatcher: Implement SLDT Not 100% correct because the Linux kernel has some cheeky false data return value when an LDT gets installed. But FEX can't really do it properly today so whatever. --- .../Interface/Core/OpcodeDispatcher.cpp | 33 ++++++++++++++++++- .../Source/Interface/Core/OpcodeDispatcher.h | 1 + .../OpcodeDispatcher/SecondaryGroupTables.h | 5 +++ .../Core/X86Tables/SecondaryGroupTables.cpp | 8 ++--- FEXCore/include/FEXCore/Core/CoreState.h | 1 - 5 files changed, 42 insertions(+), 6 deletions(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 9a7494350..7e86e3703 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -3156,7 +3156,38 @@ void OpDispatchBuilder::SMSWOp(OpcodeArgs) { } if (IsMemDst) { - // Memory destinatino always writes only 16-bits. + // Memory destination always writes only 16-bits. + DstSize = OpSize::i16Bit; + } + + StoreResultGPR_WithOpSize(Op, Op->Dest, Const, DstSize); +} + +void OpDispatchBuilder::SLDTOp(OpcodeArgs) { + const bool IsMemDst = DestIsMem(Op); + + IR::OpSize DstSize {OpSize::iInvalid}; + Ref Const = _Constant(0); + + const auto OpAddr = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0); + if (Is64BitMode) { + DstSize = OpAddr == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? OpSize::i16Bit : + OpAddr == X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST ? OpSize::i64Bit : + OpSize::i32Bit; + + if (!IsMemDst && DstSize == OpSize::i32Bit) { + // Special-case version of `sldt ebx`. This instruction does an insert in to the lower 32-bits on 64-bit hosts. + // Override and insert. + auto Dest = LoadSourceGPR_WithOpSize(Op, Op->Dest, GetGPROpSize(), Op->Flags); + Const = _Bfi(OpSize::i64Bit, 32, 0, Dest, Const); + DstSize = OpSize::i64Bit; + } + } else { + DstSize = OpAddr == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? OpSize::i16Bit : OpSize::i32Bit; + } + + if (IsMemDst) { + // Memory destination always writes only 16-bits. DstSize = OpSize::i16Bit; } diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 5ff14c092..5b5307669 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -488,6 +488,7 @@ public: void SGDTOp(OpcodeArgs); void SIDTOp(OpcodeArgs); void SMSWOp(OpcodeArgs); + void SLDTOp(OpcodeArgs); enum class VectorOpType { MMX, diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/SecondaryGroupTables.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher/SecondaryGroupTables.h index 345b561be..ac26b3af6 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/SecondaryGroupTables.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/SecondaryGroupTables.h @@ -10,6 +10,11 @@ constexpr uint16_t PF_66 = 2; constexpr uint16_t PF_F2 = 3; constexpr DispatchTableEntry OpDispatch_SecondaryGroupTables[] = { // GROUP 6 + {OPD(FEXCore::X86Tables::TYPE_GROUP_6, PF_NONE, 0), 1, &OpDispatchBuilder::SLDTOp}, + {OPD(FEXCore::X86Tables::TYPE_GROUP_6, PF_F3, 0), 1, &OpDispatchBuilder::SLDTOp}, + {OPD(FEXCore::X86Tables::TYPE_GROUP_6, PF_66, 0), 1, &OpDispatchBuilder::SLDTOp}, + {OPD(FEXCore::X86Tables::TYPE_GROUP_6, PF_F2, 0), 1, &OpDispatchBuilder::SLDTOp}, + {OPD(FEXCore::X86Tables::TYPE_GROUP_6, PF_NONE, 3), 1, &OpDispatchBuilder::PermissionRestrictedOp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_6, PF_F3, 3), 1, &OpDispatchBuilder::PermissionRestrictedOp}, {OPD(FEXCore::X86Tables::TYPE_GROUP_6, PF_66, 3), 1, &OpDispatchBuilder::PermissionRestrictedOp}, diff --git a/FEXCore/Source/Interface/Core/X86Tables/SecondaryGroupTables.cpp b/FEXCore/Source/Interface/Core/X86Tables/SecondaryGroupTables.cpp index fed57fc7e..66096d5c8 100644 --- a/FEXCore/Source/Interface/Core/X86Tables/SecondaryGroupTables.cpp +++ b/FEXCore/Source/Interface/Core/X86Tables/SecondaryGroupTables.cpp @@ -61,7 +61,7 @@ constexpr std::array SecondInstGr // Pulls from other MODRM table // GROUP 6 - {OPD(TYPE_GROUP_6, PF_NONE, 0), 1, X86InstInfo{"SLDT", TYPE_UNDEC, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, + {OPD(TYPE_GROUP_6, PF_NONE, 0), 1, X86InstInfo{"SLDT", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, {OPD(TYPE_GROUP_6, PF_NONE, 1), 1, X86InstInfo{"STR", TYPE_PRIV, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, {OPD(TYPE_GROUP_6, PF_NONE, 2), 1, X86InstInfo{"LLDT", TYPE_PRIV, FLAGS_NONE, 0}}, {OPD(TYPE_GROUP_6, PF_NONE, 3), 1, X86InstInfo{"LTR", TYPE_INST, FLAGS_NONE, 0}}, @@ -70,7 +70,7 @@ constexpr std::array SecondInstGr {OPD(TYPE_GROUP_6, PF_NONE, 6), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}}, {OPD(TYPE_GROUP_6, PF_NONE, 7), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}}, - {OPD(TYPE_GROUP_6, PF_F3, 0), 1, X86InstInfo{"SLDT", TYPE_UNDEC, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, + {OPD(TYPE_GROUP_6, PF_F3, 0), 1, X86InstInfo{"SLDT", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, {OPD(TYPE_GROUP_6, PF_F3, 1), 1, X86InstInfo{"STR", TYPE_PRIV, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, {OPD(TYPE_GROUP_6, PF_F3, 2), 1, X86InstInfo{"LLDT", TYPE_PRIV, FLAGS_NONE, 0}}, {OPD(TYPE_GROUP_6, PF_F3, 3), 1, X86InstInfo{"LTR", TYPE_INST, FLAGS_NONE, 0}}, @@ -79,7 +79,7 @@ constexpr std::array SecondInstGr {OPD(TYPE_GROUP_6, PF_F3, 6), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}}, {OPD(TYPE_GROUP_6, PF_F3, 7), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}}, - {OPD(TYPE_GROUP_6, PF_66, 0), 1, X86InstInfo{"SLDT", TYPE_UNDEC, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, + {OPD(TYPE_GROUP_6, PF_66, 0), 1, X86InstInfo{"SLDT", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, {OPD(TYPE_GROUP_6, PF_66, 1), 1, X86InstInfo{"STR", TYPE_PRIV, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, {OPD(TYPE_GROUP_6, PF_66, 2), 1, X86InstInfo{"LLDT", TYPE_PRIV, FLAGS_NONE, 0}}, {OPD(TYPE_GROUP_6, PF_66, 3), 1, X86InstInfo{"LTR", TYPE_INST, FLAGS_NONE, 0}}, @@ -88,7 +88,7 @@ constexpr std::array SecondInstGr {OPD(TYPE_GROUP_6, PF_66, 6), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}}, {OPD(TYPE_GROUP_6, PF_66, 7), 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0}}, - {OPD(TYPE_GROUP_6, PF_F2, 0), 1, X86InstInfo{"SLDT", TYPE_UNDEC, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, + {OPD(TYPE_GROUP_6, PF_F2, 0), 1, X86InstInfo{"SLDT", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, {OPD(TYPE_GROUP_6, PF_F2, 1), 1, X86InstInfo{"STR", TYPE_PRIV, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0}}, {OPD(TYPE_GROUP_6, PF_F2, 2), 1, X86InstInfo{"LLDT", TYPE_PRIV, FLAGS_NONE, 0}}, {OPD(TYPE_GROUP_6, PF_F2, 3), 1, X86InstInfo{"LTR", TYPE_INST, FLAGS_NONE, 0}}, diff --git a/FEXCore/include/FEXCore/Core/CoreState.h b/FEXCore/include/FEXCore/Core/CoreState.h index 2b1e029e1..f17084113 100644 --- a/FEXCore/include/FEXCore/Core/CoreState.h +++ b/FEXCore/include/FEXCore/Core/CoreState.h @@ -247,7 +247,6 @@ struct alignas(64) CPUState { // Follows encoding of the TI bit in segment selector encoding. constexpr static uint32_t SEGMENT_ARRAY_INDEX_GDT = 0; constexpr static uint32_t SEGMENT_ARRAY_INDEX_LDT = 1; - Core::CPUState::gdt_segment private_gdt[32] {}; }; static_assert(std::is_trivially_copyable_v, "Needs to be trivial"); static_assert(std::is_standard_layout_v, "This needs to be standard layout");