Improve formating

This commit is contained in:
Lightos1
2026-02-24 09:07:49 +01:00
parent eca6ab2297
commit 29cb868f50
4 changed files with 370 additions and 370 deletions

View File

@@ -22,153 +22,157 @@
namespace ams::ldr::hoc::pcv { namespace ams::ldr::hoc::pcv {
Result MemFreqPllmLimit(u32* ptr) { Result MemFreqPllmLimit(u32* ptr) {
clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr); clk_pll_param* entry = reinterpret_cast<clk_pll_param *>(ptr);
R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry()); R_UNLESS(entry->freq == entry->vco_max, ldr::ResultInvalidMemPllmEntry());
// Double the max clk simply // Double the max clk simply
u32 max_clk = entry->freq * 2; u32 max_clk = entry->freq * 2;
entry->freq = max_clk; entry->freq = max_clk;
entry->vco_max = max_clk; entry->vco_max = max_clk;
R_SUCCEED();
}
Result MemVoltHandler(u32* ptr) {
// ptr value might be default_uv or max_uv
regulator* entries[2] = {
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.default_uv)),
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
};
constexpr u32 uv_step = 12'500;
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());
R_SUCCEED(); R_SUCCEED();
};
regulator* entry = nullptr;
for (auto& i : entries) {
if (R_SUCCEEDED(validator(i)))
entry = i;
} }
R_UNLESS(entry, ldr::ResultInvalidRegulatorEntry()); Result MemVoltHandler(u32* ptr) {
// ptr value might be default_uv or max_uv
regulator* entries[2] = {
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.default_uv)),
reinterpret_cast<regulator *>(reinterpret_cast<u8 *>(ptr) - offsetof(regulator, type_1.max_uv)),
};
u32 emc_uv = C.commonEmcMemVolt; constexpr u32 uv_step = 12'500;
if (!emc_uv) constexpr u32 uv_min = 600'000;
R_SKIP();
if (emc_uv % uv_step)
emc_uv = emc_uv / uv_step * uv_step; // rounding
PATCH_OFFSET(ptr, emc_uv);
R_SUCCEED();
}
void SafetyCheck() {
// if (C.custRev != CUST_REV)
// CRASH("Triggered");
struct sValidator {
volatile u32 value;
u32 min;
u32 max;
bool value_required = false;
Result check() {
if (!value_required && !value)
R_SUCCEED();
if (min && value < min)
R_THROW(ldr::ResultSafetyCheckFailure());
if (max && value > max)
R_THROW(ldr::ResultSafetyCheckFailure());
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(); R_SUCCEED();
};
regulator* entry = nullptr;
for (auto& i : entries) {
if (R_SUCCEEDED(validator(i))) {
entry = i;
}
} }
};
u32 eristaCpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaCpuDvfsTable)->freq); R_UNLESS(entry, ldr::ResultInvalidRegulatorEntry());
u32 marikoCpuDvfsMaxFreq;
if (C.marikoCpuUVHigh) { u32 emc_uv = C.commonEmcMemVolt;
marikoCpuDvfsMaxFreq = static_cast<u32>( if (!emc_uv) {
GetDvfsTableLastEntry(C.marikoCpuDvfsTableSLT)->freq R_SKIP();
);
} else {
marikoCpuDvfsMaxFreq = static_cast<u32>(
GetDvfsTableLastEntry(C.marikoCpuDvfsTable)->freq
);
} }
u32 eristaGpuDvfsMaxFreq;
switch (C.eristaGpuUV) if (emc_uv % uv_step) {
{ emc_uv = emc_uv / uv_step * uv_step; // rounding
case 0: }
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
break; PATCH_OFFSET(ptr, emc_uv);
case 1:
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq); R_SUCCEED();
break;
case 2:
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
break;
default:
eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
break;
} }
u32 marikoGpuDvfsMaxFreq; void SafetyCheck() {
switch (C.marikoGpuUV) { // if (C.custRev != CUST_REV)
// CRASH("Triggered");
struct sValidator {
volatile u32 value;
u32 min;
u32 max;
bool value_required = false;
Result check() {
if (!value_required && !value)
R_SUCCEED();
if (min && value < min)
R_THROW(ldr::ResultSafetyCheckFailure());
if (max && value > max)
R_THROW(ldr::ResultSafetyCheckFailure());
R_SUCCEED();
}
};
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
);
}
u32 eristaGpuDvfsMaxFreq;
switch (C.eristaGpuUV) {
case 0: case 0:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq); eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
break; break;
case 1: case 1:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableSLT)->freq); eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableSLT)->freq);
break; break;
case 2: case 2:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq); eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTableHiOPT)->freq);
break; break;
default: default:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq); eristaGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.eristaGpuDvfsTable)->freq);
break; break;
}
u32 marikoGpuDvfsMaxFreq;
switch (C.marikoGpuUV) {
case 0:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
break;
case 1:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableSLT)->freq);
break;
case 2:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTableHiOPT)->freq);
break;
default:
marikoGpuDvfsMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(C.marikoGpuDvfsTable)->freq);
break;
}
using namespace ams::ldr::hoc::pcv;
sValidator validators[] = {
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true },
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true },
{ C.commonEmcMemVolt, 912'500, 1350'000 }, // Official burst vmax for the RAMs is 1500mV
{ C.eristaCpuMaxVolt, 1000, 1257 },
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000 },
{ C.marikoCpuMaxVolt, 1000, 1235 },
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
{ C.marikoEmcVddqVolt, 250'000, 700'000 },
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000 },
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000 },
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000 },
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000 },
};
for (auto& i : validators) {
if (R_FAILED(i.check())) {
CRASH("Validation FAIL");
}
}
} }
using namespace ams::ldr::hoc::pcv; void Patch(uintptr_t mapped_nso, size_t nso_size) {
sValidator validators[] = { #ifdef ATMOSPHERE_IS_STRATOSPHERE
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true }, SafetyCheck();
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true }, bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
{ C.commonEmcMemVolt, 912'500, 1350'000 }, // Official burst vmax for the RAMs is 1500mV if (isMariko)
{ C.eristaCpuMaxVolt, 1000, 1257 }, mariko::Patch(mapped_nso, nso_size);
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000 }, else
{ C.marikoCpuMaxVolt, 1000, 1235 }, erista::Patch(mapped_nso, nso_size);
{ C.marikoEmcMaxClock, 1600'000, 3500'000 }, #endif
{ C.marikoEmcVddqVolt, 250'000, 700'000 },
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000 },
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000 },
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000 },
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000 },
};
for (auto& i : validators) {
if (R_FAILED(i.check()))
CRASH("Validation FAIL");
} }
}
void Patch(uintptr_t mapped_nso, size_t nso_size) {
#ifdef ATMOSPHERE_IS_STRATOSPHERE
SafetyCheck();
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
if (isMariko)
mariko::Patch(mapped_nso, nso_size);
else
erista::Patch(mapped_nso, nso_size);
#endif
}
} }

