UE+LibX86: Support bigger reads and writes

This commit is contained in:
Hendiadyoin1 2021-04-10 23:29:32 +02:00 committed by Andreas Kling
parent a99812633b
commit f1957bb86b
Notes: sideshowbarker 2024-07-18 19:10:23 +09:00
11 changed files with 316 additions and 4 deletions

View file

@ -129,6 +129,40 @@ ValueWithShadow<u64> MmapRegion::read64(u32 offset)
return { *reinterpret_cast<const u64*>(m_data + offset), *reinterpret_cast<const u64*>(m_shadow_data + offset) };
}
ValueWithShadow<u128> MmapRegion::read128(u32 offset)
{
if (!is_readable()) {
reportln("128-bit read from unreadable MmapRegion @ {:p}", base() + offset);
emulator().dump_backtrace();
TODO();
}
if (is_malloc_block()) {
if (auto* tracer = emulator().malloc_tracer())
tracer->audit_read(*this, base() + offset, 16);
}
VERIFY(offset + 15 < size());
return { *reinterpret_cast<const u128*>(m_data + offset), *reinterpret_cast<const u128*>(m_shadow_data + offset) };
}
ValueWithShadow<u256> MmapRegion::read256(u32 offset)
{
if (!is_readable()) {
reportln("256-bit read from unreadable MmapRegion @ {:p}", base() + offset);
emulator().dump_backtrace();
TODO();
}
if (is_malloc_block()) {
if (auto* tracer = emulator().malloc_tracer())
tracer->audit_read(*this, base() + offset, 32);
}
VERIFY(offset + 31 < size());
return { *reinterpret_cast<const u256*>(m_data + offset), *reinterpret_cast<const u256*>(m_shadow_data + offset) };
}
void MmapRegion::write8(u32 offset, ValueWithShadow<u8> value)
{
if (!is_writable()) {
@ -203,6 +237,44 @@ void MmapRegion::write64(u32 offset, ValueWithShadow<u64> value)
*reinterpret_cast<u64*>(m_shadow_data + offset) = value.shadow();
}
void MmapRegion::write128(u32 offset, ValueWithShadow<u128> value)
{
if (!is_writable()) {
reportln("128-bit write from unwritable MmapRegion @ {:p}", base() + offset);
emulator().dump_backtrace();
TODO();
}
if (is_malloc_block()) {
if (auto* tracer = emulator().malloc_tracer())
tracer->audit_write(*this, base() + offset, 16);
}
VERIFY(offset + 15 < size());
VERIFY(m_data != m_shadow_data);
*reinterpret_cast<u128*>(m_data + offset) = value.value();
*reinterpret_cast<u128*>(m_shadow_data + offset) = value.shadow();
}
void MmapRegion::write256(u32 offset, ValueWithShadow<u256> value)
{
if (!is_writable()) {
reportln("256-bit write from unwritable MmapRegion @ {:p}", base() + offset);
emulator().dump_backtrace();
TODO();
}
if (is_malloc_block()) {
if (auto* tracer = emulator().malloc_tracer())
tracer->audit_write(*this, base() + offset, 32);
}
VERIFY(offset + 31 < size());
VERIFY(m_data != m_shadow_data);
*reinterpret_cast<u256*>(m_data + offset) = value.value();
*reinterpret_cast<u256*>(m_shadow_data + offset) = value.shadow();
}
NonnullOwnPtr<MmapRegion> MmapRegion::split_at(VirtualAddress offset)
{
VERIFY(!m_malloc);

View file

@ -24,11 +24,15 @@ public:
virtual ValueWithShadow<u16> read16(u32 offset) override;
virtual ValueWithShadow<u32> read32(u32 offset) override;
virtual ValueWithShadow<u64> read64(u32 offset) override;
virtual ValueWithShadow<u128> read128(u32 offset) override;
virtual ValueWithShadow<u256> read256(u32 offset) override;
virtual void write8(u32 offset, ValueWithShadow<u8>) override;
virtual void write16(u32 offset, ValueWithShadow<u16>) override;
virtual void write32(u32 offset, ValueWithShadow<u32>) override;
virtual void write64(u32 offset, ValueWithShadow<u64>) override;
virtual void write128(u32 offset, ValueWithShadow<u128>) override;
virtual void write256(u32 offset, ValueWithShadow<u256>) override;
virtual u8* data() override { return m_data; }
virtual u8* shadow_data() override { return m_shadow_data; }

View file

@ -10,6 +10,7 @@
#include "ValueWithShadow.h"
#include <AK/TypeCasts.h>
#include <AK/Types.h>
#include <LibX86/Types.h>
namespace UserspaceEmulator {
@ -31,11 +32,15 @@ public:
virtual void write16(u32 offset, ValueWithShadow<u16>) = 0;
virtual void write32(u32 offset, ValueWithShadow<u32>) = 0;
virtual void write64(u32 offset, ValueWithShadow<u64>) = 0;
virtual void write128(u32 offset, ValueWithShadow<u128>) = 0;
virtual void write256(u32 offset, ValueWithShadow<u256>) = 0;
virtual ValueWithShadow<u8> read8(u32 offset) = 0;
virtual ValueWithShadow<u16> read16(u32 offset) = 0;
virtual ValueWithShadow<u32> read32(u32 offset) = 0;
virtual ValueWithShadow<u64> read64(u32 offset) = 0;
virtual ValueWithShadow<u128> read128(u32 offset) = 0;
virtual ValueWithShadow<u256> read256(u32 offset) = 0;
virtual u8* cacheable_ptr([[maybe_unused]] u32 offset) { return nullptr; }

View file

@ -47,6 +47,18 @@ ValueWithShadow<u64> SimpleRegion::read64(u32 offset)
return { *reinterpret_cast<const u64*>(m_data + offset), *reinterpret_cast<const u64*>(m_shadow_data + offset) };
}
ValueWithShadow<u128> SimpleRegion::read128(u32 offset)
{
VERIFY(offset + 15 < size());
return { *reinterpret_cast<const u128*>(m_data + offset), *reinterpret_cast<const u128*>(m_shadow_data + offset) };
}
ValueWithShadow<u256> SimpleRegion::read256(u32 offset)
{
VERIFY(offset + 31 < size());
return { *reinterpret_cast<const u256*>(m_data + offset), *reinterpret_cast<const u256*>(m_shadow_data + offset) };
}
void SimpleRegion::write8(u32 offset, ValueWithShadow<u8> value)
{
VERIFY(offset < size());
@ -74,6 +86,18 @@ void SimpleRegion::write64(u32 offset, ValueWithShadow<u64> value)
*reinterpret_cast<u64*>(m_data + offset) = value.value();
*reinterpret_cast<u64*>(m_shadow_data + offset) = value.shadow();
}
void SimpleRegion::write128(u32 offset, ValueWithShadow<u128> value)
{
VERIFY(offset + 15 < size());
*reinterpret_cast<u128*>(m_data + offset) = value.value();
*reinterpret_cast<u128*>(m_shadow_data + offset) = value.shadow();
}
void SimpleRegion::write256(u32 offset, ValueWithShadow<u256> value)
{
VERIFY(offset + 31 < size());
*reinterpret_cast<u256*>(m_data + offset) = value.value();
*reinterpret_cast<u256*>(m_shadow_data + offset) = value.shadow();
}
u8* SimpleRegion::cacheable_ptr(u32 offset)
{

View file

@ -19,11 +19,15 @@ public:
virtual ValueWithShadow<u16> read16(u32 offset) override;
virtual ValueWithShadow<u32> read32(u32 offset) override;
virtual ValueWithShadow<u64> read64(u32 offset) override;
virtual ValueWithShadow<u128> read128(u32 offset) override;
virtual ValueWithShadow<u256> read256(u32 offset) override;
virtual void write8(u32 offset, ValueWithShadow<u8>) override;
virtual void write16(u32 offset, ValueWithShadow<u16>) override;
virtual void write32(u32 offset, ValueWithShadow<u32>) override;
virtual void write64(u32 offset, ValueWithShadow<u64>) override;
virtual void write128(u32 offset, ValueWithShadow<u128>) override;
virtual void write256(u32 offset, ValueWithShadow<u256>) override;
virtual u8* data() override { return m_data; }
virtual u8* shadow_data() override { return m_shadow_data; }

View file

@ -133,6 +133,25 @@ ValueWithShadow<u64> SoftCPU::read_memory64(X86::LogicalAddress address)
return value;
}
ValueWithShadow<u128> SoftCPU::read_memory128(X86::LogicalAddress address)
{
VERIFY(address.selector() == 0x1b || address.selector() == 0x23 || address.selector() == 0x2b);
auto value = m_emulator.mmu().read128(address);
#if MEMORY_DEBUG
outln("\033[36;1mread_memory128: @{:04x}:{:08x} -> {:032x} ({:032x})\033[0m", address.selector(), address.offset(), value, value.shadow());
#endif
return value;
}
ValueWithShadow<u256> SoftCPU::read_memory256(X86::LogicalAddress address)
{
VERIFY(address.selector() == 0x1b || address.selector() == 0x23 || address.selector() == 0x2b);
auto value = m_emulator.mmu().read256(address);
#if MEMORY_DEBUG
outln("\033[36;1mread_memory256: @{:04x}:{:08x} -> {:064x} ({:064x})\033[0m", address.selector(), address.offset(), value, value.shadow());
#endif
return value;
}
void SoftCPU::write_memory8(X86::LogicalAddress address, ValueWithShadow<u8> value)
{
VERIFY(address.selector() == 0x23 || address.selector() == 0x2b);
@ -161,6 +180,24 @@ void SoftCPU::write_memory64(X86::LogicalAddress address, ValueWithShadow<u64> v
m_emulator.mmu().write64(address, value);
}
void SoftCPU::write_memory128(X86::LogicalAddress address, ValueWithShadow<u128> value)
{
VERIFY(address.selector() == 0x23 || address.selector() == 0x2b);
#if MEMORY_DEBUG
outln("\033[36;1mwrite_memory128: @{:04x}:{:08x} <- {:032x} ({:032x})\033[0m", address.selector(), address.offset(), value, value.shadow());
#endif
m_emulator.mmu().write128(address, value);
}
void SoftCPU::write_memory256(X86::LogicalAddress address, ValueWithShadow<u256> value)
{
VERIFY(address.selector() == 0x23 || address.selector() == 0x2b);
#if MEMORY_DEBUG
outln("\033[36;1mwrite_memory256: @{:04x}:{:08x} <- {:064x} ({:064x})\033[0m", address.selector(), address.offset(), value, value.shadow());
#endif
m_emulator.mmu().write256(address, value);
}
void SoftCPU::push_string(const StringView& string)
{
size_t space_to_allocate = round_up_to_power_of_two(string.length() + 1, 16);

View file

@ -39,6 +39,8 @@ public:
using ValueWithShadowType16 = ValueWithShadow<u16>;
using ValueWithShadowType32 = ValueWithShadow<u32>;
using ValueWithShadowType64 = ValueWithShadow<u64>;
using ValueWithShadowType128 = ValueWithShadow<u128>;
using ValueWithShadowType256 = ValueWithShadow<u256>;
explicit SoftCPU(Emulator&);
void dump() const;
@ -347,6 +349,8 @@ public:
ValueWithShadow<u16> read_memory16(X86::LogicalAddress);
ValueWithShadow<u32> read_memory32(X86::LogicalAddress);
ValueWithShadow<u64> read_memory64(X86::LogicalAddress);
ValueWithShadow<u128> read_memory128(X86::LogicalAddress);
ValueWithShadow<u256> read_memory256(X86::LogicalAddress);
template<typename T>
ValueWithShadow<T> read_memory(X86::LogicalAddress address)
@ -357,12 +361,20 @@ public:
return read_memory16(address);
if constexpr (sizeof(T) == 4)
return read_memory32(address);
if constexpr (sizeof(T) == 8)
return read_memory64(address);
if constexpr (sizeof(T) == 16)
return read_memory128(address);
if constexpr (sizeof(T) == 32)
return read_memory256(address);
}
void write_memory8(X86::LogicalAddress, ValueWithShadow<u8>);
void write_memory16(X86::LogicalAddress, ValueWithShadow<u16>);
void write_memory32(X86::LogicalAddress, ValueWithShadow<u32>);
void write_memory64(X86::LogicalAddress, ValueWithShadow<u64>);
void write_memory128(X86::LogicalAddress, ValueWithShadow<u128>);
void write_memory256(X86::LogicalAddress, ValueWithShadow<u256>);
template<typename T>
void write_memory(X86::LogicalAddress address, ValueWithShadow<T> data)
@ -373,6 +385,12 @@ public:
return write_memory16(address, data);
if constexpr (sizeof(T) == 4)
return write_memory32(address, data);
if constexpr (sizeof(T) == 8)
return write_memory64(address, data);
if constexpr (sizeof(T) == 16)
return write_memory128(address, data);
if constexpr (sizeof(T) == 32)
return write_memory256(address, data);
}
bool evaluate_condition(u8 condition) const

View file

@ -163,6 +163,42 @@ ValueWithShadow<u64> SoftMMU::read64(X86::LogicalAddress address)
return region->read64(address.offset() - region->base());
}
ValueWithShadow<u128> SoftMMU::read128(X86::LogicalAddress address)
{
auto* region = find_region(address);
if (!region) {
reportln("SoftMMU::read128: No region for @ {:p}", address.offset());
m_emulator.dump_backtrace();
TODO();
}
if (!region->is_readable()) {
reportln("SoftMMU::read128: Non-readable region @ {:p}", address.offset());
m_emulator.dump_backtrace();
TODO();
}
return region->read128(address.offset() - region->base());
}
ValueWithShadow<u256> SoftMMU::read256(X86::LogicalAddress address)
{
auto* region = find_region(address);
if (!region) {
reportln("SoftMMU::read256: No region for @ {:p}", address.offset());
m_emulator.dump_backtrace();
TODO();
}
if (!region->is_readable()) {
reportln("SoftMMU::read256: Non-readable region @ {:p}", address.offset());
m_emulator.dump_backtrace();
TODO();
}
return region->read256(address.offset() - region->base());
}
void SoftMMU::write8(X86::LogicalAddress address, ValueWithShadow<u8> value)
{
auto* region = find_region(address);
@ -234,6 +270,42 @@ void SoftMMU::write64(X86::LogicalAddress address, ValueWithShadow<u64> value)
region->write64(address.offset() - region->base(), value);
}
void SoftMMU::write128(X86::LogicalAddress address, ValueWithShadow<u128> value)
{
auto* region = find_region(address);
if (!region) {
reportln("SoftMMU::write128: No region for @ {:p}", address.offset());
m_emulator.dump_backtrace();
TODO();
}
if (!region->is_writable()) {
reportln("SoftMMU::write128: Non-writable region @ {:p}", address.offset());
m_emulator.dump_backtrace();
TODO();
}
region->write128(address.offset() - region->base(), value);
}
void SoftMMU::write256(X86::LogicalAddress address, ValueWithShadow<u256> value)
{
auto* region = find_region(address);
if (!region) {
reportln("SoftMMU::write256: No region for @ {:p}", address.offset());
m_emulator.dump_backtrace();
TODO();
}
if (!region->is_writable()) {
reportln("SoftMMU::write256: Non-writable region @ {:p}", address.offset());
m_emulator.dump_backtrace();
TODO();
}
region->write256(address.offset() - region->base(), value);
}
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.

View file

@ -26,11 +26,15 @@ public:
ValueWithShadow<u16> read16(X86::LogicalAddress);
ValueWithShadow<u32> read32(X86::LogicalAddress);
ValueWithShadow<u64> read64(X86::LogicalAddress);
ValueWithShadow<u128> read128(X86::LogicalAddress);
ValueWithShadow<u256> read256(X86::LogicalAddress);
void write8(X86::LogicalAddress, ValueWithShadow<u8>);
void write16(X86::LogicalAddress, ValueWithShadow<u16>);
void write32(X86::LogicalAddress, ValueWithShadow<u32>);
void write64(X86::LogicalAddress, ValueWithShadow<u64>);
void write128(X86::LogicalAddress, ValueWithShadow<u128>);
void write256(X86::LogicalAddress, ValueWithShadow<u256>);
ALWAYS_INLINE Region* find_region(X86::LogicalAddress address)
{

View file

@ -4,13 +4,19 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <AK/Platform.h>
#pragma once
#include <AK/Format.h>
#include <AK/Platform.h>
#include <LibX86/Types.h>
#include <string.h>
namespace UserspaceEmulator {
constexpr u64 _inititalized_64 = 0x01010101'01010101LLU;
constexpr u128 _initialized_128 = u128(_inititalized_64, _inititalized_64);
constexpr u256 _initialized_256 = u256(_initialized_128, _initialized_128);
template<typename T>
class ValueAndShadowReference;
@ -32,6 +38,12 @@ public:
bool is_uninitialized() const
{
if constexpr (sizeof(T) == 32)
return (m_shadow & _initialized_256) != _initialized_256;
if constexpr (sizeof(T) == 16)
return (m_shadow & _initialized_128) != _initialized_128;
if constexpr (sizeof(T) == 8)
return (m_shadow & _inititalized_64) != _inititalized_64;
if constexpr (sizeof(T) == 4)
return (m_shadow & 0x01010101) != 0x01010101;
if constexpr (sizeof(T) == 2)
@ -42,6 +54,12 @@ public:
void set_initialized()
{
if constexpr (sizeof(T) == 32)
m_shadow = _initialized_256;
if constexpr (sizeof(T) == 16)
m_shadow = _initialized_128;
if constexpr (sizeof(T) == 8)
m_shadow = _inititalized_64;
if constexpr (sizeof(T) == 4)
m_shadow = 0x01010101;
if constexpr (sizeof(T) == 2)
@ -68,6 +86,12 @@ public:
bool is_uninitialized() const
{
if constexpr (sizeof(T) == 32)
return (m_shadow & _initialized_256) != _initialized_256;
if constexpr (sizeof(T) == 16)
return (m_shadow & _initialized_128) != _initialized_128;
if constexpr (sizeof(T) == 8)
return (m_shadow & _inititalized_64) != _inititalized_64;
if constexpr (sizeof(T) == 4)
return (m_shadow & 0x01010101) != 0x01010101;
if constexpr (sizeof(T) == 2)
@ -92,8 +116,12 @@ private:
template<typename T>
ALWAYS_INLINE ValueWithShadow<T> shadow_wrap_as_initialized(T value)
{
if constexpr (sizeof(T) == 32)
return { value, _initialized_256 };
if constexpr (sizeof(T) == 16)
return { value, _initialized_128 };
if constexpr (sizeof(T) == 8)
return { value, 0x01010101'01010101LLU };
return { value, _inititalized_64 };
if constexpr (sizeof(T) == 4)
return { value, 0x01010101 };
if constexpr (sizeof(T) == 2)
@ -149,3 +177,7 @@ struct AK::Formatter<UserspaceEmulator::ValueWithShadow<T>> : AK::Formatter<T> {
return Formatter<T>::format(builder, value.value());
}
};
#undef INITIALIZED_64
#undef INITIALIZED_128
#undef INITIALIZED_256

View file

@ -380,6 +380,10 @@ public:
void write32(CPU&, const Instruction&, T);
template<typename CPU, typename T>
void write64(CPU&, const Instruction&, T);
template<typename CPU, typename T>
void write128(CPU&, const Instruction&, T);
template<typename CPU, typename T>
void write256(CPU&, const Instruction&, T);
template<typename CPU>
typename CPU::ValueWithShadowType8 read8(CPU&, const Instruction&);
@ -389,6 +393,10 @@ public:
typename CPU::ValueWithShadowType32 read32(CPU&, const Instruction&);
template<typename CPU>
typename CPU::ValueWithShadowType64 read64(CPU&, const Instruction&);
template<typename CPU>
typename CPU::ValueWithShadowType128 read128(CPU&, const Instruction&);
template<typename CPU>
typename CPU::ValueWithShadowType256 read256(CPU&, const Instruction&);
template<typename CPU>
LogicalAddress resolve(const CPU&, const Instruction&);
@ -680,6 +688,22 @@ ALWAYS_INLINE void MemoryOrRegisterReference::write64(CPU& cpu, const Instructio
cpu.write_memory64(address, value);
}
template<typename CPU, typename T>
ALWAYS_INLINE void MemoryOrRegisterReference::write128(CPU& cpu, const Instruction& insn, T value)
{
VERIFY(!is_register());
auto address = resolve(cpu, insn);
cpu.write_memory128(address, value);
}
template<typename CPU, typename T>
ALWAYS_INLINE void MemoryOrRegisterReference::write256(CPU& cpu, const Instruction& insn, T value)
{
VERIFY(!is_register());
auto address = resolve(cpu, insn);
cpu.write_memory256(address, value);
}
template<typename CPU>
ALWAYS_INLINE typename CPU::ValueWithShadowType8 MemoryOrRegisterReference::read8(CPU& cpu, const Instruction& insn)
{
@ -718,6 +742,22 @@ ALWAYS_INLINE typename CPU::ValueWithShadowType64 MemoryOrRegisterReference::rea
return cpu.read_memory64(address);
}
template<typename CPU>
ALWAYS_INLINE typename CPU::ValueWithShadowType128 MemoryOrRegisterReference::read128(CPU& cpu, const Instruction& insn)
{
VERIFY(!is_register());
auto address = resolve(cpu, insn);
return cpu.read_memory128(address);
}
template<typename CPU>
ALWAYS_INLINE typename CPU::ValueWithShadowType256 MemoryOrRegisterReference::read256(CPU& cpu, const Instruction& insn)
{
VERIFY(!is_register());
auto address = resolve(cpu, insn);
return cpu.read_memory256(address);
}
template<typename InstructionStreamType>
ALWAYS_INLINE Instruction Instruction::from_stream(InstructionStreamType& stream, bool o32, bool a32)
{