HOC 3.0.0 part 1
- version change to athena (3.0.0) - cust rev 7 - build script change - EMC 64LUT
This commit is contained in:
@@ -798,6 +798,11 @@ 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 */
|
||||
if (g_is_pcv && ctx.main_nso_idx >= 0) {
|
||||
g_nso_headers[ctx.main_nso_idx].bss_size += static_cast<u32>(hoc::HocPcvScratchSize);
|
||||
}
|
||||
|
||||
/* Get CreateProcessParameter. */
|
||||
svc::CreateProcessParameter param;
|
||||
R_TRY(GetCreateProcessParameter(std::addressof(param), meta, flags, resource_limit));
|
||||
|
||||
@@ -38,11 +38,11 @@ volatile CustomizeTable C = {
|
||||
.commonEmcMemVolt = 1175000, /* LPDDR4(X) JEDEC Specification */
|
||||
.eristaEmcMaxClock = 1600000, /* Maximum HB-MGCH ram rating */
|
||||
|
||||
/* Available: 66MHz step rate, 100MHz step rate, 133MHz step rate and jedec. */
|
||||
/* Available: 33MHz step rate, 66MHz step rate, 100MHz step rate, 133MHz step rate and jedec. */
|
||||
/* Jedec freqs are 1333MHz, 1600MHz, 1866MHz, 2133MHz, 2400MHz, 2666MHz, 2933MHz, 3200MHz. */
|
||||
.stepMode = StepMode_66MHz,
|
||||
.stepMode = StepMode_33MHz,
|
||||
|
||||
.marikoEmcMaxClock = 2133000, /* 1866MHz @ 1866tWRL is guaranteed to work on all Mariko units */
|
||||
.marikoEmcMaxClock = 2666000, /* Requires the EMC DVFS 63-entry patches (EMC DVFS Count / EMC SoC LUT). */
|
||||
.marikoEmcVddqVolt = 600000,
|
||||
|
||||
.emcDvbShift = 0,
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CUST_REV 6
|
||||
#define KIP_VERSION 250
|
||||
#define CUST_REV 7
|
||||
#define KIP_VERSION 300
|
||||
|
||||
#include "oc_common.hpp"
|
||||
#include "pcv/pcv_common.hpp"
|
||||
@@ -40,6 +40,7 @@ enum StepMode: u32 {
|
||||
StepMode_100MHz = 1,
|
||||
StepMode_Jedec = 2,
|
||||
StepMode_133MHz = 3,
|
||||
StepMode_33MHz = 4,
|
||||
};
|
||||
|
||||
enum ReadLatency: u32 {
|
||||
|
||||
@@ -50,9 +50,15 @@ namespace ams::ldr {
|
||||
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);
|
||||
}
|
||||
|
||||
namespace ams::ldr::hoc {
|
||||
/* Extra pcv .bss for 64LUT */
|
||||
constexpr size_t HocPcvScratchSize = 0x1000;
|
||||
|
||||
template<typename Pointer>
|
||||
struct PatcherEntry {
|
||||
using patternFn = bool(*)(Pointer *ptr);
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace ams::ldr::hoc::pcv {
|
||||
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
|
||||
|
||||
// Double the max clk simply
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
u32 max_clk = entry->freq * 2;
|
||||
entry->freq = max_clk;
|
||||
entry->vco_max = max_clk;
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -41,14 +41,14 @@ namespace ams::ldr::hoc::pcv {
|
||||
};
|
||||
|
||||
constexpr u32 uv_step = 12'500;
|
||||
constexpr u32 uv_min = 600'000;
|
||||
constexpr u32 uv_min = 600'000;
|
||||
|
||||
auto validator = [](regulator* entry) {
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
auto validator = [](regulator *entry) {
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.step_uv == uv_step, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.min_uv == uv_min, ldr::ResultInvalidRegulatorEntry());
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
if (emc_uv % uv_step) {
|
||||
emc_uv = emc_uv / uv_step * uv_step; // rounding
|
||||
emc_uv = emc_uv / uv_step * uv_step; // rounding
|
||||
}
|
||||
|
||||
PATCH_OFFSET(ptr, emc_uv);
|
||||
@@ -102,11 +102,11 @@ namespace ams::ldr::hoc::pcv {
|
||||
|
||||
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq);
|
||||
u32 marikoCpuDvfsMaxFreq;
|
||||
if (C.marikoCpuUVHigh) {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq);
|
||||
} else {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq);
|
||||
}
|
||||
if (C.marikoCpuUVHigh) {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq);
|
||||
} else {
|
||||
marikoCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq);
|
||||
}
|
||||
u32 eristaGpuDvfsMaxFreq;
|
||||
switch (C.eristaGpuUV) {
|
||||
case 0:
|
||||
@@ -146,20 +146,80 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
sValidator validators[] = {
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, panic::Cpu, true },
|
||||
{ C.eristaCpuMaxVolt, 1000, 1260, panic::Cpu, },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1200, panic::Cpu, },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 2397'000, panic::Cpu, },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'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, 1536'000, panic::Gpu, },
|
||||
{ C.marikoGpuVmax, 800, 960, panic::Gpu, },
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, panic::Cpu, true },
|
||||
{
|
||||
C.eristaCpuMaxVolt,
|
||||
1000,
|
||||
1260,
|
||||
panic::Cpu,
|
||||
},
|
||||
{
|
||||
C.marikoCpuMaxVolt,
|
||||
1000,
|
||||
1200,
|
||||
panic::Cpu,
|
||||
},
|
||||
{
|
||||
eristaCpuDvfsMaxFreq,
|
||||
1785'000,
|
||||
2397'000,
|
||||
panic::Cpu,
|
||||
},
|
||||
{
|
||||
marikoCpuDvfsMaxFreq,
|
||||
1785'000,
|
||||
2703'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,
|
||||
1536'000,
|
||||
panic::Gpu,
|
||||
},
|
||||
{
|
||||
C.marikoGpuVmax,
|
||||
800,
|
||||
960,
|
||||
panic::Gpu,
|
||||
},
|
||||
};
|
||||
|
||||
for (auto &v : validators) {
|
||||
@@ -171,7 +231,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
void WriteKipLoadToIram() {
|
||||
const u32 hocMagic = 0x686F634D;
|
||||
const u32 hocMagic = 0x686F634D;
|
||||
constexpr uintptr_t LoadMagicAddress = 0x4003DC00; /* Should be a pretty safe address. */
|
||||
R_DISCARD(SmcCopyToIram(LoadMagicAddress, &hocMagic, sizeof(hocMagic)));
|
||||
}
|
||||
@@ -189,4 +249,4 @@ namespace ams::ldr::hoc::pcv {
|
||||
WriteKipLoadToIram();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace ams::ldr::hoc::pcv
|
||||
|
||||
@@ -36,8 +36,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
return true;
|
||||
};
|
||||
|
||||
template <bool isMariko>
|
||||
Result CpuFreqCvbTable(u32 *ptr) {
|
||||
template <bool isMariko> Result CpuFreqCvbTable(u32 *ptr) {
|
||||
cvb_entry_t *default_table = isMariko ? (cvb_entry_t *)(&mariko::CpuCvbTableDefault) : (cvb_entry_t *)(&erista::CpuCvbTableDefault);
|
||||
cvb_entry_t *customize_table = nullptr;
|
||||
|
||||
@@ -112,8 +111,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
PATCH_OFFSET(&(entry->cvb_pll_param.c5), 0);
|
||||
}
|
||||
|
||||
template <bool isMariko>
|
||||
Result GpuFreqCvbTable(u32 *ptr) {
|
||||
template <bool isMariko> Result GpuFreqCvbTable(u32 *ptr) {
|
||||
cvb_entry_t *default_table = isMariko ? (cvb_entry_t *)(&mariko::GpuCvbTableDefault) : (cvb_entry_t *)(&erista::GpuCvbTableDefault);
|
||||
cvb_entry_t *customize_table;
|
||||
if (isMariko) {
|
||||
@@ -136,7 +134,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.marikoGpuDvfsTableHiOPT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (C.eristaGpuUV) {
|
||||
case 0:
|
||||
@@ -151,7 +149,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
default:
|
||||
customize_table = const_cast<cvb_entry_t *>(C.eristaGpuDvfsTable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t default_entry_count = GetDvfsTableEntryCount(default_table);
|
||||
@@ -204,4 +202,4 @@ namespace ams::ldr::hoc::pcv {
|
||||
void SafetyCheck();
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
}
|
||||
} // namespace ams::ldr::hoc::pcv
|
||||
|
||||
@@ -44,6 +44,15 @@ namespace ams::ldr::hoc::pcv {
|
||||
return ins & ((1 << 5) - 1);
|
||||
};
|
||||
|
||||
/* Rn (bits 9:5) and Rm (bits 20:16) to get registers. */
|
||||
inline auto AsmGetRn = [](u32 ins) -> u32 { return (ins >> 5) & 0x1Fu; };
|
||||
inline auto AsmGetRm = [](u32 ins) -> u32 { return (ins >> 16) & 0x1Fu; };
|
||||
|
||||
/* Add (shifted register), 64-bit: sf=1 op=0 S=0 01011 shift(2) 0 Rm imm6 Rn Rd. */
|
||||
inline auto AsmIsAddShiftedReg64 = [](u32 ins) {
|
||||
return (ins & 0xFF200000u) == 0x8B000000u;
|
||||
};
|
||||
|
||||
inline auto asm_set_rd = [](u32 ins, u8 rd) {
|
||||
return (ins & 0xFFFFFFE0) | (rd & 0x1F);
|
||||
};
|
||||
@@ -94,6 +103,16 @@ namespace ams::ldr::hoc::pcv {
|
||||
return static_cast<uintptr_t>(static_cast<s64>(pc) + imm);
|
||||
};
|
||||
|
||||
/* adrp Rd, target */
|
||||
inline auto AsmMakeAdrp = [](uintptr_t pc, uintptr_t target, u32 rd) -> u32 {
|
||||
const s64 delta = static_cast<s64>(target & ~static_cast<uintptr_t>(0xFFF))
|
||||
- static_cast<s64>(pc & ~static_cast<uintptr_t>(0xFFF));
|
||||
const u32 imm = static_cast<u32>((delta >> 12) & 0x1FFFFF); /* 21-bit page */
|
||||
const u32 immlo = imm & 0x3;
|
||||
const u32 immhi = (imm >> 2) & 0x7FFFF;
|
||||
return 0x90000000u | (immlo << 29) | (immhi << 5) | (rd & 0x1Fu);
|
||||
};
|
||||
|
||||
inline auto AsmSetAdrTarget = [](u32 ins, uintptr_t pc, uintptr_t target) -> u32 {
|
||||
const s64 delta = static_cast<s64>(target) - static_cast<s64>(pc);
|
||||
const u32 immlo = static_cast<u32>(delta & 0x3);
|
||||
@@ -101,6 +120,76 @@ namespace ams::ldr::hoc::pcv {
|
||||
return (ins & ~((0x3u << 29) | (0x7FFFFu << 5))) | (immlo << 29) | (immhi << 5);
|
||||
};
|
||||
|
||||
/* adrp: bit31=1, bits 28:24 = 10000. */
|
||||
inline auto AsmIsAdrp = [](u32 ins) -> bool {
|
||||
return (ins & 0x9F000000u) == 0x90000000u;
|
||||
};
|
||||
|
||||
inline auto AsmAdrpPageOffset = [](u32 ins) -> s64 {
|
||||
s64 imm = static_cast<s64>((((ins >> 5) & 0x7FFFFu) << 2) | ((ins >> 29) & 0x3u));
|
||||
imm = (imm << 43) >> 43; /* sign-extend the 21-bit immediate */
|
||||
return imm << 12;
|
||||
};
|
||||
|
||||
/* add (immediate), 64-bit: sf=1 op=0 S=0 100010 sh imm12 Rn Rd. */
|
||||
inline auto AsmIsAddImm64 = [](u32 ins) -> bool {
|
||||
return (ins & 0xFF800000u) == 0x91000000u;
|
||||
};
|
||||
|
||||
inline auto AsmGetImm12 = [](u32 ins) -> u32 {
|
||||
return (ins >> 10) & 0xFFFu;
|
||||
};
|
||||
|
||||
inline auto AsmMakeAddImm64 = [](u32 rd, u32 rn, u32 imm12) -> u32 {
|
||||
return 0x91000000u | ((imm12 & 0xFFFu) << 10) | ((rn & 0x1Fu) << 5) | (rd & 0x1Fu);
|
||||
};
|
||||
|
||||
/* movz Wd,#imm16 (no shift). */
|
||||
inline auto AsmMakeMovzW = [](u32 rd, u16 imm16) -> u32 {
|
||||
return 0x52800000u | (static_cast<u32>(imm16) << 5) | (rd & 0x1Fu);
|
||||
};
|
||||
|
||||
/* mov Xd,Xm == orr Xd,XZR,Xm. */
|
||||
inline auto AsmMakeMovReg = [](u32 rd, u32 rm) -> u32 {
|
||||
return 0xAA0003E0u | ((rm & 0x1Fu) << 16) | (rd & 0x1Fu);
|
||||
};
|
||||
|
||||
/* ldr Xt,[Xn,#byteOff] */
|
||||
inline auto AsmMakeLdrImm64 = [](u32 rt, u32 rn, u32 byteOff) -> u32 {
|
||||
return 0xF9400000u | (((byteOff / 8u) & 0xFFFu) << 10) | ((rn & 0x1Fu) << 5) | (rt & 0x1Fu);
|
||||
};
|
||||
|
||||
/* mov Xd,X<rm> == orr Xd,XZR,X<rm> (matches any Rd). */
|
||||
inline auto AsmIsMovReg = [](u32 ins, u32 rm) -> bool {
|
||||
return (ins & 0xFFFFFFE0u) == (0xAA0003E0u | ((rm & 0x1Fu) << 16));
|
||||
};
|
||||
|
||||
/* add Xd,sp,#imm12 (shift 0). */
|
||||
inline auto AsmIsAddSpImm = [](u32 ins) -> bool {
|
||||
return (ins & 0xFFC003E0u) == 0x910003E0u;
|
||||
};
|
||||
|
||||
/* sub Xd,x29,#imm12 (shift 0). */
|
||||
inline auto AsmIsSubX29Imm = [](u32 ins) -> bool {
|
||||
return (ins & 0xFFC003E0u) == 0xD10003A0u;
|
||||
};
|
||||
|
||||
inline auto AsmIsB = [](u32 ins) -> bool { return (ins & 0xFC000000u) == 0x14000000u; }; /* b */
|
||||
inline auto AsmIsBl = [](u32 ins) -> bool { return (ins & 0xFC000000u) == 0x94000000u; }; /* bl */
|
||||
inline auto AsmIsBCond = [](u32 ins) -> bool { return (ins & 0xFF000010u) == 0x54000000u; }; /* b.c */
|
||||
|
||||
/* Byte target address of a b/bl at pc. */
|
||||
inline auto AsmBranchTarget = [](u32 ins, uintptr_t pc) -> uintptr_t {
|
||||
s64 off = static_cast<s64>((ins & 0x03FFFFFFu) << 2);
|
||||
off = (off << 36) >> 36; /* sign-extend the 28-bit branch offset */
|
||||
return static_cast<uintptr_t>(static_cast<s64>(pc) + off);
|
||||
};
|
||||
|
||||
/* Rewrite a scaled immediate-offset load/store (`op Wt,[Xn,#imm]`) into its register-offset form */
|
||||
inline auto AsmSetLdStRegOffset = [](u32 ldstImm, u32 rm) -> u32 {
|
||||
return (ldstImm & 0xC0C003FFu) | 0x38207800u | ((rm & 0x1Fu) << 16);
|
||||
};
|
||||
|
||||
inline auto AsmIsLdpX = [](u32 ins) {
|
||||
return (ins & 0xFE400000u) == 0xA8400000u;
|
||||
};
|
||||
|
||||
@@ -173,6 +173,16 @@ namespace ams::ldr::hoc::pcv {
|
||||
constexpr size_t DvfsTableEntryCount = 32;
|
||||
constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1;
|
||||
|
||||
// EMC-only limit.
|
||||
constexpr size_t EmcDvfsTableEntryCount = 64;
|
||||
constexpr size_t EmcDvfsTableEntryLimit = EmcDvfsTableEntryCount - 1;
|
||||
|
||||
// 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;
|
||||
|
||||
template<typename T>
|
||||
size_t GetDvfsTableEntryCount(T *table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
@@ -622,6 +622,82 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
u32 *nsoStart;
|
||||
}
|
||||
|
||||
/* Widen InitDram for a >32-entry EMC DVFS list. Freq array can be dropped to free 264 bytes, relocate the Soc LUT to that space */
|
||||
Result EmcSocLutReloc(u32 *ptr) {
|
||||
R_UNLESS(EmcSocLutPatternFn(ptr), ldr::ResultInvalidEmcSocLut()); /* str lut,[rail+0x120] ; str n,[rail+0x154] */
|
||||
constexpr u32 Window = 48;
|
||||
|
||||
u32 *freqStore = ScanAssembly(ptr - Window, Window, EmcSocFreqStoreAsm, asm_compare_no_rd); /* str x?,[x8,#0x18] */
|
||||
u32 *voltStore = ScanAssembly(ptr - Window, Window, EmcSocVoltStoreAsm, asm_compare_no_rd); /* str w?,[x8,#0x48] */
|
||||
u32 *readLoad = ScanAssembly(ptr - Window, Window, EmcSocReadLoadAsm, asm_compare_no_rd); /* ldr w?,[x9,#0x48] */
|
||||
R_UNLESS(freqStore && voltStore && readLoad, ldr::ResultInvalidEmcSocLut());
|
||||
|
||||
u32 *voltBase = voltStore - 2; /* `add Xb,Xsrc,Xi,LSL#2` (a cmn sits between it and store) */
|
||||
R_UNLESS(AsmIsAddShiftedReg64(*voltBase) && asm_get_rd(*voltBase) == AsmGetRn(*voltStore),
|
||||
ldr::ResultInvalidEmcSocLut());
|
||||
|
||||
/* adrp Xl ; add Xl,Xl,#off ; ... ; str Xl,[rail,#0x120] */
|
||||
const u32 lutReg = asm_get_rd(ptr[0]);
|
||||
const u32 railReg = AsmGetRn(ptr[0]);
|
||||
R_UNLESS(AsmIsAdrp(ptr[-3]) && asm_get_rd(ptr[-3]) == lutReg, ldr::ResultInvalidEmcSocLut());
|
||||
R_UNLESS(AsmIsAddImm64(ptr[-2]) && asm_get_rd(ptr[-2]) == lutReg && AsmGetRn(ptr[-2]) == lutReg,
|
||||
ldr::ResultInvalidEmcSocLut());
|
||||
|
||||
const u32 srcBase = AsmGetRn(*voltBase); /* rail ptr at +0x20 */
|
||||
const u32 wBase = asm_get_rd(*voltBase); /* base reg */
|
||||
const u32 wIdx = AsmGetRm(*voltBase); /* loop index */
|
||||
|
||||
PATCH_OFFSET(freqStore, NopIns); /* Unneeded */
|
||||
PATCH_OFFSET(voltBase, AsmMakeLdrImm64(wBase, srcBase, 0x20)); /* ldr Xb,[Xsrc,#0x20] (rail) */
|
||||
PATCH_OFFSET(voltStore - 1, AsmMakeAddImm64(wBase, wBase, 0x18)); /* add Xb,Xb,#0x18 (was cmn) */
|
||||
PATCH_OFFSET(voltStore, AsmSetLdStRegOffset(*voltStore, wIdx)); /* str Wv,[Xb,Xi,LSL#2] -> rail+0x18+i*4 */
|
||||
PATCH_OFFSET(voltStore + 1, NopIns); /* Unneeded */
|
||||
|
||||
/* rail+0x18 as the socMinLut pointer. */
|
||||
PATCH_OFFSET(ptr - 3, NopIns);
|
||||
PATCH_OFFSET(ptr - 2, AsmMakeAddImm64(lutReg, railReg, 0x18));/* add Xl,rail,#0x18 */
|
||||
|
||||
/* Drop the abort branch in case of a bad read */
|
||||
for (u32 i = 1; i <= 4; ++i) {
|
||||
if (AsmIsBCond(readLoad[i])) {
|
||||
PATCH_OFFSET(&readLoad[i], NopIns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result EmcDvfsCountLimit(u32 *ptr) {
|
||||
R_UNLESS(EmcDvfsCountPatternFn(ptr), ldr::ResultInvalidEmcDvfsCount());
|
||||
|
||||
/* cmp w?,#0x21 -> cmp w?,#EmcDvfsTableEntryCount */
|
||||
PATCH_OFFSET(ptr, AsmSubsSetImm12(*ptr, static_cast<u16>(EmcDvfsTableEntryCount)));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result EmcRateListLimit(u32 *ptr) {
|
||||
/* ptr = cmp w?,#0x20 ; ptr[1] = csel w?,w?,w?,lt (w? = min(maxCount, 32)) ; ptr[2] = bl */
|
||||
R_UNLESS(EmcRateListPatternFn(ptr), ldr::ResultInvalidEmcRateList());
|
||||
|
||||
/* The csel's Rm holds the 32 cap. */
|
||||
const u32 capReg = AsmGetRm(ptr[1]);
|
||||
const u32 capMov = AsmMakeMovzW(capReg, 0x20); /* movz w<Rm>,#0x20 */
|
||||
|
||||
u32 *movPtr = nullptr;
|
||||
for (u32 i = 1; i <= 16; ++i) {
|
||||
if (*(ptr - i) == capMov) {
|
||||
movPtr = ptr - i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
R_UNLESS(movPtr, ldr::ResultInvalidEmcRateList());
|
||||
|
||||
/* min(maxCount, 32) -> min(maxCount, EmcDvfsTableEntryCount). */
|
||||
PATCH_OFFSET(ptr, AsmSubsSetImm12(*ptr, static_cast<u16>(EmcDvfsTableEntryCount))); /* cmp w?,#64 */
|
||||
PATCH_OFFSET(movPtr, asm_set_imm16(*movPtr, static_cast<u16>(EmcDvfsTableEntryCount))); /* movz w?,#64 */
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void MtcGenerateJedecTable() {
|
||||
const u32 jedecFreqs[] = { 1866000, 1996000, 2133000, 2400000, 2666000, 2933000, 3200000 };
|
||||
constexpr u32 JedecFreqCount = std::size(jedecFreqs);
|
||||
@@ -638,7 +714,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
newEmcList.push_back(static_cast<u32>(C.marikoEmcMaxClock));
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
newEmcList.resize(std::min(newEmcList.size(), EmcDvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
void MtcGenerate133StepTable() {
|
||||
@@ -657,12 +733,39 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
newEmcList.push_back(static_cast<u32>(C.marikoEmcMaxClock));
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
newEmcList.resize(std::min(newEmcList.size(), EmcDvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
void MtcGenerate33StepTable() {
|
||||
/* ~33.33MHz but rounded*/
|
||||
const u32 stepFreqs33[] = {
|
||||
1633000, 1666000, 1700000, 1733000, 1766000, 1800000, 1833000, 1866000, 1900000, 1933000,
|
||||
1966000, 2000000, 2033000, 2066000, 2100000, 2133000, 2166000, 2200000, 2233000, 2266000,
|
||||
2300000, 2333000, 2366000, 2400000, 2433000, 2466000, 2500000, 2533000, 2566000, 2600000,
|
||||
2633000, 2666000, 2700000, 2733000, 2766000, 2800000, 2833000, 2866000, 2900000, 2933000,
|
||||
2966000, 3000000, 3033000, 3066000, 3100000, 3133000, 3166000, 3200000, 3233000, 3266000,
|
||||
3300000, 3333000, 3366000, 3400000, 3433000, 3466000, 3500000,
|
||||
};
|
||||
constexpr u32 StepFreqs33Size = std::size(stepFreqs33);
|
||||
|
||||
for (u32 i = 0; i < StepFreqs33Size; ++i) {
|
||||
if (stepFreqs33[i] <= C.marikoEmcMaxClock) {
|
||||
newEmcList.push_back(stepFreqs33[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newEmcList.back() != C.marikoEmcMaxClock) {
|
||||
newEmcList.push_back(static_cast<u32>(C.marikoEmcMaxClock));
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), EmcDvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
void MtcGenerateFreqTables() {
|
||||
newEmcList.clear();
|
||||
newEmcList.reserve(DvfsTableEntryCount);
|
||||
newEmcList.reserve(EmcDvfsTableEntryCount);
|
||||
newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault));
|
||||
|
||||
if (C.marikoEmcMaxClock <= EmcClkOSLimit) {
|
||||
@@ -671,6 +774,9 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
u32 stepRate = 0;
|
||||
switch (C.stepMode) {
|
||||
case StepMode_33MHz:
|
||||
MtcGenerate33StepTable();
|
||||
return;
|
||||
case StepMode_66MHz:
|
||||
stepRate = 66667;
|
||||
break;
|
||||
@@ -701,7 +807,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
newEmcList.push_back(newFreq);
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
newEmcList.resize(std::min(newEmcList.size(), EmcDvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
Result VerifyMtcTable(MarikoMtcTable *tableStart, u32 expectedFreq) {
|
||||
@@ -905,24 +1011,23 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
#undef DVB
|
||||
#undef DVB_OC
|
||||
|
||||
DvbEntry emcDvbTableOc[newEmcList.size()];
|
||||
|
||||
const size_t dvbCount = std::min(newEmcList.size(), DvbTableCapacity);
|
||||
DvbEntry emcDvbTableOc[DvbTableCapacity] = {};
|
||||
|
||||
u32 bracketIndex = 0;
|
||||
for (u32 i = 0; i < newEmcList.size(); ++i) {
|
||||
while (newEmcList[i] >= emcDvbOcTableBrackets[bracketIndex + 1].freq) {
|
||||
for (size_t i = 0; i < dvbCount; ++i) {
|
||||
const u32 freq = (i == dvbCount - 1) ? static_cast<u32>(newEmcList.back()) : newEmcList[i];
|
||||
while (freq >= emcDvbOcTableBrackets[bracketIndex + 1].freq) {
|
||||
++bracketIndex;
|
||||
}
|
||||
|
||||
emcDvbTableOc[i].freq = newEmcList[i];
|
||||
emcDvbTableOc[i].freq = freq;
|
||||
std::memcpy(emcDvbTableOc[i].volt, emcDvbOcTableBrackets[bracketIndex].volt, sizeof(emcDvbTableOc[i].volt));
|
||||
}
|
||||
|
||||
std::memset(mem_dvb_table_head, 0, sizeof(EmcDvbTableDefault));
|
||||
std::memcpy(mem_dvb_table_head, &emcDvbTableOc, sizeof(emcDvbTableOc));
|
||||
|
||||
/* Max dvfs entry is 32, but HOS doesn't seem to boot if exact freq doesn't exist in dvb table,
|
||||
reason why it's like this
|
||||
*/
|
||||
/* Clear the entire 32-entry region */
|
||||
std::memset(mem_dvb_table_head, 0, DvbTableCapacity * sizeof(DvbEntry));
|
||||
std::memcpy(mem_dvb_table_head, emcDvbTableOc, dvbCount * sizeof(DvbEntry));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -1136,9 +1241,61 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result EmcRateSessLimit(u32 *ptr) {
|
||||
u32 movzI = 0;
|
||||
R_UNLESS(EmcRateSessFindClamp(ptr, nullptr, nullptr, &movzI), ldr::ResultInvalidEmcRateList());
|
||||
|
||||
/* Reject cmd11 GetDvfsTable. */
|
||||
for (u32 i = 1; i <= 24; ++i) {
|
||||
const u32 w = ptr[i];
|
||||
if (AsmIsSubX29Imm(w) && AsmGetImm12(w) >= 0x20u) { /* sub x?,x29,#>=0x20 */
|
||||
R_THROW(ldr::ResultInvalidEmcRateList());
|
||||
}
|
||||
}
|
||||
|
||||
/* mov x<desc>,x2 */
|
||||
u32 descReg = 0xFFu;
|
||||
for (u32 i = 1; i <= 24; ++i) {
|
||||
if (AsmIsMovReg(ptr[i], 2)) { descReg = asm_get_rd(ptr[i]); break; }
|
||||
}
|
||||
R_UNLESS(descReg != 0xFFu, ldr::ResultInvalidEmcRateList());
|
||||
|
||||
/* Repoint the duplicated-imm pair */
|
||||
u32 *adds[8]; u32 addImm[8]; u32 nAdds = 0;
|
||||
for (u32 i = 1; i <= 24 && nAdds < 8; ++i) {
|
||||
const u32 w = ptr[i];
|
||||
if (AsmIsAddSpImm(w)) { /* add x?,sp,#imm12 (shift 0) */
|
||||
adds[nAdds] = ptr + i;
|
||||
addImm[nAdds] = AsmGetImm12(w);
|
||||
++nAdds;
|
||||
}
|
||||
}
|
||||
u32 patched = 0;
|
||||
for (u32 a = 0; a < nAdds; ++a) {
|
||||
bool dup = false;
|
||||
for (u32 b = 0; b < nAdds; ++b) {
|
||||
if (a != b && addImm[a] == addImm[b]) { dup = true; break; }
|
||||
}
|
||||
if (dup) {
|
||||
PATCH_OFFSET(adds[a], AsmMakeLdrImm64(asm_get_rd(*adds[a]), descReg, 0)); /* ldr x?,[x<desc>] */
|
||||
++patched;
|
||||
}
|
||||
}
|
||||
R_UNLESS(patched == 2, ldr::ResultInvalidEmcRateList());
|
||||
|
||||
/* min(maxCount, 32) -> min(maxCount, EmcDvfsTableEntryCount) */
|
||||
PATCH_OFFSET(ptr, AsmSubsSetImm12(*ptr, static_cast<u16>(EmcDvfsTableEntryCount))); /* cmp w?,#64 */
|
||||
PATCH_OFFSET(ptr + movzI, asm_set_imm16(*(ptr + movzI), static_cast<u16>(EmcDvfsTableEntryCount))); /* movz w?,#64 */
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
nsoStart = reinterpret_cast<u32 *>(mapped_nso);
|
||||
|
||||
g_pcv_scratch = mapped_nso + nso_size - HocPcvScratchSize;
|
||||
|
||||
MtcGenerateFreqTables();
|
||||
|
||||
u32 CpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq);
|
||||
u32 GpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(GpuCvbTableDefault)->freq);
|
||||
|
||||
@@ -1161,6 +1318,10 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
{ "MEM Vddq", &EmcVddqVolt, 2, nullptr, EmcVddqDefault },
|
||||
{ "MEM Vdd2", &MemVoltHandler, 2, nullptr, MemVdd2Default },
|
||||
{ "MEM Table Asm", &MemMtcTableAsm, 1, &MemMtcGetGetTablePatternFn },
|
||||
{ "EMC DVFS Count", &EmcDvfsCountLimit, 1, &EmcDvfsCountPatternFn },
|
||||
{ "EMC SoC LUT", &EmcSocLutReloc, 1, &EmcSocLutPatternFn },
|
||||
{ "EMC Rate List", &EmcRateListLimit, 0, &EmcRateListPatternFn },
|
||||
{ "EMC Rate Sess", &EmcRateSessLimit, 1, &EmcRateSessPatternFn },
|
||||
{ "SOC Volt Asm", &SocVoltAsm, 1, &SocVoltPatternFn },
|
||||
{ "SOC Volt Limit", &SocVoltLimit, 1, nullptr, SocVoltLimitOfficial },
|
||||
};
|
||||
|
||||
@@ -299,6 +299,78 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
return AsmCompareAddNoImm12(*ptr, MtcAddAsm);
|
||||
}
|
||||
|
||||
constexpr u32 EmcCountCmpAsm = 0x7100851F; /* cmp w?,#0x21 (subs wzr,w?,#0x21) */
|
||||
|
||||
/*
|
||||
str <lut>,[<rail>,#0x120] ; volt-array pointer
|
||||
str w?, [<rail>,#0x154] ; num_freqs
|
||||
*/
|
||||
constexpr u32 EmcSocLutPtrStoreAsm = 0xF9009009; /* str x?,[x0,#0x120] (anchor) */
|
||||
constexpr u32 EmcSocLutCountStoreAsm = 0xB9015408; /* str w?,[x0,#0x154] (anchor) */
|
||||
constexpr u32 EmcSocFreqStoreAsm = 0xF9000D00; /* str x?,[x8,#0x18] */
|
||||
constexpr u32 EmcSocVoltStoreAsm = 0xB9004900; /* str w?,[x8,#0x48] (socMinLut[i]) */
|
||||
constexpr u32 EmcSocReadLoadAsm = 0xB9404929; /* ldr w?,[x9,#0x48] (socMinLut readback) */
|
||||
|
||||
inline bool EmcDvfsCountPatternFn(u32 *ptr) {
|
||||
/* Local context: cbz w?,<skip> ; cmp w?,#0x21 ; b.cs <abort> */
|
||||
return asm_compare_no_rd(*ptr, EmcCountCmpAsm) && AsmCompareBrConNoImm19(*(ptr + 1), 0x54000002) /* b.cs */
|
||||
&& AsmCbzCompareOpcodeOnly(*(ptr - 1), 0x34000000); /* cbz */
|
||||
}
|
||||
|
||||
inline bool EmcSocLutPatternFn(u32 *ptr) {
|
||||
return asm_compare_no_rd(*ptr, EmcSocLutPtrStoreAsm) /* str x?,[x0,#0x120] */
|
||||
&& asm_compare_no_rd(*(ptr + 1), EmcSocLutCountStoreAsm); /* str w?,[x0,#0x154] */
|
||||
}
|
||||
|
||||
/*
|
||||
mov w?,#0x20 ; the 32 cap
|
||||
cmp w?,#0x20
|
||||
csel w?,w?,w?,lt ; w? = min(maxCount, 32)
|
||||
bl TegraGetEmcDvfsFreqTable
|
||||
|
||||
cmp w?,#0x20 ; (maxCount)
|
||||
csel w?,<same>,<cap>,lt ; min(maxCount, 32)
|
||||
bl <Get*DvfsFreqTable>
|
||||
*/
|
||||
constexpr u32 EmcRateCapCmpAsm = 0x710082FF; /* cmp w?,#0x20 */
|
||||
constexpr u32 EmcRateCapCselAsm = 0x1A80B000; /* csel w?,w?,w?,lt */
|
||||
|
||||
inline bool EmcRateListPatternFn(u32 *ptr) {
|
||||
return AsmSubsCompareNoReg(*ptr, EmcRateCapCmpAsm) /* cmp w?,#0x20 */
|
||||
&& AsmCompareCselNoReg(*(ptr + 1), EmcRateCapCselAsm) /* csel w?,w?,w?,lt */
|
||||
&& (AsmGetRn(*ptr) == AsmGetRn(*(ptr + 1))) /* min(reg, 0x20) */
|
||||
&& AsmBlCompareOpcodeOnly(*(ptr + 2), 0x94000000); /* bl <Get*DvfsFreqTable> */
|
||||
}
|
||||
|
||||
constexpr u32 EmcRateSessCmpAsm = 0x710082FF; /* cmp w?,#0x20 */
|
||||
constexpr u32 EmcRateSessMovAsm = 0x52800400; /* movz w?,#0x20 */
|
||||
constexpr u32 EmcRateSessCselAsm = 0x1A80B000; /* csel w?,w?,w?,lt (opcode + cond) */
|
||||
|
||||
inline bool EmcRateSessFindClamp(u32 *ptr, u32 *out_c, u32 *out_cap, u32 *out_movz_i) {
|
||||
if (!AsmSubsCompareNoReg(ptr[0], EmcRateSessCmpAsm)) return false; /* cmp w<c>,#0x20 */
|
||||
const u32 c = AsmGetRn(ptr[0]);
|
||||
for (u32 i = 1; i <= 14; ++i) {
|
||||
const u32 w = ptr[i];
|
||||
if (AsmCompareCselNoReg(w, EmcRateSessCselAsm) && AsmGetRn(w) == c && asm_get_rd(w) == c) {
|
||||
const u32 cap = AsmGetRm(w);
|
||||
for (u32 j = 1; j < i; ++j) {
|
||||
if ((ptr[j] & 0xFFFFFFE0u) == EmcRateSessMovAsm && asm_get_rd(ptr[j]) == cap) {
|
||||
if (out_c) *out_c = c;
|
||||
if (out_cap) *out_cap = cap;
|
||||
if (out_movz_i) *out_movz_i = j;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool EmcRateSessPatternFn(u32 *ptr) {
|
||||
return EmcRateSessFindClamp(ptr, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
}
|
||||
|
||||
BIN
Source/Horizon-OC-Monitor/Horizon-OC-Monitor.elf
Normal file
BIN
Source/Horizon-OC-Monitor/Horizon-OC-Monitor.elf
Normal file
Binary file not shown.
BIN
Source/Horizon-OC-Monitor/Horizon-OC-Monitor.nacp
Normal file
BIN
Source/Horizon-OC-Monitor/Horizon-OC-Monitor.nacp
Normal file
Binary file not shown.
BIN
Source/Horizon-OC-Monitor/Horizon-OC-Monitor.ovl
Normal file
BIN
Source/Horizon-OC-Monitor/Horizon-OC-Monitor.ovl
Normal file
Binary file not shown.
Binary file not shown.
@@ -82,9 +82,10 @@ typedef struct {
|
||||
u8 custRev;
|
||||
u16 kipVersion;
|
||||
bool isKipLoaded;
|
||||
bool rebootRequired;
|
||||
|
||||
// Reserved for future use
|
||||
u8 reserved[0x35A];
|
||||
u8 reserved[0x359];
|
||||
} HocClkContext;
|
||||
|
||||
typedef struct
|
||||
@@ -95,7 +96,7 @@ typedef struct
|
||||
};
|
||||
} HocClkTitleProfileList;
|
||||
|
||||
#define HOCCLK_FREQ_LIST_MAX 48
|
||||
#define HOCCLK_FREQ_LIST_MAX 64
|
||||
|
||||
#define HOCCLK_GLOBAL_PROFILE_TID 0xA111111111111111
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
|
||||
# version control constants
|
||||
#---------------------------------------------------------------------------------
|
||||
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
|
||||
APP_VERSION := 2.5.0 # ensure to set KIP_VERSION and CUST_REV in sysmodule Makefile when updating this
|
||||
APP_VERSION := 3.0.0 # ensure to set KIP_VERSION and CUST_REV in sysmodule Makefile when updating this
|
||||
TARGET_VERSION := $(APP_VERSION)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
@@ -96,6 +96,15 @@ class AppOverlay : public tsl::Overlay {
|
||||
"");
|
||||
}
|
||||
|
||||
HocClkContext context = {};
|
||||
if (R_SUCCEEDED(hocclkIpcGetCurrentContext(&context)) && context.rebootRequired) {
|
||||
return initially<FatalGui>("Horizon OC has been updated.\n\n"
|
||||
"\n"
|
||||
"Please reboot your console\n\n"
|
||||
"to finish applying the update.",
|
||||
"");
|
||||
}
|
||||
|
||||
return initially<MainGui>();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -132,7 +132,7 @@ void BaseGui::preDraw(tsl::gfx::Renderer *renderer) {
|
||||
|
||||
drawDynamicUltraText(renderer, LOGO_TEXT_X, TEXT_Y, LOGO_LABEL_FONT_SIZE, STATIC_TEAL, false);
|
||||
|
||||
static const std::string versionStr = "Version " + getVersionString() + " \"Gaea\"";
|
||||
static const std::string versionStr = "Version " + getVersionString() + " \"Athena\"";
|
||||
static constexpr tsl::Color versionColor(9, 9, 9, 15);
|
||||
static constexpr s32 vx = LOGO_TEXT_X + 15;
|
||||
static constexpr s32 vy = TEXT_Y + 18;
|
||||
|
||||
@@ -228,15 +228,15 @@ std::vector<std::string> ConfigInfoStrings(HocClkConfigValue val, bool isMariko,
|
||||
case KipConfigValue_stepMode:
|
||||
return {
|
||||
"The step that RAM clocks take.",
|
||||
"Options (with examples):",
|
||||
"Options:",
|
||||
" - 33MHz - 3 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 - 66 MHz step (ex. 1600, 1733, 1866, etc.)",
|
||||
" - 133MHz - 133 MHz step (ex. 1600, 1733, 1866, etc.)",
|
||||
" - JEDEC:",
|
||||
" - 1600, 1866, 1996, 2133, 2400, 2666, 2933 and 3200 MHz are used",
|
||||
"The RAM max clock will always be available regardless of the step mode, but the intermediate frequencies will be limited by the selected step mode.",
|
||||
"This setting does not affect performance and the option you choose mostly is based on your personal taste",
|
||||
"33 MHz step mode is not possible due to certain limitations of Horizon OS",
|
||||
"This setting does not affect performance and the option you choose mostly is based on your personal taste",
|
||||
"Default: 66 MHz",
|
||||
};
|
||||
|
||||
|
||||
@@ -1143,6 +1143,7 @@ class RamSubmenuGui : public MiscGui {
|
||||
|
||||
if (IsMariko()) {
|
||||
std::vector<NamedValue> stepMode = {
|
||||
NamedValue("33MHz", 4),
|
||||
NamedValue("66MHz", 0),
|
||||
NamedValue("100MHz", 1),
|
||||
NamedValue("133MHz", 3), // Mantain compatability
|
||||
|
||||
@@ -28,9 +28,9 @@ INCLUDES := ../common/include src/hos src/soc src/i2c src/util src/pwr src/ipc
|
||||
EXEFS_SRC := exefs_src
|
||||
LIBNAMES := minIni
|
||||
# major minor patch
|
||||
TARGET_VERSION := 2.5.0
|
||||
KIP_VERSION := 250
|
||||
CUST_REV := 6
|
||||
TARGET_VERSION := 3.0.0
|
||||
KIP_VERSION := 300
|
||||
CUST_REV := 7
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
|
||||
@@ -222,7 +222,8 @@ namespace kip {
|
||||
!config::GetConfigValue(HocClkConfigValue_IsFirstLoad)) {
|
||||
MigrateKipData(cust_get_cust_rev(&table), cust_get_kip_version(&table));
|
||||
SetKipData();
|
||||
notification::writeNotification("Horizon OC\nKIP has been updated\nPlease reboot your console");
|
||||
clockManager::gContext.rebootRequired = true;
|
||||
notification::writeNotification("Horizon OC\nKIP has been updated\nPlease reboot your console to use Horizon OC");
|
||||
return;
|
||||
}
|
||||
if (config::GetConfigValue(HocClkConfigValue_IsFirstLoad) == true) {
|
||||
|
||||
@@ -295,6 +295,47 @@ namespace clockManager {
|
||||
hz++;
|
||||
}
|
||||
|
||||
/* Since it is a pain to patch the vtables in ipc we can just hack the freqs in. You can still set them. */
|
||||
constexpr u64 EmcClkOSLimitHz = 1600000ULL * 1000; // 1600 MHz
|
||||
const u64 maxHz = static_cast<u64>(config::GetConfigValue(KipConfigValue_marikoEmcMaxClock)) * 1000;
|
||||
if (module == HocClkModule_MEM && board::GetSocType() == HocClkSocType_Mariko &&
|
||||
kip::kipAvailable && maxHz >= EmcClkOSLimitHz &&
|
||||
config::GetConfigValue(KipConfigValue_stepMode) == 4 /* 33 MHz */) {
|
||||
|
||||
/* Drop the clkrst entries above the OS limit */
|
||||
u32 kept = 0;
|
||||
for (u32 i = 0; i < gFreqTable[module].count; ++i) {
|
||||
if (static_cast<u64>(gFreqTable[module].list[i]) <= EmcClkOSLimitHz) {
|
||||
gFreqTable[module].list[kept++] = gFreqTable[module].list[i];
|
||||
}
|
||||
}
|
||||
gFreqTable[module].count = kept;
|
||||
|
||||
auto push = [&](u64 freqHz) {
|
||||
if (freqHz > maxHz || gFreqTable[module].count >= HOCCLK_FREQ_LIST_MAX) {
|
||||
return;
|
||||
}
|
||||
gFreqTable[module].list[gFreqTable[module].count++] = static_cast<u32>(freqHz);
|
||||
};
|
||||
|
||||
static const u32 stepFreqs33[] = {
|
||||
1633000, 1666000, 1700000, 1733000, 1766000, 1800000, 1833000, 1866000, 1900000, 1933000,
|
||||
1966000, 2000000, 2033000, 2066000, 2100000, 2133000, 2166000, 2200000, 2233000, 2266000,
|
||||
2300000, 2333000, 2366000, 2400000, 2433000, 2466000, 2500000, 2533000, 2566000, 2600000,
|
||||
2633000, 2666000, 2700000, 2733000, 2766000, 2800000, 2833000, 2866000, 2900000, 2933000,
|
||||
2966000, 3000000, 3033000, 3066000, 3100000, 3133000, 3166000, 3200000, 3233000, 3266000,
|
||||
3300000, 3333000, 3366000, 3400000, 3433000, 3466000, 3500000,
|
||||
};
|
||||
for (u32 f : stepFreqs33) {
|
||||
push(static_cast<u64>(f) * 1000);
|
||||
}
|
||||
|
||||
if (gFreqTable[module].count == 0 ||
|
||||
static_cast<u64>(gFreqTable[module].list[gFreqTable[module].count - 1]) != maxHz) {
|
||||
push(maxHz);
|
||||
}
|
||||
}
|
||||
|
||||
fileUtils::LogLine("[mgr] count = %u", gFreqTable[module].count);
|
||||
}
|
||||
|
||||
@@ -560,7 +601,6 @@ namespace clockManager {
|
||||
if (module == HocClkModule_MEM && targetHz > oldHz && config::GetConfigValue(HocClkConfigValue_DVFSMode) == DVFSMode_Hijack) {
|
||||
ApplyGpuDvfs(targetHz);
|
||||
}
|
||||
|
||||
board::SetHz((HocClkModule)module, nearestHz);
|
||||
gContext.freqs[module] = nearestHz;
|
||||
|
||||
@@ -739,6 +779,11 @@ namespace clockManager {
|
||||
gContext = {};
|
||||
gContext.applicationId = 0;
|
||||
gContext.profile = HocClkProfile_Handheld;
|
||||
|
||||
/* Load the KIP customize table before building the freq tables: the MEM freq-list
|
||||
synthesis in RefreshFreqTableRow reads marikoEmcMaxClock / stepMode from it. */
|
||||
kip::GetKipData();
|
||||
|
||||
for (unsigned int module = 0; module < HocClkModule_EnumMax; module++) {
|
||||
gContext.freqs[module] = 0;
|
||||
gContext.realFreqs[module] = 0;
|
||||
@@ -757,8 +802,6 @@ namespace clockManager {
|
||||
gLastTempLogNs = 0;
|
||||
gLastCsvWriteNs = 0;
|
||||
|
||||
kip::GetKipData();
|
||||
|
||||
board::FuseData *fuse = board::GetFuseData();
|
||||
|
||||
gContext.speedos[HocClkSpeedo_CPU] = fuse->cpuSpeedo;
|
||||
|
||||
18
build.sh
18
build.sh
@@ -3,6 +3,7 @@
|
||||
EXT=0
|
||||
LDR_MAKE="nx_release"
|
||||
NO_EXO=0
|
||||
JOBS=""
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
DIST_DIR="$ROOT_DIR/dist"
|
||||
@@ -18,6 +19,13 @@ while [ $# -gt 0 ]; do
|
||||
--no-exo)
|
||||
NO_EXO=1
|
||||
;;
|
||||
-j)
|
||||
shift
|
||||
JOBS="$1"
|
||||
;;
|
||||
-j*)
|
||||
JOBS="${1#-j}"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
@@ -39,6 +47,8 @@ fi
|
||||
|
||||
CORES="$(nproc --all)"
|
||||
echo "CORES: $CORES"
|
||||
JOBS="${JOBS:-$CORES}"
|
||||
echo "JOBS: $JOBS"
|
||||
|
||||
SRC="Source/Atmosphere/stratosphere/loader/"
|
||||
|
||||
@@ -88,7 +98,7 @@ fi
|
||||
echo
|
||||
echo "*** Compiling loader ***"
|
||||
cd build/atmosphere/stratosphere/loader || exit 1
|
||||
make -j$CORES "$LDR_MAKE"
|
||||
make -j$JOBS "$LDR_MAKE"
|
||||
hactool -t kip1 "out/nintendo_nx_arm64_armv8a/$LDR_BUILD_PATH/loader.kip" --uncompress=hoc.kip
|
||||
cd "$ROOT_DIR" # exit
|
||||
cp -v build/atmosphere/stratosphere/loader/hoc.kip dist/atmosphere/kips/hoc.kip
|
||||
@@ -97,7 +107,7 @@ if [ "$NO_EXO" -eq 0 ]; then
|
||||
echo
|
||||
echo "*** Compiling exosphere ***"
|
||||
cd build/atmosphere/exosphere
|
||||
make -j$CORES
|
||||
make -j$JOBS
|
||||
cd "$ROOT_DIR"
|
||||
cp -v build/atmosphere/exosphere/out/nintendo_nx_arm64_armv8a/release/exosphere.bin dist/atmosphere/exosphere.bin
|
||||
fi
|
||||
@@ -131,7 +141,7 @@ if [ "$EXT" -eq 1 ]; then
|
||||
cd hekate/
|
||||
echo
|
||||
echo "*** Compiling custom Hekate ***"
|
||||
make -j$CORES
|
||||
make -j$JOBS
|
||||
echo
|
||||
|
||||
mkdir -p "$DIST_DIR/bootloader/sys/"
|
||||
@@ -142,7 +152,7 @@ if [ "$EXT" -eq 1 ]; then
|
||||
cd "$ROOT_DIR"/Source/Benchmark-Toolbox
|
||||
echo
|
||||
echo "*** Compiling Benchmark-Toolbox ***"
|
||||
make -j$CORES
|
||||
make -j$JOBS
|
||||
cp -v Benchmark-Toolbox.nro "$DIST_DIR"/switch/Benchmark-Toolbox.nro
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user