This commit is contained in:
Lightos1
2026-07-27 20:57:58 +02:00
7 changed files with 84 additions and 84 deletions

View File

@@ -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<u32>(hoc::pcv::HocPcvScratchSize);
}
/* Get CreateProcessParameter. */
svc::CreateProcessParameter param;
R_TRY(GetCreateProcessParameter(std::addressof(param), meta, flags, resource_limit));

View File

@@ -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);

View File

@@ -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<typename T>
size_t GetDvfsTableEntryCount(T *table_head) {
using NT = std::remove_const_t<std::remove_volatile_t<T>>;

View File

@@ -145,6 +145,10 @@ namespace ams::ldr::hoc::pcv {
uintptr_t CaveVa() const { return ToVa(reinterpret_cast<const void *>(m_cave)); }
uintptr_t CaveBase() const { return m_cave; }
u32 *Reserve(size_t words) { return this->AllocCode(words); }
Result CopyPayload() {
R_TRY(this->CheckEnabled());

View File

@@ -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<u32> 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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(Hooks().Reserve(40));
if (helper == 0) {
LOGGING("NvLogRedirect: cave unavailable (cave=%lx size=%lx)",
static_cast<unsigned long>(g_pcv_cave), static_cast<unsigned long>(g_pcv_cave_size));
LOGGING("NvLogRedirect: cave unavailable (cave=%lx free=%lx)",
static_cast<unsigned long>(Hooks().CaveBase()), static_cast<unsigned long>(Hooks().CaveFree()));
R_THROW(ldr::ResultInvalidNvLogRedirect());
}
u32 *t = reinterpret_cast<u32 *>(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<uintptr_t>(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<uintptr_t>(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<u64>(data->busFreqReloc.buf[idx]); /* bus[0x10] = big buffer */
}
using OrigFn = u64 (*)(u64 *);
u64 result = reinterpret_cast<OrigFn>(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<u32 *>(tramp);
size_t n = 0;
auto emit = [&](u32 ins) { t[n] = ins; ++n; };
emit(AsmMakeAdrp(tramp + n * 4, region, s[0])); /* adrp s0,<region> */
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<BusFreqBuf>();
R_UNLESS(buf != nullptr, ldr::ResultHookDataOutOfMemory());
data->busFreqReloc.buf[i] = reinterpret_cast<u32 *>(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<uintptr_t>(call), tramp));
const uintptr_t base = reinterpret_cast<uintptr_t>(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<uintptr_t>(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<u32 *>(mapped_nso);
nsoStart = reinterpret_cast<u32 *>(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");
}
}
}

View File

@@ -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<uintptr_t>(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<uintptr_t>(ptr + 11) > g_pcv_cave) { /* .text only */
if (reinterpret_cast<uintptr_t>(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<uintptr_t>(ptr + std::size(NvLogVsnSig)) > g_pcv_cave) { /* must sit in .text */
if (reinterpret_cast<uintptr_t>(ptr + std::size(NvLogVsnSig)) > Hooks().CaveBase()) { /* must sit in .text */
return false;
}
for (size_t k = 0; k < std::size(NvLogVsnSig); ++k) {

View File

@@ -229,7 +229,7 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
return {
"The step that RAM clocks take.",
"Options:",
" - 33MHz - 3 MHz step (ex. 1600, 1633, 1666, 1700, etc.)",
" - 33MHz - 33 MHz step (ex. 1600, 1633, 1666, 1700, etc.)",
" - 66MHz - 66 MHz step (ex. 1600, 1666, 1733, etc.)",
" - 100MHz - 100 MHz step (ex. 1600, 1700, 1800, etc.)",
" - 133MHz - 133 MHz step (ex. 1600, 1733, 1866, etc.)",