mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 15:57:35 +00:00
UserspaceEmulator: Add helpers for making loop instructions generic
Use them to implement CMPSB/CMPSW/CMPSD.
This commit is contained in:
parent
28b6ba56aa
commit
485d1faf09
2 changed files with 138 additions and 22 deletions
|
@ -195,23 +195,9 @@ void SoftCPU::do_once_or_repeat(const X86::Instruction& insn, Callback callback)
|
||||||
if (!insn.has_rep_prefix())
|
if (!insn.has_rep_prefix())
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
if (insn.has_address_size_override_prefix()) {
|
while (loop_index(insn.a32())) {
|
||||||
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()) {
|
|
||||||
callback();
|
callback();
|
||||||
set_ecx(ecx() - 1);
|
decrement_loop_index(insn.a32());
|
||||||
if constexpr (check_zf) {
|
if constexpr (check_zf) {
|
||||||
if (insn.rep_prefix() == X86::Prefix::REPZ && !zf())
|
if (insn.rep_prefix() == X86::Prefix::REPZ && !zf())
|
||||||
break;
|
break;
|
||||||
|
@ -1057,9 +1043,33 @@ void SoftCPU::CMOVcc_reg32_RM32(const X86::Instruction& insn)
|
||||||
gpr32(insn.reg32()) = insn.modrm().read32(*this, insn);
|
gpr32(insn.reg32()) = insn.modrm().read32(*this, insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftCPU::CMPSB(const X86::Instruction&) { TODO(); }
|
template<typename T>
|
||||||
void SoftCPU::CMPSD(const X86::Instruction&) { TODO(); }
|
ALWAYS_INLINE static void do_cmps(SoftCPU& cpu, const X86::Instruction& insn)
|
||||||
void SoftCPU::CMPSW(const X86::Instruction&) { TODO(); }
|
{
|
||||||
|
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)
|
void SoftCPU::CMPXCHG_RM16_reg16(const X86::Instruction& insn)
|
||||||
{
|
{
|
||||||
|
|
|
@ -140,6 +140,90 @@ public:
|
||||||
u32 gpr32(X86::RegisterIndex32 reg) const { return m_gpr[reg].full_u32; }
|
u32 gpr32(X86::RegisterIndex32 reg) const { return m_gpr[reg].full_u32; }
|
||||||
u32& gpr32(X86::RegisterIndex32 reg) { 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 eax() const { return gpr32(X86::RegisterEAX); }
|
||||||
u32 ebx() const { return gpr32(X86::RegisterEBX); }
|
u32 ebx() const { return gpr32(X86::RegisterEBX); }
|
||||||
u32 ecx() const { return gpr32(X86::RegisterECX); }
|
u32 ecx() const { return gpr32(X86::RegisterECX); }
|
||||||
|
@ -253,10 +337,32 @@ public:
|
||||||
u16 read_memory16(X86::LogicalAddress);
|
u16 read_memory16(X86::LogicalAddress);
|
||||||
u32 read_memory32(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_memory8(X86::LogicalAddress, u8);
|
||||||
void write_memory16(X86::LogicalAddress, u16);
|
void write_memory16(X86::LogicalAddress, u16);
|
||||||
void write_memory32(X86::LogicalAddress, u32);
|
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
|
bool evaluate_condition(u8 condition) const
|
||||||
{
|
{
|
||||||
switch (condition) {
|
switch (condition) {
|
||||||
|
@ -298,6 +404,9 @@ public:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool check_zf, typename Callback>
|
||||||
|
void do_once_or_repeat(const X86::Instruction& insn, Callback);
|
||||||
|
|
||||||
// ^X86::InstructionStream
|
// ^X86::InstructionStream
|
||||||
virtual bool can_read() override { return false; }
|
virtual bool can_read() override { return false; }
|
||||||
virtual u8 read8() override;
|
virtual u8 read8() override;
|
||||||
|
@ -818,9 +927,6 @@ private:
|
||||||
template<typename Op>
|
template<typename Op>
|
||||||
void generic_RM32_CL(Op, const X86::Instruction&);
|
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 update_code_cache();
|
||||||
|
|
||||||
void did_receive_secret_data();
|
void did_receive_secret_data();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue