From 102e1d330c010d054d6a58e1adc9ffd74faecfaf Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 15 Nov 2020 17:54:11 +0100 Subject: [PATCH] UserspaceEmulator: Add a fast path for forward REP STOSB This is used by memset() so we get a lot of mileage out of optimizing this instruction. Note that we currently audit every individual byte accessed separately. This could be greatly improved by adding a range auditing mechanism to MallocTracer. --- DevTools/UserspaceEmulator/SoftCPU.cpp | 16 +++++++++++++++ DevTools/UserspaceEmulator/SoftMMU.cpp | 27 ++++++++++++++++++++++++++ DevTools/UserspaceEmulator/SoftMMU.h | 2 ++ 3 files changed, 45 insertions(+) diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp index 08b9fa7be0..791e7085f0 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -3048,6 +3048,22 @@ void SoftCPU::STI(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::STOSB(const X86::Instruction& insn) { + if (insn.has_rep_prefix() && !df()) { + // Fast path for 8-bit forward memory fill. + if (m_emulator.mmu().fast_fill_memory8({ es(), destination_index(insn.a32()).value() }, ecx().value(), al())) { + if (insn.a32()) { + // FIXME: Should an uninitialized ECX taint EDI here? + set_edi({ (u32)(edi().value() + ecx().value()), edi().shadow() }); + set_ecx(shadow_wrap_as_initialized(0)); + } else { + // FIXME: Should an uninitialized CX taint DI here? + set_di({ (u16)(di().value() + cx().value()), di().shadow() }); + set_cx(shadow_wrap_as_initialized(0)); + } + return; + } + } + do_once_or_repeat(insn, [&] { write_memory8({ es(), destination_index(insn.a32()).value() }, al()); step_destination_index(insn.a32(), 1); diff --git a/DevTools/UserspaceEmulator/SoftMMU.cpp b/DevTools/UserspaceEmulator/SoftMMU.cpp index 58b7f72475..a90fab44ba 100644 --- a/DevTools/UserspaceEmulator/SoftMMU.cpp +++ b/DevTools/UserspaceEmulator/SoftMMU.cpp @@ -26,9 +26,11 @@ #include "SoftMMU.h" #include "Emulator.h" +#include "MmapRegion.h" #include "Report.h" #include "SharedBufferRegion.h" #include +#include namespace UserspaceEmulator { @@ -244,4 +246,29 @@ SharedBufferRegion* SoftMMU::shbuf_region(int shbuf_id) return (SharedBufferRegion*)m_shbuf_regions.get(shbuf_id).value_or(nullptr); } +bool SoftMMU::fast_fill_memory8(X86::LogicalAddress address, size_t size, ValueWithShadow value) +{ + if (!size) + return true; + auto* region = find_region(address); + if (!region) + return false; + if (!region->contains(address.offset() + size - 1)) + return false; + + if (region->is_mmap() && static_cast(*region).is_malloc_block()) { + if (auto* tracer = Emulator::the().malloc_tracer()) { + // FIXME: Add a way to audit an entire range of memory instead of looping here! + for (size_t i = 0; i < size; i += sizeof(u8)) { + tracer->audit_write(address.offset() + (i * sizeof(u8)), sizeof(u8)); + } + } + } + + size_t offset_in_region = address.offset() - region->base(); + memset(region->data() + offset_in_region, value.value(), size); + memset(region->shadow_data() + offset_in_region, value.shadow(), size); + return true; +} + } diff --git a/DevTools/UserspaceEmulator/SoftMMU.h b/DevTools/UserspaceEmulator/SoftMMU.h index 5820b21ecf..1efdb47a2b 100644 --- a/DevTools/UserspaceEmulator/SoftMMU.h +++ b/DevTools/UserspaceEmulator/SoftMMU.h @@ -108,6 +108,8 @@ public: void set_tls_region(NonnullOwnPtr); + bool fast_fill_memory8(X86::LogicalAddress, size_t size, ValueWithShadow); + void copy_to_vm(FlatPtr destination, const void* source, size_t); void copy_from_vm(void* destination, const FlatPtr source, size_t); ByteBuffer copy_buffer_from_vm(const FlatPtr source, size_t);