feat(psml): implement the MFSR shared-resource and 800 context setup

scePsmlMfsrInit, the shared-resource calls and the 800M3_2 context calls
threw or answered "not initialized", so a title that sets PSSR up at
start-up stopped there even when it never uses PSSR on hardware without
it (PPSA08330 calls the setup unconditionally and only dispatches when
sceKernelIsTrinityMode is set, which AnyPS5 reports as 0).

The layouts come from the calls in PPSA08330 and PPSA03016: requirements
are {block bytes, alignment, block count}, handles are 8-byte values
written through the first argument, and a context parameter carries its
block list at 8/16 and the shared-resources handle at 0x38. Init sets
the initialized state, the requirements ask for four 2 MiB blocks (what
PPSA08330 allocates regardless of the returned count), and create and
release keep bookkeeping objects. Invalid arguments throw because their
error codes are unknown.

The 1100 calls, scePsmlMfsrCreateContext1300 and the 900/1000/1300
dispatch packets keep returning 0x8A810001 before Init and throw after
it; packet size, mip bias and capture still throw.

The guest test links libc and gets Windows unwinding so it can check the
refused calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ps54allandClaude Opus 5.5 authored and Adrià Franch committed 2026-10-16 20:41:44 +02:00
1 parent 16a0f509a3
commit 7ab3d441c1
4 files changed
+353 -43

No files matched your search

