13 Commits
1.0.1 ... 1.0.2

Author SHA1 Message Date
souldbminersmwc
9558fd67bb update binaries 2026-03-17 20:33:19 -04:00
souldbminersmwc
59b62a835b misc: fix config bug 2026-03-17 20:30:33 -04:00
souldbminersmwc
ad6847ec59 Update zh-tw.json 2026-03-16 18:38:04 -04:00
Lightos1
061c255978 Change eristaCpuDvfsTable max to 2091, this is fine because vmax exists 2026-03-16 20:04:23 +01:00
Lightos1
bb44d0907d Fix dvfs yet again, todo make this not shit 2026-03-16 20:01:52 +01:00
Lightos1
2215b17a54 Merge pull request #45 from nangongjing1/main
Incorporate Traditional Chinese into Horizon-oc-overlay.
2026-03-16 16:18:46 +01:00
南宫镜
cc52eab3f6 Add files via upload 2026-03-16 23:13:15 +08:00
Lightos1
155a4ce50a Remove redundant else 2026-03-15 21:24:35 +01:00
Lightos1
17739377bd Fix Typo, add todo and ordering cleanup 2026-03-15 21:14:52 +01:00
Lightos1
782fae1624 minimum vmax = 800 2026-03-15 20:49:56 +01:00
Lightos1
59ca1f18d6 Add modified secmon_smc_handler.cpp for panic codes in loader 2026-03-15 20:44:25 +01:00
Lightos1
c6cda6eb30 Remove soctherm region unlock 2026-03-15 20:43:31 +01:00
Lightos1
9f3c5d8de6 Add debug panic codes 2026-03-15 20:35:45 +01:00
23 changed files with 631 additions and 1124 deletions

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define __ACCESS_TABLE_NAME__ SocthermAccessTable
#define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceSoctherm.GetAddress()
#define __ACCESS_TABLE_INC__ "secmon_soctherm_access_table_data.inc"
#include "secmon_define_access_table.inc"
#undef __ACCESS_TABLE_INC__
#undef __ACCESS_TABLE_ADDRESS__
#undef __ACCESS_TABLE_NAME__

View File

