Moving xe::Memory and code cache to abstracted APIs.
This commit is contained in:
parent
fefaa31cd8
commit
8154d1dad6
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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) &&
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue