summaryrefslogtreecommitdiff
path: root/DevTools/UserspaceEmulator
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-07-18 00:10:21 +0200
committerAndreas Kling <kling@serenityos.org>2020-07-18 00:25:02 +0200
commit485d1faf09fcadd3f9830ea18e585076ce7eb2d6 (patch)
treebdd818b86449381039beac886459447ffedbee01 /DevTools/UserspaceEmulator
parent28b6ba56aa5115efc127068fbf5839f06149c5e7 (diff)
downloadserenity-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.cpp48
-rw-r--r--DevTools/UserspaceEmulator/SoftCPU.h112
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();