@@ -4,7 +4,8 @@ add_sce_psml_library(libScePsml_debug)
if(BUILD_TESTING)
add_test_executable(guest_psml_tests ${LIBS_INCLUDE_DIR}/tests/GuestPsml.cpp)
target_include_directories(guest_psml_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_psml_tests PRIVATE libScePsml_debug)
target_link_libraries(guest_psml_tests PRIVATE libScePsml_debug libc)
configure_windows_unwind(guest_psml_tests)
add_test(NAME guest_psml COMMAND guest_psml_tests)
if(WIN32)
set_tests_properties(guest_psml PROPERTIES ENVIRONMENT_MODIFICATION
+155 -39
View File
@@ -1,11 +1,94 @@
#include <cstdint>
#include <cstddef>
#include <atomic>
#include <mutex>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
namespace {
constexpr std::int32_t SCE_PSML_ERROR_NOT_INITIALIZED = static_cast<std::int32_t>(0x8A810001);
constexpr std::uint64_t MfsrBlockBytes = 0x200000;
constexpr std::uint64_t MfsrBlockCount = 4;
struct MfsrRequirement {
std::uint64_t blockBytes;
std::uint64_t alignment;
std::uint64_t blockCount;
};
struct MfsrBlock {
std::uint64_t address;
std::uint64_t bytes;
};
struct MfsrSharedResourcesParam {
std::uint32_t type;
std::uint32_t reserved;
const MfsrBlock* blocks;
std::uint64_t blockCount;
std::uint64_t reserved2;
};
struct MfsrContextParam {
std::uint32_t reserved0[2];
const MfsrBlock* blocks;
std::uint64_t blockCount;
std::uint32_t reserved1[8];
void* sharedResources;
};
static_assert(sizeof(MfsrRequirement) == 0x18);
static_assert(sizeof(MfsrSharedResourcesParam) == 0x20);
static_assert(offsetof(MfsrContextParam, blocks) == 0x08);
static_assert(offsetof(MfsrContextParam, blockCount) == 0x10);
static_assert(offsetof(MfsrContextParam, sharedResources) == 0x38);
enum class MfsrObjectKind { SharedResources, Context };
struct MfsrObject {
MfsrObjectKind kind;
void* sharedResources;
};
std::atomic<bool> g_mfsrInitialized{false};
std::mutex g_mfsrMutex;
std::unordered_map<void*, MfsrObject*> g_mfsrObjects;
void RequireMfsr(bool condition, const char* function, const char* what) {
if (!condition) throw std::runtime_error(std::string(function) + ": " + what);
}
void RequireBlocks(const MfsrBlock* blocks, std::uint64_t blockCount, const char* function) {
RequireMfsr(blockCount >= MfsrBlockCount, function, "fewer memory blocks than the requirement");
RequireMfsr(blocks != nullptr, function, "null memory block list");
for (std::uint64_t i = 0; i < MfsrBlockCount; ++i) {
RequireMfsr(blocks[i].bytes >= MfsrBlockBytes && blocks[i].address % MfsrBlockBytes == 0, function, "memory block smaller or less aligned than the requirement");
}
}
void* CreateMfsrObject(MfsrObjectKind kind, void* sharedResources) {
auto* object = new MfsrObject{kind, sharedResources};
std::lock_guard lock(g_mfsrMutex);
g_mfsrObjects.emplace(object, object);
return object;
}
void ReleaseMfsrObject(void* handle, MfsrObjectKind kind, const char* function) {
std::lock_guard lock(g_mfsrMutex);
const auto found = g_mfsrObjects.find(handle);
RequireMfsr(found != g_mfsrObjects.end() && found->second->kind == kind, function, "handle was not created by this library");
if (kind == MfsrObjectKind::SharedResources) {
for (const auto& [key, object] : g_mfsrObjects) {
RequireMfsr(object->sharedResources != handle, function, "shared resources still used by a context");
}
}
delete found->second;
g_mfsrObjects.erase(found);
}
}
@@ -14,12 +97,14 @@ extern "C" {
std::int32_t APS5_VABI scePsmlMfsrGetContextBufferRequirement1100(void* requirement, const void* param) {
(void)requirement;
(void)param;
if (g_mfsrInitialized) NotImplemented_nid_no_patch(__func__);
return SCE_PSML_ERROR_NOT_INITIALIZED;
}
std::int32_t APS5_VABI scePsmlMfsrCreateContext1100(void** context, const void* param) {
(void)context;
(void)param;
if (g_mfsrInitialized) NotImplemented_nid_no_patch(__func__);
return SCE_PSML_ERROR_NOT_INITIALIZED;
}
@@ -27,39 +112,84 @@ std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1100(void* context, void*
(void)context;
(void)commandBuffer;
(void)param;
if (g_mfsrInitialized) NotImplemented_nid_no_patch(__func__);
return SCE_PSML_ERROR_NOT_INITIALIZED;
}
int APS5_VABI scePsmlMfsrCreateContext1300() {
NotImplemented_nid_no_patch(__func__);
std::int32_t APS5_VABI scePsmlMfsrInit() {
g_mfsrInitialized = true;
return 0;
}
int APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1300() {
NotImplemented_nid_no_patch(__func__);
std::int32_t APS5_VABI scePsmlMfsrGetSharedResourcesInitRequirement(MfsrRequirement* requirement, const MfsrSharedResourcesParam* param) {
if (!g_mfsrInitialized) return SCE_PSML_ERROR_NOT_INITIALIZED;
RequireMfsr(requirement != nullptr && param != nullptr, __func__, "null requirement or parameter");
RequireMfsr(param->type == 0, __func__, ("shared resources type " + std::to_string(param->type) + " is not supported").c_str());
*requirement = {MfsrBlockBytes, MfsrBlockBytes, MfsrBlockCount};
return 0;
}
int APS5_VABI scePsmlMfsrGetSharedResourcesInitRequirement() {
NotImplemented_nid_no_patch(__func__);
std::int32_t APS5_VABI scePsmlMfsrCreateSharedResources(void** sharedResources, const MfsrSharedResourcesParam* param) {
if (!g_mfsrInitialized) return SCE_PSML_ERROR_NOT_INITIALIZED;
RequireMfsr(sharedResources != nullptr && param != nullptr, __func__, "null handle or parameter");
RequireMfsr(param->type == 0, __func__, ("shared resources type " + std::to_string(param->type) + " is not supported").c_str());
RequireBlocks(param->blocks, param->blockCount, __func__);
*sharedResources = CreateMfsrObject(MfsrObjectKind::SharedResources, nullptr);
return 0;
}
int APS5_VABI scePsmlMfsrInit() {
NotImplemented_nid_no_patch(__func__);
std::int32_t APS5_VABI scePsmlMfsrReleaseSharedResources(void* sharedResources) {
if (!g_mfsrInitialized) return SCE_PSML_ERROR_NOT_INITIALIZED;
ReleaseMfsrObject(sharedResources, MfsrObjectKind::SharedResources, __func__);
return 0;
}
std::int32_t APS5_VABI scePsmlMfsrGetContextBufferRequirement800M3_2(MfsrRequirement* requirement, const MfsrContextParam* param) {
if (!g_mfsrInitialized) return SCE_PSML_ERROR_NOT_INITIALIZED;
RequireMfsr(requirement != nullptr && param != nullptr, __func__, "null requirement or parameter");
*requirement = {MfsrBlockBytes, MfsrBlockBytes, MfsrBlockCount};
return 0;
}
std::int32_t APS5_VABI scePsmlMfsrCreateContext800M3_2(void** context, const MfsrContextParam* param) {
if (!g_mfsrInitialized) return SCE_PSML_ERROR_NOT_INITIALIZED;
RequireMfsr(context != nullptr && param != nullptr, __func__, "null handle or parameter");
RequireBlocks(param->blocks, param->blockCount, __func__);
{
std::lock_guard lock(g_mfsrMutex);
const auto found = g_mfsrObjects.find(param->sharedResources);
RequireMfsr(found != g_mfsrObjects.end() && found->second->kind == MfsrObjectKind::SharedResources, __func__, "shared resources handle was not created by this library");
}
*context = CreateMfsrObject(MfsrObjectKind::Context, param->sharedResources);
return 0;
}
std::int32_t APS5_VABI scePsmlMfsrReleaseContext(void* context) {
if (!g_mfsrInitialized) return SCE_PSML_ERROR_NOT_INITIALIZED;
ReleaseMfsrObject(context, MfsrObjectKind::Context, __func__);
return 0;
}
std::int32_t APS5_VABI scePsmlMfsrCreateContext1300(void** context, const void* param) {
(void)context;
(void)param;
if (g_mfsrInitialized) NotImplemented_nid_no_patch(__func__);
return SCE_PSML_ERROR_NOT_INITIALIZED;
}
std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1300(void* context, void* commandBuffer, const void* param) {
(void)context;
(void)commandBuffer;
(void)param;
if (g_mfsrInitialized) NotImplemented_nid_no_patch(__func__);
return SCE_PSML_ERROR_NOT_INITIALIZED;
}
int APS5_VABI scePsmlMfsrGetDispatchMfsrPacketSizeInDwords() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI scePsmlMfsrGetContextBufferRequirement800M3_2() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI scePsmlMfsrSelectConfig() {
NotImplemented_nid_no_patch(__func__);
return 0;
@@ -75,39 +205,25 @@ int APS5_VABI scePsmlMfsrRequestCapture() {
return 0;
}
int APS5_VABI scePsmlMfsrReleaseContext() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI scePsmlMfsrIsCaptureInProgress() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1000() {
NotImplemented_nid_no_patch(__func__);
return 0;
std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1000(void* context, void* commandBuffer, const void* param) {
(void)context;
(void)commandBuffer;
(void)param;
if (g_mfsrInitialized) NotImplemented_nid_no_patch(__func__);
return SCE_PSML_ERROR_NOT_INITIALIZED;
}
int APS5_VABI scePsmlMfsrGetDispatchMfsrPacket900() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI scePsmlMfsrCreateSharedResources() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI scePsmlMfsrCreateContext800M3_2() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI scePsmlMfsrReleaseSharedResources() {
NotImplemented_nid_no_patch(__func__);
return 0;
std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket900(void* context, void* commandBuffer, const void* param) {
(void)context;
(void)commandBuffer;
(void)param;
if (g_mfsrInitialized) NotImplemented_nid_no_patch(__func__);
return SCE_PSML_ERROR_NOT_INITIALIZED;
}
int APS5_VABI scePsmlMfsr2ReleaseSharedResources() {
+188
View File
@@ -2,11 +2,25 @@
#include <array>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <string>
extern "C" {
std::int32_t APS5_VABI scePsmlMfsrGetContextBufferRequirement1100(void* requirement, const void* param);
std::int32_t APS5_VABI scePsmlMfsrCreateContext1100(void** context, const void* param);
std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1100(void* context, void* commandBuffer, const void* param);
std::int32_t APS5_VABI scePsmlMfsrGetContextBufferRequirement800M3_2(void* requirement, const void* param);
std::int32_t APS5_VABI scePsmlMfsrCreateContext800M3_2(void** context, const void* param);
std::int32_t APS5_VABI scePsmlMfsrCreateContext1300(void** context, const void* param);
std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket900(void* context, void* commandBuffer, const void* param);
std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1000(void* context, void* commandBuffer, const void* param);
std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1300(void* context, void* commandBuffer, const void* param);
std::int32_t APS5_VABI scePsmlMfsrInit();
std::int32_t APS5_VABI scePsmlMfsrGetSharedResourcesInitRequirement(void* requirement, const void* param);
std::int32_t APS5_VABI scePsmlMfsrCreateSharedResources(void** sharedResources, const void* param);
std::int32_t APS5_VABI scePsmlMfsrReleaseSharedResources(void* sharedResources);
std::int32_t APS5_VABI scePsmlMfsrReleaseContext(void* context);
}
namespace {
@@ -20,6 +34,164 @@ struct CommandBuffer {
std::uint32_t sizeInDwords;
};
using CreateContext = std::int32_t (APS5_VABI*)(void**, const void*);
using GetDispatchPacket = std::int32_t (APS5_VABI*)(void*, void*, const void*);
void CreateContextUntouched(CreateContext create) {
std::array<std::uint8_t, 0x158> param{};
std::uint64_t contextStorage = 0;
void* const sentinel = &contextStorage;
void* context = sentinel;
Require(create(&context, param.data()) == kErrNotInitialized);
Require(context == sentinel);
Require(create(nullptr, nullptr) == kErrNotInitialized);
}
void DispatchPacketUntouched(GetDispatchPacket dispatch) {
std::array<std::uint8_t, 0x158> param{};
std::uint64_t contextStorage = 0;
std::array<std::uint32_t, 64> dwords;
dwords.fill(0xa5a5a5a5u);
const auto untouchedDwords = dwords;
CommandBuffer commandBuffer{dwords.data(), static_cast<std::uint32_t>(dwords.size())};
Require(dispatch(&contextStorage, &commandBuffer, param.data()) == kErrNotInitialized);
Require(dispatch(nullptr, &commandBuffer, nullptr) == kErrNotInitialized);
Require(commandBuffer.cursor == dwords.data());
Require(commandBuffer.sizeInDwords == dwords.size());
Require(dwords == untouchedDwords);
}
template <typename TCall>
bool Throws(TCall call, const char* text) {
try {
call();
} catch (const std::runtime_error& error) {
return std::string(error.what()).find(text) != std::string::npos;
}
return false;
}
struct Requirement {
std::uint64_t blockBytes;
std::uint64_t alignment;
std::uint64_t blockCount;
};
struct Block {
std::uint64_t address;
std::uint64_t bytes;
};
struct SharedParam {
std::uint32_t type;
std::uint32_t reserved;
const Block* blocks;
std::uint64_t blockCount;
std::uint64_t reserved2;
};
struct ContextParam {
std::array<std::uint8_t, 0x60> bytes{};
void Set(const Block* blocks, std::uint64_t count, void* shared) {
std::memcpy(bytes.data() + 0x08, &blocks, sizeof(blocks));
std::memcpy(bytes.data() + 0x10, &count, sizeof(count));
std::memcpy(bytes.data() + 0x38, &shared, sizeof(shared));
}
};
std::array<Block, 4> Blocks(const Requirement& requirement, std::uint64_t first) {
std::array<Block, 4> blocks{};
for (std::size_t i = 0; i < blocks.size(); ++i) blocks[i] = {first + i * requirement.blockBytes, requirement.blockBytes};
return blocks;
}
void SetupBeforeInit() {
std::uint64_t storage = 0;
void* const sentinel = &storage;
void* handle = sentinel;
Requirement requirement{1, 2, 3};
SharedParam sharedParam{};
Require(scePsmlMfsrGetSharedResourcesInitRequirement(&requirement, &sharedParam) == kErrNotInitialized);
Require(requirement.blockBytes == 1 && requirement.alignment == 2 && requirement.blockCount == 3);
Require(scePsmlMfsrCreateSharedResources(&handle, &sharedParam) == kErrNotInitialized);
Require(handle == sentinel);
Require(scePsmlMfsrReleaseContext(sentinel) == kErrNotInitialized);
Require(scePsmlMfsrReleaseSharedResources(sentinel) == kErrNotInitialized);
}
void SetupAfterInit() {
Require(scePsmlMfsrInit() == 0);
Require(scePsmlMfsrInit() == 0);
SharedParam sharedParam{};
Requirement shared{};
Require(scePsmlMfsrGetSharedResourcesInitRequirement(&shared, &sharedParam) == 0);
Require(shared.blockBytes == 0x200000 && shared.alignment == 0x200000 && shared.blockCount == 4);
const auto sharedBlocks = Blocks(shared, 0x10000000);
sharedParam.blocks = sharedBlocks.data();
sharedParam.blockCount = sharedBlocks.size();
void* sharedResources = nullptr;
Require(scePsmlMfsrCreateSharedResources(&sharedResources, &sharedParam) == 0);
Require(sharedResources != nullptr);
ContextParam contextParam;
contextParam.Set(nullptr, 0, sharedResources);
Requirement context{};
Require(scePsmlMfsrGetContextBufferRequirement800M3_2(&context, contextParam.bytes.data()) == 0);
Require(context.blockBytes == 0x200000 && context.alignment == 0x200000 && context.blockCount == 4);
const auto contextBlocks = Blocks(context, 0x20000000);
contextParam.Set(contextBlocks.data(), contextBlocks.size(), sharedResources);
void* mfsrContext = nullptr;
Require(scePsmlMfsrCreateContext800M3_2(&mfsrContext, contextParam.bytes.data()) == 0);
Require(mfsrContext != nullptr && mfsrContext != sharedResources);
Require(Throws([&] { scePsmlMfsrReleaseSharedResources(sharedResources); }, "still used by a context"));
Require(Throws([&] { scePsmlMfsrReleaseContext(sharedResources); }, "not created by this library"));
Require(scePsmlMfsrReleaseContext(mfsrContext) == 0);
Require(Throws([&] { scePsmlMfsrReleaseContext(mfsrContext); }, "not created by this library"));
Require(scePsmlMfsrReleaseSharedResources(sharedResources) == 0);
}
void RefusedAfterInit() {
SharedParam sharedParam{};
Requirement requirement{};
sharedParam.type = 1;
Require(Throws([&] { scePsmlMfsrGetSharedResourcesInitRequirement(&requirement, &sharedParam); }, "type 1 is not supported"));
sharedParam.type = 0;
Require(scePsmlMfsrGetSharedResourcesInitRequirement(&requirement, &sharedParam) == 0);
const auto blocks = Blocks(requirement, 0x10000000);
sharedParam.blocks = blocks.data();
sharedParam.blockCount = 3;
void* sharedResources = nullptr;
Require(Throws([&] { scePsmlMfsrCreateSharedResources(&sharedResources, &sharedParam); }, "fewer memory blocks"));
auto small = blocks;
small[2].bytes = 0x100000;
sharedParam.blocks = small.data();
sharedParam.blockCount = small.size();
Require(Throws([&] { scePsmlMfsrCreateSharedResources(&sharedResources, &sharedParam); }, "smaller or less aligned"));
Require(sharedResources == nullptr);
std::uint64_t foreign = 0;
ContextParam contextParam;
contextParam.Set(blocks.data(), blocks.size(), &foreign);
void* context = nullptr;
Require(Throws([&] { scePsmlMfsrCreateContext800M3_2(&context, contextParam.bytes.data()); }, "shared resources handle was not created"));
Require(context == nullptr);
std::array<std::uint8_t, 0x158> param{};
std::array<std::uint32_t, 64> dwords{};
CommandBuffer commandBuffer{dwords.data(), static_cast<std::uint32_t>(dwords.size())};
Require(Throws([&] { scePsmlMfsrGetContextBufferRequirement1100(&requirement, param.data()); }, "not implemented"));
Require(Throws([&] { scePsmlMfsrCreateContext1300(&context, param.data()); }, "not implemented"));
Require(Throws([&] { scePsmlMfsrGetDispatchMfsrPacket900(&foreign, &commandBuffer, param.data()); }, "not implemented"));
Require(Throws([&] { scePsmlMfsrGetDispatchMfsrPacket1000(&foreign, &commandBuffer, param.data()); }, "not implemented"));
Require(Throws([&] { scePsmlMfsrGetDispatchMfsrPacket1300(&foreign, &commandBuffer, param.data()); }, "not implemented"));
}
}
int main() {
@@ -50,4 +222,20 @@ int main() {
Require(scePsmlMfsrGetDispatchMfsrPacket1100(nullptr, &commandBuffer, param.data()) == kErrNotInitialized);
Require(commandBuffer.cursor == dwords.data());
Require(dwords == untouchedDwords);
std::array<std::uint8_t, 0x18> olderRequirement;
olderRequirement.fill(0xa5);
const auto untouchedOlderRequirement = olderRequirement;
Require(scePsmlMfsrGetContextBufferRequirement800M3_2(olderRequirement.data(), param.data()) == kErrNotInitialized);
Require(olderRequirement == untouchedOlderRequirement);
Require(scePsmlMfsrGetContextBufferRequirement800M3_2(nullptr, nullptr) == kErrNotInitialized);
CreateContextUntouched(scePsmlMfsrCreateContext800M3_2);
CreateContextUntouched(scePsmlMfsrCreateContext1300);
DispatchPacketUntouched(scePsmlMfsrGetDispatchMfsrPacket900);
DispatchPacketUntouched(scePsmlMfsrGetDispatchMfsrPacket1000);
DispatchPacketUntouched(scePsmlMfsrGetDispatchMfsrPacket1300);
SetupBeforeInit();
SetupAfterInit();
RefusedAfterInit();
}
+8 -3
View File
@@ -2,8 +2,13 @@
### Unknown function info
- [scePsmlMfsrGetSharedResourcesInitRequirement, scePsmlMfsrCreateSharedResources, scePsmlMfsrReleaseSharedResources, scePsmlMfsrGetContextBufferRequirement800M3_2, scePsmlMfsrCreateContext800M3_2, scePsmlMfsrReleaseContext](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml) - signatures from the calls in PPSA08330 (0x5724b6-0x5727e8, 0xc8697) and PPSA03016 (0x43dcf4d-0x43dd69a): a `{block bytes, alignment, block count}` requirement, a 32-byte shared-resources parameter with the type at 0 and the `{address, bytes}` block list at 8 and 16, a context parameter with the block list at 8 and 16 and the shared-resources handle at 0x38, and 8-byte handles written through the first argument and passed back by value. The other context parameter fields (a 16-bit size pair at 0x18, two descriptor pointers at 0x20 and 0x28) are not read. The requirement of four 2 MiB blocks, 2 MiB aligned, is what PPSA08330 v06.006 allocates regardless of the returned count; Sony's values are unknown ([KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/9e41d8320a2774b303fbad344c2347e8d0292e83/src/libs/libPsml.cpp) derives 52 blocks for type 0). Only type 0 is accepted. The error codes for null pointers, short block lists and foreign handles are unknown, so those calls throw
- [scePsmlMfsr2CreateContext, scePsmlMfsr2CreateSharedResources, scePsmlMfsr2GetContextInitRequirement, scePsmlMfsr2GetDispatchPackets, scePsmlMfsr2GetDispatchPacketsSizeInDwords, scePsmlMfsr2GetSharedResourcesInitRequirement, scePsmlMfsr2Init, scePsmlMfsr2ReleaseContext, scePsmlMfsr2ReleaseSharedResources](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml_mfsr2) - unknown signatures, imported by PPSA23566; declared without parameters
- [scePsmlMfsrGetContextBufferRequirement1100, scePsmlMfsrCreateContext1100, scePsmlMfsrGetDispatchMfsrPacket1100](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml_debug) - argument layouts unknown; PPSA26344 imports but does not call the first two; at `0x87EFA` it passes `(rdi, rsi=&stack, rdx)` as three pointers to `GetDispatchMfsrPacket1100`. Only 0x8A810001 (not initialized) is returned
- [scePsmlMfsrGetContextBufferRequirement1100, scePsmlMfsrCreateContext1100, scePsmlMfsrGetDispatchMfsrPacket1100](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml_debug) - argument layouts unknown; PPSA26344 imports but does not call the first two and at `0x87EFA` passes `(rdi, rsi=&stack, rdx)` as three pointers to `GetDispatchMfsrPacket1100`; before `scePsmlMfsrInit` they return 0x8A810001 (not initialized) and after it they throw. `scePsmlMfsrCreateContext1300` and `scePsmlMfsrGetDispatchMfsrPacket900`, `1000` and `1300` take the same shapes (context slot and parameter; context, command buffer and parameter) and behave the same way. PPSA08330 and PPSA03016 pass `GetDispatchMfsrPacket900`/`1000` the context handle, a `{cursor, size in dwords}` command buffer and the dispatch parameters, and advance their cursor by the size `scePsmlMfsrGetDispatchMfsrPacketSizeInDwords` returned. Whether the 1100 and 1300 versions take these arguments, and the console's error, are unverified
- [scePsmlMfsrGetDispatchMfsrPacket1000](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml) - imported by PPSA25344. libScePsml and libScePsml_debug are built from the same source
- [scePsmlMfsrCreateContext1300, scePsmlMfsrGetDispatchMfsrPacket1300](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml) - imported by PPSA28416 next to `scePsmlMfsrGetContextBufferRequirement1100`. The names are not in the aerolib NID list; they hash to the imported NIDs `kLF7WtQ1-Dg` and `DDVUyPyYHTA` (`tools/nid_names.py`)
- [scePsmlMfsrEnableSpecularAA, scePsmlMfsrEnableQuality8K](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml_specularAA and libScePsml_quality8K) - imported by PPSA01317, which fails to load without them; signatures unknown, so they throw. The names are not in the aerolib NID list; they hash to the imported NIDs `xNZM9Y5lf-M` and `lcZD9tJraAw` (`tools/nid_names.py`)
- [scePsmlMfsrGetDispatchMfsrPacket1000](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml) - unknown signature, imported by PPSA25344; declared without parameters. libScePsml and libScePsml_debug are built from the same source
- [scePsmlMfsrCreateContext1300, scePsmlMfsrGetDispatchMfsrPacket1300](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml) - unknown signatures, imported by PPSA28416 next to `scePsmlMfsrGetContextBufferRequirement1100`; declared without parameters. The names are not in the aerolib NID list; they hash to the imported NIDs `kLF7WtQ1-Dg` and `DDVUyPyYHTA` (`tools/nid_names.py`)
### Functional
- [scePsmlMfsrInit](../../../core/libs/prx/libScePsml_debug/Export.cpp) (libScePsml) - succeeds and only sets the initialized state; the shared resources and contexts are bookkeeping objects that use none of the guest blocks. Whether Sony's library fails on hardware without PSSR is unknown. PPSA08330 calls the setup unconditionally and only uses a context when its cached `sceKernelIsTrinityMode` result is set (0x3c643d, 0x567f97; otherwise it stores a -0.25 mip bias itself at 0x567fe2), which AnyPS5 reports as 0, so the dispatch, mip bias and capture calls still throw