mirror of
https://github.com/RGBCube/serenity
synced 2025-05-22 16:35:08 +00:00
UserspaceEmulator+LibX86: Add support for 64-bit memory reads and writes (#3584)
This is useful for reading and writing doubles for #3329. It is also useful for emulating 64-bit binaries. MemoryOrRegisterReference assumes that 64-bit values are always memory references since that's enough for fpu support. If we ever want to emulate 64-bit binaries, that part will need minor updating.
This commit is contained in:
parent
1fa5a526e8
commit
f1c0f661f4
12 changed files with 156 additions and 0 deletions
|
@ -116,6 +116,23 @@ ValueWithShadow<u32> MmapRegion::read32(u32 offset)
|
||||||
return { *reinterpret_cast<const u32*>(m_data + offset), *reinterpret_cast<const u32*>(m_shadow_data + offset) };
|
return { *reinterpret_cast<const u32*>(m_data + offset), *reinterpret_cast<const u32*>(m_shadow_data + offset) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueWithShadow<u64> MmapRegion::read64(u32 offset)
|
||||||
|
{
|
||||||
|
if (!is_readable()) {
|
||||||
|
warn() << "64-bit read from unreadable MmapRegion @ " << (const void*)(base() + offset);
|
||||||
|
Emulator::the().dump_backtrace();
|
||||||
|
TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_malloc_block()) {
|
||||||
|
if (auto* tracer = Emulator::the().malloc_tracer())
|
||||||
|
tracer->audit_read(base() + offset, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(offset + 7 < size());
|
||||||
|
return { *reinterpret_cast<const u64*>(m_data + offset), *reinterpret_cast<const u64*>(m_shadow_data + offset) };
|
||||||
|
}
|
||||||
|
|
||||||
void MmapRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
void MmapRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
||||||
{
|
{
|
||||||
if (!is_writable()) {
|
if (!is_writable()) {
|
||||||
|
@ -171,4 +188,23 @@ void MmapRegion::write32(u32 offset, ValueWithShadow<u32> value)
|
||||||
*reinterpret_cast<u32*>(m_shadow_data + offset) = value.shadow();
|
*reinterpret_cast<u32*>(m_shadow_data + offset) = value.shadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MmapRegion::write64(u32 offset, ValueWithShadow<u64> value)
|
||||||
|
{
|
||||||
|
if (!is_writable()) {
|
||||||
|
warn() << "64-bit write to unreadable MmapRegion @ " << (const void*)(base() + offset);
|
||||||
|
Emulator::the().dump_backtrace();
|
||||||
|
TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_malloc_block()) {
|
||||||
|
if (auto* tracer = Emulator::the().malloc_tracer())
|
||||||
|
tracer->audit_write(base() + offset, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(offset + 7 < size());
|
||||||
|
ASSERT(m_data != m_shadow_data);
|
||||||
|
*reinterpret_cast<u64*>(m_data + offset) = value.value();
|
||||||
|
*reinterpret_cast<u64*>(m_shadow_data + offset) = value.shadow();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,12 @@ public:
|
||||||
virtual ValueWithShadow<u8> read8(u32 offset) override;
|
virtual ValueWithShadow<u8> read8(u32 offset) override;
|
||||||
virtual ValueWithShadow<u16> read16(u32 offset) override;
|
virtual ValueWithShadow<u16> read16(u32 offset) override;
|
||||||
virtual ValueWithShadow<u32> read32(u32 offset) override;
|
virtual ValueWithShadow<u32> read32(u32 offset) override;
|
||||||
|
virtual ValueWithShadow<u64> read64(u32 offset) override;
|
||||||
|
|
||||||
virtual void write8(u32 offset, ValueWithShadow<u8>) override;
|
virtual void write8(u32 offset, ValueWithShadow<u8>) override;
|
||||||
virtual void write16(u32 offset, ValueWithShadow<u16>) override;
|
virtual void write16(u32 offset, ValueWithShadow<u16>) override;
|
||||||
virtual void write32(u32 offset, ValueWithShadow<u32>) override;
|
virtual void write32(u32 offset, ValueWithShadow<u32>) override;
|
||||||
|
virtual void write64(u32 offset, ValueWithShadow<u64>) override;
|
||||||
|
|
||||||
u8* data() { return m_data; }
|
u8* data() { return m_data; }
|
||||||
u8* shadow_data() { return m_shadow_data; }
|
u8* shadow_data() { return m_shadow_data; }
|
||||||
|
|
|
@ -70,6 +70,12 @@ ValueWithShadow<u32> SharedBufferRegion::read32(u32 offset)
|
||||||
return { *reinterpret_cast<const u32*>(m_data + offset), *reinterpret_cast<const u32*>(m_shadow_data + offset) };
|
return { *reinterpret_cast<const u32*>(m_data + offset), *reinterpret_cast<const u32*>(m_shadow_data + offset) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueWithShadow<u64> SharedBufferRegion::read64(u32 offset)
|
||||||
|
{
|
||||||
|
ASSERT(offset + 7 < size());
|
||||||
|
return { *reinterpret_cast<const u64*>(m_data + offset), *reinterpret_cast<const u64*>(m_shadow_data + offset) };
|
||||||
|
}
|
||||||
|
|
||||||
void SharedBufferRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
void SharedBufferRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
||||||
{
|
{
|
||||||
ASSERT(offset < size());
|
ASSERT(offset < size());
|
||||||
|
@ -91,6 +97,13 @@ void SharedBufferRegion::write32(u32 offset, ValueWithShadow<u32> value)
|
||||||
*reinterpret_cast<u32*>(m_shadow_data + offset) = value.shadow();
|
*reinterpret_cast<u32*>(m_shadow_data + offset) = value.shadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SharedBufferRegion::write64(u32 offset, ValueWithShadow<u64> value)
|
||||||
|
{
|
||||||
|
ASSERT(offset + 7 < size());
|
||||||
|
*reinterpret_cast<u64*>(m_data + offset) = value.value();
|
||||||
|
*reinterpret_cast<u64*>(m_shadow_data + offset) = value.shadow();
|
||||||
|
}
|
||||||
|
|
||||||
int SharedBufferRegion::allow_all()
|
int SharedBufferRegion::allow_all()
|
||||||
{
|
{
|
||||||
return syscall(SC_shbuf_allow_all, m_shbuf_id);
|
return syscall(SC_shbuf_allow_all, m_shbuf_id);
|
||||||
|
|
|
@ -39,10 +39,12 @@ public:
|
||||||
virtual ValueWithShadow<u8> read8(u32 offset) override;
|
virtual ValueWithShadow<u8> read8(u32 offset) override;
|
||||||
virtual ValueWithShadow<u16> read16(u32 offset) override;
|
virtual ValueWithShadow<u16> read16(u32 offset) override;
|
||||||
virtual ValueWithShadow<u32> read32(u32 offset) override;
|
virtual ValueWithShadow<u32> read32(u32 offset) override;
|
||||||
|
virtual ValueWithShadow<u64> read64(u32 offset) override;
|
||||||
|
|
||||||
virtual void write8(u32 offset, ValueWithShadow<u8>) override;
|
virtual void write8(u32 offset, ValueWithShadow<u8>) override;
|
||||||
virtual void write16(u32 offset, ValueWithShadow<u16>) override;
|
virtual void write16(u32 offset, ValueWithShadow<u16>) override;
|
||||||
virtual void write32(u32 offset, ValueWithShadow<u32>) override;
|
virtual void write32(u32 offset, ValueWithShadow<u32>) override;
|
||||||
|
virtual void write64(u32 offset, ValueWithShadow<u64>) override;
|
||||||
|
|
||||||
u8* data() { return m_data; }
|
u8* data() { return m_data; }
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,12 @@ ValueWithShadow<u32> SimpleRegion::read32(u32 offset)
|
||||||
return { *reinterpret_cast<const u32*>(m_data + offset), *reinterpret_cast<const u32*>(m_shadow_data + offset) };
|
return { *reinterpret_cast<const u32*>(m_data + offset), *reinterpret_cast<const u32*>(m_shadow_data + offset) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueWithShadow<u64> SimpleRegion::read64(u32 offset)
|
||||||
|
{
|
||||||
|
ASSERT(offset + 7 < size());
|
||||||
|
return { *reinterpret_cast<const u64*>(m_data + offset), *reinterpret_cast<const u64*>(m_shadow_data + offset) };
|
||||||
|
}
|
||||||
|
|
||||||
void SimpleRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
void SimpleRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
||||||
{
|
{
|
||||||
ASSERT(offset < size());
|
ASSERT(offset < size());
|
||||||
|
@ -82,6 +88,13 @@ void SimpleRegion::write32(u32 offset, ValueWithShadow<u32> value)
|
||||||
*reinterpret_cast<u32*>(m_shadow_data + offset) = value.shadow();
|
*reinterpret_cast<u32*>(m_shadow_data + offset) = value.shadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SimpleRegion::write64(u32 offset, ValueWithShadow<u64> value)
|
||||||
|
{
|
||||||
|
ASSERT(offset + 7 < size());
|
||||||
|
*reinterpret_cast<u64*>(m_data + offset) = value.value();
|
||||||
|
*reinterpret_cast<u64*>(m_shadow_data + offset) = value.shadow();
|
||||||
|
}
|
||||||
|
|
||||||
u8* SimpleRegion::cacheable_ptr(u32 offset)
|
u8* SimpleRegion::cacheable_ptr(u32 offset)
|
||||||
{
|
{
|
||||||
return m_data + offset;
|
return m_data + offset;
|
||||||
|
|
|
@ -38,10 +38,12 @@ public:
|
||||||
virtual ValueWithShadow<u8> read8(u32 offset) override;
|
virtual ValueWithShadow<u8> read8(u32 offset) override;
|
||||||
virtual ValueWithShadow<u16> read16(u32 offset) override;
|
virtual ValueWithShadow<u16> read16(u32 offset) override;
|
||||||
virtual ValueWithShadow<u32> read32(u32 offset) override;
|
virtual ValueWithShadow<u32> read32(u32 offset) override;
|
||||||
|
virtual ValueWithShadow<u64> read64(u32 offset) override;
|
||||||
|
|
||||||
virtual void write8(u32 offset, ValueWithShadow<u8>) override;
|
virtual void write8(u32 offset, ValueWithShadow<u8>) override;
|
||||||
virtual void write16(u32 offset, ValueWithShadow<u16>) override;
|
virtual void write16(u32 offset, ValueWithShadow<u16>) override;
|
||||||
virtual void write32(u32 offset, ValueWithShadow<u32>) override;
|
virtual void write32(u32 offset, ValueWithShadow<u32>) override;
|
||||||
|
virtual void write64(u32 offset, ValueWithShadow<u64>) override;
|
||||||
|
|
||||||
u8* data() { return m_data; }
|
u8* data() { return m_data; }
|
||||||
u8* shadow_data() { return m_shadow_data; }
|
u8* shadow_data() { return m_shadow_data; }
|
||||||
|
|
|
@ -158,6 +158,16 @@ ValueWithShadow<u32> SoftCPU::read_memory32(X86::LogicalAddress address)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueWithShadow<u64> SoftCPU::read_memory64(X86::LogicalAddress address)
|
||||||
|
{
|
||||||
|
ASSERT(address.selector() == 0x18 || address.selector() == 0x20 || address.selector() == 0x28);
|
||||||
|
auto value = m_emulator.mmu().read64(address);
|
||||||
|
#ifdef MEMORY_DEBUG
|
||||||
|
printf("\033[36;1mread_memory64: @%04x:%08x -> %016llx (%016llx)\033[0m\n", address.selector(), address.offset(), value.value(), value.shadow());
|
||||||
|
#endif
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
void SoftCPU::write_memory8(X86::LogicalAddress address, ValueWithShadow<u8> value)
|
void SoftCPU::write_memory8(X86::LogicalAddress address, ValueWithShadow<u8> value)
|
||||||
{
|
{
|
||||||
ASSERT(address.selector() == 0x20 || address.selector() == 0x28);
|
ASSERT(address.selector() == 0x20 || address.selector() == 0x28);
|
||||||
|
@ -185,6 +195,15 @@ void SoftCPU::write_memory32(X86::LogicalAddress address, ValueWithShadow<u32> v
|
||||||
m_emulator.mmu().write32(address, value);
|
m_emulator.mmu().write32(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoftCPU::write_memory64(X86::LogicalAddress address, ValueWithShadow<u64> value)
|
||||||
|
{
|
||||||
|
ASSERT(address.selector() == 0x20 || address.selector() == 0x28);
|
||||||
|
#ifdef MEMORY_DEBUG
|
||||||
|
printf("\033[35;1mwrite_memory64: @%04x:%08x <- %016llx (%016llx)\033[0m\n", address.selector(), address.offset(), value.value(), value.shadow());
|
||||||
|
#endif
|
||||||
|
m_emulator.mmu().write64(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
void SoftCPU::push_string(const StringView& string)
|
void SoftCPU::push_string(const StringView& string)
|
||||||
{
|
{
|
||||||
size_t space_to_allocate = round_up_to_power_of_two(string.length() + 1, 16);
|
size_t space_to_allocate = round_up_to_power_of_two(string.length() + 1, 16);
|
||||||
|
|
|
@ -360,6 +360,7 @@ public:
|
||||||
ValueWithShadow<u8> read_memory8(X86::LogicalAddress);
|
ValueWithShadow<u8> read_memory8(X86::LogicalAddress);
|
||||||
ValueWithShadow<u16> read_memory16(X86::LogicalAddress);
|
ValueWithShadow<u16> read_memory16(X86::LogicalAddress);
|
||||||
ValueWithShadow<u32> read_memory32(X86::LogicalAddress);
|
ValueWithShadow<u32> read_memory32(X86::LogicalAddress);
|
||||||
|
ValueWithShadow<u64> read_memory64(X86::LogicalAddress);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ValueWithShadow<T> read_memory(X86::LogicalAddress address)
|
ValueWithShadow<T> read_memory(X86::LogicalAddress address)
|
||||||
|
@ -375,6 +376,7 @@ public:
|
||||||
void write_memory8(X86::LogicalAddress, ValueWithShadow<u8>);
|
void write_memory8(X86::LogicalAddress, ValueWithShadow<u8>);
|
||||||
void write_memory16(X86::LogicalAddress, ValueWithShadow<u16>);
|
void write_memory16(X86::LogicalAddress, ValueWithShadow<u16>);
|
||||||
void write_memory32(X86::LogicalAddress, ValueWithShadow<u32>);
|
void write_memory32(X86::LogicalAddress, ValueWithShadow<u32>);
|
||||||
|
void write_memory64(X86::LogicalAddress, ValueWithShadow<u64>);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void write_memory(X86::LogicalAddress address, ValueWithShadow<T> data)
|
void write_memory(X86::LogicalAddress address, ValueWithShadow<T> data)
|
||||||
|
@ -456,6 +458,7 @@ public:
|
||||||
virtual u8 read8() override;
|
virtual u8 read8() override;
|
||||||
virtual u16 read16() override;
|
virtual u16 read16() override;
|
||||||
virtual u32 read32() override;
|
virtual u32 read32() override;
|
||||||
|
virtual u64 read64() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^X86::Interpreter
|
// ^X86::Interpreter
|
||||||
|
@ -1154,4 +1157,15 @@ ALWAYS_INLINE u32 SoftCPU::read32()
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE u64 SoftCPU::read64()
|
||||||
|
{
|
||||||
|
if (!m_cached_code_ptr || (m_cached_code_ptr + 8) >= m_cached_code_end)
|
||||||
|
update_code_cache();
|
||||||
|
|
||||||
|
u64 value = *reinterpret_cast<const u64*>(m_cached_code_ptr);
|
||||||
|
m_cached_code_ptr += 8;
|
||||||
|
m_eip += 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,17 @@ ValueWithShadow<u32> SoftMMU::read32(X86::LogicalAddress address)
|
||||||
return region->read32(address.offset() - region->base());
|
return region->read32(address.offset() - region->base());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueWithShadow<u64> SoftMMU::read64(X86::LogicalAddress address)
|
||||||
|
{
|
||||||
|
auto* region = find_region(address);
|
||||||
|
if (!region) {
|
||||||
|
warn() << "SoftMMU::read64: No region for @" << (const void*)address.offset();
|
||||||
|
TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
return region->read64(address.offset() - region->base());
|
||||||
|
}
|
||||||
|
|
||||||
void SoftMMU::write8(X86::LogicalAddress address, ValueWithShadow<u8> value)
|
void SoftMMU::write8(X86::LogicalAddress address, ValueWithShadow<u8> value)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
|
@ -130,6 +141,17 @@ void SoftMMU::write32(X86::LogicalAddress address, ValueWithShadow<u32> value)
|
||||||
region->write32(address.offset() - region->base(), value);
|
region->write32(address.offset() - region->base(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoftMMU::write64(X86::LogicalAddress address, ValueWithShadow<u64> value)
|
||||||
|
{
|
||||||
|
auto* region = find_region(address);
|
||||||
|
if (!region) {
|
||||||
|
warn() << "SoftMMU::write64: No region for @" << (const void*)address.offset();
|
||||||
|
TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
region->write64(address.offset() - region->base(), value);
|
||||||
|
}
|
||||||
|
|
||||||
void SoftMMU::copy_to_vm(FlatPtr destination, const void* source, size_t size)
|
void SoftMMU::copy_to_vm(FlatPtr destination, const void* source, size_t size)
|
||||||
{
|
{
|
||||||
// FIXME: We should have a way to preserve the shadow data here as well.
|
// FIXME: We should have a way to preserve the shadow data here as well.
|
||||||
|
|
|
@ -52,10 +52,12 @@ public:
|
||||||
virtual void write8(u32 offset, ValueWithShadow<u8>) = 0;
|
virtual void write8(u32 offset, ValueWithShadow<u8>) = 0;
|
||||||
virtual void write16(u32 offset, ValueWithShadow<u16>) = 0;
|
virtual void write16(u32 offset, ValueWithShadow<u16>) = 0;
|
||||||
virtual void write32(u32 offset, ValueWithShadow<u32>) = 0;
|
virtual void write32(u32 offset, ValueWithShadow<u32>) = 0;
|
||||||
|
virtual void write64(u32 offset, ValueWithShadow<u64>) = 0;
|
||||||
|
|
||||||
virtual ValueWithShadow<u8> read8(u32 offset) = 0;
|
virtual ValueWithShadow<u8> read8(u32 offset) = 0;
|
||||||
virtual ValueWithShadow<u16> read16(u32 offset) = 0;
|
virtual ValueWithShadow<u16> read16(u32 offset) = 0;
|
||||||
virtual ValueWithShadow<u32> read32(u32 offset) = 0;
|
virtual ValueWithShadow<u32> read32(u32 offset) = 0;
|
||||||
|
virtual ValueWithShadow<u64> read64(u32 offset) = 0;
|
||||||
|
|
||||||
virtual u8* cacheable_ptr([[maybe_unused]] u32 offset) { return nullptr; }
|
virtual u8* cacheable_ptr([[maybe_unused]] u32 offset) { return nullptr; }
|
||||||
virtual bool is_shared_buffer() const { return false; }
|
virtual bool is_shared_buffer() const { return false; }
|
||||||
|
@ -85,10 +87,12 @@ public:
|
||||||
ValueWithShadow<u8> read8(X86::LogicalAddress);
|
ValueWithShadow<u8> read8(X86::LogicalAddress);
|
||||||
ValueWithShadow<u16> read16(X86::LogicalAddress);
|
ValueWithShadow<u16> read16(X86::LogicalAddress);
|
||||||
ValueWithShadow<u32> read32(X86::LogicalAddress);
|
ValueWithShadow<u32> read32(X86::LogicalAddress);
|
||||||
|
ValueWithShadow<u64> read64(X86::LogicalAddress);
|
||||||
|
|
||||||
void write8(X86::LogicalAddress, ValueWithShadow<u8>);
|
void write8(X86::LogicalAddress, ValueWithShadow<u8>);
|
||||||
void write16(X86::LogicalAddress, ValueWithShadow<u16>);
|
void write16(X86::LogicalAddress, ValueWithShadow<u16>);
|
||||||
void write32(X86::LogicalAddress, ValueWithShadow<u32>);
|
void write32(X86::LogicalAddress, ValueWithShadow<u32>);
|
||||||
|
void write64(X86::LogicalAddress, ValueWithShadow<u64>);
|
||||||
|
|
||||||
Region* find_region(X86::LogicalAddress);
|
Region* find_region(X86::LogicalAddress);
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,8 @@ private:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ALWAYS_INLINE ValueWithShadow<T> shadow_wrap_as_initialized(T value)
|
ALWAYS_INLINE ValueWithShadow<T> shadow_wrap_as_initialized(T value)
|
||||||
{
|
{
|
||||||
|
if constexpr (sizeof(T) == 8)
|
||||||
|
return { value, 0x01010101'01010101LLU };
|
||||||
if constexpr (sizeof(T) == 4)
|
if constexpr (sizeof(T) == 4)
|
||||||
return { value, 0x01010101 };
|
return { value, 0x01010101 };
|
||||||
if constexpr (sizeof(T) == 2)
|
if constexpr (sizeof(T) == 2)
|
||||||
|
|
|
@ -315,6 +315,7 @@ public:
|
||||||
virtual u8 read8() = 0;
|
virtual u8 read8() = 0;
|
||||||
virtual u16 read16() = 0;
|
virtual u16 read16() = 0;
|
||||||
virtual u32 read32() = 0;
|
virtual u32 read32() = 0;
|
||||||
|
virtual u64 read64() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleInstructionStream final : public InstructionStream {
|
class SimpleInstructionStream final : public InstructionStream {
|
||||||
|
@ -347,6 +348,12 @@ public:
|
||||||
return ((u32)msw << 16) | (u32)lsw;
|
return ((u32)msw << 16) | (u32)lsw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual u64 read64() override
|
||||||
|
{
|
||||||
|
u32 lsw = read32();
|
||||||
|
u32 msw = read32();
|
||||||
|
return ((u64)msw << 32) | (u64)lsw;
|
||||||
|
}
|
||||||
size_t offset() const { return m_offset; }
|
size_t offset() const { return m_offset; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -385,6 +392,8 @@ public:
|
||||||
void write16(CPU&, const Instruction&, T);
|
void write16(CPU&, const Instruction&, T);
|
||||||
template<typename CPU, typename T>
|
template<typename CPU, typename T>
|
||||||
void write32(CPU&, const Instruction&, T);
|
void write32(CPU&, const Instruction&, T);
|
||||||
|
template<typename CPU, typename T>
|
||||||
|
void write64(CPU&, const Instruction&, T);
|
||||||
|
|
||||||
template<typename T, typename CPU>
|
template<typename T, typename CPU>
|
||||||
T read8(CPU&, const Instruction&);
|
T read8(CPU&, const Instruction&);
|
||||||
|
@ -392,6 +401,8 @@ public:
|
||||||
T read16(CPU&, const Instruction&);
|
T read16(CPU&, const Instruction&);
|
||||||
template<typename T, typename CPU>
|
template<typename T, typename CPU>
|
||||||
T read32(CPU&, const Instruction&);
|
T read32(CPU&, const Instruction&);
|
||||||
|
template<typename T, typename CPU>
|
||||||
|
T read64(CPU&, const Instruction&);
|
||||||
|
|
||||||
template<typename CPU>
|
template<typename CPU>
|
||||||
LogicalAddress resolve(const CPU&, const Instruction&);
|
LogicalAddress resolve(const CPU&, const Instruction&);
|
||||||
|
@ -752,6 +763,14 @@ ALWAYS_INLINE void MemoryOrRegisterReference::write32(CPU& cpu, const Instructio
|
||||||
cpu.write_memory32(address, value);
|
cpu.write_memory32(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename CPU, typename T>
|
||||||
|
ALWAYS_INLINE void MemoryOrRegisterReference::write64(CPU& cpu, const Instruction& insn, T value)
|
||||||
|
{
|
||||||
|
ASSERT(!is_register());
|
||||||
|
auto address = resolve(cpu, insn);
|
||||||
|
cpu.write_memory64(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, typename CPU>
|
template<typename T, typename CPU>
|
||||||
ALWAYS_INLINE T MemoryOrRegisterReference::read8(CPU& cpu, const Instruction& insn)
|
ALWAYS_INLINE T MemoryOrRegisterReference::read8(CPU& cpu, const Instruction& insn)
|
||||||
{
|
{
|
||||||
|
@ -782,6 +801,14 @@ ALWAYS_INLINE T MemoryOrRegisterReference::read32(CPU& cpu, const Instruction& i
|
||||||
return cpu.read_memory32(address);
|
return cpu.read_memory32(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T, typename CPU>
|
||||||
|
ALWAYS_INLINE T MemoryOrRegisterReference::read64(CPU& cpu, const Instruction& insn)
|
||||||
|
{
|
||||||
|
ASSERT(!is_register());
|
||||||
|
auto address = resolve(cpu, insn);
|
||||||
|
return cpu.read_memory64(address);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename InstructionStreamType>
|
template<typename InstructionStreamType>
|
||||||
ALWAYS_INLINE Instruction Instruction::from_stream(InstructionStreamType& stream, bool o32, bool a32)
|
ALWAYS_INLINE Instruction Instruction::from_stream(InstructionStreamType& stream, bool o32, bool a32)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue