| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2008 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:09:55 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <cstddef>
 | 
					
						
							|  |  |  | #include <cstdlib>
 | 
					
						
							| 
									
										
										
										
											2013-10-19 18:58:02 -04:00
										 |  |  | #include <set>
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 12:53:32 +02:00
										 |  |  | #include "Common/CommonFuncs.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/MemArena.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-26 17:13:07 -04:00
										 |  |  | #include "Common/MsgHandler.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/StringUtil.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-16 02:58:34 +00:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  | #include <windows.h>
 | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #include <cerrno>
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <sys/mman.h>
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #ifdef ANDROID
 | 
					
						
							|  |  |  | #include <linux/ashmem.h>
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <sys/ioctl.h>
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #ifdef ANDROID
 | 
					
						
							|  |  |  | #define ASHMEM_DEVICE "/dev/ashmem"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 20:46:25 +01:00
										 |  |  | static int AshmemCreateFileMapping(const char* name, size_t size) | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int fd, ret; | 
					
						
							|  |  |  |   fd = open(ASHMEM_DEVICE, O_RDWR); | 
					
						
							|  |  |  |   if (fd < 0) | 
					
						
							|  |  |  |     return fd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // We don't really care if we can't set the name, it is optional
 | 
					
						
							|  |  |  |   ioctl(fd, ASHMEM_SET_NAME, name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ret = ioctl(fd, ASHMEM_SET_SIZE, size); | 
					
						
							|  |  |  |   if (ret < 0) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     NOTICE_LOG(MEMMAP, "Ashmem returned error: 0x%08x", ret); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return fd; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-01 13:30:14 -07:00
										 |  |  | void MemArena::GrabSHMSegment(size_t size) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   hMemoryMapping = | 
					
						
							|  |  |  |       CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #elif defined(ANDROID)
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   fd = AshmemCreateFileMapping("Dolphin-emu", size); | 
					
						
							|  |  |  |   if (fd < 0) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     NOTICE_LOG(MEMMAP, "Ashmem allocation failed"); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (int i = 0; i < 10000; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::string file_name = StringFromFormat("/dolphinmem.%d", i); | 
					
						
							|  |  |  |     fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); | 
					
						
							|  |  |  |     if (fd != -1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       shm_unlink(file_name.c_str()); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (errno != EEXIST) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno)); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (ftruncate(fd, size) < 0) | 
					
						
							|  |  |  |     ERROR_LOG(MEMMAP, "Failed to allocate low memory space"); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-01 13:30:14 -07:00
										 |  |  | void MemArena::ReleaseSHMSegment() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   CloseHandle(hMemoryMapping); | 
					
						
							|  |  |  |   hMemoryMapping = 0; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   close(fd); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-21 21:16:51 +01:00
										 |  |  | void* MemArena::CreateView(s64 offset, size_t size, void* base) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   void* retval = mmap(base, size, PROT_READ | PROT_WRITE, | 
					
						
							|  |  |  |                       MAP_SHARED | ((base == nullptr) ? 0 : MAP_FIXED), fd, offset); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (retval == MAP_FAILED) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     NOTICE_LOG(MEMMAP, "mmap failed"); | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return retval; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MemArena::ReleaseView(void* view, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   UnmapViewOfFile(view); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   munmap(view, size); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-17 13:17:36 -08:00
										 |  |  | u8* MemArena::FindMemoryBase() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-04-14 12:53:32 +02:00
										 |  |  | #if _ARCH_32
 | 
					
						
							|  |  |  |   const size_t memory_size = 0x31000000; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |   const size_t memory_size = 0x400000000; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2017-04-14 12:53:32 +02:00
										 |  |  |   u8* base = static_cast<u8*>(VirtualAlloc(nullptr, memory_size, MEM_RESERVE, PAGE_READWRITE)); | 
					
						
							|  |  |  |   if (!base) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-08-17 20:12:44 +01:00
										 |  |  |     PanicAlert("Failed to map enough memory space: %s", GetLastErrorString().c_str()); | 
					
						
							| 
									
										
										
										
											2017-04-14 12:53:32 +02:00
										 |  |  |     return nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   VirtualFree(base, 0, MEM_RELEASE); | 
					
						
							|  |  |  |   return base; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2013-03-24 21:06:34 -05:00
										 |  |  | #ifdef ANDROID
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Android 4.3 changed how mmap works.
 | 
					
						
							|  |  |  |   // if we map it private and then munmap it, we can't use the base returned.
 | 
					
						
							|  |  |  |   // This may be due to changes in them support a full SELinux implementation.
 | 
					
						
							|  |  |  |   const int flags = MAP_ANON | MAP_SHARED; | 
					
						
							| 
									
										
										
										
											2013-03-24 21:06:34 -05:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const int flags = MAP_ANON | MAP_PRIVATE; | 
					
						
							| 
									
										
										
										
											2013-03-24 21:06:34 -05:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-04-14 12:53:32 +02:00
										 |  |  |   void* base = mmap(nullptr, memory_size, PROT_NONE, flags, -1, 0); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (base == MAP_FAILED) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-08-17 20:12:44 +01:00
										 |  |  |     PanicAlert("Failed to map enough memory space: %s", LastStrerrorString().c_str()); | 
					
						
							| 
									
										
										
										
											2017-04-14 12:53:32 +02:00
										 |  |  |     return nullptr; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-04-14 12:53:32 +02:00
										 |  |  |   munmap(base, memory_size); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return static_cast<u8*>(base); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } |