diff --git a/core/libs/prx/libSceVideoOut/InventoryExports.cpp b/core/libs/prx/libSceVideoOut/InventoryExports.cpp index abb57b2e2e..0bbcff8e99 100644 --- a/core/libs/prx/libSceVideoOut/InventoryExports.cpp +++ b/core/libs/prx/libSceVideoOut/InventoryExports.cpp @@ -9,6 +9,12 @@ namespace { constexpr int VideoOutErrorCurveSamplePoints = static_cast(0x8029001Cu); constexpr int VideoOutErrorLatestEopHandle = static_cast(0x802900FFu); + +std::uint32_t ModeFlags(const void* mode) { + std::uint32_t flags; + std::memcpy(&flags, static_cast(mode) + 0x20, sizeof(flags)); + return flags; +} } extern "C" { @@ -425,8 +431,10 @@ int APS5_VABI sceVideoOutSysHdmiMonitorInfoIsMorpheus() { NotImplemented_nid_no_patch(__func__); } -int APS5_VABI sceVideoOutSysInitMode() { - NotImplemented_nid_no_patch(__func__); +void APS5_VABI sceVideoOutSysInitMode(void* mode) { + std::memset(mode, 0xFF, 0x20); + const std::uint32_t size = 0x20; + std::memcpy(mode, &size, sizeof(size)); } int APS5_VABI sceVideoOutSysIsModeS3d() { @@ -453,26 +461,25 @@ int APS5_VABI sceVideoOutSysIsUserStatusVr() { NotImplemented_nid_no_patch(__func__); } -int APS5_VABI sceVideoOutSysModeIsHdr() { - NotImplemented_nid_no_patch(__func__); +int APS5_VABI sceVideoOutSysModeIsHdr(const void* mode) { + const auto value = static_cast(mode)[6]; + return static_cast(value - 12u) < 6u ? 1 : 0; } -int APS5_VABI sceVideoOutSysModeIsSystemDefault() { - NotImplemented_nid_no_patch(__func__); +int APS5_VABI sceVideoOutSysModeIsSystemDefault(const void* mode) { + return static_cast(~ModeFlags(mode) & 1u); } -int APS5_VABI sceVideoOutSysModeIsVrLegacy() { - NotImplemented_nid_no_patch(__func__); +int APS5_VABI sceVideoOutSysModeIsVrLegacy(const void* mode) { + return (ModeFlags(mode) & 6u) == 6u ? 1 : 0; } -int APS5_VABI sceVideoOutSysModeIsVrNative() { - NotImplemented_nid_no_patch(__func__); +int APS5_VABI sceVideoOutSysModeIsVrNative(const void* mode) { + return (ModeFlags(mode) & 6u) == 2u ? 1 : 0; } int APS5_VABI sceVideoOutSysModeIsVr(const void* mode) { - std::uint32_t flags; - std::memcpy(&flags, static_cast(mode) + 0x20, sizeof(flags)); - return static_cast((flags >> 1) & 1u); + return static_cast((ModeFlags(mode) >> 1) & 1u); } int APS5_VABI sceVideoOutSysOpenInternal() { diff --git a/core/libs/prx/libSceVideoOut/include/InventoryExports.hpp b/core/libs/prx/libSceVideoOut/include/InventoryExports.hpp index 6b9f6feedc..40c9079b46 100644 --- a/core/libs/prx/libSceVideoOut/include/InventoryExports.hpp +++ b/core/libs/prx/libSceVideoOut/include/InventoryExports.hpp @@ -107,17 +107,17 @@ int APS5_VABI sceVideoOutSysGetVblankStatus2(); int APS5_VABI sceVideoOutSysGetVblankStatus(); int APS5_VABI sceVideoOutSysGetVideoOutModeByBusSpecifier(); int APS5_VABI sceVideoOutSysHdmiMonitorInfoIsMorpheus(); -int APS5_VABI sceVideoOutSysInitMode(); +void APS5_VABI sceVideoOutSysInitMode(void* mode); int APS5_VABI sceVideoOutSysIsModeS3d(); int APS5_VABI sceVideoOutSysIsOutputSupported(); int APS5_VABI sceVideoOutSysIsSupportedByMonitorInfo_(); int APS5_VABI sceVideoOutSysIsUserStatusHdr(); int APS5_VABI sceVideoOutSysIsUserStatusSystemDefault(); int APS5_VABI sceVideoOutSysIsUserStatusVr(); -int APS5_VABI sceVideoOutSysModeIsHdr(); -int APS5_VABI sceVideoOutSysModeIsSystemDefault(); -int APS5_VABI sceVideoOutSysModeIsVrLegacy(); -int APS5_VABI sceVideoOutSysModeIsVrNative(); +int APS5_VABI sceVideoOutSysModeIsHdr(const void* mode); +int APS5_VABI sceVideoOutSysModeIsSystemDefault(const void* mode); +int APS5_VABI sceVideoOutSysModeIsVrLegacy(const void* mode); +int APS5_VABI sceVideoOutSysModeIsVrNative(const void* mode); int APS5_VABI sceVideoOutSysModeIsVr(const void* mode); int APS5_VABI sceVideoOutSysOpenInternal(); int APS5_VABI sceVideoOutSysOpenVrNative(); diff --git a/core/libs/tests/GuestVideoOutFirmwareAnswers.cpp b/core/libs/tests/GuestVideoOutFirmwareAnswers.cpp index c463fc5d09..c1f55364e6 100644 --- a/core/libs/tests/GuestVideoOutFirmwareAnswers.cpp +++ b/core/libs/tests/GuestVideoOutFirmwareAnswers.cpp @@ -1,5 +1,6 @@ #include "prx/libSceVideoOut/include/InventoryExports.hpp" #include +#include #include #include #include @@ -19,6 +20,54 @@ static int ModeIsVr(std::uint32_t flags, std::uint8_t fill) { return sceVideoOutSysModeIsVr(mode.data()); } +static std::array Mode(std::uint32_t flags, std::uint8_t fill) { + std::array mode; + mode.fill(fill); + std::memcpy(mode.data() + 0x20, &flags, sizeof(flags)); + return mode; +} + +static std::array ModeWithByte6(std::uint8_t value, std::uint8_t fill) { + std::array mode; + mode.fill(fill); + mode[6] = value; + return mode; +} + +static void CheckInitMode() { + std::array mode; + mode.fill(0x5A); + sceVideoOutSysInitMode(mode.data()); + std::uint32_t size; + std::memcpy(&size, mode.data(), sizeof(size)); + Require(size == 0x20, "sceVideoOutSysInitMode did not store 0x20 in the first dword"); + for (std::size_t i = 4; i < 0x20; ++i) Require(mode[i] == 0xFF, "sceVideoOutSysInitMode did not fill bytes 4 to 0x1F with 0xFF"); + for (std::size_t i = 0x20; i < mode.size(); ++i) Require(mode[i] == 0x5A, "sceVideoOutSysInitMode wrote past 0x20 bytes"); +} + +static void CheckModeFlags() { + for (std::uint8_t fill : {std::uint8_t{0}, std::uint8_t{0xFF}}) { + for (std::uint32_t flags = 0; flags < 8; ++flags) { + for (std::uint32_t high : {0u, 0xFFFFFFF8u}) { + const auto mode = Mode(flags | high, fill); + Require(sceVideoOutSysModeIsSystemDefault(mode.data()) == ((flags & 1u) ? 0 : 1), "sceVideoOutSysModeIsSystemDefault did not report bit 0 of the dword at 0x20 clear"); + Require(sceVideoOutSysModeIsVrNative(mode.data()) == ((flags & 6u) == 2u ? 1 : 0), "sceVideoOutSysModeIsVrNative did not report bits 1 and 2 of the dword at 0x20 as 1 and 0"); + Require(sceVideoOutSysModeIsVrLegacy(mode.data()) == ((flags & 6u) == 6u ? 1 : 0), "sceVideoOutSysModeIsVrLegacy did not report bits 1 and 2 of the dword at 0x20 both set"); + } + } + } +} + +static void CheckModeIsHdr() { + for (unsigned value = 0; value < 256; ++value) { + const int expected = value >= 12 && value <= 17 ? 1 : 0; + for (std::uint8_t fill : {std::uint8_t{0}, std::uint8_t{0xFF}}) { + const auto mode = ModeWithByte6(static_cast(value), fill); + Require(sceVideoOutSysModeIsHdr(mode.data()) == expected, "sceVideoOutSysModeIsHdr did not report byte 6 from 12 to 17"); + } + } +} + int main() { Require(sceVideoOutAddBufferHdrPrivilege() == 0, "sceVideoOutAddBufferHdrPrivilege did not return 0"); Require(sceVideoOutRazorRecallCallbacks() == 0, "sceVideoOutRazorRecallCallbacks did not return 0"); @@ -30,5 +79,8 @@ int main() { Require(ModeIsVr(0xFFFFFFFFu, 0xFF) == 1, "a mode with every bit set did not report VR"); Require(ModeIsVr(0xFFFFFFFDu, 0xFF) == 0, "the other bits of the dword at 0x20 reported VR"); Require(ModeIsVr(0u, 0xFF) == 0, "bytes outside the dword at 0x20 reported VR"); + CheckInitMode(); + CheckModeFlags(); + CheckModeIsHdr(); return 0; } diff --git a/docs/dev/debt/libSceVideoOut.md b/docs/dev/debt/libSceVideoOut.md index 754fd25e5f..9904d8e22d 100644 --- a/docs/dev/debt/libSceVideoOut.md +++ b/docs/dev/debt/libSceVideoOut.md @@ -65,7 +65,7 @@ - The [revision-pinned identity inventory](https://gist.github.com/kyon-eth/ea0a096e6231dbe7b98b5a308e2ac91e/00f8422a1ae71e32816d72ae579c2f2d097f63a0) records module, logical library, symbol type and NIDs for [InventoryExports.cpp](../../../core/libs/prx/libSceVideoOut/InventoryExports.cpp); it is a metadata summary rather than independent verification. Some NIDs belong to multiple logical libraries within the module. -- [Additional callable exports](../../../core/libs/prx/libSceVideoOut/InventoryExports.cpp) - 175 entries observed in a 3.20-labelled image and a later 13.60-labelled image; of the original 182, 107 match the public 3.20 catalogue and 75 do not. These are import-resolution declarations only. Neither image label authenticates a retail firmware version. Parameter lists, return types and behavior are unverified; parameterless `int` declarations are placeholders, not verified ABI contracts. Every entry throws through `NotImplemented_nid_no_patch`. Unidentified names use literal NID aliases. No runtime functionality is implemented; data exports need separate analysis. Identified candidate names match their NIDs in the [public symbol database](https://github.com/zecoxao/sce_symbols/blob/2883963a0a514ba6e77407a08ef4730a65e88254/aerolib.csv) or [supplemental catalog](https://github.com/claimore22/ps5rs/blob/2304be5131221bae0dac24b9767cabffda33f747/data/nids.csv). +- [Additional callable exports](../../../core/libs/prx/libSceVideoOut/InventoryExports.cpp) - 170 entries observed in a 3.20-labelled image and a later 13.60-labelled image; of the original 182, 107 match the public 3.20 catalogue and 75 do not. These are import-resolution declarations only. Neither image label authenticates a retail firmware version. Parameter lists, return types and behavior are unverified; parameterless `int` declarations are placeholders, not verified ABI contracts. Every entry throws through `NotImplemented_nid_no_patch`. Unidentified names use literal NID aliases. No runtime functionality is implemented; data exports need separate analysis. Identified candidate names match their NIDs in the [public symbol database](https://github.com/zecoxao/sce_symbols/blob/2883963a0a514ba6e77407a08ef4730a65e88254/aerolib.csv) or [supplemental catalog](https://github.com/claimore22/ps5rs/blob/2304be5131221bae0dac24b9767cabffda33f747/data/nids.csv). | Name | NID | | --- | --- | @@ -167,17 +167,12 @@ | `sceVideoOutSysGetVblankStatus` | `d1AjT2uZJn0` | | `sceVideoOutSysGetVideoOutModeByBusSpecifier` | `AAELy8Yc3Mc` | | `sceVideoOutSysHdmiMonitorInfoIsMorpheus` | `3-9DXFGVg0M` | -| `sceVideoOutSysInitMode` | `9cmjhjqa7Sg` | | `sceVideoOutSysIsModeS3d` | `iUigHJ2op4M` | | `sceVideoOutSysIsOutputSupported` | `Z0EyU29WqOg` | | `sceVideoOutSysIsSupportedByMonitorInfo_` | `mfxElr79O7Q` | | `sceVideoOutSysIsUserStatusHdr` | `q+vWPvYIh8o` | | `sceVideoOutSysIsUserStatusSystemDefault` | `O57F5ikhGxo` | | `sceVideoOutSysIsUserStatusVr` | `4XsQdhiOaAc` | -| `sceVideoOutSysModeIsHdr` | `I7-lGGvFgBM` | -| `sceVideoOutSysModeIsSystemDefault` | `5Y8uUbGMio0` | -| `sceVideoOutSysModeIsVrLegacy` | `zecl8Gox+P0` | -| `sceVideoOutSysModeIsVrNative` | `SgA2MtojPto` | | `sceVideoOutSysOpenInternal` | `kP4l+nyBjRA` | | `sceVideoOutSysOpenVrNative` | `WUU+ufqgLJg` | | `sceVideoOutSysReadCrc64` | `eBvoaLwfBBQ` | @@ -247,6 +242,8 @@ - [Firmware 13.42 answers](../../../core/libs/prx/libSceVideoOut/InventoryExports.cpp) (libSceVideoOut) - `sceVideoOutAddBufferHdrPrivilege`, `sceVideoOutRazorRecallCallbacks` and `sceVideoOutSysUpdateRenderingMode` return 0, `sceVideoOutCurveSamplePointsCalc_` returns 0x8029001C, `sceVideoOutDriverGetLatestEopHandle` 0x802900FF and `sceVideoOutSysGetMonitorInfo_` -1, and `sceVideoOutSysModeIsVr` returns bit 1 of the dword at offset 0x20 of its argument, as firmware 13.42's libSceVideoOut does: read to the return, disassembly only, not measured on a console. Their parameter lists are unverified beyond what the code reads; the layout of the structure `sceVideoOutSysModeIsVr` reads is unknown apart from that dword. The module reads that dword without checking the pointer, so a null argument faults on the console as it does here +- [Firmware 13.42 mode helpers](../../../core/libs/prx/libSceVideoOut/InventoryExports.cpp) (libSceVideoOut) - `sceVideoOutSysInitMode` fills the first 0x20 bytes of its argument with 0xFF and then stores 0x20 in the first dword. Of the dword at offset 0x20, `sceVideoOutSysModeIsSystemDefault` reports bit 0 clear, `sceVideoOutSysModeIsVrNative` bits 2:1 equal to 01 and `sceVideoOutSysModeIsVrLegacy` both bits set; `sceVideoOutSysModeIsHdr` reports byte 6 from 12 to 17. As firmware 13.42's libSceVideoOut does: read to the return, disassembly only, not measured on a console. The init function leaves EAX unset, so it is declared `void`. Field meanings are unknown, and none of them checks the pointer. + - [sceVideoOutSetConfigurationMode](../../../core/libs/prx/libSceVideoOut/InventoryExports.cpp): the name hashes to NID `N1+j0RymMUQ`, a function export in both older and later version-labelled images. Its signature and behavior are unverified; this import-resolution declaration throws. - [Older callable NIDs](../../../core/libs/prx/libSceVideoOut/InventoryExports.cpp): 7 unidentified exports have unverified names, signatures and behavior. These are throwing import-resolution placeholders; no functionality is implemented. No matching NIDs were found in the later module inventory. Six use the primary library qualifier and one uses the nosubmission qualifier; qualified guest import resolution is unverified.