View File

@@ -16,153 +16,154 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
namespace ams::ldr::hoc::pcv { namespace ams::ldr::hoc::pcv {
typedef struct cvb_coefficients { typedef struct cvb_coefficients {
s32 c0 = 0; s32 c0 = 0;
s32 c1 = 0; s32 c1 = 0;
s32 c2 = 0; s32 c2 = 0;
s32 c3 = 0; s32 c3 = 0;
s32 c4 = 0; s32 c4 = 0;
s32 c5 = 0; s32 c5 = 0;
} cvb_coefficients; } cvb_coefficients;
typedef struct cvb_entry_t { typedef struct cvb_entry_t {
u64 freq; u64 freq;
cvb_coefficients cvb_dfll_param; cvb_coefficients cvb_dfll_param;
cvb_coefficients cvb_pll_param; cvb_coefficients cvb_pll_param;
} cvb_entry_t; } cvb_entry_t;
static_assert(sizeof(cvb_entry_t) == 0x38); static_assert(sizeof(cvb_entry_t) == 0x38);
typedef struct cvb_cpu_dfll_data { typedef struct cvb_cpu_dfll_data {
u32 tune0_low; u32 tune0_low;
u32 tune0_high; u32 tune0_high;
u32 tune1_low; u32 tune1_low;
u32 tune1_high; u32 tune1_high;
unsigned int tune_high_min_millivolts; unsigned int tune_high_min_millivolts;
unsigned int tune_high_margin_millivolts; unsigned int tune_high_margin_millivolts;
unsigned long dvco_calibration_max; unsigned long dvco_calibration_max;
} cvb_cpu_dfll_data; } cvb_cpu_dfll_data;
typedef struct emc_dvb_dvfs_table_t { typedef struct emc_dvb_dvfs_table_t {
u64 freq; u64 freq;
s32 volt[4] = {0}; s32 volt[4] = {0};
} emc_dvb_dvfs_table_t; } emc_dvb_dvfs_table_t;
typedef struct __attribute__((packed)) div_nmp { typedef struct __attribute__((packed)) div_nmp {
u8 divn_shift; u8 divn_shift;
u8 divn_width; u8 divn_width;
u8 divm_shift; u8 divm_shift;
u8 divm_width; u8 divm_width;
u8 divp_shift; u8 divp_shift;
u8 divp_width; u8 divp_width;
u8 override_divn_shift; u8 override_divn_shift;
u8 override_divm_shift; u8 override_divm_shift;
u8 override_divp_shift; u8 override_divp_shift;
} div_nmp; } div_nmp;
typedef struct __attribute__((packed)) clk_pll_param { typedef struct __attribute__((packed)) clk_pll_param {
u32 freq; u32 freq;
u32 input_min; u32 input_min;
u32 input_max; u32 input_max;
u32 cf_min; u32 cf_min;
u32 cf_max; u32 cf_max;
u32 vco_min; u32 vco_min;
u32 vco_max; u32 vco_max;
s32 lock_delay; s32 lock_delay;
u32 fixed_rate; u32 fixed_rate;
u32 unk_0; u32 unk_0;
struct div_nmp *div_nmp; struct div_nmp *div_nmp;
u32 unk_1[4]; u32 unk_1[4];
void (*unk_fn)(u64* unk_struct); // set_defaults? void (*unk_fn)(u64* unk_struct); // set_defaults?
} clk_pll_param; } clk_pll_param;
typedef struct __attribute__((packed)) dvfs_rail { typedef struct __attribute__((packed)) dvfs_rail {
u32 id; u32 id;
u32 unk_0[5]; u32 unk_0[5];
u32 freq; u32 freq;
u32 unk_1[8]; u32 unk_1[8];
u32 unk_flag; u32 unk_flag;
u32 min_mv; u32 min_mv;
u32 step_mv; u32 step_mv;
u32 max_mv; u32 max_mv;
u32 unk_2[11]; u32 unk_2[11];
} dvfs_rail; } dvfs_rail;
typedef struct __attribute__((packed)) regulator { typedef struct __attribute__((packed)) regulator {
u64 id; u64 id;
const char* name; const char* name;
u32 type; u32 type;
union { union {
struct { struct {
u32 volt_reg; u32 volt_reg;
u32 step_uv; u32 step_uv;
u32 min_uv; u32 min_uv;
u32 default_uv; u32 default_uv;
u32 max_uv; u32 max_uv;
u32 unk_0[2]; u32 unk_0[2];
} type_1; } type_1;
struct { struct {
u32 unk_0; u32 unk_0;
u32 step_uv; u32 step_uv;
u32 unk_1; u32 unk_1;
u32 min_uv; u32 min_uv;
u32 max_uv; u32 max_uv;
u32 unk_2; u32 unk_2;
u32 default_uv; u32 default_uv;
} type_2_3; } type_2_3;
}; };
u32 unk_x[60]; u32 unk_x[60];
} regulator; } regulator;
static_assert(sizeof(regulator) == 0x120); static_assert(sizeof(regulator) == 0x120);
constexpr u32 CpuClkOSLimit = 1785'000; constexpr u32 CpuClkOSLimit = 1785'000;
constexpr u32 EmcClkOSLimit = 1600'000; constexpr u32 EmcClkOSLimit = 1600'000;
#define R_SKIP() R_SUCCEED() #define R_SKIP() R_SUCCEED()
// Count 32 / Index 31 is reserved to be empty // Count 32 / Index 31 is reserved to be empty
constexpr size_t DvfsTableEntryCount = 32; constexpr size_t DvfsTableEntryCount = 32;
constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1; constexpr size_t DvfsTableEntryLimit = DvfsTableEntryCount - 1;
template<typename T> template<typename T>
size_t GetDvfsTableEntryCount(T* table_head) { size_t GetDvfsTableEntryCount(T* table_head) {
using NT = std::remove_const_t<std::remove_volatile_t<T>>; using NT = std::remove_const_t<std::remove_volatile_t<T>>;
auto is_empty = [](NT* entry) { auto is_empty = [](NT* entry) {
uint8_t* m = reinterpret_cast<uint8_t *>(entry); uint8_t* m = reinterpret_cast<uint8_t *>(entry);
for (size_t i = 0; i < sizeof(NT); i++) { for (size_t i = 0; i < sizeof(NT); i++) {
if (*(m + i)) if (*(m + i)) {
return false; return false;
} }
return true; }
}; return true;
};
NT* table = const_cast<NT *>(table_head); NT* table = const_cast<NT *>(table_head);
size_t count = 0; size_t count = 0;
while (count < DvfsTableEntryLimit) { while (count < DvfsTableEntryLimit) {
if (is_empty(table++)) { if (is_empty(table++)) {
return count; return count;
} }
count++; count++;
} }
return DvfsTableEntryLimit; return DvfsTableEntryLimit;
} }
template<typename T> template<typename T>
T* GetDvfsTableLastEntry(T* table_head) { T* GetDvfsTableLastEntry(T* table_head) {
using NT = std::remove_const_t<std::remove_volatile_t<T>>; using NT = std::remove_const_t<std::remove_volatile_t<T>>;
NT* table = const_cast<NT *>(table_head); NT* table = const_cast<NT *>(table_head);
size_t count = GetDvfsTableEntryCount(table_head); size_t count = GetDvfsTableEntryCount(table_head);
if (!count) { if (!count) {
return nullptr; return nullptr;
} }
size_t index = count - 1; size_t index = count - 1;
return table + index; return table + index;
} }
} }

