Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9558fd67bb | ||
|
|
59b62a835b | ||
|
|
ad6847ec59 | ||
|
|
061c255978 | ||
|
|
bb44d0907d | ||
|
|
2215b17a54 | ||
|
|
cc52eab3f6 | ||
|
|
155a4ce50a | ||
|
|
17739377bd | ||
|
|
782fae1624 | ||
|
|
59ca1f18d6 | ||
|
|
c6cda6eb30 | ||
|
|
9f3c5d8de6 | ||
|
|
e4c9ac6ee3 | ||
|
|
5d6500523b | ||
|
|
b111ccabb5 | ||
|
|
b90a67aa43 |
@@ -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__
|
|
||||||
@@ -123,7 +123,7 @@ namespace ams::secmon {
|
|||||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCode = MemoryRegion(UINT64_C(0x40020000), 0x20000);
|
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCode = MemoryRegion(UINT64_C(0x40020000), 0x20000);
|
||||||
static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramBootCode));
|
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));
|
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDevice));
|
||||||
|
|
||||||
constexpr inline const MemoryRegion MemoryRegionVirtualDeviceEmpty = MemoryRegion(MemoryRegionVirtualDevice.GetStartAddress(), 0);
|
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(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
|
||||||
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), 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(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_) \
|
#define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
|
||||||
constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \
|
constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \
|
||||||
|
|||||||
268
Source/Atmosphere-Patches/secmon_smc_handler.cpp
Normal file
268
Source/Atmosphere-Patches/secmon_smc_handler.cpp
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -101,7 +101,6 @@ namespace ams::secmon::smc {
|
|||||||
#include "secmon_define_emc_access_table.inc"
|
#include "secmon_define_emc_access_table.inc"
|
||||||
#include "secmon_define_emc1_access_table.inc"
|
#include "secmon_define_emc1_access_table.inc"
|
||||||
#include "secmon_define_emc2_access_table.inc"
|
#include "secmon_define_emc2_access_table.inc"
|
||||||
#include "secmon_define_soctherm_access_table.inc"
|
|
||||||
#include "secmon_define_mc01_access_table.inc"
|
#include "secmon_define_mc01_access_table.inc"
|
||||||
|
|
||||||
constexpr const AccessTableEntry AccessTables[] = {
|
constexpr const AccessTableEntry AccessTables[] = {
|
||||||
@@ -110,7 +109,6 @@ namespace ams::secmon::smc {
|
|||||||
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
|
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
|
||||||
{ EmcAccessTable1::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), EmcAccessTable1::Address, EmcAccessTable1::Size, },
|
{ EmcAccessTable1::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), EmcAccessTable1::Address, EmcAccessTable1::Size, },
|
||||||
{ EmcAccessTable2::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController2.GetAddress(), EmcAccessTable2::Address, EmcAccessTable2::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 + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
|
||||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.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
@@ -98,7 +98,7 @@ volatile CustomizeTable C = {
|
|||||||
.eristaCpuBoostClock = 1785000, // Default boost clock
|
.eristaCpuBoostClock = 1785000, // Default boost clock
|
||||||
.marikoCpuBoostClock = 1963000, // Default boost clock
|
.marikoCpuBoostClock = 1963000, // Default boost clock
|
||||||
|
|
||||||
.eristaGpuUV = 2,
|
.eristaGpuUV = 0,
|
||||||
.eristaGpuVmin = 810,
|
.eristaGpuVmin = 810,
|
||||||
|
|
||||||
.marikoGpuUV = 0,
|
.marikoGpuUV = 0,
|
||||||
@@ -199,9 +199,9 @@ volatile CustomizeTable C = {
|
|||||||
{ 1581000, { 1130000, }, { 2889664, -122173, 1834, } },
|
{ 1581000, { 1130000, }, { 2889664, -122173, 1834, } },
|
||||||
{ 1683000, { 1168000, }, { 5100873, -279186, 4747, } },
|
{ 1683000, { 1168000, }, { 5100873, -279186, 4747, } },
|
||||||
{ 1785000, { 1225000, }, { 5100873, -279186, 4747, } },
|
{ 1785000, { 1225000, }, { 5100873, -279186, 4747, } },
|
||||||
// { 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
|
{ 1887000, { 1225000, }, { 5100873, -279186, 4747, } },
|
||||||
// { 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
|
{ 1989000, { 1227500, }, { 5100873, -279186, 4747, } },
|
||||||
// { 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
|
{ 2091000, { 1256250, }, { 5100873, -279186, 4747, } },
|
||||||
},
|
},
|
||||||
|
|
||||||
.eristaCpuDvfsTableSLT = {
|
.eristaCpuDvfsTableSLT = {
|
||||||
|
|||||||
@@ -99,4 +99,25 @@ namespace ams::ldr::hoc {
|
|||||||
R_SUCCEED();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ namespace ams::ldr::hoc::pcv {
|
|||||||
u32 min;
|
u32 min;
|
||||||
u32 max;
|
u32 max;
|
||||||
bool value_required = false;
|
bool value_required = false;
|
||||||
|
u32 panic;
|
||||||
|
|
||||||
Result check() {
|
Result check() {
|
||||||
if (!value_required && !value)
|
if (!value_required && !value)
|
||||||
@@ -143,22 +144,27 @@ namespace ams::ldr::hoc::pcv {
|
|||||||
|
|
||||||
using namespace ams::ldr::hoc::pcv;
|
using namespace ams::ldr::hoc::pcv;
|
||||||
sValidator validators[] = {
|
sValidator validators[] = {
|
||||||
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true },
|
{ C.eristaCpuBoostClock, 1020'000, 2295'000, true, panic::Cpu },
|
||||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true },
|
{ C.marikoCpuBoostClock, 1020'000, 2703'000, true, panic::Cpu },
|
||||||
{ C.commonEmcMemVolt, 912'500, 1350'000 }, // Official burst vmax for the RAMs is 1500mV
|
{ C.eristaCpuMaxVolt, 1000, 1260, false, panic::Cpu },
|
||||||
{ C.eristaCpuMaxVolt, 1000, 1260 },
|
{ C.marikoCpuMaxVolt, 1000, 1200, false, panic::Cpu },
|
||||||
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000 },
|
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000, false, panic::Cpu },
|
||||||
{ C.marikoCpuMaxVolt, 1000, 1200 },
|
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, false, panic::Cpu },
|
||||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000 },
|
{ C.commonEmcMemVolt, 912'500, 1350'000, false, panic::Emc }, // Official burst vmax for the RAMs is 1500mV
|
||||||
{ C.marikoEmcVddqVolt, 250'000, 700'000 },
|
{ GET_MAX_OF_ARR(erista::maxEmcClocks), 1600'000, 2600'000, false, panic::Emc },
|
||||||
{ eristaCpuDvfsMaxFreq, 1785'000, 2295'000 },
|
{ C.marikoEmcMaxClock, 1600'000, 3500'000, false, panic::Emc },
|
||||||
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000 },
|
{ C.marikoEmcVddqVolt, 250'000, 700'000, false, panic::Emc },
|
||||||
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000 },
|
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, false, panic::Gpu },
|
||||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000 },
|
{ marikoGpuDvfsMaxFreq, 768'000, 1570'000, false, panic::Gpu },
|
||||||
|
{ C.marikoGpuVmax, 800, 960, false, panic::Gpu },
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto& i : validators) {
|
for (auto &v : validators) {
|
||||||
if (R_FAILED(i.check())) {
|
if (R_FAILED(v.check())) {
|
||||||
|
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||||
|
panic::SmcError(v.panic);
|
||||||
|
#endif
|
||||||
|
|
||||||
CRASH("Validation FAIL");
|
CRASH("Validation FAIL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -474,6 +474,10 @@ namespace ams::ldr::hoc::pcv::erista {
|
|||||||
for (auto &entry : patches) {
|
for (auto &entry : patches) {
|
||||||
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
||||||
if (R_FAILED(entry.CheckResult())) {
|
if (R_FAILED(entry.CheckResult())) {
|
||||||
|
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||||
|
panic::SmcError(panic::Patch);
|
||||||
|
#endif
|
||||||
|
|
||||||
CRASH(entry.description);
|
CRASH(entry.description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -415,6 +415,8 @@ namespace ams::ldr::hoc::pcv::mariko {
|
|||||||
u32 trefbw = refresh_raw + 0x40;
|
u32 trefbw = refresh_raw + 0x40;
|
||||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
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();
|
CalculateTimings();
|
||||||
|
|
||||||
WRITE_PARAM_ALL_REG(table, emc_rd_rcd, GET_CYCLE_CEIL(tRCD));
|
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_refresh, refresh_raw);
|
||||||
WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4);
|
WRITE_PARAM_ALL_REG(table, emc_pre_refresh_req_cnt, refresh_raw / 4);
|
||||||
WRITE_PARAM_ALL_REG(table, emc_trefbw, trefbw);
|
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_dyn_self_ref_control, dyn_self_ref_control);
|
||||||
WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw);
|
WRITE_PARAM_ALL_REG(table, emc_pdex2wr, pdex2rw);
|
||||||
WRITE_PARAM_ALL_REG(table, emc_pdex2rd, 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_early_mask, rdv);
|
||||||
WRITE_PARAM_ALL_REG(table, emc_rdv_mask, rdv + 2);
|
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_tr_rdv, rdv);
|
||||||
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_2, 0x24)
|
/* TODO: Check this out again at some point. */
|
||||||
WRITE_PARAM_ALL_REG(table, emc_cmd_brlshft_3, 0x24)
|
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. */
|
/* This needs some clean up. */
|
||||||
constexpr double MC_ARB_DIV = 4.0;
|
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;
|
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. */
|
/* 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) {
|
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;
|
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
|
// Copy unmodified 1600000 table to tmp
|
||||||
std::memcpy(reinterpret_cast<void *>(tmp), reinterpret_cast<void *>(table_max), sizeof(MarikoMtcTable));
|
std::memcpy(reinterpret_cast<void *>(tmp), reinterpret_cast<void *>(table_max), sizeof(MarikoMtcTable));
|
||||||
|
|
||||||
/* Adjust timings properly according to the new frequency. */
|
/* Adjust timings properly according to the new frequency. */
|
||||||
MemMtcTableAutoAdjust(table_max);
|
MemMtcTableAutoAdjust(table_max);
|
||||||
|
|
||||||
@@ -810,6 +812,10 @@ namespace ams::ldr::hoc::pcv::mariko {
|
|||||||
for (auto &entry : patches) {
|
for (auto &entry : patches) {
|
||||||
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
||||||
if (R_FAILED(entry.CheckResult())) {
|
if (R_FAILED(entry.CheckResult())) {
|
||||||
|
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||||
|
panic::SmcError(panic::Patch);
|
||||||
|
#endif
|
||||||
|
|
||||||
CRASH(entry.description);
|
CRASH(entry.description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||||||
# NACP building is skipped as well.
|
# NACP building is skipped as well.
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
APP_TITLE := Horizon OC Monitor
|
APP_TITLE := Horizon OC Monitor
|
||||||
APP_VERSION := 1.3.2+r4-hoc
|
APP_VERSION := 1.3.2+r4-hoc-r2
|
||||||
TARGET := $(notdir $(CURDIR))
|
TARGET := $(notdir $(CURDIR))
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source
|
SOURCES := source
|
||||||
|
|||||||
@@ -79,14 +79,17 @@ Result sysclkIpcGetAPIVersion(u32* out_ver)
|
|||||||
Result sysclkIpcGetVersionString(char* out, size_t len)
|
Result sysclkIpcGetVersionString(char* out, size_t len)
|
||||||
{
|
{
|
||||||
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetVersionString,
|
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetVersionString,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
|
||||||
.buffers = {{out, len}},
|
.buffers = {{out, len}},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result sysclkIpcGetCurrentContext(SysClkContext* out_context)
|
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)
|
Result sysclkIpcGetProfileCount(u64 tid, u8* out_count)
|
||||||
@@ -112,7 +115,7 @@ Result sysclkIpcSetOverride(SysClkModule module, u32 hz)
|
|||||||
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles)
|
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles)
|
||||||
{
|
{
|
||||||
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid,
|
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
|
||||||
.buffers = {{out_profiles, sizeof(SysClkTitleProfileList)}},
|
.buffers = {{out_profiles, sizeof(SysClkTitleProfileList)}},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -128,7 +131,7 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles)
|
|||||||
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
|
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
|
||||||
{
|
{
|
||||||
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues,
|
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
|
||||||
.buffers = {{out_configValues, sizeof(SysClkConfigValueList)}},
|
.buffers = {{out_configValues, sizeof(SysClkConfigValueList)}},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -136,7 +139,7 @@ Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
|
|||||||
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
|
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
|
||||||
{
|
{
|
||||||
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues,
|
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
|
||||||
.buffers = {{configValues, sizeof(SysClkConfigValueList)}},
|
.buffers = {{configValues, sizeof(SysClkConfigValueList)}},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -583,6 +583,7 @@ static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t in
|
|||||||
case HorizonOCConfigValue_DVFSOffset:
|
case HorizonOCConfigValue_DVFSOffset:
|
||||||
case HorizonOCConfigValue_GPUScheduling:
|
case HorizonOCConfigValue_GPUScheduling:
|
||||||
case HorizonOCConfigValue_RAMVoltUsageDisplayMode:
|
case HorizonOCConfigValue_RAMVoltUsageDisplayMode:
|
||||||
|
case HorizonOCConfigValue_CpuGovernorMinimumFreq:
|
||||||
return true;
|
return true;
|
||||||
case HorizonOCConfigValue_BatteryChargeCurrent:
|
case HorizonOCConfigValue_BatteryChargeCurrent:
|
||||||
return ((input >= 1024) && (input <= 3072)) || !input;
|
return ((input >= 1024) && (input <= 3072)) || !input;
|
||||||
|
|||||||
@@ -79,14 +79,17 @@ Result sysclkIpcGetAPIVersion(u32* out_ver)
|
|||||||
Result sysclkIpcGetVersionString(char* out, size_t len)
|
Result sysclkIpcGetVersionString(char* out, size_t len)
|
||||||
{
|
{
|
||||||
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetVersionString,
|
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetVersionString,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
|
||||||
.buffers = {{out, len}},
|
.buffers = {{out, len}},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result sysclkIpcGetCurrentContext(SysClkContext* out_context)
|
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)
|
Result sysclkIpcGetProfileCount(u64 tid, u8* out_count)
|
||||||
@@ -112,7 +115,7 @@ Result sysclkIpcSetOverride(SysClkModule module, u32 hz)
|
|||||||
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles)
|
Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles)
|
||||||
{
|
{
|
||||||
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid,
|
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_GetProfiles, tid,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
|
||||||
.buffers = {{out_profiles, sizeof(SysClkTitleProfileList)}},
|
.buffers = {{out_profiles, sizeof(SysClkTitleProfileList)}},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -128,7 +131,7 @@ Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles)
|
|||||||
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
|
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
|
||||||
{
|
{
|
||||||
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues,
|
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_GetConfigValues,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
|
||||||
.buffers = {{out_configValues, sizeof(SysClkConfigValueList)}},
|
.buffers = {{out_configValues, sizeof(SysClkConfigValueList)}},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -136,7 +139,7 @@ Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues)
|
|||||||
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
|
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
|
||||||
{
|
{
|
||||||
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues,
|
return serviceDispatch(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues,
|
||||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
|
||||||
.buffers = {{configValues, sizeof(SysClkConfigValueList)}},
|
.buffers = {{configValues, sizeof(SysClkConfigValueList)}},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ include ${TOPDIR}/lib/libultrahand/ultrahand.mk
|
|||||||
# version control constants
|
# version control constants
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
|
#TARGET_VERSION := $(shell git describe --dirty --always --tags)
|
||||||
APP_VERSION := 1.0.0
|
APP_VERSION := 1.0.2
|
||||||
TARGET_VERSION := $(APP_VERSION)
|
TARGET_VERSION := $(APP_VERSION)
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
|||||||
132
Source/sys-clk/overlay/lang/zh-tw.json
Normal file
132
Source/sys-clk/overlay/lang/zh-tw.json
Normal 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"
|
||||||
|
}
|
||||||
@@ -48,16 +48,11 @@ std::string getVersionString() {
|
|||||||
return std::string(buf);
|
return std::string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------
|
static constexpr tsl::Color dynamicLogoRGB1 = tsl::Color(0, 4, 8, 15);
|
||||||
// AQUATIC BLUE COLORS (4-bit color space)
|
static constexpr tsl::Color dynamicLogoRGB2 = tsl::Color(7, 15, 15, 15);
|
||||||
// ---------------------------------------------
|
static constexpr tsl::Color STATIC_AQUA = tsl::Color(2, 10, 12, 15);
|
||||||
static constexpr tsl::Color dynamicLogoRGB1 = tsl::Color(0, 4, 8, 15); // Deep ocean blue
|
const std::string name = "Horizon OC Zeus";
|
||||||
static constexpr tsl::Color dynamicLogoRGB2 = tsl::Color(7, 15, 15, 15); // Bright aqua cyan
|
|
||||||
static constexpr tsl::Color STATIC_AQUA = tsl::Color(2, 10, 12, 15); // Mid aqua
|
|
||||||
|
|
||||||
// ---------------------------------------------
|
|
||||||
// FULLY ENHANCED ANIMATED LOGO EFFECT
|
|
||||||
// ---------------------------------------------
|
|
||||||
static s32 drawDynamicUltraText(
|
static s32 drawDynamicUltraText(
|
||||||
tsl::gfx::Renderer* renderer,
|
tsl::gfx::Renderer* renderer,
|
||||||
s32 startX,
|
s32 startX,
|
||||||
@@ -68,7 +63,6 @@ static s32 drawDynamicUltraText(
|
|||||||
{
|
{
|
||||||
static constexpr double cycleDuration = 1.6;
|
static constexpr double cycleDuration = 1.6;
|
||||||
|
|
||||||
const std::string name = "Horizon OC Zeus";
|
|
||||||
s32 currentX = startX;
|
s32 currentX = startX;
|
||||||
|
|
||||||
const u64 currentTime_ns = armTicksToNs(armGetSystemTick());
|
const u64 currentTime_ns = armTicksToNs(armGetSystemTick());
|
||||||
@@ -89,15 +83,9 @@ static s32 drawDynamicUltraText(
|
|||||||
double s1 = n * n * (3.0 - 2.0 * n);
|
double s1 = n * n * (3.0 - 2.0 * n);
|
||||||
double blend = std::clamp(s1, 0.0, 1.0);
|
double blend = std::clamp(s1, 0.0, 1.0);
|
||||||
|
|
||||||
// ---------------------------------------------
|
|
||||||
// Glow Pulse (brightness modulation)
|
|
||||||
// ---------------------------------------------
|
|
||||||
double glow = (cos(phase * 1.5) + 1.0) * 0.5;
|
double glow = (cos(phase * 1.5) + 1.0) * 0.5;
|
||||||
double brightness = 0.75 + glow * 0.25;
|
double brightness = 0.75 + glow * 0.25;
|
||||||
|
|
||||||
// ---------------------------------------------
|
|
||||||
// Color interpolation (4-bit!)
|
|
||||||
// ---------------------------------------------
|
|
||||||
u8 r = static_cast<u8>(
|
u8 r = static_cast<u8>(
|
||||||
(dynamicLogoRGB1.r + (dynamicLogoRGB2.r - dynamicLogoRGB1.r) * blend) * brightness
|
(dynamicLogoRGB1.r + (dynamicLogoRGB2.r - dynamicLogoRGB1.r) * blend) * brightness
|
||||||
);
|
);
|
||||||
@@ -112,21 +100,15 @@ static s32 drawDynamicUltraText(
|
|||||||
g = std::clamp<u8>(g, 0, 15);
|
g = std::clamp<u8>(g, 0, 15);
|
||||||
b = std::clamp<u8>(b, 0, 15);
|
b = std::clamp<u8>(b, 0, 15);
|
||||||
|
|
||||||
// ---------------------------------------------
|
|
||||||
// ZEUS Lightning Flash
|
|
||||||
// ---------------------------------------------
|
|
||||||
bool lightning = (fmod(timeNow, 5.0) < 0.15);
|
bool lightning = (fmod(timeNow, 5.0) < 0.15);
|
||||||
if (lightning) {
|
if (lightning) {
|
||||||
r = std::min<u8>(r + 4, 15);
|
r = std::min<u8>(r + 4, 15);
|
||||||
g = std::min<u8>(g + 4, 15);
|
g = std::min<u8>(g + 4, 15);
|
||||||
b = std::min<u8>(b + 15, 15); // strong blue spike
|
b = std::min<u8>(b + 15, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
tsl::Color color(r, g, b, 15);
|
tsl::Color color(r, g, b, 15);
|
||||||
|
|
||||||
// ---------------------------------------------
|
|
||||||
// Static Position (no vertical wobble)
|
|
||||||
// ---------------------------------------------
|
|
||||||
std::string ls(1, letter);
|
std::string ls(1, letter);
|
||||||
|
|
||||||
if (useNotificationMethod)
|
if (useNotificationMethod)
|
||||||
@@ -138,11 +120,7 @@ static s32 drawDynamicUltraText(
|
|||||||
return currentX;
|
return currentX;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------
|
void BaseGui::preDraw(tsl::gfx::Renderer* renderer) {
|
||||||
// PRE-DRAW HOOK
|
|
||||||
// ---------------------------------------------
|
|
||||||
void BaseGui::preDraw(tsl::gfx::Renderer* renderer)
|
|
||||||
{
|
|
||||||
drawDynamicUltraText(
|
drawDynamicUltraText(
|
||||||
renderer,
|
renderer,
|
||||||
LOGO_X,
|
LOGO_X,
|
||||||
@@ -153,9 +131,6 @@ void BaseGui::preDraw(tsl::gfx::Renderer* renderer)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------
|
|
||||||
// UI SETUP
|
|
||||||
// ---------------------------------------------
|
|
||||||
tsl::elm::Element* BaseGui::createUI()
|
tsl::elm::Element* BaseGui::createUI()
|
||||||
{
|
{
|
||||||
BaseFrame* rootFrame = new BaseFrame(this);
|
BaseFrame* rootFrame = new BaseFrame(this);
|
||||||
@@ -163,9 +138,6 @@ tsl::elm::Element* BaseGui::createUI()
|
|||||||
return rootFrame;
|
return rootFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------
|
|
||||||
// LIVE UPDATE
|
|
||||||
// ---------------------------------------------
|
|
||||||
void BaseGui::update()
|
void BaseGui::update()
|
||||||
{
|
{
|
||||||
this->refresh();
|
this->refresh();
|
||||||
|
|||||||
@@ -1292,11 +1292,11 @@ protected:
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
addConfigButton(KipConfigValue_marikoGpuVmin, "GPU VMIN", ValueRange(0, 0, 0, "0", 1), "GPU VMIN", &thresholdsDisabled, {}, mGpuVoltsVmin, false);
|
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(
|
addConfigButton(
|
||||||
KipConfigValue_marikoGpuVmax,
|
KipConfigValue_marikoGpuVmax,
|
||||||
"GPU Maximum Voltage",
|
"GPU Maximum Voltage",
|
||||||
ValueRange(750, 960, 5, "mV", 1),
|
ValueRange(800, 960, 5, "mV", 1),
|
||||||
"GPU Maximum Voltage",
|
"GPU Maximum Voltage",
|
||||||
&MgpuVmaxThresholds,
|
&MgpuVmaxThresholds,
|
||||||
{},
|
{},
|
||||||
|
|||||||
@@ -145,14 +145,14 @@ ClockManager::ClockManager()
|
|||||||
this->context->isDram8GB = Board::IsDram8GB();
|
this->context->isDram8GB = Board::IsDram8GB();
|
||||||
Board::SetGpuSchedulingMode((GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling), (GpuSchedulingOverrideMethod)this->config->GetConfigValue(HorizonOCConfigValue_GPUSchedulingMethod));
|
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->gpuSchedulingMode = (GpuSchedulingMode)this->config->GetConfigValue(HorizonOCConfigValue_GPUScheduling);
|
||||||
|
|
||||||
this->context->isSysDockInstalled = this->sysDockIntegration->getCurrentSysDockState();
|
this->context->isSysDockInstalled = this->sysDockIntegration->getCurrentSysDockState();
|
||||||
this->context->isSaltyNXInstalled = this->saltyNXIntegration->getCurrentSaltyNXState();
|
this->context->isSaltyNXInstalled = this->saltyNXIntegration->getCurrentSaltyNXState();
|
||||||
if(this->context->isSaltyNXInstalled) {
|
if(this->context->isSaltyNXInstalled) {
|
||||||
this->saltyNXIntegration->LoadSaltyNX();
|
this->saltyNXIntegration->LoadSaltyNX();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
threadStart(&cpuGovernorTHREAD);
|
threadStart(&cpuGovernorTHREAD);
|
||||||
threadStart(&gpuGovernorTHREAD);
|
threadStart(&gpuGovernorTHREAD);
|
||||||
threadStart(&vrrTHREAD);
|
threadStart(&vrrTHREAD);
|
||||||
@@ -635,7 +635,7 @@ void ClockManager::HandleGovernor(uint32_t targetHz) {
|
|||||||
effectiveState == GovernorState_Enabled_CpuVrr ||
|
effectiveState == GovernorState_Enabled_CpuVrr ||
|
||||||
effectiveState == GovernorState_Enabled_GpuVrr ||
|
effectiveState == GovernorState_Enabled_GpuVrr ||
|
||||||
effectiveState == GovernorState_Enabled_Vrr);
|
effectiveState == GovernorState_Enabled_Vrr);
|
||||||
|
|
||||||
isCpuGovernorEnabled = newCpuGovernorState;
|
isCpuGovernorEnabled = newCpuGovernorState;
|
||||||
isGpuGovernorEnabled = newGpuGovernorState;
|
isGpuGovernorEnabled = newGpuGovernorState;
|
||||||
isVRREnabled = newVrrGovernorState;
|
isVRREnabled = newVrrGovernorState;
|
||||||
@@ -675,22 +675,18 @@ void ClockManager::DVFSBeforeSet(u32 targetHz) {
|
|||||||
|
|
||||||
void ClockManager::DVFSAfterSet(u32 targetHz) {
|
void ClockManager::DVFSAfterSet(u32 targetHz) {
|
||||||
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
s32 dvfsOffset = this->config->GetConfigValue(HorizonOCConfigValue_DVFSOffset);
|
||||||
dvfsOffset = std::max(dvfsOffset, -50);
|
dvfsOffset = std::max(dvfsOffset, -80);
|
||||||
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000) + dvfsOffset;
|
u32 vmin = Board::GetMinimumGpuVoltage(targetHz / 1000000);
|
||||||
Board::PcvHijackDvfs(vmin);
|
|
||||||
|
|
||||||
targetHz = this->context->overrideFreqs[SysClkModule_GPU];
|
if (vmin) {
|
||||||
if (!targetHz)
|
vmin += dvfsOffset;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 maxHz = this->GetMaxAllowedHz(SysClkModule_GPU, this->context->profile);
|
u32 maxHz = this->GetMaxAllowedHz(SysClkModule_GPU, this->context->profile);
|
||||||
u32 nearestHz = this->GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
|
u32 nearestHz = this->GetNearestHz(SysClkModule_GPU, targetHz, maxHz);
|
||||||
|
Board::PcvHijackDvfs(vmin);
|
||||||
|
|
||||||
if(targetHz) {
|
if (targetHz) {
|
||||||
Board::SetHz(SysClkModule_GPU, ~0);
|
Board::SetHz(SysClkModule_GPU, ~0);
|
||||||
Board::SetHz(SysClkModule_GPU, nearestHz);
|
Board::SetHz(SysClkModule_GPU, nearestHz);
|
||||||
} else {
|
} else {
|
||||||
@@ -1030,7 +1026,7 @@ bool ClockManager::RefreshContext()
|
|||||||
this->context->fps = saltyNXIntegration->GetFPS();
|
this->context->fps = saltyNXIntegration->GetFPS();
|
||||||
else
|
else
|
||||||
this->context->fps = 254; // N/A
|
this->context->fps = 254; // N/A
|
||||||
|
|
||||||
return hasChanged;
|
return hasChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,9 +119,15 @@ Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8*
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SysClkIpcCmd_GetCurrentContext:
|
case SysClkIpcCmd_GetCurrentContext:
|
||||||
*out_dataSize = sizeof(SysClkContext);
|
if(r->data.size >= sizeof(std::uint64_t) && r->hipc.meta.num_recv_buffers >= 1)
|
||||||
return ipcSrv->GetCurrentContext((SysClkContext*)out_data);
|
{
|
||||||
|
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:
|
case SysClkIpcCmd_Exit:
|
||||||
return ipcSrv->Exit();
|
return ipcSrv->Exit();
|
||||||
|
|
||||||
|
|||||||
168
dist/README.md
vendored
Normal file
168
dist/README.md
vendored
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="assets/logo.png" alt="logo" width="768"/>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
[](https://dsc.gg/horizonoc)
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## ⚠️ Disclaimer
|
||||||
|
|
||||||
|
> **THIS TOOL CAN BE DANGEROUS IF MISUSED. PROCEED WITH CAUTION.**
|
||||||
|
> Due to the design of Horizon OS, **overclocking RAM can cause NAND OR SD CORRUPTION.**
|
||||||
|
> Ensure you have a **full NAND, PROINFO, EMUMMC and SD backup** before proceeding.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
**Horizon OC** is an open-source overclocking tool for Nintendo Switch consoles running **Atmosphere custom firmware**.
|
||||||
|
It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration tools.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* **CPU:** Up to 1963MHz (Mariko) / 1785MHz (Erista)
|
||||||
|
* **GPU:** Up to 1075MHz (Mariko) / 921MHz (Erista)
|
||||||
|
* **RAM:** Up to 1866/2133MHz (Mariko) / 1600MHz (Erista)
|
||||||
|
* Over/undervolting support
|
||||||
|
* Built-in configurator
|
||||||
|
* Compatible with most homebrew
|
||||||
|
|
||||||
|
> It is recommended to read the [guide](https://rentry.co/howtoget60fps) before proceeding, as this can help you get a *significant* performance boost over the default settings, often times with less power draw and heat output
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Ensure you have the latest versions of
|
||||||
|
|
||||||
|
* [Atmosphere](https://github.com/Atmosphere-NX/Atmosphere)
|
||||||
|
* [Ultrahand Overlay](https://github.com/ppkantorski/Ultrahand-Overlay)
|
||||||
|
2. Download and extract the **Horizon OC Package** to the root of your SD card.
|
||||||
|
3. If using **Hekate**, edit `hekate_ipl.ini` to include:
|
||||||
|
|
||||||
|
```
|
||||||
|
kip1=atmosphere/kips/hoc.kip
|
||||||
|
```
|
||||||
|
|
||||||
|
*(No changes needed if using fusee.)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
1. Open the Horizon OC Overlay
|
||||||
|
2. Open the settings menu
|
||||||
|
3. Adjust your overclocking settings as desired. A helpful guide can be found [here.](https://rentry.co/mariko#oc-settings-for-horizon-oc)
|
||||||
|
4. Click **Save KIP Settings** to apply your configuration.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Building from Source
|
||||||
|
|
||||||
|
Refer to COMPILATION.md
|
||||||
|
|
||||||
|
---
|
||||||
|
## Clock table
|
||||||
|
|
||||||
|
### MEM clocks
|
||||||
|
* 3200 → max on mariko, JEDEC.
|
||||||
|
* 2933 → JEDEC.
|
||||||
|
* 2666 → JEDEC.
|
||||||
|
* 2400 → max on erista, JEDEC.
|
||||||
|
* 2133 → mariko safe max (4266 Modules), JEDEC.
|
||||||
|
* 1996 → JEDEC.
|
||||||
|
* 1866 → mariko safe max (3733 Modules), JEDEC.
|
||||||
|
* 1600 → official docked, boost mode, erista safe max, JEDEC.
|
||||||
|
* 1331 → official handheld, JEDEC.
|
||||||
|
* 1065
|
||||||
|
* 800
|
||||||
|
* 665
|
||||||
|
|
||||||
|
### CPU clocks
|
||||||
|
* 2601 → mariko absolute max, very dangerous
|
||||||
|
* 2499
|
||||||
|
* 2397 → mariko safe max with UV (low speedo)
|
||||||
|
* 2295
|
||||||
|
* 2193
|
||||||
|
* 2091
|
||||||
|
* 1963 → mariko no UV max clock
|
||||||
|
* 1887
|
||||||
|
* 1785 → erista no UV max clock, boost mode
|
||||||
|
* 1683
|
||||||
|
* 1581
|
||||||
|
* 1428
|
||||||
|
* 1326
|
||||||
|
* 1224 → sdev oc
|
||||||
|
* 1122
|
||||||
|
* 1020 → official docked & handheld
|
||||||
|
* 918
|
||||||
|
* 816
|
||||||
|
* 714
|
||||||
|
* 612 → sleep mode
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
1. On Erista, CPU in handheld is capped to 1581MHz
|
||||||
|
|
||||||
|
### GPU clocks
|
||||||
|
* 1536 → absolute max clock on mariko. very dangerous
|
||||||
|
* 1459
|
||||||
|
* 1382
|
||||||
|
* 1305
|
||||||
|
* 1267 → NVIDIA T214 rating
|
||||||
|
* 1228 → mariko HiOPT safe clock
|
||||||
|
* 1152 → mariko SLT max clock
|
||||||
|
* 1075 → mariko no UV max clock. absolute max clock on erista. very dangerous
|
||||||
|
* 998 → NVIDIA T210 rating
|
||||||
|
* 960 (erista only) → erista slt/hiopt safe max clock
|
||||||
|
* 921 → erista no UV max clock
|
||||||
|
* 844
|
||||||
|
* 768 → official docked
|
||||||
|
* 691
|
||||||
|
* 614
|
||||||
|
* 537
|
||||||
|
* 460 → max handheld
|
||||||
|
* 384 → official handheld
|
||||||
|
* 307 → official handheld
|
||||||
|
* 230
|
||||||
|
* 153
|
||||||
|
* 76 → boost mode
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
1. GPU overclock is capped at 460MHz on erista in handheld
|
||||||
|
2. On Mariko, cap with No uv is 614MHz, with SLT it is 691MHz and with HiOPT it's 768MHz
|
||||||
|
3. Clocks higher than 768MHz on erista need the official charger is plugged in.
|
||||||
|
4. On Mariko, cap with No uv is 844MHz, with SLT it is 921MHz and with HiOPT it's 998MHz
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
* **Lightos's Cat** - Cat
|
||||||
|
|
||||||
|
* **Souldbminer** – hoc-clk and loader development
|
||||||
|
* **Lightos** – loader patches development
|
||||||
|
* **SciresM** - Atmosphere CFW
|
||||||
|
* **CTCaer** - L4T, Hekate, perfect ram timings
|
||||||
|
* **KazushiMe** – Switch OC Suite
|
||||||
|
* **hanai3bi (meha)** – Switch OC Suite, EOS, sys-clk-eos
|
||||||
|
* **NaGaa95** – L4T-OC-kernel
|
||||||
|
* **B3711 (halop)** – EOS
|
||||||
|
* **sys-clk team (m4xw, p-sam, natinusala)** – sys-clk
|
||||||
|
* **b0rd2death** – Ultrahand sys-clk & Status Monitor fork
|
||||||
|
* **MasaGratoR and ZachyCatGames** - General help
|
||||||
|
* **MasaGratoR** - Status Monitor & Display Refresh Rate Driver
|
||||||
|
* **Dom, Samybigio, Arcdelta, Miki, Happy, Flopsider, Winnerboi77, Blaise, Alvise, TDRR, agjeococh, frost, letum00 and Xenshen** - Testing
|
||||||
|
* **Samybigio2011** - Italian translations
|
||||||
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
BIN
dist/atmosphere/contents/00FF0000636C6BFF/exefs.nsp
vendored
Binary file not shown.
BIN
dist/atmosphere/kips/hoc.kip
vendored
BIN
dist/atmosphere/kips/hoc.kip
vendored
Binary file not shown.
132
dist/config/horizon-oc/lang/lang/zh-tw.json
vendored
Normal file
132
dist/config/horizon-oc/lang/lang/zh-tw.json
vendored
Normal 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"
|
||||||
|
}
|
||||||
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
BIN
dist/switch/.overlays/Horizon-OC-Monitor.ovl
vendored
Binary file not shown.
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
BIN
dist/switch/.overlays/horizon-oc-overlay.ovl
vendored
Binary file not shown.
Reference in New Issue
Block a user