@@ -123,7 +123,7 @@ namespace ams::secmon {
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCode = MemoryRegion(UINT64_C(0x40020000), 0x20000);
static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramBootCode));
constexpr inline const MemoryRegion MemoryRegionVirtualDevice = MemoryRegion(UINT64_C(0x1F0040000), UINT64_C(0x40000 + 0x2000));
constexpr inline const MemoryRegion MemoryRegionVirtualDevice = MemoryRegion(UINT64_C(0x1F0040000), UINT64_C(0x40000));
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDevice));
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceEmpty = MemoryRegion(MemoryRegionVirtualDevice.GetStartAddress(), 0);
@@ -155,9 +155,6 @@ namespace ams::secmon {
HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(Soctherm, MipiCal, UINT64_C(0x700E2000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExternalMemoryController1, Soctherm, UINT64_C(0x7001e000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
HANDLER(ExternalMemoryController2, ExternalMemoryController1, UINT64_C(0x7001f000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
#define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \

View File

@@ -0,0 +1,268 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "../secmon_misc.hpp"
#include "secmon_smc_common.hpp"
#include "secmon_smc_handler.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_carveout.hpp"
#include "secmon_smc_device_unique_data.hpp"
#include "secmon_smc_error.hpp"
#include "secmon_smc_info.hpp"
#include "secmon_smc_memory_access.hpp"
#include "secmon_smc_power_management.hpp"
#include "secmon_smc_random.hpp"
#include "secmon_smc_register_access.hpp"
#include "secmon_smc_result.hpp"
#include "secmon_smc_rsa.hpp"
namespace ams::secmon::smc {
namespace {
struct HandlerInfo {
u32 function_id;
u32 restriction_mask;
SmcHandler handler;
};
struct HandlerTable {
const HandlerInfo *entries;
size_t count;
};
enum HandlerType : int {
HandlerType_User = 0,
HandlerType_Kern = 1,
HandlerType_Count = 2,
};
enum Restriction {
Restriction_None = (0 << 0),
Restriction_Normal = (1 << 0),
Restriction_DeviceUniqueDataNotAllowed = (1 << 1),
Restriction_SafeModeNotAllowed = (1 << 2),
};
enum SmcCallRange {
SmcCallRange_ArmArch = 0,
SmcCallRange_Cpu = 1,
SmcCallRange_Sip = 2,
SmcCallRange_Oem = 3,
SmcCallRange_Standard = 4,
SmcCallRange_TrustedApp = 0x30,
};
enum SmcArgumentType {
ArgumentType_Integer = 0,
ArgumentType_Pointer = 1,
};
enum SmcConvention {
Convention_Smc32 = 0,
Convention_Smc64 = 1,
};
enum SmcCallType {
SmcCallType_YieldingCall = 0,
SmcCallType_FastCall = 1,
};
struct SmcFunctionId {
using FunctionId = util::BitPack64::Field< 0, 8, u32>;
using ArgumentType0 = util::BitPack64::Field< 8, 1, SmcArgumentType>;
using ArgumentType1 = util::BitPack64::Field< 9, 1, SmcArgumentType>;
using ArgumentType2 = util::BitPack64::Field<10, 1, SmcArgumentType>;
using ArgumentType3 = util::BitPack64::Field<11, 1, SmcArgumentType>;
using ArgumentType4 = util::BitPack64::Field<12, 1, SmcArgumentType>;
using ArgumentType5 = util::BitPack64::Field<13, 1, SmcArgumentType>;
using ArgumentType6 = util::BitPack64::Field<14, 1, SmcArgumentType>;
using ArgumentType7 = util::BitPack64::Field<15, 1, SmcArgumentType>;
using Reserved = util::BitPack64::Field<16, 8, u32>;
using CallRange = util::BitPack64::Field<24, 6, SmcCallRange>;
using Convention = util::BitPack64::Field<30, 1, SmcConvention>;
using CallType = util::BitPack64::Field<31, 1, SmcCallType>;
using Reserved2 = util::BitPack64::Field<32, 32, u32>;
};
constinit HandlerInfo g_user_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC3000401, Restriction_SafeModeNotAllowed, SmcSetConfig },
{ 0xC3000002, Restriction_Normal, SmcGetConfigUser },
{ 0xC3000003, Restriction_Normal, SmcGetResult },
{ 0xC3000404, Restriction_Normal, SmcGetResultData },
{ 0xC3000E05, Restriction_SafeModeNotAllowed, SmcModularExponentiate },
{ 0xC3000006, Restriction_Normal, SmcGenerateRandomBytes },
{ 0xC3000007, Restriction_Normal, SmcGenerateAesKek },
{ 0xC3000008, Restriction_Normal, SmcLoadAesKey },
{ 0xC3000009, Restriction_Normal, SmcComputeAes },
{ 0xC300000A, Restriction_Normal, SmcGenerateSpecificAesKey },
{ 0xC300040B, Restriction_Normal, SmcComputeCmac },
{ 0xC300D60C, Restriction_Normal, SmcReencryptDeviceUniqueData },
{ 0xC300100D, Restriction_DeviceUniqueDataNotAllowed, SmcDecryptDeviceUniqueData },
{ 0xC300000E, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC300060F, Restriction_DeviceUniqueDataNotAllowed, SmcModularExponentiateByStorageKey },
{ 0xC3000610, Restriction_SafeModeNotAllowed, SmcPrepareEsDeviceUniqueKey },
{ 0xC3000011, Restriction_SafeModeNotAllowed, SmcLoadPreparedAesKey },
{ 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonTitleKey }
};
/* Deprecated handlerss. */
constexpr inline const HandlerInfo DecryptAndImportEsDeviceKeyHandlerInfo = {
0xC300100C, Restriction_Normal, SmcDecryptAndImportEsDeviceKey
};
constexpr inline const HandlerInfo DecryptAndImportLotusKeyHandlerInfo = {
0xC300100E, Restriction_SafeModeNotAllowed, SmcDecryptAndImportLotusKey
};
constinit HandlerInfo g_kern_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC4000001, Restriction_SafeModeNotAllowed, SmcSuspendCpu },
{ 0x84000002, Restriction_SafeModeNotAllowed, SmcPowerOffCpu },
{ 0xC4000003, Restriction_SafeModeNotAllowed, SmcPowerOnCpu },
{ 0xC3000004, Restriction_Normal, SmcGetConfigKern },
{ 0xC3000005, Restriction_Normal, SmcGenerateRandomBytesNonBlocking },
{ 0xC3000006, Restriction_Normal, SmcShowError },
{ 0xC3000007, Restriction_Normal, SmcSetKernelCarveoutRegion },
{ 0xC3000008, Restriction_Normal, SmcReadWriteRegister },
/* NOTE: Atmosphere extension for mesosphere. This ID is subject to change at any time. */
{ 0xC3000409, Restriction_Normal, SmcSetConfig },
};
constinit HandlerInfo g_ams_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xF0000201, Restriction_None, SmcIramCopy },
{ 0xF0000002, Restriction_None, SmcReadWriteRegister },
{ 0xF0000003, Restriction_None, SmcWriteAddress },
{ 0xF0000404, Restriction_None, SmcGetEmummcConfig },
{ 0xF0000005, Restriction_None, SmcShowError },
};
constexpr const HandlerInfo GetSecureDataHandlerInfo = {
0x67891234, Restriction_None, SmcGetSecureData
};
constinit HandlerTable g_handler_tables[] = {
{ g_user_handlers, util::size(g_user_handlers) },
{ g_kern_handlers, util::size(g_kern_handlers) },
};
constinit HandlerTable g_ams_handler_table = {
g_ams_handlers, util::size(g_ams_handlers)
};
NORETURN void InvalidSmcError(u64 id) {
SetError(pkg1::ErrorInfo_UnknownSmc);
AMS_ABORT("Invalid SMC: %lx", id);
}
const HandlerTable &GetHandlerTable(HandlerType type, u64 id) {
/* Ensure we have a valid handler type. */
if (AMS_UNLIKELY(!(0 <= type && type < HandlerType_Count))) {
InvalidSmcError(id);
}
/* Provide support for legacy SmcGetSecureData. */
if (id == GetSecureDataHandlerInfo.function_id) {
return g_handler_tables[HandlerType_User];
}
/* Check if we're a user SMC. */
if (type == HandlerType_User) {
/* Nintendo uses OEM SMCs. */
/* We will assign Atmosphere extension SMCs the TrustedApplication range. */
if (util::BitPack64{id}.Get<SmcFunctionId::CallRange>() == SmcCallRange_TrustedApp) {
return g_ams_handler_table;
}
/* If we're not performing an atmosphere extension smc, require that we're being invoked by spl on core 3. */
if (AMS_UNLIKELY(hw::GetCurrentCoreId() != 3)) {
InvalidSmcError(id);
}
}
return g_handler_tables[type];
}
const HandlerInfo &GetHandlerInfo(const HandlerTable &table, u64 id) {
/* Provide support for legacy SmcGetSecureData. */
if (id == GetSecureDataHandlerInfo.function_id) {
return GetSecureDataHandlerInfo;
}
/* Get and check the index. */
const auto index = util::BitPack64{id}.Get<SmcFunctionId::FunctionId>();
if (AMS_UNLIKELY(index >= table.count)) {
InvalidSmcError(id);
}
/* Get and check the handler info. */
const auto &handler_info = table.entries[index];
/* Check that the handler isn't null. */
if (AMS_UNLIKELY(handler_info.handler == nullptr)) {
InvalidSmcError(id);
}
/* Check that the handler's id matches. */
if (AMS_UNLIKELY(handler_info.function_id != id)) {
InvalidSmcError(id);
}
return handler_info;
}
bool IsHandlerRestricted(const HandlerInfo &info) {
return (info.restriction_mask & secmon::GetRestrictedSmcMask()) != 0;
}
SmcResult InvokeSmcHandler(const HandlerInfo &info, SmcArguments &args) {
/* Check if the smc is restricted. */
if (GetTargetFirmware() >= TargetFirmware_8_0_0 && AMS_UNLIKELY(IsHandlerRestricted(info))) {
return SmcResult::NotPermitted;
}
/* Invoke the smc. */
return info.handler(args);
}
}
void ConfigureSmcHandlersForTargetFirmware() {
const auto target_fw = GetTargetFirmware();
if (target_fw < TargetFirmware_5_0_0) {
g_user_handlers[DecryptAndImportEsDeviceKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportEsDeviceKeyHandlerInfo;
g_user_handlers[DecryptAndImportLotusKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportLotusKeyHandlerInfo;
}
}
void HandleSmc(int type, SmcArguments &args) {
/* Get the table. */
const auto &table = GetHandlerTable(static_cast<HandlerType>(type), args.r[0]);
/* Get the handler info. */
const auto &info = GetHandlerInfo(table, args.r[0]);
/* Set the invocation result. */
args.r[0] = static_cast<u64>(InvokeSmcHandler(info, args));
}
}

View File

@@ -101,7 +101,6 @@ namespace ams::secmon::smc {
#include "secmon_define_emc_access_table.inc"
#include "secmon_define_emc1_access_table.inc"
#include "secmon_define_emc2_access_table.inc"
#include "secmon_define_soctherm_access_table.inc"
#include "secmon_define_mc01_access_table.inc"
constexpr const AccessTableEntry AccessTables[] = {
@@ -110,7 +109,6 @@ namespace ams::secmon::smc {
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
{ EmcAccessTable1::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), EmcAccessTable1::Address, EmcAccessTable1::Size, },
{ EmcAccessTable2::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController2.GetAddress(), EmcAccessTable2::Address, EmcAccessTable2::Size, },
{ SocthermAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceSoctherm.GetAddress(), SocthermAccessTable::Address, SocthermAccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
};

File diff suppressed because it is too large Load Diff

View File

@@ -199,9 +199,9 @@ volatile CustomizeTable C = {
{ 1581000, { 1130000, }, { 2889664, -122173, 1834, } },
{ 1683000, { 1168000, }, { 5100873, -279186, 4747, } },
{ 1785000, { 1225000, }, { 5100873, -279186, 4747, } },
// { 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
// { 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
// { 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
{ 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
{ 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
{ 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
},
.eristaCpuDvfsTableSLT = {

View File

@@ -99,4 +99,25 @@ namespace ams::ldr::hoc {
R_SUCCEED();
}
};
namespace panic {
/* Requires modifying g_ams_handlers in secmon_smc_handler.cpp */
constexpr inline void SmcError(u32 rgb) {
SecmonArgs args = {};
constexpr u32 SmcShowErrorID = 0xF0000005;
args.X[0] = SmcShowErrorID;
args.X[1] = rgb;
svcCallSecureMonitor(&args);
}
constexpr inline u32 PackCode(u32 r, u32 g, u32 b) {
return ((r & 0xF) << 8) | ((g & 0xF) << 4) | ((b & 0xF) << 0);
}
constexpr u32 Gpu = PackCode(0xF, 0x7, 0x0);
constexpr u32 Cpu = PackCode(0xF, 0x0, 0x0);
constexpr u32 Emc = PackCode(0x0, 0xF, 0xF);
constexpr u32 Patch = PackCode(0x8, 0x0, 0xF);
}
}

View File

@@ -84,6 +84,7 @@ namespace ams::ldr::hoc::pcv {
u32 min;
u32 max;
bool value_required = false;
u32 panic;
Result check() {
if (!value_required && !value)
@@ -143,22 +144,27 @@ namespace ams::ldr::hoc::pcv {
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, 1260 },
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000 },
{ C.marikoCpuMaxVolt, 1000, 1200 },
{ 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 },
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true, panic::Cpu },
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true, panic::Cpu },
{ C.eristaCpuMaxVolt, 1000, 1260, false, panic::Cpu },
{ C.marikoCpuMaxVolt, 1000, 1200, false, panic::Cpu },
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000, false, panic::Cpu },
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, false, panic::Cpu },
{ C.commonEmcMemVolt, 912'500, 1350'000, false, panic::Emc }, // Official burst vmax for the RAMs is 1500mV
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000, false, panic::Emc },
{ C.marikoEmcMaxClock, 1600'000, 3500'000, false, panic::Emc },
{ C.marikoEmcVddqVolt, 250'000, 700'000, false, panic::Emc },
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, false, panic::Gpu },
{ marikoGpuDvfsMaxFreq, 768'000, 1570'000, false, panic::Gpu },
{ C.marikoGpuVmax, 800, 960, false, panic::Gpu },
};
for (auto& i : validators) {
if (R_FAILED(i.check())) {
for (auto &v : validators) {
if (R_FAILED(v.check())) {
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
panic::SmcError(v.panic);
#endif
CRASH("Validation FAIL");
}
}

View File

@@ -474,6 +474,10 @@ namespace ams::ldr::hoc::pcv::erista {
for (auto &entry : patches) {
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
if (R_FAILED(entry.CheckResult())) {
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
panic::SmcError(panic::Patch);
#endif
CRASH(entry.description);
}
}

View File

@@ -415,6 +415,8 @@ namespace ams::ldr::hoc::pcv::mariko {
u32 trefbw = refresh_raw + 0x40;
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
CalculateTimings();
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
@@ -446,7 +448,6 @@ namespace ams::ldr::hoc::pcv::mariko {
WRITE_PARAM_ALL_REG(table, emc_refresh, refresh_raw);
WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4);
WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw);
const u32 dyn_self_ref_control = (static_cast<u32>(7605.0 / tCK_avg) + 260) | (table->burst_regs.emc_dyn_self_ref_control & 0xffff0000);
WRITE_PARAM_ALL_REG(table, emc_dyn_self_ref_control, dyn_self_ref_control);
WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw);
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, pdex2rw);
@@ -479,8 +480,9 @@ namespace ams::ldr::hoc::pcv::mariko {
WRITE_PARAM_ALL_REG(table, emc_rdv_early_mask, rdv);
WRITE_PARAM_ALL_REG(table, emc_rdv_mask, rdv + 2);
WRITE_PARAM_ALL_REG(table, emc_tr_rdv, rdv);
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_2, 0x24)
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_3, 0x24)
/* TODO: Check this out again at some point. */
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_2, 0x24);
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_3, 0x24);
/* This needs some clean up. */
constexpr double MC_ARB_DIV = 4.0;
@@ -498,7 +500,7 @@ namespace ams::ldr::hoc::pcv::mariko {
table->burst_mc_regs.mc_emem_arb_timing_wap2pre = CEIL(tW2P / MC_ARB_DIV) + MC_ARB_SFA;
/* Two consecutive reads between two different dram modules. */
/* Only be above 1 for 8gb ram. */
/* Only above 1 for 8gb ram. */
if (table->burst_mc_regs.mc_emem_arb_timing_r2r > 1) {
table->burst_mc_regs.mc_emem_arb_timing_r2r = CEIL(table->burst_regs.emc_rext / 4) - 1 + MC_ARB_SFA;
}
@@ -652,7 +654,7 @@ namespace ams::ldr::hoc::pcv::mariko {
// Copy unmodified 1600000 table to tmp
std::memcpy(reinterpret_cast<void *>(tmp), reinterpret_cast<void *>(table_max), sizeof(MarikoMtcTable));
/* Adjust timings properly according to the new frequency. */
MemMtcTableAutoAdjust(table_max);
@@ -810,6 +812,10 @@ namespace ams::ldr::hoc::pcv::mariko {
for (auto &entry : patches) {
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
if (R_FAILED(entry.CheckResult())) {
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
panic::SmcError(panic::Patch);
#endif
CRASH(entry.description);
}
}

View File

@@ -38,7 +38,7 @@ include $(DEVKITPRO)/libnx/switch_rules
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
APP_TITLE := Horizon OC Monitor
APP_VERSION := 1.3.2+r4-hoc
APP_VERSION := 1.3.2+r4-hoc-r2
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source

View File

@@ -79,14 +79,17 @@ Result sysclkIpcGetAPIVersion(u32* out_ver)
Result sysclkIpcGetVersionString(char* out, size_t len)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetVersionString,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out, len}},
);
}
Result sysclkIpcGetCurrentContext(SysClkContext* out_context)
{
return serviceDispatchOut(&g_sysclkSrv, SysClkIpcCmd_GetCurrentContext, *out_context);
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetCurrentContext,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_context, sizeof(SysClkContext)}},
);
}
Result sysclkIpcGetProfileCount(u64 tid, u8* out_count)
@@ -112,7 +115,7 @@ Result sysclkIpcSetOverride(SysClkModule module, u32 hz)
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles)
{
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_profiles, sizeof(SysClkTitleProfileList)}},
);
}
@@ -128,7 +131,7 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles)
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_configValues, sizeof(SysClkConfigValueList)}},
);
}
@@ -136,7 +139,7 @@ Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
.buffers = {{configValues, sizeof(SysClkConfigValueList)}},
);
}

