shadPS4/src/core/libraries/kernel/memory.h
Stephen Miller 528a060709
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / linux-sdl-gcc (push) Blocked by required conditions
Build and Release / linux-qt-gcc (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions
Core: Memory code cleanup and further direct memory fixes (#3655)
* Remove mapped dmem type

Since physical addresses can be mapped multiple times, tracking mapped pages is not necessary.
This also allows me to significantly simplify the MapMemory physical address validation logic.

* Proper implementation for sceKernelMtypeprotect

I've rewritten SetDirectMemoryType to use virtual addresses instead of physical addresses, allowing it to be used in sceKernelMtypeprotect.

To accommodate this change, I've also moved address and size alignment out of MemoryManager::Protect

* Apply memory type in sceKernelMemoryPoolCommit

* Organization

Some potentially important missing mutexes, removed some unnecessary mutexes, moved some mutexes after early error returns, and updated copyright dates

* Iterator logic cleanup

Missing end check in ClampRangeSize, and adjusted VirtualQuery and DirectMemoryQuery.

* Clang

* Adjustments

* Properly account for behavior differences in MapDirectMemory2

Undid the changes to direct memory areas, added more robust logic for changing dma types, and fixed DirectMemoryQuery to return hardware-accurate direct memory information in cases where dmas split here, but not on real hardware.

I've also changed MapMemory's is_exec flag to a validate_dmem flag, used to handle alternate behavior in MapDirectMemory2. is_exec is now determined by the use of MemoryProt::CpuExec instead.

* Clang

* Add execute permissions to physical backing

Needed for executable mappings to work properly on Windows, fixes regression in RE2 with prior commit.

* Minor variable cleanup

* Update memory.h

* Prohibit direct memory mappings with exec protections

Did a quick hardware test to confirm, only seems to be prohibited for dmem mappings though.

* Update memory.cpp
2025-09-26 02:28:32 -07:00

192 lines
7.0 KiB
C++

// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/bit_field.h"
#include "common/types.h"
constexpr u64 ORBIS_KERNEL_TOTAL_MEM = 5248_MB;
constexpr u64 ORBIS_KERNEL_TOTAL_MEM_PRO = 5888_MB;
constexpr u64 ORBIS_KERNEL_TOTAL_MEM_DEV = 6656_MB;
// TODO: This value needs confirmation
constexpr u64 ORBIS_KERNEL_TOTAL_MEM_DEV_PRO = 7936_MB;
constexpr u64 ORBIS_FLEXIBLE_MEMORY_BASE = 64_MB;
constexpr u64 ORBIS_FLEXIBLE_MEMORY_SIZE = 512_MB;
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Kernel {
enum MemoryTypes : u32 {
ORBIS_KERNEL_WB_ONION = 0, // write - back mode (Onion bus)
ORBIS_KERNEL_WC_GARLIC = 3, // write - combining mode (Garlic bus)
ORBIS_KERNEL_WB_GARLIC = 10 // write - back mode (Garlic bus)
};
enum MemoryFlags : u32 {
ORBIS_KERNEL_MAP_FIXED = 0x0010, // Fixed
ORBIS_KERNEL_MAP_NO_OVERWRITE = 0x0080,
ORBIS_KERNEL_MAP_NO_COALESCE = 0x400000
};
enum MemoryProtection : u32 {
ORBIS_KERNEL_PROT_CPU_READ = 0x01, // Permit reads from the CPU
ORBIS_KERNEL_PROT_CPU_RW = 0x02, // Permit reads/writes from the CPU
ORBIS_KERNEL_PROT_CPU_WRITE = 0x02, // Permit reads/writes from the CPU (same)
ORBIS_KERNEL_PROT_GPU_READ = 0x10, // Permit reads from the GPU
ORBIS_KERNEL_PROT_GPU_WRITE = 0x20, // Permit writes from the GPU
ORBIS_KERNEL_PROT_GPU_RW = 0x30 // Permit reads/writes from the GPU
};
enum MemoryOpTypes : u32 {
ORBIS_KERNEL_MAP_OP_MAP_DIRECT = 0,
ORBIS_KERNEL_MAP_OP_UNMAP = 1,
ORBIS_KERNEL_MAP_OP_PROTECT = 2,
ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE = 3,
ORBIS_KERNEL_MAP_OP_TYPE_PROTECT = 4
};
constexpr u32 ORBIS_KERNEL_MAXIMUM_NAME_LENGTH = 32;
struct OrbisQueryInfo {
uintptr_t start;
uintptr_t end;
s32 memoryType;
};
struct OrbisVirtualQueryInfo {
uintptr_t start;
uintptr_t end;
u64 offset;
s32 protection;
s32 memory_type;
u8 is_flexible : 1;
u8 is_direct : 1;
u8 is_stack : 1;
u8 is_pooled : 1;
u8 is_committed : 1;
char name[ORBIS_KERNEL_MAXIMUM_NAME_LENGTH];
};
static_assert(sizeof(OrbisVirtualQueryInfo) == 72,
"OrbisVirtualQueryInfo struct size is incorrect");
struct OrbisKernelBatchMapEntry {
void* start;
u64 offset;
u64 length;
char protection;
char type;
s16 reserved;
s32 operation;
};
enum class OrbisKernelMemoryPoolOpcode : u32 {
Commit = 1,
Decommit = 2,
Protect = 3,
TypeProtect = 4,
Move = 5,
};
struct OrbisKernelMemoryPoolBatchEntry {
OrbisKernelMemoryPoolOpcode opcode;
u32 flags;
union {
struct {
void* addr;
u64 len;
u8 prot;
u8 type;
} commit_params;
struct {
void* addr;
u64 len;
} decommit_params;
struct {
void* addr;
u64 len;
u8 prot;
} protect_params;
struct {
void* addr;
u64 len;
u8 prot;
u8 type;
} type_protect_params;
struct {
void* dest_addr;
void* src_addr;
u64 len;
} move_params;
uintptr_t padding[3];
};
};
struct OrbisKernelMemoryPoolBlockStats {
s32 available_flushed_blocks;
s32 available_cached_blocks;
s32 allocated_flushed_blocks;
s32 allocated_cached_blocks;
};
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
s32 PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
u64 alignment, s32 memoryType, s64* physAddrOut);
s32 PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, s32 prot, s32 flags,
s64 phys_addr, u64 alignment, const char* name);
s32 PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, s32 prot, s32 flags, s64 phys_addr,
u64 alignment);
s32 PS4_SYSV_ABI sceKernelAllocateMainDirectMemory(u64 len, u64 alignment, s32 memoryType,
s64* physAddrOut);
s32 PS4_SYSV_ABI sceKernelReleaseDirectMemory(u64 start, u64 len);
s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, u64 len);
s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchEnd, u64 alignment,
u64* physAddrOut, u64* sizeOut);
s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, s32 flags, OrbisVirtualQueryInfo* info,
u64 infoSize);
s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, s32 flags, u64 alignment);
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, u64 len, s32 prot, s32 flags,
const char* name);
s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, u64 len, s32 prot, s32 flags);
s32 PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot);
s32 PS4_SYSV_ABI sceKernelMprotect(const void* addr, u64 size, s32 prot);
s32 PS4_SYSV_ABI sceKernelMtypeprotect(const void* addr, u64 size, s32 mtype, s32 prot);
s32 PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, s32 flags, OrbisQueryInfo* query_info,
u64 infoSize);
s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(u64* sizeOut);
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]);
s32 PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, s32* directMemoryTypeOut,
void** directMemoryStartOut,
void** directMemoryEndOut);
s32 PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end);
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, s32 numEntries,
s32* numEntriesOut);
s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, s32 numEntries,
s32* numEntriesOut, s32 flags);
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, u64 len, const char* name);
s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, u64 len, u64 alignment,
u64* physAddrOut);
s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addr_in, u64 len, u64 alignment, s32 flags,
void** addr_out);
s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, u64 len, s32 type, s32 prot, s32 flags);
s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, u64 len, s32 flags);
s32 PS4_SYSV_ABI sceKernelMemoryPoolBatch(const OrbisKernelMemoryPoolBatchEntry* entries, s32 count,
s32* num_processed, s32 flags);
s32 PS4_SYSV_ABI sceKernelMemoryPoolGetBlockStats(OrbisKernelMemoryPoolBlockStats* stats, u64 size);
s32 PS4_SYSV_ABI sceKernelMunmap(void* addr, u64 len);
void RegisterMemory(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel