diff --git a/orbis-kernel/src/module.cpp b/orbis-kernel/src/module.cpp index aa3436316..a3f532281 100644 --- a/orbis-kernel/src/module.cpp +++ b/orbis-kernel/src/module.cpp @@ -69,6 +69,121 @@ static void allocateTlsOffset(orbis::Process *process, orbis::Module *module) { module->isTlsDone = true; } +static orbis::SysResult doPltRelocation(orbis::Process *process, + orbis::Module *module, + orbis::Relocation rel) { + auto symbol = module->symbols.at(rel.symbolIndex); + + auto A = rel.addend; + auto B = reinterpret_cast(module->base); + auto where = reinterpret_cast(B + rel.offset); + auto where32 = reinterpret_cast(B + rel.offset); + auto P = reinterpret_cast(where); + + auto findDefModule = [module, + symbol] -> std::pair { + if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) { + return std::pair(module, symbol.address); + } + + auto &defModule = module->importedModules.at(symbol.moduleIndex); + if (!defModule) { + // std::printf( + // "Delaying plt relocation '%s' ('%s'), symbol '%llx' in %s + // module\n", module->moduleName, module->soName, (unsigned long + // long)symbol.id, + // module->neededModules[symbol.moduleIndex].name.c_str()); + + return {}; + } + + auto library = module->neededLibraries.at(symbol.libraryIndex); + + std::vector foundInLibs; + for (auto defSym : defModule->symbols) { + if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) { + continue; + } + + if (defSym.visibility == orbis::SymbolVisibility::Hidden) { + std::printf("Ignoring hidden symbol\n"); + continue; + } + + auto defLib = defModule->neededLibraries.at(defSym.libraryIndex); + + if (defLib.name == library.name) { + return std::pair(defModule.get(), defSym.address); + } + + foundInLibs.emplace_back(std::string_view(defLib.name)); + } + + for (auto nsDefModule : defModule->namespaceModules) { + for (auto defSym : nsDefModule->symbols) { + if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) { + continue; + } + + if (defSym.visibility == orbis::SymbolVisibility::Hidden) { + std::printf("Ignoring hidden symbol\n"); + continue; + } + + auto defLib = nsDefModule->neededLibraries.at(defSym.libraryIndex); + + if (defLib.name == library.name) { + return std::pair(nsDefModule.get(), defSym.address); + } + } + } + + std::printf( + "'%s' ('%s') uses undefined symbol '%llx' in '%s' ('%s') module\n", + module->moduleName, module->soName, (unsigned long long)symbol.id, + defModule->moduleName, defModule->soName); + if (foundInLibs.size() > 0) { + std::printf("Requested library is '%s', exists in libraries: [", + library.name.c_str()); + + for (bool isFirst = true; auto &lib : foundInLibs) { + if (isFirst) { + isFirst = false; + } else { + std::printf(", "); + } + + std::printf("'%s'", lib.c_str()); + } + std::printf("]\n"); + } + return std::pair(module, symbol.address); + }; + + switch (rel.relType) { + case kRelJumpSlot: { + bool isLazyBind = false; // TODO + if (isLazyBind) { + *where += B; + } else { + auto [defObj, S] = findDefModule(); + + if (defObj == nullptr) { + return orbis::ErrorCode::INVAL; + } + + *where = reinterpret_cast(defObj->base) + S; + } + return {}; + } + } + + std::fprintf(stderr, "unimplemented relocation type %u\n", + (unsigned)rel.relType); + std::abort(); + return {}; +} + static orbis::SysResult doRelocation(orbis::Process *process, orbis::Module *module, orbis::Relocation rel) { @@ -80,18 +195,22 @@ static orbis::SysResult doRelocation(orbis::Process *process, auto where32 = reinterpret_cast(B + rel.offset); auto P = reinterpret_cast(where); - auto findDefModule = [module, symbol] { + auto findDefModule = [module, symbol, + rel] -> std::pair { if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) { return std::pair(module, symbol.address); } auto &defModule = module->importedModules.at(symbol.moduleIndex); if (!defModule) { - std::printf( - "'%s' ('%s') uses undefined symbol '%llx' in unloaded module\n", - module->moduleName, module->soName, (unsigned long long)symbol.id); + std::printf("'%s' ('%s') uses undefined symbol '%llx' in unloaded module " + "'%s', rel %u\n", + module->moduleName, module->soName, + (unsigned long long)symbol.id, + module->neededModules.at(symbol.moduleIndex).name.c_str(), + rel.relType); - return std::pair(module, symbol.address); + return {}; } auto library = module->neededLibraries.at(symbol.libraryIndex); @@ -162,12 +281,20 @@ static orbis::SysResult doRelocation(orbis::Process *process, return {}; case kRel64: { auto [defObj, S] = findDefModule(); + + if (defObj == nullptr) { + return orbis::ErrorCode::INVAL; + } *where = reinterpret_cast(defObj->base) + S + A; return {}; } return {}; case kRelPc32: { auto [defObj, S] = findDefModule(); + + if (defObj == nullptr) { + return orbis::ErrorCode::INVAL; + } *where32 = reinterpret_cast(defObj->base) + S + A - P; return {}; } @@ -175,37 +302,39 @@ static orbis::SysResult doRelocation(orbis::Process *process, // return{}; case kRelGlobDat: { auto [defObj, S] = findDefModule(); + + if (defObj == nullptr) { + return orbis::ErrorCode::INVAL; + } *where = reinterpret_cast(defObj->base) + S; return {}; } - case kRelJumpSlot: { - bool isLazyBind = false; // TODO - if (isLazyBind) { - *where += B; - } else { - auto [defObj, S] = findDefModule(); - *where = reinterpret_cast(defObj->base) + S; - } - return {}; - } - case kRelRelative: *where = B + A; return {}; case kRelDtpMod64: { auto [defObj, S] = findDefModule(); + if (defObj == nullptr) { + return orbis::ErrorCode::INVAL; + } *where += defObj->tlsIndex; return {}; } case kRelDtpOff64: { auto [defObj, S] = findDefModule(); + if (defObj == nullptr) { + return orbis::ErrorCode::INVAL; + } *where += S + A; return {}; } case kRelTpOff64: { auto [defObj, S] = findDefModule(); + if (defObj == nullptr) { + return orbis::ErrorCode::INVAL; + } if (!defObj->isTlsDone) { - allocateTlsOffset(process, module); + allocateTlsOffset(process, defObj); } *where = S - defObj->tlsOffset + A; return {}; @@ -217,8 +346,11 @@ static orbis::SysResult doRelocation(orbis::Process *process, } case kRelTpOff32: { auto [defObj, S] = findDefModule(); + if (defObj == nullptr) { + return orbis::ErrorCode::INVAL; + } if (!defObj->isTlsDone) { - allocateTlsOffset(process, module); + allocateTlsOffset(process, defObj); } *where32 = S - defObj->tlsOffset + A; return {}; @@ -232,25 +364,45 @@ static orbis::SysResult doRelocation(orbis::Process *process, } orbis::SysResult orbis::Module::relocate(Process *process) { - for (auto rel : pltRelocations) { - auto result = doRelocation(process, this, rel); + if (!pltRelocations.empty()) { + kvector delayedRelocations; + std::size_t resolved = 0; + std::size_t delayed = 0; + for (auto rel : pltRelocations) { + auto result = doPltRelocation(process, this, rel); - if (result.isError()) { - return result; + if (result.isError()) { + delayedRelocations.push_back(rel); + ++delayed; + } else { + ++resolved; + } } + + std::printf("plt relocation of %s: delayed/resolved: %zu/%zu\n", moduleName, + delayed, resolved); + pltRelocations = std::move(delayedRelocations); } - pltRelocations = {}; + if (!nonPltRelocations.empty()) { + kvector delayedRelocations; + std::size_t resolved = 0; + std::size_t delayed = 0; + for (auto rel : nonPltRelocations) { + auto result = doRelocation(process, this, rel); - for (auto rel : nonPltRelocations) { - auto result = doRelocation(process, this, rel); - - if (result.isError()) { - return result; + if (result.isError()) { + delayedRelocations.push_back(rel); + ++delayed; + } else { + ++resolved; + } } - } - nonPltRelocations = {}; + std::printf("non-plt relocation of %s: delayed/resolved: %zu/%zu\n", + moduleName, delayed, resolved); + nonPltRelocations = std::move(delayedRelocations); + } return {}; } diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index fb6ab4b05..d1db1679f 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -93,7 +93,10 @@ orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, if (int_value->encoded_id == 0x12356328ECF5617B || int_value->encoded_id == 0x22666251FE7BECFF) { int_value->value = 1; + return {}; } + + int_value->value = 0; } return {}; @@ -623,14 +626,30 @@ orbis::SysResult orbis::sys_dmem_container(Thread *thread, uint id) { orbis::SysResult orbis::sys_get_authinfo(Thread *thread, pid_t pid, ptr info) { struct authinfo { - uint64_t a; - uint64_t b; + uint64_t unk0; + uint64_t caps[4]; + uint64_t attrs[4]; + uint64_t unk[8]; + }; + static_assert(sizeof(authinfo) == 136); + + authinfo result { + .unk0 = 0x3100000000000001, + .caps = { + 0x2000038000000000, + 0x000000000000FF00, + 0x0000000000000000, + 0x0000000000000000, + }, + .attrs = { + 0x4000400040000000, + 0x4000000000000000, + 0x0080000000000002, + 0xF0000000FFFF4000, + }, }; - std::memset(info, 0, 136); - ((authinfo *)info)->b = ~0; - - return {}; + return uwrite((ptr)info, result); } orbis::SysResult orbis::sys_mname(Thread *thread, uint64_t addr, uint64_t len, ptr name) { @@ -688,11 +707,9 @@ orbis::SysResult orbis::sys_dynlib_get_list(Thread *thread, if (actualNum >= numArray) { break; } - pArray[actualNum++] = id; } - uwrite(pActualNum, actualNum); - return {}; + return uwrite(pActualNum, actualNum); } orbis::SysResult orbis::sys_dynlib_get_info(Thread *thread, SceKernelModule handle, @@ -847,7 +864,8 @@ orbis::SysResult orbis::sys_dl_get_metadata(Thread *thread /* TODO */) { return ErrorCode::NOSYS; } orbis::SysResult orbis::sys_workaround8849(Thread *thread /* TODO */) { - return ErrorCode::NOSYS; + thread->retval[0] = 1; + return {}; } orbis::SysResult orbis::sys_is_development_mode(Thread *thread /* TODO */) { return ErrorCode::NOSYS; @@ -887,12 +905,12 @@ orbis::sys_dynlib_get_info_ex(Thread *thread, SceKernelModule handle, std::memcpy(result.segments, module->segments, sizeof(ModuleSegment) * module->segmentCount); result.segmentCount = module->segmentCount; - result.refCount = module->references.load(std::memory_order::relaxed); + result.refCount = 1; ORBIS_LOG_WARNING(__FUNCTION__, result.id, result.name, result.tlsIndex, result.tlsInit, result.tlsInitSize, result.tlsSize, result.tlsOffset, result.tlsAlign, result.initProc, result.finiProc, result.ehFrameHdr, result.ehFrame, - result.ehFrameHdrSize, result.ehFrameSize); + result.ehFrameHdrSize, result.ehFrameSize, result.segmentCount, result.refCount); return uwrite(destModuleInfoEx, result); } orbis::SysResult orbis::sys_budget_getid(Thread *thread) { diff --git a/orbis-kernel/src/sys/sys_sysctl.cpp b/orbis-kernel/src/sys/sys_sysctl.cpp index b2e34a072..b202064f2 100644 --- a/orbis-kernel/src/sys/sys_sysctl.cpp +++ b/orbis-kernel/src/sys/sys_sysctl.cpp @@ -64,6 +64,23 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, memset(old, 0, sizeof(app_info)); return {}; } + + if (name[0] == 1 && name[1] == 14 && name[2] == 44) { + // GetLibkernelTextLocation + if (*oldlenp != 16) { + return ErrorCode::INVAL; + } + + auto *dest = (uint64_t *)old; + + for (auto [id, mod] : thread->tproc->modulesMap) { + if (std::string_view("libkernel") == mod->moduleName) { + dest[0] = (uint64_t)mod->segments[0].addr; + dest[1] = mod->segments[0].size; + return{}; + } + } + } } if (namelen == 2) { @@ -169,7 +186,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, } *(uint32_t *)old = 1; - break; + return{}; case sysctl_kern::sdk_version: { if (*oldlenp != 4 || new_ != nullptr || newlen != 0) { @@ -187,7 +204,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, std::printf("Reporting SDK version %x\n", *reinterpret_cast(sdkVersion)); *(uint32_t *)old = *reinterpret_cast(sdkVersion); - break; + return{}; } case sysctl_kern::sched_cpusetsize: @@ -196,7 +213,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, } *(std::uint32_t *)old = 4; - break; + return{}; case sysctl_kern::rng_pseudo: if (*oldlenp != 0x40 || new_ != nullptr || newlen != 0) { @@ -205,7 +222,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, std::memset(old, 0, 0x40); - break; + return{}; case sysctl_kern::kern_37: { struct kern37_value { @@ -220,7 +237,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, auto value = (kern37_value *)old; value->size = sizeof(kern37_value); - break; + return{}; } case sysctl_kern::proc_ptc: { @@ -229,7 +246,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, } *(std::uint64_t *)old = 1357; - break; + return{}; } case sysctl_kern::cpu_mode: { @@ -241,7 +258,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, // 1 - 7 cpu, low power // 5 - 7 cpu, normal *(std::uint32_t *)old = 5; - break; + return{}; } default: @@ -263,7 +280,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, } *(uint32_t *)old = 0x4000; - break; + return{}; default: break; @@ -289,5 +306,15 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr name, } } + std::string concatName; + for (unsigned int i = 0; i < namelen; ++i) { + if (i != 0) { + concatName += '.'; + } + + concatName += std::to_string(name[i]); + } + + ORBIS_LOG_TODO(__FUNCTION__, concatName); return {}; } diff --git a/rpcsx-os/CMakeLists.txt b/rpcsx-os/CMakeLists.txt index 8572e8ef1..901548110 100644 --- a/rpcsx-os/CMakeLists.txt +++ b/rpcsx-os/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(orbis::kernel::config ALIAS standalone-config) add_executable(rpcsx-os iodev/ajm.cpp iodev/blockpool.cpp + iodev/camera.cpp iodev/console.cpp iodev/dce.cpp iodev/dipsw.cpp diff --git a/rpcsx-os/io-devices.hpp b/rpcsx-os/io-devices.hpp index 71defd2b7..9e6abb37c 100644 --- a/rpcsx-os/io-devices.hpp +++ b/rpcsx-os/io-devices.hpp @@ -22,3 +22,4 @@ IoDevice *createSblSrvCharacterDevice(); IoDevice *createShmDevice(); IoDevice *createBlockPoolDevice(); IoDevice *createUrandomCharacterDevice(); +IoDevice *createCameraCharacterDevice(); diff --git a/rpcsx-os/iodev/camera.cpp b/rpcsx-os/iodev/camera.cpp new file mode 100644 index 000000000..b7253f9c2 --- /dev/null +++ b/rpcsx-os/iodev/camera.cpp @@ -0,0 +1,32 @@ +#include "io-device.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/file.hpp" +#include "orbis/utils/Logs.hpp" + +struct CameraFile : orbis::File {}; + +static orbis::ErrorCode camera_ioctl(orbis::File *file, std::uint64_t request, + void *argp, orbis::Thread *thread) { + + ORBIS_LOG_FATAL("Unhandled camera ioctl", request); + return {}; +} + +static const orbis::FileOps fileOps = { + .ioctl = camera_ioctl, +}; + +struct CameraDevice : IoDevice { + orbis::ErrorCode open(orbis::Ref *file, const char *path, + std::uint32_t flags, std::uint32_t mode, + orbis::Thread *thread) override { + auto newFile = orbis::knew(); + newFile->ops = &fileOps; + newFile->device = this; + + *file = newFile; + return {}; + } +}; + +IoDevice *createCameraCharacterDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/dipsw.cpp b/rpcsx-os/iodev/dipsw.cpp index eab3a6e33..36ef156dd 100644 --- a/rpcsx-os/iodev/dipsw.cpp +++ b/rpcsx-os/iodev/dipsw.cpp @@ -2,18 +2,25 @@ #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" #include "orbis/utils/Logs.hpp" +#include "orbis/thread/Thread.hpp" struct DipswFile : public orbis::File {}; static orbis::ErrorCode dipsw_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { - if (request == 0x40048806) { // is connected? - ORBIS_LOG_ERROR("dipsw ioctl 0x40048806", argp); + if (request == 0x40048806) { // isDevelopmentMode + ORBIS_LOG_ERROR("dipsw ioctl isDevelopmentMode", argp); *reinterpret_cast(argp) = 0; return {}; } + if (request == 0x40048807) { + ORBIS_LOG_ERROR("dipsw ioctl 0x40048807", argp); + *reinterpret_cast(argp) = 1; + return {}; + } + // 0x40088808 // 0x40088809 @@ -38,6 +45,7 @@ static orbis::ErrorCode dipsw_ioctl(orbis::File *file, std::uint64_t request, } ORBIS_LOG_FATAL("Unhandled dipsw ioctl", request); + thread->where(); //__builtin_trap(); return {}; } diff --git a/rpcsx-os/linker.cpp b/rpcsx-os/linker.cpp index d767709af..90df7a092 100644 --- a/rpcsx-os/linker.cpp +++ b/rpcsx-os/linker.cpp @@ -659,20 +659,20 @@ Ref rx::linker::loadModule(std::span image, std::memcpy(result->soName + name.size(), ".prx", sizeof(".prx")); } - if (dyn.d_tag == kElfDynamicTypeNeeded) { - auto name = std::string_view( - sceStrtab + static_cast(dyn.d_un.d_val)); - if (name == "STREQUAL") { - // HACK for broken FWs - result->needed.push_back("libSceDolbyVision.prx"); - } else { - name = patchSoName(name); - if (name != "libSceFreeTypeOptBm") { // TODO - result->needed.emplace_back(name); - result->needed.back() += ".prx"; - } - } - } + // if (dyn.d_tag == kElfDynamicTypeNeeded) { + // auto name = std::string_view( + // sceStrtab + static_cast(dyn.d_un.d_val)); + // if (name == "STREQUAL") { + // // HACK for broken FWs + // result->needed.push_back("libSceDolbyVision.prx"); + // } else { + // name = patchSoName(name); + // if (name != "libSceFreeTypeOptBm") { // TODO + // result->needed.emplace_back(name); + // result->needed.back() += ".prx"; + // } + // } + // } if (dyn.d_tag == kElfDynamicTypeSceModuleInfo) { idToModuleIndex[dyn.d_un.d_val >> 48] = -1; @@ -1054,16 +1054,5 @@ Ref rx::linker::loadModuleByName(std::string_view name, } } - // HACK: implement lazy bind support - for (auto path : { "/app0/Media/Modules/" }) { - auto filePath = std::string(path); - filePath += name; - filePath += ".prx"; - - if (auto result = rx::linker::loadModuleFile(filePath.c_str(), thread)) { - return result; - } - } - return {}; } diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index 28ddca4ca..e1992f462 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -326,6 +326,7 @@ static int ps4Exec(orbis::Thread *mainThread, rx::vfs::mount("/dev/npdrm", createNpdrmCharacterDevice()); rx::vfs::mount("/dev/icc_configuration", createIccConfigurationCharacterDevice()); rx::vfs::mount("/dev/console", createConsoleCharacterDevice()); + rx::vfs::mount("/dev/camera", createCameraCharacterDevice()); rx::vfs::mount("/dev/dmem1", dmem1); rx::vfs::mount("/dev/dmem2", createDmemCharacterDevice(2)); rx::vfs::mount("/dev/stdout", createFdWrapDevice(STDOUT_FILENO)); @@ -363,6 +364,16 @@ static int ps4Exec(orbis::Thread *mainThread, std::vector argvOffsets; std::vector envpOffsets; + auto libSceLibcInternal = rx::linker::loadModuleFile( + "/system/common/lib/libSceLibcInternal.sprx", mainThread); + + if (libSceLibcInternal == nullptr) { + std::fprintf(stderr, "libSceLibcInternal not found\n"); + return 1; + } + + libSceLibcInternal->id = mainThread->tproc->modulesMap.insert(libSceLibcInternal); + auto libkernel = rx::linker::loadModuleFile( "/system/common/lib/libkernel_sys.sprx", mainThread); diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index 77b60aa00..ef468de3a 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -85,6 +85,7 @@ loadPrx(orbis::Thread *thread, std::string_view name, bool relocate, } } + module->importedModules.clear(); module->importedModules.reserve(module->neededModules.size()); for (auto mod : module->neededModules) { @@ -182,8 +183,7 @@ orbis::SysResult dmem_mmap(orbis::Thread *thread, orbis::caddr_t addr, orbis::off_t directMemoryStart) { auto dmem = static_cast(orbis::g_context.dmemDevice.get()); void *address = addr; - auto result = - dmem->mmap(&address, len, prot, flags, directMemoryStart); + auto result = dmem->mmap(&address, len, prot, flags, directMemoryStart); if (result != ErrorCode{}) { return result; } @@ -405,6 +405,32 @@ orbis::SysResult dynlib_load_prx(orbis::Thread *thread, return result; } + { + std::map> loadedModules; + + for (auto [id, module] : thread->tproc->modulesMap) { + // std::fprintf(stderr, "%u: %s\n", (unsigned)id, module->moduleName); + loadedModules[module->moduleName] = module; + } + + for (auto [id, module] : thread->tproc->modulesMap) { + module->importedModules.clear(); + module->importedModules.reserve(module->neededModules.size()); + + for (auto mod : module->neededModules) { + if (auto it = loadedModules.find(std::string_view(mod.name)); + it != loadedModules.end()) { + module->importedModules.emplace_back(it->second); + continue; + } + + module->importedModules.push_back({}); + } + + module->relocate(thread->tproc); + } + } + *pHandle = module->id; return {}; } @@ -554,6 +580,7 @@ SysResult processNeeded(Thread *thread) { } for (auto [id, module] : thread->tproc->modulesMap) { + module->importedModules.clear(); module->importedModules.reserve(module->neededModules.size()); for (auto mod : module->neededModules) {