Early memory regions setup

Needed to enable flexible allocations before mapping the eboot
This commit is contained in:
Stephen Miller 2026-04-17 17:33:09 -05:00
parent 95ba5918dd
commit da1552d4ac
4 changed files with 123 additions and 40 deletions

View File

@ -74,41 +74,6 @@ void Linker::Execute(const std::vector<std::string>& args) {
Relocate(m.get());
}
// Configure the direct and flexible memory regions.
u64 fmem_size = ORBIS_FLEXIBLE_MEMORY_SIZE;
bool use_extended_mem1 = true, use_extended_mem2 = true;
const auto* proc_param = GetProcParam();
ASSERT(proc_param);
Core::OrbisKernelMemParam mem_param{};
if (proc_param->size >= offsetof(OrbisProcParam, mem_param) + sizeof(OrbisKernelMemParam*)) {
if (proc_param->mem_param) {
mem_param = *proc_param->mem_param;
if (mem_param.size >=
offsetof(OrbisKernelMemParam, flexible_memory_size) + sizeof(u64*)) {
if (const auto* flexible_size = mem_param.flexible_memory_size) {
fmem_size = *flexible_size + ORBIS_FLEXIBLE_MEMORY_BASE;
}
}
}
}
if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_1) + sizeof(u64*)) {
mem_param.extended_memory_1 = nullptr;
}
if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_2) + sizeof(u64*)) {
mem_param.extended_memory_2 = nullptr;
}
const u64 sdk_ver = proc_param->sdk_version;
if (sdk_ver < Common::ElfInfo::FW_50) {
use_extended_mem1 = mem_param.extended_memory_1 ? *mem_param.extended_memory_1 : false;
use_extended_mem2 = mem_param.extended_memory_2 ? *mem_param.extended_memory_2 : false;
}
memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2);
main_thread.Run([this, module, &args](std::stop_token) {
Common::SetCurrentThreadName("Game:Main");
#ifndef _WIN32 // Clear any existing signal mask for game threads.

View File

@ -33,8 +33,23 @@ MemoryManager::MemoryManager() {
MemoryManager::~MemoryManager() = default;
void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1,
bool use_extended_mem2) {
void MemoryManager::SetupMemoryRegions(u64* flexible_size, u8* extended_memory_1,
u8* extended_memory_2) {
u64 fmem_size = ORBIS_FLEXIBLE_MEMORY_SIZE;
bool use_extended_mem1 = true, use_extended_mem2 = true;
if (flexible_size) {
fmem_size = *flexible_size + ORBIS_FLEXIBLE_MEMORY_BASE;
}
s32 sdk_ver;
ASSERT_MSG(::Libraries::Kernel::sceKernelGetCompiledSdkVersion(&sdk_ver) == ORBIS_OK,
"Failed to get SDK version");
if (sdk_ver < Common::ElfInfo::FW_50) {
use_extended_mem1 = extended_memory_1 ? *extended_memory_1 : false;
use_extended_mem2 = extended_memory_2 ? *extended_memory_2 : false;
}
const bool is_neo = ::Libraries::Kernel::sceKernelIsNeoMode();
auto total_size = is_neo ? ORBIS_KERNEL_TOTAL_MEM_PRO : ORBIS_KERNEL_TOTAL_MEM;
if (EmulatorSettings.IsDevKit()) {
@ -53,8 +68,8 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1
if (!use_extended_mem2 && !is_neo) {
total_size -= 128_MB;
}
total_flexible_size = flexible_size - ORBIS_FLEXIBLE_MEMORY_BASE;
total_direct_size = total_size - flexible_size;
total_flexible_size = fmem_size - ORBIS_FLEXIBLE_MEMORY_BASE;
total_direct_size = total_size - fmem_size;
// Insert an area that covers the direct memory physical address block.
// Note that this should never be called after direct memory allocations have been made.

View File

@ -240,7 +240,7 @@ public:
bool TryWriteBacking(void* address, const void* data, u64 size);
void SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1, bool use_extended_mem2);
void SetupMemoryRegions(u64* flexible_size, u8* extended_memory_1, u8* extended_memory_2);
PAddr PoolExpand(PAddr search_start, PAddr search_end, u64 size, u64 alignment);

View File

@ -92,6 +92,106 @@ s32 ReadCompiledSdkVersion(const std::filesystem::path& file) {
return 0;
}
void InitializeMemoryRegions(const std::filesystem::path& file) {
Core::Loader::Elf elf;
elf.Open(file);
if (!elf.IsElfFile()) {
return;
}
const auto elf_pheader = elf.GetProgramHeader();
auto i_procparam = std::find_if(elf_pheader.begin(), elf_pheader.end(), [](const auto& entry) {
return entry.p_type == PT_SCE_PROCPARAM;
});
if (i_procparam != elf_pheader.end()) {
Core::OrbisProcParam param{};
elf.LoadSegment(std::bit_cast<u64>(&param), i_procparam->p_offset, i_procparam->p_filesz);
// We need to convert virtual addresses to their physical file offset.
// To do this, search through program headers and calculate the offset for
// the block the address is in.
const auto get_offset = [](std::span<const elf_program_header> phdr, void* offset) {
s64 virtual_offset = std::bit_cast<u64>(offset);
auto block =
std::find_if(phdr.begin(), phdr.end(), [virtual_offset](const auto& entry) {
return (entry.p_type == PT_SCE_RELRO || entry.p_type == PT_LOAD) &&
entry.p_vaddr <= virtual_offset &&
entry.p_vaddr + entry.p_memsz > virtual_offset;
});
if (block != phdr.end()) {
return virtual_offset + block->p_offset - block->p_vaddr;
}
return static_cast<u64>(0);
};
// Read raw memory parameter data
Core::OrbisKernelMemParam* mem_param = new Core::OrbisKernelMemParam();
if (param.mem_param) {
u64 offset = get_offset(elf_pheader, param.mem_param);
u64 vaddr = std::bit_cast<u64>(mem_param);
elf.LoadSegment(vaddr, offset, sizeof(*mem_param));
} else {
delete (mem_param);
mem_param = nullptr;
}
// Read flexible memory size
u64* flexible_memory_size = new u64();
if (mem_param && mem_param->flexible_memory_size) {
u64 offset = get_offset(elf_pheader, mem_param->flexible_memory_size);
u64 vaddr = std::bit_cast<u64>(flexible_memory_size);
elf.LoadSegment(vaddr, offset, sizeof(*flexible_memory_size));
} else {
delete (flexible_memory_size);
flexible_memory_size = nullptr;
}
// Read the extended memory parameters
u8* extended_memory_1 = new u8();
if (mem_param && mem_param->extended_memory_1) {
u64 offset = get_offset(elf_pheader, mem_param->extended_memory_1);
u64 vaddr = std::bit_cast<u64>(extended_memory_1);
elf.LoadSegment(vaddr, offset, sizeof(*extended_memory_1));
} else {
delete (extended_memory_1);
extended_memory_1 = nullptr;
}
u8* extended_memory_2 = new u8();
if (mem_param && mem_param->extended_memory_2) {
u64 offset = get_offset(elf_pheader, mem_param->extended_memory_2);
u64 vaddr = std::bit_cast<u64>(extended_memory_2);
elf.LoadSegment(vaddr, offset, sizeof(*extended_memory_2));
} else {
delete (extended_memory_2);
extended_memory_2 = nullptr;
}
// Run memory initialization with these parameters.
auto* memory = Core::Memory::Instance();
memory->SetupMemoryRegions(flexible_memory_size, extended_memory_1, extended_memory_2);
// Clean up
if (mem_param) {
delete (mem_param);
mem_param = nullptr;
}
if (flexible_memory_size) {
delete (flexible_memory_size);
flexible_memory_size = nullptr;
}
if (extended_memory_1) {
delete (extended_memory_1);
extended_memory_1 = nullptr;
}
if (extended_memory_2) {
delete (extended_memory_2);
extended_memory_2 = nullptr;
}
return;
}
return;
}
void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
std::optional<std::filesystem::path> p_game_folder) {
Common::SetCurrentThreadName("shadPS4:Main");
@ -450,6 +550,9 @@ void Emulator::Run(std::filesystem::path file, std::vector<std::string> args,
LOG_WARNING(Loader, "No dumped system fonts, expect missing text or instability");
}
// Initialize memory regions
InitializeMemoryRegions(eboot_path);
// Initialize kernel and library facilities.
Libraries::InitHLELibs(&linker->GetHLESymbols());