Shrinking alloy memory interface so that alloy-sandbox doesn't need xe.

This commit is contained in:
Ben Vanik 2014-08-19 21:02:15 -07:00
parent 76d524b655
commit 48a0e5c601
23 changed files with 230 additions and 192 deletions

View File

@ -1499,7 +1499,9 @@ int Translate_LOAD(TranslationContext& ctx, Instr* i) {
void MarkPageDirty(IntCodeState& ics, uint32_t address) {
// 16KB pages.
ics.page_table[(address >> 14) & 0x7FFF] = 1;
if (ics.page_table) {
ics.page_table[(address >> 14) & 0x7FFF] = 1;
}
}
uint32_t IntCode_STORE_I8(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;

View File

@ -1557,9 +1557,12 @@ EMITTER_OPCODE_TABLE(
// Note: most *should* be aligned, but needs to be checked!
void EmitMarkPageDirty(X64Emitter& e, RegExp& addr) {
// 16KB pages.
e.shr(e.eax, 14);
e.and(e.eax, 0x7FFF);
e.mov(e.byte[e.rdx + e.rax + e.page_table_address()], 1);
auto page_table_address = e.page_table_address();
if (page_table_address) {
e.shr(e.eax, 14);
e.and(e.eax, 0x7FFF);
e.mov(e.byte[e.rdx + e.rax + page_table_address], 1);
}
}
EMITTER(STORE_I8, MATCH(I<OPCODE_STORE, VoidOp, I64<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) {

View File

@ -172,7 +172,7 @@ typedef struct alignas(64) PPCContext_s {
uint32_t thread_id;
// Reserve address for load acquire/store release. Shared.
uint32_t* reserve_address;
uint64_t* reserve_address;
// Runtime-specific data pointer. Used on callbacks to get access to the
// current runtime and its data.

View File

@ -61,4 +61,43 @@ uint64_t Memory::SearchAligned(uint64_t start, uint64_t end,
return 0;
}
SimpleMemory::SimpleMemory(size_t capacity) : memory_(capacity) {
membase_ = reinterpret_cast<uint8_t*>(memory_.data());
reserve_address_ = capacity - 8;
}
SimpleMemory::~SimpleMemory() = default;
uint8_t SimpleMemory::LoadI8(uint64_t address) {
return poly::load<uint8_t>(membase_ + address);
}
uint16_t SimpleMemory::LoadI16(uint64_t address) {
return poly::load<uint16_t>(membase_ + address);
}
uint32_t SimpleMemory::LoadI32(uint64_t address) {
return poly::load<uint32_t>(membase_ + address);
}
uint64_t SimpleMemory::LoadI64(uint64_t address) {
return poly::load<uint64_t>(membase_ + address);
}
void SimpleMemory::StoreI8(uint64_t address, uint8_t value) {
poly::store<uint8_t>(membase_ + address, value);
}
void SimpleMemory::StoreI16(uint64_t address, uint16_t value) {
poly::store<uint16_t>(membase_ + address, value);
}
void SimpleMemory::StoreI32(uint64_t address, uint32_t value) {
poly::store<uint32_t>(membase_ + address, value);
}
void SimpleMemory::StoreI64(uint64_t address, uint64_t value) {
poly::store<uint64_t>(membase_ + address, value);
}
} // namespace alloy

View File

@ -14,23 +14,6 @@
namespace alloy {
enum {
MEMORY_FLAG_64KB_PAGES = (1 << 1),
MEMORY_FLAG_ZERO = (1 << 2),
MEMORY_FLAG_PHYSICAL = (1 << 3),
};
// Equivalent to the Win32 MEMORY_BASIC_INFORMATION struct.
struct AllocationInfo {
uint64_t base_address;
uint64_t allocation_base;
uint32_t allocation_protect; // TBD
size_t region_size;
uint32_t state; // TBD
uint32_t protect; // TBD
uint32_t type; // TBD
};
class Memory {
public:
Memory();
@ -40,8 +23,9 @@ class Memory {
inline uint8_t* Translate(uint64_t guest_address) const {
return membase_ + guest_address;
};
inline uint32_t* reserve_address() { return &reserve_address_; }
inline uint64_t* reserve_address() { return &reserve_address_; }
// TODO(benvanik): remove with GPU refactor.
virtual uint64_t page_table() const = 0;
uint64_t trace_base() const { return trace_base_; }
@ -49,6 +33,7 @@ class Memory {
virtual int Initialize();
// TODO(benvanik): make poly memory utils for these.
void Zero(uint64_t address, size_t size);
void Fill(uint64_t address, size_t size, uint8_t value);
void Copy(uint64_t dest, uint64_t src, size_t size);
@ -56,6 +41,7 @@ class Memory {
uint64_t SearchAligned(uint64_t start, uint64_t end, const uint32_t* values,
size_t value_count);
// TODO(benvanik): remove with IVM.
virtual uint8_t LoadI8(uint64_t address) = 0;
virtual uint16_t LoadI16(uint64_t address) = 0;
virtual uint32_t LoadI32(uint64_t address) = 0;
@ -65,24 +51,34 @@ class Memory {
virtual void StoreI32(uint64_t address, uint32_t value) = 0;
virtual void StoreI64(uint64_t address, uint64_t value) = 0;
virtual uint64_t HeapAlloc(uint64_t base_address, size_t size, uint32_t flags,
uint32_t alignment = 0x20) = 0;
virtual int HeapFree(uint64_t address, size_t size) = 0;
virtual bool QueryInformation(uint64_t base_address,
AllocationInfo* mem_info) = 0;
virtual size_t QuerySize(uint64_t base_address) = 0;
virtual int Protect(uint64_t address, size_t size, uint32_t access) = 0;
virtual uint32_t QueryProtect(uint64_t address) = 0;
protected:
size_t system_page_size_;
uint8_t* membase_;
uint32_t reserve_address_;
uint64_t reserve_address_;
uint64_t trace_base_;
};
class SimpleMemory : public Memory {
public:
SimpleMemory(size_t capacity);
~SimpleMemory() override;
uint64_t page_table() const override { return 0; }
// TODO(benvanik): remove with IVM.
uint8_t LoadI8(uint64_t address) override;
uint16_t LoadI16(uint64_t address) override;
uint32_t LoadI32(uint64_t address) override;
uint64_t LoadI64(uint64_t address) override;
void StoreI8(uint64_t address, uint8_t value) override;
void StoreI16(uint64_t address, uint16_t value) override;
void StoreI32(uint64_t address, uint32_t value) override;
void StoreI64(uint64_t address, uint64_t value) override;
private:
std::vector<uint8_t> memory_;
};
} // namespace alloy
#endif // ALLOY_MEMORY_H_

View File

@ -15,11 +15,7 @@ namespace runtime {
RawModule::RawModule(Runtime* runtime)
: Module(runtime), base_address_(0), low_address_(0), high_address_(0) {}
RawModule::~RawModule() {
if (base_address_) {
memory_->HeapFree(base_address_, high_address_ - low_address_);
}
}
RawModule::~RawModule() {}
int RawModule::LoadFile(uint64_t base_address, const std::string& path) {
FILE* file = fopen(path.c_str(), "rb");
@ -28,15 +24,12 @@ int RawModule::LoadFile(uint64_t base_address, const std::string& path) {
fseek(file, 0, SEEK_SET);
// Allocate memory.
base_address_ =
memory_->HeapAlloc(base_address, file_length, MEMORY_FLAG_ZERO);
if (!base_address_) {
fclose(file);
return 1;
}
// Since we have no real heap just load it wherever.
base_address_ = base_address;
uint8_t* p = memory_->Translate(base_address_);
memset(p, 0, file_length);
// Read into memory.
uint8_t* p = memory_->Translate(base_address_);
fread(p, file_length, 1, file);
fclose(file);

View File

@ -48,7 +48,7 @@ X_STATUS AudioSystem::Setup() {
new XenonThreadState(emulator_->processor()->runtime(), 0, 16 * 1024, 0);
thread_state_->set_name("Audio Worker");
thread_block_ =
(uint32_t)memory_->HeapAlloc(0, 2048, alloy::MEMORY_FLAG_ZERO);
(uint32_t)memory_->HeapAlloc(0, 2048, MEMORY_FLAG_ZERO);
thread_state_->context()->r[13] = thread_block_;
// Create worker thread.

View File

@ -12,13 +12,9 @@
#include <xenia/common.h>
#include <alloy/memory.h>
namespace xe {
using Memory = alloy::Memory;
} // namespace xe
#include <xenia/core/ref.h>
#include <xenia/core/run_loop.h>
#include <xenia/core/socket.h>
#include <xenia/memory.h>
#endif // XENIA_CORE_H_

View File

@ -12,7 +12,6 @@
#include <xenia/emulator.h>
#include <xenia/export_resolver.h>
#include <xenia/cpu/cpu-private.h>
#include <xenia/cpu/xenon_memory.h>
#include <xenia/cpu/xenon_runtime.h>
#include <xenia/cpu/xex_module.h>

View File

@ -19,6 +19,7 @@
XEDECLARECLASS2(alloy, runtime, Breakpoint);
XEDECLARECLASS1(xe, Emulator);
XEDECLARECLASS1(xe, ExportResolver);
XEDECLARECLASS1(xe, Memory);
XEDECLARECLASS2(xe, cpu, XenonMemory);
XEDECLARECLASS2(xe, cpu, XenonRuntime);
XEDECLARECLASS2(xe, cpu, XenonThreadState);

View File

@ -8,8 +8,6 @@
'mmio_handler.h',
'processor.cc',
'processor.h',
'xenon_memory.cc',
'xenon_memory.h',
'xenon_runtime.cc',
'xenon_runtime.h',
'xenon_thread_state.cc',

View File

@ -10,25 +10,20 @@
#include <xenia/cpu/xenon_runtime.h>
#include <alloy/frontend/ppc/ppc_frontend.h>
#include <xenia/cpu/xenon_thread_state.h>
using namespace alloy;
using namespace alloy::frontend::ppc;
using namespace alloy::runtime;
using namespace xe;
using namespace xe::cpu;
XenonRuntime::XenonRuntime(alloy::Memory* memory,
ExportResolver* export_resolver,
XenonRuntime::XenonRuntime(Memory* memory, ExportResolver* export_resolver,
uint32_t debug_info_flags, uint32_t trace_flags)
: Runtime(memory, debug_info_flags, trace_flags),
export_resolver_(export_resolver) {}
XenonRuntime::~XenonRuntime() = default;
int XenonRuntime::Initialize(std::unique_ptr<backend::Backend> backend) {
std::unique_ptr<PPCFrontend> frontend(new PPCFrontend(this));
int XenonRuntime::Initialize(std::unique_ptr<alloy::backend::Backend> backend) {
auto frontend = std::make_unique<alloy::frontend::ppc::PPCFrontend>(this);
// TODO(benvanik): set options/etc.
int result = Runtime::Initialize(std::move(frontend), std::move(backend));

View File

@ -24,7 +24,7 @@ XenonThreadState::XenonThreadState(XenonRuntime* runtime, uint32_t thread_id,
: ThreadState(runtime, thread_id),
stack_size_(stack_size),
thread_state_address_(thread_state_address) {
stack_address_ = memory_->HeapAlloc(0, stack_size, MEMORY_FLAG_ZERO);
stack_address_ = xenon_memory()->HeapAlloc(0, stack_size, MEMORY_FLAG_ZERO);
assert_not_zero(stack_address_);
// Allocate with 64b alignment.
@ -56,7 +56,7 @@ XenonThreadState::~XenonThreadState() {
runtime_->debugger()->OnThreadDestroyed(this);
xe_free_aligned(context_);
memory_->HeapFree(stack_address_, stack_size_);
xenon_memory()->HeapFree(stack_address_, stack_size_);
}
void XenonThreadState::WriteRegisters(xdb::protocol::Registers* registers) {

View File

@ -27,13 +27,13 @@ class XenonRuntime;
using PPCContext = alloy::frontend::ppc::PPCContext;
class XenonThreadState : public alloy::runtime::ThreadState {
public:
XenonThreadState(XenonRuntime* runtime, uint32_t thread_id,
size_t stack_size, uint64_t thread_state_address);
public:
XenonThreadState(XenonRuntime* runtime, uint32_t thread_id, size_t stack_size,
uint64_t thread_state_address);
virtual ~XenonThreadState();
Memory* xenon_memory() { return static_cast<Memory*>(memory_); }
uint64_t stack_address() const { return stack_address_; }
size_t stack_size() const { return stack_size_; }
uint64_t thread_state_address() const { return thread_state_address_; }
@ -41,18 +41,16 @@ public:
void WriteRegisters(xdb::protocol::Registers* registers);
private:
uint64_t stack_address_;
size_t stack_size_;
uint64_t thread_state_address_;
private:
uint64_t stack_address_;
size_t stack_size_;
uint64_t thread_state_address_;
// NOTE: must be 64b aligned for SSE ops.
PPCContext* context_;
};
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_XENON_THREAD_STATE_H_

View File

@ -13,13 +13,13 @@
#include <xdb/protocol.h>
#include <xenia/apu/apu.h>
#include <xenia/cpu/cpu.h>
#include <xenia/cpu/xenon_memory.h>
#include <xenia/gpu/gpu.h>
#include <xenia/hid/hid.h>
#include <xenia/kernel/kernel.h>
#include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/modules.h>
#include <xenia/kernel/fs/filesystem.h>
#include <xenia/memory.h>
#include <xenia/ui/window.h>
namespace xe {
@ -87,7 +87,7 @@ X_STATUS Emulator::Setup() {
XEEXPECTZERO(result);
// Create memory system first, as it is required for other systems.
memory_ = new XenonMemory();
memory_ = new Memory();
XEEXPECTNOTNULL(memory_);
result = memory_->Initialize();
XEEXPECTZERO(result);

View File

@ -14,7 +14,6 @@
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/cpu/xenon_memory.h>
#include <xenia/debug_agent.h>
#include <xenia/kernel/kernel_state.h>
#include <xenia/xbox.h>
@ -55,7 +54,7 @@ class Emulator {
ui::Window* main_window() const { return main_window_; }
void set_main_window(ui::Window* window);
cpu::XenonMemory* memory() const { return memory_; }
Memory* memory() const { return memory_; }
DebugAgent* debug_agent() const { return debug_agent_.get(); }
@ -79,31 +78,29 @@ class Emulator {
private:
X_STATUS CompleteLaunch(const std::wstring& path,
const std::string& module_path);
const std::string& module_path);
std::wstring command_line_;
std::wstring command_line_;
ui::Window* main_window_;
ui::Window* main_window_;
cpu::XenonMemory* memory_;
Memory* memory_;
std::unique_ptr<DebugAgent> debug_agent_;
cpu::Processor* processor_;
apu::AudioSystem* audio_system_;
gpu::GraphicsSystem* graphics_system_;
hid::InputSystem* input_system_;
cpu::Processor* processor_;
apu::AudioSystem* audio_system_;
gpu::GraphicsSystem* graphics_system_;
hid::InputSystem* input_system_;
ExportResolver* export_resolver_;
ExportResolver* export_resolver_;
kernel::fs::FileSystem* file_system_;
kernel::KernelState* kernel_state_;
kernel::XamModule* xam_;
kernel::KernelState* kernel_state_;
kernel::XamModule* xam_;
kernel::XboxkrnlModule* xboxkrnl_;
};
} // namespace xe
#endif // XENIA_EMULATOR_H_

View File

@ -152,7 +152,7 @@ X_STATUS XThread::Create() {
// So, at offset 0x100 we have a 4b pointer to offset 200, then have the
// structure.
thread_state_address_ =
(uint32_t)memory()->HeapAlloc(0, 2048, alloy::MEMORY_FLAG_ZERO);
(uint32_t)memory()->HeapAlloc(0, 2048, MEMORY_FLAG_ZERO);
if (!thread_state_address_) {
XELOGW("Unable to allocate thread state block");
return X_STATUS_NO_MEMORY;
@ -167,13 +167,12 @@ X_STATUS XThread::Create() {
// This is used by interrupts/APCs/etc so we can round-trip pointers through.
scratch_size_ = 4 * 16;
scratch_address_ =
(uint32_t)memory()->HeapAlloc(0, scratch_size_, alloy::MEMORY_FLAG_ZERO);
(uint32_t)memory()->HeapAlloc(0, scratch_size_, MEMORY_FLAG_ZERO);
// Allocate TLS block.
const xe_xex2_header_t* header = module->xex_header();
uint32_t tls_size = header->tls_info.slot_count * header->tls_info.data_size;
tls_address_ =
(uint32_t)memory()->HeapAlloc(0, tls_size, alloy::MEMORY_FLAG_ZERO);
tls_address_ = (uint32_t)memory()->HeapAlloc(0, tls_size, MEMORY_FLAG_ZERO);
if (!tls_address_) {
XELOGW("Unable to allocate thread local storage block");
module->Release();

View File

@ -21,14 +21,14 @@
#include <third_party/mspack/mspack.h>
#include <third_party/pe/pe_image.h>
using namespace alloy;
// using namespace alloy;
DEFINE_bool(xex_dev_key, false, "Use the devkit key.");
typedef struct xe_xex2 {
xe_ref_t ref;
Memory *memory;
xe::Memory *memory;
xe_xex2_header_t header;
@ -44,13 +44,13 @@ int xe_xex2_read_header(const uint8_t *addr, const size_t length,
xe_xex2_header_t *header);
int xe_xex2_decrypt_key(xe_xex2_header_t *header);
int xe_xex2_read_image(xe_xex2_ref xex, const uint8_t *xex_addr,
const size_t xex_length, Memory *memory);
const size_t xex_length, xe::Memory *memory);
int xe_xex2_load_pe(xe_xex2_ref xex);
int xe_xex2_find_import_infos(xe_xex2_ref xex,
const xe_xex2_import_library_t *library);
xe_xex2_ref xe_xex2_load(Memory *memory, const void *addr, const size_t length,
xe_xex2_options_t options) {
xe_xex2_ref xe_xex2_load(xe::Memory *memory, const void *addr,
const size_t length, xe_xex2_options_t options) {
xe_xex2_ref xex = (xe_xex2_ref)xe_calloc(sizeof(xe_xex2));
xe_ref_init((xe_ref)xex);
@ -542,12 +542,13 @@ void xe_xex2_decrypt_buffer(const uint8_t *session_key,
int xe_xex2_read_image_uncompressed(const xe_xex2_header_t *header,
const uint8_t *xex_addr,
const size_t xex_length, Memory *memory) {
const size_t xex_length,
xe::Memory *memory) {
// Allocate in-place the XEX memory.
const size_t exe_length = xex_length - header->exe_offset;
size_t uncompressed_size = exe_length;
uint32_t alloc_result = (uint32_t)memory->HeapAlloc(
header->exe_address, uncompressed_size, MEMORY_FLAG_ZERO);
header->exe_address, uncompressed_size, xe::MEMORY_FLAG_ZERO);
if (!alloc_result) {
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.", header->exe_address,
uncompressed_size);
@ -575,7 +576,7 @@ int xe_xex2_read_image_uncompressed(const xe_xex2_header_t *header,
int xe_xex2_read_image_basic_compressed(const xe_xex2_header_t *header,
const uint8_t *xex_addr,
const size_t xex_length,
Memory *memory) {
xe::Memory *memory) {
const size_t exe_length = xex_length - header->exe_offset;
const uint8_t *source_buffer = (const uint8_t *)xex_addr + header->exe_offset;
const uint8_t *p = source_buffer;
@ -592,7 +593,7 @@ int xe_xex2_read_image_basic_compressed(const xe_xex2_header_t *header,
// Allocate in-place the XEX memory.
uint32_t alloc_result = (uint32_t)memory->HeapAlloc(
header->exe_address, uncompressed_size, MEMORY_FLAG_ZERO);
header->exe_address, uncompressed_size, xe::MEMORY_FLAG_ZERO);
if (!alloc_result) {
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.", header->exe_address,
uncompressed_size);
@ -645,7 +646,7 @@ XECLEANUP:
int xe_xex2_read_image_compressed(const xe_xex2_header_t *header,
const uint8_t *xex_addr,
const size_t xex_length, Memory *memory) {
const size_t xex_length, xe::Memory *memory) {
const size_t exe_length = xex_length - header->exe_offset;
const uint8_t *exe_buffer = (const uint8_t *)xex_addr + header->exe_offset;
@ -726,7 +727,7 @@ int xe_xex2_read_image_compressed(const xe_xex2_header_t *header,
// Allocate in-place the XEX memory.
uint32_t alloc_result = (uint32_t)memory->HeapAlloc(
header->exe_address, uncompressed_size, MEMORY_FLAG_ZERO);
header->exe_address, uncompressed_size, xe::MEMORY_FLAG_ZERO);
if (!alloc_result) {
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.", header->exe_address,
uncompressed_size);
@ -778,7 +779,7 @@ XECLEANUP:
}
int xe_xex2_read_image(xe_xex2_ref xex, const uint8_t *xex_addr,
const size_t xex_length, Memory *memory) {
const size_t xex_length, xe::Memory *memory) {
const xe_xex2_header_t *header = &xex->header;
switch (header->file_format_info.compression_type) {
case XEX_COMPRESSION_NONE:

View File

@ -158,7 +158,7 @@ SHIM_CALL NtQueryVirtualMemory_shim(PPCContext* ppc_state, KernelState* state) {
XELOGD("NtQueryVirtualMemory(%.8X, %.8X)", base_address,
memory_basic_information_ptr);
alloy::AllocationInfo mem_info;
AllocationInfo mem_info;
size_t result = state->memory()->QueryInformation(base_address, &mem_info);
if (!result) {
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER);
@ -250,7 +250,7 @@ SHIM_CALL MmAllocatePhysicalMemoryEx_shim(PPCContext* ppc_state,
assert_true(max_addr_range == 0xFFFFFFFF);
// Allocate.
uint32_t flags = alloy::MEMORY_FLAG_PHYSICAL;
uint32_t flags = MEMORY_FLAG_PHYSICAL;
uint32_t base_address = (uint32_t)state->memory()->HeapAlloc(
0, adjusted_size, flags, adjusted_alignment);
if (!base_address) {
@ -410,7 +410,7 @@ SHIM_CALL ExAllocatePoolTypeWithTag_shim(PPCContext* ppc_state,
}
uint32_t addr = (uint32_t)state->memory()->HeapAlloc(
0, adjusted_size, alloy::MEMORY_FLAG_ZERO, alignment);
0, adjusted_size, MEMORY_FLAG_ZERO, alignment);
SHIM_SET_RETURN_32(addr);
}

View File

@ -7,16 +7,16 @@
******************************************************************************
*/
#include <xenia/cpu/xenon_memory.h>
#include <xenia/memory.h>
#include <algorithm>
#include <mutex>
#include <gflags/gflags.h>
#include <poly/math.h>
#include <xenia/cpu/mmio_handler.h>
using namespace alloy;
using namespace xe::cpu;
using namespace xe;
// TODO(benvanik): move xbox.h out
#include <xenia/xbox.h>
@ -84,10 +84,10 @@ DEFINE_bool(scribble_heap, false,
#define XENON_MEMORY_VIRTUAL_HEAP_LOW 0x20000000
#define XENON_MEMORY_VIRTUAL_HEAP_HIGH 0x40000000
class xe::cpu::XenonMemoryHeap {
class xe::MemoryHeap {
public:
XenonMemoryHeap(XenonMemory* memory, bool is_physical);
~XenonMemoryHeap();
MemoryHeap(Memory* memory, bool is_physical);
~MemoryHeap();
int Initialize(uint64_t low, uint64_t high);
@ -104,7 +104,7 @@ class xe::cpu::XenonMemoryHeap {
void* context);
private:
XenonMemory* memory_;
Memory* memory_;
uint32_t heap_id_;
bool is_physical_;
std::mutex lock_;
@ -112,15 +112,15 @@ class xe::cpu::XenonMemoryHeap {
uint8_t* ptr_;
mspace space_;
};
uint32_t XenonMemoryHeap::next_heap_id_ = 1;
uint32_t MemoryHeap::next_heap_id_ = 1;
XenonMemory::XenonMemory()
: Memory(), mapping_(0), mapping_base_(0), page_table_(0) {
virtual_heap_ = new XenonMemoryHeap(this, false);
physical_heap_ = new XenonMemoryHeap(this, true);
Memory::Memory()
: alloy::Memory(), mapping_(0), mapping_base_(0), page_table_(0) {
virtual_heap_ = new MemoryHeap(this, false);
physical_heap_ = new MemoryHeap(this, true);
}
XenonMemory::~XenonMemory() {
Memory::~Memory() {
// Uninstall the MMIO handler, as we won't be able to service more
// requests.
mmio_handler_.reset();
@ -142,8 +142,8 @@ XenonMemory::~XenonMemory() {
}
}
int XenonMemory::Initialize() {
int result = Memory::Initialize();
int Memory::Initialize() {
int result = alloy::Memory::Initialize();
if (result) {
return result;
}
@ -196,7 +196,7 @@ int XenonMemory::Initialize() {
VirtualAlloc(Translate(0xC0000000), 0x00100000, MEM_COMMIT, PAGE_READWRITE);
// Add handlers for MMIO.
mmio_handler_ = MMIOHandler::Install(mapping_base_);
mmio_handler_ = cpu::MMIOHandler::Install(mapping_base_);
if (!mmio_handler_) {
XELOGE("Unable to install MMIO handlers");
assert_always();
@ -227,7 +227,7 @@ const static struct {
0xC0000000, 0xDFFFFFFF, 0x00000000, // - physical 16mb pages
0xE0000000, 0xFFFFFFFF, 0x00000000, // - physical 4k pages
};
int XenonMemory::MapViews(uint8_t* mapping_base) {
int Memory::MapViews(uint8_t* mapping_base) {
assert_true(poly::countof(map_info) == poly::countof(views_.all_views));
for (size_t n = 0; n < poly::countof(map_info); n++) {
#if XE_PLATFORM_WIN32
@ -252,7 +252,7 @@ XECLEANUP:
return 1;
}
void XenonMemory::UnmapViews() {
void Memory::UnmapViews() {
for (size_t n = 0; n < poly::countof(views_.all_views); n++) {
if (views_.all_views[n]) {
#if XE_PLATFORM_WIN32
@ -266,9 +266,9 @@ void XenonMemory::UnmapViews() {
}
}
bool XenonMemory::AddMappedRange(uint64_t address, uint64_t mask, uint64_t size,
void* context, MMIOReadCallback read_callback,
MMIOWriteCallback write_callback) {
bool Memory::AddMappedRange(uint64_t address, uint64_t mask, uint64_t size,
void* context, cpu::MMIOReadCallback read_callback,
cpu::MMIOWriteCallback write_callback) {
DWORD protect = PAGE_NOACCESS;
if (!VirtualAlloc(Translate(address), size, MEM_COMMIT, protect)) {
XELOGE("Unable to map range; commit/protect failed");
@ -278,7 +278,7 @@ bool XenonMemory::AddMappedRange(uint64_t address, uint64_t mask, uint64_t size,
read_callback, write_callback);
}
uint8_t XenonMemory::LoadI8(uint64_t address) {
uint8_t Memory::LoadI8(uint64_t address) {
uint64_t value;
if (!mmio_handler_->CheckLoad(address, &value)) {
value = *reinterpret_cast<uint8_t*>(Translate(address));
@ -286,7 +286,7 @@ uint8_t XenonMemory::LoadI8(uint64_t address) {
return static_cast<uint8_t>(value);
}
uint16_t XenonMemory::LoadI16(uint64_t address) {
uint16_t Memory::LoadI16(uint64_t address) {
uint64_t value;
if (!mmio_handler_->CheckLoad(address, &value)) {
value = *reinterpret_cast<uint16_t*>(Translate(address));
@ -294,7 +294,7 @@ uint16_t XenonMemory::LoadI16(uint64_t address) {
return static_cast<uint16_t>(value);
}
uint32_t XenonMemory::LoadI32(uint64_t address) {
uint32_t Memory::LoadI32(uint64_t address) {
uint64_t value;
if (!mmio_handler_->CheckLoad(address, &value)) {
value = *reinterpret_cast<uint32_t*>(Translate(address));
@ -302,7 +302,7 @@ uint32_t XenonMemory::LoadI32(uint64_t address) {
return static_cast<uint32_t>(value);
}
uint64_t XenonMemory::LoadI64(uint64_t address) {
uint64_t Memory::LoadI64(uint64_t address) {
uint64_t value;
if (!mmio_handler_->CheckLoad(address, &value)) {
value = *reinterpret_cast<uint64_t*>(Translate(address));
@ -310,32 +310,32 @@ uint64_t XenonMemory::LoadI64(uint64_t address) {
return static_cast<uint64_t>(value);
}
void XenonMemory::StoreI8(uint64_t address, uint8_t value) {
void Memory::StoreI8(uint64_t address, uint8_t value) {
if (!mmio_handler_->CheckStore(address, value)) {
*reinterpret_cast<uint8_t*>(Translate(address)) = value;
}
}
void XenonMemory::StoreI16(uint64_t address, uint16_t value) {
void Memory::StoreI16(uint64_t address, uint16_t value) {
if (!mmio_handler_->CheckStore(address, value)) {
*reinterpret_cast<uint16_t*>(Translate(address)) = value;
}
}
void XenonMemory::StoreI32(uint64_t address, uint32_t value) {
void Memory::StoreI32(uint64_t address, uint32_t value) {
if (!mmio_handler_->CheckStore(address, value)) {
*reinterpret_cast<uint32_t*>(Translate(address)) = value;
}
}
void XenonMemory::StoreI64(uint64_t address, uint64_t value) {
void Memory::StoreI64(uint64_t address, uint64_t value) {
if (!mmio_handler_->CheckStore(address, value)) {
*reinterpret_cast<uint64_t*>(Translate(address)) = value;
}
}
uint64_t XenonMemory::HeapAlloc(uint64_t base_address, size_t size,
uint32_t flags, uint32_t alignment) {
uint64_t Memory::HeapAlloc(uint64_t base_address, size_t size, uint32_t flags,
uint32_t alignment) {
// If we were given a base address we are outside of the normal heap and
// will place wherever asked (so long as it doesn't overlap the heap).
if (!base_address) {
@ -384,7 +384,7 @@ uint64_t XenonMemory::HeapAlloc(uint64_t base_address, size_t size,
}
}
int XenonMemory::HeapFree(uint64_t address, size_t size) {
int Memory::HeapFree(uint64_t address, size_t size) {
if (address >= XENON_MEMORY_VIRTUAL_HEAP_LOW &&
address < XENON_MEMORY_VIRTUAL_HEAP_HIGH) {
return virtual_heap_->Free(address, size) ? 0 : 1;
@ -398,8 +398,7 @@ int XenonMemory::HeapFree(uint64_t address, size_t size) {
}
}
bool XenonMemory::QueryInformation(uint64_t base_address,
AllocationInfo* mem_info) {
bool Memory::QueryInformation(uint64_t base_address, AllocationInfo* mem_info) {
uint8_t* p = Translate(base_address);
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery(p, &mbi, sizeof(mbi))) {
@ -416,7 +415,7 @@ bool XenonMemory::QueryInformation(uint64_t base_address,
return true;
}
size_t XenonMemory::QuerySize(uint64_t base_address) {
size_t Memory::QuerySize(uint64_t base_address) {
if (base_address >= XENON_MEMORY_VIRTUAL_HEAP_LOW &&
base_address < XENON_MEMORY_VIRTUAL_HEAP_HIGH) {
return virtual_heap_->QuerySize(base_address);
@ -436,7 +435,7 @@ size_t XenonMemory::QuerySize(uint64_t base_address) {
}
}
int XenonMemory::Protect(uint64_t address, size_t size, uint32_t access) {
int Memory::Protect(uint64_t address, size_t size, uint32_t access) {
uint8_t* p = Translate(address);
size_t heap_guard_size = FLAGS_heap_guard_pages * 4096;
@ -452,7 +451,7 @@ int XenonMemory::Protect(uint64_t address, size_t size, uint32_t access) {
return VirtualProtect(p, size, new_protect, &old_protect) == TRUE ? 0 : 1;
}
uint32_t XenonMemory::QueryProtect(uint64_t address) {
uint32_t Memory::QueryProtect(uint64_t address) {
uint8_t* p = Translate(address);
MEMORY_BASIC_INFORMATION info;
size_t info_size = VirtualQuery((void*)p, &info, sizeof(info));
@ -462,12 +461,12 @@ uint32_t XenonMemory::QueryProtect(uint64_t address) {
return info.Protect;
}
XenonMemoryHeap::XenonMemoryHeap(XenonMemory* memory, bool is_physical)
MemoryHeap::MemoryHeap(Memory* memory, bool is_physical)
: memory_(memory), is_physical_(is_physical) {
heap_id_ = next_heap_id_++;
}
XenonMemoryHeap::~XenonMemoryHeap() {
MemoryHeap::~MemoryHeap() {
if (space_) {
std::lock_guard<std::mutex> guard(lock_);
destroy_mspace(space_);
@ -479,7 +478,7 @@ XenonMemoryHeap::~XenonMemoryHeap() {
}
}
int XenonMemoryHeap::Initialize(uint64_t low, uint64_t high) {
int MemoryHeap::Initialize(uint64_t low, uint64_t high) {
// Commit the memory where our heap will live and allocate it.
// TODO(benvanik): replace dlmalloc with an implementation that can commit
// as it goes.
@ -494,8 +493,8 @@ int XenonMemoryHeap::Initialize(uint64_t low, uint64_t high) {
return 0;
}
uint64_t XenonMemoryHeap::Alloc(uint64_t base_address, size_t size,
uint32_t flags, uint32_t alignment) {
uint64_t MemoryHeap::Alloc(uint64_t base_address, size_t size, uint32_t flags,
uint32_t alignment) {
lock_.lock();
size_t alloc_size = size;
size_t heap_guard_size = FLAGS_heap_guard_pages * 4096;
@ -547,7 +546,7 @@ uint64_t XenonMemoryHeap::Alloc(uint64_t base_address, size_t size,
return address;
}
uint64_t XenonMemoryHeap::Free(uint64_t address, size_t size) {
uint64_t MemoryHeap::Free(uint64_t address, size_t size) {
uint8_t* p = memory_->Translate(address);
// Heap allocated address.
@ -590,7 +589,7 @@ uint64_t XenonMemoryHeap::Free(uint64_t address, size_t size) {
return (uint64_t)real_size;
}
size_t XenonMemoryHeap::QuerySize(uint64_t base_address) {
size_t MemoryHeap::QuerySize(uint64_t base_address) {
uint8_t* p = memory_->Translate(base_address);
// Heap allocated address.
@ -605,8 +604,8 @@ size_t XenonMemoryHeap::QuerySize(uint64_t base_address) {
return real_size;
}
void XenonMemoryHeap::Dump() {
XELOGI("XenonMemoryHeap::Dump - %s", is_physical_ ? "physical" : "virtual");
void MemoryHeap::Dump() {
XELOGI("MemoryHeap::Dump - %s", is_physical_ ? "physical" : "virtual");
if (FLAGS_heap_guard_pages) {
XELOGI(" (heap guard pages enabled, stats will be wrong)");
}
@ -622,10 +621,10 @@ void XenonMemoryHeap::Dump() {
mspace_inspect_all(space_, DumpHandler, this);
}
void XenonMemoryHeap::DumpHandler(void* start, void* end, size_t used_bytes,
void* context) {
XenonMemoryHeap* heap = (XenonMemoryHeap*)context;
XenonMemory* memory = heap->memory_;
void MemoryHeap::DumpHandler(void* start, void* end, size_t used_bytes,
void* context) {
MemoryHeap* heap = (MemoryHeap*)context;
Memory* memory = heap->memory_;
size_t heap_guard_size = FLAGS_heap_guard_pages * 4096;
uint64_t start_addr = (uint64_t)start + heap_guard_size;
uint64_t end_addr = (uint64_t)end - heap_guard_size;

View File

@ -7,8 +7,8 @@
******************************************************************************
*/
#ifndef XENIA_CPU_XENON_MEMORY_H_
#define XENIA_CPU_XENON_MEMORY_H_
#ifndef XENIA_MEMORY_H_
#define XENIA_MEMORY_H_
#include <memory>
@ -20,22 +20,41 @@
typedef struct xe_ppc_state xe_ppc_state_t;
namespace xe {
namespace cpu {
class XenonMemoryHeap;
class MemoryHeap;
class XenonMemory : public alloy::Memory {
// TODO(benvanik): move to heap.
enum {
MEMORY_FLAG_64KB_PAGES = (1 << 1),
MEMORY_FLAG_ZERO = (1 << 2),
MEMORY_FLAG_PHYSICAL = (1 << 3),
};
// TODO(benvanik): move to heap.
// Equivalent to the Win32 MEMORY_BASIC_INFORMATION struct.
struct AllocationInfo {
uint64_t base_address;
uint64_t allocation_base;
uint32_t allocation_protect; // TBD
size_t region_size;
uint32_t state; // TBD
uint32_t protect; // TBD
uint32_t type; // TBD
};
class Memory : public alloy::Memory {
public:
XenonMemory();
virtual ~XenonMemory();
Memory();
~Memory() override;
int Initialize() override;
// TODO(benvanik): remove with GPU refactor.
uint64_t page_table() const override { return page_table_; }
bool AddMappedRange(uint64_t address, uint64_t mask, uint64_t size,
void* context, MMIOReadCallback read_callback,
MMIOWriteCallback write_callback);
void* context, cpu::MMIOReadCallback read_callback,
cpu::MMIOWriteCallback write_callback);
uint8_t LoadI8(uint64_t address) override;
uint16_t LoadI16(uint64_t address) override;
@ -47,15 +66,14 @@ class XenonMemory : public alloy::Memory {
void StoreI64(uint64_t address, uint64_t value) override;
uint64_t HeapAlloc(uint64_t base_address, size_t size, uint32_t flags,
uint32_t alignment = 0x20) override;
int HeapFree(uint64_t address, size_t size) override;
uint32_t alignment = 0x20);
int HeapFree(uint64_t address, size_t size);
bool QueryInformation(uint64_t base_address,
alloy::AllocationInfo* mem_info) override;
size_t QuerySize(uint64_t base_address) override;
bool QueryInformation(uint64_t base_address, AllocationInfo* mem_info);
size_t QuerySize(uint64_t base_address);
int Protect(uint64_t address, size_t size, uint32_t access) override;
uint32_t QueryProtect(uint64_t address) override;
int Protect(uint64_t address, size_t size, uint32_t access);
uint32_t QueryProtect(uint64_t address);
private:
int MapViews(uint8_t* mapping_base);
@ -76,17 +94,16 @@ class XenonMemory : public alloy::Memory {
uint8_t* all_views[6];
} views_;
std::unique_ptr<MMIOHandler> mmio_handler_;
std::unique_ptr<cpu::MMIOHandler> mmio_handler_;
XenonMemoryHeap* virtual_heap_;
XenonMemoryHeap* physical_heap_;
MemoryHeap* virtual_heap_;
MemoryHeap* physical_heap_;
uint64_t page_table_;
friend class XenonMemoryHeap;
friend class MemoryHeap;
};
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_XENON_MEMORY_H_
#endif // XENIA_MEMORY_H_

View File

@ -13,6 +13,8 @@
'logging.h',
'malloc.cc',
'malloc.h',
'memory.cc',
'memory.h',
'profiling.cc',
'profiling.h',
'types.h',

View File

@ -15,7 +15,6 @@
#include <alloy/runtime/raw_module.h>
#include <poly/main.h>
#include <poly/poly.h>
#include <xenia/cpu/xenon_memory.h>
#include <gflags/gflags.h>
@ -28,11 +27,12 @@ using alloy::runtime::Runtime;
class ThreadState : public alloy::runtime::ThreadState {
public:
ThreadState(Runtime* runtime, uint32_t thread_id, size_t stack_size,
uint64_t thread_state_address)
uint64_t thread_state_address, uint64_t thread_stack_address)
: alloy::runtime::ThreadState(runtime, thread_id),
stack_address_(thread_stack_address),
stack_size_(stack_size),
thread_state_address_(thread_state_address) {
stack_address_ = memory_->HeapAlloc(0, stack_size, MEMORY_FLAG_ZERO);
memset(memory_->Translate(stack_address_), 0, stack_size_);
// Allocate with 64b alignment.
context_ = (PPCContext*)xe_malloc_aligned(sizeof(PPCContext));
@ -60,7 +60,6 @@ class ThreadState : public alloy::runtime::ThreadState {
~ThreadState() override {
runtime_->debugger()->OnThreadDestroyed(this);
xe_free_aligned(context_);
memory_->HeapFree(stack_address_, stack_size_);
}
PPCContext* context() const { return context_; }
@ -80,7 +79,8 @@ int main(std::vector<std::wstring>& args) {
xe::Profiler::Initialize();
xe::Profiler::ThreadEnter("main");
auto memory = std::make_unique<xe::cpu::XenonMemory>();
size_t memory_size = 16 * 1024 * 1024;
auto memory = std::make_unique<SimpleMemory>(memory_size);
auto runtime = std::make_unique<Runtime>(memory.get());
auto frontend =
@ -97,11 +97,14 @@ int main(std::vector<std::wstring>& args) {
runtime->AddModule(std::move(module));
{
auto thread_state =
std::make_unique<ThreadState>(runtime.get(), 100, 64 * 1024, 0);
uint64_t thread_state_address = 0;
uint64_t stack_address = memory_size - 1024;
uint64_t stack_size = 64 * 1024;
auto thread_state = std::make_unique<ThreadState>(
runtime.get(), 100, stack_address, stack_size, thread_state_address);
alloy::runtime::Function* fn;
runtime->ResolveFunction(0x82000000, &fn);
runtime->ResolveFunction(0x1000, &fn);
auto ctx = thread_state->context();
ctx->lr = 0xBEBEBEBE;
ctx->r[5] = 10;