diff --git a/Common/MemArena.h b/Common/MemArena.h index fd2524535f..48e1bcece2 100644 --- a/Common/MemArena.h +++ b/Common/MemArena.h @@ -17,6 +17,8 @@ #pragma once +#include + #ifdef _WIN32 #include "CommonWindows.h" #endif @@ -36,13 +38,18 @@ public: void ReleaseSpace(); void *CreateView(s64 offset, size_t size, void *base = 0); void ReleaseView(void *view, size_t size); + // This only finds 1 GB in 32-bit u8 *Find4GBBase(); + bool NeedsProbing(); private: #ifdef _WIN32 HANDLE hMemoryMapping; SYSTEM_INFO sysInfo; +#elif defined(IOS) && PPSSPP_ARCH(ARM64) + size_t vm_size; + uintptr_t vm_mem; // same type as vm_address_t #else int fd; #endif diff --git a/Common/MemArenaAndroid.cpp b/Common/MemArenaAndroid.cpp index cbf53a86ba..dbcde0584c 100644 --- a/Common/MemArenaAndroid.cpp +++ b/Common/MemArenaAndroid.cpp @@ -33,6 +33,10 @@ #define ASHMEM_DEVICE "/dev/ashmem" +bool MemArena::NeedsProbing() { + return false; +} + // ashmem_create_region - creates a new ashmem region and returns the file // descriptor, or <0 on error // `name' is an optional label to give the region (visible in /proc/pid/maps) @@ -127,4 +131,4 @@ u8* MemArena::Find4GBBase() { #endif } -#endif // __ANDROID__ \ No newline at end of file +#endif // __ANDROID__ diff --git a/Common/MemArenaDarwin.cpp b/Common/MemArenaDarwin.cpp new file mode 100644 index 0000000000..4632670f27 --- /dev/null +++ b/Common/MemArenaDarwin.cpp @@ -0,0 +1,97 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "ppsspp_config.h" + +#if defined(IOS) && PPSSPP_ARCH(ARM64) + +#include +#include + +#include "FileUtil.h" +#include "MemoryUtil.h" +#include "MemArena.h" + +#include +#include +#include +#include +#include + +#include +#include + +size_t MemArena::roundup(size_t x) { + return x; +} + +void MemArena::GrabLowMemSpace(size_t size) +{ + vm_size = size; + kern_return_t retval = vm_allocate(mach_task_self(), &vm_mem, size, VM_FLAGS_ANYWHERE); + if (retval != KERN_SUCCESS) { + ERROR_LOG(MEMMAP, "Failed to grab a block of virtual memory"); + } else { + INFO_LOG(MEMMAP, "Successfully allocated %d bytes at %p", (int)size, (void *)vm_mem); + } +} + +void MemArena::ReleaseSpace() { + vm_deallocate(mach_task_self(), vm_mem, vm_size); + vm_size = 0; + vm_mem = 0; +} + +void *MemArena::CreateView(s64 offset, size_t size, void *base) +{ + mach_port_t self = mach_task_self(); + vm_address_t target = (vm_address_t)base; + uint64_t mask = 0; + bool anywhere = false; + vm_address_t source = vm_mem + offset; + vm_prot_t cur_protection = 0; + vm_prot_t max_protection = 0; + kern_return_t retval = + vm_remap(self, &target, size, mask, anywhere, + self, source, false, + &cur_protection, &max_protection, VM_INHERIT_DEFAULT); + if (retval != KERN_SUCCESS) { + // 1 == KERN_INVALID_ADDRESS + // 3 == KERN_NO_SPACE (race?) + // 4 == KERN_INVALID_ARGUMENT + ERROR_LOG(MEMMAP, "vm_remap failed (%d) - could not remap from %llx (offset %llx) of size %llx to %p", + (int)retval, (uint64_t)source, (uint64_t)offset, (uint64_t)size, base); + return nullptr; + } + return (void *)target; +} + +void MemArena::ReleaseView(void* view, size_t size) { + vm_address_t addr = (vm_address_t)view; + vm_deallocate(mach_task_self(), addr, size); +} + +bool MemArena::NeedsProbing() { + return true; +} + +u8* MemArena::Find4GBBase() { + // The caller will need to do probing, like on 32-bit Windows. + return nullptr; +} + +#endif // defined(IOS) && PPSSPP_ARCH(ARM64) diff --git a/Common/MemArenaPosix.cpp b/Common/MemArenaPosix.cpp index d71d1f6886..764edae78f 100644 --- a/Common/MemArenaPosix.cpp +++ b/Common/MemArenaPosix.cpp @@ -17,7 +17,7 @@ #include "ppsspp_config.h" -#if !defined(_WIN32) && !defined(ANDROID) +#if !defined(_WIN32) && !defined(ANDROID) && !(defined(IOS) && PPSSPP_ARCH(ARM64)) #include @@ -41,6 +41,10 @@ size_t MemArena::roundup(size_t x) { return x; } +bool MemArena::NeedsProbing() { + return false; +} + void MemArena::GrabLowMemSpace(size_t size) { mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; @@ -114,4 +118,4 @@ u8* MemArena::Find4GBBase() { #endif } -#endif \ No newline at end of file +#endif diff --git a/Common/MemArenaWin32.cpp b/Common/MemArenaWin32.cpp index 55621df442..4e7868e3f4 100644 --- a/Common/MemArenaWin32.cpp +++ b/Common/MemArenaWin32.cpp @@ -48,6 +48,14 @@ void MemArena::ReleaseView(void* view, size_t size) { UnmapViewOfFile(view); } +bool MemArena::NeedsProbing() { +#if PPSSPP_ARCH(32BIT) + return true; +#else + return false; +#endif +} + u8* MemArena::Find4GBBase() { // Now, create views in high memory where there's plenty of space. #if PPSSPP_ARCH(32BIT) @@ -65,4 +73,4 @@ u8* MemArena::Find4GBBase() { #endif } -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index b7b8a67243..c085e24494 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -152,8 +152,10 @@ static bool Memory_TryBase(u32 flags) { #if PPSSPP_ARCH(64BIT) *view.out_ptr = (u8*)g_arena.CreateView( position, view.size, base + view.virtual_address); - if (!*view.out_ptr) + if (!*view.out_ptr) { goto bail; + ERROR_LOG(MEMMAP, "Failed at view %d", i); + } #else if (CanIgnoreView(view)) { // This is handled by address masking in 32-bit, no view needs to be created. @@ -161,8 +163,10 @@ static bool Memory_TryBase(u32 flags) { } else { *view.out_ptr = (u8*)g_arena.CreateView( position, view.size, base + (view.virtual_address & MEMVIEW32_MASK)); - if (!*view.out_ptr) + if (!*view.out_ptr) { + ERROR_LOG(MEMMAP, "Failed at view %d", i); goto bail; + } } #endif last_position = position; @@ -201,27 +205,32 @@ bool MemoryMap_Setup(u32 flags) { // Grab some pagefile backed memory out of the void ... g_arena.GrabLowMemSpace(total_mem); - base = g_arena.Find4GBBase(); - - // Try base we retrieved earlier - if (!base) { + if (g_arena.NeedsProbing()) { + int base_attempts = 0; #if defined(_WIN32) && PPSSPP_ARCH(32BIT) // Try a whole range of possible bases. Return once we got a valid one. - int base_attempts = 0; - u32 max_base_addr = 0x7FFF0000 - 0x10000000; - for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000) { + uintptr_t max_base_addr = 0x7FFF0000 - 0x10000000; + uintptr_t min_base_addr = 0x01000000; + uintptr_t stride = 0x400000; +#else + // iOS + uintptr_t max_base_addr = 0x1FFFF0000ULL - 0xE1000000; + uintptr_t min_base_addr = 0x01000000; + uintptr_t stride = 0x800000; +#endif + for (uintptr_t base_addr = min_base_addr; base_addr < max_base_addr; base_addr += stride) { base_attempts++; base = (u8 *)base_addr; if (Memory_TryBase(flags)) { INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); - base_attempts = 0; return true; } } -#endif ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); PanicAlert("MemoryMap_Setup: Failed finding a memory base."); return false; + } else { + base = g_arena.Find4GBBase(); } // Should return true...