View File

@@ -79,14 +79,17 @@ Result sysclkIpcGetAPIVersion(u32* out_ver)
Result sysclkIpcGetVersionString(char* out, size_t len)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetVersionString,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out, len}},
);
}
Result sysclkIpcGetCurrentContext(SysClkContext* out_context)
{
return serviceDispatchOut(&g_sysclkSrv, SysClkIpcCmd_GetCurrentContext, *out_context);
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetCurrentContext,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_context, sizeof(SysClkContext)}},
);
}
Result sysclkIpcGetProfileCount(u64 tid, u8* out_count)
@@ -112,7 +115,7 @@ Result sysclkIpcSetOverride(SysClkModule module, u32 hz)
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles)
{
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_profiles, sizeof(SysClkTitleProfileList)}},
);
}
@@ -128,7 +131,7 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles)
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{out_configValues, sizeof(SysClkConfigValueList)}},
);
}
@@ -136,7 +139,7 @@ Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
{
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
.buffers = {{configValues, sizeof(SysClkConfigValueList)}},
);
}

View File

@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
# version control constants
#---------------------------------------------------------------------------------
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
APP_VERSION := 1.0.1
APP_VERSION := 1.0.2
TARGET_VERSION := $(APP_VERSION)
#---------------------------------------------------------------------------------

