diff options
author | Andreas Kling <kling@serenityos.org> | 2020-07-18 00:10:21 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-18 00:25:02 +0200 |
commit | 485d1faf09fcadd3f9830ea18e585076ce7eb2d6 (patch) | |
tree | bdd818b86449381039beac886459447ffedbee01 /DevTools/UserspaceEmulator | |
parent | 28b6ba56aa5115efc127068fbf5839f06149c5e7 (diff) | |
download | serenity-485d1faf09fcadd3f9830ea18e585076ce7eb2d6.zip |
UserspaceEmulator: Add helpers for making loop instructions generic
Use them to implement CMPSB/CMPSW/CMPSD.
Diffstat (limited to 'DevTools/UserspaceEmulator')
-rw-r--r-- | DevTools/UserspaceEmulator/SoftCPU.cpp | 48 | ||||
-rw-r--r-- | DevTools/UserspaceEmulator/SoftCPU.h | 112 |
2 files changed, 138 insertions, 22 deletions
diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp index 270dbb7c66..4e2d6bc817 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -195,23 +195,9 @@ void SoftCPU::do_once_or_repeat(const X86::Instruction& insn, Callback callback) if (!insn.has_rep_prefix()) return callback(); - if (insn.has_address_size_override_prefix()) { - while (cx()) { - callback(); - set_cx(cx() - 1); - if constexpr (check_zf) { - if (insn.rep_prefix() == X86::Prefix::REPZ && !zf()) - break; - if (insn.rep_prefix() == X86::Prefix::REPNZ && zf()) - break; - } - } - return; - } - - while (ecx()) { + while (loop_index(insn.a32())) { callback(); - set_ecx(ecx() - 1); + decrement_loop_index(insn.a32()); if constexpr (check_zf) { if (insn.rep_prefix() == X86::Prefix::REPZ && !zf()) break; @@ -1057,9 +1043,33 @@ void SoftCPU::CMOVcc_reg32_RM32(const X86::Instruction& insn) gpr32(insn.reg32()) = insn.modrm().read32(*this, insn); } -void SoftCPU::CMPSB(const X86::Instruction&) { TODO(); } -void SoftCPU::CMPSD(const X86::Instruction&) { TODO(); } -void SoftCPU::CMPSW(const X86::Instruction&) { TODO(); } +template<typename T> +ALWAYS_INLINE static void do_cmps(SoftCPU& cpu, const X86::Instruction& insn) +{ + auto src_segment = cpu.segment(insn.segment_prefix().value_or(X86::SegmentRegister::DS)); + cpu.do_once_or_repeat<true>(insn, [&] { + auto src = cpu.read_memory<T>({ src_segment, cpu.source_index(insn.a32()) }); + auto dest = cpu.read_memory<T>({ cpu.es(), cpu.destination_index(insn.a32()) }); + op_sub(cpu, dest, src); + cpu.step_source_index(insn.a32(), sizeof(T)); + cpu.step_destination_index(insn.a32(), sizeof(T)); + }); +} + +void SoftCPU::CMPSB(const X86::Instruction& insn) +{ + do_cmps<u8>(*this, insn); +} + +void SoftCPU::CMPSD(const X86::Instruction& insn) +{ + do_cmps<u32>(*this, insn); +} + +void SoftCPU::CMPSW(const X86::Instruction& insn) +{ + do_cmps<u16>(*this, insn); +} void SoftCPU::CMPXCHG_RM16_reg16(const X86::Instruction& insn) { diff --git a/DevTools/UserspaceEmulator/SoftCPU.h b/DevTools/UserspaceEmulator/SoftCPU.h index d1068d95ee..7d0e3d8e69 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.h +++ b/DevTools/UserspaceEmulator/SoftCPU.h @@ -140,6 +140,90 @@ public: u32 gpr32(X86::RegisterIndex32 reg) const { return m_gpr[reg].full_u32; } u32& gpr32(X86::RegisterIndex32 reg) { return m_gpr[reg].full_u32; } + template<typename T> + T gpr(unsigned register_index) const + { + if constexpr (sizeof(T) == 1) + return gpr8((X86::RegisterIndex8)register_index); + if constexpr (sizeof(T) == 2) + return gpr16((X86::RegisterIndex16)register_index); + if constexpr (sizeof(T) == 4) + return gpr32((X86::RegisterIndex32)register_index); + } + + template<typename T> + T& gpr(unsigned register_index) + { + if constexpr (sizeof(T) == 1) + return gpr8((X86::RegisterIndex8)register_index); + if constexpr (sizeof(T) == 2) + return gpr16((X86::RegisterIndex16)register_index); + if constexpr (sizeof(T) == 4) + return gpr32((X86::RegisterIndex32)register_index); + } + + u32 source_index(bool a32) const + { + if (a32) + return esi(); + return si(); + } + + u32 destination_index(bool a32) const + { + if (a32) + return edi(); + return di(); + } + + u32 loop_index(bool a32) const + { + if (a32) + return ecx(); + return cx(); + } + + bool decrement_loop_index(bool a32) + { + if (a32) { + set_ecx(ecx() - 1); + return ecx() == 0; + } + set_cx(cx() - 1); + return cx() == 0; + } + + ALWAYS_INLINE void step_source_index(bool a32, u32 step) + { + if (a32) { + if (df()) + set_esi(esi() - step); + else + set_esi(esi() + step); + } else { + if (df()) + set_si(si() - step); + else + set_si(si() + step); + } + } + + ALWAYS_INLINE void step_destination_index(bool a32, u32 step) + { + if (a32) { + if (df()) + set_edi(edi() - step); + else + set_edi(edi() + step); + } else { + if (df()) + set_di(di() - step); + else + set_di(di() + step); + } + } + + u32 eax() const { return gpr32(X86::RegisterEAX); } u32 ebx() const { return gpr32(X86::RegisterEBX); } u32 ecx() const { return gpr32(X86::RegisterECX); } @@ -253,10 +337,32 @@ public: u16 read_memory16(X86::LogicalAddress); u32 read_memory32(X86::LogicalAddress); + template<typename T> + T read_memory(X86::LogicalAddress address) + { + if constexpr (sizeof(T) == 1) + return read_memory8(address); + if constexpr (sizeof(T) == 2) + return read_memory16(address); + if constexpr (sizeof(T) == 4) + return read_memory32(address); + } + void write_memory8(X86::LogicalAddress, u8); void write_memory16(X86::LogicalAddress, u16); void write_memory32(X86::LogicalAddress, u32); + template<typename T> + void write_memory(X86::LogicalAddress address, T data) + { + if constexpr (sizeof(T) == 1) + return write_memory8(address, data); + if constexpr (sizeof(T) == 2) + return write_memory16(address, data); + if constexpr (sizeof(T) == 4) + return write_memory32(address, data); + } + bool evaluate_condition(u8 condition) const { switch (condition) { @@ -298,6 +404,9 @@ public: return 0; } + template<bool check_zf, typename Callback> + void do_once_or_repeat(const X86::Instruction& insn, Callback); + // ^X86::InstructionStream virtual bool can_read() override { return false; } virtual u8 read8() override; @@ -818,9 +927,6 @@ private: template<typename Op> void generic_RM32_CL(Op, const X86::Instruction&); - template<bool check_zf, typename Callback> - void do_once_or_repeat(const X86::Instruction& insn, Callback); - void update_code_cache(); void did_receive_secret_data(); |