1 // Copyright (C) 2003 Dolphin Project / 2012 PPSSPP Project.
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 #pragma once
19
20 #include "ppsspp_config.h"
21
22 #include <cstring>
23 #include <cstdint>
24 #ifndef offsetof
25 #include <stddef.h>
26 #endif
27
28 // Includes
29 #include "Common/Common.h"
30 #include "Common/CommonTypes.h"
31 #include "Common/Swap.h"
32 #include "Core/Opcode.h"
33
34 // PPSSPP is very aggressive about trying to do memory accesses directly, for speed.
35 // This can be a problem when debugging though, as stray memory reads and writes will
36 // crash the whole emulator.
37 // If safe memory is enabled and JIT is disabled, all memory access will go through the proper
38 // memory access functions, and thus won't crash the emu when they go out of bounds.
39 #if defined(_DEBUG)
40 //#define SAFE_MEMORY
41 #endif
42
43 // Global declarations
44 class PointerWrap;
45
46 typedef void (*writeFn8 )(const u8, const u32);
47 typedef void (*writeFn16)(const u16,const u32);
48 typedef void (*writeFn32)(const u32,const u32);
49 typedef void (*writeFn64)(const u64,const u32);
50
51 typedef void (*readFn8 )(u8&, const u32);
52 typedef void (*readFn16)(u16&, const u32);
53 typedef void (*readFn32)(u32&, const u32);
54 typedef void (*readFn64)(u64&, const u32);
55
56 namespace Memory {
57 // Base is a pointer to the base of the memory map. Yes, some MMU tricks
58 // are used to set up a full GC or Wii memory map in process memory. on
59 // 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that
60 // some things are mirrored too many times, but eh... it works.
61
62 // In 64-bit, this might point to "high memory" (above the 32-bit limit),
63 // so be sure to load it into a 64-bit register.
64 extern u8 *base;
65
66 // This replaces RAM_NORMAL_SIZE at runtime.
67 extern u32 g_MemorySize;
68 extern u32 g_PSPModel;
69
70 // UWP has such limited memory management that we need to mask
71 // even in 64-bit mode. Also, when using the sanitizer, we need to mask as well.
72 #if PPSSPP_ARCH(32BIT) || PPSSPP_PLATFORM(UWP) || USE_ASAN || PPSSPP_PLATFORM(IOS)
73 #define MASKED_PSP_MEMORY
74 #endif
75
76 enum
77 {
78 // This may be adjusted by remaster games.
79 RAM_NORMAL_SIZE = 0x02000000,
80 // Used if the PSP model is PSP-2000 (Slim).
81 RAM_DOUBLE_SIZE = RAM_NORMAL_SIZE * 2,
82
83 VRAM_SIZE = 0x00200000,
84
85 SCRATCHPAD_SIZE = 0x00004000,
86
87 #ifdef MASKED_PSP_MEMORY
88 // This wraparound should work for PSP too.
89 MEMVIEW32_MASK = 0x3FFFFFFF,
90 #endif
91 };
92
93 enum {
94 MV_MIRROR_PREVIOUS = 1,
95 MV_IS_PRIMARY_RAM = 0x100,
96 MV_IS_EXTRA1_RAM = 0x200,
97 MV_IS_EXTRA2_RAM = 0x400,
98 MV_KERNEL = 0x800 // Can be skipped on platforms where memory is tight.
99 };
100
101 struct MemoryView
102 {
103 u8 **out_ptr;
104 u32 virtual_address;
105 u32 size;
106 u32 flags;
107 };
108
109 // Uses a memory arena to set up an emulator-friendly memory map
110 bool MemoryMap_Setup(u32 flags);
111 void MemoryMap_Shutdown(u32 flags);
112
113 // Init and Shutdown
114 bool Init();
115 void Shutdown();
116 void DoState(PointerWrap &p);
117 void Clear();
118 // False when shutdown has already been called.
119 bool IsActive();
120
121 class MemoryInitedLock {
122 public:
123 MemoryInitedLock();
124 ~MemoryInitedLock();
125 };
126
127 // This doesn't lock memory access or anything, it just makes sure memory isn't freed.
128 // Use it when accessing PSP memory from external threads.
129 MemoryInitedLock Lock();
130
131 // used by JIT to read instructions. Does not resolve replacements.
132 Opcode Read_Opcode_JIT(const u32 _Address);
133 // used by JIT. Reads in the "Locked cache" mode
134 void Write_Opcode_JIT(const u32 _Address, const Opcode& _Value);
135
136 // Should be used by analyzers, disassemblers etc. Does resolve replacements.
137 Opcode Read_Instruction(const u32 _Address, bool resolveReplacements = false);
138 Opcode ReadUnchecked_Instruction(const u32 _Address, bool resolveReplacements = false);
139
140 u8 Read_U8(const u32 _Address);
141 u16 Read_U16(const u32 _Address);
142 u32 Read_U32(const u32 _Address);
143 u64 Read_U64(const u32 _Address);
144
GetPointerUnchecked(const u32 address)145 inline u8* GetPointerUnchecked(const u32 address) {
146 #ifdef MASKED_PSP_MEMORY
147 return (u8 *)(base + (address & MEMVIEW32_MASK));
148 #else
149 return (u8 *)(base + address);
150 #endif
151 }
152
ReadUnchecked_U32(const u32 address)153 inline u32 ReadUnchecked_U32(const u32 address) {
154 #ifdef MASKED_PSP_MEMORY
155 return *(u32_le *)(base + (address & MEMVIEW32_MASK));
156 #else
157 return *(u32_le *)(base + address);
158 #endif
159 }
160
ReadUnchecked_Float(const u32 address)161 inline float ReadUnchecked_Float(const u32 address) {
162 #ifdef MASKED_PSP_MEMORY
163 return *(float_le *)(base + (address & MEMVIEW32_MASK));
164 #else
165 return *(float_le *)(base + address);
166 #endif
167 }
168
ReadUnchecked_U16(const u32 address)169 inline u16 ReadUnchecked_U16(const u32 address) {
170 #ifdef MASKED_PSP_MEMORY
171 return *(u16_le *)(base + (address & MEMVIEW32_MASK));
172 #else
173 return *(u16_le *)(base + address);
174 #endif
175 }
176
ReadUnchecked_U8(const u32 address)177 inline u8 ReadUnchecked_U8(const u32 address) {
178 #ifdef MASKED_PSP_MEMORY
179 return (*(u8 *)(base + (address & MEMVIEW32_MASK)));
180 #else
181 return (*(u8 *)(base + address));
182 #endif
183 }
184
WriteUnchecked_U32(u32 data,u32 address)185 inline void WriteUnchecked_U32(u32 data, u32 address) {
186 #ifdef MASKED_PSP_MEMORY
187 *(u32_le *)(base + (address & MEMVIEW32_MASK)) = data;
188 #else
189 *(u32_le *)(base + address) = data;
190 #endif
191 }
192
WriteUnchecked_Float(float data,u32 address)193 inline void WriteUnchecked_Float(float data, u32 address) {
194 #ifdef MASKED_PSP_MEMORY
195 *(float_le *)(base + (address & MEMVIEW32_MASK)) = data;
196 #else
197 *(float_le *)(base + address) = data;
198 #endif
199 }
200
WriteUnchecked_U16(u16 data,u32 address)201 inline void WriteUnchecked_U16(u16 data, u32 address) {
202 #ifdef MASKED_PSP_MEMORY
203 *(u16_le *)(base + (address & MEMVIEW32_MASK)) = data;
204 #else
205 *(u16_le *)(base + address) = data;
206 #endif
207 }
208
WriteUnchecked_U8(u8 data,u32 address)209 inline void WriteUnchecked_U8(u8 data, u32 address) {
210 #ifdef MASKED_PSP_MEMORY
211 (*(u8 *)(base + (address & MEMVIEW32_MASK))) = data;
212 #else
213 (*(u8 *)(base + address)) = data;
214 #endif
215 }
216
Read_Float(u32 address)217 inline float Read_Float(u32 address)
218 {
219 u32 ifloat = Read_U32(address);
220 float f;
221 memcpy(&f, &ifloat, sizeof(float));
222 return f;
223 }
224
225 // used by JIT. Return zero-extended 32bit values
226 u32 Read_U8_ZX(const u32 address);
227 u32 Read_U16_ZX(const u32 address);
228
229 void Write_U8(const u8 data, const u32 address);
230 void Write_U16(const u16 data, const u32 address);
231 void Write_U32(const u32 data, const u32 address);
232 void Write_U64(const u64 data, const u32 address);
233
Write_Float(float f,u32 address)234 inline void Write_Float(float f, u32 address)
235 {
236 u32 u;
237 memcpy(&u, &f, sizeof(float));
238 Write_U32(u, address);
239 }
240
241 u8* GetPointer(const u32 address);
242 bool IsRAMAddress(const u32 address);
IsVRAMAddress(const u32 address)243 inline bool IsVRAMAddress(const u32 address) {
244 return ((address & 0x3F800000) == 0x04000000);
245 }
IsDepthTexVRAMAddress(const u32 address)246 inline bool IsDepthTexVRAMAddress(const u32 address) {
247 return ((address & 0x3FE00000) == 0x04200000) || ((address & 0x3FE00000) == 0x04600000);
248 }
249
250 // 0x08000000 -> 0x08800000
IsKernelAddress(const u32 address)251 inline bool IsKernelAddress(const u32 address) {
252 return ((address & 0x3F800000) == 0x08000000);
253 }
254
255 // 0x08000000 -> 0x08400000
IsKernelAndNotVolatileAddress(const u32 address)256 inline bool IsKernelAndNotVolatileAddress(const u32 address) {
257 return ((address & 0x3FC00000) == 0x08000000);
258 }
259
260 bool IsScratchpadAddress(const u32 address);
261
262 // Used for auto-converted char * parameters, which can sometimes legitimately be null -
263 // so we don't want to get caught in GetPointer's crash reporting.
GetCharPointer(const u32 address)264 inline const char* GetCharPointer(const u32 address) {
265 if (address) {
266 return (const char *)GetPointer(address);
267 } else {
268 return nullptr;
269 }
270 }
271
MemcpyUnchecked(void * to_data,const u32 from_address,const u32 len)272 inline void MemcpyUnchecked(void *to_data, const u32 from_address, const u32 len) {
273 memcpy(to_data, GetPointerUnchecked(from_address), len);
274 }
275
MemcpyUnchecked(const u32 to_address,const void * from_data,const u32 len)276 inline void MemcpyUnchecked(const u32 to_address, const void *from_data, const u32 len) {
277 memcpy(GetPointerUnchecked(to_address), from_data, len);
278 }
279
MemcpyUnchecked(const u32 to_address,const u32 from_address,const u32 len)280 inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const u32 len) {
281 MemcpyUnchecked(GetPointer(to_address), from_address, len);
282 }
283
IsValidAddress(const u32 address)284 inline bool IsValidAddress(const u32 address) {
285 if ((address & 0x3E000000) == 0x08000000) {
286 return true;
287 } else if ((address & 0x3F800000) == 0x04000000) {
288 return true;
289 } else if ((address & 0xBFFFC000) == 0x00010000) {
290 return true;
291 } else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {
292 return true;
293 } else {
294 return false;
295 }
296 }
297
ValidSize(const u32 address,const u32 requested_size)298 inline u32 ValidSize(const u32 address, const u32 requested_size) {
299 u32 max_size;
300 if ((address & 0x3E000000) == 0x08000000) {
301 max_size = 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF);
302 } else if ((address & 0x3F800000) == 0x04000000) {
303 max_size = 0x04800000 - (address & 0x3FFFFFFF);
304 } else if ((address & 0xBFFFC000) == 0x00010000) {
305 max_size = 0x00014000 - (address & 0x3FFFFFFF);
306 } else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {
307 max_size = 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF);
308 } else {
309 max_size = 0;
310 }
311
312 if (requested_size > max_size) {
313 return max_size;
314 }
315 return requested_size;
316 }
317
IsValidRange(const u32 address,const u32 size)318 inline bool IsValidRange(const u32 address, const u32 size) {
319 return IsValidAddress(address) && ValidSize(address, size) == size;
320 }
321
322 } // namespace Memory
323
324 template <typename T>
325 struct PSPPointer
326 {
327 u32_le ptr;
328
329 inline T &operator*() const
330 {
331 #ifdef MASKED_PSP_MEMORY
332 return *(T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));
333 #else
334 return *(T *)(Memory::base + ptr);
335 #endif
336 }
337
338 inline T &operator[](int i) const
339 {
340 #ifdef MASKED_PSP_MEMORY
341 return *((T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK)) + i);
342 #else
343 return *((T *)(Memory::base + ptr) + i);
344 #endif
345 }
346
347 inline T *operator->() const
348 {
349 #ifdef MASKED_PSP_MEMORY
350 return (T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));
351 #else
352 return (T *)(Memory::base + ptr);
353 #endif
354 }
355
356 inline PSPPointer<T> operator+(int i) const
357 {
358 PSPPointer other;
359 other.ptr = ptr + i * sizeof(T);
360 return other;
361 }
362
363 inline PSPPointer<T> &operator=(u32 p)
364 {
365 ptr = p;
366 return *this;
367 }
368
369 inline PSPPointer<T> &operator+=(int i)
370 {
371 ptr = ptr + i * sizeof(T);
372 return *this;
373 }
374
375 inline PSPPointer<T> operator-(int i) const
376 {
377 PSPPointer other;
378 other.ptr = ptr - i * sizeof(T);
379 return other;
380 }
381
382 inline PSPPointer<T> &operator-=(int i)
383 {
384 ptr = ptr - i * sizeof(T);
385 return *this;
386 }
387
388 inline PSPPointer<T> &operator++()
389 {
390 ptr += sizeof(T);
391 return *this;
392 }
393
394 inline PSPPointer<T> operator++(int i)
395 {
396 PSPPointer<T> other;
397 other.ptr = ptr;
398 ptr += sizeof(T);
399 return other;
400 }
401
402 inline PSPPointer<T> &operator--()
403 {
404 ptr -= sizeof(T);
405 return *this;
406 }
407
408 inline PSPPointer<T> operator--(int i)
409 {
410 PSPPointer<T> other;
411 other.ptr = ptr;
412 ptr -= sizeof(T);
413 return other;
414 }
415
416 inline operator T*()
417 {
418 #ifdef MASKED_PSP_MEMORY
419 return (T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));
420 #else
421 return (T *)(Memory::base + ptr);
422 #endif
423 }
424
425 inline operator const T*() const
426 {
427 #ifdef MASKED_PSP_MEMORY
428 return (const T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));
429 #else
430 return (const T *)(Memory::base + ptr);
431 #endif
432 }
433
IsValidPSPPointer434 bool IsValid() const
435 {
436 return Memory::IsValidAddress(ptr);
437 }
438
CreatePSPPointer439 static PSPPointer<T> Create(u32 ptr) {
440 PSPPointer<T> p;
441 p = ptr;
442 return p;
443 }
444 };
445
446
PSP_GetScratchpadMemoryBase()447 constexpr u32 PSP_GetScratchpadMemoryBase() { return 0x00010000;}
PSP_GetScratchpadMemoryEnd()448 constexpr u32 PSP_GetScratchpadMemoryEnd() { return 0x00014000;}
449
PSP_GetKernelMemoryBase()450 constexpr u32 PSP_GetKernelMemoryBase() { return 0x08000000;}
PSP_GetUserMemoryEnd()451 inline u32 PSP_GetUserMemoryEnd() { return PSP_GetKernelMemoryBase() + Memory::g_MemorySize;}
PSP_GetKernelMemoryEnd()452 constexpr u32 PSP_GetKernelMemoryEnd() { return 0x08400000;}
453
454 // "Volatile" RAM is between 0x08400000 and 0x08800000, can be requested by the
455 // game through sceKernelVolatileMemTryLock.
PSP_GetVolatileMemoryStart()456 constexpr u32 PSP_GetVolatileMemoryStart() { return 0x08400000; }
PSP_GetVolatileMemoryEnd()457 constexpr u32 PSP_GetVolatileMemoryEnd() { return 0x08800000; }
458
PSP_GetUserMemoryBase()459 constexpr u32 PSP_GetUserMemoryBase() { return 0x08800000; }
PSP_GetDefaultLoadAddress()460 constexpr u32 PSP_GetDefaultLoadAddress() { return 0; }
PSP_GetVidMemBase()461 constexpr u32 PSP_GetVidMemBase() { return 0x04000000; }
PSP_GetVidMemEnd()462 constexpr u32 PSP_GetVidMemEnd() { return 0x04800000; }
463
464 template <typename T>
465 inline bool operator==(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
466 return lhs.ptr == rhs.ptr;
467 }
468
469 template <typename T>
470 inline bool operator!=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
471 return lhs.ptr != rhs.ptr;
472 }
473
474 template <typename T>
475 inline bool operator<(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
476 return lhs.ptr < rhs.ptr;
477 }
478
479 template <typename T>
480 inline bool operator>(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
481 return lhs.ptr > rhs.ptr;
482 }
483
484 template <typename T>
485 inline bool operator<=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
486 return lhs.ptr <= rhs.ptr;
487 }
488
489 template <typename T>
490 inline bool operator>=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {
491 return lhs.ptr >= rhs.ptr;
492 }
493