View File

@@ -0,0 +1,132 @@
{
"Horizon OC Zeus": "Horizon OC Zeus",
"Edit App Profile": "編輯應用配置",
"Advanced": "高級",
"Edit Global Profile": "編輯全局配置",
"Temporary Overrides": "臨時覆蓋",
"Temporary Overrides Reset": "臨時覆蓋 重設",
"Settings": "設置",
"Information": "資訊",
"Enable": "啟用",
"Uncapped Clocks": "解除頻率上限",
"Override Boost Mode": "覆蓋加速模式",
"CPU Max Display Clock": "CPU 最大顯示頻率",
"Thermal Throttle": "溫度節流",
"Thermal Throttle Threshold": "溫度節流閾值",
"Handheld TDP": "掌機模式 TDP",
"Handheld TDP Limit": "掌機模式 TDP 限制",
"Lite TDP Limit": "Lite TDP 限制",
"Enforce Board Limit": "強制主板限制",
"Battery Charge Current": "電池充電電流",
"Display Refresh Rate Changing": "顯示刷新率變更",
"Fix CPU Volt Bug": "修復 CPU 電壓錯誤",
"[cfg] no enum format string": "[cfg] 無枚舉格式字串",
"KIP": "KIP",
"Save KIP Settings": "保存 KIP 設置",
"RAM Settings": "記憶體設定",
"CPU Settings": "CPU 設置",
"GPU Settings": "GPU 設置",
"Experimental": "實驗性功能",
"Charge Current Override": "充電電流覆蓋",
"Disabled": "禁用",
"HP Mode": "高性能模式",
"EMC Max Clock": "EMC 最大頻率",
"EMC VDD2 Voltage": "EMC VDD2 電壓",
"EMC VDDQ Voltage": "EMC VDDQ 電壓",
"DVB Shift": "DVB 偏移",
"Memory Timings": "記憶體時序",
"Memory Latencies": "記憶體延遲",
"t1 tRCD": "t1 tRCD",
"t2 tRP": "t2 tRP",
"t3 tRAS": "t3 tRAS",
"t4 tRRD": "t4 tRRD",
"t5 tRFC": "t5 tRFC",
"t6 tRTW": "t6 tRTW",
"t7 tWTR": "t7 tWTR",
"t8 tREFI": "t8 tREFI",
"Update RAM Timings": "更新記憶體時序",
"\uE150 This feature is EXPERIMENTAL": "\uE150 此功能為實驗性功能",
"and should only be used for testing!": "僅應用於測試!",
"Read Latency": "讀取延遲",
"Write Latency": "寫入延遲",
"CPU UV": "CPU 降壓",
"CPU Unlock": "CPU 解鎖",
"CPU VMIN": "CPU 最低電壓",
"CPU Max Voltage": "CPU 最大電壓",
"CPU UV Table": "CPU 降壓表",
"CPU Low UV": "CPU 低頻降壓",
"CPU High UV": "CPU 高頻降壓",
"CPU Max Clock": "CPU 最大頻率",
"CPU Low VMIN": "CPU 低頻最低電壓",
"CPU High VMIN": "CPU 高頻最低電壓",
"GPU Undervolt Table": "GPU 降壓表",
"Calculate GPU Vmin": "計算 GPU 最低電壓",
"GPU VMIN": "GPU 最低電壓",
"GPU VMAX": "GPU 最大電壓",
"GPU Volt Offset": "GPU 電壓偏移",
"GPU Custom Table": "GPU 自訂表",
"GPU Custom Table (mV)": "GPU 自訂表 (mV)",
"\uE150 Setting GPU Clocks past": "\uE150 將 GPU 頻率設置超過",
"1075MHz without UV, 1152MHz on SLT or ": "無降壓時的 1075MHz、SLT 時的 1152MHz 或",
"1228MHz on HiOPT can cause ": "HiOPT 時的 1228MHz 可能會造成",
"permanent damage to your Switch!": "對您的 Switch 造成永久性損壞!",
"Proceed at your own risk!": "風險自負!",
"921MHz without UV and 960MHz on": "無降壓時的 921MHz 和",
"SLT or HiOPT can cause ": "SLT 或 HiOPT 時的 960MHz 可能會造成",
"Auto": "自動",
"Sleep Mode": "休眠模式",
"Stock": "默認",
"Dev OC": "開發超頻",
"Boost Mode": "加速模式",
"Safe Max": "安全最大值",
"Unsafe Max": "不安全最大值",
"Absolute Max": "絕對最大值",
"Boost Mode & Safe Max": "加速模式 & 安全最大值",
"Official Rating": "官方額定值",
"Default (Mariko)": "默認 (Mariko)",
"Default (Erista)": "默認 (Erista)",
"Rating": "額定值",
"Safe Max (Mariko)": "安全最大值 (Mariko)",
"Safe Max (Erista)": "安全最大值 (Erista)",
"Default": "默認",
"1581MHz Tbreak": "1581MHz Tbreak",
"1683MHz Tbreak": "1683MHz Tbreak",
"Extreme UV Table": "極限降壓表",
"No UV": "不降壓",
"SLT Table": "SLT 表",
"HiOPT Table": "HiOPT 表",
"Power": "功耗",
"Temp": "溫度",
"Voltage": "電壓",
"TDP Threshold": "TDP 閾值",
"Lite TDP Threshold": "Lite TDP 閾值",
"Thermal Throttle Limit": "溫度節流限制",
"1600BL": "1600BL",
"1866BL": "1866BL",
"2133BL": "2133BL",
"BAT": "電池",
"FAN": "風扇",
"DISP": "顯示",
"Board": "主板",
"Skin": "外殼",
"Now": "當前",
"Avg": "平均",
"App ID": "應用 ID",
"Profile": "配置",
"CPU": "CPU",
"GPU": "GPU",
"Memory": "記憶體",
"Display": "顯示",
"Governor": "調速器",
"SOC": "SOC",
"PCB": "PCB",
"PMIC": "PMIC",
"Docked": "底座模式",
"Handheld": "掌機模式",
"Charging": "充電中",
"USB Charger": "USB 充電器",
"PD Charger": "PD 充電器",
"VDD2": "VDD2",
"VDDQ": "VDDQ",
"GPU DVFS": "GPU DVFS"
}

