From 72e3b0dd34491879bb55677e9ca78f13b2b8be63 Mon Sep 17 00:00:00 2001 From: Alula Date: Fri, 3 Apr 2026 20:36:36 +0200 Subject: [PATCH 1/3] erpt: Fix rare aborts caused by ResultInvalidPowerState --- .../source/erpt/srv/erpt_srv_reporter.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp index a1314cc77..d24736272 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp @@ -423,7 +423,17 @@ namespace ams::erpt::srv { auto report = std::make_unique(record.get(), redirect_new_reports); R_UNLESS(report != nullptr, erpt::ResultOutOfMemory()); - auto report_guard = SCOPE_GUARD { const auto delete_res = report->Delete(); R_ASSERT(delete_res); AMS_UNUSED(delete_res); }; + auto report_guard = SCOPE_GUARD { + const auto delete_res = report->Delete(); + R_ASSERT(delete_res); + AMS_UNUSED(delete_res); + /* if (erpt::ResultInvalidPowerState::Includes(result)) { + * Nintendo ignores this and sends "power_state_violation" play report if this error happens. + * } else { + * Nintendo sends "write_failure" play report if any other error happens. + * } + */ + }; R_TRY(Context::WriteContextsToReport(report.get())); R_TRY(report->GetSize(std::addressof(record->m_info.report_size))); @@ -434,7 +444,7 @@ namespace ams::erpt::srv { } else { /* If we are redirecting new reports, we don't want to store the report in the journal. */ /* We should take this opportunity to delete any attachments associated with the report. */ - R_ABORT_UNLESS(JournalForAttachments::DeleteAttachments(report_id)); + R_TRY(JournalForAttachments::DeleteAttachments(report_id)); } R_TRY(Journal::Commit()); From 9a1ea02c8c2bb5e73687fb47c3718391d5ffe45b Mon Sep 17 00:00:00 2001 From: Alula Date: Sat, 4 Apr 2026 00:00:35 +0200 Subject: [PATCH 2/3] erpt: Add some missed 20.0.0+ FsInfo changes --- .../include/stratosphere/fs/fs_game_card.hpp | 6 +++-- .../source/erpt/srv/erpt_srv_fs_info.hpp | 1 + .../erpt/srv/erpt_srv_fs_info.os.horizon.cpp | 25 +++++++++++++++++++ .../source/erpt/srv/erpt_srv_reporter.cpp | 22 ++++++++++------ 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_game_card.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_game_card.hpp index ccfc0fc8f..44cc8bdd4 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_game_card.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_game_card.hpp @@ -52,7 +52,8 @@ namespace ams::fs { struct GameCardErrorReportInfo { u16 game_card_crc_error_num; - u16 reserved1; + u8 last_deactivate_reason; + u8 reserved1; u16 asic_crc_error_num; u16 reserved2; u16 refresh_num; @@ -73,7 +74,8 @@ namespace ams::fs { u32 awaken_count; u32 read_count_from_insert; u32 read_count_from_awaken; - u8 reserved5[8]; + u32 last_deactivate_reason_result; + u32 reserved5; }; static_assert(util::is_pod::value); static_assert(sizeof(GameCardErrorReportInfo) == 0x40); diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.hpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.hpp index 5d9d7ad17..b032a6ca1 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.hpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.hpp @@ -19,5 +19,6 @@ namespace ams::erpt::srv { Result SubmitFsInfo(); + void ClearFsInfo(); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.os.horizon.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.os.horizon.cpp index 1b7840783..dda71d939 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.os.horizon.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.os.horizon.cpp @@ -363,6 +363,8 @@ namespace ams::erpt::srv { R_ABORT_UNLESS(record->Add(FieldId_GameCardReadCountFromAwaken, ei.read_count_from_awaken)); R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageAddress, ei.last_read_error_page_address)); R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageCount, ei.last_read_error_page_count)); + R_ABORT_UNLESS(record->Add(FieldId_GameCardLastDeactivateReasonResult, ei.last_deactivate_reason_result)); + R_ABORT_UNLESS(record->Add(FieldId_GameCardLastDeactivateReason, ei.last_deactivate_reason)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); @@ -496,4 +498,27 @@ namespace ams::erpt::srv { R_SUCCEED(); } + void ClearFsInfo() { + Context::ClearContext(CategoryId_NANDTypeInfo); + Context::ClearContext(CategoryId_NANDSpeedModeInfo); + Context::ClearContext(CategoryId_NANDExtendedCsd); + Context::ClearContext(CategoryId_NANDPatrolInfo); + Context::ClearContext(CategoryId_NANDErrorInfo); + Context::ClearContext(CategoryId_NANDDriverLog); + Context::ClearContext(CategoryId_MicroSDTypeInfo); + Context::ClearContext(CategoryId_MicroSDSpeedModeInfo); + Context::ClearContext(CategoryId_SdCardSizeSpec); + Context::ClearContext(CategoryId_SdCardActivationInfo); + Context::ClearContext(CategoryId_SdCardErrorInfo); + Context::ClearContext(CategoryId_SdCardDriverLog); + Context::ClearContext(CategoryId_GameCardCIDInfo); + Context::ClearContext(CategoryId_GameCardErrorInfo); + Context::ClearContext(CategoryId_GameCardDetailedErrorInfo); + Context::ClearContext(CategoryId_GameCardLogInfo); + Context::ClearContext(CategoryId_FsProxyErrorInfo); + Context::ClearContext(CategoryId_FsProxyErrorInfo2); + Context::ClearContext(CategoryId_FsProxyErrorInfo3); + Context::ClearContext(CategoryId_FsMemoryInfo); + } + } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp index d24736272..cb26409f1 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp @@ -426,13 +426,7 @@ namespace ams::erpt::srv { auto report_guard = SCOPE_GUARD { const auto delete_res = report->Delete(); R_ASSERT(delete_res); - AMS_UNUSED(delete_res); - /* if (erpt::ResultInvalidPowerState::Includes(result)) { - * Nintendo ignores this and sends "power_state_violation" play report if this error happens. - * } else { - * Nintendo sends "write_failure" play report if any other error happens. - * } - */ + AMS_UNUSED(delete_res); }; R_TRY(Context::WriteContextsToReport(report.get())); @@ -499,6 +493,20 @@ namespace ams::erpt::srv { static_cast(Context::ClearContext(CategoryId_ErrorInfo)); static_cast(Context::ClearContext(CategoryId_ErrorInfoAuto)); static_cast(Context::ClearContext(CategoryId_ErrorInfoDefaults)); + + #if defined(ATMOSPHERE_OS_HORIZON) + /* TODO: What else is missing? */ + if (hos::GetVersion() >= hos::Version_17_0_0 && flags.Test()) { + ClearFsInfo(); + } + + /* if (erpt::ResultInvalidPowerState::Includes(...)) { + * Nintendo ignores this and sends "power_state_violation" play report if this error happens. + * } else { + * Nintendo sends "write_failure" play report if any other error happens. + * } + */ + #endif }; /* Get the context entry pointer. */ From a051c3c723e797a1e2f7b3a30c5d7949c7bba410 Mon Sep 17 00:00:00 2001 From: Alula Date: Sat, 4 Apr 2026 00:04:45 +0200 Subject: [PATCH 3/3] erpt: document unknown 0x20000 flag --- .../libstratosphere/include/stratosphere/erpt/erpt_types.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/libstratosphere/include/stratosphere/erpt/erpt_types.hpp b/libraries/libstratosphere/include/stratosphere/erpt/erpt_types.hpp index 899de49db..c3b92f62e 100644 --- a/libraries/libstratosphere/include/stratosphere/erpt/erpt_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/erpt/erpt_types.hpp @@ -111,6 +111,7 @@ namespace ams::erpt { struct CreateReportOptionFlag { using SubmitFsInfo = util::BitFlagSet::Flag<0>; + using Unknown0x20000 = util::BitFlagSet::Flag<17>; /* TODO: What is this, it's checked in Reporter::CreateReport or below */ }; using CreateReportOptionFlagSet = util::BitFlagSet;