diff --git a/rpcs3/Emu/PSP2/ARMv7Module.cpp b/rpcs3/Emu/PSP2/ARMv7Module.cpp index 145a96a342..c421343d53 100644 --- a/rpcs3/Emu/PSP2/ARMv7Module.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Module.cpp @@ -1,226 +1,226 @@ -#include "stdafx.h" -#include "Loader/ELF.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "ARMv7Thread.h" -#include "ARMv7Opcodes.h" -#include "ARMv7Function.h" -#include "ARMv7Module.h" -#include "Modules/sceLibKernel.h" - -extern std::string arm_get_function_name(const std::string& module, u32 fnid); -extern std::string arm_get_variable_name(const std::string& module, u32 vnid); - -// Function lookup table. Not supposed to grow after emulation start. -std::vector g_arm_function_cache; - -std::vector g_arm_function_names; - -extern std::string arm_get_module_function_name(u32 index) -{ - if (index < g_arm_function_names.size()) - { - return g_arm_function_names[index]; - } - - return fmt::format(".%u", index); -} - -extern void arm_execute_function(ARMv7Thread& cpu, u32 index) -{ - if (index < g_arm_function_cache.size()) - { - if (const auto func = g_arm_function_cache[index]) - { - func(cpu); - LOG_TRACE(ARMv7, "Function '%s' finished, r0=0x%x", arm_get_module_function_name(index), cpu.GPR[0]); - return; - } - } - - fmt::throw_exception("Function not registered (%u)" HERE, index); -} - -arm_static_module::arm_static_module(const char* name) - : name(name) -{ - arm_module_manager::register_module(this); -} - -std::unordered_map& arm_module_manager::access() -{ - static std::unordered_map map; - - return map; -} - -void arm_module_manager::register_module(arm_static_module* module) -{ - access().emplace(module->name, module); -} - -arm_static_function& arm_module_manager::access_static_function(const char* module, u32 fnid) -{ - return access().at(module)->functions[fnid]; -} - -arm_static_variable& arm_module_manager::access_static_variable(const char* module, u32 vnid) -{ - return access().at(module)->variables[vnid]; -} - -const arm_static_module* arm_module_manager::get_module(const std::string& name) -{ - const auto& map = access(); - const auto found = map.find(name); - return found != map.end() ? found->second : nullptr; -} - -static void arm_initialize_modules() -{ - const std::initializer_list registered - { - &arm_module_manager::SceAppMgr, - &arm_module_manager::SceAppUtil, - &arm_module_manager::SceAudio, - &arm_module_manager::SceAudiodec, - &arm_module_manager::SceAudioenc, - &arm_module_manager::SceAudioIn, - &arm_module_manager::SceCamera, - &arm_module_manager::SceCodecEngine, - &arm_module_manager::SceCommonDialog, - &arm_module_manager::SceCpu, - &arm_module_manager::SceCtrl, - &arm_module_manager::SceDbg, - &arm_module_manager::SceDebugLed, - &arm_module_manager::SceDeci4p, - &arm_module_manager::SceDeflt, - &arm_module_manager::SceDipsw, - &arm_module_manager::SceDisplay, - &arm_module_manager::SceDisplayUser, - &arm_module_manager::SceFiber, - &arm_module_manager::SceFios, - &arm_module_manager::SceFpu, - &arm_module_manager::SceGxm, - &arm_module_manager::SceHttp, - &arm_module_manager::SceIme, - &arm_module_manager::SceIofilemgr, - &arm_module_manager::SceJpeg, - &arm_module_manager::SceJpegEnc, - &arm_module_manager::SceLibc, - &arm_module_manager::SceLibKernel, - &arm_module_manager::SceLibm, - &arm_module_manager::SceLibstdcxx, - &arm_module_manager::SceLibXml, - &arm_module_manager::SceLiveArea, - &arm_module_manager::SceLocation, - &arm_module_manager::SceMd5, - &arm_module_manager::SceModulemgr, - &arm_module_manager::SceMotion, - &arm_module_manager::SceMt19937, - &arm_module_manager::SceNet, - &arm_module_manager::SceNetCtl, - &arm_module_manager::SceNgs, - &arm_module_manager::SceNpBasic, - &arm_module_manager::SceNpCommon, - &arm_module_manager::SceNpManager, - &arm_module_manager::SceNpMatching, - &arm_module_manager::SceNpScore, - &arm_module_manager::SceNpUtility, - &arm_module_manager::ScePerf, - &arm_module_manager::ScePgf, - &arm_module_manager::ScePhotoExport, - &arm_module_manager::SceProcessmgr, - &arm_module_manager::SceRazorCapture, - &arm_module_manager::SceRtc, - &arm_module_manager::SceSas, - &arm_module_manager::SceScreenShot, - &arm_module_manager::SceSfmt, - &arm_module_manager::SceSha, - &arm_module_manager::SceSqlite, - &arm_module_manager::SceSsl, - &arm_module_manager::SceStdio, - &arm_module_manager::SceSulpha, - &arm_module_manager::SceSysmem, - &arm_module_manager::SceSysmodule, - &arm_module_manager::SceSystemGesture, - &arm_module_manager::SceThreadmgr, - &arm_module_manager::SceTouch, - &arm_module_manager::SceUlt, - &arm_module_manager::SceVideodec, - &arm_module_manager::SceVoice, - &arm_module_manager::SceVoiceQoS, - }; - - // Reinitialize function cache - g_arm_function_cache = arm_function_manager::get(); - g_arm_function_names.clear(); - g_arm_function_names.resize(g_arm_function_cache.size()); - - // "Use" all the modules for correct linkage - for (auto& module : registered) - { - LOG_TRACE(LOADER, "Registered static module: %s", module->name); - } - - for (auto& pair : arm_module_manager::get()) - { - const auto module = pair.second; - - for (auto& function : module->functions) - { - LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); - g_arm_function_names.at(function.second.index) = fmt::format("%s.%s", module->name, function.second.name); - } - - for (auto& variable : module->variables) - { - LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); - variable.second.var->set(0); - } - } -} - -struct psv_moduleinfo_t -{ - le_t attr; // ??? - u8 major; // ??? - u8 minor; // ??? - char name[24]; // ??? - le_t unk0; - le_t unk1; - le_t libent_top; - le_t libent_end; - le_t libstub_top; - le_t libstub_end; - le_t data[1]; // ... -}; - -struct psv_libent_t -{ - le_t size; // ??? - le_t version; - le_t flags; - le_t fcount; - le_t vcount; - le_t unk2; - le_t module_nid; +#include "stdafx.h" +#include "Loader/ELF.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" + +#include "ARMv7Thread.h" +#include "ARMv7Opcodes.h" +#include "ARMv7Function.h" +#include "ARMv7Module.h" +#include "Modules/sceLibKernel.h" + +extern std::string arm_get_function_name(const std::string& module, u32 fnid); +extern std::string arm_get_variable_name(const std::string& module, u32 vnid); + +// Function lookup table. Not supposed to grow after emulation start. +std::vector g_arm_function_cache; + +std::vector g_arm_function_names; + +extern std::string arm_get_module_function_name(u32 index) +{ + if (index < g_arm_function_names.size()) + { + return g_arm_function_names[index]; + } + + return fmt::format(".%u", index); +} + +extern void arm_execute_function(ARMv7Thread& cpu, u32 index) +{ + if (index < g_arm_function_cache.size()) + { + if (const auto func = g_arm_function_cache[index]) + { + func(cpu); + LOG_TRACE(ARMv7, "Function '%s' finished, r0=0x%x", arm_get_module_function_name(index), cpu.GPR[0]); + return; + } + } + + fmt::throw_exception("Function not registered (%u)" HERE, index); +} + +arm_static_module::arm_static_module(const char* name) + : name(name) +{ + arm_module_manager::register_module(this); +} + +std::unordered_map& arm_module_manager::access() +{ + static std::unordered_map map; + + return map; +} + +void arm_module_manager::register_module(arm_static_module* module) +{ + access().emplace(module->name, module); +} + +arm_static_function& arm_module_manager::access_static_function(const char* module, u32 fnid) +{ + return access().at(module)->functions[fnid]; +} + +arm_static_variable& arm_module_manager::access_static_variable(const char* module, u32 vnid) +{ + return access().at(module)->variables[vnid]; +} + +const arm_static_module* arm_module_manager::get_module(const std::string& name) +{ + const auto& map = access(); + const auto found = map.find(name); + return found != map.end() ? found->second : nullptr; +} + +static void arm_initialize_modules() +{ + const std::initializer_list registered + { + &arm_module_manager::SceAppMgr, + &arm_module_manager::SceAppUtil, + &arm_module_manager::SceAudio, + &arm_module_manager::SceAudiodec, + &arm_module_manager::SceAudioenc, + &arm_module_manager::SceAudioIn, + &arm_module_manager::SceCamera, + &arm_module_manager::SceCodecEngine, + &arm_module_manager::SceCommonDialog, + &arm_module_manager::SceCpu, + &arm_module_manager::SceCtrl, + &arm_module_manager::SceDbg, + &arm_module_manager::SceDebugLed, + &arm_module_manager::SceDeci4p, + &arm_module_manager::SceDeflt, + &arm_module_manager::SceDipsw, + &arm_module_manager::SceDisplay, + &arm_module_manager::SceDisplayUser, + &arm_module_manager::SceFiber, + &arm_module_manager::SceFios, + &arm_module_manager::SceFpu, + &arm_module_manager::SceGxm, + &arm_module_manager::SceHttp, + &arm_module_manager::SceIme, + &arm_module_manager::SceIofilemgr, + &arm_module_manager::SceJpeg, + &arm_module_manager::SceJpegEnc, + &arm_module_manager::SceLibc, + &arm_module_manager::SceLibKernel, + &arm_module_manager::SceLibm, + &arm_module_manager::SceLibstdcxx, + &arm_module_manager::SceLibXml, + &arm_module_manager::SceLiveArea, + &arm_module_manager::SceLocation, + &arm_module_manager::SceMd5, + &arm_module_manager::SceModulemgr, + &arm_module_manager::SceMotion, + &arm_module_manager::SceMt19937, + &arm_module_manager::SceNet, + &arm_module_manager::SceNetCtl, + &arm_module_manager::SceNgs, + &arm_module_manager::SceNpBasic, + &arm_module_manager::SceNpCommon, + &arm_module_manager::SceNpManager, + &arm_module_manager::SceNpMatching, + &arm_module_manager::SceNpScore, + &arm_module_manager::SceNpUtility, + &arm_module_manager::ScePerf, + &arm_module_manager::ScePgf, + &arm_module_manager::ScePhotoExport, + &arm_module_manager::SceProcessmgr, + &arm_module_manager::SceRazorCapture, + &arm_module_manager::SceRtc, + &arm_module_manager::SceSas, + &arm_module_manager::SceScreenShot, + &arm_module_manager::SceSfmt, + &arm_module_manager::SceSha, + &arm_module_manager::SceSqlite, + &arm_module_manager::SceSsl, + &arm_module_manager::SceStdio, + &arm_module_manager::SceSulpha, + &arm_module_manager::SceSysmem, + &arm_module_manager::SceSysmodule, + &arm_module_manager::SceSystemGesture, + &arm_module_manager::SceThreadmgr, + &arm_module_manager::SceTouch, + &arm_module_manager::SceUlt, + &arm_module_manager::SceVideodec, + &arm_module_manager::SceVoice, + &arm_module_manager::SceVoiceQoS, + }; + + // Reinitialize function cache + g_arm_function_cache = arm_function_manager::get(); + g_arm_function_names.clear(); + g_arm_function_names.resize(g_arm_function_cache.size()); + + // "Use" all the modules for correct linkage + for (auto& module : registered) + { + LOG_TRACE(LOADER, "Registered static module: %s", module->name); + } + + for (auto& pair : arm_module_manager::get()) + { + const auto module = pair.second; + + for (auto& function : module->functions) + { + LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); + g_arm_function_names.at(function.second.index) = fmt::format("%s.%s", module->name, function.second.name); + } + + for (auto& variable : module->variables) + { + LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); + variable.second.var->set(0); + } + } +} + +struct psv_moduleinfo_t +{ + le_t attr; // ??? + u8 major; // ??? + u8 minor; // ??? + char name[24]; // ??? + le_t unk0; + le_t unk1; + le_t libent_top; + le_t libent_end; + le_t libstub_top; + le_t libstub_end; + le_t data[1]; // ... +}; + +struct psv_libent_t +{ + le_t size; // ??? + le_t version; + le_t flags; + le_t fcount; + le_t vcount; + le_t unk2; + le_t module_nid; le_t module_name; /* Pointer to name of this module */ le_t nid_table; /* Pointer to array of 32-bit NIDs to export */ - le_t entry_table; /* Pointer to array of data pointers for each NID */ -}; - -struct psv_libstub_t -{ - le_t size; // 0x2C, 0x34 - le_t version; // (usually 1, 5 for sceLibKernel) - le_t flags; // (usually 0) - le_t fcount; - le_t vcount; - le_t unk2; - le_t unk3; + le_t entry_table; /* Pointer to array of data pointers for each NID */ +}; + +struct psv_libstub_t +{ + le_t size; // 0x2C, 0x34 + le_t version; // (usually 1, 5 for sceLibKernel) + le_t flags; // (usually 0) + le_t fcount; + le_t vcount; + le_t unk2; + le_t unk3; le_t module_nid; /* NID of module to import */ le_t module_name; /* Pointer to name of imported module, for debugging */ le_t reserved2; @@ -229,51 +229,51 @@ struct psv_libstub_t le_t var_nid_table; /* Pointer to array of variable NIDs to import */ le_t var_entry_table; /* Pointer to array of data pointers to write to */ le_t unk_nid_table; - le_t unk_entry_table; -}; - -struct psv_libcparam_t -{ - le_t size; - le_t unk0; - - vm::lcptr sceLibcHeapSize; - vm::lcptr sceLibcHeapSizeDefault; - vm::lcptr sceLibcHeapExtendedAlloc; - vm::lcptr sceLibcHeapDelayedAlloc; - - le_t unk1; - le_t unk2; - - vm::lptr __sce_libcmallocreplace; - vm::lptr __sce_libcnewreplace; -}; - -struct psv_process_param_t -{ - le_t size; // 0x00000030 - nse_t ver; // 'PSP2' - le_t unk0; // 0x00000005 - le_t unk1; - - vm::lcptr sceUserMainThreadName; - vm::lcptr sceUserMainThreadPriority; - vm::lcptr sceUserMainThreadStackSize; - vm::lcptr sceUserMainThreadAttribute; - vm::lcptr sceProcessName; - vm::lcptr sce_process_preload_disabled; - vm::lcptr sceUserMainThreadCpuAffinityMask; - - vm::lcptr sce_libcparam; -}; - -struct psv_reloc -{ - u32 addr; - u32 type; - u64 data; -}; - + le_t unk_entry_table; +}; + +struct psv_libcparam_t +{ + le_t size; + le_t unk0; + + vm::lcptr sceLibcHeapSize; + vm::lcptr sceLibcHeapSizeDefault; + vm::lcptr sceLibcHeapExtendedAlloc; + vm::lcptr sceLibcHeapDelayedAlloc; + + le_t unk1; + le_t unk2; + + vm::lptr __sce_libcmallocreplace; + vm::lptr __sce_libcnewreplace; +}; + +struct psv_process_param_t +{ + le_t size; // 0x00000030 + nse_t ver; // 'PSP2' + le_t unk0; // 0x00000005 + le_t unk1; + + vm::lcptr sceUserMainThreadName; + vm::lcptr sceUserMainThreadPriority; + vm::lcptr sceUserMainThreadStackSize; + vm::lcptr sceUserMainThreadAttribute; + vm::lcptr sceProcessName; + vm::lcptr sce_process_preload_disabled; + vm::lcptr sceUserMainThreadCpuAffinityMask; + + vm::lcptr sce_libcparam; +}; + +struct psv_reloc +{ + u32 addr; + u32 type; + u64 data; +}; + /** \name Macros to get SCE reloc values * @{ */ @@ -306,100 +306,101 @@ struct psv_reloc #define R_ARM_MOVT_ABS 44 #define R_ARM_THM_MOVW_ABS_NC 47 #define R_ARM_THM_MOVT_ABS 48 -/** @}*/ - - -static void arm_patch_refs(u32 refs, u32 addr) -{ - auto ptr = vm::cptr::make(refs); - LOG_NOTICE(LOADER, "**** Processing refs at 0x%x:", ptr); - - if (ptr[0] != 0xff || ptr[1] != addr) - { - LOG_ERROR(LOADER, "**** Unexpected ref format ([0]=0x%x, [1]=0x%x)", ptr[0], ptr[1]); - } - else for (ptr += 2; *ptr; ptr++) - { - switch (u32 code = *ptr) - { - case 0x0000002f: // movw r*,# instruction - { - const u32 raddr = *++ptr; - vm::write16(raddr + 0, vm::read16(raddr + 0) | (addr & 0x800) >> 1 | (addr & 0xf000) >> 12); - vm::write16(raddr + 2, vm::read16(raddr + 2) | (addr & 0x700) << 4 | (addr & 0xff)); - - LOG_NOTICE(LOADER, "**** MOVW written at *0x%x", raddr); - break; - } - case 0x00000030: // movt r*,# instruction - { - const u32 raddr = *++ptr; - vm::write16(raddr + 0, vm::read16(raddr + 0) | (addr & 0x8000000) >> 17 | (addr & 0xf0000000) >> 28); - vm::write16(raddr + 2, vm::read16(raddr + 2) | (addr & 0x7000000) >> 12 | (addr & 0xff0000) >> 16); - - LOG_NOTICE(LOADER, "**** MOVT written at *0x%x", raddr); - break; - } - default: - { - LOG_ERROR(LOADER, "**** Unknown ref code found (0x%08x)", code); - } - } - } - -} - -void arm_load_exec(const arm_exec_object& elf) -{ - arm_initialize_modules(); - - vm::cptr module_info{}; - vm::cptr libent{}; - vm::cptr libstub{}; - vm::cptr proc_param{}; - - u32 entry_point{}; - u32 start_addr{}; - u32 arm_exidx{}; - u32 arm_extab{}; - u32 tls_faddr{}; - u32 tls_fsize{}; - u32 tls_vsize{}; - - std::unique_ptr p_vaddr = std::make_unique(elf.progs.size()); - - for (int i = 0; i < elf.progs.size(); i++) - { - const auto& prog = elf.progs[i]; - const u32 addr = vm::cast(prog.p_vaddr, HERE); - const u32 size = ::narrow(prog.p_memsz, "p_memsz" HERE); - const u32 type = prog.p_type; - const u32 flag = prog.p_flags; - - if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) - { - if (!(p_vaddr[i] = vm::alloc(size, vm::main))) - { - fmt::throw_exception("vm::alloc() failed (size=0x%x)", size); - } - - if (elf.header.e_type == elf_type::psv1 && prog.p_paddr) - { - module_info.set(start_addr + (prog.p_paddr - prog.p_offset)); - LOG_NOTICE(LOADER, "Found program with p_paddr=0x%x", prog.p_paddr); - } - - if (!start_addr) - { - start_addr = p_vaddr[i]; - } - - std::memcpy(vm::base(p_vaddr[i]), prog.bin.data(), prog.p_filesz); - } - else if (prog.p_type == 0x60000000) { - // Relocation code taken from - // https://github.com/yifanlu/UVLoader/blob/master/relocate.c - // Relocation information of the SCE_PPURELA segment +/** @}*/ + + +static void arm_patch_refs(u32 refs, u32 addr) +{ + auto ptr = vm::cptr::make(refs); + LOG_NOTICE(LOADER, "**** Processing refs at 0x%x:", ptr); + + if (ptr[0] != 0xff || ptr[1] != addr) + { + LOG_ERROR(LOADER, "**** Unexpected ref format ([0]=0x%x, [1]=0x%x)", ptr[0], ptr[1]); + } + else for (ptr += 2; *ptr; ptr++) + { + switch (u32 code = *ptr) + { + case 0x0000002f: // movw r*,# instruction + { + const u32 raddr = *++ptr; + vm::write16(raddr + 0, vm::read16(raddr + 0) | (addr & 0x800) >> 1 | (addr & 0xf000) >> 12); + vm::write16(raddr + 2, vm::read16(raddr + 2) | (addr & 0x700) << 4 | (addr & 0xff)); + + LOG_NOTICE(LOADER, "**** MOVW written at *0x%x", raddr); + break; + } + case 0x00000030: // movt r*,# instruction + { + const u32 raddr = *++ptr; + vm::write16(raddr + 0, vm::read16(raddr + 0) | (addr & 0x8000000) >> 17 | (addr & 0xf0000000) >> 28); + vm::write16(raddr + 2, vm::read16(raddr + 2) | (addr & 0x7000000) >> 12 | (addr & 0xff0000) >> 16); + + LOG_NOTICE(LOADER, "**** MOVT written at *0x%x", raddr); + break; + } + default: + { + LOG_ERROR(LOADER, "**** Unknown ref code found (0x%08x)", code); + } + } + } + +} + +void arm_load_exec(const arm_exec_object& elf) +{ + arm_initialize_modules(); + + vm::cptr module_info{}; + vm::cptr libent{}; + vm::cptr libstub{}; + vm::cptr proc_param{}; + + u32 entry_point{}; + u32 start_addr{}; + u32 arm_exidx{}; + u32 arm_extab{}; + u32 tls_faddr{}; + u32 tls_fsize{}; + u32 tls_vsize{}; + + std::unique_ptr p_vaddr = std::make_unique(elf.progs.size()); + + for (int i = 0; i < elf.progs.size(); i++) + { + const auto& prog = elf.progs[i]; + const u32 addr = vm::cast(prog.p_vaddr, HERE); + const u32 size = ::narrow(prog.p_memsz, "p_memsz" HERE); + const u32 type = prog.p_type; + const u32 flag = prog.p_flags; + + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) + { + if (!(p_vaddr[i] = vm::alloc(size, vm::main))) + { + fmt::throw_exception("vm::alloc() failed (size=0x%x)", size); + } + + if (elf.header.e_type == elf_type::psv1 && prog.p_paddr) + { + module_info.set(start_addr + (prog.p_paddr - prog.p_offset)); + LOG_NOTICE(LOADER, "Found program with p_paddr=0x%x", prog.p_paddr); + } + + if (!start_addr) + { + start_addr = p_vaddr[i]; + } + + std::memcpy(vm::base(p_vaddr[i]), prog.bin.data(), prog.p_filesz); + } + else if (prog.p_type == 0x60000000) + { + // Relocation code taken from + // https://github.com/yifanlu/UVLoader/blob/master/relocate.c + // Relocation information of the SCE_PPURELA segment typedef union sce_reloc { u32 r_type; @@ -414,20 +415,20 @@ void arm_load_exec(const arm_exec_object& elf) u32 r_addend; u32 r_offset; } r_long; - } sce_reloc_t; - - for (uint i = 0; i < prog.p_filesz; ) - { - const auto& rel = reinterpret_cast(prog.bin[i]); + } sce_reloc_t; + + for (uint i = 0; i < prog.p_filesz; ) + { + const auto& rel = reinterpret_cast(prog.bin[i]); u32 r_offset; - u32 r_addend; + u32 r_addend; u8 r_symseg; u8 r_datseg; s32 offset; - u32 symval, addend, loc; + u32 symval, addend, loc; u32 upper, lower, sign, j1, j2; - u32 value; - + u32 value; + if (SCE_RELOC_IS_SHORT(rel)) { r_offset = SCE_RELOC_SHORT_OFFSET(rel.r_short); @@ -445,14 +446,14 @@ void arm_load_exec(const arm_exec_object& elf) } LOG_NOTICE(LOADER, "LONG RELOC %X %X %X", r_offset, r_addend, SCE_RELOC_CODE(rel)); i += 12; - } - + } + // get values r_symseg = SCE_RELOC_SYMSEG(rel); r_datseg = SCE_RELOC_DATSEG(rel); symval = r_symseg == 15 ? 0 : p_vaddr[r_symseg]; - loc = p_vaddr[r_datseg] + r_offset; - + loc = p_vaddr[r_datseg] + r_offset; + // perform relocation // taken from linux/arch/arm/kernel/module.c of Linux Kernel 4.0 switch (SCE_RELOC_CODE(rel)) @@ -502,7 +503,8 @@ void arm_load_exec(const arm_exec_object& elf) offset = r_addend + symval - loc; if (offset <= (s32)0xff000000 || - offset >= (s32)0x01000000) { + offset >= (s32)0x01000000) + { LOG_NOTICE(LOADER, "reloc %x out of range: 0x%08X", i, symval); break; } @@ -524,7 +526,8 @@ void arm_load_exec(const arm_exec_object& elf) { offset = r_addend + symval - loc; if (offset <= (s32)0xfe000000 || - offset >= (s32)0x02000000) { + offset >= (s32)0x02000000) + { LOG_NOTICE(LOADER, "reloc %x out of range: 0x%08X", i, symval); break; } @@ -592,285 +595,285 @@ void arm_load_exec(const arm_exec_object& elf) { LOG_NOTICE(LOADER, "Unknown relocation code %u at %x", SCE_RELOC_CODE(rel), i); continue; - } - } - - LOG_NOTICE(LOADER, "Writing at %X[%d], %X, %X, %d", p_vaddr[r_datseg], r_datseg, r_offset, value, sizeof(value)); - if ((r_offset + sizeof(value)) > elf.progs[r_datseg].p_filesz) - { + } + } + + LOG_NOTICE(LOADER, "Writing at %X[%d], %X, %X, %d", p_vaddr[r_datseg], r_datseg, r_offset, value, sizeof(value)); + if ((r_offset + sizeof(value)) > elf.progs[r_datseg].p_filesz) + { LOG_NOTICE(LOADER, "Relocation overflows segment"); - continue; - } - vm::_ref(p_vaddr[r_datseg]+r_offset) = value; - } - } - } - - if (!module_info) module_info.set(start_addr + elf.header.e_entry); - if (!libent) libent.set(start_addr + module_info->libent_top); - if (!libstub) libstub.set(start_addr + module_info->libstub_top); - - LOG_NOTICE(LOADER, "__sce_moduleinfo(*0x%x) analysis...", module_info); - - if (module_info->data[2] == 0xffffffff) - { - arm_exidx = module_info->data[3]; - arm_extab = module_info->data[4]; - tls_faddr = module_info->data[5]; - tls_fsize = module_info->data[6]; - tls_vsize = module_info->data[7]; - } - else if (module_info->data[5] == 0xffffffff || module_info->data[5] == 0) - { - tls_faddr = module_info->data[1]; // Guess - tls_fsize = module_info->data[2]; - tls_vsize = module_info->data[3]; - arm_exidx = module_info->data[6]; - arm_extab = module_info->data[8]; - } - else - { - LOG_ERROR(LOADER, "Failed to recognize __sce_moduleinfo format"); - } - - LOG_NOTICE(LOADER, "** arm_exidx=0x%x", arm_exidx); - LOG_NOTICE(LOADER, "** arm_extab=0x%x", arm_extab); - LOG_NOTICE(LOADER, "** tls_faddr=0x%x", tls_faddr); - LOG_NOTICE(LOADER, "** tls_fsize=0x%x", tls_fsize); - LOG_NOTICE(LOADER, "** tls_vsize=0x%x", tls_vsize); - - // Process exports - while (libent.addr() < start_addr + module_info->libent_end) - { - const u32 size = libent->size; - - // TODO: check addresses - if (size != 0x1c && size != 0x20) - { - LOG_ERROR(LOADER, "Unknown libent size (0x%x) at *0x%x", libent->size, libent); - } - else - { - LOG_NOTICE(LOADER, "Loading libent at *0x%x", libent); - LOG_NOTICE(LOADER, "** Version: 0x%x, Flags: 0x%x", libent->version, libent->flags); - LOG_NOTICE(LOADER, "** Functions: %u", libent->fcount); - LOG_NOTICE(LOADER, "** Variables: %u", libent->vcount); - LOG_NOTICE(LOADER, "** 0x%x, Module NID: 0x%08x", libent->unk2, libent->module_nid); - - const auto export_nids = vm::cptr::make(libent->nid_table); - const auto export_data = vm::cptr::make(libent->entry_table); - - LOG_NOTICE(LOADER, "** Export Data: 0x%x, Export NIDs: 0x%08x", export_data, export_nids); - - for (u32 i = 0, count = export_data - export_nids; i < count; i++) - { - const u32 nid = export_nids[i]; - const u32 addr = export_data[i]; - - // Known exports - switch (nid) - { - case 0x935cd196: // set entry point - { - entry_point = addr; - break; - } - - case 0x6c2224ba: // __sce_moduleinfo - { - verify(HERE), addr == module_info.addr(); - break; - } - - case 0x70fba1e7: // __sce_process_param - { - proc_param.set(addr); - break; - } - - default: - { - LOG_ERROR(LOADER, "** Unknown export '0x%08X' (*0x%x)", nid, addr); - } - } - } - } - - // Next entry - libent.set(libent.addr() + libent->size); - } - - // Process imports - while (libstub.addr() < start_addr + module_info->libstub_end) - { - const u32 size = libstub->size; - - // TODO: check addresses - if (size != 0x2c && size != 0x34) - { - LOG_ERROR(LOADER, "Unknown libstub size (0x%x) at *0x%x)", libstub->size, libstub); - } - else - { - const std::string module_name(vm::_ptr(libstub->module_name)); - - LOG_NOTICE(LOADER, "Loading libstub at 0x%x: %s", libstub, module_name); - - const auto _sm = arm_module_manager::get_module(module_name); - - if (!_sm) - { - LOG_ERROR(LOADER, "** Unknown module '%s'", module_name); - } - else - { - // Allocate HLE variables (TODO) - for (auto& var : _sm->variables) - { - var.second.var->set(vm::alloc(var.second.size, vm::main, std::max(var.second.align, 4096))); - LOG_WARNING(LOADER, "** Allocated variable '%s' in module '%s' at *0x%x", var.second.name, module_name, var.second.var->addr()); - } - - // Initialize HLE variables (TODO) - for (auto& var : _sm->variables) - { - var.second.init(); - } - } - - LOG_NOTICE(LOADER, "** Version: 0x%x, Flags: 0x%x", libstub->version, libstub->flags); - LOG_NOTICE(LOADER, "** Functions: %u", libstub->fcount); - LOG_NOTICE(LOADER, "** Variables: %u", libstub->vcount); - LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libstub->unk2, libstub->unk3); - - const auto fnids = vm::cptr::make(libstub->func_nid_table); - const auto fstubs = vm::cptr::make(libstub->func_entry_table); - - for (u32 j = 0; j < libstub->fcount; j++) - { - const u32 fnid = fnids[j]; - const u32 faddr = fstubs[j]; - - u32 index = 0; - - const auto fstub = vm::ptr::make(faddr); - const auto fname = arm_get_function_name(module_name, fnid); - - if (_sm && _sm->functions.count(fnid)) - { - index = _sm->functions.at(fnid).index; - LOG_NOTICE(LOADER, "** Imported function '%s' in module '%s' (*0x%x)", fname, module_name, faddr); - } - else - { - // TODO - index = ::size32(g_arm_function_cache); - g_arm_function_cache.emplace_back(); - g_arm_function_names.emplace_back(fmt::format("%s.%s", module_name, fname)); - - LOG_ERROR(LOADER, "** Unknown function '%s' in module '%s' (*0x%x) -> index %u", fname, module_name, faddr, index); - } - - // Check import stub - if (fstub[2] != 0xE1A00000) - { - LOG_ERROR(LOADER, "**** Unexpected import function stub (*0x%x, [2]=0x%08x)", faddr, fstub[2]); - } - - // Process refs - if (const u32 refs = fstub[3]) - { - arm_patch_refs(refs, faddr); - } - - // Install HACK instruction (ARM) - fstub[0] = 0xe0700090 | arm_code::hack::index::insert(index); - } - - const auto vnids = vm::cptr::make(libstub->var_nid_table); - const auto vstub = vm::cptr::make(libstub->var_entry_table); - - for (u32 j = 0; j < libstub->vcount; j++) - { - const u32 vnid = vnids[j]; - const u32 refs = vstub[j]; - - // Static variable - if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) - { - LOG_NOTICE(LOADER, "** Imported variable '%s' in module '%s' (refs=*0x%x)", arm_get_variable_name(module_name, vnid), module_name, refs); - arm_patch_refs(refs, _sv->var->addr()); - } - else - { - LOG_FATAL(LOADER, "** Unknown variable '%s' in module '%s' (refs=*0x%x)", arm_get_variable_name(module_name, vnid), module_name, refs); - } - } - } - - // Next lib - libstub.set(libstub.addr() + size); - } - - LOG_NOTICE(LOADER, "__sce_process_param(*0x%x) analysis...", proc_param); - - verify(HERE), proc_param->size >= sizeof(psv_process_param_t); - verify(HERE), proc_param->ver == "PSP2"_u32; - - LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", proc_param->size, proc_param->ver, proc_param->unk0, proc_param->unk1); - - LOG_NOTICE(LOADER, "*** &sceUserMainThreadName = 0x%x", proc_param->sceUserMainThreadName); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadPriority = 0x%x", proc_param->sceUserMainThreadPriority); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadStackSize = 0x%x", proc_param->sceUserMainThreadStackSize); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadAttribute = 0x%x", proc_param->sceUserMainThreadAttribute); - LOG_NOTICE(LOADER, "*** &sceProcessName = 0x%x", proc_param->sceProcessName); - LOG_NOTICE(LOADER, "*** &sce_process_preload_disabled = 0x%x", proc_param->sce_process_preload_disabled); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadCpuAffinityMask = 0x%x", proc_param->sceUserMainThreadCpuAffinityMask); - - const auto libc_param = proc_param->sce_libcparam; - - if (libc_param) - { - - LOG_NOTICE(LOADER, "__sce_libcparam(*0x%x) analysis...", libc_param); - - verify(HERE), libc_param->size >= 0x1c; - - LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", libc_param->size, libc_param->unk0, libc_param->unk1, libc_param->unk2); - - LOG_NOTICE(LOADER, "*** &sceLibcHeapSize = 0x%x", libc_param->sceLibcHeapSize); - LOG_NOTICE(LOADER, "*** &sceLibcHeapSizeDefault = 0x%x", libc_param->sceLibcHeapSizeDefault); - LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc); - LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc); - - } - - const auto stop_code = vm::ptr::make(vm::alloc(3 * 4, vm::main)); - stop_code[0] = 0xf870; // HACK instruction (Thumb) - stop_code[1] = 1; // Predefined function index (HLE return) - arm_function_manager::addr = stop_code.addr(); - - const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread"; - const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024; - const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160; - - auto thread = idm::make_ptr(thread_name, priority, stack_size); - - thread->write_pc(entry_point, 0); - thread->TLS = fxm::make_always(tls_faddr + start_addr, tls_fsize, tls_vsize)->alloc(); - - // Initialize args - std::vector argv_data; - - for (const auto& arg : Emu.argv) - { - argv_data.insert(argv_data.end(), arg.begin(), arg.end()); - argv_data.insert(argv_data.end(), '\0'); - - thread->GPR[0]++; // argc - } - - const u32 argv = vm::alloc(::size32(argv_data), vm::main); - std::memcpy(vm::base(argv), argv_data.data(), argv_data.size()); // copy arg list - thread->GPR[1] = argv; -} + continue; + } + vm::_ref(p_vaddr[r_datseg]+r_offset) = value; + } + } + } + + if (!module_info) module_info.set(start_addr + elf.header.e_entry); + if (!libent) libent.set(start_addr + module_info->libent_top); + if (!libstub) libstub.set(start_addr + module_info->libstub_top); + + LOG_NOTICE(LOADER, "__sce_moduleinfo(*0x%x) analysis...", module_info); + + if (module_info->data[2] == 0xffffffff) + { + arm_exidx = module_info->data[3]; + arm_extab = module_info->data[4]; + tls_faddr = module_info->data[5]; + tls_fsize = module_info->data[6]; + tls_vsize = module_info->data[7]; + } + else if (module_info->data[5] == 0xffffffff || module_info->data[5] == 0) + { + tls_faddr = module_info->data[1]; // Guess + tls_fsize = module_info->data[2]; + tls_vsize = module_info->data[3]; + arm_exidx = module_info->data[6]; + arm_extab = module_info->data[8]; + } + else + { + LOG_ERROR(LOADER, "Failed to recognize __sce_moduleinfo format"); + } + + LOG_NOTICE(LOADER, "** arm_exidx=0x%x", arm_exidx); + LOG_NOTICE(LOADER, "** arm_extab=0x%x", arm_extab); + LOG_NOTICE(LOADER, "** tls_faddr=0x%x", tls_faddr); + LOG_NOTICE(LOADER, "** tls_fsize=0x%x", tls_fsize); + LOG_NOTICE(LOADER, "** tls_vsize=0x%x", tls_vsize); + + // Process exports + while (libent.addr() < start_addr + module_info->libent_end) + { + const u32 size = libent->size; + + // TODO: check addresses + if (size != 0x1c && size != 0x20) + { + LOG_ERROR(LOADER, "Unknown libent size (0x%x) at *0x%x", libent->size, libent); + } + else + { + LOG_NOTICE(LOADER, "Loading libent at *0x%x", libent); + LOG_NOTICE(LOADER, "** Version: 0x%x, Flags: 0x%x", libent->version, libent->flags); + LOG_NOTICE(LOADER, "** Functions: %u", libent->fcount); + LOG_NOTICE(LOADER, "** Variables: %u", libent->vcount); + LOG_NOTICE(LOADER, "** 0x%x, Module NID: 0x%08x", libent->unk2, libent->module_nid); + + const auto export_nids = vm::cptr::make(libent->nid_table); + const auto export_data = vm::cptr::make(libent->entry_table); + + LOG_NOTICE(LOADER, "** Export Data: 0x%x, Export NIDs: 0x%08x", export_data, export_nids); + + for (u32 i = 0, count = export_data - export_nids; i < count; i++) + { + const u32 nid = export_nids[i]; + const u32 addr = export_data[i]; + + // Known exports + switch (nid) + { + case 0x935cd196: // set entry point + { + entry_point = addr; + break; + } + + case 0x6c2224ba: // __sce_moduleinfo + { + verify(HERE), addr == module_info.addr(); + break; + } + + case 0x70fba1e7: // __sce_process_param + { + proc_param.set(addr); + break; + } + + default: + { + LOG_ERROR(LOADER, "** Unknown export '0x%08X' (*0x%x)", nid, addr); + } + } + } + } + + // Next entry + libent.set(libent.addr() + libent->size); + } + + // Process imports + while (libstub.addr() < start_addr + module_info->libstub_end) + { + const u32 size = libstub->size; + + // TODO: check addresses + if (size != 0x2c && size != 0x34) + { + LOG_ERROR(LOADER, "Unknown libstub size (0x%x) at *0x%x)", libstub->size, libstub); + } + else + { + const std::string module_name(vm::_ptr(libstub->module_name)); + + LOG_NOTICE(LOADER, "Loading libstub at 0x%x: %s", libstub, module_name); + + const auto _sm = arm_module_manager::get_module(module_name); + + if (!_sm) + { + LOG_ERROR(LOADER, "** Unknown module '%s'", module_name); + } + else + { + // Allocate HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.var->set(vm::alloc(var.second.size, vm::main, std::max(var.second.align, 4096))); + LOG_WARNING(LOADER, "** Allocated variable '%s' in module '%s' at *0x%x", var.second.name, module_name, var.second.var->addr()); + } + + // Initialize HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.init(); + } + } + + LOG_NOTICE(LOADER, "** Version: 0x%x, Flags: 0x%x", libstub->version, libstub->flags); + LOG_NOTICE(LOADER, "** Functions: %u", libstub->fcount); + LOG_NOTICE(LOADER, "** Variables: %u", libstub->vcount); + LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libstub->unk2, libstub->unk3); + + const auto fnids = vm::cptr::make(libstub->func_nid_table); + const auto fstubs = vm::cptr::make(libstub->func_entry_table); + + for (u32 j = 0; j < libstub->fcount; j++) + { + const u32 fnid = fnids[j]; + const u32 faddr = fstubs[j]; + + u32 index = 0; + + const auto fstub = vm::ptr::make(faddr); + const auto fname = arm_get_function_name(module_name, fnid); + + if (_sm && _sm->functions.count(fnid)) + { + index = _sm->functions.at(fnid).index; + LOG_NOTICE(LOADER, "** Imported function '%s' in module '%s' (*0x%x)", fname, module_name, faddr); + } + else + { + // TODO + index = ::size32(g_arm_function_cache); + g_arm_function_cache.emplace_back(); + g_arm_function_names.emplace_back(fmt::format("%s.%s", module_name, fname)); + + LOG_ERROR(LOADER, "** Unknown function '%s' in module '%s' (*0x%x) -> index %u", fname, module_name, faddr, index); + } + + // Check import stub + if (fstub[2] != 0xE1A00000) + { + LOG_ERROR(LOADER, "**** Unexpected import function stub (*0x%x, [2]=0x%08x)", faddr, fstub[2]); + } + + // Process refs + if (const u32 refs = fstub[3]) + { + arm_patch_refs(refs, faddr); + } + + // Install HACK instruction (ARM) + fstub[0] = 0xe0700090 | arm_code::hack::index::insert(index); + } + + const auto vnids = vm::cptr::make(libstub->var_nid_table); + const auto vstub = vm::cptr::make(libstub->var_entry_table); + + for (u32 j = 0; j < libstub->vcount; j++) + { + const u32 vnid = vnids[j]; + const u32 refs = vstub[j]; + + // Static variable + if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) + { + LOG_NOTICE(LOADER, "** Imported variable '%s' in module '%s' (refs=*0x%x)", arm_get_variable_name(module_name, vnid), module_name, refs); + arm_patch_refs(refs, _sv->var->addr()); + } + else + { + LOG_FATAL(LOADER, "** Unknown variable '%s' in module '%s' (refs=*0x%x)", arm_get_variable_name(module_name, vnid), module_name, refs); + } + } + } + + // Next lib + libstub.set(libstub.addr() + size); + } + + LOG_NOTICE(LOADER, "__sce_process_param(*0x%x) analysis...", proc_param); + + verify(HERE), proc_param->size >= sizeof(psv_process_param_t); + verify(HERE), proc_param->ver == "PSP2"_u32; + + LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", proc_param->size, proc_param->ver, proc_param->unk0, proc_param->unk1); + + LOG_NOTICE(LOADER, "*** &sceUserMainThreadName = 0x%x", proc_param->sceUserMainThreadName); + LOG_NOTICE(LOADER, "*** &sceUserMainThreadPriority = 0x%x", proc_param->sceUserMainThreadPriority); + LOG_NOTICE(LOADER, "*** &sceUserMainThreadStackSize = 0x%x", proc_param->sceUserMainThreadStackSize); + LOG_NOTICE(LOADER, "*** &sceUserMainThreadAttribute = 0x%x", proc_param->sceUserMainThreadAttribute); + LOG_NOTICE(LOADER, "*** &sceProcessName = 0x%x", proc_param->sceProcessName); + LOG_NOTICE(LOADER, "*** &sce_process_preload_disabled = 0x%x", proc_param->sce_process_preload_disabled); + LOG_NOTICE(LOADER, "*** &sceUserMainThreadCpuAffinityMask = 0x%x", proc_param->sceUserMainThreadCpuAffinityMask); + + const auto libc_param = proc_param->sce_libcparam; + + if (libc_param) + { + + LOG_NOTICE(LOADER, "__sce_libcparam(*0x%x) analysis...", libc_param); + + verify(HERE), libc_param->size >= 0x1c; + + LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", libc_param->size, libc_param->unk0, libc_param->unk1, libc_param->unk2); + + LOG_NOTICE(LOADER, "*** &sceLibcHeapSize = 0x%x", libc_param->sceLibcHeapSize); + LOG_NOTICE(LOADER, "*** &sceLibcHeapSizeDefault = 0x%x", libc_param->sceLibcHeapSizeDefault); + LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc); + LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc); + + } + + const auto stop_code = vm::ptr::make(vm::alloc(3 * 4, vm::main)); + stop_code[0] = 0xf870; // HACK instruction (Thumb) + stop_code[1] = 1; // Predefined function index (HLE return) + arm_function_manager::addr = stop_code.addr(); + + const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread"; + const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024; + const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160; + + auto thread = idm::make_ptr(thread_name, priority, stack_size); + + thread->write_pc(entry_point, 0); + thread->TLS = fxm::make_always(tls_faddr + start_addr, tls_fsize, tls_vsize)->alloc(); + + // Initialize args + std::vector argv_data; + + for (const auto& arg : Emu.argv) + { + argv_data.insert(argv_data.end(), arg.begin(), arg.end()); + argv_data.insert(argv_data.end(), '\0'); + + thread->GPR[0]++; // argc + } + + const u32 argv = vm::alloc(::size32(argv_data), vm::main); + std::memcpy(vm::base(argv), argv_data.data(), argv_data.size()); // copy arg list + thread->GPR[1] = argv; +}