From f3fe260a179e46a851f1641ea298e4502cd5c28a Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Wed, 4 Nov 2015 06:46:52 -0600 Subject: [PATCH 1/2] Fallback case if indirection table could not be allocated. --- src/xenia/cpu/backend/x64/x64_code_cache.cc | 9 +++++-- src/xenia/cpu/backend/x64/x64_code_cache.h | 1 + src/xenia/cpu/backend/x64/x64_emitter.cc | 27 ++++++++++++++++++--- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.cc b/src/xenia/cpu/backend/x64/x64_code_cache.cc index 8a2a51cde..75df2e385 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.cc +++ b/src/xenia/cpu/backend/x64/x64_code_cache.cc @@ -52,7 +52,6 @@ bool X64CodeCache::Initialize() { "This is likely because the %.8X-%.8X range is in use by some other " "system DLL", kIndirectionTableBase, kIndirectionTableBase + kIndirectionTableSize); - return false; } // Create mmap file. This allows us to share the code cache with the debugger. @@ -91,6 +90,8 @@ void X64CodeCache::set_indirection_default(uint32_t default_value) { void X64CodeCache::AddIndirection(uint32_t guest_address, uint32_t host_address) { + assert_not_null(indirection_table_base_); + uint32_t* indirection_slot = reinterpret_cast( indirection_table_base_ + (guest_address - kIndirectionTableBase)); *indirection_slot = host_address; @@ -98,6 +99,10 @@ void X64CodeCache::AddIndirection(uint32_t guest_address, void X64CodeCache::CommitExecutableRange(uint32_t guest_low, uint32_t guest_high) { + if (!indirection_table_base_) { + return; + } + // Commit the memory. xe::memory::AllocFixed( indirection_table_base_ + (guest_low - kIndirectionTableBase), @@ -178,7 +183,7 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code, // Now that everything is ready, fix up the indirection table. // Note that we do support code that doesn't have an indirection fixup, so // ignore those when we see them. - if (guest_address) { + if (guest_address && indirection_table_base_) { uint32_t* indirection_slot = reinterpret_cast( indirection_table_base_ + (guest_address - kIndirectionTableBase)); *indirection_slot = uint32_t(reinterpret_cast(code_address)); diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.h b/src/xenia/cpu/backend/x64/x64_code_cache.h index 31f001e48..5795f85d7 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.h +++ b/src/xenia/cpu/backend/x64/x64_code_cache.h @@ -41,6 +41,7 @@ class X64CodeCache : public CodeCache { // TODO(benvanik): keep track of code blocks // TODO(benvanik): padding/guards/etc + bool has_indirection_table() { return indirection_table_base_ != nullptr; } void set_indirection_default(uint32_t default_value); void AddIndirection(uint32_t guest_address, uint32_t host_address); diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index b4517bfe5..731025ecd 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -366,12 +366,21 @@ void X64Emitter::Call(const hir::Instr* instr, GuestFunction* function) { // a ResolveFunction call, but makes the table less useful. assert_zero(uint64_t(fn->machine_code()) & 0xFFFFFFFF00000000); mov(eax, uint32_t(uint64_t(fn->machine_code()))); - } else { + } else if (code_cache_->has_indirection_table()) { // Load the pointer to the indirection table maintained in X64CodeCache. // The target dword will either contain the address of the generated code // or a thunk to ResolveAddress. mov(ebx, function->address()); mov(eax, dword[ebx]); + } else { + // Old-style resolve. + // Not too important because indirection table is almost always available. + // TODO: Overwrite the call-site with a straight call. + mov(rax, reinterpret_cast(ResolveFunction)); + mov(rdx, function->address()); + call(rax); + ReloadECX(); + ReloadEDX(); } // Actually jump/call to rax. @@ -403,10 +412,20 @@ void X64Emitter::CallIndirect(const hir::Instr* instr, // Load the pointer to the indirection table maintained in X64CodeCache. // The target dword will either contain the address of the generated code // or a thunk to ResolveAddress. - if (reg.cvt32() != ebx) { - mov(ebx, reg.cvt32()); + if (code_cache_->has_indirection_table()) { + if (reg.cvt32() != ebx) { + mov(ebx, reg.cvt32()); + } + mov(eax, dword[ebx]); + } else { + // Old-style resolve. + // Not too important because indirection table is almost always available. + mov(edx, reg.cvt32()); + mov(rax, reinterpret_cast(ResolveFunction)); + call(rax); + ReloadECX(); + ReloadEDX(); } - mov(eax, dword[ebx]); // Actually jump/call to rax. if (instr->flags & hir::CALL_TAIL) { From 4ca62bf02cb758474e8cd908240572f17810385c Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Wed, 4 Nov 2015 06:47:38 -0600 Subject: [PATCH 2/2] Setup the processor before doing anything else (and return an actual error code if it fails) --- src/xenia/emulator.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index ec87e9ea4..733f021be 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -105,6 +105,9 @@ X_STATUS Emulator::Setup(ui::Window* display_window) { // Initialize the CPU. processor_ = std::make_unique( memory_.get(), export_resolver_.get(), debugger_.get()); + if (!processor_->Setup()) { + return X_STATUS_UNSUCCESSFUL; + } // Initialize the APU. audio_system_ = xe::apu::AudioSystem::Create(processor_.get()); @@ -140,9 +143,6 @@ X_STATUS Emulator::Setup(ui::Window* display_window) { kernel_state_ = std::make_unique(this); // Setup the core components. - if (!processor_->Setup()) { - return result; - } result = graphics_system_->Setup(processor_.get(), display_window_->loop(), display_window_); if (result) {