Moving xe::Memory and code cache to abstracted APIs.

This commit is contained in:
Ben Vanik 2015-07-15 22:10:05 -07:00
parent fefaa31cd8
commit 8154d1dad6
7 changed files with 118 additions and 108 deletions

View File

@ -58,6 +58,15 @@ bool DeallocFixed(void* base_address, size_t length,
bool Protect(void* base_address, size_t length, PageAccess access, bool Protect(void* base_address, size_t length, PageAccess access,
PageAccess* out_old_access); PageAccess* out_old_access);
typedef void* FileMappingHandle;
FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length,
PageAccess access, bool commit);
void CloseFileMappingHandle(FileMappingHandle handle);
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
PageAccess access, size_t file_offset);
bool UnmapFileView(FileMappingHandle handle, void* base_address, size_t length);
inline size_t hash_combine(size_t seed) { return seed; } inline size_t hash_combine(size_t seed) { return seed; }
template <typename T, typename... Ts> template <typename T, typename... Ts>

View File

@ -89,7 +89,9 @@ bool Protect(void* base_address, size_t length, PageAccess access,
DWORD new_protect = ToWin32ProtectFlags(access); DWORD new_protect = ToWin32ProtectFlags(access);
DWORD old_protect = 0; DWORD old_protect = 0;
BOOL result = VirtualProtect(base_address, length, new_protect, &old_protect); BOOL result = VirtualProtect(base_address, length, new_protect, &old_protect);
if (result) { if (!result) {
return false;
}
if (out_old_access) { if (out_old_access) {
switch (old_protect) { switch (old_protect) {
case PAGE_NOACCESS: case PAGE_NOACCESS:
@ -109,9 +111,46 @@ bool Protect(void* base_address, size_t length, PageAccess access,
} }
} }
return true; return true;
} else {
return false;
} }
FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length,
PageAccess access, bool commit) {
DWORD protect =
ToWin32ProtectFlags(access) | (commit ? SEC_COMMIT : SEC_RESERVE);
return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, protect,
static_cast<DWORD>(length >> 32),
static_cast<DWORD>(length), path.c_str());
}
void CloseFileMappingHandle(FileMappingHandle handle) { CloseHandle(handle); }
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
PageAccess access, size_t file_offset) {
DWORD target_address_low = static_cast<DWORD>(file_offset);
DWORD target_address_high = static_cast<DWORD>(file_offset >> 32);
DWORD file_access = 0;
switch (access) {
case PageAccess::kReadOnly:
file_access = FILE_MAP_READ;
break;
case PageAccess::kReadWrite:
file_access = FILE_MAP_ALL_ACCESS;
break;
case PageAccess::kExecuteReadWrite:
file_access = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE;
break;
case PageAccess::kNoAccess:
default:
assert_unhandled_case(access);
return nullptr;
}
return MapViewOfFileEx(handle, file_access, target_address_high,
target_address_low, length, base_address);
}
bool UnmapFileView(FileMappingHandle handle, void* base_address,
size_t length) {
return UnmapViewOfFile(base_address) ? true : false;
} }
} // namespace memory } // namespace memory

View File

