From 8403386f1a0080c57c85b483281adafd3337c821 Mon Sep 17 00:00:00 2001 From: souldbminersmwc Date: Wed, 7 Oct 2026 19:43:05 -0400 Subject: [PATCH] 64lut --- .../loader/source/oc/oc_common.hpp | 67 +++++----- .../source/oc/pcv/mariko/pcv_mariko.cpp | 6 + .../source/oc/pcv/mariko/pcv_mariko.hpp | 4 + .../source/oc/pcv/mariko/pcv_mariko_cpu.cpp | 122 ++++++++++++++++++ .../source/oc/pcv/mariko/pcv_mariko_cpu.hpp | 33 ++++- .../source/oc/pcv/mariko/pcv_mariko_log.cpp | 2 + .../stratosphere/loader/source/oc/pcv/pcv.cpp | 31 +++-- .../loader/source/oc/pcv/pcv_asm.hpp | 26 ++++ Source/hoc-clk/sysmodule/src/board/board.cpp | 4 +- .../sysmodule/src/board/board_freq.cpp | 1 - .../sysmodule/src/board/board_volt.cpp | 13 +- .../sysmodule/src/board/board_volt.hpp | 6 +- Source/hoc-clk/sysmodule/src/file/kip.cpp | 29 +++-- Source/hoc-clk/sysmodule/src/file/kip.hpp | 1 + 14 files changed, 277 insertions(+), 68 deletions(-) diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp index cb360cdb..9c51fff8 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/oc_common.hpp @@ -60,39 +60,42 @@ *(offset) = value; namespace ams::ldr { - R_DEFINE_ERROR_RESULT(OutOfRange, 1000); - R_DEFINE_ERROR_RESULT(InvalidMemPllmEntry, 1001); - R_DEFINE_ERROR_RESULT(InvalidMtcMagic, 1002); - R_DEFINE_ERROR_RESULT(InvalidMtcTable, 1003); - R_DEFINE_ERROR_RESULT(InvalidDvbTable, 1004); - R_DEFINE_ERROR_RESULT(InvalidCpuFreqVddEntry, 1005); - R_DEFINE_ERROR_RESULT(InvalidCpuVoltDfllEntry, 1006); - R_DEFINE_ERROR_RESULT(InvalidCpuDvfs, 1007); - R_DEFINE_ERROR_RESULT(InvalidCpuMinVolt, 1008); - R_DEFINE_ERROR_RESULT(InvalidGpuDvfs, 1009); - R_DEFINE_ERROR_RESULT(InvalidGpuFreqMaxPattern, 1010); - R_DEFINE_ERROR_RESULT(InvalidGpuPllEntry, 1011); - R_DEFINE_ERROR_RESULT(InvalidRegulatorEntry, 1012); - R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1013); - R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1014); - R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1015); - R_DEFINE_ERROR_RESULT(InvalidMtcTablePattern, 1016); - R_DEFINE_ERROR_RESULT(InvalidSocVoltPattern, 1017); - R_DEFINE_ERROR_RESULT(InvalidSocVoltLimit, 1018); - R_DEFINE_ERROR_RESULT(InvalidEmcDvfsCount, 1019); - R_DEFINE_ERROR_RESULT(InvalidEmcSocLut, 1020); - R_DEFINE_ERROR_RESULT(InvalidEmcRateList, 1021); - R_DEFINE_ERROR_RESULT(InvalidNvLogRedirect, 1022); - R_DEFINE_ERROR_RESULT(InvalidBusFreqReloc, 1023); - R_DEFINE_ERROR_RESULT(HookArenaOutOfMemory, 1024); - R_DEFINE_ERROR_RESULT(HookPayloadTooLarge, 1025); - R_DEFINE_ERROR_RESULT(HookRelocationUnsupported, 1026); - R_DEFINE_ERROR_RESULT(HookSiteInvalid, 1027); - R_DEFINE_ERROR_RESULT(HookPayloadEscapes, 1028); - R_DEFINE_ERROR_RESULT(HookDataOutOfMemory, 1029); - R_DEFINE_ERROR_RESULT(HookUnavailable, 1030); - R_DEFINE_ERROR_RESULT(InvalidNvsrvDevTable, 1031); + R_DEFINE_ERROR_RESULT(OutOfRange, 1000); + R_DEFINE_ERROR_RESULT(InvalidMemPllmEntry, 1001); + R_DEFINE_ERROR_RESULT(InvalidMtcMagic, 1002); + R_DEFINE_ERROR_RESULT(InvalidMtcTable, 1003); + R_DEFINE_ERROR_RESULT(InvalidDvbTable, 1004); + R_DEFINE_ERROR_RESULT(InvalidCpuFreqVddEntry, 1005); + R_DEFINE_ERROR_RESULT(InvalidCpuVoltDfllEntry, 1006); + R_DEFINE_ERROR_RESULT(InvalidCpuDvfs, 1007); + R_DEFINE_ERROR_RESULT(InvalidCpuMinVolt, 1008); + R_DEFINE_ERROR_RESULT(InvalidGpuDvfs, 1009); + R_DEFINE_ERROR_RESULT(InvalidGpuFreqMaxPattern, 1010); + R_DEFINE_ERROR_RESULT(InvalidGpuPllEntry, 1011); + R_DEFINE_ERROR_RESULT(InvalidRegulatorEntry, 1012); + R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1013); + R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1014); + R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1015); + R_DEFINE_ERROR_RESULT(InvalidMtcTablePattern, 1016); + R_DEFINE_ERROR_RESULT(InvalidSocVoltPattern, 1017); + R_DEFINE_ERROR_RESULT(InvalidSocVoltLimit, 1018); + R_DEFINE_ERROR_RESULT(InvalidEmcDvfsCount, 1019); + R_DEFINE_ERROR_RESULT(InvalidEmcSocLut, 1020); + R_DEFINE_ERROR_RESULT(InvalidEmcRateList, 1021); + R_DEFINE_ERROR_RESULT(InvalidNvLogRedirect, 1022); + R_DEFINE_ERROR_RESULT(InvalidBusFreqReloc, 1023); + R_DEFINE_ERROR_RESULT(HookArenaOutOfMemory, 1024); + R_DEFINE_ERROR_RESULT(HookPayloadTooLarge, 1025); + R_DEFINE_ERROR_RESULT(HookRelocationUnsupported, 1026); + R_DEFINE_ERROR_RESULT(HookSiteInvalid, 1027); + R_DEFINE_ERROR_RESULT(HookPayloadEscapes, 1028); + R_DEFINE_ERROR_RESULT(HookDataOutOfMemory, 1029); + R_DEFINE_ERROR_RESULT(HookUnavailable, 1030); + R_DEFINE_ERROR_RESULT(InvalidNvsrvDevTable, 1031); R_DEFINE_ERROR_RESULT(InvalidForceVerbosityPattern, 1032); + R_DEFINE_ERROR_RESULT(InvalidCpuLutMaxAsmPattern, 1033); + R_DEFINE_ERROR_RESULT(InvalidCpuLutHook, 1034); + } namespace ams::ldr::hoc { diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko.cpp index 4db531f9..75479c91 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko.cpp @@ -48,6 +48,8 @@ namespace ams::ldr::hoc::pcv::mariko { R_TRY(SharedClkBusInstallHooks(data)); + R_TRY(LutWriterInstallHooks(data)); + #if HOC_UART_LOG R_TRY(ForceVebosityInstallHooks(data)); #endif @@ -90,6 +92,10 @@ namespace ams::ldr::hoc::pcv::mariko { { "Bus Freq Reloc", &BusFreqReloc, 1, &BusFreqRelocPatternFn }, { "SOC Volt Asm", &SocVoltAsm, 1, &SocVoltPatternFn }, { "SOC Volt Limit", &SocVoltLimit, 1, nullptr, SocVoltLimitOfficial }, + { "CPU Lut Max Asm", &CpuLutMaxAsm, 1, &CpuLutAsmPatternFn }, + { "CPU Lut Max Asm2", &CpuLutMaxAsm2, 1, &CpuLutAsmPatternFn2 }, + { "CPU Lut Writer", &LutWriterFind, 1, &LutWriterPatternFn }, + /* Debugging patches */ #if HOC_UART_LOG { "NvLog Redirect", &NvLogUartRedirect, 1, &NvLogVsnprintfPatternFn, 0, 0, true }, diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko.hpp index 0bc99c18..fc41c7b2 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/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 { @@ -34,6 +35,9 @@ namespace ams::ldr::hoc::pcv::mariko { uintptr_t originalFnCallback; u32 table[BusFreqTableCount][EmcDvfsTableEntryCount]; /* Original bus table size: 32. */ } busData; + struct { + uintptr_t orig; /* ClDvfsLut64ExpandImpl to CLDVFS LUT writer trampoline. */ + } lut64; #if HOC_UART_LOG u32 verbosityLevel; #endif diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_cpu.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_cpu.cpp index 64e48b70..68665a5e 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_cpu.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_cpu.cpp @@ -235,4 +235,126 @@ namespace ams::ldr::hoc::pcv::mariko { R_SUCCEED(); } + /* Little helper for ORR:LSL pairs which are found in here */ + inline bool IsOrrLsl(u32 w) { + if (!_asm::IsOp(w, _asm::op::OrrShifted32, _asm::field::Rd, _asm::field::Rn, _asm::field::Rm, _asm::field::Shift, _asm::field::Imm6)) + return false; + return _asm::Get(w, _asm::field::Shift) == 0; /* 0=LSL, 1=LSR, 2=ASR, 3=ROR */ + } + + /* Probably overcomplicated but I wanted to have a rock-solid way to do this regardless of FW version */ + Result CpuLutMaxAsm(u32* ptr) { + /* Check for the dual ORR-LSL pairs*/ + R_UNLESS(IsOrrLsl(ptr[2]), ldr::ResultInvalidCpuLutMaxAsmPattern()); + R_UNLESS(IsOrrLsl(ptr[3]), ldr::ResultInvalidCpuLutMaxAsmPattern()); + /* We can safely assume that we are in the right place now */ + + /* Safety check */ + R_UNLESS(ptr - 10 >= nsoStart, ldr::ResultInvalidCpuLutMaxAsmPattern()); + + /* Search for the STRB */ + u32* strb = _asm::ScanAssembly(ptr - 10, 10, _asm::Encode(_asm::op::StrbImm, + {_asm::field::Rt, 0}, {_asm::field::Rn, 0}, {_asm::field::Off1, 0x25D}), _asm::field::Rt, + _asm::field::Rn); + R_UNLESS(strb != nullptr, ldr::ResultInvalidCpuLutMaxAsmPattern()); + + /* Probably a cleaner way to do this?*/ + u32 *prod = strb + 2; + const u32 rd = _asm::Get(*prod, _asm::field::Rd); + const u32 off = static_cast(prod - nsoStart) * 4; + const u32 old = *prod; + if (_asm::IsOp(*prod, _asm::op::Ubfm32, _asm::field::Rd, _asm::field::Rn, _asm::field::Immr, _asm::field::Imm6)) { + /* replacement must carry LSL#16 to make up for ubfiz's remoal */ + const u32 nw = _asm::Encode(_asm::op::MovzW, {_asm::field::Rd, rd}, {_asm::field::Imm16, 0x3F}, {_asm::field::Hw, 1}); + PATCH_OFFSET(prod, nw); /* movz wD,#0x3F,LSL#16 */ + } else { + /* Imm12 is 7 for 0xff*/ + R_UNLESS(_asm::IsOp(*prod, _asm::op::AndImm32, _asm::field::Rd, _asm::field::Rn, _asm::field::Imm12) && _asm::Get(*prod, _asm::field::Imm12) == 7, ldr::ResultInvalidCpuLutMaxAsmPattern()); + /* No need to do the lsl */ + const u32 nw = _asm::Encode(_asm::op::MovzW, {_asm::field::Rd, rd}, {_asm::field::Imm16, 0x3F}); + PATCH_OFFSET(prod, nw); /* movz wD,#0x3F */ + } + + /* Set SAFE to entry 32 */ + PATCH_OFFSET(ptr + 1, _asm::Encode(_asm::op::MovzW, {_asm::field::Rd, _asm::Get(ptr[1], _asm::field::Rd)}, {_asm::field::Imm16, 0x20})); + + R_SUCCEED(); + } + + namespace { + struct { + u32 *site = nullptr; /* LUT writer prologue. */ + } lutWriterCache; + } + + HOOK_PAYLOAD_FN void CpuLutWriterExpandImpl(u64 param) { + HookPayloadData *data = HOOK_PAYLOAD_PTR(HookPayloadData, m_HookPayloadData); + reinterpret_cast(data->lut64.orig)(param); + + /* *(param+8) = CLDVFS mapping */ + const u64 base = *reinterpret_cast(param + 8); + u32 *lut = reinterpret_cast(base + 0x200); + + /* Expand the LUT in place */ + const u32 last = lut[31]; + lut[62] = last; + lut[63] = last; + + for (int i = 30; i >= 0; --i) { + const u32 a = lut[i]; + const u32 b = lut[i + 1]; /* dst 2*(i+1) > src i+1 */ + lut[2 * i] = a; + lut[2 * i + 1] = (a + b) >> 1; + } + __asm__ volatile("dsb st" ::: "memory"); + } + + Result LutWriterFind(u32 *ptr) { + R_UNLESS(LutWriterPatternFn(ptr), ldr::ResultInvalidCpuLutHook()); + + u32 *prog = _asm::FindFnPrologue(ptr, 140, nsoStart); + R_UNLESS(prog != nullptr, ldr::ResultInvalidCpuLutHook()); + + /* Prolouge must hold MMIO base, so obtain it. */ + bool ok = false; + for (u32 i = 0; i < 8; ++i) { + if (_asm::IsOp(prog[i], _asm::op::LdrImm64, _asm::field::Rt, _asm::field::Rn, _asm::field::Off8) + && _asm::Get(prog[i], _asm::field::Rn) == 0 + && _asm::Get(prog[i], _asm::field::Off8) == 0x8) { + ok = true; + break; + } + } + + R_UNLESS(ok, ldr::ResultInvalidCpuLutHook()); + lutWriterCache.site = prog; + + R_SUCCEED(); + } + + Result LutWriterInstallHooks(HookPayloadData *data) { + R_UNLESS(lutWriterCache.site != nullptr, ldr::ResultInvalidCpuLutHook()); + + uintptr_t orig = 0; + R_TRY(INSTALL_IMPL_HOOK_ORIG(lutWriterCache.site, CpuLutWriterExpandImpl, &orig)); + data->lut64.orig = orig; + + R_SUCCEED(); + } + + Result CpuLutMaxAsm2(u32* ptr) { + /* movk w?,#0xFFC0,LSL#16 */ + R_UNLESS(_asm::IsOp(ptr[1], _asm::op::MovkW, _asm::field::Rd, _asm::field::Imm16, _asm::field::Hw) + && _asm::Get(ptr[1], _asm::field::Imm16) == 0xFFC0 + && _asm::Get(ptr[1], _asm::field::Hw) == 1, ldr::ResultInvalidCpuLutMaxAsmPattern()); + + /* and x, x, #0xff */ + R_UNLESS(_asm::IsOp(ptr[2], _asm::op::AndImm32, _asm::field::Rd, _asm::field::Rn, _asm::field::Imm12) || + _asm::Get(ptr[2], _asm::field::Imm12) != 7, ldr::ResultInvalidCpuLutMaxAsmPattern()); + + const u32 rd = _asm::Get(ptr[2], _asm::field::Rd); + PATCH_OFFSET(ptr + 2, _asm::Encode(_asm::op::MovzW, {_asm::field::Rd, rd}, {_asm::field::Imm16, 0x3F})); /* movz wD,#0x3F */ + + R_SUCCEED(); + } } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_cpu.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_cpu.hpp index 0ab58912..a7b5bb4c 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_cpu.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_cpu.hpp @@ -23,9 +23,28 @@ #pragma once #include "../pcv.hpp" +#include "../pcv_asm.hpp" +#include "../pcv_hook.hpp" namespace ams::ldr::hoc::pcv::mariko { + extern u32 *nsoStart; + + /* Maybe a cleaner way to do this? */ + inline bool LutWriterPatternFn(u32 *ptr) { + if (_asm::IsOp(*ptr, _asm::op::AndImm64, _asm::field::Rd, _asm::field::Rn, _asm::field::Immr, _asm::field::Imm6) + && _asm::Get(*ptr, _asm::field::Immr) == 61 && _asm::Get(*ptr, _asm::field::Imm6) == 7) + return true; + if (_asm::IsOp(*ptr, _asm::op::AndImm32, _asm::field::Rd, _asm::field::Rn, _asm::field::Imm12) + && _asm::Get(*ptr, _asm::field::Imm12) == 0x747) + return true; + return false; + } + + HOOK_PAYLOAD_FN void CpuLutWriterExpandImpl(u64 param); + Result LutWriterFind(u32 *ptr); + Result LutWriterInstallHooks(HookPayloadData *data); + constexpr cvb_entry_t CpuCvbTableDefault[] = { { 204000, { 721589, -12695, 27 }, { } }, { 306000, { 747134, -14195, 27 }, { } }, @@ -63,10 +82,22 @@ namespace ams::ldr::hoc::pcv::mariko { /* Refer to customize.cpp for more information */ static const u32 allowedCpuMaxFrequencies[] = { 1'963'500, 2'091'000, 2'193'000, 2'295'000, 2'397'000, 2'499'000, 2'601'000, 2'703'000, 2'805'000 }; - Result CpuFreqVdd(u32 *ptr); Result CpuVoltDVFS(u32 *ptr); Result CpuVoltThermals(u32 *ptr); Result CpuVoltDfll(u32 *ptr); + Result CpuLutMaxAsm(u32* ptr); + Result CpuLutMaxAsm2(u32* ptr); + ALWAYS_INLINE bool CpuLutAsmPatternFn(u32* ptr) { + /* Check if it is a DSB ST, a common indication of CL-DVFS related functions */ + return *ptr == _asm::Dsb(_asm::barrier::St); + } + + ALWAYS_INLINE bool CpuLutAsmPatternFn2(u32* ptr) { + /* Note: We are doing multiple checks here as it is the cleanest method */ + return _asm::IsOp(*ptr, _asm::op::MovzW, _asm::field::Rd, _asm::field::Imm16, _asm::field::Hw) + && _asm::Get(*ptr, _asm::field::Imm16) == 0xC0FF + && _asm::Get(*ptr, _asm::field::Hw) == 0; + } } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_log.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_log.cpp index 5f24e677..0377aade 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_log.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/mariko/pcv_mariko_log.cpp @@ -231,6 +231,8 @@ namespace ams::ldr::hoc::pcv::mariko { R_DISCARD(INSTALL_IMPL_HOOK(forceVerbosityCache.sites[i], ForceVerbosityImpl)); } } + + R_SUCCEED(); } #endif diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp index bd35f3bd..42fd2423 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv.cpp @@ -82,6 +82,7 @@ namespace ams::ldr::hoc::pcv { u32 max; u32 panic; bool value_required = false; + const char *name = "unnamed"; Result Check() { if (!value_required && !value) { @@ -147,26 +148,28 @@ namespace ams::ldr::hoc::pcv { } Validator validators[] = { - { C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true }, - { C.marikoCpuBoostClock, 1020'000, 2805'000, panic::Cpu, true }, - { C.eristaCpuMaxVolt, 1000, 1260, panic::Cpu, }, - { C.marikoCpuMaxVolt, 1000, 1235, panic::Cpu, }, - { eristaCpuDvfsMaxFreq, 1785'000, 2397'000, panic::Cpu, }, - { marikoCpuDvfsMaxFreq, 1785'000, 2805'000, panic::Cpu, }, - { C.commonEmcMemVolt, 912'500, 1350'000, panic::Emc, }, /* Official vmax for the RAMs is 1400-1500mV */ - { C.eristaEmcMaxClock, 1600'000, 2600'000, panic::Emc, }, - { C.marikoEmcMaxClock, 1600'000, 3500'000, panic::Emc, }, - { C.marikoEmcVddqVolt, 400'000, 750'000, panic::Emc, }, - { C.marikoSocVmax, 1000, 1200, panic::Emc, }, - { eristaGpuDvfsMaxFreq, 768'000, 1152'000, panic::Gpu, }, - { marikoGpuDvfsMaxFreq, 768'000, 1574'400, panic::Gpu, }, - { C.marikoGpuVmax, 800, 995, panic::Gpu, }, /* Official GPU vMax is 1050mV */ + { C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true, "eristaCpuBoostClock" }, + { C.marikoCpuBoostClock, 1020'000, 2805'000, panic::Cpu, true, "marikoCpuBoostClock" }, + { C.eristaCpuMaxVolt, 1000, 1260, panic::Cpu, false, "eristaCpuMaxVolt" }, + { C.marikoCpuMaxVolt, 1000, 1235, panic::Cpu, false, "marikoCpuMaxVolt" }, + { eristaCpuDvfsMaxFreq, 1785'000, 2397'000, panic::Cpu, false, "eristaCpuDvfsMaxFreq"}, + { marikoCpuDvfsMaxFreq, 1785'000, 2805'000, panic::Cpu, false, "marikoCpuDvfsMaxFreq"}, + { C.commonEmcMemVolt, 912'500, 1350'000, panic::Emc, false, "commonEmcMemVolt" }, /* Official vmax for the RAMs is 1400-1500mV */ + { C.eristaEmcMaxClock, 1600'000, 2600'000, panic::Emc, false, "eristaEmcMaxClock" }, + { C.marikoEmcMaxClock, 1600'000, 3500'000, panic::Emc, false, "marikoEmcMaxClock" }, + { C.marikoEmcVddqVolt, 400'000, 750'000, panic::Emc, false, "marikoEmcVddqVolt" }, + { C.marikoSocVmax, 1000, 1200, panic::Emc, false, "marikoSocVmax" }, + { eristaGpuDvfsMaxFreq, 768'000, 1152'000, panic::Gpu, false, "eristaGpuDvfsMaxFreq"}, + { marikoGpuDvfsMaxFreq, 768'000, 1574'400, panic::Gpu, false, "marikoGpuDvfsMaxFreq"}, + { C.marikoGpuVmax, 800, 995, panic::Gpu, false, "marikoGpuVmax" }, /* Official GPU vMax is 1050mV */ }; for (auto &v : validators) { if (R_FAILED(v.Check())) { + LOGGING("Validation FAIL: %s value=%u min=%u max=%u", v.name, static_cast(v.value), v.min, v.max); panic::SmcError(v.panic); CRASH("Validation FAIL"); + } } } diff --git a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp index c5d030a8..86c5f044 100644 --- a/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp +++ b/Source/Atmosphere/stratosphere/loader/source/oc/pcv/pcv_asm.hpp @@ -66,6 +66,7 @@ namespace ams::ldr::hoc::pcv::_asm { constexpr Descriptor Sh {22, 1}; constexpr Descriptor Shift {22, 2}; /* ADD/SUB (shifted register) shift type */ constexpr Descriptor Imm6 {10, 6}; /* ADD/SUB (shifted register) shift amount */ + constexpr Descriptor Immr {16, 6}; /* UBFM immr */ constexpr Descriptor Imm16 { 5, 16}; /* MOVZ/MOVK/MOVN immediate */ constexpr Descriptor Imm12 {10, 12}; /* ADD/SUB (immediate) */ @@ -77,6 +78,8 @@ namespace ams::ldr::hoc::pcv::_asm { constexpr Descriptor Off1 {10, 12, 0}; /* LDRB/STRB */ constexpr Descriptor Off4 {10, 12, 2}; /* 32-bit LDR/STR */ + + constexpr Descriptor Barrier { 8, 4}; /* DSB/DMB option (CRm) */ constexpr Descriptor Off8 {10, 12, 3}; /* 64-bit LDR/STR */ constexpr Descriptor PairOff8 {15, 7, 3}; /* X pairs */ @@ -114,6 +117,9 @@ namespace ams::ldr::hoc::pcv::_asm { constexpr u32 MovnW = 0x12800000; constexpr u32 AddShifted64 = 0x8B000000; + constexpr u32 AndImm32 = 0x12000000; + constexpr u32 AndImm64 = 0x92400000; + constexpr u32 Ubfm32 = 0x53000000; /* UBFIZ/UBFX/LSL aliases */ constexpr u32 OrrShifted32 = 0x2A000000; constexpr u32 OrrShifted64 = 0xAA000000; constexpr u32 SubsShifted32 = 0x6B000000; @@ -140,6 +146,18 @@ namespace ams::ldr::hoc::pcv::_asm { constexpr u32 Adrp = 0x90000000; constexpr u32 Svc = 0xD4000001; + + constexpr u32 Dsb = 0xD503309F; /* DSB, option cleared */ + constexpr u32 Dmb = 0xD50330BF; /* DMB, option cleared */ + constexpr u32 Isb = 0xD5033FDF; /* ISB SY (only valid option) */ + } + + /* Barrier options (CRm). */ + namespace barrier { + constexpr u32 Sy = 0xFu, St = 0xEu, Ld = 0xDu; + constexpr u32 Ish = 0xBu, Ishst = 0xAu, Ishld = 0x9u; + constexpr u32 Nsh = 0x7u, Nshst = 0x6u, Nshld = 0x5u; + constexpr u32 Osh = 0x3u, Oshst = 0x2u, Oshld = 0x1u; } constexpr u32 Get(u32 ins, field::Descriptor f) { @@ -217,6 +235,14 @@ namespace ams::ldr::hoc::pcv::_asm { return Set(Set(ins, field::ImmAdrpHi, imm21 >> 2), field::ImmAdrpLo, imm21 & 0x3u); } + constexpr u32 Dsb(u32 opt) { + return Encode(op::Dsb, {field::Barrier, opt}); + } + + constexpr u32 Dmb(u32 opt) { + return Encode(op::Dmb, {field::Barrier, opt}); + } + constexpr u32 MovReg64(u32 rd, u32 rm) { return Encode(op::OrrShifted64, {field::Rd, rd}, {field::Rn, reg::Xzr}, {field::Rm, rm}); } diff --git a/Source/hoc-clk/sysmodule/src/board/board.cpp b/Source/hoc-clk/sysmodule/src/board/board.cpp index 0a71ed1c..de2a7ede 100644 --- a/Source/hoc-clk/sysmodule/src/board/board.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board.cpp @@ -53,6 +53,8 @@ #include "../i2c/max77620_wdt.hpp" #include "../mgr/clock_manager.hpp" #include "../file/config.hpp" +#include "../file/kip.hpp" + namespace board { u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr; @@ -271,7 +273,7 @@ namespace board { display::Initialize(&cfg); CacheDfllData(); - InitializeCpuLut(); + InitializeCpuLut(file::kip::IsKipLoaded()); CacheGpuVoltTable(); rc = pscmInitialize(); diff --git a/Source/hoc-clk/sysmodule/src/board/board_freq.cpp b/Source/hoc-clk/sysmodule/src/board/board_freq.cpp index 0e8944aa..5e714da8 100644 --- a/Source/hoc-clk/sysmodule/src/board/board_freq.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board_freq.cpp @@ -121,7 +121,6 @@ namespace board { svcSleepThread(300'000); ClkrstSetHz(session, pcvHz); } - clkrstCloseSession(&session); } else { PcvSetHz(GetPcvModule(module), pcvHz); diff --git a/Source/hoc-clk/sysmodule/src/board/board_volt.cpp b/Source/hoc-clk/sysmodule/src/board/board_volt.cpp index 0819e1ee..c0502b24 100644 --- a/Source/hoc-clk/sysmodule/src/board/board_volt.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board_volt.cpp @@ -611,13 +611,14 @@ namespace board { } namespace { - constexpr size_t LutSize = 33; + constexpr size_t MaxPotentialLutSize = 64; + size_t LutSize = 33; constexpr u32 PmicVmin = 250; constexpr u32 PmicStep = 5; struct { volatile u32 *lut = nullptr; - u32 table[LutSize] = {}; + u32 table[MaxPotentialLutSize] = {}; u32 lastVmin = 0; u32 outputCfg = 0; bool initialized = false; @@ -742,11 +743,13 @@ namespace board { } } - void InitializeCpuLut() { + void InitializeCpuLut(bool kip) { InitializeLutPtr(); CacheCpuLut(); cpuVoltData.outputCfg = *reinterpret_cast(cldvfs + CL_DVFS_OUTPUT_CFG_0); - + if(kip) { + LutSize = 63; /* Account for patched LUT by KIP */ + } cpuVoltData.initialized = true; } @@ -786,7 +789,6 @@ namespace board { return baseVolt; } - void ApplyCpuMinVolt(u32 vmin, bool force) { if(!force) { if (!cpuVoltData.initialized || (vmin == cpuVoltData.lastVmin)) { @@ -830,5 +832,4 @@ namespace board { cpuVoltData.lastVmin = vmin; } - } diff --git a/Source/hoc-clk/sysmodule/src/board/board_volt.hpp b/Source/hoc-clk/sysmodule/src/board/board_volt.hpp index 215afaf1..49fa4be8 100644 --- a/Source/hoc-clk/sysmodule/src/board/board_volt.hpp +++ b/Source/hoc-clk/sysmodule/src/board/board_volt.hpp @@ -59,8 +59,10 @@ namespace board { void PcvHijackGpuVolts(u32 vmin); void PcvHijackGpuFrequency(u32 voltage, u32 hz); u32 GetMinimumGpuVmin(u32 freqMhz, u32 bracket); - - void InitializeCpuLut(); + void ClDvfsSetOutputCfg(u8 safe, u8 max, u8 min); + void LogOutputCfg(const char *tag); + void SetSafeToMaxAndRelock(); + void InitializeCpuLut(bool kip); void ApplyCpuMinVolt(u32 vmin, bool force); u32 GetMinimumCpuVmin(u32 freqMhz, u32 bracket); diff --git a/Source/hoc-clk/sysmodule/src/file/kip.cpp b/Source/hoc-clk/sysmodule/src/file/kip.cpp index 17277af6..6ee37cb7 100644 --- a/Source/hoc-clk/sysmodule/src/file/kip.cpp +++ b/Source/hoc-clk/sysmodule/src/file/kip.cpp @@ -173,21 +173,28 @@ namespace file::kip { } bool IsKipLoaded() { - constexpr u32 ExpectedMagic = 0x686F634D; - constexpr uintptr_t LoadMagicAddress = 0x4003DC00; - u32 iramValue = {}; + static bool ran = false; + static bool loaded = false; + if(!ran) { + constexpr u32 ExpectedMagic = 0x686F634D; + constexpr uintptr_t LoadMagicAddress = 0x4003DC00; + u32 iramValue = {}; - SmcCopyFromIram(&iramValue, LoadMagicAddress, sizeof(iramValue)); + SmcCopyFromIram(&iramValue, LoadMagicAddress, sizeof(iramValue)); - if (iramValue == ExpectedMagic) { - iramValue = 0; - SmcCopyToIram(LoadMagicAddress, &iramValue, sizeof(iramValue)); - return true; + if (iramValue == ExpectedMagic) { + iramValue = 0; + SmcCopyToIram(LoadMagicAddress, &iramValue, sizeof(iramValue)); + loaded = true; + } else { + hos::WriteNotification("Kip is not loaded!"); + file::utils::LogLine("Kip was not loaded!"); + loaded = false; + } + ran = true; } - hos::WriteNotification("Kip is not loaded!"); - file::utils::LogLine("Kip was not loaded!"); - return false; + return loaded; } // I know this is very hacky, but the config system in the sysmodule doesn't really support writing diff --git a/Source/hoc-clk/sysmodule/src/file/kip.hpp b/Source/hoc-clk/sysmodule/src/file/kip.hpp index 9c692cfe..7c229ff9 100644 --- a/Source/hoc-clk/sysmodule/src/file/kip.hpp +++ b/Source/hoc-clk/sysmodule/src/file/kip.hpp @@ -825,4 +825,5 @@ namespace file::kip { void MigrateKipData(u32 custRev, u32 version); void SetKipData(); void GetKipData(); + bool IsKipLoaded(); } // namespace file::kip \ No newline at end of file