瀏覽代碼

UserspaceEmulator: Add helpers for making loop instructions generic

Use them to implement CMPSB/CMPSW/CMPSD.
Andreas Kling 5 年之前
父節點
當前提交
485d1faf09
共有 2 個文件被更改,包括 138 次插入22 次删除
  1. 29 19
      DevTools/UserspaceEmulator/SoftCPU.cpp
  2. 109 3
      DevTools/UserspaceEmulator/SoftCPU.h

+ 29 - 19
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)
 {

+ 109 - 3
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();