@ -31,15 +31,7 @@ namespace x64 {
// TODO(benvanik): move this to emitter. // TODO(benvanik): move this to emitter.
const static uint32_t kUnwindInfoSize = 4 + (2 * 1 + 2 + 2); const static uint32_t kUnwindInfoSize = 4 + (2 * 1 + 2 + 2);
X64CodeCache::X64CodeCache() X64CodeCache::X64CodeCache() = default;
: mapping_(nullptr),
indirection_default_value_(0xFEEDF00D),
indirection_table_base_(nullptr),
generated_code_base_(nullptr),
generated_code_offset_(0),
generated_code_commit_mark_(0),
unwind_table_handle_(nullptr),
unwind_table_count_(0) {}
X64CodeCache::~X64CodeCache() { X64CodeCache::~X64CodeCache() {
if (indirection_table_base_) { if (indirection_table_base_) {
@ -60,9 +52,10 @@ X64CodeCache::~X64CodeCache() {
// Unmap all views and close mapping. // Unmap all views and close mapping.
if (mapping_) { if (mapping_) {
UnmapViewOfFile(generated_code_base_); xe::memory::UnmapFileView(mapping_, generated_code_base_,
CloseHandle(mapping_); kGeneratedCodeSize);
mapping_ = 0; xe::memory::CloseFileMappingHandle(mapping_);
mapping_ = nullptr;
} }
} }
@ -81,22 +74,20 @@ bool X64CodeCache::Initialize() {
} }
// Create mmap file. This allows us to share the code cache with the debugger. // Create mmap file. This allows us to share the code cache with the debugger.
wchar_t file_name[256]; file_name_ = std::wstring(L"Local\\xenia_code_cache_") +
wsprintf(file_name, L"Local\\xenia_code_cache_%p", std::to_wstring(Clock::QueryHostTickCount());
Clock::QueryHostTickCount()); mapping_ = xe::memory::CreateFileMappingHandle(
file_name_ = file_name; file_name_, kGeneratedCodeSize, xe::memory::PageAccess::kExecuteReadWrite,
mapping_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, false);
PAGE_EXECUTE_READWRITE | SEC_RESERVE, 0,
kGeneratedCodeSize, file_name_.c_str());
if (!mapping_) { if (!mapping_) {
XELOGE("Unable to create code cache mmap"); XELOGE("Unable to create code cache mmap");
return false; return false;
} }
// Map generated code region into the file. Pages are committed as required. // Map generated code region into the file. Pages are committed as required.
generated_code_base_ = reinterpret_cast<uint8_t*>(MapViewOfFileEx( generated_code_base_ = reinterpret_cast<uint8_t*>(xe::memory::MapFileView(
mapping_, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, mapping_, reinterpret_cast<void*>(kGeneratedCodeBase), kGeneratedCodeSize,
kGeneratedCodeSize, reinterpret_cast<void*>(kGeneratedCodeBase))); xe::memory::PageAccess::kExecuteReadWrite, 0));
if (!generated_code_base_) { if (!generated_code_base_) {
XELOGE("Unable to allocate code cache generated code storage"); XELOGE("Unable to allocate code cache generated code storage");
XELOGE( XELOGE(

View File

@ -15,6 +15,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "xenia/base/memory.h"
#include "xenia/base/mutex.h" #include "xenia/base/mutex.h"
#include "xenia/base/platform_win.h" #include "xenia/base/platform_win.h"
#include "xenia/cpu/backend/code_cache.h" #include "xenia/cpu/backend/code_cache.h"
@ -61,33 +62,33 @@ class X64CodeCache : public CodeCache {
void* LookupUnwindEntry(uintptr_t host_address); void* LookupUnwindEntry(uintptr_t host_address);
std::wstring file_name_; std::wstring file_name_;
HANDLE mapping_; xe::memory::FileMappingHandle mapping_ = nullptr;
// Must be held when manipulating the offsets or counts of anything, to keep // Must be held when manipulating the offsets or counts of anything, to keep
// the tables consistent and ordered. // the tables consistent and ordered.
xe::mutex allocation_mutex_; xe::mutex allocation_mutex_;
// Value that the indirection table will be initialized with upon commit. // Value that the indirection table will be initialized with upon commit.
uint32_t indirection_default_value_; uint32_t indirection_default_value_ = 0xFEEDF00D;
// Fixed at kIndirectionTableBase in host space, holding 4 byte pointers into // Fixed at kIndirectionTableBase in host space, holding 4 byte pointers into
// the generated code table that correspond to the PPC functions in guest // the generated code table that correspond to the PPC functions in guest
// space. // space.
uint8_t* indirection_table_base_; uint8_t* indirection_table_base_ = nullptr;
// Fixed at kGeneratedCodeBase and holding all generated code, growing as // Fixed at kGeneratedCodeBase and holding all generated code, growing as
// needed. // needed.
uint8_t* generated_code_base_; uint8_t* generated_code_base_ = nullptr;
// Current offset to empty space in generated code. // Current offset to empty space in generated code.
size_t generated_code_offset_; size_t generated_code_offset_ = 0;
// Current high water mark of COMMITTED code. // Current high water mark of COMMITTED code.
std::atomic<size_t> generated_code_commit_mark_; std::atomic<size_t> generated_code_commit_mark_ = 0;
// Growable function table system handle. // Growable function table system handle.
void* unwind_table_handle_; void* unwind_table_handle_ = nullptr;
// Actual unwind table entries. // Actual unwind table entries.
std::vector<RUNTIME_FUNCTION> unwind_table_; std::vector<RUNTIME_FUNCTION> unwind_table_;
// Current number of entries in the table. // Current number of entries in the table.
std::atomic<uint32_t> unwind_table_count_; std::atomic<uint32_t> unwind_table_count_ = 0;
}; };
} // namespace x64 } // namespace x64

View File

@ -22,6 +22,9 @@
#include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/util/xex2.h" #include "xenia/kernel/util/xex2.h"
// For FileTimeToSystemTime and SystemTimeToFileTime:
#include "xenia/base/platform_win.h"
namespace xe { namespace xe {
namespace kernel { namespace kernel {

View File

@ -24,10 +24,6 @@
// TODO(benvanik): move xbox.h out // TODO(benvanik): move xbox.h out
#include "xenia/xbox.h" #include "xenia/xbox.h"
#if !XE_PLATFORM_WIN32
#include <sys/mman.h>
#endif // WIN32
DEFINE_bool(protect_zero, false, DEFINE_bool(protect_zero, false,
"Protect the zero page from reads and writes."); "Protect the zero page from reads and writes.");
@ -76,12 +72,7 @@ static Memory* active_memory_ = nullptr;
void CrashDump() { active_memory_->DumpMap(); } void CrashDump() { active_memory_->DumpMap(); }
Memory::Memory() Memory::Memory() {
: virtual_membase_(nullptr),
physical_membase_(nullptr),
reserve_address_(0),
mapping_(0),
mapping_base_(nullptr) {
system_page_size_ = uint32_t(xe::memory::page_size()); system_page_size_ = uint32_t(xe::memory::page_size());
assert_zero(active_memory_); assert_zero(active_memory_);
active_memory_ = this; active_memory_ = this;
@ -107,9 +98,9 @@ Memory::~Memory() {
// Unmap all views and close mapping. // Unmap all views and close mapping.
if (mapping_) { if (mapping_) {
UnmapViews(); UnmapViews();
CloseHandle(mapping_); xe::memory::CloseFileMappingHandle(mapping_);
mapping_base_ = 0; mapping_base_ = nullptr;
mapping_ = 0; mapping_ = nullptr;
} }
virtual_membase_ = nullptr; virtual_membase_ = nullptr;
@ -117,23 +108,15 @@ Memory::~Memory() {
} }
int Memory::Initialize() { int Memory::Initialize() {
wchar_t file_name[256]; file_name_ = std::wstring(L"Local\\xenia_memory_") +
wsprintf(file_name, L"Local\\xenia_memory_%p", Clock::QueryHostTickCount()); std::to_wstring(Clock::QueryHostTickCount());
file_name_ = file_name;
// Create main page file-backed mapping. This is all reserved but // Create main page file-backed mapping. This is all reserved but
// uncommitted (so it shouldn't expand page file). // uncommitted (so it shouldn't expand page file).
#if XE_PLATFORM_WIN32 mapping_ = xe::memory::CreateFileMappingHandle(
mapping_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, file_name_,
PAGE_READWRITE | SEC_RESERVE,
// entire 4gb space + 512mb physical: // entire 4gb space + 512mb physical:
1, 0x1FFFFFFF, file_name_.c_str()); 0x11FFFFFFF, xe::memory::PageAccess::kReadWrite, false);
#else
char mapping_path[] = "/xenia/mapping/XXXXXX";
mktemp(mapping_path);
mapping_ = shm_open(mapping_path, O_CREAT, 0);
ftruncate(mapping_, 0x11FFFFFFF);
#endif // XE_PLATFORM_WIN32
if (!mapping_) { if (!mapping_) {
XELOGE("Unable to reserve the 4gb guest address space."); XELOGE("Unable to reserve the 4gb guest address space.");
assert_not_null(mapping_); assert_not_null(mapping_);
@ -236,21 +219,10 @@ const static struct {
int Memory::MapViews(uint8_t* mapping_base) { int Memory::MapViews(uint8_t* mapping_base) {
assert_true(xe::countof(map_info) == xe::countof(views_.all_views)); assert_true(xe::countof(map_info) == xe::countof(views_.all_views));
for (size_t n = 0; n < xe::countof(map_info); n++) { for (size_t n = 0; n < xe::countof(map_info); n++) {
#if XE_PLATFORM_WIN32 views_.all_views[n] = reinterpret_cast<uint8_t*>(xe::memory::MapFileView(
DWORD target_address_low = static_cast<DWORD>(map_info[n].target_address); mapping_, mapping_base + map_info[n].virtual_address_start,
DWORD target_address_high =
static_cast<DWORD>(map_info[n].target_address >> 32);
views_.all_views[n] = reinterpret_cast<uint8_t*>(MapViewOfFileEx(
mapping_, FILE_MAP_ALL_ACCESS, target_address_high, target_address_low,
map_info[n].virtual_address_end - map_info[n].virtual_address_start + 1, map_info[n].virtual_address_end - map_info[n].virtual_address_start + 1,
mapping_base + map_info[n].virtual_address_start)); xe::memory::PageAccess::kReadWrite, map_info[n].target_address));
#else
views_.all_views[n] = reinterpret_cast<uint8_t*>(mmap(
map_info[n].virtual_address_start + mapping_base,
map_info[n].virtual_address_end - map_info[n].virtual_address_start + 1,
PROT_NONE, MAP_SHARED | MAP_FIXED, mapping_,
map_info[n].target_address));
#endif // XE_PLATFORM_WIN32
if (!views_.all_views[n]) { if (!views_.all_views[n]) {
// Failed, so bail and try again. // Failed, so bail and try again.
UnmapViews(); UnmapViews();
@ -263,13 +235,9 @@ int Memory::MapViews(uint8_t* mapping_base) {
void Memory::UnmapViews() { void Memory::UnmapViews() {
for (size_t n = 0; n < xe::countof(views_.all_views); n++) { for (size_t n = 0; n < xe::countof(views_.all_views); n++) {
if (views_.all_views[n]) { if (views_.all_views[n]) {
#if XE_PLATFORM_WIN32
UnmapViewOfFile(views_.all_views[n]);
#else
size_t length = map_info[n].virtual_address_end - size_t length = map_info[n].virtual_address_end -
map_info[n].virtual_address_start + 1; map_info[n].virtual_address_start + 1;
munmap(views_.all_views[n], length); xe::memory::UnmapFileView(mapping_, views_.all_views[n], length);
#endif // XE_PLATFORM_WIN32
} }
} }
} }
@ -437,7 +405,6 @@ void Memory::DumpMap() {
} }
xe::memory::PageAccess ToPageAccess(uint32_t protect) { xe::memory::PageAccess ToPageAccess(uint32_t protect) {
DWORD result = 0;
if ((protect & kMemoryProtectRead) && !(protect & kMemoryProtectWrite)) { if ((protect & kMemoryProtectRead) && !(protect & kMemoryProtectWrite)) {
return xe::memory::PageAccess::kReadOnly; return xe::memory::PageAccess::kReadOnly;
} else if ((protect & kMemoryProtectRead) && } else if ((protect & kMemoryProtectRead) &&

View File

@ -16,8 +16,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "xenia/base/memory.h"
#include "xenia/base/mutex.h" #include "xenia/base/mutex.h"
#include "xenia/base/platform_win.h"
#include "xenia/cpu/mmio_handler.h" #include "xenia/cpu/mmio_handler.h"
namespace xe { namespace xe {
@ -216,13 +216,13 @@ class Memory {
private: private:
std::wstring file_name_; std::wstring file_name_;
uint32_t system_page_size_; uint32_t system_page_size_ = 0;
uint8_t* virtual_membase_; uint8_t* virtual_membase_ = nullptr;
uint8_t* physical_membase_; uint8_t* physical_membase_ = nullptr;
uint64_t reserve_address_; uint64_t reserve_address_ = 0;
HANDLE mapping_; xe::memory::FileMappingHandle mapping_ = nullptr;
uint8_t* mapping_base_; uint8_t* mapping_base_ = nullptr;
union { union {
struct { struct {
uint8_t* v00000000; uint8_t* v00000000;
@ -236,7 +236,7 @@ class Memory {
uint8_t* physical; uint8_t* physical;
}; };
uint8_t* all_views[9]; uint8_t* all_views[9];
} views_; } views_ = {0};
std::unique_ptr<cpu::MMIOHandler> mmio_handler_; std::unique_ptr<cpu::MMIOHandler> mmio_handler_;