feat(libkernel): implement sceKernelGetProsperoSystemSwVersion

AI-assisted: yes
This commit is contained in:
overlordxrz-source 2026-10-11 02:38:19 +00:00
parent 2a4e03ce58
commit 26cad4e8c8
4 changed files with 97 additions and 0 deletions

View File

@ -53,6 +53,7 @@ add_library(libkernel SHARED EXCLUDE_FROM_ALL
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Process.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Sandbox.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/SystemConfiguration.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/SoftwareVersion.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Signals.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/SignalSets.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Notification.cpp
@ -677,6 +678,15 @@ if(BUILD_TESTING)
set_tests_properties(guest_system_configuration PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_software_version_tests ${LIBS_INCLUDE_DIR}/tests/GuestSoftwareVersion.cpp)
target_include_directories(guest_software_version_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_software_version_tests PRIVATE libkernel libc)
configure_windows_unwind(guest_software_version_tests)
add_test(NAME guest_software_version COMMAND guest_software_version_tests)
if(WIN32)
set_tests_properties(guest_software_version PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_system_command_tests ${LIBS_INCLUDE_DIR}/tests/GuestSystemCommand.cpp)
target_include_directories(guest_system_command_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_system_command_tests PRIVATE libkernel libc)

View File

@ -0,0 +1,36 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libkernel/KernelErrors.hpp"
#include <cstddef>
#include <cstdint>
#include <cstring>
struct SceKernelProsperoSystemSwVersion {
std::uint64_t size;
char versionString[0x1C];
std::uint32_t version;
};
static_assert(offsetof(SceKernelProsperoSystemSwVersion, size) == 0x00);
static_assert(offsetof(SceKernelProsperoSystemSwVersion, versionString) == 0x08);
static_assert(offsetof(SceKernelProsperoSystemSwVersion, version) == 0x24);
static_assert(sizeof(SceKernelProsperoSystemSwVersion) == 0x28);
namespace {
constexpr std::uint32_t SystemSoftwareVersion = 0x01000000;
constexpr char SystemSoftwareVersionString[] = "01.000.000";
}
extern "C" {
int APS5_VABI sceKernelGetProsperoSystemSwVersion_nid_postfix(SceKernelProsperoSystemSwVersion* version) {
if (version == nullptr) return SCE_KERNEL_ERROR_EFAULT;
if (version->size != sizeof(SceKernelProsperoSystemSwVersion)) return SCE_KERNEL_ERROR_EINVAL;
std::memset(version->versionString, 0, sizeof(version->versionString));
std::memcpy(version->versionString, SystemSoftwareVersionString, sizeof(SystemSoftwareVersionString));
version->version = SystemSoftwareVersion;
return 0;
}
}

View File

@ -0,0 +1,50 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libkernel/KernelErrors.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
struct SceKernelProsperoSystemSwVersion {
std::uint64_t size;
char versionString[0x1C];
std::uint32_t version;
};
static_assert(offsetof(SceKernelProsperoSystemSwVersion, versionString) == 0x08);
static_assert(offsetof(SceKernelProsperoSystemSwVersion, version) == 0x24);
static_assert(sizeof(SceKernelProsperoSystemSwVersion) == 0x28);
extern "C" {
int* APS5_VABI __error_nid_postfix();
int APS5_VABI sceKernelGetProsperoSystemSwVersion_nid_postfix(SceKernelProsperoSystemSwVersion*);
}
static void Require(bool value) { if (!value) std::abort(); }
static void CheckProsperoSystemSwVersion() {
*__error_nid_postfix() = 13;
Require(sceKernelGetProsperoSystemSwVersion_nid_postfix(nullptr) == SCE_KERNEL_ERROR_EFAULT);
const std::uint64_t sizes[] = {0, 0x18, 0x27, 0x30};
for (const std::uint64_t size : sizes) {
SceKernelProsperoSystemSwVersion version{};
std::memset(&version, 0xaa, sizeof(version));
version.size = size;
Require(sceKernelGetProsperoSystemSwVersion_nid_postfix(&version) == SCE_KERNEL_ERROR_EINVAL);
Require(version.size == size && version.version == 0xaaaaaaaa && static_cast<unsigned char>(version.versionString[0]) == 0xaa);
}
SceKernelProsperoSystemSwVersion version{};
std::memset(&version, 0xaa, sizeof(version));
version.size = sizeof(version);
Require(sceKernelGetProsperoSystemSwVersion_nid_postfix(&version) == 0);
Require(version.size == sizeof(version));
Require(std::strcmp(version.versionString, "01.000.000") == 0);
for (std::size_t i = sizeof("01.000.000"); i < sizeof(version.versionString); ++i) Require(version.versionString[i] == 0);
Require(version.version == 0x01000000);
Require(*__error_nid_postfix() == 13);
}
int main() {
CheckProsperoSystemSwVersion();
return 0;
}

View File

@ -48,6 +48,7 @@ Throughout the project, every function at every stage either **does exactly what
- [sceNpGetSandboxInfo](../../core/libs/prx/libSceNpManager/Export.cpp) (libSceNpManager, NID `ZVZ++68nNI8`) - the name hashes to the imported NID (found with nidhunt, confirmed with `tools/nid_names.py`). STAR WARS: Galactic Racer (PPSA28416) imports it; its OnlineSubsystemPS5 calls it with one pointer to a 0x50-byte stack buffer and reads the buffer as a string (discussions/3086). The returned string, the exact parameter struct and console errors are unknown, so every call throws without reading or writing caller memory. A working implementation belongs with that title's bring-up.
- [sceVideoOutGetOutputStatusWithVrr](../../core/libs/prx/libSceVideoOut/Unimplemented.cpp) (libSceVideoOut, NID `gWT7X8H0bYs`) - the name hashes to the imported NID. PPSA26344 version 02.002.000 passes a VideoOut handle and an output pointer at three call sites. It compares a 32-bit value at byte 4 with 2, tests bit 0x10 at byte 16, and, when set, compares low 16-bit values at bytes 48, 50 and 52 with 48, 60 and 120. The full output layout, size, field meanings and console errors are unknown. Every call throws without reading or writing caller memory.
- [sceKernelGetProsperoSystemSwVersion](../../core/libs/prx/libkernel/System/src/SoftwareVersion.cpp) (libkernel) reports system software version `0x01000000` ("01.000.000"); the console's firmware version is not modeled. The 0x28-byte block (a 64-bit size at 0, the version string at 8 and the packed version at 0x24) follows [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/Kernel/KernelSystem.cs), which Prospero Multi Tools (PPSA99110) and Prospero Explorer (PPSA99109) are built with and which sets the size to 40, and the same fields in [etaHEN](https://github.com/etaHEN/etaHEN/blob/main/Source%20Code/daemon/include/ipc.hpp) and [shsrv](https://github.com/ps5-payload-dev/shsrv/blob/master/sh.c). A size other than 0x28 returns `SCE_KERNEL_ERROR_EINVAL` without writing; whether the console checks the size is unverified, since etaHEN and shsrv declare a 0x30-byte block and do not set it
- [getuid, geteuid, getgid, getegid and issetugid](../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) report the root identity (0) and a process that never changed credentials (`issetugid` 0), as a jailbroken process has; the host user and group are not exposed to the guest. The values a title sees on a console are unverified
- [sceKernelGetAppInfo](../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) - only `app_id` and the title ID (offset 0x10, up to 9 characters plus a terminator) are written; callers declare the structure with different sizes, so the rest is left alone. `app_id` is 1, the running title's id in libSceSystemService, which is a guess, not something measured. The error codes follow shadPS4: `EPERM` for another process, and 0 without writing anything for a null pointer.
- [sceFontSetScriptLanguage, sceFontGetScriptLanguage, sceFontSetTypographicDesign, sceFontGetTypographicDesign](../../core/libs/prx/libSceFont/src/Style.cpp) (libSceFont) - signatures follow [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/Font/SceFont.cs), not confirmed for the PS5. The handle keeps the language set for each script and the feature set for each typographic design and returns them, with 0 for one never set; the console default and its valid ranges are unknown, so any value is accepted. Neither setting changes shaping or rendering yet