- Fixed gpu_hz_list typo in governor (#46)

- Parse loader.kip config from { "/", "/atmosphere/", "/atmosphere/kips/", "/bootloader/" } (#44)
This commit is contained in:
KazushiM
2022-10-31 00:43:40 +08:00
parent 524247955f
commit 859841ab8e
20 changed files with 232 additions and 115 deletions

View File

@@ -60,8 +60,6 @@ ClockManager::ClockManager()
this->oc->systemCoreBoostCPU = false;
this->oc->governor = false;
this->oc->realProfile = SysClkProfile_Handheld;
this->oc->maxMEMFreq = 0;
this->oc->boostCPUFreq = 0;
this->rnxSync = new ReverseNXSync;
this->governor = new Governor;
@@ -76,17 +74,6 @@ ClockManager::~ClockManager()
delete this->config;
}
bool ClockManager::IsBoostMode()
{
std::uint32_t confId = this->context->perfConfId;
bool isBoostMode = apmExtIsBoostMode(confId);
if (apmExtIsCPUBoosted(confId) && !this->oc->boostCPUFreq) {
this->oc->boostCPUFreq = std::max(this->context->freqs[SysClkModule_CPU], 1785'000'000U);
this->governor->SetCPUBoostHz(this->oc->boostCPUFreq);
}
return isBoostMode;
}
void ClockManager::SetRunning(bool running)
{
this->running = running;
@@ -127,7 +114,7 @@ uint32_t ClockManager::GetHz(SysClkModule module)
case SysClkModule_MEM:
hz = (mode == ReverseNX_Docked ||
this->oc->realProfile == SysClkProfile_Docked) ?
MAX_MEM_CLOCK : 1600'000'000;
Clocks::maxMemFreq : 1600'000'000;
break;
default:
break;
@@ -138,27 +125,13 @@ uint32_t ClockManager::GetHz(SysClkModule module)
{
/* Considering realProfile frequency limit */
hz = Clocks::GetNearestHz(module, this->oc->realProfile, hz);
if (module == SysClkModule_MEM && hz == MAX_MEM_CLOCK)
{
/* Trigger Max Mem Clock and record it */
if (!this->oc->maxMEMFreq)
{
uint32_t currentHz = Clocks::GetCurrentHz(SysClkModule_MEM);
Clocks::SetHz(SysClkModule_MEM, MAX_MEM_CLOCK);
this->oc->maxMEMFreq = Clocks::GetCurrentHz(SysClkModule_MEM);
Clocks::SetHz(SysClkModule_MEM, currentHz);
}
return this->oc->maxMEMFreq;
}
}
/* Handle CPU Auto Boost, no user-defined hz required */
if (module == SysClkModule_CPU)
{
if (this->oc->systemCoreBoostCPU && hz < this->oc->boostCPUFreq)
return this->oc->boostCPUFreq;
if (this->oc->systemCoreBoostCPU && hz < Clocks::boostCpuFreq)
return Clocks::boostCpuFreq;
if (!hz)
/* Trigger RefreshContext() and Tick(), resetting default CPU frequency */
return 1020'000'000;
@@ -182,7 +155,8 @@ void ClockManager::Tick()
if (hz && hz != this->context->freqs[module] && !this->oc->governor)
{
// Skip setting CPU or GPU clocks in CpuBoostMode if CPU <= boostCPUFreq or GPU >= 76.8MHz
bool skipBoost = IsBoostMode() && ((module == SysClkModule_CPU && hz <= this->oc->boostCPUFreq) || module == SysClkModule_GPU);
bool skipBoost = apmExtIsBoostMode(this->context->perfConfId);
skipBoost &= (module == SysClkModule_CPU && hz <= Clocks::boostCpuFreq) || module == SysClkModule_GPU;
if (!skipBoost) {
FileUtils::LogLine("[mgr] %s clock set : %u.%u MHz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
Clocks::SetHz((SysClkModule)module, hz);
@@ -210,7 +184,7 @@ void ClockManager::WaitForNextTick()
this->GetConfig()->GetConfigValue(SysClkConfigValue_AutoCPUBoost) &&
this->context->enabled &&
this->oc->realProfile != SysClkProfile_Handheld &&
this->context->freqs[SysClkModule_CPU] <= this->oc->boostCPUFreq;
this->context->freqs[SysClkModule_CPU] <= Clocks::boostCpuFreq;
if (boostOK) {
uint32_t core3Util = CpuCoreUtil(3, tickWaitTimeMs * 1000'000ULL).Get();
@@ -222,7 +196,7 @@ void ClockManager::WaitForNextTick()
Clocks::SetHz(SysClkModule_CPU, GetHz(SysClkModule_CPU));
if (!lastBoost && this->oc->systemCoreBoostCPU)
Clocks::SetHz(SysClkModule_CPU, this->oc->boostCPUFreq);
Clocks::SetHz(SysClkModule_CPU, Clocks::boostCpuFreq);
return;
}
@@ -313,7 +287,7 @@ bool ClockManager::RefreshContext()
}
// let ptm module handle boost clocks rather than resetting
if (hasChanged && !IsBoostMode()) {
if (hasChanged && !apmExtIsBoostMode(this->context->perfConfId)) {
Clocks::ResetToStock();
}

View File

@@ -52,7 +52,5 @@ class ClockManager
ReverseNXSync *rnxSync;
Governor *governor;
bool IsBoostMode();
uint32_t GetHz(SysClkModule);
};

View File

@@ -12,6 +12,7 @@
#include <nxExt.h>
#include "clocks.h"
#include "errors.h"
#include "file_utils.h"
void Clocks::GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min, uint32_t** max)
{
@@ -58,18 +59,18 @@ void Clocks::GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min
ERROR_THROW("No such PcvModule: %u", module);
}
Result Clocks::GetTable(SysClkModule module, SysClkProfile profile, size_t max_entry_num, uint32_t* out_table) {
Result Clocks::GetTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table) {
uint32_t* min = NULL;
uint32_t* max = NULL;
memset(out_table, 0, max_entry_num * sizeof(uint32_t));
GetRange(module, profile, &min, &max);
if (!min || !max || (max - min) / sizeof(uint32_t) >= max_entry_num)
if (!min || !max || (max - min) / sizeof(uint32_t) >= sizeof(SysClkFrequencyTable) / sizeof(uint32_t))
return 1;
memset(out_table, 0, sizeof(SysClkFrequencyTable));
uint32_t* p = min;
size_t idx = 0;
while(p <= max)
out_table[idx++] = *p++;
out_table->values[idx++] = *p++;
return 0;
}
@@ -78,7 +79,6 @@ void Clocks::Initialize()
{
Result rc = 0;
// Check if it's Mariko
u64 hardware_type = 0;
rc = splInitialize();
ASSERT_RESULT_OK(rc, "splInitialize");
@@ -89,11 +89,11 @@ void Clocks::Initialize()
switch (hardware_type) {
case 0: // Icosa
case 1: // Copper
case 4: // Calcio
isMariko = false;
break;
case 2: // Hoag
case 3: // Iowa
case 4: // Calcio
case 5: // Aula
isMariko = true;
break;
@@ -127,6 +127,19 @@ void Clocks::Initialize()
rc = tcInitialize();
ASSERT_RESULT_OK(rc, "tcInitialize");
}
FileUtils::ParseLoaderKip();
if (!maxMemFreq) {
uint32_t curr_mem_hz = GetCurrentHz(SysClkModule_MEM);
SetHz(SysClkModule_MEM, MAX_MEM_CLOCK);
svcSleepThread(1'000'000);
if (uint32_t hz = GetCurrentHz(SysClkModule_MEM))
maxMemFreq = hz;
else
maxMemFreq = MAX_MEM_CLOCK;
SetHz(SysClkModule_MEM, curr_mem_hz);
}
}
void Clocks::Exit()
@@ -359,6 +372,9 @@ std::uint32_t Clocks::GetCurrentHz(SysClkModule module)
std::uint32_t Clocks::GetNearestHz(SysClkModule module, SysClkProfile profile, std::uint32_t inHz)
{
if (module == SysClkModule_MEM && inHz == MAX_MEM_CLOCK)
return Clocks::maxMemFreq;
uint32_t* min = NULL;
uint32_t* max = NULL;
GetRange(module, profile, &min, &max);

View File

@@ -18,8 +18,11 @@
class Clocks
{
public:
static inline uint32_t boostCpuFreq = 1785000000;
static inline uint32_t maxMemFreq = MAX_MEM_CLOCK;
static void GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min, uint32_t** max);
static Result GetTable(SysClkModule module, SysClkProfile profile, size_t max_entry_num, uint32_t* out_table);
static Result GetTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table);
static void SetAllowUnsafe(bool allow) { allowUnsafe = allow; };
static bool GetIsMariko() { return isMariko; };
static void Exit();

View File

@@ -11,7 +11,6 @@
#include "file_utils.h"
#include "clocks.h"
#include <dirent.h>
#include <filesystem>
#include <nxExt.h>
static LockableMutex g_log_mutex;
@@ -182,3 +181,126 @@ void FileUtils::Exit()
fsdevUnmountAll();
fsExit();
}
void FileUtils::ParseLoaderKip() {
const char* dirs[] = { "/", "/atmosphere/", "/atmosphere/kips/", "/bootloader/" };
char* full_path = new char[0x200];
for (auto const& dir : dirs) {
struct dirent *entry = NULL;
DIR *dp = opendir(dir);
if (!dp)
continue;
while ((entry = readdir(dp))) {
if (entry->d_type != DT_REG)
continue;
snprintf(full_path, 0x200, "%s%s", dir, entry->d_name);
FILE* fp = fopen(full_path, "r");
if (!fp)
continue;
fseek(fp, 0, SEEK_END);
long res = ftell(fp);
fclose(fp);
if (res == -1)
continue;
size_t filesize = (size_t)res;
if (filesize < 0x1000 || filesize > 512 * 1024)
continue;
const char kip_ext[] = {'.', 'k', 'i', 'p'};
size_t file_name_len = strnlen(reinterpret_cast<const char*>(&entry->d_name), 256);
const char* file_ext = &entry->d_name[file_name_len - sizeof(kip_ext)];
if (strncasecmp((const char*)kip_ext, file_ext, sizeof(kip_ext)))
continue;
if (R_SUCCEEDED(CustParser(full_path, filesize))) {
LogLine("Parsed cust config from %s, maxMemFreq: %u MHz, boostCpuFreq: %u MHz",
full_path,
Clocks::maxMemFreq / 1'000'000,
Clocks::boostCpuFreq / 1'000'000
);
delete[] full_path;
return;
}
}
}
delete[] full_path;
}
Result FileUtils::CustParser(const char* filepath, size_t filesize) {
enum ParseError {
ParseError_Success = 0,
ParseError_OpenReadFailed,
ParseError_WrongKipMagic,
ParseError_CustNotFound,
ParseError_WrongCustRev,
};
FILE* fp = fopen(filepath, "r");
if (!fp)
return ParseError_OpenReadFailed;
constexpr uint8_t KIP_MAGIC[] = {'K', 'I', 'P', '1', 'L', 'o', 'a', 'd', 'e', 'r'};
constexpr size_t BLOCK_SIZE = 0x1000;
char* tmp_block = new char[BLOCK_SIZE];
fread(tmp_block, sizeof(char), BLOCK_SIZE, fp);
if (memcmp(KIP_MAGIC, tmp_block, sizeof(KIP_MAGIC))) {
delete[] tmp_block;
return ParseError_WrongKipMagic;
}
CustTable table {};
fpos_t cust_pos = 0;
long block_pos = 0;
while ((block_pos = ftell(fp)) >= 0 && (size_t)block_pos < filesize) {
for (size_t i = 0; i < BLOCK_SIZE; i += sizeof(table.cust)) {
if (memcmp(table.cust, &tmp_block[i], sizeof(table.cust)))
continue;
fgetpos(fp, &cust_pos);
cust_pos = cust_pos + i - BLOCK_SIZE;
goto found;
}
fread(tmp_block, sizeof(char), BLOCK_SIZE, fp);
}
found:
delete[] tmp_block;
if (!cust_pos) {
fclose(fp);
return ParseError_CustNotFound;
}
memset(reinterpret_cast<void*>(&table), 0, sizeof(CustTable));
fsetpos(fp, &cust_pos);
if (!fread(reinterpret_cast<char*>(&table), 1, sizeof(CustTable), fp)) {
fclose(fp);
return ParseError_OpenReadFailed;
}
fclose(fp);
if (table.custRev != 2)
return ParseError_WrongCustRev;
if (Clocks::GetIsMariko()) {
if (table.marikoCpuBoostClock)
Clocks::boostCpuFreq = table.marikoCpuBoostClock * 1000;
if (table.marikoEmcMaxClock)
Clocks::maxMemFreq = table.marikoEmcMaxClock * 1000;
} else {
if (table.eristaEmcMaxClock)
Clocks::maxMemFreq = table.eristaEmcMaxClock * 1000;
}
return ParseError_Success;
}

View File

@@ -13,6 +13,7 @@
#include <time.h>
#include <vector>
#include <string>
#include <cstring>
#include <atomic>
#include <cstdarg>
#include <sysclk.h>
@@ -34,6 +35,23 @@ class FileUtils
static void InitializeAsync();
static void LogLine(const char *format, ...);
static void WriteContextToCsv(const SysClkContext* context);
static void ParseLoaderKip();
protected:
typedef struct CustTable {
uint8_t cust[4] = {'C', 'U', 'S', 'T'};
uint16_t custRev;
uint16_t mtcConf;
uint32_t marikoCpuMaxClock;
uint32_t marikoCpuBoostClock;
uint32_t marikoCpuMaxVolt;
uint32_t marikoGpuMaxClock;
uint32_t marikoEmcMaxClock;
uint32_t eristaCpuOCEnable;
uint32_t eristaCpuMaxVolt;
uint32_t eristaEmcMaxClock;
uint32_t eristaEmcVolt;
} CustTable;
static void RefreshFlags(bool force);
static Result CustParser(const char* path, size_t filesize);
};

View File

@@ -164,8 +164,8 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8*
if(r->data.size >= sizeof(SysClkIpc_GetFrequencyTable_Args))
{
SysClkIpc_GetFrequencyTable_Args* in_args = (SysClkIpc_GetFrequencyTable_Args*)r->data.ptr;
*out_dataSize = sizeof(uint32_t) * in_args->max_entry_num;
return ipcSrv->GetFrequencyTable(in_args, (uint32_t*)out_data);
*out_dataSize = sizeof(SysClkFrequencyTable);
return ipcSrv->GetFrequencyTable(in_args, (SysClkFrequencyTable*)out_data);
}
break;
case SysClkIpcCmd_GetIsMariko:
@@ -313,8 +313,8 @@ Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) {
return 0;
}
Result IpcService::GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, uint32_t* out_table) {
return Clocks::GetTable(args->module, args->profile, args->max_entry_num, out_table);
Result IpcService::GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, SysClkFrequencyTable* out_table) {
return Clocks::GetTable(args->module, args->profile, out_table);
}
Result IpcService::GetIsMariko(bool* out_is_mariko) {

View File

@@ -37,7 +37,7 @@ class IpcService
Result GetConfigValues(SysClkConfigValueList* out_configValues);
Result SetConfigValues(SysClkConfigValueList* configValues);
Result SetReverseNXRTMode(ReverseNXMode mode);
Result GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, uint32_t* out_table);
Result GetFrequencyTable(SysClkIpc_GetFrequencyTable_Args* args, SysClkFrequencyTable* out_table);
Result GetIsMariko(bool* out_is_mariko);
bool running;

View File

@@ -22,7 +22,7 @@
#include "ipc_service.h"
#include "oc_extra.h"
#define INNER_HEAP_SIZE 0x38000
#define INNER_HEAP_SIZE 0x40000
extern "C"
{

View File

@@ -135,10 +135,10 @@ Governor::Governor() {
m_cpu_freq.module = SysClkModule_CPU;
m_gpu_freq.module = SysClkModule_GPU;
m_cpu_freq.hz_list = &g_freq_table_cpu_hz[0];
m_gpu_freq.hz_list = &g_freq_table_cpu_hz[0];
m_cpu_freq.hz_list = GetTable(SysClkModule_CPU);
m_gpu_freq.hz_list = GetTable(SysClkModule_GPU);
m_cpu_freq.boost_hz = 1785'000'000;
m_cpu_freq.boost_hz = Clocks::boostCpuFreq;
m_cpu_freq.utilref_hz = 2397'000'000;
m_gpu_freq.boost_hz = 76'800'000;
@@ -244,7 +244,7 @@ void Governor::s_FreqContext::SetNextFreq(uint32_t norm_util) {
} else {
uint32_t* p = hz_list;
do {
if (*p > next_freq) {
if (*p >= next_freq) {
adj_next_freq = *p;
break;
}