View File

@@ -1292,11 +1292,11 @@ protected:
// });
addConfigButton(KipConfigValue_marikoGpuVmin, "GPU VMIN", ValueRange(0, 0, 0, "0", 1), "GPU VMIN", &thresholdsDisabled, {}, mGpuVoltsVmin, false);
ValueThresholds MgpuVmaxThresholds(800, 850);
ValueThresholds MgpuVmaxThresholds(805, 850);
addConfigButton(
KipConfigValue_marikoGpuVmax,
"GPU Maximum Voltage",
ValueRange(750, 960, 5, "mV", 1),
ValueRange(800, 960, 5, "mV", 1),
"GPU Maximum Voltage",
&MgpuVmaxThresholds,
{},

View File

@@ -145,14 +145,14 @@ ClockManager::ClockManager()
this->context->isDram8GB = Board::IsDram8GB();
Board::SetGpuSchedulingMode((GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling), (GpuSchedulingOverrideMethod)this->config->GetConfigValue(HorizonOCConfigValue_GPUSchedulingMethod));
this->context->gpuSchedulingMode = (GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling);
this->context->isSysDockInstalled = this->sysDockIntegration->getCurrentSysDockState();
this->context->isSaltyNXInstalled = this->saltyNXIntegration->getCurrentSaltyNXState();
if(this->context->isSaltyNXInstalled) {
this->saltyNXIntegration->LoadSaltyNX();
}
threadStart(&cpuGovernorTHREAD);
threadStart(&gpuGovernorTHREAD);
threadStart(&vrrTHREAD);
@@ -635,7 +635,7 @@ void ClockManager::HandleGovernor(uint32_t targetHz) {
effectiveState == GovernorState_Enabled_CpuVrr ||
effectiveState == GovernorState_Enabled_GpuVrr ||
effectiveState == GovernorState_Enabled_Vrr);
isCpuGovernorEnabled = newCpuGovernorState;
isGpuGovernorEnabled = newGpuGovernorState;
isVRREnabled = newVrrGovernorState;
@@ -675,22 +675,18 @@ void ClockManager::DVFSBeforeSet(u32 targetHz) {
void ClockManager::DVFSAfterSet(u32 targetHz) {
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
dvfsOffset = std::max(dvfsOffset, -50);
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
Board::PcvHijackDvfs(vmin);
dvfsOffset = std::max(dvfsOffset, -80);
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000);
targetHz = this->context->overrideFreqs[SysClkModule_GPU];
if (!targetHz)
{
targetHz = this->config->GetAutoClockHz(this->context->applicationId, SysClkModule_GPU, this->context->profile, false);
if(!targetHz)
targetHz = this->config->GetAutoClockHz(GLOBAL_PROFILE_ID, SysClkModule_GPU, this->context->profile, false);
if (vmin) {
vmin += dvfsOffset;
}
u32 maxHz = this->GetMaxAllowedHz(SysClkModule_GPU, this->context->profile);
u32 nearestHz = this->GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
Board::PcvHijackDvfs(vmin);
if(targetHz) {
if (targetHz) {
Board::SetHz(SysClkModule_GPU, ~0);
Board::SetHz(SysClkModule_GPU, nearestHz);
} else {
@@ -1030,7 +1026,7 @@ bool ClockManager::RefreshContext()
this->context->fps = saltyNXIntegration->GetFPS();
else
this->context->fps = 254; // N/A
return hasChanged;
}

View File

@@ -119,9 +119,15 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8*
break;
case SysClkIpcCmd_GetCurrentContext:
*out_dataSize = sizeof(SysClkContext);
return ipcSrv->GetCurrentContext((SysClkContext*)out_data);
if(r->data.size >= sizeof(std::uint64_t) && r->hipc.meta.num_recv_buffers >= 1)
{
size_t bufSize = hipcGetBufferSize(r->hipc.data.recv_buffers);
if(bufSize >= sizeof(SysClkContext))
{
return ipcSrv->GetCurrentContext((SysClkContext*)hipcGetBufferAddress(r->hipc.data.recv_buffers));
}
}
break;
case SysClkIpcCmd_Exit:
return ipcSrv->Exit();

Binary file not shown.

View File

@@ -0,0 +1,132 @@
{
"Horizon OC Zeus": "Horizon OC Zeus",
"Edit App Profile": "編輯應用配置",
"Advanced": "高級",
"Edit Global Profile": "編輯全局配置",
"Temporary Overrides": "臨時覆蓋",
"Temporary Overrides Reset": "臨時覆蓋 重設",
"Settings": "設置",
"Information": "資訊",
"Enable": "啟用",
"Uncapped Clocks": "解除頻率上限",
"Override Boost Mode": "覆蓋加速模式",
"CPU Max Display Clock": "CPU 最大顯示頻率",
"Thermal Throttle": "溫度節流",
"Thermal Throttle Threshold": "溫度節流閾值",
"Handheld TDP": "掌機模式 TDP",
"Handheld TDP Limit": "掌機模式 TDP 限制",
"Lite TDP Limit": "Lite TDP 限制",
"Enforce Board Limit": "強制主板限制",
"Battery Charge Current": "電池充電電流",
"Display Refresh Rate Changing": "顯示刷新率變更",
"Fix CPU Volt Bug": "修復 CPU 電壓錯誤",
"[cfg] no enum format string": "[cfg] 無枚舉格式字串",
"KIP": "KIP",
"Save KIP Settings": "保存 KIP 設置",
"RAM Settings": "記憶體設定",
"CPU Settings": "CPU 設置",
"GPU Settings": "GPU 設置",
"Experimental": "實驗性功能",
"Charge Current Override": "充電電流覆蓋",
"Disabled": "禁用",
"HP Mode": "高性能模式",
"EMC Max Clock": "EMC 最大頻率",
"EMC VDD2 Voltage": "EMC VDD2 電壓",
"EMC VDDQ Voltage": "EMC VDDQ 電壓",
"DVB Shift": "DVB 偏移",
"Memory Timings": "記憶體時序",
"Memory Latencies": "記憶體延遲",
"t1 tRCD": "t1 tRCD",
"t2 tRP": "t2 tRP",
"t3 tRAS": "t3 tRAS",
"t4 tRRD": "t4 tRRD",
"t5 tRFC": "t5 tRFC",
"t6 tRTW": "t6 tRTW",
"t7 tWTR": "t7 tWTR",
"t8 tREFI": "t8 tREFI",
"Update RAM Timings": "更新記憶體時序",
"\uE150 This feature is EXPERIMENTAL": "\uE150 此功能為實驗性功能",
"and should only be used for testing!": "僅應用於測試!",
"Read Latency": "讀取延遲",
"Write Latency": "寫入延遲",
"CPU UV": "CPU 降壓",
"CPU Unlock": "CPU 解鎖",
"CPU VMIN": "CPU 最低電壓",
"CPU Max Voltage": "CPU 最大電壓",
"CPU UV Table": "CPU 降壓表",
"CPU Low UV": "CPU 低頻降壓",
"CPU High UV": "CPU 高頻降壓",
"CPU Max Clock": "CPU 最大頻率",
"CPU Low VMIN": "CPU 低頻最低電壓",
"CPU High VMIN": "CPU 高頻最低電壓",
"GPU Undervolt Table": "GPU 降壓表",
"Calculate GPU Vmin": "計算 GPU 最低電壓",
"GPU VMIN": "GPU 最低電壓",
"GPU VMAX": "GPU 最大電壓",
"GPU Volt Offset": "GPU 電壓偏移",
"GPU Custom Table": "GPU 自訂表",
"GPU Custom Table (mV)": "GPU 自訂表 (mV)",
"\uE150 Setting GPU Clocks past": "\uE150 將 GPU 頻率設置超過",
"1075MHz without UV, 1152MHz on SLT or ": "無降壓時的 1075MHz、SLT 時的 1152MHz 或",
"1228MHz on HiOPT can cause ": "HiOPT 時的 1228MHz 可能會造成",
"permanent damage to your Switch!": "對您的 Switch 造成永久性損壞!",
"Proceed at your own risk!": "風險自負!",
"921MHz without UV and 960MHz on": "無降壓時的 921MHz 和",
"SLT or HiOPT can cause ": "SLT 或 HiOPT 時的 960MHz 可能會造成",
"Auto": "自動",
"Sleep Mode": "休眠模式",
"Stock": "默認",
"Dev OC": "開發超頻",
"Boost Mode": "加速模式",
"Safe Max": "安全最大值",
"Unsafe Max": "不安全最大值",
"Absolute Max": "絕對最大值",
"Boost Mode & Safe Max": "加速模式 & 安全最大值",
"Official Rating": "官方額定值",
"Default (Mariko)": "默認 (Mariko)",
"Default (Erista)": "默認 (Erista)",
"Rating": "額定值",
"Safe Max (Mariko)": "安全最大值 (Mariko)",
"Safe Max (Erista)": "安全最大值 (Erista)",
"Default": "默認",
"1581MHz Tbreak": "1581MHz Tbreak",
"1683MHz Tbreak": "1683MHz Tbreak",
"Extreme UV Table": "極限降壓表",
"No UV": "不降壓",
"SLT Table": "SLT 表",
"HiOPT Table": "HiOPT 表",
"Power": "功耗",
"Temp": "溫度",
"Voltage": "電壓",
"TDP Threshold": "TDP 閾值",
"Lite TDP Threshold": "Lite TDP 閾值",
"Thermal Throttle Limit": "溫度節流限制",
"1600BL": "1600BL",
"1866BL": "1866BL",
"2133BL": "2133BL",
"BAT": "電池",
"FAN": "風扇",
"DISP": "顯示",
"Board": "主板",
"Skin": "外殼",
"Now": "當前",
"Avg": "平均",
"App ID": "應用 ID",
"Profile": "配置",
"CPU": "CPU",
"GPU": "GPU",
"Memory": "記憶體",
"Display": "顯示",
"Governor": "調速器",
"SOC": "SOC",
"PCB": "PCB",
"PMIC": "PMIC",
"Docked": "底座模式",
"Handheld": "掌機模式",
"Charging": "充電中",
"USB Charger": "USB 充電器",
"PD Charger": "PD 充電器",
"VDD2": "VDD2",
"VDDQ": "VDDQ",
"GPU DVFS": "GPU DVFS"
}

Binary file not shown.

Binary file not shown.