From 88ca2e86885f993852ae166b114a933eadbd924f Mon Sep 17 00:00:00 2001 From: souldbminersmwc Date: Mon, 27 Jul 2026 14:38:29 -0400 Subject: [PATCH] mariko 64lut cleanup --- .../loader/source/ldr_process_creation.cpp | 6 - .../stratosphere/loader/source/oc/pcv/pcv.hpp | 4 - .../loader/source/oc/pcv/pcv_common.hpp | 6 - .../loader/source/oc/pcv/pcv_hook.hpp | 4 + .../loader/source/oc/pcv/pcv_mariko.cpp | 131 ++++++++++-------- .../loader/source/oc/pcv/pcv_mariko.hpp | 15 +- 6 files changed, 83 insertions(+), 83 deletions(-) diff --git a/Source/Atmosphere/stratosphere/loader/source/ldr_process_creation.cpp b/Source/Atmosphere/stratosphere/loader/source/ldr_process_creation.cpp index 0baf0b56..de998557 100644 --- a/Source/Atmosphere/stratosphere/loader/source/ldr_process_creation.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/ldr_process_creation.cpp @@ -813,12 +813,6 @@ namespace ams::ldr { } Result CreateProcessAndLoadAutoLoadModules(ProcessInfo *out, const Meta *meta, const AutoLoadModuleContext &ctx, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit) { - /* Append extra .bss for 64LUT */ - /* TODO: REMOVE THIS. */ - if (g_is_pcv && ctx.main_nso_idx >= 0) { - g_nso_headers[ctx.main_nso_idx].bss_size += static_cast(hoc::pcv::HocPcvScratchSize); - } - /* Get CreateProcessParameter. */ svc::CreateProcessParameter param; R_TRY(GetCreateProcessParameter(std::addressof(param), meta, flags, resource_limit)); diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp index 74e540eb..2f68e285 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.hpp @@ -202,10 +202,6 @@ namespace ams::ldr::hoc::pcv { Result MemFreqPllmLimit(u32 *ptr); Result MemVoltHandler(u32 *ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2 - /* Extra pcv .bss */ - constexpr size_t HocPcvScratchSize = 0x2000; - constexpr size_t HocBusFreqBufOffset = 0x1000; /* start of the SOC bus region */ - void SafetyCheck(); void Patch(uintptr_t mapped_nso, size_t nso_size, uintptr_t cave, size_t cave_size, uintptr_t nso_address, uintptr_t data_arena); diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp index 1d3b9232..76412776 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_common.hpp @@ -180,12 +180,6 @@ namespace ams::ldr::hoc::pcv { // The pcv SoC-voltage DVB table is a fixed 32-entry region. (it doesn't need to be larger) constexpr size_t DvbTableCapacity = 32; - // extra .bss location, 0 until Patch() runs. - inline uintptr_t g_pcv_scratch = 0; - - inline uintptr_t g_pcv_cave = 0; - inline size_t g_pcv_cave_size = 0; - template size_t GetDvfsTableEntryCount(T *table_head) { using NT = std::remove_const_t>; diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_hook.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_hook.hpp index 06acacda..1a59adbe 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_hook.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_hook.hpp @@ -145,6 +145,10 @@ namespace ams::ldr::hoc::pcv { uintptr_t CaveVa() const { return ToVa(reinterpret_cast(m_cave)); } + uintptr_t CaveBase() const { return m_cave; } + + u32 *Reserve(size_t words) { return this->AllocCode(words); } + Result CopyPayload() { R_TRY(this->CheckEnabled()); diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp index 111e8a55..e9285fd7 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.cpp @@ -617,23 +617,24 @@ namespace ams::ldr::hoc::pcv::mariko { } } + /* hook payload data + buffers */ + struct HookPayloadData { + struct { + u64 orig; + u32 *buf[2]; /* VAs of the bus freq buffers */ + u32 counter; + } busFreqReloc; + }; + DEFINE_HOOK_PAYLOAD_PTR(HookPayloadData, m_HookPayloadData); + + /* The new replacement buffer */ + struct BusFreqBuf { u32 e[256]; }; + namespace { std::vector newEmcList; u32 *nsoStart; size_t g_nso_size = 0; - uintptr_t g_cave_cursor = 0; - } - - static uintptr_t CaveReserve(size_t count) { - if (g_pcv_cave == 0 || g_cave_cursor == 0) { - return 0; - } - if (g_cave_cursor + count * sizeof(u32) > g_pcv_cave + g_pcv_cave_size) { - return 0; - } - const uintptr_t entry = g_cave_cursor; - g_cave_cursor += count * sizeof(u32); - return entry; + u32 *g_busInitSite = nullptr; /* VccSharedBusInit entry, cached by BusFreqReloc */ } #if HOC_UART_LOG @@ -641,7 +642,7 @@ namespace ams::ldr::hoc::pcv::mariko { Result NvLogUartRedirect(u32 *ptr) { const uintptr_t mapped_nso = reinterpret_cast(nsoStart); const size_t nso_size = g_nso_size; - const uintptr_t textEnd = g_pcv_cave; /* .text ends where the cave begins */ + const uintptr_t textEnd = Hooks().CaveBase(); /* .text ends where the cave begins */ const uintptr_t vsnprintf_addr = reinterpret_cast(ptr); /* NvLog via the VDD_SOC log */ @@ -685,10 +686,10 @@ namespace ams::ldr::hoc::pcv::mariko { R_THROW(ldr::ResultInvalidNvLogRedirect()); } - const uintptr_t helper = CaveReserve(40); + const uintptr_t helper = reinterpret_cast(Hooks().Reserve(40)); if (helper == 0) { - LOGGING("NvLogRedirect: cave unavailable (cave=%lx size=%lx)", - static_cast(g_pcv_cave), static_cast(g_pcv_cave_size)); + LOGGING("NvLogRedirect: cave unavailable (cave=%lx free=%lx)", + static_cast(Hooks().CaveBase()), static_cast(Hooks().CaveFree())); R_THROW(ldr::ResultInvalidNvLogRedirect()); } u32 *t = reinterpret_cast(helper); @@ -726,7 +727,7 @@ namespace ams::ldr::hoc::pcv::mariko { emit(RetIns); /* Redirect the call sites as patching the actual function causes crash */ - const uintptr_t roStart = g_pcv_cave + g_pcv_cave_size; /* module .rodata start */ + const uintptr_t roStart = Hooks().CaveBase() + Hooks().CaveSize(); /* module .rodata start */ size_t patchedSites = 0; if (HOC_PCV_NVLOG_PATCH) { for (u32 *p = nsoStart; reinterpret_cast(p + 1) <= textEnd; ++p) { @@ -759,47 +760,55 @@ namespace ams::ldr::hoc::pcv::mariko { } #endif - /* Relocate C2/C3Bus to avoid issues*/ + /* Relocate C3bus/C2bus freq buffers */ Result BusFreqReloc(u32 *ptr) { - const u32 busReg = AsmGetRn(ptr[0]); /* ldr Xbuf,[Xbus,#0x10] : bus struct pointer */ - const u32 bufReg = asm_get_rd(ptr[0]); /* : freq-buffer arg */ - const u32 bufOff = AsmGetLdStImm64Off(ptr[0]); /* : bus->freqBuf offset */ - const u32 cntReg = asm_get_rd(ptr[1]); /* add Xcnt,Xbus,#0x18 : arg2 (&count) */ - const u32 railReg = asm_get_rd(ptr[2]); /* str Xrail,[Xbus,#0x50]: arg0 (rail) */ - u32 *call = ptr + 3; /* the bl to relocate */ - const uintptr_t realFn = AsmBranchTarget(*call, reinterpret_cast(call)); - - /* Pick 3 scratch registers */ - u32 s[3], sc = 0; - for (u32 r = 9; r <= 15 && sc < 3; ++r) { - if (r != busReg && r != bufReg && r != cntReg && r != railReg) { - s[sc++] = r; + /* Entry shape: sub sp,sp,#imm ; stp x29,x30,[sp,#0x10]. */ + for (u32 i = 1; i <= 48; ++i) { + u32 *p = ptr - i; + if (p - 1 < nsoStart) { + break; + } + if (p[0] == 0xA9017BFDu /* stp x29,x30,[sp,#0x10] */ + && (p[-1] & 0xFFC003FFu) == 0xD10003FFu) { /* sub sp,sp,#imm12 */ + g_busInitSite = p - 1; + R_SUCCEED(); } } - R_UNLESS(sc == 3, ldr::ResultInvalidBusFreqReloc()); + R_THROW(ldr::ResultInvalidBusFreqReloc()); + } - const uintptr_t tramp = CaveReserve(9); - R_UNLESS(tramp != 0, ldr::ResultInvalidBusFreqReloc()); + /* Replace VCCBusInit entry with new buffer. */ + HOOK_PAYLOAD_FN u64 VccSharedBusInitHook(u64 *bus) { + HookPayloadData *data = HOOK_PAYLOAD_PTR(HookPayloadData, m_HookPayloadData); + const u32 idx = data->busFreqReloc.counter; + if (idx < 2) { + data->busFreqReloc.counter = idx + 1; + bus[2] = reinterpret_cast(data->busFreqReloc.buf[idx]); /* bus[0x10] = big buffer */ + } + using OrigFn = u64 (*)(u64 *); + u64 result = reinterpret_cast(data->busFreqReloc.orig)(bus); + __asm__ __volatile__("" : "+r"(result)); + return result; + } - const uintptr_t region = g_pcv_scratch + HocBusFreqBufOffset; /* [0]=counter, +0x10 + i*0x400 = bufs */ - u32 *t = reinterpret_cast(tramp); - size_t n = 0; - auto emit = [&](u32 ins) { t[n] = ins; ++n; }; - emit(AsmMakeAdrp(tramp + n * 4, region, s[0])); /* adrp s0, */ - emit(AsmMakeAddImm64(s[0], s[0], region & 0xFFFu)); /* add s0,s0,#lo */ - emit(AsmMakeLdrImm32(s[1], s[0], 0x00)); /* s1 = counter */ - emit(AsmMakeAddImm64(s[2], s[1], 1)); /* s2 = counter+1 */ - emit(AsmMakeStrImm32(s[2], s[0], 0x00)); /* counter++ */ - emit(AsmMakeAddImm64(s[0], s[0], 0x10)); /* s0 = region+0x10 (buffers) */ - emit(AsmMakeAddShiftedReg64(bufReg, s[0], s[1], 10)); /* Xbuf = s0 + counter*0x400 */ - emit(AsmMakeStrImm64(bufReg, busReg, bufOff)); /* bus[freqBuf] = Xbuf */ - emit(AsmMakeB(tramp + n * 4, realFn)); /* tail-call the real function */ + Result InstallHooks() { + R_TRY(Hooks().CheckEnabled()); /* CopyPayload already done at the top of Patch() */ + + auto *data = Hooks().BindData(m_HookPayloadData); + R_UNLESS(data != nullptr, ldr::ResultHookDataOutOfMemory()); + + R_UNLESS(g_busInitSite != nullptr, ldr::ResultInvalidBusFreqReloc()); + for (u32 i = 0; i < 2; ++i) { + auto *buf = Hooks().DataAlloc(); + R_UNLESS(buf != nullptr, ldr::ResultHookDataOutOfMemory()); + data->busFreqReloc.buf[i] = reinterpret_cast(Hooks().ToVa(buf)); + } + data->busFreqReloc.counter = 0; + + uintptr_t orig = 0; + R_TRY(INSTALL_IMPL_HOOK_ORIG(g_busInitSite, VccSharedBusInitHook, std::addressof(orig))); + data->busFreqReloc.orig = orig; - PATCH_OFFSET(call, AsmMakeBl(reinterpret_cast(call), tramp)); - const uintptr_t base = reinterpret_cast(nsoStart); - (void) base; - LOGGING("BusFreqReloc: call@+%lx -> tramp@+%lx realfn@+%lx (bus=x%u buf=x%u off=0x%x scratch=x%u,x%u,x%u)", - reinterpret_cast(call) - base, tramp - base, realFn - base, busReg, bufReg, bufOff, s[0], s[1], s[2]); R_SUCCEED(); } @@ -1479,11 +1488,14 @@ namespace ams::ldr::hoc::pcv::mariko { } void Patch(uintptr_t mapped_nso, size_t nso_size) { - nsoStart = reinterpret_cast(mapped_nso); + nsoStart = reinterpret_cast(mapped_nso); + g_nso_size = nso_size; - g_pcv_scratch = mapped_nso + nso_size - HocPcvScratchSize; - g_nso_size = nso_size; - g_cave_cursor = g_pcv_cave; /* start the .text-cave bump allocator (0 if unavailable) */ + /* Copy the hook payload into the cave first, patchers can allocate code past it. */ + if (R_FAILED(Hooks().CopyPayload())) { + panic::SmcError(panic::Patch); + CRASH("CopyPayload"); + } MtcGenerateFreqTables(); @@ -1540,6 +1552,11 @@ namespace ams::ldr::hoc::pcv::mariko { CRASH(entry.description); } } + + if (R_FAILED(InstallHooks())) { + panic::SmcError(panic::Patch); + CRASH("InstallHooks"); + } } } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp index de72f004..ee7e18b1 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_mariko.hpp @@ -23,6 +23,7 @@ #include "../oc_common.hpp" #include "pcv_common.hpp" #include "pcv_asm.hpp" +#include "pcv_hook.hpp" namespace ams::ldr::hoc::pcv::mariko { @@ -372,12 +373,6 @@ namespace ams::ldr::hoc::pcv::mariko { } inline bool BusFreqRelocPatternFn(u32 *ptr) { - if (g_pcv_scratch == 0 || g_pcv_cave == 0) { - return false; - } - if (reinterpret_cast(ptr + 4) > g_pcv_cave) { /* the call site lives in .text */ - return false; - } if (!(AsmIsLdrImm64(ptr[0]) && AsmGetLdStImm64Off(ptr[0]) == 0x10)) return false; /* ldr Xbuf,[Xbus,#0x10] */ if (!(AsmIsAddImm64(ptr[1]) && AsmGetImm12(ptr[1]) == 0x18)) return false; /* add Xcnt,Xbus,#0x18 */ if (!(AsmIsStrImm64(ptr[2]) && AsmGetLdStImm64Off(ptr[2]) == 0x50)) return false; /* str Xrail,[Xbus,#0x50]*/ @@ -387,10 +382,10 @@ namespace ams::ldr::hoc::pcv::mariko { } inline bool ForceVerbosityPatternFn(u32 *ptr) { - if (HOC_PCV_FORCE_VERBOSITY == 0 || g_pcv_cave == 0) { + if (HOC_PCV_FORCE_VERBOSITY == 0 || Hooks().CaveBase() == 0) { return false; } - if (reinterpret_cast(ptr + 11) > g_pcv_cave) { /* .text only */ + if (reinterpret_cast(ptr + 11) > Hooks().CaveBase()) { /* .text only */ return false; } if (ptr[0] != 0xA9BE7BFDu || ptr[1] != 0xF9000BF3u || ptr[2] != 0x910003FDu) return false; /* stp/str/mov x29,sp */ @@ -409,10 +404,10 @@ namespace ams::ldr::hoc::pcv::mariko { inline constexpr u32 NvLogVsnSig[] = { 0xD10483FFu, 0xA9107BFDu, 0xF9008BFCu, 0x910403FDu, 0xF100003Fu }; inline bool NvLogVsnprintfPatternFn(u32 *ptr) { - if (HOC_UART_LOG == 0 || g_pcv_cave == 0) { + if (HOC_UART_LOG == 0 || Hooks().CaveBase() == 0) { return false; } - if (reinterpret_cast(ptr + std::size(NvLogVsnSig)) > g_pcv_cave) { /* must sit in .text */ + if (reinterpret_cast(ptr + std::size(NvLogVsnSig)) > Hooks().CaveBase()) { /* must sit in .text */ return false; } for (size_t k = 0; k < std::size(NvLogVsnSig); ++k) {