mirror of
https://github.com/Ishan09811/pine.git
synced 2025-04-28 09:35:08 +00:00
This commit fixes GroupMutex and by extension issues with trying to run ROMs without quitting the application in between.
356 lines
15 KiB
C++
356 lines
15 KiB
C++
#pragma once
|
|
|
|
#include <common.h>
|
|
#include "types/KObject.h"
|
|
#include <forward_list>
|
|
|
|
namespace skyline {
|
|
namespace memory {
|
|
/**
|
|
* @brief The Permission struct holds the permission of a particular chunk of memory
|
|
*/
|
|
struct Permission {
|
|
/**
|
|
* @brief This constructor initializes all permissions to false
|
|
*/
|
|
Permission() {
|
|
r = 0;
|
|
w = 0;
|
|
x = 0;
|
|
};
|
|
|
|
/**
|
|
* @param read If memory has read permission
|
|
* @param write If memory has write permission
|
|
* @param execute If memory has execute permission
|
|
*/
|
|
Permission(bool read, bool write, bool execute) {
|
|
r = read;
|
|
w = write;
|
|
x = execute;
|
|
};
|
|
|
|
/**
|
|
* @brief Equality operator between two Permission objects
|
|
*/
|
|
inline bool operator==(const Permission &rhs) const { return (this->r == rhs.r && this->w == rhs.w && this->x == rhs.x); };
|
|
|
|
/**
|
|
* @brief Inequality operator between two Permission objects
|
|
*/
|
|
inline bool operator!=(const Permission &rhs) const { return !operator==(rhs); };
|
|
|
|
/**
|
|
* @return The value of the permission struct in Linux format
|
|
*/
|
|
int Get() const {
|
|
int perm = 0;
|
|
if (r)
|
|
perm |= PROT_READ;
|
|
if (w)
|
|
perm |= PROT_WRITE;
|
|
if (x)
|
|
perm |= PROT_EXEC;
|
|
return perm;
|
|
};
|
|
|
|
bool r; //!< The permission to read
|
|
bool w; //!< The permission to write
|
|
bool x; //!< The permission to execute
|
|
};
|
|
|
|
/**
|
|
* @brief This holds certain attributes of a chunk of memory: https://switchbrew.org/wiki/SVC#MemoryAttribute
|
|
*/
|
|
union MemoryAttribute {
|
|
struct {
|
|
bool isBorrowed : 1; //!< This is required for async IPC user buffers
|
|
bool isIpcLocked : 1; //!< True when IpcRefCount > 0
|
|
bool isDeviceShared : 1; //!< True when DeviceRefCount > 0
|
|
bool isUncached : 1; //!< This is used to disable memory caching to share memory with the GPU
|
|
};
|
|
u32 value;
|
|
};
|
|
|
|
/**
|
|
* @brief This contains information about a chunk of memory: https://switchbrew.org/wiki/SVC#MemoryInfo
|
|
*/
|
|
struct MemoryInfo {
|
|
u64 address; //!< The base address of the mapping
|
|
u64 size; //!< The size of the mapping
|
|
u32 type; //!< The MemoryType of the mapping
|
|
u32 attributes; //!< The attributes of the mapping
|
|
u32 permissions; //!< The permissions of the mapping
|
|
u32 ipcRefCount; //!< The IPC reference count (This is always 0)
|
|
u32 deviceRefCount; //!< The device reference count (This is always 0)
|
|
u32 _pad0_;
|
|
};
|
|
static_assert(sizeof(MemoryInfo) == 0x28);
|
|
|
|
/**
|
|
* @brief These are specific markers for the type of a memory region (https://switchbrew.org/wiki/SVC#MemoryType)
|
|
*/
|
|
enum class MemoryType : u8 {
|
|
Unmapped = 0x0,
|
|
Io = 0x1,
|
|
Normal = 0x2,
|
|
CodeStatic = 0x3,
|
|
CodeMutable = 0x4,
|
|
Heap = 0x5,
|
|
SharedMemory = 0x6,
|
|
Alias = 0x7,
|
|
ModuleCodeStatic = 0x8,
|
|
ModuleCodeMutable = 0x9,
|
|
Ipc = 0xA,
|
|
Stack = 0xB,
|
|
ThreadLocal = 0xC,
|
|
TransferMemoryIsolated = 0xD,
|
|
TransferMemory = 0xE,
|
|
ProcessMemory = 0xF,
|
|
Reserved = 0x10,
|
|
NonSecureIpc = 0x11,
|
|
NonDeviceIpc = 0x12,
|
|
KernelStack = 0x13,
|
|
CodeReadOnly = 0x14,
|
|
CodeWritable = 0x15
|
|
};
|
|
|
|
/**
|
|
* @brief This structure is used to hold the state of a certain block of memory (https://switchbrew.org/wiki/SVC#MemoryState)
|
|
*/
|
|
union MemoryState {
|
|
constexpr MemoryState(const u32 value) : value(value) {};
|
|
|
|
constexpr MemoryState() : value(0) {};
|
|
|
|
struct {
|
|
MemoryType type; //!< The MemoryType of this memory block
|
|
bool PermissionChangeAllowed : 1; //!< If the application can use svcSetMemoryPermission on this block
|
|
bool ForceReadWritableByDebugSyscalls : 1; //!< If the application can use svcWriteDebugProcessMemory on this block
|
|
bool IpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=0
|
|
bool NonDeviceIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=3
|
|
bool NonSecureIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=1
|
|
bool _pad0_ : 1;
|
|
bool ProcessPermissionChangeAllowed : 1; //!< If the application can use svcSetProcessMemoryPermission on this block
|
|
bool MapAllowed : 1; //!< If the application can use svcMapMemory on this block
|
|
bool UnmapProcessCodeMemoryAllowed : 1; //!< If the application can use svcUnmapProcessCodeMemory on this block
|
|
bool TransferMemoryAllowed : 1; //!< If the application can use svcCreateTransferMemory on this block
|
|
bool QueryPhysicalAddressAllowed : 1; //!< If the application can use svcQueryPhysicalAddress on this block
|
|
bool MapDeviceAllowed : 1; //!< If the application can use svcMapDeviceAddressSpace or svcMapDeviceAddressSpaceByForce on this block
|
|
bool MapDeviceAlignedAllowed : 1; //!< If the application can use svcMapDeviceAddressSpaceAligned on this block
|
|
bool IpcBufferAllowed : 1; //!< If the application can use this block with svcSendSyncRequestWithUserBuffer
|
|
bool IsReferenceCounted : 1; //!< If the physical memory blocks backing this region are reference counted
|
|
bool MapProcessAllowed : 1; //!< If the application can use svcMapProcessMemory on this block
|
|
bool AttributeChangeAllowed : 1; //!< If the application can use svcSetMemoryAttribute on this block
|
|
bool CodeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block
|
|
};
|
|
u32 value;
|
|
};
|
|
static_assert(sizeof(MemoryState) == sizeof(u32));
|
|
|
|
/**
|
|
* @brief The preset states that different regions are set to (https://switchbrew.org/wiki/SVC#MemoryType)
|
|
*/
|
|
namespace MemoryStates {
|
|
constexpr MemoryState Unmapped = 0x00000000;
|
|
constexpr MemoryState Io = 0x00002001;
|
|
constexpr MemoryState CodeStatic = 0x00DC7E03;
|
|
constexpr MemoryState CodeMutable = 0x03FEBD04;
|
|
constexpr MemoryState Heap = 0x037EBD05;
|
|
constexpr MemoryState SharedMemory = 0x00402006;
|
|
constexpr MemoryState Alias = 0x00482907;
|
|
constexpr MemoryState AliasCode = 0x00DD7E08;
|
|
constexpr MemoryState AliasCodeData = 0x03FFBD09;
|
|
constexpr MemoryState Ipc = 0x005C3C0A;
|
|
constexpr MemoryState Stack = 0x005C3C0B;
|
|
constexpr MemoryState ThreadLocal = 0x0040200C;
|
|
constexpr MemoryState TransferMemoryIsolated = 0x015C3C0D;
|
|
constexpr MemoryState TransferMemory = 0x005C380E;
|
|
constexpr MemoryState SharedCode = 0x0040380F;
|
|
constexpr MemoryState Reserved = 0x00000010;
|
|
constexpr MemoryState NonSecureIpc = 0x005C3811;
|
|
constexpr MemoryState NonDeviceIpc = 0x004C2812;
|
|
constexpr MemoryState KernelStack = 0x00002013;
|
|
constexpr MemoryState CodeReadOnly = 0x00402214;
|
|
constexpr MemoryState CodeWritable = 0x00402015;
|
|
};
|
|
|
|
/**
|
|
* @brief This enumerates all of the memory regions in the process address space
|
|
*/
|
|
enum class Regions {
|
|
Base, //!< The region representing the entire address space
|
|
Code, //!< The code region contains all of the loaded in code
|
|
Alias, //!< The alias region is reserved for allocating thread stack before 2.0.0
|
|
Heap, //!< The heap region is reserved for heap allocations
|
|
Stack, //!< The stack region is reserved for allocating thread stack after 2.0.0
|
|
TlsIo, //!< The TLS/IO region is reserved for allocating TLS and Device MMIO
|
|
};
|
|
|
|
/**
|
|
* @brief This struct is used to hold the location and size of a memory region
|
|
*/
|
|
struct Region {
|
|
Regions id; //!< The ID of the region
|
|
u64 address; //!< The base address of the region
|
|
u64 size; //!< The size of the region in bytes
|
|
|
|
/**
|
|
* @brief Checks if the specified address is within the region
|
|
* @param address The address to check
|
|
* @return If the address is inside the region
|
|
*/inline bool IsInside(u64 address) {
|
|
return (this->address <= address) && ((this->address + this->size) > address);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief The type of the address space used by an application
|
|
*/
|
|
enum class AddressSpaceType {
|
|
AddressSpace32Bit, //!< 32-bit address space used by 32-bit applications
|
|
AddressSpace36Bit, //!< 36-bit address space used by 64-bit applications before 2.0.0
|
|
AddressSpace39Bit, //!< 39-bit address space used by 64-bit applications after 2.0.0
|
|
};
|
|
}
|
|
|
|
namespace loader {
|
|
class NroLoader;
|
|
}
|
|
|
|
namespace kernel {
|
|
namespace type {
|
|
class KPrivateMemory;
|
|
class KSharedMemory;
|
|
class KTransferMemory;
|
|
}
|
|
|
|
namespace svc {
|
|
void SetMemoryAttribute(DeviceState &state);
|
|
|
|
void MapMemory(DeviceState &state);
|
|
}
|
|
|
|
/**
|
|
* @brief This describes a single block of memory and all of it's individual attributes
|
|
*/
|
|
struct BlockDescriptor {
|
|
u64 address; //!< The address of the current block
|
|
u64 size; //!< The size of the current block in bytes
|
|
memory::Permission permission; //!< The permissions applied to the current block
|
|
memory::MemoryAttribute attributes; //!< The MemoryAttribute for the current block
|
|
};
|
|
|
|
/**
|
|
* @brief This describes a single chunk of memory, this is owned by a memory backing
|
|
*/
|
|
struct ChunkDescriptor {
|
|
u64 address; //!< The address of the current chunk
|
|
u64 size; //!< The size of the current chunk in bytes
|
|
u64 host; //!< The address of the chunk in the host
|
|
memory::MemoryState state; //!< The MemoryState for the current block
|
|
std::forward_list<BlockDescriptor> blockList; //!< This linked list holds the block descriptors for all the children blocks of this Chunk
|
|
};
|
|
|
|
/**
|
|
* @brief This contains both of the descriptors for a specific address
|
|
*/
|
|
struct DescriptorPack {
|
|
const BlockDescriptor block; //!< The block descriptor at the address
|
|
const ChunkDescriptor chunk; //!< The chunk descriptor at the address
|
|
};
|
|
|
|
/**
|
|
* @brief The MemoryManager class handles the memory map and the memory regions of the process
|
|
*/
|
|
class MemoryManager {
|
|
private:
|
|
const DeviceState &state; //!< The state of the device
|
|
std::forward_list<ChunkDescriptor> chunkList; //!< This linked list holds all the chunk descriptors
|
|
memory::Region base{memory::Regions::Base}; //!< The Region object for the entire address space
|
|
memory::Region code{memory::Regions::Code}; //!< The Region object for the code memory region
|
|
memory::Region alias{memory::Regions::Alias}; //!< The Region object for the alias memory region
|
|
memory::Region heap{memory::Regions::Heap}; //!< The Region object for the heap memory region
|
|
memory::Region stack{memory::Regions::Stack}; //!< The Region object for the stack memory region
|
|
memory::Region tlsIo{memory::Regions::TlsIo}; //!< The Region object for the TLS/IO memory region
|
|
|
|
/**
|
|
* @param address The address to find a chunk at
|
|
* @return A pointer to the ChunkDescriptor or nullptr in case chunk was not found
|
|
*/
|
|
ChunkDescriptor *GetChunk(u64 address);
|
|
|
|
/**
|
|
* @param address The address to find a block at
|
|
* @return A pointer to the BlockDescriptor or nullptr in case chunk was not found
|
|
*/
|
|
BlockDescriptor *GetBlock(u64 address);
|
|
|
|
/**
|
|
* @brief Inserts a chunk into the memory map
|
|
* @param chunk The chunk to insert
|
|
*/
|
|
void InsertChunk(const ChunkDescriptor &chunk);
|
|
|
|
/**
|
|
* @brief Deletes a chunk located at the address from the memory map
|
|
* @param address The address of the chunk to delete
|
|
*/
|
|
void DeleteChunk(u64 address);
|
|
|
|
/**
|
|
* @brief Resize the specified chunk to the specified size
|
|
* @param chunk The chunk to resize
|
|
* @param size The new size of the chunk
|
|
*/
|
|
static void ResizeChunk(ChunkDescriptor *chunk, size_t size);
|
|
|
|
/**
|
|
* @brief Insert a block into a chunk
|
|
* @param chunk The chunk to insert the block into
|
|
* @param block The block to insert
|
|
*/
|
|
static void InsertBlock(ChunkDescriptor *chunk, BlockDescriptor block);
|
|
|
|
/**
|
|
* @brief This initializes all of the regions in the address space
|
|
* @param address The starting address of the code region
|
|
* @param size The size of the code region
|
|
* @param type The type of the address space
|
|
*/
|
|
void InitializeRegions(u64 address, u64 size, const memory::AddressSpaceType type);
|
|
|
|
public:
|
|
friend class type::KPrivateMemory;
|
|
friend class type::KSharedMemory;
|
|
friend class type::KTransferMemory;
|
|
friend class type::KProcess;
|
|
friend class loader::NroLoader;
|
|
|
|
friend void svc::SetMemoryAttribute(DeviceState &state);
|
|
|
|
friend void svc::MapMemory(skyline::DeviceState &state);
|
|
|
|
MemoryManager(const DeviceState &state);
|
|
|
|
/**
|
|
* @param address The address to query in the memory map
|
|
* @return A DescriptorPack retrieved from the memory map
|
|
*/
|
|
std::optional<DescriptorPack> Get(u64 address);
|
|
|
|
/**
|
|
* @param region The region to retrieve
|
|
* @return A Region object for the specified region
|
|
*/
|
|
memory::Region GetRegion(memory::Regions region);
|
|
|
|
/**
|
|
* @brief The total amount of space in bytes occupied by all memory mappings
|
|
* @return The cumulative size of all memory mappings in bytes
|
|
*/
|
|
size_t GetProgramSize();
|
|
};
|
|
}
|
|
}
|