/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2017 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/base/memory.h" #include "xenia/base/string.h" #include #include #include namespace xe { namespace memory { size_t page_size() { return getpagesize(); } size_t allocation_granularity() { return page_size(); } uint32_t ToPosixProtectFlags(PageAccess access) { switch (access) { case PageAccess::kNoAccess: return PROT_NONE; case PageAccess::kReadOnly: return PROT_READ; case PageAccess::kReadWrite: return PROT_READ | PROT_WRITE; case PageAccess::kExecuteReadWrite: return PROT_READ | PROT_WRITE | PROT_EXEC; default: assert_unhandled_case(access); return PROT_NONE; } } void* AllocFixed(void* base_address, size_t length, AllocationType allocation_type, PageAccess access) { // mmap does not support reserve / commit, so ignore allocation_type. uint32_t prot = ToPosixProtectFlags(access); return mmap(base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } bool DeallocFixed(void* base_address, size_t length, DeallocationType deallocation_type) { return munmap(base_address, length) == 0; } bool Protect(void* base_address, size_t length, PageAccess access, PageAccess* out_old_access) { // Linux does not have a syscall to query memory permissions. assert_null(out_old_access); uint32_t prot = ToPosixProtectFlags(access); return mprotect(base_address, length, prot) == 0; } bool QueryProtect(void* base_address, size_t& length, PageAccess& access_out) { return false; } FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length, PageAccess access, bool commit) { int oflag; switch (access) { case PageAccess::kNoAccess: oflag = 0; break; case PageAccess::kReadOnly: oflag = O_RDONLY; break; case PageAccess::kReadWrite: case PageAccess::kExecuteReadWrite: oflag = O_RDWR; break; default: assert_always(); return nullptr; } oflag |= O_CREAT; int ret = shm_open(xe::to_string(path).c_str(), oflag, 0777); if (ret > 0) { ftruncate64(ret, length); } return ret <= 0 ? nullptr : reinterpret_cast(ret); } void CloseFileMappingHandle(FileMappingHandle handle) { close((intptr_t)handle); } void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, PageAccess access, size_t file_offset) { uint32_t prot = ToPosixProtectFlags(access); return mmap64(base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, reinterpret_cast(handle), file_offset); } bool UnmapFileView(FileMappingHandle handle, void* base_address, size_t length) { return munmap(base_address, length) == 0; } } // namespace memory } // namespace xe