View File

@@ -20,116 +20,111 @@
namespace ams::ldr::hoc::ptm { namespace ams::ldr::hoc::ptm {
Result CpuPtmBoost(perf_conf_entry* entry) { Result CpuPtmBoost(perf_conf_entry* entry) {
#ifdef ATMOSPHERE_IS_STRATOSPHERE
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
#else
bool isMariko = true;
#endif
#ifdef ATMOSPHERE_IS_STRATOSPHERE if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock) {
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko); R_SUCCEED();
#else }
bool isMariko = true;
#endif u32 cpuPtmBoostNew = isMariko ? C.marikoCpuBoostClock * 1000 : C.eristaCpuBoostClock * 1000;
PATCH_OFFSET(&(entry->cpu_freq_1), cpuPtmBoostNew);
PATCH_OFFSET(&(entry->cpu_freq_2), cpuPtmBoostNew);
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock)
R_SUCCEED(); R_SUCCEED();
u32 cpuPtmBoostNew = isMariko ? C.marikoCpuBoostClock * 1000 : C.eristaCpuBoostClock * 1000;
PATCH_OFFSET(&(entry->cpu_freq_1), cpuPtmBoostNew);
PATCH_OFFSET(&(entry->cpu_freq_2), cpuPtmBoostNew);
R_SUCCEED();
}
Result MemPtm(perf_conf_entry* entry) {
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
R_SUCCEED();
}
bool PtmEntryIsValid(perf_conf_entry* entry) {
return (entry->cpu_freq_1 == entry->cpu_freq_2 &&
entry->gpu_freq_1 == entry->gpu_freq_2 &&
entry->emc_freq_1 == entry->emc_freq_2);
}
bool PtmTablePatternFn(u32* ptr) {
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
if (!PtmEntryIsValid(entry))
return false;
return entry->cpu_freq_1 == cpuPtmDefault;
}
void Patch(uintptr_t mapped_nso, size_t nso_size) {
perf_conf_entry* confTable = nullptr;
for (uintptr_t ptr = mapped_nso;
ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt;
ptr += sizeof(u32))
{
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
if (PtmTablePatternFn(ptr32)) {
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
break;
}
} }
if (!confTable) { Result MemPtm(perf_conf_entry* entry) {
CRASH("confTable not found!"); PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
R_SUCCEED();
} }
PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, }; bool PtmEntryIsValid(perf_conf_entry* entry) {
PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, }; return (entry->cpu_freq_1 == entry->cpu_freq_2 && entry->gpu_freq_1 == entry->gpu_freq_2 && entry->emc_freq_1 == entry->emc_freq_2);
}
#ifdef ATMOSPHERE_IS_STRATOSPHERE
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
#else
bool isMariko = true;
#endif
for (u32 i = 0; i < entryCnt; i++) {
perf_conf_entry* entry = confTable + i;
bool PtmTablePatternFn(u32* ptr) {
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
if (!PtmEntryIsValid(entry)) { if (!PtmEntryIsValid(entry)) {
LOGGING("@%p", &entry); return false;
CRASH("Invalid ptm confTable entry");
} }
switch (entry->cpu_freq_1) { return entry->cpu_freq_1 == cpuPtmDefault;
case cpuPtmBoost: }
cpuPtmBoostPatch.Apply(entry);
void Patch(uintptr_t mapped_nso, size_t nso_size) {
perf_conf_entry* confTable = nullptr;
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt; ptr += sizeof(u32)) {
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
if (PtmTablePatternFn(ptr32)) {
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
break; break;
case cpuPtmDefault: }
case cpuPtmDevOC:
break;
default:
LOGGING("%u (0x%08x) @%p", entry->cpu_freq_1, entry->conf_id, &(entry->cpu_freq_1));
CRASH("Unknown CPU Freq");
} }
switch (entry->emc_freq_1) { if (!confTable) {
case memPtmLimit: CRASH("confTable not found!");
case memPtmAlt: }
case memPtmClamp:
if (isMariko) { PatcherEntry<perf_conf_entry> cpuPtmBoostPatch = { "CPU Ptm Boost", &CpuPtmBoost, 2, };
memPtmPatch.Apply(entry); PatcherEntry<perf_conf_entry> memPtmPatch = { "MEM Ptm", &MemPtm, 16, };
}
break; #ifdef ATMOSPHERE_IS_STRATOSPHERE
default: bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
LOGGING("%u (0x%08x) @%p", entry->emc_freq_1, entry->conf_id, &(entry->emc_freq_2)); #else
CRASH("Unknown MEM Freq"); bool isMariko = true;
#endif
for (u32 i = 0; i < entryCnt; i++) {
perf_conf_entry *entry = confTable + i;
if (!PtmEntryIsValid(entry)) {
LOGGING("@%p", &entry);
CRASH("Invalid ptm confTable entry");
}
switch (entry->cpu_freq_1) {
case cpuPtmBoost:
cpuPtmBoostPatch.Apply(entry);
break;
case cpuPtmDefault:
case cpuPtmDevOC:
break;
default:
LOGGING("%u (0x%08x) @%p", entry->cpu_freq_1, entry->conf_id, &(entry->cpu_freq_1));
CRASH("Unknown CPU Freq");
}
switch (entry->emc_freq_1) {
case memPtmLimit:
case memPtmAlt:
case memPtmClamp:
if (isMariko) {
memPtmPatch.Apply(entry);
}
break;
default:
LOGGING("%u (0x%08x) @%p", entry->emc_freq_1, entry->conf_id, &(entry->emc_freq_2));
CRASH("Unknown MEM Freq");
}
}
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
CRASH(cpuPtmBoostPatch.description);
if (isMariko) {
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
if (R_FAILED(memPtmPatch.CheckResult()))
CRASH(memPtmPatch.description);
} }
} }
LOGGING("%s Count: %zu", cpuPtmBoostPatch.description, cpuPtmBoostPatch.patched_count);
if (R_FAILED(cpuPtmBoostPatch.CheckResult()))
CRASH(cpuPtmBoostPatch.description);
if (isMariko) {
LOGGING("%s Count: %zu", memPtmPatch.description, memPtmPatch.patched_count);
if (R_FAILED(memPtmPatch.CheckResult()))
CRASH(memPtmPatch.description);
}
}
} }

