From 4bedd493764dc91e749094a62a4bb32b864c5186 Mon Sep 17 00:00:00 2001 From: wildcard Date: Mon, 11 May 2026 02:34:57 +0200 Subject: [PATCH] Fix Paper Mario TTYD crashes on Android This fixes the crash in Paper Mario TTYD on Android. The issue was a 32bit svc was being executed at module_start + 0x112F50 so we replace that svc we nop to fix the crash issue. --- src/core/loader/nso.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 482c853542..115df373ad 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -5,6 +5,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include #include @@ -44,6 +45,40 @@ static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size."); constexpr u32 PageAlignSize(u32 size) { return static_cast((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK); } + +constexpr u64 PaperMarioTTYDProgramId = 0x0100ECD018EBE000ULL; +constexpr u32 PaperMarioTTYDTrapOffset = 0x112F50; + +bool IsPaperMarioTTYD(u64 program_id) { + return (program_id & ~0xFFFULL) == PaperMarioTTYDProgramId; +} + +void ApplyPaperMarioTTYDWorkaround(const Kernel::KProcess& process, std::string_view module_name, + std::span image, size_t module_start) { + static constexpr std::array kTrapThenRet{ + 0xFE, 0xDE, 0xFF, 0xE7, 0xC0, 0x03, 0x5F, 0xD6, + }; + static constexpr std::array kNop{ + 0x1F, 0x20, 0x03, 0xD5, + }; + + if (!IsPaperMarioTTYD(process.GetProgramId()) || module_name != "sdk") { + return; + } + + const size_t trap_offset = module_start + PaperMarioTTYDTrapOffset; + if (trap_offset + kTrapThenRet.size() > image.size()) { + return; + } + + if (!std::equal(kTrapThenRet.begin(), kTrapThenRet.end(), image.begin() + trap_offset)) { + return; + } + + std::copy(kNop.begin(), kNop.end(), image.begin() + trap_offset); + LOG_WARNING(Loader, "Applied Paper Mario TTYD boot workaround for {:016X} at nnSdk+{:#x}", + process.GetProgramId(), PaperMarioTTYDTrapOffset); +} } // Anonymous namespace bool NSOHeader::IsSegmentCompressed(size_t segment_num) const { @@ -149,6 +184,8 @@ std::optional AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), patchable_section.data()); } + ApplyPaperMarioTTYDWorkaround(process, name, codeset.memory, module_start); + #ifdef HAS_NCE // If we are computing the process code layout and using nce backend, patch. const auto& code = codeset.CodeSegment();