diff --git a/nx/include/switch/services/apm.h b/nx/include/switch/services/apm.h index ca006948..611c01aa 100644 --- a/nx/include/switch/services/apm.h +++ b/nx/include/switch/services/apm.h @@ -1,13 +1,18 @@ /** * @file apm.h - * @brief Performance management (apm) service IPC wrapper. + * @brief Performance management (apm) service IPC wrapper. This is used internally by applet with __nx_applet_PerformanceConfiguration, however if you prefer non-init/exit can be used manually. * @author yellows8 * @copyright libnx Authors */ #pragma once #include "../types.h" -/// These are used internally by applet. +/// CpuBoostMode. With \ref appletSetCpuBoostMode, only values 0/1 are available. This allows using higher clock rates. +typedef enum { + ApmCpuBoostMode_Disabled = 0, ///< Default, use normal PerformanceConfiguration. + ApmCpuBoostMode_Type1 = 1, ///< Use performance configurations 0x92220009 (Docked) and 0x9222000A (Handheld), or 0x9222000B and 0x9222000C. All of these use the normal GPU clock rate for Docked-mode. The latter pair uses the normal CPU clock rate, while the former pair uses the maximum TX1 CPU clock rate. Memory clock rate is the same as normal. + ApmCpuBoostMode_Type2 = 2, ///< Use performance configurations 0x9222000B and 0x9222000C. +} ApmCpuBoostMode; Result apmInitialize(void); void apmExit(void); diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index caed849d..4d24ad67 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -8,6 +8,7 @@ #pragma once #include "../types.h" #include "../services/sm.h" +#include "../services/apm.h" #include "../kernel/tmem.h" #include "../kernel/event.h" @@ -278,6 +279,20 @@ Result appletHomeButtonReaderLockAccessorGetEvent(Event *out_event); */ Result appletPushToGeneralChannel(AppletStorage *s); +/** + * @brief Sets the \ref ApmCpuBoostMode. + * @note Only available with [7.0.0+] (not fully usable system-side with 6.x). + * @param mode \ref ApmCpuBoostMode. + */ +Result appletSetCpuBoostMode(ApmCpuBoostMode mode); + +/** + * @brief Gets the current PerformanceConfiguration. + * @note Only available with [7.0.0+]. + * @param PerformanceConfiguration Output PerformanceConfiguration. + */ +Result appletGetCurrentPerformanceConfiguration(u32 *PerformanceConfiguration); + /** * @brief Creates a LibraryApplet. * @param h AppletHolder object. diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index ae521cd5..0fe77985 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -15,6 +15,7 @@ __attribute__((weak)) u32 __nx_applet_type = AppletType_Default; __attribute__((weak)) bool __nx_applet_auto_notifyrunning = true; __attribute__((weak)) u8 __nx_applet_AppletAttribute[0x80]; +/// When set, controls the PerformanceConfiguration passed to apmSetPerformanceConfiguration during app startup, where the array index is the PerformanceMode. __attribute__((weak)) u32 __nx_applet_PerformanceConfiguration[2] = {/*0x92220008*//*0x20004*//*0x92220007*/0, 0}; //// Controls whether to use applet exit cmds during \ref appletExit. 0 (default): Only run exit cmds when running under a NSO. 1: Use exit cmds regardless. >1: Skip exit cmds. __attribute__((weak)) u32 __nx_applet_exit_mode = 0; @@ -59,6 +60,8 @@ static Event g_appletLibraryAppletLaunchableEvent; static AppletThemeColorType g_appletThemeColorType = AppletThemeColorType_Default; +static ApmCpuBoostMode g_appletCpuBoostMode = ApmCpuBoostMode_Disabled; + static Result _appletGetHandle(Service* srv, Handle* handle_out, u64 cmd_id); static Result _appletGetEvent(Service* srv, Event* event_out, u64 cmd_id, bool autoclear); static Result _appletGetSession(Service* srv, Service* srv_out, u64 cmd_id); @@ -250,7 +253,6 @@ Result appletInitialize(void) // Official apps aren't known to use apmSetPerformanceConfiguration with mode=1. if (R_SUCCEEDED(rc)) { - // This is broken with the regular "apm" service. u32 i; for (i=0; i<2; i++) { @@ -293,6 +295,8 @@ void appletExit(void) } if (__nx_applet_type == AppletType_Application) appletSetFocusHandlingMode(AppletFocusHandlingMode_NoSuspend); + + if (g_appletCpuBoostMode != ApmCpuBoostMode_Disabled) appletSetCpuBoostMode(ApmCpuBoostMode_Disabled); } if ((envIsNso() && __nx_applet_exit_mode==0) || __nx_applet_exit_mode==1) { @@ -668,6 +672,43 @@ static Result _appletCmdNoInOut64(Service* srv, u64 *out, u64 cmd_id) { return rc; } +static Result _appletCmdNoInOut32(Service* srv, u32 *out, u64 cmd_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + + Result rc = serviceIpcDispatch(srv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u32 out; + } *resp; + + serviceIpcParse(srv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && out) { + *out = resp->out; + } + } + + return rc; +} + static Result _appletCmdInU8(Service* srv, u8 inval, u64 cmd_id) { IpcCommand c; ipcInitialize(&c); @@ -702,6 +743,40 @@ static Result _appletCmdInU8(Service* srv, u8 inval, u64 cmd_id) { return rc; } +static Result _appletCmdInU32(Service* srv, u32 inval, u64 cmd_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 inval; + } PACKED *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->inval = inval; + + Result rc = serviceIpcDispatch(srv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(srv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + static Result _appletCmdInU64(Service* srv, u64 inval, u64 cmd_id) { IpcCommand c; ipcInitialize(&c); @@ -1558,6 +1633,23 @@ Result appletPushToGeneralChannel(AppletStorage *s) { return _appletCmdInStorage(&g_appletICommonStateGetter, s, 20); } +Result appletSetCpuBoostMode(ApmCpuBoostMode mode) { + Result rc=0; + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + rc = _appletCmdInU32(&g_appletICommonStateGetter, mode, 66); + if (R_SUCCEEDED(rc)) g_appletCpuBoostMode = mode; + return rc; +} + +Result appletGetCurrentPerformanceConfiguration(u32 *PerformanceConfiguration) { + if (hosversionBefore(7,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _appletCmdNoInOut32(&g_appletICommonStateGetter, PerformanceConfiguration, 91); +} + // ISelfController static Result _appletSelfExit(void) {