diff --git a/Common/MemArena.cpp b/Common/MemArena.cpp index 1581e8ae92..262af0736c 100644 --- a/Common/MemArena.cpp +++ b/Common/MemArena.cpp @@ -95,8 +95,6 @@ int ashmem_unpin_region(int fd, size_t offset, size_t len) } #endif // Android - - #ifndef _WIN32 // do not make this "static" #if defined(MAEMO) || defined(MEEGO_EDITION_HARMATTAN) @@ -111,7 +109,7 @@ SYSTEM_INFO sysInfo; // Windows mappings need to be on 64K boundaries, due to Alpha legacy. #ifdef _WIN32 -size_t roundup(size_t x) { +size_t MemArena::roundup(size_t x) { #ifndef _XBOX int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; #else @@ -120,12 +118,11 @@ size_t roundup(size_t x) { return (x + gran - 1) & ~(gran - 1); } #else -size_t roundup(size_t x) { +size_t MemArena::roundup(size_t x) { return x; } #endif - void MemArena::GrabLowMemSpace(size_t size) { #ifdef _WIN32 @@ -166,9 +163,6 @@ void MemArena::ReleaseSpace() #ifdef _WIN32 CloseHandle(hMemoryMapping); hMemoryMapping = 0; -#elif defined(__SYMBIAN32__) - memmap->Close(); - delete memmap; #else close(fd); #endif @@ -214,14 +208,11 @@ void MemArena::ReleaseView(void* view, size_t size) #ifndef _XBOX UnmapViewOfFile(view); #endif -#elif defined(__SYMBIAN32__) - memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size); #else munmap(view, size); #endif } -#ifndef __SYMBIAN32__ u8* MemArena::Find4GBBase() { #ifdef _M_X64 @@ -256,205 +247,4 @@ u8* MemArena::Find4GBBase() #endif #endif } -#endif - -// yeah, this could also be done in like two bitwise ops... -#define SKIP(a_flags, b_flags) -// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) -// continue; -// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) -// continue; - -static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) { - // OK, we know where to find free space. Now grab it! - // We just mimic the popular BAT setup. - size_t position = 0; - size_t last_position = 0; - -#if defined(_XBOX) - void *ptr; -#endif - - // Zero all the pointers to be sure. - for (int i = 0; i < num_views; i++) - { - if (views[i].out_ptr_low) - *views[i].out_ptr_low = 0; - if (views[i].out_ptr) - *views[i].out_ptr = 0; - } - - int i; - for (i = 0; i < num_views; i++) - { - const MemoryView &view = views[i]; - if (view.size == 0) - continue; - SKIP(flags, view.flags); - if (view.flags & MV_MIRROR_PREVIOUS) { - position = last_position; - } else { -#ifdef __SYMBIAN32__ - *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address); - // Over allocate VRAM to span the mirrors. Hopefully resolves crash. - if (i == 2) - arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size * 4); - else - arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); - } - *(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF); -#elif defined(_XBOX) - *(view.out_ptr_low) = (u8*)(base + view.virtual_address); - //arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); - ptr = VirtualAlloc(base + (view.virtual_address & 0x3FFFFFFF), view.size, MEM_COMMIT, PAGE_READWRITE); - } - *(view.out_ptr) = (u8*)base + (view.virtual_address & 0x3FFFFFFF); -#else - *(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size); - if (!*view.out_ptr_low) - goto bail; - } -#ifdef _M_X64 - *view.out_ptr = (u8*)arena->CreateView( - position, view.size, base + view.virtual_address); -#else - if (view.flags & MV_MIRROR_PREVIOUS) { // TODO: should check if the two & 0x3FFFFFFF are identical. - // No need to create multiple identical views. - *view.out_ptr = *views[i - 1].out_ptr; - } else { - *view.out_ptr = (u8*)arena->CreateView( - position, view.size, base + (view.virtual_address & 0x3FFFFFFF)); - if (!*view.out_ptr) - goto bail; - } -#endif - -#endif - last_position = position; - position += roundup(view.size); - } - - return true; - -bail: - // Argh! ERROR! Free what we grabbed so far so we can try again. - for (int j = 0; j <= i; j++) - { - if (views[i].size == 0) - continue; - SKIP(flags, views[i].flags); - if (views[j].out_ptr_low && *views[j].out_ptr_low) - { - arena->ReleaseView(*views[j].out_ptr_low, views[j].size); - *views[j].out_ptr_low = NULL; - } - if (*views[j].out_ptr) - { -#ifdef _M_X64 - arena->ReleaseView(*views[j].out_ptr, views[j].size); -#else - if (!(views[j].flags & MV_MIRROR_PREVIOUS)) - { - arena->ReleaseView(*views[j].out_ptr, views[j].size); - } -#endif - *views[j].out_ptr = NULL; - } - } - return false; -} - -u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena) -{ - size_t total_mem = 0; - int base_attempts = 0; - - for (int i = 0; i < num_views; i++) - { - if (views[i].size == 0) - continue; - SKIP(flags, views[i].flags); - if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0) - total_mem += roundup(views[i].size); - } - // Grab some pagefile backed memory out of the void ... -#ifndef __SYMBIAN32__ - arena->GrabLowMemSpace(total_mem); -#endif - - // Now, create views in high memory where there's plenty of space. -#ifdef _M_X64 - u8 *base = MemArena::Find4GBBase(); - // This really shouldn't fail - in 64-bit, there will always be enough - // address space. - if (!Memory_TryBase(base, views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } -#elif defined(_XBOX) - // Reserve 256MB - u8 *base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE|MEM_LARGE_PAGES, PAGE_READWRITE); - if (!Memory_TryBase(base, views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - exit(0); - return 0; - } -#elif defined(_WIN32) - // Try a whole range of possible bases. Return once we got a valid one. - u32 max_base_addr = 0x7FFF0000 - 0x10000000; - u8 *base = NULL; - - for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000) - { - base_attempts++; - base = (u8 *)base_addr; - if (Memory_TryBase(base, views, num_views, flags, arena)) - { - INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); - base_attempts = 0; - break; - } - } -#elif defined(__SYMBIAN32__) - arena->memmap = new RChunk(); - arena->memmap->CreateDisconnectedLocal(0 , 0, 0x10000000); - if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } - u8* base = arena->memmap->Base(); -#else - // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors. - u8 *base = MemArena::Find4GBBase(); - if (!Memory_TryBase(base, views, num_views, flags, arena)) - { - ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - return 0; - } -#endif - if (base_attempts) - PanicAlert("No possible memory base pointer found!"); - return base; -} - -void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) -{ - for (int i = 0; i < num_views; i++) - { - if (views[i].size == 0) - continue; - SKIP(flags, views[i].flags); - if (views[i].out_ptr_low && *views[i].out_ptr_low) - arena->ReleaseView(*views[i].out_ptr_low, views[i].size); - if (*views[i].out_ptr && (!views[i].out_ptr_low || *views[i].out_ptr != *views[i].out_ptr_low)) - arena->ReleaseView(*views[i].out_ptr, views[i].size); - *views[i].out_ptr = NULL; - if (views[i].out_ptr_low) - *views[i].out_ptr_low = NULL; - } -} diff --git a/Common/MemArena.h b/Common/MemArena.h index 20093770b7..b3c100bb89 100644 --- a/Common/MemArena.h +++ b/Common/MemArena.h @@ -22,10 +22,6 @@ #include "CommonWindows.h" #endif -#ifdef __SYMBIAN32__ -#include -#endif - #include "Common.h" // This class lets you create a block of anonymous RAM, and then arbitrarily map views into it. @@ -35,17 +31,13 @@ class MemArena { public: + size_t roundup(size_t x); void GrabLowMemSpace(size_t size); void ReleaseSpace(); void *CreateView(s64 offset, size_t size, void *base = 0); void ReleaseView(void *view, size_t size); - -#ifdef __SYMBIAN32__ - RChunk* memmap; -#else // This only finds 1 GB in 32-bit static u8 *Find4GBBase(); -#endif private: #ifdef _WIN32 @@ -55,27 +47,4 @@ private: #endif }; -enum { - MV_MIRROR_PREVIOUS = 1, - // MV_FAKE_VMEM = 2, - // MV_WII_ONLY = 4, - MV_IS_PRIMARY_RAM = 0x100, - MV_IS_EXTRA1_RAM = 0x200, - MV_IS_EXTRA2_RAM = 0x400, -}; - -struct MemoryView -{ - u8 **out_ptr_low; - u8 **out_ptr; - u32 virtual_address; - u32 size; - u32 flags; -}; - -// Uses a memory arena to set up an emulator-friendly memory map according to -// a passed-in list of MemoryView structures. -u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena); -void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena); - #endif // _MEMARENA_H_ diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index e88e775fb3..13b491d000 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -19,7 +19,9 @@ #include "Common/Common.h" #include "Common/MemoryUtil.h" +#ifndef __SYMBIAN32__ #include "Common/MemArena.h" +#endif #include "Common/ChunkFile.h" #include "Core/MemMap.h" @@ -37,10 +39,14 @@ namespace Memory { // The base pointer to the auto-mirrored arena. -u8* base = NULL; +u8* base = NULL; +#ifdef __SYMBIAN32__ +RChunk* memmap; +#else // The MemArena class MemArena g_arena; +#endif // ============== // 64-bit: Pointers to low-mem (sub-0x10000000) mirror @@ -114,6 +120,199 @@ static MemoryView views[] = static const int num_views = sizeof(views) / sizeof(MemoryView); +// yeah, this could also be done in like two bitwise ops... +#define SKIP(a_flags, b_flags) +// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) +// continue; +// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) +// continue; + +static bool Memory_TryBase(u32 flags) { + // OK, we know where to find free space. Now grab it! + // We just mimic the popular BAT setup. + +#if defined(_XBOX) + void *ptr; +#elif !defined(__SYMBIAN32__) + size_t position = 0; + size_t last_position = 0; +#endif + + // Zero all the pointers to be sure. + for (int i = 0; i < num_views; i++) + { + if (views[i].out_ptr_low) + *views[i].out_ptr_low = 0; + if (views[i].out_ptr) + *views[i].out_ptr = 0; + } + + int i; + for (i = 0; i < num_views; i++) + { + const MemoryView &view = views[i]; + if (view.size == 0) + continue; + SKIP(flags, view.flags); + +#ifdef __SYMBIAN32__ + if (!(view.flags & MV_MIRROR_PREVIOUS)) { + *(view.out_ptr_low) = (u8*)((int)memmap->Base() + view.virtual_address); + // Over allocate VRAM to span the mirrors. Hopefully resolves crash. + if (i == 2) + memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size * 4); + else + memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size); + } + *(view.out_ptr) = (u8*)((int)memmap->Base() + view.virtual_address & 0x3FFFFFFF); +#elif defined(_XBOX) + if (!(view.flags & MV_MIRROR_PREVIOUS)) { + *(view.out_ptr_low) = (u8*)(base + view.virtual_address); + ptr = VirtualAlloc(base + (view.virtual_address & 0x3FFFFFFF), view.size, MEM_COMMIT, PAGE_READWRITE); + } + *(view.out_ptr) = (u8*)base + (view.virtual_address & 0x3FFFFFFF); +#else + if (view.flags & MV_MIRROR_PREVIOUS) { + position = last_position; + } else { + *(view.out_ptr_low) = (u8*)g_arena.CreateView(position, view.size); + if (!*view.out_ptr_low) + goto bail; + } +#ifdef _M_X64 + *view.out_ptr = (u8*)g_arena.CreateView( + position, view.size, base + view.virtual_address); +#else + if (view.flags & MV_MIRROR_PREVIOUS) { // TODO: should check if the two & 0x3FFFFFFF are identical. + // No need to create multiple identical views. + *view.out_ptr = *views[i - 1].out_ptr; + } else { + *view.out_ptr = (u8*)g_arena.CreateView( + position, view.size, base + (view.virtual_address & 0x3FFFFFFF)); + if (!*view.out_ptr) + goto bail; + } +#endif + last_position = position; + position += g_arena.roundup(view.size); +#endif + } + + return true; + +#if !defined(_XBOX) && !defined(__SYMBIAN32__) +bail: + // Argh! ERROR! Free what we grabbed so far so we can try again. + for (int j = 0; j <= i; j++) + { + if (views[i].size == 0) + continue; + SKIP(flags, views[i].flags); + if (views[j].out_ptr_low && *views[j].out_ptr_low) + { + g_arena.ReleaseView(*views[j].out_ptr_low, views[j].size); + *views[j].out_ptr_low = NULL; + } + if (*views[j].out_ptr) + { +#ifdef _M_X64 + g_arena.ReleaseView(*views[j].out_ptr, views[j].size); +#else + if (!(views[j].flags & MV_MIRROR_PREVIOUS)) + { + g_arena.ReleaseView(*views[j].out_ptr, views[j].size); + } +#endif + *views[j].out_ptr = NULL; + } + } + return false; +#endif +} + +void MemoryMap_Setup(u32 flags) +{ + // Find a base to reserve 256MB +#if defined(_XBOX) + base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE|MEM_LARGE_PAGES, PAGE_READWRITE); +#elif defined(__SYMBIAN32__) + memmap = new RChunk(); + memmap->CreateDisconnectedLocal(0 , 0, 0x10000000); + base = memmap->Base(); +#elif defined(_M_X64) || !defined(_WIN32) + size_t total_mem = 0; + + for (int i = 0; i < num_views; i++) + { + if (views[i].size == 0) + continue; + SKIP(flags, views[i].flags); + if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0) + total_mem += g_arena.roundup(views[i].size); + } + // Grab some pagefile backed memory out of the void ... + g_arena.GrabLowMemSpace(total_mem); + // This really shouldn't fail - in 64-bit, there will always be enough address space. + // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors. + base = MemArena::Find4GBBase(); +#endif + + + // Now, create views in high memory where there's plenty of space. +#ifdef _WIN32 + // 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) + { + 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; + break; + } + } + + if (base_attempts) + PanicAlert("No possible memory base pointer found!"); +#else + // Try base we retrieved earlier + if (!Memory_TryBase(flags)) + { + ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + } +#endif + return; +} + +void MemoryMap_Shutdown(u32 flags) +{ +#ifdef __SYMBIAN32__ + memmap->Decommit(0, memmap->MaxSize()); + memmap->Close(); + delete memmap; +#else + for (int i = 0; i < num_views; i++) + { + if (views[i].size == 0) + continue; + SKIP(flags, views[i].flags); + if (views[i].out_ptr_low && *views[i].out_ptr_low) + g_arena.ReleaseView(*views[i].out_ptr_low, views[i].size); + if (*views[i].out_ptr && (!views[i].out_ptr_low || *views[i].out_ptr != *views[i].out_ptr_low)) + g_arena.ReleaseView(*views[i].out_ptr, views[i].size); + *views[i].out_ptr = NULL; + if (views[i].out_ptr_low) + *views[i].out_ptr_low = NULL; + } + g_arena.ReleaseSpace(); +#endif +} + void Init() { int flags = 0; @@ -129,7 +328,7 @@ void Init() if (views[i].flags & MV_IS_EXTRA2_RAM) views[i].size = std::min(std::max((int)g_MemorySize - MAX_MMAP_SIZE * 2, 0), MAX_MMAP_SIZE); } - base = MemoryMap_Setup(views, num_views, flags, &g_arena); + MemoryMap_Setup(flags); INFO_LOG(MEMMAP, "Memory system initialized. RAM at %p (mirror at 0 @ %p, uncached @ %p)", m_pRAM, m_pPhysicalRAM, m_pUncachedRAM); @@ -170,8 +369,8 @@ void DoState(PointerWrap &p) void Shutdown() { u32 flags = 0; - MemoryMap_Shutdown(views, num_views, flags, &g_arena); - g_arena.ReleaseSpace(); + + MemoryMap_Shutdown(flags); base = NULL; DEBUG_LOG(MEMMAP, "Memory system shut down."); } diff --git a/Core/MemMap.h b/Core/MemMap.h index 5b1de5fa11..c0d25dcac1 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -18,6 +18,9 @@ #pragma once #include +#ifdef __SYMBIAN32__ +#include +#endif // Includes #include "Common/Common.h" @@ -93,6 +96,28 @@ enum #endif }; +enum { + MV_MIRROR_PREVIOUS = 1, + // MV_FAKE_VMEM = 2, + // MV_WII_ONLY = 4, + MV_IS_PRIMARY_RAM = 0x100, + MV_IS_EXTRA1_RAM = 0x200, + MV_IS_EXTRA2_RAM = 0x400, +}; + +struct MemoryView +{ + u8 **out_ptr_low; + u8 **out_ptr; + u32 virtual_address; + u32 size; + u32 flags; +}; + +// Uses a memory arena to set up an emulator-friendly memory map +void MemoryMap_Setup(u32 flags); +void MemoryMap_Shutdown(u32 flags); + // Init and Shutdown void Init(); void Shutdown(); diff --git a/Qt/Common.pro b/Qt/Common.pro index 51a503fa20..c4284e68ab 100755 --- a/Qt/Common.pro +++ b/Qt/Common.pro @@ -31,12 +31,16 @@ win32 { HEADERS += $$P/Common/stdafx.h } +!symbian { + SOURCES += $$P/Common/MemArena.cpp + HEADERS += $$P/Common/MemArena.h +} + SOURCES += $$P/Common/ChunkFile.cpp \ $$P/Common/ConsoleListener.cpp \ $$P/Common/FileUtil.cpp \ $$P/Common/LogManager.cpp \ $$P/Common/KeyMap.cpp \ - $$P/Common/MemArena.cpp \ $$P/Common/MemoryUtil.cpp \ $$P/Common/Misc.cpp \ $$P/Common/MsgHandler.cpp \ @@ -49,7 +53,6 @@ HEADERS += $$P/Common/ChunkFile.h \ $$P/Common/FileUtil.h \ $$P/Common/LogManager.h \ $$P/Common/KeyMap.h \ - $$P/Common/MemArena.h \ $$P/Common/MemoryUtil.h \ $$P/Common/MsgHandler.h \ $$P/Common/StringUtils.h \