diff --git a/libxenia.vcxproj b/libxenia.vcxproj index 9bfcc742a..35dd76a06 100644 --- a/libxenia.vcxproj +++ b/libxenia.vcxproj @@ -299,6 +299,7 @@ + diff --git a/libxenia.vcxproj.filters b/libxenia.vcxproj.filters index 1c4a2eac9..48681189a 100644 --- a/libxenia.vcxproj.filters +++ b/libxenia.vcxproj.filters @@ -1497,6 +1497,9 @@ src\xenia\cpu\compiler\passes + + src\xenia\cpu\backend + diff --git a/src/xenia/cpu/backend/backend.cc b/src/xenia/cpu/backend/backend.cc index 741957d66..090cb13f7 100644 --- a/src/xenia/cpu/backend/backend.cc +++ b/src/xenia/cpu/backend/backend.cc @@ -13,7 +13,8 @@ namespace xe { namespace cpu { namespace backend { -Backend::Backend(Processor* processor) : processor_(processor) { +Backend::Backend(Processor* processor) + : processor_(processor), code_cache_(nullptr) { std::memset(&machine_info_, 0, sizeof(machine_info_)); } diff --git a/src/xenia/cpu/backend/backend.h b/src/xenia/cpu/backend/backend.h index 0777bb89f..463a2321b 100644 --- a/src/xenia/cpu/backend/backend.h +++ b/src/xenia/cpu/backend/backend.h @@ -25,6 +25,7 @@ namespace cpu { namespace backend { class Assembler; +class CodeCache; class Backend { public: @@ -33,6 +34,7 @@ class Backend { Processor* processor() const { return processor_; } const MachineInfo* machine_info() const { return &machine_info_; } + CodeCache* code_cache() const { return code_cache_; } virtual bool Initialize(); @@ -47,6 +49,7 @@ class Backend { protected: Processor* processor_; MachineInfo machine_info_; + CodeCache* code_cache_; }; } // namespace backend diff --git a/src/xenia/cpu/backend/code_cache.h b/src/xenia/cpu/backend/code_cache.h new file mode 100644 index 000000000..c00e3302a --- /dev/null +++ b/src/xenia/cpu/backend/code_cache.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_BACKEND_CODE_CACHE_H_ +#define XENIA_BACKEND_CODE_CACHE_H_ + +#include + +namespace xe { +namespace cpu { +namespace backend { + +class CodeCache { + public: + CodeCache() = default; + virtual ~CodeCache() = default; + + virtual std::wstring file_name() const = 0; + virtual uint32_t base_address() const = 0; + virtual uint32_t total_size() const = 0; +}; + +} // namespace backend +} // namespace cpu +} // namespace xe + +#endif // XENIA_BACKEND_CODE_CACHE_H_ diff --git a/src/xenia/cpu/backend/x64/x64_backend.cc b/src/xenia/cpu/backend/x64/x64_backend.cc index d77ff60aa..f892453b5 100644 --- a/src/xenia/cpu/backend/x64/x64_backend.cc +++ b/src/xenia/cpu/backend/x64/x64_backend.cc @@ -62,6 +62,7 @@ bool X64Backend::Initialize() { }; code_cache_ = new X64CodeCache(); + Backend::code_cache_ = code_cache_; if (!code_cache_->Initialize()) { return false; } diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.cc b/src/xenia/cpu/backend/x64/x64_code_cache.cc index 6b02e65e4..be027ab74 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.cc +++ b/src/xenia/cpu/backend/x64/x64_code_cache.cc @@ -10,6 +10,7 @@ #include "xenia/cpu/backend/x64/x64_code_cache.h" #include "xenia/base/assert.h" +#include "xenia/base/clock.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" #include "xenia/base/memory.h" @@ -24,7 +25,8 @@ namespace x64 { const static uint32_t kUnwindInfoSize = 4 + (2 * 1 + 2 + 2); X64CodeCache::X64CodeCache() - : indirection_default_value_(0xFEEDF00D), + : mapping_(nullptr), + indirection_default_value_(0xFEEDF00D), indirection_table_base_(nullptr), generated_code_base_(nullptr), generated_code_offset_(0), @@ -39,8 +41,11 @@ X64CodeCache::~X64CodeCache() { if (indirection_table_base_) { VirtualFree(indirection_table_base_, 0, MEM_RELEASE); } - if (generated_code_base_) { - VirtualFree(generated_code_base_, 0, MEM_RELEASE); + // Unmap all views and close mapping. + if (mapping_) { + UnmapViewOfFile(generated_code_base_); + CloseHandle(mapping_); + mapping_ = 0; } } @@ -57,9 +62,22 @@ bool X64CodeCache::Initialize() { return false; } - generated_code_base_ = reinterpret_cast( - VirtualAlloc(reinterpret_cast(kGeneratedCodeBase), - kGeneratedCodeSize, MEM_RESERVE, PAGE_EXECUTE_READWRITE)); + // Create mmap file. This allows us to share the code cache with the debugger. + wchar_t file_name[256]; + wsprintf(file_name, L"Local\\xenia_code_cache_%p", Clock::QueryHostTickCount()); + file_name_ = file_name; + mapping_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_EXECUTE_READWRITE | SEC_RESERVE, 0, + kGeneratedCodeSize, file_name_.c_str()); + if (!mapping_) { + XELOGE("Unable to create code cache mmap"); + return false; + } + + // Mapp generated code region into the file. Pages are committed as required. + generated_code_base_ = reinterpret_cast(MapViewOfFileEx( + mapping_, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, + kGeneratedCodeSize, reinterpret_cast(kGeneratedCodeBase))); if (!generated_code_base_) { XELOGE("Unable to allocate code cache generated code storage"); XELOGE( @@ -103,7 +121,7 @@ void X64CodeCache::CommitExecutableRange(uint32_t guest_low, uint32_t guest_high) { // Commit the memory. VirtualAlloc(indirection_table_base_ + (guest_low - kIndirectionTableBase), - guest_high - guest_low, MEM_COMMIT, PAGE_READWRITE); + guest_high - guest_low, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // Fill memory with the default value. uint32_t* p = reinterpret_cast(indirection_table_base_); diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.h b/src/xenia/cpu/backend/x64/x64_code_cache.h index 2ee785c5d..5fe7cb529 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.h +++ b/src/xenia/cpu/backend/x64/x64_code_cache.h @@ -10,27 +10,31 @@ #ifndef XENIA_BACKEND_X64_X64_CODE_CACHE_H_ #define XENIA_BACKEND_X64_X64_CODE_CACHE_H_ -// For RUNTIME_FUNCTION: -#include "xenia/base/platform.h" - #include #include +#include #include #include "xenia/base/mutex.h" +#include "xenia/base/platform.h" +#include "xenia/cpu/backend/code_cache.h" namespace xe { namespace cpu { namespace backend { namespace x64 { -class X64CodeCache { +class X64CodeCache : public CodeCache { public: X64CodeCache(); - virtual ~X64CodeCache(); + ~X64CodeCache() override; bool Initialize(); + std::wstring file_name() const override { return file_name_; } + uint32_t base_address() const override { return kGeneratedCodeBase; } + uint32_t total_size() const override { return kGeneratedCodeSize; } + // TODO(benvanik): ELF serialization/etc // TODO(benvanik): keep track of code blocks // TODO(benvanik): padding/guards/etc @@ -55,6 +59,9 @@ class X64CodeCache { size_t unwind_table_slot, uint8_t* code_address, size_t code_size, size_t stack_size); + std::wstring file_name_; + HANDLE mapping_; + // Must be held when manipulating the offsets or counts of anything, to keep // the tables consistent and ordered. xe::mutex allocation_mutex_;