summaryrefslogtreecommitdiff
path: root/src/common/memory_util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/memory_util.cpp')
-rw-r--r--src/common/memory_util.cpp197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
new file mode 100644
index 000000000..cc6e77b35
--- /dev/null
+++ b/src/common/memory_util.cpp
@@ -0,0 +1,197 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5
6#include "common.h"
7#include "memory_util.h"
8#include "string_util.h"
9
10#ifdef _WIN32
11#include <windows.h>
12#include <psapi.h>
13#else
14#include <errno.h>
15#include <stdio.h>
16#endif
17
18#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
19#include <unistd.h>
20#define PAGE_MASK (getpagesize() - 1)
21#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
22#endif
23
24// This is purposely not a full wrapper for virtualalloc/mmap, but it
25// provides exactly the primitive operations that Dolphin needs.
26
27void* AllocateExecutableMemory(size_t size, bool low)
28{
29#if defined(_WIN32)
30 void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
31#else
32 static char *map_hint = 0;
33#if defined(__x86_64__) && !defined(MAP_32BIT)
34 // This OS has no flag to enforce allocation below the 4 GB boundary,
35 // but if we hint that we want a low address it is very likely we will
36 // get one.
37 // An older version of this code used MAP_FIXED, but that has the side
38 // effect of discarding already mapped pages that happen to be in the
39 // requested virtual memory range (such as the emulated RAM, sometimes).
40 if (low && (!map_hint))
41 map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */
42#endif
43 void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
44 MAP_ANON | MAP_PRIVATE
45#if defined(__x86_64__) && defined(MAP_32BIT)
46 | (low ? MAP_32BIT : 0)
47#endif
48 , -1, 0);
49#endif /* defined(_WIN32) */
50
51 // printf("Mapped executable memory at %p (size %ld)\n", ptr,
52 // (unsigned long)size);
53
54#if defined(__FreeBSD__)
55 if (ptr == MAP_FAILED)
56 {
57 ptr = NULL;
58#else
59 if (ptr == NULL)
60 {
61#endif
62 PanicAlert("Failed to allocate executable memory");
63 }
64#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
65 else
66 {
67 if (low)
68 {
69 map_hint += size;
70 map_hint = (char*)round_page(map_hint); /* round up to the next page */
71 // printf("Next map will (hopefully) be at %p\n", map_hint);
72 }
73 }
74#endif
75
76#if defined(_M_X64)
77 if ((u64)ptr >= 0x80000000 && low == true)
78 PanicAlert("Executable memory ended up above 2GB!");
79#endif
80
81 return ptr;
82}
83
84void* AllocateMemoryPages(size_t size)
85{
86#ifdef _WIN32
87 void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
88#else
89 void* ptr = mmap(0, size, PROT_READ | PROT_WRITE,
90 MAP_ANON | MAP_PRIVATE, -1, 0);
91#endif
92
93 // printf("Mapped memory at %p (size %ld)\n", ptr,
94 // (unsigned long)size);
95
96 if (ptr == NULL)
97 PanicAlert("Failed to allocate raw memory");
98
99 return ptr;
100}
101
102void* AllocateAlignedMemory(size_t size,size_t alignment)
103{
104#ifdef _WIN32
105 void* ptr = _aligned_malloc(size,alignment);
106#else
107 void* ptr = NULL;
108#ifdef ANDROID
109 ptr = memalign(alignment, size);
110#else
111 if (posix_memalign(&ptr, alignment, size) != 0)
112 ERROR_LOG(MEMMAP, "Failed to allocate aligned memory");
113#endif
114#endif
115
116 // printf("Mapped memory at %p (size %ld)\n", ptr,
117 // (unsigned long)size);
118
119 if (ptr == NULL)
120 PanicAlert("Failed to allocate aligned memory");
121
122 return ptr;
123}
124
125void FreeMemoryPages(void* ptr, size_t size)
126{
127 if (ptr)
128 {
129#ifdef _WIN32
130
131 if (!VirtualFree(ptr, 0, MEM_RELEASE))
132 PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
133 ptr = NULL; // Is this our responsibility?
134
135#else
136 munmap(ptr, size);
137#endif
138 }
139}
140
141void FreeAlignedMemory(void* ptr)
142{
143 if (ptr)
144 {
145#ifdef _WIN32
146 _aligned_free(ptr);
147#else
148 free(ptr);
149#endif
150 }
151}
152
153void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
154{
155#ifdef _WIN32
156 DWORD oldValue;
157 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
158 PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg());
159#else
160 mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
161#endif
162}
163
164void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
165{
166#ifdef _WIN32
167 DWORD oldValue;
168 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
169 PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
170#else
171 mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
172#endif
173}
174
175std::string MemUsage()
176{
177#ifdef _WIN32
178#pragma comment(lib, "psapi")
179 DWORD processID = GetCurrentProcessId();
180 HANDLE hProcess;
181 PROCESS_MEMORY_COUNTERS pmc;
182 std::string Ret;
183
184 // Print information about the memory usage of the process.
185
186 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
187 if (NULL == hProcess) return "MemUsage Error";
188
189 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
190 Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
191
192 CloseHandle(hProcess);
193 return Ret;
194#else
195 return "";
196#endif
197}