forked from eden-emu/eden
		
	grabbed ppsspp's MemArena
This commit is contained in:
		
							parent
							
								
									4fdeadb8e2
								
							
						
					
					
						commit
						07ea22de5c
					
				
					 2 changed files with 423 additions and 216 deletions
				
			
		|  | @ -1,14 +1,27 @@ | ||||||
| // Copyright 2013 Dolphin Emulator Project
 | // Copyright (C) 2003 Dolphin Project.
 | ||||||
| // Licensed under GPLv2
 |  | ||||||
| // Refer to the license.txt file included.
 |  | ||||||
| 
 | 
 | ||||||
|  | // 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 <string> | ||||||
| 
 | 
 | ||||||
| #include "common.h" |  | ||||||
| #include "memory_util.h" | #include "memory_util.h" | ||||||
| #include "mem_arena.h" | #include "mem_arena.h" | ||||||
| 
 | 
 | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| #include <windows.h> | //#include "CommonWindows.h"
 | ||||||
| #else | #else | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
|  | @ -20,54 +33,133 @@ | ||||||
| #include <linux/ashmem.h> | #include <linux/ashmem.h> | ||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
| #include <set> |  | ||||||
| 
 | 
 | ||||||
| #if defined(__APPLE__) | #ifdef IOS | ||||||
| static const char* ram_temp_file = "/tmp/gc_mem.tmp"; | void* globalbase = NULL; | ||||||
| #elif !defined(_WIN32) // non OSX unixes
 |  | ||||||
| static const char* ram_temp_file = "/dev/shm/gc_mem.tmp"; |  | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
| #ifdef ANDROID | #ifdef ANDROID | ||||||
|  | 
 | ||||||
|  | // Hopefully this ABI will never change...
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| #define ASHMEM_DEVICE	"/dev/ashmem" | #define ASHMEM_DEVICE	"/dev/ashmem" | ||||||
| 
 | 
 | ||||||
