CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/MemMap.h
Views: 1401
// Copyright (C) 2003 Dolphin Project / 2012 PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official SVN repository and contact information can be found at15// http://code.google.com/p/dolphin-emu/1617#pragma once1819#include "ppsspp_config.h"2021#include <cstring>22#include <cstdint>23#ifndef offsetof24#include <stddef.h>25#endif2627#include "Common/CommonTypes.h"28#include "Common/Swap.h"29#include "Core/Opcode.h"3031// PPSSPP is very aggressive about trying to do memory accesses directly, for speed.32// This can be a problem when debugging though, as stray memory reads and writes will33// crash the whole emulator.34// If safe memory is enabled and JIT is disabled, all memory access will go through the proper35// memory access functions, and thus won't crash the emu when they go out of bounds.36#if defined(_DEBUG)37//#define SAFE_MEMORY38#endif3940// Global declarations41class PointerWrap;4243typedef void (*writeFn8 )(const u8, const u32);44typedef void (*writeFn16)(const u16,const u32);45typedef void (*writeFn32)(const u32,const u32);46typedef void (*writeFn64)(const u64,const u32);4748typedef void (*readFn8 )(u8&, const u32);49typedef void (*readFn16)(u16&, const u32);50typedef void (*readFn32)(u32&, const u32);51typedef void (*readFn64)(u64&, const u32);5253namespace Memory {54// Base is a pointer to the base of the memory map. Yes, some MMU tricks55// are used to set up a full GC or Wii memory map in process memory. on56// 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that57// some things are mirrored too many times, but eh... it works.5859// In 64-bit, this might point to "high memory" (above the 32-bit limit),60// so be sure to load it into a 64-bit register.61extern u8 *base;6263// This replaces RAM_NORMAL_SIZE at runtime.64extern u32 g_MemorySize;65extern u32 g_PSPModel;6667// UWP has such limited memory management that we need to mask68// even in 64-bit mode. Also, when using the sanitizer, we need to mask as well.69#if PPSSPP_ARCH(32BIT) || PPSSPP_PLATFORM(UWP) || USE_ASAN || PPSSPP_PLATFORM(IOS) || defined(__EMSCRIPTEN__)70#define MASKED_PSP_MEMORY71#endif7273enum74{75// This may be adjusted by remaster games.76RAM_NORMAL_SIZE = 0x02000000,77// Used if the PSP model is PSP-2000 (Slim).78RAM_DOUBLE_SIZE = RAM_NORMAL_SIZE * 2,7980VRAM_SIZE = 0x00200000,8182SCRATCHPAD_SIZE = 0x00004000,8384#ifdef MASKED_PSP_MEMORY85// This wraparound should work for PSP too.86MEMVIEW32_MASK = 0x3FFFFFFF,87#endif88};8990enum {91MV_MIRROR_PREVIOUS = 1,92MV_IS_PRIMARY_RAM = 0x100,93MV_IS_EXTRA1_RAM = 0x200,94MV_IS_EXTRA2_RAM = 0x400,95MV_KERNEL = 0x800 // Can be skipped on platforms where memory is tight.96};9798struct MemoryView99{100u8 **out_ptr;101u32 virtual_address;102u32 size;103u32 flags;104};105106// Uses a memory arena to set up an emulator-friendly memory map107bool MemoryMap_Setup(u32 flags);108void MemoryMap_Shutdown(u32 flags);109110// Init and Shutdown111bool Init();112void Shutdown();113void DoState(PointerWrap &p);114void Clear();115// False when shutdown has already been called.116bool IsActive();117118class MemoryInitedLock {119public:120MemoryInitedLock();121~MemoryInitedLock();122};123124// This doesn't lock memory access or anything, it just makes sure memory isn't freed.125// Use it when accessing PSP memory from external threads.126MemoryInitedLock Lock();127128// used by JIT to read instructions. Does not resolve replacements.129Opcode Read_Opcode_JIT(const u32 _Address);130// used by JIT. Reads in the "Locked cache" mode131void Write_Opcode_JIT(const u32 _Address, const Opcode& _Value);132133// Should be used by analyzers, disassemblers etc. Does resolve replacements.134Opcode Read_Instruction(const u32 _Address, bool resolveReplacements = false);135Opcode ReadUnchecked_Instruction(const u32 _Address, bool resolveReplacements = false);136137u8 Read_U8(const u32 _Address);138u16 Read_U16(const u32 _Address);139u32 Read_U32(const u32 _Address);140u64 Read_U64(const u32 _Address);141142inline u8* GetPointerWriteUnchecked(const u32 address) {143#ifdef MASKED_PSP_MEMORY144return (u8 *)(base + (address & MEMVIEW32_MASK));145#else146return (u8 *)(base + address);147#endif148}149150inline const u8* GetPointerUnchecked(const u32 address) {151#ifdef MASKED_PSP_MEMORY152return (const u8 *)(base + (address & MEMVIEW32_MASK));153#else154return (const u8 *)(base + address);155#endif156}157158inline u32 ReadUnchecked_U32(const u32 address) {159#ifdef MASKED_PSP_MEMORY160return *(u32_le *)(base + (address & MEMVIEW32_MASK));161#else162return *(u32_le *)(base + address);163#endif164}165166inline float ReadUnchecked_Float(const u32 address) {167#ifdef MASKED_PSP_MEMORY168return *(float_le *)(base + (address & MEMVIEW32_MASK));169#else170return *(float_le *)(base + address);171#endif172}173174inline u16 ReadUnchecked_U16(const u32 address) {175#ifdef MASKED_PSP_MEMORY176return *(u16_le *)(base + (address & MEMVIEW32_MASK));177#else178return *(u16_le *)(base + address);179#endif180}181182inline u8 ReadUnchecked_U8(const u32 address) {183#ifdef MASKED_PSP_MEMORY184return (*(u8 *)(base + (address & MEMVIEW32_MASK)));185#else186return (*(u8 *)(base + address));187#endif188}189190inline void WriteUnchecked_U32(u32 data, u32 address) {191#ifdef MASKED_PSP_MEMORY192*(u32_le *)(base + (address & MEMVIEW32_MASK)) = data;193#else194*(u32_le *)(base + address) = data;195#endif196}197198inline void WriteUnchecked_Float(float data, u32 address) {199#ifdef MASKED_PSP_MEMORY200*(float_le *)(base + (address & MEMVIEW32_MASK)) = data;201#else202*(float_le *)(base + address) = data;203#endif204}205206inline void WriteUnchecked_U16(u16 data, u32 address) {207#ifdef MASKED_PSP_MEMORY208*(u16_le *)(base + (address & MEMVIEW32_MASK)) = data;209#else210*(u16_le *)(base + address) = data;211#endif212}213214inline void WriteUnchecked_U8(u8 data, u32 address) {215#ifdef MASKED_PSP_MEMORY216(*(u8 *)(base + (address & MEMVIEW32_MASK))) = data;217#else218(*(u8 *)(base + address)) = data;219#endif220}221222inline float Read_Float(u32 address)223{224u32 ifloat = Read_U32(address);225float f;226memcpy(&f, &ifloat, sizeof(float));227return f;228}229230// used by JIT. Return zero-extended 32bit values231u32 Read_U8_ZX(const u32 address);232u32 Read_U16_ZX(const u32 address);233234void Write_U8(const u8 data, const u32 address);235void Write_U16(const u16 data, const u32 address);236void Write_U32(const u32 data, const u32 address);237void Write_U64(const u64 data, const u32 address);238239inline void Write_Float(float f, u32 address)240{241u32 u;242memcpy(&u, &f, sizeof(float));243Write_U32(u, address);244}245246u8* GetPointerWrite(const u32 address);247const u8* GetPointer(const u32 address);248249u8 *GetPointerWriteRange(const u32 address, const u32 size);250const u8 *GetPointerRange(const u32 address, const u32 size);251252bool IsRAMAddress(const u32 address);253inline bool IsVRAMAddress(const u32 address) {254return ((address & 0x3F800000) == 0x04000000);255}256inline bool IsDepthTexVRAMAddress(const u32 address) {257return ((address & 0x3FE00000) == 0x04200000) || ((address & 0x3FE00000) == 0x04600000);258}259260// 0x08000000 -> 0x08800000261inline bool IsKernelAddress(const u32 address) {262return ((address & 0x3F800000) == 0x08000000);263}264265// 0x08000000 -> 0x08400000266inline bool IsKernelAndNotVolatileAddress(const u32 address) {267return ((address & 0x3FC00000) == 0x08000000);268}269270bool IsScratchpadAddress(const u32 address);271272inline void MemcpyUnchecked(void *to_data, const u32 from_address, const u32 len) {273memcpy(to_data, GetPointerUnchecked(from_address), len);274}275276inline void MemcpyUnchecked(const u32 to_address, const void *from_data, const u32 len) {277memcpy(GetPointerWriteUnchecked(to_address), from_data, len);278}279280inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const u32 len) {281MemcpyUnchecked(GetPointerWriteUnchecked(to_address), from_address, len);282}283284inline bool IsValidAddress(const u32 address) {285if ((address & 0x3E000000) == 0x08000000) {286return true;287} else if ((address & 0x3F800000) == 0x04000000) {288return true;289} else if ((address & 0xBFFFC000) == 0x00010000) {290return true;291} else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {292return true;293} else {294return false;295}296}297298inline bool IsValid4AlignedAddress(const u32 address) {299if ((address & 0x3E000003) == 0x08000000) {300return true;301} else if ((address & 0x3F800003) == 0x04000000) {302return true;303} else if ((address & 0xBFFFC003) == 0x00010000) {304return true;305} else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {306return (address & 3) == 0;307} else {308return false;309}310}311312313inline u32 MaxSizeAtAddress(const u32 address){314if ((address & 0x3E000000) == 0x08000000) {315return 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF);316} else if ((address & 0x3F800000) == 0x04000000) {317return 0x04800000 - (address & 0x3FFFFFFF);318} else if ((address & 0xBFFFC000) == 0x00010000) {319return 0x00014000 - (address & 0x3FFFFFFF);320} else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {321return 0x08000000 + g_MemorySize - (address & 0x3FFFFFFF);322} else {323return 0;324}325}326327inline const char *GetCharPointerUnchecked(const u32 address) {328return (const char *)GetPointerUnchecked(address);329}330331// NOTE: Unlike the similar IsValidRange/IsValidAddress functions, this one is linear cost vs the size of the string,332// for hopefully-obvious reasons.333inline bool IsValidNullTerminatedString(const u32 address) {334u32 max_size = MaxSizeAtAddress(address);335if (max_size == 0) {336return false;337}338339const char *c = GetCharPointerUnchecked(address);340if (memchr(c, '\0', max_size)) {341return true;342}343return false;344}345346inline u32 ValidSize(const u32 address, const u32 requested_size) {347u32 max_size = MaxSizeAtAddress(address);348if (requested_size > max_size) {349return max_size;350}351return requested_size;352}353354// NOTE: If size == 0, any address will be accepted. This may not be ideal for all cases.355inline bool IsValidRange(const u32 address, const u32 size) {356return ValidSize(address, size) == size;357}358359// Used for auto-converted char * parameters, which can sometimes legitimately be null -360// so we don't want to get caught in GetPointer's crash reporting361// TODO: This should use IsValidNullTerminatedString, but may be expensive since this is used so much - needs evaluation.362inline const char *GetCharPointer(const u32 address) {363if (address && IsValidAddress(address)) {364return GetCharPointerUnchecked(address);365} else {366return nullptr;367}368}369370} // namespace Memory371372// Avoiding a global include for NotifyMemInfo.373void PSPPointerNotifyRW(int rw, uint32_t ptr, uint32_t bytes, const char *tag, size_t tagLen);374375template <typename T>376struct PSPPointer377{378u32_le ptr;379380inline T &operator*() const381{382#ifdef MASKED_PSP_MEMORY383return *(T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));384#else385return *(T *)(Memory::base + ptr);386#endif387}388389inline T &operator[](int i) const390{391#ifdef MASKED_PSP_MEMORY392return *((T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK)) + i);393#else394return *((T *)(Memory::base + ptr) + i);395#endif396}397398inline T *operator->() const399{400#ifdef MASKED_PSP_MEMORY401return (T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));402#else403return (T *)(Memory::base + ptr);404#endif405}406407inline PSPPointer<T> operator+(int i) const408{409PSPPointer other;410other.ptr = ptr + i * sizeof(T);411return other;412}413414inline PSPPointer<T> &operator=(u32 p)415{416ptr = p;417return *this;418}419420inline PSPPointer<T> &operator+=(int i)421{422ptr = ptr + i * sizeof(T);423return *this;424}425426inline PSPPointer<T> operator-(int i) const427{428PSPPointer other;429other.ptr = ptr - i * sizeof(T);430return other;431}432433inline PSPPointer<T> &operator-=(int i)434{435ptr = ptr - i * sizeof(T);436return *this;437}438439inline PSPPointer<T> &operator++()440{441ptr += sizeof(T);442return *this;443}444445inline PSPPointer<T> operator++(int i)446{447PSPPointer<T> other;448other.ptr = ptr;449ptr += sizeof(T);450return other;451}452453inline PSPPointer<T> &operator--()454{455ptr -= sizeof(T);456return *this;457}458459inline PSPPointer<T> operator--(int i)460{461PSPPointer<T> other;462other.ptr = ptr;463ptr -= sizeof(T);464return other;465}466467inline operator T*()468{469#ifdef MASKED_PSP_MEMORY470return (T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));471#else472return (T *)(Memory::base + ptr);473#endif474}475476inline operator const T*() const477{478#ifdef MASKED_PSP_MEMORY479return (const T *)(Memory::base + (ptr & Memory::MEMVIEW32_MASK));480#else481return (const T *)(Memory::base + ptr);482#endif483}484485bool IsValid() const {486return Memory::IsValidRange(ptr, (u32)sizeof(T));487}488489T *PtrOrNull() {490if (IsValid())491return (T *)*this;492return nullptr;493}494495const T *PtrOrNull() const {496if (IsValid())497return (const T *)*this;498return nullptr;499}500501template <size_t tagLen>502void NotifyWrite(const char(&tag)[tagLen]) const {503PSPPointerNotifyRW(1, (uint32_t)ptr, (uint32_t)sizeof(T), tag, tagLen - 1);504}505506template <size_t tagLen>507void NotifyRead(const char(&tag)[tagLen]) const {508PSPPointerNotifyRW(2, (uint32_t)ptr, (uint32_t)sizeof(T), tag, tagLen - 1);509}510511size_t ElementSize() const512{513return sizeof(T);514}515516static PSPPointer<T> Create(u32 ptr) {517PSPPointer<T> p;518p = ptr;519return p;520}521};522523constexpr u32 PSP_GetScratchpadMemoryBase() { return 0x00010000;}524constexpr u32 PSP_GetScratchpadMemoryEnd() { return 0x00014000;}525526constexpr u32 PSP_GetKernelMemoryBase() { return 0x08000000;}527inline u32 PSP_GetUserMemoryEnd() { return PSP_GetKernelMemoryBase() + Memory::g_MemorySize;}528constexpr u32 PSP_GetKernelMemoryEnd() { return 0x08400000;}529530// "Volatile" RAM is between 0x08400000 and 0x08800000, can be requested by the531// game through sceKernelVolatileMemTryLock.532constexpr u32 PSP_GetVolatileMemoryStart() { return 0x08400000; }533constexpr u32 PSP_GetVolatileMemoryEnd() { return 0x08800000; }534535constexpr u32 PSP_GetUserMemoryBase() { return 0x08800000; }536constexpr u32 PSP_GetDefaultLoadAddress() { return 0; }537constexpr u32 PSP_GetVidMemBase() { return 0x04000000; }538constexpr u32 PSP_GetVidMemEnd() { return 0x04800000; }539540template <typename T>541inline bool operator==(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {542return lhs.ptr == rhs.ptr;543}544545template <typename T>546inline bool operator!=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {547return lhs.ptr != rhs.ptr;548}549550template <typename T>551inline bool operator<(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {552return lhs.ptr < rhs.ptr;553}554555template <typename T>556inline bool operator>(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {557return lhs.ptr > rhs.ptr;558}559560template <typename T>561inline bool operator<=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {562return lhs.ptr <= rhs.ptr;563}564565template <typename T>566inline bool operator>=(const PSPPointer<T> &lhs, const PSPPointer<T> &rhs) {567return lhs.ptr >= rhs.ptr;568}569570571