View File

@@ -22,26 +22,26 @@
namespace ams::ldr::hoc::ptm { namespace ams::ldr::hoc::ptm {
typedef struct { typedef struct {
u32 conf_id; u32 conf_id;
u32 cpu_freq_1; // min-max pair? u32 cpu_freq_1; // min-max pair?
u32 cpu_freq_2; u32 cpu_freq_2;
u32 gpu_freq_1; u32 gpu_freq_1;
u32 gpu_freq_2; u32 gpu_freq_2;
u32 emc_freq_1; u32 emc_freq_1;
u32 emc_freq_2; u32 emc_freq_2;
u32 padding; u32 padding;
} perf_conf_entry; } perf_conf_entry;
constexpr u32 entryCnt = 16; constexpr u32 entryCnt = 16;
constexpr u32 cpuPtmDefault = 1020'000'000; constexpr u32 cpuPtmDefault = 1020'000'000;
constexpr u32 cpuPtmDevOC = 1224'000'000; constexpr u32 cpuPtmDevOC = 1224'000'000;
constexpr u32 cpuPtmBoost = 1785'000'000; constexpr u32 cpuPtmBoost = 1785'000'000;
constexpr u32 memPtmLimit = 1600'000'000; constexpr u32 memPtmLimit = 1600'000'000;
constexpr u32 memPtmAlt = 1331'200'000; constexpr u32 memPtmAlt = 1331'200'000;
constexpr u32 memPtmClamp = 1065'600'000; constexpr u32 memPtmClamp = 1065'600'000;
void Patch(uintptr_t mapped_nso, size_t nso_size); void Patch(uintptr_t mapped_nso, size_t nso_size);
} }