| int AshmemCreateFileMapping(const char *name, size_t size) | /*
 | ||||||
|  | * 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) | ||||||
|  | * `size' is the size of the region, in page-aligned bytes | ||||||
|  | */ | ||||||
|  | int ashmem_create_region(const char *name, size_t size) | ||||||
| { | { | ||||||
|     int fd, ret; |     int fd, ret; | ||||||
|  | 
 | ||||||
|     fd = open(ASHMEM_DEVICE, O_RDWR); |     fd = open(ASHMEM_DEVICE, O_RDWR); | ||||||
|     if (fd < 0) |     if (fd < 0) | ||||||
|         return fd; |         return fd; | ||||||
| 
 | 
 | ||||||
| 	// We don't really care if we can't set the name, it is optional	
 |     if (name) { | ||||||
| 	ret = ioctl(fd, ASHMEM_SET_NAME, name); |         char buf[ASHMEM_NAME_LEN]; | ||||||
|  | 
 | ||||||
|  |         strncpy(buf, name, sizeof(buf)); | ||||||
|  |         ret = ioctl(fd, ASHMEM_SET_NAME, buf); | ||||||
|  |         if (ret < 0) | ||||||
|  |             goto error; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     ret = ioctl(fd, ASHMEM_SET_SIZE, size); |     ret = ioctl(fd, ASHMEM_SET_SIZE, size); | ||||||
|     if (ret < 0) |     if (ret < 0) | ||||||
| 	{ |         goto error; | ||||||
|  | 
 | ||||||
|  |     return fd; | ||||||
|  | 
 | ||||||
|  | error: | ||||||
|  |     ERROR_LOG(MEMMAP, "NASTY ASHMEM ERROR: ret = %08x", ret); | ||||||
|     close(fd); |     close(fd); | ||||||
| 		NOTICE_LOG(MEMMAP, "Ashmem returned error: 0x%08x", ret); |  | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 	return fd; | 
 | ||||||
|  | int ashmem_set_prot_region(int fd, int prot) | ||||||
|  | { | ||||||
|  |     return ioctl(fd, ASHMEM_SET_PROT_MASK, prot); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ashmem_pin_region(int fd, size_t offset, size_t len) | ||||||
|  | { | ||||||
|  |     struct ashmem_pin pin = { offset, len }; | ||||||
|  |     return ioctl(fd, ASHMEM_PIN, &pin); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ashmem_unpin_region(int fd, size_t offset, size_t len) | ||||||
|  | { | ||||||
|  |     struct ashmem_pin pin = { offset, len }; | ||||||
|  |     return ioctl(fd, ASHMEM_UNPIN, &pin); | ||||||
|  | } | ||||||
|  | #endif  // Android
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #ifndef _WIN32 | ||||||
|  | // do not make this "static"
 | ||||||
|  | #if defined(MAEMO) || defined(MEEGO_EDITION_HARMATTAN) | ||||||
|  | std::string ram_temp_file = "/home/user/gc_mem.tmp"; | ||||||
|  | #else | ||||||
|  | std::string ram_temp_file = "/tmp/gc_mem.tmp"; | ||||||
|  | #endif | ||||||
|  | #elif !defined(_XBOX) | ||||||
|  | SYSTEM_INFO sysInfo; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Windows mappings need to be on 64K boundaries, due to Alpha legacy.
 | ||||||
|  | #ifdef _WIN32 | ||||||
|  | size_t roundup(size_t x) { | ||||||
|  | #ifndef _XBOX | ||||||
|  |     int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; | ||||||
|  | #else | ||||||
|  |     int gran = 0x10000; // 64k in 360
 | ||||||
|  | #endif | ||||||
|  |     return (x + gran - 1) & ~(gran - 1); | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | size_t roundup(size_t x) { | ||||||
|  |     return x; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| void MemArena::GrabLowMemSpace(size_t size) | void MemArena::GrabLowMemSpace(size_t size) | ||||||
| { | { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|  | #ifndef _XBOX | ||||||
|     hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); |     hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); | ||||||
|  |     GetSystemInfo(&sysInfo); | ||||||
|  | #endif | ||||||
| #elif defined(ANDROID) | #elif defined(ANDROID) | ||||||
| 	fd = AshmemCreateFileMapping("Dolphin-emu", size); |     // Use ashmem so we don't have to allocate a file on disk!
 | ||||||
|  |     fd = ashmem_create_region("PPSSPP_RAM", size); | ||||||
|  |     // Note that it appears that ashmem is pinned by default, so no need to pin.
 | ||||||
|     if (fd < 0) |     if (fd < 0) | ||||||
|     { |     { | ||||||
| 		NOTICE_LOG(MEMMAP, "Ashmem allocation failed"); |         ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x  errno: %d", (int)size, (int)(errno)); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| #else | #else | ||||||
|     mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; |     mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; | ||||||
| 	fd = open(ram_temp_file, O_RDWR | O_CREAT, mode); |     fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode); | ||||||
| 	unlink(ram_temp_file); |     if (fd < 0) | ||||||
| 	if (ftruncate(fd, size) < 0) |     { | ||||||
| 		ERROR_LOG(MEMMAP, "Failed to allocate low memory space"); |         ERROR_LOG(MEMMAP, "Failed to grab memory space as a file: %s of size: %08x  errno: %d", ram_temp_file.c_str(), (int)size, (int)(errno)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     // delete immediately, we keep the fd so it still lives
 | ||||||
|  |     unlink(ram_temp_file.c_str()); | ||||||
|  |     if (ftruncate(fd, size) != 0) | ||||||
|  |     { | ||||||
|  |         ERROR_LOG(MEMMAP, "Failed to ftruncate %d to size %08x", (int)fd, (int)size); | ||||||
|  |     } | ||||||
|     return; |     return; | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  | @ -78,6 +170,9 @@ void MemArena::ReleaseSpace() | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|     CloseHandle(hMemoryMapping); |     CloseHandle(hMemoryMapping); | ||||||
|     hMemoryMapping = 0; |     hMemoryMapping = 0; | ||||||
|  | #elif defined(__SYMBIAN32__) | ||||||
|  |     memmap->Close(); | ||||||
|  |     delete memmap; | ||||||
| #else | #else | ||||||
|     close(fd); |     close(fd); | ||||||
| #endif | #endif | ||||||
|  | @ -87,23 +182,32 @@ void MemArena::ReleaseSpace() | ||||||
| void *MemArena::CreateView(s64 offset, size_t size, void *base) | void *MemArena::CreateView(s64 offset, size_t size, void *base) | ||||||
| { | { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	return MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); | #ifdef _XBOX | ||||||
|  |     size = roundup(size); | ||||||
|  |     // use 64kb pages
 | ||||||
|  |     void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); | ||||||
|  |     return ptr; | ||||||
| #else | #else | ||||||
| 	void *retval = mmap( |     size = roundup(size); | ||||||
| 		base, size, |     void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); | ||||||
| 		PROT_READ | PROT_WRITE, |     return ptr; | ||||||
| 		MAP_SHARED | ((base == nullptr) ? 0 : MAP_FIXED), | #endif | ||||||
| 		fd, offset); | #else | ||||||
|  |     void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED | | ||||||
|  |         // Do not sync memory to underlying file. Linux has this by default.
 | ||||||
|  | #ifdef BLACKBERRY | ||||||
|  |         MAP_NOSYNCFILE | | ||||||
|  | #elif defined(__FreeBSD__) | ||||||
|  |         MAP_NOSYNC | | ||||||
|  | #endif | ||||||
|  |         ((base == 0) ? 0 : MAP_FIXED), fd, offset); | ||||||
| 
 | 
 | ||||||
|     if (retval == MAP_FAILED) |     if (retval == MAP_FAILED) | ||||||
|     { |     { | ||||||
| 		NOTICE_LOG(MEMMAP, "mmap on %s failed", ram_temp_file); |         NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed", ram_temp_file.c_str(), (int)fd); | ||||||
| 		return nullptr; |         return 0; | ||||||
|     } |     } | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
|     return retval; |     return retval; | ||||||
| 	} |  | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -111,13 +215,17 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base) | ||||||
| void MemArena::ReleaseView(void* view, size_t size) | void MemArena::ReleaseView(void* view, size_t size) | ||||||
| { | { | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|  | #ifndef _XBOX | ||||||
|     UnmapViewOfFile(view); |     UnmapViewOfFile(view); | ||||||
|  | #endif | ||||||
|  | #elif defined(__SYMBIAN32__) | ||||||
|  |     memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size); | ||||||
| #else | #else | ||||||
|     munmap(view, size); |     munmap(view, size); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | #ifndef __SYMBIAN32__ | ||||||
| u8* MemArena::Find4GBBase() | u8* MemArena::Find4GBBase() | ||||||
| { | { | ||||||
| #ifdef _M_X64 | #ifdef _M_X64 | ||||||
|  | @ -132,42 +240,60 @@ u8* MemArena::Find4GBBase() | ||||||
|     return reinterpret_cast<u8*>(0x2300000000ULL); |     return reinterpret_cast<u8*>(0x2300000000ULL); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #else | #else // 32 bit
 | ||||||
| 	// 32 bit
 | 
 | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	// The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it.
 |     u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE); | ||||||
| 	u8* base = (u8*)VirtualAlloc(0, 0x31000000, MEM_RESERVE, PAGE_READWRITE); |  | ||||||
|     if (base) { |     if (base) { | ||||||
|         VirtualFree(base, 0, MEM_RELEASE); |         VirtualFree(base, 0, MEM_RELEASE); | ||||||
|     } |     } | ||||||
|     return base; |     return base; | ||||||
| #else | #else | ||||||
| #ifdef ANDROID | #ifdef IOS | ||||||
| 	// Android 4.3 changed how mmap works.
 |     void* base = NULL; | ||||||
| 	// if we map it private and then munmap it, we can't use the base returned.
 |     if (globalbase == NULL){ | ||||||
| 	// This may be due to changes in them support a full SELinux implementation.
 |         base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE, | ||||||
| 	const int flags = MAP_ANON; |             MAP_ANON | MAP_SHARED, -1, 0); | ||||||
| #else |  | ||||||
| 	const int flags = MAP_ANON | MAP_PRIVATE; |  | ||||||
| #endif |  | ||||||
| 	const u32 MemSize = 0x31000000; |  | ||||||
| 	void* base = mmap(0, MemSize, PROT_NONE, flags, -1, 0); |  | ||||||
|         if (base == MAP_FAILED) { |         if (base == MAP_FAILED) { | ||||||
| 		PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno)); |             PanicAlert("Failed to map 128 MB of memory space: %s", strerror(errno)); | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
| 	munmap(base, MemSize); |         munmap(base, 0x08000000); | ||||||
|  |         globalbase = base; | ||||||
|  |     } | ||||||
|  |     else{ base = globalbase; } | ||||||
|  | #else | ||||||
|  |     void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, | ||||||
|  |         MAP_ANON | MAP_SHARED, -1, 0); | ||||||
|  |     if (base == MAP_FAILED) { | ||||||
|  |         PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno)); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     munmap(base, 0x10000000); | ||||||
|  | #endif | ||||||
|     return static_cast<u8*>(base); |     return static_cast<u8*>(base); | ||||||
| #endif | #endif | ||||||
| #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) { | 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!
 |     // OK, we know where to find free space. Now grab it!
 | ||||||
|     // We just mimic the popular BAT setup.
 |     // We just mimic the popular BAT setup.
 | ||||||
| 	u32 position = 0; |     size_t position = 0; | ||||||
| 	u32 last_position = 0; |     size_t last_position = 0; | ||||||
|  | 
 | ||||||
|  | #if defined(_XBOX) | ||||||
|  |     void *ptr; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     // Zero all the pointers to be sure.
 |     // Zero all the pointers to be sure.
 | ||||||
|     for (int i = 0; i < num_views; i++) |     for (int i = 0; i < num_views; i++) | ||||||
|  | @ -181,51 +307,98 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 | ||||||
|     int i; |     int i; | ||||||
|     for (i = 0; i < num_views; i++) |     for (i = 0; i < num_views; i++) | ||||||
|     { |     { | ||||||
| 		if (views[i].flags & MV_MIRROR_PREVIOUS) { |         const MemoryView &view = views[i]; | ||||||
|  |         if (view.size == 0) | ||||||
|  |             continue; | ||||||
|  |         SKIP(flags, view.flags); | ||||||
|  |         if (view.flags & MV_MIRROR_PREVIOUS) { | ||||||
|             position = last_position; |             position = last_position; | ||||||
| 		} else { |         } | ||||||
| 			*(views[i].out_ptr_low) = (u8*)arena->CreateView(position, views[i].size); |         else { | ||||||
| 			if (!*views[i].out_ptr_low) | #ifdef __SYMBIAN32__ | ||||||
|  |             *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address); | ||||||
|  |             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; |                 goto bail; | ||||||
|         } |         } | ||||||
| #ifdef _M_X64 | #ifdef _M_X64 | ||||||
| 		*views[i].out_ptr = (u8*)arena->CreateView( |         *view.out_ptr = (u8*)arena->CreateView( | ||||||
| 			position, views[i].size, base + views[i].virtual_address); |             position, view.size, base + view.virtual_address); | ||||||
| #else | #else | ||||||
| 		if (views[i].flags & MV_MIRROR_PREVIOUS) { |         if (view.flags & MV_MIRROR_PREVIOUS) {  // TODO: should check if the two & 0x3FFFFFFF are identical.
 | ||||||
|             // No need to create multiple identical views.
 |             // No need to create multiple identical views.
 | ||||||
| 			*views[i].out_ptr = *views[i - 1].out_ptr; |             *view.out_ptr = *views[i - 1].out_ptr; | ||||||
| 		} else { |         } | ||||||
| 			*views[i].out_ptr = (u8*)arena->CreateView( |         else { | ||||||
| 				position, views[i].size, base + (views[i].virtual_address & 0x3FFFFFFF)); |             *view.out_ptr = (u8*)arena->CreateView( | ||||||
| 			if (!*views[i].out_ptr) |                 position, view.size, base + (view.virtual_address & 0x3FFFFFFF)); | ||||||
|  |             if (!*view.out_ptr) | ||||||
|                 goto bail; |                 goto bail; | ||||||
|         } |         } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|         last_position = position; |         last_position = position; | ||||||
| 		position += views[i].size; |         position += roundup(view.size); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| 
 | 
 | ||||||
| bail: | bail: | ||||||
|     // Argh! ERROR! Free what we grabbed so far so we can try again.
 |     // Argh! ERROR! Free what we grabbed so far so we can try again.
 | ||||||
| 	MemoryMap_Shutdown(views, i+1, flags, arena); |     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; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena) | u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena) | ||||||
| { | { | ||||||
| 	u32 total_mem = 0; |     size_t total_mem = 0; | ||||||
|     int base_attempts = 0; |     int base_attempts = 0; | ||||||
| 
 | 
 | ||||||
|     for (int i = 0; i < num_views; i++) |     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) |         if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0) | ||||||
| 			total_mem += views[i].size; |             total_mem += roundup(views[i].size); | ||||||
|     } |     } | ||||||
|     // Grab some pagefile backed memory out of the void ...
 |     // Grab some pagefile backed memory out of the void ...
 | ||||||
|  | #ifndef __SYMBIAN32__ | ||||||
|     arena->GrabLowMemSpace(total_mem); |     arena->GrabLowMemSpace(total_mem); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     // Now, create views in high memory where there's plenty of space.
 |     // Now, create views in high memory where there's plenty of space.
 | ||||||
| #ifdef _M_X64 | #ifdef _M_X64 | ||||||
|  | @ -233,18 +406,25 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena | ||||||
|     // This really shouldn't fail - in 64-bit, there will always be enough
 |     // This really shouldn't fail - in 64-bit, there will always be enough
 | ||||||
|     // address space.
 |     // address space.
 | ||||||
|     if (!Memory_TryBase(base, views, num_views, flags, arena)) |     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."); |         PanicAlert("MemoryMap_Setup: Failed finding a memory base."); | ||||||
|         exit(0); |         exit(0); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| #else | #elif defined(_WIN32) | ||||||
| #ifdef _WIN32 |  | ||||||
|     // Try a whole range of possible bases. Return once we got a valid one.
 |     // Try a whole range of possible bases. Return once we got a valid one.
 | ||||||
| 	u32 max_base_addr = 0x7FFF0000 - 0x31000000; |     u32 max_base_addr = 0x7FFF0000 - 0x10000000; | ||||||
|     u8 *base = NULL; |     u8 *base = NULL; | ||||||
| 
 | 
 | ||||||
| 	for (u32 base_addr = 0x40000; base_addr < max_base_addr; base_addr += 0x40000) |     for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000) | ||||||
|     { |     { | ||||||
|         base_attempts++; |         base_attempts++; | ||||||
|         base = (u8 *)base_addr; |         base = (u8 *)base_addr; | ||||||
|  | @ -254,19 +434,25 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena | ||||||
|             base_attempts = 0; |             base_attempts = 0; | ||||||
|             break; |             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 | #else | ||||||
|     // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors.
 |     // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors.
 | ||||||
|     u8 *base = MemArena::Find4GBBase(); |     u8 *base = MemArena::Find4GBBase(); | ||||||
|     if (!Memory_TryBase(base, views, num_views, flags, arena)) |     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."); |         PanicAlert("MemoryMap_Setup: Failed finding a memory base."); | ||||||
| 		exit(0); |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #endif | #endif | ||||||
|     if (base_attempts) |     if (base_attempts) | ||||||
|         PanicAlert("No possible memory base pointer found!"); |         PanicAlert("No possible memory base pointer found!"); | ||||||
|  | @ -275,20 +461,17 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena | ||||||
| 
 | 
 | ||||||
| void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) | void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) | ||||||
| { | { | ||||||
| 	std::set<void*> freeset; |  | ||||||
|     for (int i = 0; i < num_views; i++) |     for (int i = 0; i < num_views; i++) | ||||||
|     { |     { | ||||||
| 		const MemoryView* view = &views[i]; |         if (views[i].size == 0) | ||||||
| 		u8** outptrs[2] = {view->out_ptr_low, view->out_ptr}; |             continue; | ||||||
| 		for (int j = 0; j < 2; j++) |         SKIP(flags, views[i].flags); | ||||||
| 		{ |         if (views[i].out_ptr_low && *views[i].out_ptr_low) | ||||||
| 			u8** outptr = outptrs[j]; |             arena->ReleaseView(*views[i].out_ptr_low, views[i].size); | ||||||
| 			if (outptr && *outptr && !freeset.count(*outptr)) |         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); | ||||||
| 				arena->ReleaseView(*outptr, view->size); |         *views[i].out_ptr = NULL; | ||||||
| 				freeset.insert(*outptr); |         if (views[i].out_ptr_low) | ||||||
| 				*outptr = NULL; |             *views[i].out_ptr_low = NULL; | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,19 @@ | ||||||
| // Copyright 2013 Dolphin Emulator Project
 | // Copyright (C) 2003 Dolphin Project.
 | ||||||
| // Licensed under GPLv2
 |  | ||||||
| // Refer to the license.txt file included.
 |  | ||||||
| 
 | 
 | ||||||
|  | // 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/
 | ||||||
| 
 | 
 | ||||||
| #ifndef _MEMARENA_H_ | #ifndef _MEMARENA_H_ | ||||||
| #define _MEMARENA_H_ | #define _MEMARENA_H_ | ||||||
|  | @ -10,10 +22,14 @@ | ||||||
| #include <windows.h> | #include <windows.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef __SYMBIAN32__ | ||||||
|  | #include <e32std.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #include "common.h" | #include "common.h" | ||||||
| 
 | 
 | ||||||
| // This class lets you create a block of anonymous RAM, and then arbitrarily map views into it.
 | // This class lets you create a block of anonymous RAM, and then arbitrarily map views into it.
 | ||||||
| // Multiple views can mirror the same section of the block, which makes it very convenient for emulating
 | // Multiple views can mirror the same section of the block, which makes it very convient for emulating
 | ||||||
| // memory mirrors.
 | // memory mirrors.
 | ||||||
| 
 | 
 | ||||||
| class MemArena | class MemArena | ||||||
|  | @ -21,11 +37,15 @@ class MemArena | ||||||
| public: | public: | ||||||
|     void GrabLowMemSpace(size_t size); |     void GrabLowMemSpace(size_t size); | ||||||
|     void ReleaseSpace(); |     void ReleaseSpace(); | ||||||
| 	void *CreateView(s64 offset, size_t size, void *base = nullptr); |     void *CreateView(s64 offset, size_t size, void *base = 0); | ||||||
|     void ReleaseView(void *view, size_t size); |     void ReleaseView(void *view, size_t size); | ||||||
| 
 | 
 | ||||||
|  | #ifdef __SYMBIAN32__ | ||||||
|  |     RChunk* memmap; | ||||||
|  | #else | ||||||
|     // This only finds 1 GB in 32-bit
 |     // This only finds 1 GB in 32-bit
 | ||||||
|     static u8 *Find4GBBase(); |     static u8 *Find4GBBase(); | ||||||
|  | #endif | ||||||
| private: | private: | ||||||
| 
 | 
 | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|  | @ -37,7 +57,11 @@ private: | ||||||
| 
 | 
 | ||||||
| enum { | enum { | ||||||
|     MV_MIRROR_PREVIOUS = 1, |     MV_MIRROR_PREVIOUS = 1, | ||||||
|  |     // MV_FAKE_VMEM = 2,
 | ||||||
|  |     // MV_WII_ONLY = 4,
 | ||||||
|     MV_IS_PRIMARY_RAM = 0x100, |     MV_IS_PRIMARY_RAM = 0x100, | ||||||
|  |     MV_IS_EXTRA1_RAM = 0x200, | ||||||
|  |     MV_IS_EXTRA2_RAM = 0x400, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct MemoryView | struct MemoryView | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bunnei
						bunnei