summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2014-03-31 21:04:50 -0400
committerGravatar bunnei2014-03-31 21:04:50 -0400
commit07ea22de5c9a9a6aff494bdd84083ab4637f26f6 (patch)
treec223425ac87dba3e72cf288797850788deeed4e3 /src
parentreplaced some error logs with debug asserts (diff)
downloadyuzu-07ea22de5c9a9a6aff494bdd84083ab4637f26f6.tar.gz
yuzu-07ea22de5c9a9a6aff494bdd84083ab4637f26f6.tar.xz
yuzu-07ea22de5c9a9a6aff494bdd84083ab4637f26f6.zip
grabbed ppsspp's MemArena
Diffstat (limited to 'src')
-rw-r--r--src/common/src/mem_arena.cpp587
-rw-r--r--src/common/src/mem_arena.h62
2 files changed, 428 insertions, 221 deletions
diff --git a/src/common/src/mem_arena.cpp b/src/common/src/mem_arena.cpp
index 291103be7..1a6fcf44d 100644
--- a/src/common/src/mem_arena.cpp
+++ b/src/common/src/mem_arena.cpp
@@ -1,14 +1,27 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright (C) 2003 Dolphin Project.
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4 2
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, version 2.0 or later versions.
6
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU General Public License 2.0 for more details.
11
12// A copy of the GPL 2.0 should have been included with the program.
13// If not, see http://www.gnu.org/licenses/
14
15// Official SVN repository and contact information can be found at
16// http://code.google.com/p/dolphin-emu/
17
18#include <string>
5 19
6#include "common.h"
7#include "memory_util.h" 20#include "memory_util.h"
8#include "mem_arena.h" 21#include "mem_arena.h"
9 22
10#ifdef _WIN32 23#ifdef _WIN32
11#include <windows.h> 24//#include "CommonWindows.h"
12#else 25#else
13#include <sys/stat.h> 26#include <sys/stat.h>
14#include <fcntl.h> 27#include <fcntl.h>
@@ -20,55 +33,134 @@
20#include <linux/ashmem.h> 33#include <linux/ashmem.h>
21#endif 34#endif
22#endif 35#endif
23#include <set>
24 36
25#if defined(__APPLE__) 37#ifdef IOS
26static const char* ram_temp_file = "/tmp/gc_mem.tmp"; 38void* globalbase = NULL;
27#elif !defined(_WIN32) // non OSX unixes
28static const char* ram_temp_file = "/dev/shm/gc_mem.tmp";
29#endif 39#endif
40
30#ifdef ANDROID 41#ifdef ANDROID
31#define ASHMEM_DEVICE "/dev/ashmem"
32 42
33int AshmemCreateFileMapping(const char *name, size_t size) 43// Hopefully this ABI will never change...
44
45
46#define ASHMEM_DEVICE "/dev/ashmem"
47
48/*
49* ashmem_create_region - creates a new ashmem region and returns the file
50* descriptor, or <0 on error
51*
52* `name' is an optional label to give the region (visible in /proc/pid/maps)
53* `size' is the size of the region, in page-aligned bytes
54*/
55int ashmem_create_region(const char *name, size_t size)
56{
57 int fd, ret;
58
59 fd = open(ASHMEM_DEVICE, O_RDWR);
60 if (fd < 0)
61 return fd;
62
63 if (name) {
64 char buf[ASHMEM_NAME_LEN];
65
66 strncpy(buf, name, sizeof(buf));
67 ret = ioctl(fd, ASHMEM_SET_NAME, buf);
68 if (ret < 0)
69 goto error;
70 }
71
72 ret = ioctl(fd, ASHMEM_SET_SIZE, size);
73 if (ret < 0)
74 goto error;
75
76 return fd;
77
78error:
79 ERROR_LOG(MEMMAP, "NASTY ASHMEM ERROR: ret = %08x", ret);
80 close(fd);
81 return ret;
82}
83
84int ashmem_set_prot_region(int fd, int prot)
34{ 85{
35 int fd, ret; 86 return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
36 fd = open(ASHMEM_DEVICE, O_RDWR); 87}
37 if (fd < 0) 88
38 return fd; 89int ashmem_pin_region(int fd, size_t offset, size_t len)
39 90{
40 // We don't really care if we can't set the name, it is optional 91 struct ashmem_pin pin = { offset, len };
41 ret = ioctl(fd, ASHMEM_SET_NAME, name); 92 return ioctl(fd, ASHMEM_PIN, &pin);
42 93}
43 ret = ioctl(fd, ASHMEM_SET_SIZE, size); 94
44 if (ret < 0) 95int ashmem_unpin_region(int fd, size_t offset, size_t len)
45 { 96{
46 close(fd); 97 struct ashmem_pin pin = { offset, len };
47 NOTICE_LOG(MEMMAP, "Ashmem returned error: 0x%08x", ret); 98 return ioctl(fd, ASHMEM_UNPIN, &pin);
48 return ret; 99}
49 } 100#endif // Android
50 return fd; 101
102
103
104#ifndef _WIN32
105// do not make this "static"
106#if defined(MAEMO) || defined(MEEGO_EDITION_HARMATTAN)
107std::string ram_temp_file = "/home/user/gc_mem.tmp";
108#else
109std::string ram_temp_file = "/tmp/gc_mem.tmp";
110#endif
111#elif !defined(_XBOX)
112SYSTEM_INFO sysInfo;
113#endif
114
115
116// Windows mappings need to be on 64K boundaries, due to Alpha legacy.
117#ifdef _WIN32
118size_t roundup(size_t x) {
119#ifndef _XBOX
120 int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000;
121#else
122 int gran = 0x10000; // 64k in 360
123#endif
124 return (x + gran - 1) & ~(gran - 1);
125}
126#else
127size_t roundup(size_t x) {
128 return x;
51} 129}
52#endif 130#endif
53 131
132
54void MemArena::GrabLowMemSpace(size_t size) 133void MemArena::GrabLowMemSpace(size_t size)
55{ 134{
56#ifdef _WIN32 135#ifdef _WIN32
57 hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); 136#ifndef _XBOX
137 hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL);
138 GetSystemInfo(&sysInfo);
139#endif
58#elif defined(ANDROID) 140#elif defined(ANDROID)
59 fd = AshmemCreateFileMapping("Dolphin-emu", size); 141 // Use ashmem so we don't have to allocate a file on disk!
60 if (fd < 0) 142 fd = ashmem_create_region("PPSSPP_RAM", size);
61 { 143 // Note that it appears that ashmem is pinned by default, so no need to pin.
62 NOTICE_LOG(MEMMAP, "Ashmem allocation failed"); 144 if (fd < 0)
63 return; 145 {
64 } 146 ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
147 return;
148 }
65#else 149#else
66 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 150 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
67 fd = open(ram_temp_file, O_RDWR | O_CREAT, mode); 151 fd = open(ram_temp_file.c_str(), O_RDWR | O_CREAT, mode);
68 unlink(ram_temp_file); 152 if (fd < 0)
69 if (ftruncate(fd, size) < 0) 153 {
70 ERROR_LOG(MEMMAP, "Failed to allocate low memory space"); 154 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));
71 return; 155 return;
156 }
157 // delete immediately, we keep the fd so it still lives
158 unlink(ram_temp_file.c_str());
159 if (ftruncate(fd, size) != 0)
160 {
161 ERROR_LOG(MEMMAP, "Failed to ftruncate %d to size %08x", (int)fd, (int)size);
162 }
163 return;
72#endif 164#endif
73} 165}
74 166
@@ -76,10 +168,13 @@ void MemArena::GrabLowMemSpace(size_t size)
76void MemArena::ReleaseSpace() 168void MemArena::ReleaseSpace()
77{ 169{
78#ifdef _WIN32 170#ifdef _WIN32
79 CloseHandle(hMemoryMapping); 171 CloseHandle(hMemoryMapping);
80 hMemoryMapping = 0; 172 hMemoryMapping = 0;
173#elif defined(__SYMBIAN32__)
174 memmap->Close();
175 delete memmap;
81#else 176#else
82 close(fd); 177 close(fd);
83#endif 178#endif
84} 179}
85 180
@@ -87,23 +182,32 @@ void MemArena::ReleaseSpace()
87void *MemArena::CreateView(s64 offset, size_t size, void *base) 182void *MemArena::CreateView(s64 offset, size_t size, void *base)
88{ 183{
89#ifdef _WIN32 184#ifdef _WIN32
90 return MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); 185#ifdef _XBOX
186 size = roundup(size);
187 // use 64kb pages
188 void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
189 return ptr;
91#else 190#else
92 void *retval = mmap( 191 size = roundup(size);
93 base, size, 192 void *ptr = MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base);
94 PROT_READ | PROT_WRITE, 193 return ptr;
95 MAP_SHARED | ((base == nullptr) ? 0 : MAP_FIXED), 194#endif
96 fd, offset); 195#else
97 196 void *retval = mmap(base, size, PROT_READ | PROT_WRITE, MAP_SHARED |
98 if (retval == MAP_FAILED) 197 // Do not sync memory to underlying file. Linux has this by default.
99 { 198#ifdef BLACKBERRY
100 NOTICE_LOG(MEMMAP, "mmap on %s failed", ram_temp_file); 199 MAP_NOSYNCFILE |
101 return nullptr; 200#elif defined(__FreeBSD__)
102 } 201 MAP_NOSYNC |
103 else 202#endif
104 { 203 ((base == 0) ? 0 : MAP_FIXED), fd, offset);
105 return retval; 204
106 } 205 if (retval == MAP_FAILED)
206 {
207 NOTICE_LOG(MEMMAP, "mmap on %s (fd: %d) failed", ram_temp_file.c_str(), (int)fd);
208 return 0;
209 }
210 return retval;
107#endif 211#endif
108} 212}
109 213
@@ -111,184 +215,263 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base)
111void MemArena::ReleaseView(void* view, size_t size) 215void MemArena::ReleaseView(void* view, size_t size)
112{ 216{
113#ifdef _WIN32 217#ifdef _WIN32
114 UnmapViewOfFile(view); 218#ifndef _XBOX
219 UnmapViewOfFile(view);
220#endif
221#elif defined(__SYMBIAN32__)
222 memmap->Decommit(((int)view - (int)memmap->Base()) & 0x3FFFFFFF, size);
115#else 223#else
116 munmap(view, size); 224 munmap(view, size);
117#endif 225#endif
118} 226}
119 227
120 228#ifndef __SYMBIAN32__
121u8* MemArena::Find4GBBase() 229u8* MemArena::Find4GBBase()
122{ 230{
123#ifdef _M_X64 231#ifdef _M_X64
124#ifdef _WIN32 232#ifdef _WIN32
125 // 64 bit 233 // 64 bit
126 u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE); 234 u8* base = (u8*)VirtualAlloc(0, 0xE1000000, MEM_RESERVE, PAGE_READWRITE);
127 VirtualFree(base, 0, MEM_RELEASE); 235 VirtualFree(base, 0, MEM_RELEASE);
128 return base; 236 return base;
129#else 237#else
130 // Very precarious - mmap cannot return an error when trying to map already used pages. 238 // Very precarious - mmap cannot return an error when trying to map already used pages.
131 // This makes the Windows approach above unusable on Linux, so we will simply pray... 239 // This makes the Windows approach above unusable on Linux, so we will simply pray...
132 return reinterpret_cast<u8*>(0x2300000000ULL); 240 return reinterpret_cast<u8*>(0x2300000000ULL);
133#endif 241#endif
134 242
135#else 243#else // 32 bit
136 // 32 bit 244
137#ifdef _WIN32 245#ifdef _WIN32
138 // The highest thing in any 1GB section of memory space is the locked cache. We only need to fit it. 246 u8* base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE, PAGE_READWRITE);
139 u8* base = (u8*)VirtualAlloc(0, 0x31000000, MEM_RESERVE, PAGE_READWRITE); 247 if (base) {
140 if (base) { 248 VirtualFree(base, 0, MEM_RELEASE);
141 VirtualFree(base, 0, MEM_RELEASE); 249 }
142 } 250 return base;
143 return base;
144#else 251#else
145#ifdef ANDROID 252#ifdef IOS
146 // Android 4.3 changed how mmap works. 253 void* base = NULL;
147 // if we map it private and then munmap it, we can't use the base returned. 254 if (globalbase == NULL){
148 // This may be due to changes in them support a full SELinux implementation. 255 base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE,
149 const int flags = MAP_ANON; 256 MAP_ANON | MAP_SHARED, -1, 0);
257 if (base == MAP_FAILED) {
258 PanicAlert("Failed to map 128 MB of memory space: %s", strerror(errno));
259 return 0;
260 }
261 munmap(base, 0x08000000);
262 globalbase = base;
263 }
264 else{ base = globalbase; }
150#else 265#else
151 const int flags = MAP_ANON | MAP_PRIVATE; 266 void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE,
267 MAP_ANON | MAP_SHARED, -1, 0);
268 if (base == MAP_FAILED) {
269 PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno));
270 return 0;
271 }
272 munmap(base, 0x10000000);
152#endif 273#endif
153 const u32 MemSize = 0x31000000; 274 return static_cast<u8*>(base);
154 void* base = mmap(0, MemSize, PROT_NONE, flags, -1, 0);
155 if (base == MAP_FAILED) {
156 PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno));
157 return 0;
158 }
159 munmap(base, MemSize);
160 return static_cast<u8*>(base);
161#endif 275#endif
162#endif 276#endif
163} 277}
278#endif
164 279
165 280
281// yeah, this could also be done in like two bitwise ops...
282#define SKIP(a_flags, b_flags)
283// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY))
284// continue;
285// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))
286// continue;
287
166static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) { 288static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) {
167 // OK, we know where to find free space. Now grab it! 289 // OK, we know where to find free space. Now grab it!
168 // We just mimic the popular BAT setup. 290 // We just mimic the popular BAT setup.
169 u32 position = 0; 291 size_t position = 0;
170 u32 last_position = 0; 292 size_t last_position = 0;
171 293
172 // Zero all the pointers to be sure. 294#if defined(_XBOX)
173 for (int i = 0; i < num_views; i++) 295 void *ptr;
174 { 296#endif
175 if (views[i].out_ptr_low) 297
176 *views[i].out_ptr_low = 0; 298 // Zero all the pointers to be sure.
177 if (views[i].out_ptr) 299 for (int i = 0; i < num_views; i++)
178 *views[i].out_ptr = 0; 300 {
179 } 301 if (views[i].out_ptr_low)
180 302 *views[i].out_ptr_low = 0;
181 int i; 303 if (views[i].out_ptr)
182 for (i = 0; i < num_views; i++) 304 *views[i].out_ptr = 0;
183 { 305 }
184 if (views[i].flags & MV_MIRROR_PREVIOUS) { 306
185 position = last_position; 307 int i;
186 } else { 308 for (i = 0; i < num_views; i++)
187 *(views[i].out_ptr_low) = (u8*)arena->CreateView(position, views[i].size); 309 {
188 if (!*views[i].out_ptr_low) 310 const MemoryView &view = views[i];
189 goto bail; 311 if (view.size == 0)
190 } 312 continue;
313 SKIP(flags, view.flags);
314 if (view.flags & MV_MIRROR_PREVIOUS) {
315 position = last_position;
316 }
317 else {
318#ifdef __SYMBIAN32__
319 *(view.out_ptr_low) = (u8*)((int)arena->memmap->Base() + view.virtual_address);
320 arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size);
321 }
322 *(view.out_ptr) = (u8*)((int)arena->memmap->Base() + view.virtual_address & 0x3FFFFFFF);
323#elif defined(_XBOX)
324 *(view.out_ptr_low) = (u8*)(base + view.virtual_address);
325 //arena->memmap->Commit(view.virtual_address & 0x3FFFFFFF, view.size);
326 ptr = VirtualAlloc(base + (view.virtual_address & 0x3FFFFFFF), view.size, MEM_COMMIT, PAGE_READWRITE);
327 }
328 *(view.out_ptr) = (u8*)base + (view.virtual_address & 0x3FFFFFFF);
329#else
330 *(view.out_ptr_low) = (u8*)arena->CreateView(position, view.size);
331 if (!*view.out_ptr_low)
332 goto bail;
333 }
191#ifdef _M_X64 334#ifdef _M_X64
192 *views[i].out_ptr = (u8*)arena->CreateView( 335 *view.out_ptr = (u8*)arena->CreateView(
193 position, views[i].size, base + views[i].virtual_address); 336 position, view.size, base + view.virtual_address);
194#else 337#else
195 if (views[i].flags & MV_MIRROR_PREVIOUS) { 338 if (view.flags & MV_MIRROR_PREVIOUS) { // TODO: should check if the two & 0x3FFFFFFF are identical.
196 // No need to create multiple identical views. 339 // No need to create multiple identical views.
197 *views[i].out_ptr = *views[i - 1].out_ptr; 340 *view.out_ptr = *views[i - 1].out_ptr;
198 } else { 341 }
199 *views[i].out_ptr = (u8*)arena->CreateView( 342 else {
200 position, views[i].size, base + (views[i].virtual_address & 0x3FFFFFFF)); 343 *view.out_ptr = (u8*)arena->CreateView(
201 if (!*views[i].out_ptr) 344 position, view.size, base + (view.virtual_address & 0x3FFFFFFF));
202 goto bail; 345 if (!*view.out_ptr)
203 } 346 goto bail;
347 }
204#endif 348#endif
205 last_position = position;
206 position += views[i].size;
207 }
208 349
209 return true; 350#endif
351 last_position = position;
352 position += roundup(view.size);
353 }
354
355 return true;
210 356
211bail: 357bail:
212 // Argh! ERROR! Free what we grabbed so far so we can try again. 358 // Argh! ERROR! Free what we grabbed so far so we can try again.
213 MemoryMap_Shutdown(views, i+1, flags, arena); 359 for (int j = 0; j <= i; j++)
214 return false; 360 {
361 if (views[i].size == 0)
362 continue;
363 SKIP(flags, views[i].flags);
364 if (views[j].out_ptr_low && *views[j].out_ptr_low)
365 {
366 arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
367 *views[j].out_ptr_low = NULL;
368 }
369 if (*views[j].out_ptr)
370 {
371#ifdef _M_X64
372 arena->ReleaseView(*views[j].out_ptr, views[j].size);
373#else
374 if (!(views[j].flags & MV_MIRROR_PREVIOUS))
375 {
376 arena->ReleaseView(*views[j].out_ptr, views[j].size);
377 }
378#endif
379 *views[j].out_ptr = NULL;
380 }
381 }
382 return false;
215} 383}
216 384
217u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena) 385u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
218{ 386{
219 u32 total_mem = 0; 387 size_t total_mem = 0;
220 int base_attempts = 0; 388 int base_attempts = 0;
221 389
222 for (int i = 0; i < num_views; i++) 390 for (int i = 0; i < num_views; i++)
223 { 391 {
224 if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0) 392 if (views[i].size == 0)
225 total_mem += views[i].size; 393 continue;
226 } 394 SKIP(flags, views[i].flags);
227 // Grab some pagefile backed memory out of the void ... 395 if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0)
228 arena->GrabLowMemSpace(total_mem); 396 total_mem += roundup(views[i].size);
229 397 }
230 // Now, create views in high memory where there's plenty of space. 398 // Grab some pagefile backed memory out of the void ...
231#ifdef _M_X64 399#ifndef __SYMBIAN32__
232 u8 *base = MemArena::Find4GBBase(); 400 arena->GrabLowMemSpace(total_mem);
233 // This really shouldn't fail - in 64-bit, there will always be enough
234 // address space.
235 if (!Memory_TryBase(base, views, num_views, flags, arena))
236 {
237 PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
238 exit(0);
239 return 0;
240 }
241#else
242#ifdef _WIN32
243 // Try a whole range of possible bases. Return once we got a valid one.
244 u32 max_base_addr = 0x7FFF0000 - 0x31000000;
245 u8 *base = NULL;
246
247 for (u32 base_addr = 0x40000; base_addr < max_base_addr; base_addr += 0x40000)
248 {
249 base_attempts++;
250 base = (u8 *)base_addr;
251 if (Memory_TryBase(base, views, num_views, flags, arena))
252 {
253 INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts);
254 base_attempts = 0;
255 break;
256 }
257
258 }
259#else
260 // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors.
261 u8 *base = MemArena::Find4GBBase();
262 if (!Memory_TryBase(base, views, num_views, flags, arena))
263 {
264 PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
265 exit(0);
266 return 0;
267 }
268#endif 401#endif
269 402
403 // Now, create views in high memory where there's plenty of space.
404#ifdef _M_X64
405 u8 *base = MemArena::Find4GBBase();
406 // This really shouldn't fail - in 64-bit, there will always be enough
407 // address space.
408 if (!Memory_TryBase(base, views, num_views, flags, arena))
409 {
410 PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
411 return 0;
412 }
413#elif defined(_XBOX)
414 // Reserve 256MB
415 u8 *base = (u8*)VirtualAlloc(0, 0x10000000, MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE);
416 if (!Memory_TryBase(base, views, num_views, flags, arena))
417 {
418 PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
419 exit(0);
420 return 0;
421 }
422#elif defined(_WIN32)
423 // Try a whole range of possible bases. Return once we got a valid one.
424 u32 max_base_addr = 0x7FFF0000 - 0x10000000;
425 u8 *base = NULL;
426
427 for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000)
428 {
429 base_attempts++;
430 base = (u8 *)base_addr;
431 if (Memory_TryBase(base, views, num_views, flags, arena))
432 {
433 INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts);
434 base_attempts = 0;
435 break;
436 }
437 }
438#elif defined(__SYMBIAN32__)
439 arena->memmap = new RChunk();
440 arena->memmap->CreateDisconnectedLocal(0, 0, 0x10000000);
441 if (!Memory_TryBase(arena->memmap->Base(), views, num_views, flags, arena))
442 {
443 PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
444 return 0;
445 }
446 u8* base = arena->memmap->Base();
447#else
448 // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors.
449 u8 *base = MemArena::Find4GBBase();
450 if (!Memory_TryBase(base, views, num_views, flags, arena))
451 {
452 ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base.");
453 PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
454 return 0;
455 }
270#endif 456#endif
271 if (base_attempts) 457 if (base_attempts)
272 PanicAlert("No possible memory base pointer found!"); 458 PanicAlert("No possible memory base pointer found!");
273 return base; 459 return base;
274} 460}
275 461
276void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) 462void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
277{ 463{
278 std::set<void*> freeset; 464 for (int i = 0; i < num_views; i++)
279 for (int i = 0; i < num_views; i++) 465 {
280 { 466 if (views[i].size == 0)
281 const MemoryView* view = &views[i]; 467 continue;
282 u8** outptrs[2] = {view->out_ptr_low, view->out_ptr}; 468 SKIP(flags, views[i].flags);
283 for (int j = 0; j < 2; j++) 469 if (views[i].out_ptr_low && *views[i].out_ptr_low)
284 { 470 arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
285 u8** outptr = outptrs[j]; 471 if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
286 if (outptr && *outptr && !freeset.count(*outptr)) 472 arena->ReleaseView(*views[i].out_ptr, views[i].size);
287 { 473 *views[i].out_ptr = NULL;
288 arena->ReleaseView(*outptr, view->size); 474 if (views[i].out_ptr_low)
289 freeset.insert(*outptr); 475 *views[i].out_ptr_low = NULL;
290 *outptr = NULL; 476 }
291 }
292 }
293 }
294} 477}
diff --git a/src/common/src/mem_arena.h b/src/common/src/mem_arena.h
index 3c14756db..8bdf9f189 100644
--- a/src/common/src/mem_arena.h
+++ b/src/common/src/mem_arena.h
@@ -1,7 +1,19 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright (C) 2003 Dolphin Project.
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4 2
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, version 2.0 or later versions.
6
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU General Public License 2.0 for more details.
11
12// A copy of the GPL 2.0 should have been included with the program.
13// If not, see http://www.gnu.org/licenses/
14
15// Official SVN repository and contact information can be found at
16// http://code.google.com/p/dolphin-emu/
5 17
6#ifndef _MEMARENA_H_ 18#ifndef _MEMARENA_H_
7#define _MEMARENA_H_ 19#define _MEMARENA_H_
@@ -10,43 +22,55 @@
10#include <windows.h> 22#include <windows.h>
11#endif 23#endif
12 24
25#ifdef __SYMBIAN32__
26#include <e32std.h>
27#endif
28
13#include "common.h" 29#include "common.h"
14 30
15// This class lets you create a block of anonymous RAM, and then arbitrarily map views into it. 31// This class lets you create a block of anonymous RAM, and then arbitrarily map views into it.
16// Multiple views can mirror the same section of the block, which makes it very convenient for emulating 32// Multiple views can mirror the same section of the block, which makes it very convient for emulating
17// memory mirrors. 33// memory mirrors.
18 34
19class MemArena 35class MemArena
20{ 36{
21public: 37public:
22 void GrabLowMemSpace(size_t size); 38 void GrabLowMemSpace(size_t size);
23 void ReleaseSpace(); 39 void ReleaseSpace();
24 void *CreateView(s64 offset, size_t size, void *base = nullptr); 40 void *CreateView(s64 offset, size_t size, void *base = 0);
25 void ReleaseView(void *view, size_t size); 41 void ReleaseView(void *view, size_t size);
26 42
27 // This only finds 1 GB in 32-bit 43#ifdef __SYMBIAN32__
28 static u8 *Find4GBBase(); 44 RChunk* memmap;
45#else
46 // This only finds 1 GB in 32-bit
47 static u8 *Find4GBBase();
48#endif
29private: 49private:
30 50
31#ifdef _WIN32 51#ifdef _WIN32
32 HANDLE hMemoryMapping; 52 HANDLE hMemoryMapping;
33#else 53#else
34 int fd; 54 int fd;
35#endif 55#endif
36}; 56};
37 57
38enum { 58enum {
39 MV_MIRROR_PREVIOUS = 1, 59 MV_MIRROR_PREVIOUS = 1,
40 MV_IS_PRIMARY_RAM = 0x100, 60 // MV_FAKE_VMEM = 2,
61 // MV_WII_ONLY = 4,
62 MV_IS_PRIMARY_RAM = 0x100,
63 MV_IS_EXTRA1_RAM = 0x200,
64 MV_IS_EXTRA2_RAM = 0x400,
41}; 65};
42 66
43struct MemoryView 67struct MemoryView
44{ 68{
45 u8 **out_ptr_low; 69 u8 **out_ptr_low;
46 u8 **out_ptr; 70 u8 **out_ptr;
47 u32 virtual_address; 71 u32 virtual_address;
48 u32 size; 72 u32 size;
49 u32 flags; 73 u32 flags;
50}; 74};
51 75
52// Uses a memory arena to set up an emulator-friendly memory map according to 76// Uses a memory arena to set up an emulator-friendly memory map according to