initial commit

This commit is contained in:
KazushiM
2021-07-05 17:02:51 +08:00
commit 586c36d6f2
32 changed files with 2175 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.DS_Store

BIN
PatchTools/bspatch.exe Normal file

Binary file not shown.

BIN
PatchTools/elf2nso.exe Normal file

Binary file not shown.

BIN
PatchTools/hacpack.exe Normal file

Binary file not shown.

BIN
PatchTools/hactool.exe Normal file

Binary file not shown.

BIN
PatchTools/nx2elf.exe Normal file

Binary file not shown.

241
README.md Normal file
View File

@@ -0,0 +1,241 @@
# Switch OC Suite
Overclocking suite for Switch(Erista and Mariko) running on Atmosphere CFW.
## Notice
### Reserved and intended for personal use ONLY. It will NOT be actively maintained.
### Failure to read this README carefully or Doing CPU/GPU Overclocking on Erista will brick or fry your device (in the short term or long term, who knows).
- Erista support will be dropped later.
- nx-ovlloader seems to be unstable in Docked mode only with RAM OC applied. Grab `STACK_SIZE` patch [here](https://github.com/KazushiMe/nx-ovlloader/tree/patch-1) and build it yourself.
## Features
- CPU/GPU Overclock up to 2397.0/1344.0 MHz for Mariko and up to 2295.0/1075.2 MHz for Erista
- Auto-Boost CPU when a game starts or is loading (Mariko Only)
- Optimization for fan control at high load (Mariko Only)
- RAM Overclock up to 2131.2 MHz for Erista and 1996.8 MHz for Mariko
- Disable some background services, less power consumption in standby mode (Optional)
- Sync sys-clk profiles with ReverseNX(-Tools and -RT), no need to change clocks after toggling modes
- Profile-aware frequency override for all games
- Game recording and SysDVR streaming @ 60fps with high video bitrate (Optional)
- Remove copyright watermark in screenshots/recordings and bypass connection test, courtesy of [HookedBehemoth](https://github.com/HookedBehemoth/exefs_patches)
### Details
- Bump CPU/GPU frequencies up to 2397.0/1344.0 MHz for Mariko and 2295.0/1075.2 MHz for Erista, bypassing Horizon OS limit.
- Some SoCs may not reach MAX clock, or be unstable at/near MAX clock.
- CPU/GPU Overclocking on Erista will consume more power than what the charger provides, and generates much more heat. **You have been WARNED AGAIN!**
- Mariko is still functioning w/o charger under MAX OC(Your Mileage May Vary), therefore limit posed by sys-clk is lifted only for Mariko, but don't overdo it on battery.
- Auto-Boost CPU when a game starts or is in loading screen (Mariko Only, Optional).
- 1963.5 MHz w/o charger and 2295.0 MHz with charger
- Some games don't utilize SetCpuBoostMode, e.g. Overcooked 2, so Auto-Boost would be invalid in loading screens.
- RAM Overclock for both Erista and Mariko consoles. For now, Erista can reach up to 2131.2 MHz with overvolting, and up to 1996.8 MHz for Mariko without overvolting.
- RAM frequencies other than the only one you've chosen can NOT be used, but the impact of power consumption is negligible. So the ability to set RAM frequencies is removed in favor of ptm RAM patches, which could set RAM at specific clock permanently.
- For Mariko:
- Recommended frequency for Hynix RAM is 1731.2/1862.4 MHz(fk Hynix), but for Samsung and Micron ones you may use higher frequencies like 1996.8 MHz.
- Use Hekate to check out the brand of your RAM chips.
- Choose RAM clock with care, or your eMMC filesystem will be **corrupted**.
- For Erista:
- If you boot via Hekate, Minerva module(`/bootloader/sys/libsys_minerva.bso`) should be removed or recompiled with [changes](https://github.com/CTCaer/hekate/blob/master/modules/hekate_libsys_minerva/sys_sdrammtc.c#L31) applied.
- RAM voltage is set at 1125mV @ 1731.2 MHz, 1150 mV @ 1862.4 MHz, 1175 mV @ 1996.8 MHz and 1200 mV @ 2131.2 MHz.
- Game recording and SysDVR streaming @ 60fps with high video bitrate (Optional).
- Video duration shown in album will be 2x than the actual value, but playback speed is not affected.
- Recordings may be less than 30sec if higher bitrate is used.
- It has noticeable performance impacts in demanding games.
## Installation
### Method A: AIO Package
**Contains:**
- Patches for pcv and ptm modules
- Precompiled patch tools for pcv module (only for amd64 Windows, build yourself otherwise):
[hactool](https://github.com/SciresM/hactool), [nx2elf](https://github.com/shuffle2/nx2elf), elf2nso from [switch-tools](https://github.com/switchbrew/switch-tools/), [hacPack](https://github.com/The-4n/hacPack), [bsdiff-win](https://github.com/cnSchwarzer/bsdiff-win/) ([bsdiff](http://www.daemonology.net/bsdiff/))
- Prebuilt sys-clk and ReverseNX-RT modified for OC
- `system-settings.ini` for Horizon OS
⚠️**Warnings**:⚠️
- Since system files are altered, you could **NOT** boot to stock(OFW) with patch applied to SysNAND until you revert the patch, and ban risks exist (?). Therefore, patching SysNAND is **NOT encouraged**.
- Restoring pcv module backup is required before updating Horizon OS and booting OFW. Launch the `patcher.te` script to restore your backup.
**Steps:**
1. Make sure you are running targeted HOS (12.0.x), and have `prod.keys` dumped by [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM).
2. Loader patches for Atmosphere: Grab from the web and apply. I won't provide them here. (Or build AMS with `ValidateAcidSignature()` stubbed.)
3. Place all the files in `SdOut` into SD card.
See [Usage and customization](#usage and customization) and [Details](#details) sections for more info.
- Be careful of `/atmosphere/config/system_settings.ini`, you may want to edit it manually.
- Remove all the files in previous OC Suite version before updating to avoid conflicts.
4. Dump your pcv module.
If you already have the pcv backup of targeted HOS version, jump to Step 4. Otherwise, redump is required.
- Load [TegraExplorer](https://github.com/suchmememanyskill/TegraExplorer/releases/latest) payload in hekate.
- Choose `Browse SD` -> `patcher.te` -> `Launch Script`.
- Select the MMC you'd like to mount and `Dump PCV Module Backup`
- Wait for `Done!` showing up and transfer the backup `/atmosphere/oc_patches/pcv-backup` to your PC.
5. Extract `PatchTools` folder from the AIO package, put `pcv-backup` and `prod.keys` in.
6. Select RAM frequency and prepare the patches:
- Copy the `/atmosphere/oc_patches/xx-xxxx.x/ptm-patch` folder ->`/atmosphere/exefs_patches/` on your SD card.
- Copy `/atmosphere/oc_patches/xx-xxxx.x/pcv-bspatch` -> `PatchTools` on your PC.
7. Open `cmd.exe`, change working directory to the `PatchTools` folder and type in the following commands.
Assuming that you put the folder on your Desktop:
```cmd
cd %USERPROFILE%\Desktop\PatchTools
mkdir .\temp
mkdir .\temp\pcv_exefs
hactool -k prod.keys --disablekeywarns -t -nca .\pcv-backup --exefsdir .\temp
nx2elf .\temp\main
bspatch .\temp\main.elf .\temp\main-mod.elf .\pcv-bspatch
elf2nso .\temp\main-mod.elf .\temp\pcv_exefs\main
copy .\temp\main.npdm .\temp\pcv_exefs\
hacpack -k prod.keys -o .\ --type nca --ncatype program --titleid 010000000000001A --exefsdir .\temp\pcv_exefs\
ren *.nca pcv-module
rd /S /Q .\temp\
rd /S /Q .\hacpack_backup\
```
8. Move the patched `pcv-module` to `/atmosphere/oc_patches/`.
9. In TegraExplorer, `Browse SD` -> `patcher.te` -> `Launch Script` and then `Apply Patched PCV Module`.
10. Wait for `Done!` and then reboot to enjoy.
### Method B: For Pro-users
```bash
git clone https://github.com/KazushiMe/Switch-OC-Suite.git ~/Switch-OC-Suite
cd $YOUR_ATMOSPHERE_REPO
cp -R ~/Switch-OC-Suite/Atmosphere/*pp stratosphere/loader/source/
patch < ~/Switch-OC-Suite/Atmosphere/ldr_patcher.diff
cd $YOUR_SYS_CLK_REPO
git apply ~/Switch-OC-Suite/sys-clk.diff
cd $YOUR_REVERSENX_RT_REPO
git apply ~/Switch-OC-Suite/ReverseNX-RT.diff
```
Then compile sys-clk, ReverseNX-RT and Atmosphere with devkitpro, and don't forget to grab necessary patches in the repo.
Simply build `loader.kip` from Atmosphere and load it with hekate if you don't feel like wasting time.
## Usage and customization
**system_settings.ini** in `/atmosphere/config/`
- **For Erista:**
- Remove the "Fan Control for Mariko" section.
- Remove the "disable services" part if you use Nintendo Online services like friends, cloud saving and notifications.
- For "Game Recording FPS and Bitrate", if you play demanding games or don't care about streaming/framerate/bitrate, comment out this section.
**sys-clk**
- **For Mariko:**
- Remove `/config/sys-clk/boost.flag` if you like longer waiting time in loading screens.
- Remove `/config/sys-clk/boost_start.flag` if you don't want games to boot faster.
- Add `/config/sys-clk/downclock_dock.flag` to use handheld clocks in Docked mode when Handheld flag is set in ReverseNX.
- Add `[A111111111111111]` title config in `/config/sys-clk/config.ini` to set frequency override globally:
```ini
[A111111111111111]
docked_cpu=
docked_gpu=
handheld_charging_cpu=
handheld_charging_gpu=
handheld_charging_usb_cpu=
handheld_charging_usb_gpu=
handheld_charging_official_cpu=
handheld_charging_official_gpu=
handheld_cpu=
handheld_gpu=
```
## Credit
- CTCaer for modded Hekate bootloader, RE and hardware research
- HookedBehemoth for nifm_ctest and am_no_copyright [patches](https://github.com/HookedBehemoth/exefs_patches)
- masagrator for [ReverseNX-RT](https://github.com/masagrator/ReverseNX-RT)
- RetroNX team for [sys-clk](https://github.com/retronx-team/sys-clk) and a [place](https://*discord*.*gg*/erNC4FB) to discuss
- SciresM and Reswitched Team for the state-of-the-art [Atmosphere](https://github.com/Atmosphere-NX/Atmosphere) CFW of Switch
- suchmememanyskill for [TegraExplorer](https://github.com/suchmememanyskill/TegraExplorer) and [TegraScript](https://github.com/suchmememanyskill/TegraScript)
- Switchbrew [wiki](http://switchbrew.org/wiki/) for Switch in-depth info
- ZatchyCatGames for RE and original OC patches

View File

@@ -0,0 +1,104 @@
;Don't apply all cheats automatically
[atmosphere]
dmnt_cheats_enabled_by_default = u8!0x0
;Fan Control for Mariko
[tc]
tskin_rate_table_console = str!"[[-1000000, 40000, 0, 0], [36000, 43000, 51, 51], [43000, 50000, 51, 153], [50000, 56000, 153, 255], [56000, 1000000, 255, 255]]"
tskin_rate_table_handheld = str!"[[-1000000, 40000, 0, 0], [36000, 43000, 51, 51], [43000, 48000, 51, 102], [48000, 56000, 102, 204], [56000, 1000000, 255, 255], [48000, 1000000, 255, 255]]"
holdable_tskin = u32!0xDAC0
;Game Recording FPS and Bitrate
[am.debug]
;30 or 60
continuous_recording_fps=u32!60
;~7.5Mbps, default is ~5Mbps, VBR(Variable Bitrate)
continuous_recording_video_bit_rate=u32!0x780000
;Disable services for power saving in standby mode
;Delete following part if you use Nintendo Online Services
[bgtc]
enable_halfawake = u32!0x0
minimum_interval_normal = u32!0x7FFFFFFF
minimum_interval_save = u32!0x7FFFFFFF
battery_threshold_save = u32!0x64
battery_threshold_stop = u32!0x0
[npns]
background_processing = u8!0x0
sleep_periodic_interval = u32!0x7FFFFFFF
sleep_processing_timeout = u32!0x0
sleep_max_try_count = u32!0x0
[ns.notification]
enable_download_task_list = u8!0x0
enable_download_ticket = u8!0x0
enable_network_update = u8!0x0
enable_random_wait = u8!0x0
enable_request_on_cold_boot = u8!0x0
enable_send_rights_usage_status_request = u8!0x0
enable_sync_elicense_request = u8!0x0
enable_version_list = u8!0x0
retry_interval_min = u32!0x7FFFFFFF
retry_interval_max = u32!0x7FFFFFFF
[ns.rights]
register_na_ids_as_valid_accounts_forcibly_even_if_not_exist = u8!0x1
[account]
na_required_for_network_service = u8!0x0
na_license_verification_enabled = u8!0x0
[account.daemon]
background_awaking_periodicity = u32!0x7FFFFFFF
initial_schedule_delay = u32!0x7FFFFFFF
profile_sync_interval = u32!0x7FFFFFFF
na_info_refresh_interval = u32!0x7FFFFFFF
[capsrv]
enable_album_screenshot_filedata_verification = u8!0x0
enable_album_movie_filehash_verification = u8!0x0
enable_album_movie_filesign_verification = u8!0x0
[friends]
background_processing = u8!0x0
[notification.presenter]
snooze_interval_in_seconds = u32!0x7FFFFFFF
connection_retry_count = u32!0x0
alarm_pattern_total_repeat_count = u32!0x0
alarm_pattern_with_vibration_repeat_count = u32!0x0
[prepo]
;background_processing = u8!0x0 (shutdown directly when entering sleep mode)
transmission_interval_min = u32!0x7FFFFFFF
transmission_retry_interval_min = u32!0x7FFFFFFF
transmission_retry_interval_max = u32!0x7FFFFFFF
transmission_interval_in_sleep = u32!0x7FFFFFFF
statistics_save_interval_min = u32!0x7FFFFFFF
statistics_post_interval = u32!0x7FFFFFFF
save_system_report = u8!0x0
[olsc]
default_auto_upload_global_setting = u8!0x0
default_auto_download_global_setting = u8!0x0
autonomy_registration_interval_seconds = u32!0x7FFFFFFF
network_service_license_info_cache_expiration_seconds = u32!0x7FFFFFFF
postponed_transfer_task_processing_interval_seconds = u32!0x7FFFFFFF
retry_offset_seconds = u32!0x7FFFFFFF
network_trouble_detection_span_seconds = u32!0x7FFFFFFF
network_connection_polling_interval_seconds = u32!0x7FFFFFFF
is_save_data_backup_policy_check_required = u8!0x0
is_global_transfer_task_autonomy_registration_enabled = u8!0x0
is_on_event_transfer_task_registration_enabled = u8!0x0
is_periodic_transfer_task_registration_enabled = u8!0x0
[ntc]
is_autonomic_correction_enabled = u8!0x0
autonomic_correction_interval_seconds = u32!0x7FFFFFFF
autonomic_correction_failed_retry_interval_seconds = u32!0x7FFFFFFF
autonomic_correction_immediate_try_count_max = u32!0x0
autonomic_correction_immediate_try_interval_milliseconds = u32!0x7FFFFFFF
[systemupdate]
bgnup_retry_seconds = u32!0x7FFFFFFF

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

149
SdOut/patcher.te Normal file
View File

@@ -0,0 +1,149 @@
pcvModulePath = "bis:/Contents/registered/875acbb5a5b6526159ac68a3c91884c7.nca/00"
OldBackupPath = "sd:/atmosphere/oc_patches/12-patch.bak"
BackupPath = "sd:/atmosphere/oc_patches/pcv-backup"
PatchPath = "sd:/atmosphere/oc_patches/pcv-module"
POWER = 0x8
pauseexit = {
println("Press any button to exit.\n")
pause()
exit()
}
pausecont = {
println("Press A/POWER button to continue.")
println("Press any other button to exit.")
if ( ! ( pause() & POWER ) ) {
exit()
}
}
header = {
println("\n-- Switch OC Suite Patcher --\n\n")
println(" OC Suite is provided 'as is' without warranty of any kind,\n USE AT YOUR OWN RISKS!")
println(" If you don't have Joy-Cons connected or are using Switch Lite,")
println(" Press VOL+/- to navigate and POWER button to confirm.\n")
}
header()
if (_EMU) {
menuOptions = ["Exit", "Mount EmuMMC", "Mount SysMMC"]
}
else() {
menuOptions = ["Exit", "Mount SysMMC"]
}
res = menu(menuOptions, 0)
clearscreen()
if ( res == 0 ) {
exit()
}
if ( res == 1 && _EMU ) {
println("EmuMMC is selected!")
wait(1000)
if ( mmcConnect("EMUMMC") ) {
println("An error occured during mmc connect!")
pauseexit()
}
}
if ( res == 2 || ( res == 1 && ! _EMU ) ) {
println("SysMMC is selected!")
wait(1000)
if ( mmcConnect("SYSMMC") ) {
println("An error occured during mmc connect!")
pauseexit()
}
}
println("Mounting SYSTEM Partition and Checking...")
if ( mmcMount("SYSTEM") ) {
println("An error occured during SYSTEM mount!")
pauseexit()
}
if ( ! fileExists(pcvModulePath) ) {
println("You're NOT using targeted Horizon OS version!")
println("Targeted version: 12.0.x\n")
pauseexit()
}
if ( fileExists(OldBackupPath) ) {
println("Old Backup found! Renaming...")
if ( fileMove(OldBackupPath, BackupPath) ) {
println("An error occured during renaming backup!")
pauseexit()
}
}
clearscreen()
header()
menuOptions = ["Exit", "Dump PCV Module Backup", "Apply Patched PCV Module", "Restore PCV Module Backup"]
res = menu(menuOptions, 0)
clearscreen()
if ( res == 0 ) {
exit()
}
if ( res == 1 ) {
if ( fileExists(BackupPath) ) {
color("RED")
println("You have the backup already. Do you want to DELETE it and redump?")
println("Make sure you DO NOT have the patched one in the MMC!")
color("WHITE")
wait(3000)
pausecont()
if ( fileDel(BackupPath) ) {
println("An error occured during removing old backup!")
pauseexit()
}
}
println("Dumping...")
if ( fileCopy(pcvModulePath, BackupPath) ) {
println("An error occured during dumping!")
pauseexit()
}
println("Done! ")
pauseexit()
}
if ( res == 2 ) {
if ( ! fileExists(PatchPath) ) {
color("RED")
println("Patched PCV Module NOT FOUND!")
println("Make sure you have followed the instructions in README.")
color("WHITE")
pauseexit()
}
println("Applying Patched PCV Module...")
if ( fileDel(pcvModulePath) && fileCopy(PatchPath, pcvModulePath) ) {
println("An error occured!")
pauseexit()
}
println("Done! ")
pauseexit()
}
if ( res == 3 ) {
if ( ! fileExists(BackupPath) ) {
println("PCV Module Backup NOT FOUND!")
pauseexit()
}
println("Restoring PCV Module...")
if ( fileDel(pcvModulePath) && fileCopy(BackupPath, pcvModulePath) ) {
println("An error occured!")
pauseexit()
}
println("Done! ")
pauseexit()
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,51 @@
--- stratosphere/loader/source/ldr_patcher.cpp @a672917
+++ stratosphere/loader/source/ldr_patcher.cpp
@@ -15,11 +15,27 @@
*/
#include <stratosphere.hpp>
#include "ldr_patcher.hpp"
+#include "ldr_pcv_patch.hpp"
namespace ams::ldr {
namespace {
+ constexpr u8 PcvModuleId[2][20] = {
+ { 0x91, 0xD6, 0x1D, 0x59, 0xD7, 0x00, 0x23, 0x78, 0xE3, 0x55, 0x84, 0xFC, 0x0B, 0x38, 0xC7, 0x69, 0x3A, 0x3A, 0xBA, 0xB5, }, //11.0.0
+ { 0xC5, 0x03, 0xE9, 0x65, 0x50, 0xF3, 0x02, 0xE1, 0x21, 0x87, 0x31, 0x36, 0xB8, 0x14, 0xA5, 0x29, 0x86, 0x3D, 0x94, 0x9B, }, //12.0.0
+ };
+
+ constexpr u8 NifmModuleId[2][20] = {
+ { 0x7A, 0x43, 0xF8, 0x40, 0x33, 0x7C, 0x28, 0xD4, 0x53, 0x71, 0x88, 0x43, 0x60, 0x8E, 0xEF, 0xF7, 0x8A, 0xFD, 0x46, 0x0B, }, //11.0.0
+ { 0xA8, 0x5F, 0x50, 0xFB, 0xA1, 0x0E, 0x06, 0xA3, 0xEB, 0xA3, 0xD3, 0xFA, 0xCB, 0x9E, 0x07, 0x5B, 0x21, 0x8C, 0x7D, 0x6D, },
+ };
+
+ constexpr u8 AmModuleId[2][20] = {
+ { 0x25, 0x50, 0x97, 0xEF, 0x11, 0xC0, 0x75, 0x9B, 0x1F, 0x36, 0x13, 0x2F, 0x73, 0xBD, 0xDB, 0x04, 0xC3, 0xEF, 0x9A, 0xBE, }, //11.0.0
+ { 0x5E, 0x5F, 0x1C, 0xC2, 0x4D, 0x37, 0x45, 0x91, 0xAF, 0xC2, 0xA2, 0x33, 0x6C, 0x94, 0x53, 0xCC, 0xFA, 0x39, 0x61, 0xC1, },
+ };
+
constexpr const char *NsoPatchesDirectory = "exefs_patches";
/* Exefs patches want to prevent modification of header, */
@@ -113,6 +129,20 @@ namespace ams::ldr {
/* Apply IPS patches. */
void LocateAndApplyIpsPatchesToModule(const u8 *build_id, uintptr_t mapped_nso, size_t mapped_size) {
+ for(int i = 0; i < 2; i++)
+ {
+ if(memcmp(PcvModuleId[i], build_id, sizeof(PcvModuleId[i])) == 0) {
+ ApplyPcvPatch(reinterpret_cast<u8 *>(mapped_nso), mapped_size, i);
+ return; // Return here since pcv module loads before sd card can be mounted
+ }
+ else if(memcmp(NifmModuleId[i], build_id, sizeof(NifmModuleId[i])) == 0) {
+ ApplyCtestPatch(reinterpret_cast<u8 *>(mapped_nso), mapped_size, i);
+ }
+ else if(memcmp(AmModuleId[i], build_id, sizeof(AmModuleId[i])) == 0) {
+ ApplyCopyrightPatch(reinterpret_cast<u8 *>(mapped_nso), mapped_size, i);
+ }
+ }
+
if (!EnsureSdCardMounted()) {
return;
}

View File

@@ -0,0 +1,268 @@
// placed in Atmosphere/stratosphere/loader/source/
#include <stratosphere.hpp>
#define EMC_OVERCLOCK 1
#define EMC_OVERVOLT 1
namespace ams::ldr {
namespace {
constexpr u32 CtestOffset[2] = { 0xF400, 0x1079C };
constexpr u32 CopyrightOffset[2] = { 0xC6128, 0xCA414 }; //am_no_copyright port
constexpr u8 BehemothPatch[8] = { 0xE0, 0x03, 0x1F, 0xAA, 0xC0, 0x03, 0x5F, 0xD6 }; //🤔
typedef struct {
u32 hz = 0;
u32 volt = 0;
u32 unk[6] = {0};
s32 coeffs[6] = {0};
} gpu_clock_table_t;
constexpr u32 EmcFreqOffsets[2][30] = {
{ 0xD7C60, 0xD7C68, 0xD7C70, 0xD7C78, 0xD7C80, 0xD7C88, 0xD7C90, 0xD7C98, 0xD7CA0, 0xD7CA8, 0xE1800, 0xEEFA0, 0xF2478, 0xFE284, 0x10A304, 0x10D7DC, 0x110A40, 0x113CA4, 0x116F08, 0x11A16C, 0x11D3D0, 0x120634, 0x123898, 0x126AFC, 0x129D60, 0x12CFC4, 0x130228, 0x13BFE0, 0x140D00, 0x140D50, },
{ 0xE1810, 0xE6530, 0xE6580, 0xE6AB0, 0xE6AB8, 0xE6AC0, 0xE6AC8, 0xE6AD0, 0xE6AD8, 0xE6AE0, 0xE6AE8, 0xE6AF0, 0xE6AF8, 0xF0650, 0xFDDF0, 0x1012C8, 0x10D0D4, 0x119154, 0x11C62C, 0x11F890, 0x122AF4, 0x125D58, 0x128FBC, 0x12C220, 0x12F484, 0x1326E8, 0x13594C, 0x138BB0, 0x13BE14, 0x13F078, }
};
// RAM freqs to choose: 1731200, 1862400, 1996800, 2131200
constexpr u32 NewEmcFreq = 1862400;
// RAM overclock could be UNSTABLE on some RAM without bumping up voltage,
// and therefore show graphical glitches, hang randomly or even worse, corrupt your NAND
namespace Erista {
typedef struct {
u32 hz = 0;
u32 unk = 0;
u32 volt = 0;
u32 unk2[5] = {0};
s32 coeffs[6] = {0};
} cpu_clock_table_t;
/* CPU */
constexpr u32 CpuVoltageLimitOffsets[2][3] = {
{ 0xE1AC8, 0xE1AD4, 0xE37E4 },
{ 0xF0918, 0xF0924, 0xF2634 },
};
constexpr u32 NewCpuVoltageLimit = 1358;
static_assert(NewCpuVoltageLimit <= 1400);
constexpr u32 CpuTablesFreeSpace[2] = { 0xE3B78, 0xF29C8 };
constexpr cpu_clock_table_t NewCpuTables[] = {
{ 1887000, 0, 1240000, {}, { 5100873, -279186, 4747 } },
{ 1963500, 0, 1262000, {}, { 5100873, -279186, 4747 } },
{ 2091000, 0, 1298000, {}, { 5100873, -279186, 4747 } },
{ 2193000, 0, 1328000, {}, { 5100873, -279186, 4747 } },
{ 2295000, 0, 1358000, {}, { 5100873, -279186, 4747 } },
};
static_assert(sizeof(NewCpuTables) <= sizeof(cpu_clock_table_t)*16);
/* GPU */
constexpr u32 GpuTablesFreeSpace[2] = { 0xE2B58, 0xF19A8 };
constexpr gpu_clock_table_t NewGpuTables[] = {
{ 998400, 0, {}, { 1316991, 8144, -940, 808, -21583, 226 } },
{ 1075200, 0, {}, { 1358883, 8144, -940, 808, -21583, 226 } },
};
static_assert(sizeof(NewGpuTables) <= sizeof(gpu_clock_table_t)*20);
/* EMC */
constexpr u32 EmcVolatageOffsets[2][2] = {
{ 0x143998, 0x14399C },
{ 0x142878, 0x14287C },
};
constexpr u32 NewEmcVoltage = 1150000;
static_assert(NewEmcVoltage <= 1250000);
// 1150mV for 1862.4 MHz and 1200 mV for 2131.2 MHz, according to the feedback in RetroNX Discord
// 1125mV(HOS default) for 1731.2 MHz and 1175mV for 1996.8 MHz
};
namespace Mariko {
typedef struct {
u32 hz = 0;
u32 unk1 = 0;
s32 coeffs[6] = {0};
u32 volt = 0;
u32 unk3[5] = {0};
} cpu_clock_table_t;
/* CPU */
constexpr u32 CpuVoltageLimitOffsets[2][11] = {
{ 0xE1A8C, 0xE1A98, 0xE1AA4, 0xE1AB0, 0xE1AF8, 0xE1B04, 0xE1B10, 0xE1B1C, 0xE1B28, 0xE1B34, 0xE1F4C },
{ 0xF08DC, 0xF08E8, 0xF08F4, 0xF0900, 0xF0948, 0xF0954, 0xF0960, 0xF096C, 0xF0978, 0xF0984, 0xF0D9C },
};
constexpr u32 NewCpuVoltageLimit = 1220;
static_assert(NewCpuVoltageLimit <= 1300); //1300mV hangs for me
constexpr u32 CpuVoltageCoeffTable[2][10] = {
{ 0xE2140, 0xE2178, 0xE21B0, 0xE21E8, 0xE2220, 0xE2258, 0xE2290, 0xE22C8, 0xE2300, 0xE2338 },
{ 0xF0F90, 0xF0FC8, 0xF1000, 0xF1038, 0xF1070, 0xF10A8, 0xF10E0, 0xF1118, 0xF1150, 0xF1188 },
};
constexpr u32 NewCpuVoltageCoeff = NewCpuVoltageLimit * 1000;
constexpr u32 CpuTablesFreeSpace[2] = { 0xE2350, 0xF11A0 };
constexpr cpu_clock_table_t NewCpuTables[] = {
{2091000, 0, {1719782, -40440, 27}, NewCpuVoltageCoeff, {}},
{2193000, 0, {1809766, -41939, 27}, NewCpuVoltageCoeff, {}},
{2295000, 0, {1904458, -43439, 27}, NewCpuVoltageCoeff, {}},
{2397000, 0, {2004105, -44938, 27}, NewCpuVoltageCoeff, {}},
/*{2499000, 0, {2108966, -46437, 27}, NewCpuVoltageCoeff, {}},
{2601000, 0, {2219313, -47937, 27}, NewCpuVoltageCoeff, {}},
{2703000, 0, {2335434, -49436, 27}, NewCpuVoltageCoeff, {}},
{2805000, 0, {2457630, -50936, 27}, NewCpuVoltageCoeff, {}},
{2907000, 0, {2586221, -52435, 27}, NewCpuVoltageCoeff, {}},
{3009000, 0, {2721539, -53934, 27}, NewCpuVoltageCoeff, {}},*/
// calculated using linear regression:
// coeffs[0]=604531*exp(0.0000005*hz)
// coeffs[1]=-0.0147*hz-9702.1
};
static_assert(sizeof(NewCpuTables) <= sizeof(cpu_clock_table_t)*14);
constexpr u32 MaxCpuClockOffset[2] = { 0xE2740, 0xF1590 };
constexpr u32 NewMaxCpuClock = 2397000;
/* GPU */
constexpr u32 GpuTablesFreeSpace[2] = { 0xE3410, 0xF2260 };
constexpr gpu_clock_table_t NewGpuTables[] = {
{ 1305600, 0, {}, {1380113, -13465, -874, 0, 2580, 648} },
{ 1344000, 0, {}, {1420000, -14000, -870, 0, 2193, 824} },
/*{ 1382400, 0, {}, {1423200, -14188, -868, 0, 2150, 830} },
{ 1420800, 0, {}, {1426290, -14368, -860, 0, 2100, 850} },
{ 1305600, 0, {}, {1380113, -13465, -874, 0, 2580, 648} },
{ 1344000, 0, {}, {1420000, -14100, -870, 0, 2193, 824} },
{ 1382400, 0, {}, {1426290, -14368, -860, 0, 2100, 850} },
{ 1420800, 0, {}, {1450000, -14600, -860, 0, 2000, 850} },
{ 1382400, 0, {}, {1454061, -14500, -868, 0, 2000, 900} },
{ 1382400, 0, {}, {1474061, -15277, -866, 0, 1710, 1024} },
{ 1382400, 0, {}, {1500000, -15500, -880, 0, 1000, 548} },
{ 1420800, 0, {}, {1550000, -16500, -885, 0, 1500, 300} },*/
// some arbitrary coeffs I guessed and tested, YMMV
};
static_assert(sizeof(NewGpuTables) <= sizeof(gpu_clock_table_t)*15);
constexpr u32 Reg1MaxGpuOffset[2] = { 0x2E0AC, 0x3F6CC };
constexpr u8 Reg1NewMaxGpuClock[2][0xC] = {
// Original: 1267MHz
/*
MOV W13,#0x5600
MOVK W13,#0x13,LSL #16
NOP
*/
// Bump to 1536MHz
/*
MOV W13,#0x7000
MOVK W13,#0x17,LSL #16
NOP
*/
//0x0D, 0xC0, 0x8A, 0x52, 0x6D, 0x02, 0xA0, 0x72, 0x1F, 0x20, 0x03, 0xD5
{ 0x0D, 0x00, 0x8E, 0x52, 0xED, 0x02, 0xA0, 0x72, 0x1F, 0x20, 0x03, 0xD5 },
{ 0x0B, 0x00, 0x8E, 0x52, 0xEB, 0x02, 0xA0, 0x72, 0x1F, 0x20, 0x03, 0xD5 },
};
constexpr u32 Reg2MaxGpuOffset[2] = { 0x2E110, 0x3F730 };
constexpr u8 Reg2NewMaxGpuClock[2][0x8] = {
// Original: 1267MHz
/*
MOV W13,#0x5600
MOVK W13,#0x13,LSL #16
*/
// Bump to 1536MHz
/*
MOV W13,#0x7000
MOVK W13,#0x17,LSL #16
*/
//0x0D, 0xC0, 0x8A, 0x52, 0x6D, 0x02, 0xA0, 0x72
{ 0x0D, 0x00, 0x8E, 0x52, 0xED, 0x02, 0xA0, 0x72, },
{ 0x0B, 0x00, 0x8E, 0x52, 0xEB, 0x02, 0xA0, 0x72, },
};
/* EMC */
// Not available on Mariko
/*constexpr u32 EmcVolatageOffsets[2][2] = {
{
0x145FE4, //max77812_dram
0x144BA4, //max77812_dram
},
{
0x143A84,
0x144EC4,
}
};
constexpr u32 NewEmcVoltage = 650000;
static_assert(NewEmcVoltage <= 750000);*/
};
}
void ApplyPcvPatch(u8 *mapped_module, size_t mapped_size, int i) {
/* Add new CPU and GPU clock tables for Erista */
AMS_ABORT_UNLESS(Erista::CpuTablesFreeSpace[i] <= mapped_size && Erista::GpuTablesFreeSpace[i] <= mapped_size);
std::memcpy(mapped_module + Erista::CpuTablesFreeSpace[i], Erista::NewCpuTables, sizeof(Erista::NewCpuTables));
std::memcpy(mapped_module + Erista::GpuTablesFreeSpace[i], Erista::NewGpuTables, sizeof(Erista::NewGpuTables));
/* Patch max CPU voltage on Erista */
for(int j = 0; j < 3; j++) {
std::memcpy(mapped_module + Erista::CpuVoltageLimitOffsets[i][j], &Erista::NewCpuVoltageLimit, sizeof(Erista::NewCpuVoltageLimit));
}
/* Add new CPU and GPU clock tables for Mariko */
AMS_ABORT_UNLESS(Mariko::CpuTablesFreeSpace[i] <= mapped_size && Mariko::GpuTablesFreeSpace[i] <= mapped_size);
std::memcpy(mapped_module + Mariko::CpuTablesFreeSpace[i], Mariko::NewCpuTables, sizeof(Mariko::NewCpuTables));
std::memcpy(mapped_module + Mariko::GpuTablesFreeSpace[i], Mariko::NewGpuTables, sizeof(Mariko::NewGpuTables));
/* Patch Mariko max CPU and GPU clockrates */
AMS_ABORT_UNLESS(Mariko::MaxCpuClockOffset[i] <= mapped_size && Mariko::Reg1MaxGpuOffset[i] <= mapped_size && Mariko::Reg2MaxGpuOffset[i] <= mapped_size);
std::memcpy(mapped_module + Mariko::MaxCpuClockOffset[i], &Mariko::NewMaxCpuClock, sizeof(Mariko::NewMaxCpuClock));
std::memcpy(mapped_module + Mariko::Reg1MaxGpuOffset[i], Mariko::Reg1NewMaxGpuClock, sizeof(Mariko::Reg1NewMaxGpuClock[i]));
std::memcpy(mapped_module + Mariko::Reg2MaxGpuOffset[i], Mariko::Reg2NewMaxGpuClock, sizeof(Mariko::Reg2NewMaxGpuClock[i]));
/* Patch max cpu voltage on Mariko */
for(int j = 0; j < 11; j++) {
std::memcpy(mapped_module + Mariko::CpuVoltageLimitOffsets[i][j], &Mariko::NewCpuVoltageLimit, sizeof(Mariko::NewCpuVoltageLimit));
}
for(int j = 0; j < 10; j++) {
std::memcpy(mapped_module + Mariko::CpuVoltageCoeffTable[i][j], &Mariko::NewCpuVoltageCoeff, sizeof(Mariko::NewCpuVoltageCoeff));
}
/* Patch EMC clocks and voltage if enabled.
Note: On Erista, this requires removing or modifiying minerva */
if constexpr(EMC_OVERCLOCK) {
for(u32 j = 0; j < sizeof(EmcFreqOffsets[i])/sizeof(u32); j++) {
AMS_ABORT_UNLESS(EmcFreqOffsets[i][j] <= mapped_size);
std::memcpy(mapped_module + EmcFreqOffsets[i][j], &NewEmcFreq, sizeof(NewEmcFreq));
}
}
if constexpr(EMC_OVERVOLT) {
if(spl::GetSocType() == spl::SocType_Erista) {
for(u32 j = 0; j < sizeof(Erista::EmcVolatageOffsets[i])/sizeof(u32); j++) {
AMS_ABORT_UNLESS(Erista::EmcVolatageOffsets[i][j] <= mapped_size);
std::memcpy(mapped_module + Erista::EmcVolatageOffsets[i][j], &Erista::NewEmcVoltage, sizeof(Erista::NewEmcVoltage));
}
}
// Not available on Mariko
/*else if(spl::GetSocType() == spl::SocType_Mariko) {
for(u32 j = 0; j < sizeof(Mariko::EmcVolatageOffsets[i])/sizeof(u32); j++) {
AMS_ABORT_UNLESS(Mariko::EmcVolatageOffsets[i][j] <= mapped_size);
std::memcpy(mapped_module + Mariko::EmcVolatageOffsets[i][j], &Mariko::NewEmcVoltage, sizeof(Mariko::NewEmcVoltage));
}
}*/
}
return;
}
void ApplyCtestPatch(u8 *mapped_module, size_t mapped_size, int i) {
AMS_ABORT_UNLESS(CtestOffset[i] - 0x100 <= mapped_size);
std::memcpy(mapped_module + CtestOffset[i] - 0x100, BehemothPatch, sizeof(BehemothPatch));
}
void ApplyCopyrightPatch(u8 *mapped_module, size_t mapped_size, int i) {
AMS_ABORT_UNLESS(CopyrightOffset[i] - 0x100 <= mapped_size);
std::memcpy(mapped_module + CopyrightOffset[i] - 0x100, BehemothPatch, sizeof(BehemothPatch));
}
}

View File

@@ -0,0 +1,14 @@
// placed in Atmosphere/stratosphere/loader/source/
#pragma once
#include <stratosphere.hpp>
namespace ams::ldr {
void ApplyPcvPatch(u8 *mapped_module, size_t mapped_size, int i);
void ApplyCtestPatch(u8 *mapped_module, size_t mapped_size, int i);
void ApplyCopyrightPatch(u8 *mapped_module, size_t mapped_size, int i);
}

160
Source/Patch/12-ptm.pchtxt Normal file
View File

@@ -0,0 +1,160 @@
@nsobid-A79706954C6C45568B0FFE610627E2E89D8FB0D4
@flag offset_shift 0x100
// PTM PerformanceConfiguration Patch for 12.0.x
// Change all RAM freqs to 1862.4 MHz and Boost CPU freqs to 1963.5 MHz by default
// RAM
// 1731.2 MHz - 00043067
// 1862.4 MHz - 00F8016F
// 1996.8 MHz - 00C00477
// 2131.2 MHz - 0088077F
// CPU
// 1963.5 MHz - E0A10875
// 2295.0 MHz - C0EBCA88
// All values are Little-Endian
// See https://switchbrew.org/wiki/PTM_services#PerformanceConfiguration for details
// Use IPSwitch(https://github.com/3096/ipswitch/) to convert into ips patch
//0x00010000: 1020, 384.0, 1600.0
@enabled
000C5E14 00F7CB3C
000C5E18 00F7CB3C
000C5E1C 0060E316
000C5E20 0060E316
000C5E24 00F8016F
000C5E28 00F8016F
//0x00010001: 1020, 768.0, 1600.0
@enabled
000C5E34 00F7CB3C
000C5E38 00F7CB3C
000C5E3C 00C0C62D
000C5E40 00C0C62D
000C5E44 00F8016F
000C5E48 00F8016F
//0x00010002: 1224, 691.0, 1600.0
@enabled
000C5E54 00C2F448
000C5E58 00C2F448
000C5E5C 00E03229
000C5E60 00E03229
000C5E64 00F8016F
000C5E68 00F8016F
//0x00020000: 1020, 230.4, 1600.0
@enabled
000C5E74 00F7CB3C
000C5E78 00F7CB3C
000C5E7C 00A0BB0D
000C5E80 00A0BB0D
000C5E84 00F8016F
000C5E88 00F8016F
//0x00020001: 1020, 307.2, 1600.0
@enabled
000C5E94 00F7CB3C
000C5E98 00F7CB3C
000C5E9C 00804F12
000C5EA0 00804F12
000C5EA4 00F8016F
000C5EA8 00F8016F
//0x00020002: 1224, 230.4, 1600.0
@enabled
000C5EB4 00C2F448
000C5EB8 00C2F448
000C5EBC 00A0BB0D
000C5EC0 00A0BB0D
000C5EC4 00F8016F
000C5EC8 00F8016F
//0x00020003: 1020, 307.2, 1331.2
@enabled
000C5ED4 00F7CB3C
000C5ED8 00F7CB3C
000C5EDC 00804F12
000C5EE0 00804F12
000C5EE4 00F8016F
000C5EE8 00F8016F
//0x00020004: 1020, 384.0, 1331.2
@enabled
000C5EF4 00F7CB3C
000C5EF8 00F7CB3C
000C5EFC 0060E316
000C5F00 0060E316
000C5F04 00F8016F
000C5F08 00F8016F
//0x00020005: 1020, 307.0, 1065.6
@enabled
000C5F14 00F7CB3C
000C5F18 00F7CB3C
000C5F1C 00804F12
000C5F20 00804F12
000C5F24 00F8016F
000C5F28 00F8016F
//0x00020006: 1020, 384.0, 1065.6
@enabled
000C5F34 00F7CB3C
000C5F38 00F7CB3C
000C5F3C 0060E316
000C5F40 0060E316
000C5F44 00F8016F
000C5F48 00F8016F
//0x92220007: 1020, 460.0, 1600.0
@enabled
000C5F54 00F7CB3C
000C5F58 00F7CB3C
000C5F5C 0040771B
000C5F60 0040771B
000C5F64 00F8016F
000C5F68 00F8016F
//0x92220008: 1020, 460.0, 1331.2
@enabled
000C5F74 00F7CB3C
000C5F78 00F7CB3C
000C5F7C 0040771B
000C5F80 0040771B
000C5F84 00F8016F
000C5F88 00F8016F
//0x92220009: 1785, 76.8, 1600.0
@enabled
000C5F94 E0A10875
000C5F98 E0A10875
000C5F9C 00E09304
000C5FA0 00E09304
000C5FA4 00F8016F
000C5FA8 00F8016F
//0x9222000A: 1785, 76.8, 1331.2
@enabled
000C5FB4 E0A10875
000C5FB8 E0A10875
000C5FBC 00E09304
000C5FC0 00E09304
000C5FC4 00F8016F
000C5FC8 00F8016F
//0x9222000B: 1020, 76.8, 1600.0
@enabled
000C5FD4 00F7CB3C
000C5FD8 00F7CB3C
000C5FDC 00E09304
000C5FE0 00E09304
000C5FE4 00F8016F
000C5FE8 00F8016F
//0x9222000C: 1020, 76.8, 1331.2
@enabled
000C5FF4 00F7CB3C
000C5FF8 00F7CB3C
000C5FFC 00E09304
000C6000 00E09304
000C6004 00F8016F
000C6008 00F8016F

View File

@@ -0,0 +1,190 @@
diff --git a/.gitignore b/.gitignore
index 3e35c18..6b42bc5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ build/
*.nacp
*.nro
+*.DS_Store
diff --git a/Overlay/libs/Atmosphere-libs b/Overlay/libs/Atmosphere-libs
index 2d522dc..bc08912 160000
--- a/Overlay/libs/Atmosphere-libs
+++ b/Overlay/libs/Atmosphere-libs
@@ -1 +1 @@
-Subproject commit 2d522dc6a12b2eb5eb3f103a8c5b5126ca301b1a
+Subproject commit bc08912dd31bb172467add8e24b4f0adac431939
diff --git a/Overlay/libs/libtesla b/Overlay/libs/libtesla
index 6628524..a5ce77d 160000
--- a/Overlay/libs/libtesla
+++ b/Overlay/libs/libtesla
@@ -1 +1 @@
-Subproject commit 66285245361a02e5480c7bb7dac9ef6449ae6181
+Subproject commit a5ce77d14f144a24c21684128ae79ef1e808734c
diff --git a/Overlay/source/main.cpp b/Overlay/source/main.cpp
index cec060c..7b7d8b1 100644
--- a/Overlay/source/main.cpp
+++ b/Overlay/source/main.cpp
@@ -2,8 +2,12 @@
#include <tesla.hpp> // The Tesla Header
#include "dmntcht.h"
+#define PROCESS_MANAGEMENT_QLAUNCH_TID 0x0100000000001000ULL
+
bool def = true;
+bool defChanged = false;
bool isDocked = false;
+bool isDockedChanged = false;
bool PluginRunning = false;
bool closed = false;
Handle debug;
@@ -17,6 +21,7 @@ bool dmntcht = false;
bool SaltySD = false;
bool bak = false;
bool plugin = false;
+bool sysclkComm = false;
char DockedChar[32];
char SystemChar[32];
char PluginChar[36];
@@ -54,6 +59,29 @@ bool isServiceRunning(const char *serviceName) {
}
}
+u64 GetCurrentApplicationId()
+{
+ // Copied from sys-clk
+ Result rc = 0;
+ std::uint64_t pid = 0;
+ std::uint64_t tid = 0;
+ rc = pmdmntGetApplicationProcessId(&pid);
+
+ if (rc == 0x20f)
+ {
+ return PROCESS_MANAGEMENT_QLAUNCH_TID;
+ }
+
+ rc = pminfoGetProgramId(&tid, pid);
+
+ if (rc == 0x20f)
+ {
+ return PROCESS_MANAGEMENT_QLAUNCH_TID;
+ }
+
+ return tid;
+}
+
class GuiTest : public tsl::Gui {
public:
GuiTest(u8 arg1, u8 arg2, bool arg3) { }
@@ -95,9 +123,10 @@ class GuiTest : public tsl::Gui {
if (MAGIC == 0x06BA7E39) {
auto *clickableListItem = new tsl::elm::ListItem("Change system control");
clickableListItem->setClickListener([](u64 keys) {
- if (keys & KEY_A) {
+ if (keys & HidNpadButton_A) {
if (PluginRunning == true) {
def = !def;
+ defChanged = true;
if (dmntcht == true) {
dmntchtWriteCheatProcessMemory(def_address, &def, 0x1);
dmntchtReadCheatProcessMemory(def_address, &def, 0x1);
@@ -120,9 +149,10 @@ class GuiTest : public tsl::Gui {
auto *clickableListItem2 = new tsl::elm::ListItem("Change mode");
clickableListItem2->setClickListener([](u64 keys) {
- if (keys & KEY_A) {
+ if (keys & HidNpadButton_A) {
if (PluginRunning == true && def == false) {
isDocked =! isDocked;
+ isDockedChanged = true;
if (dmntcht == true) {
dmntchtWriteCheatProcessMemory(docked_address, &isDocked, 0x1);
dmntchtReadCheatProcessMemory(docked_address, &isDocked, 0x1);
@@ -145,7 +175,7 @@ class GuiTest : public tsl::Gui {
else if (SaltySD == true && plugin == true && check == false) {
auto *clickableListItem = new tsl::elm::ListItem("(De)activate plugin");
clickableListItem->setClickListener([](u64 keys) {
- if (keys & KEY_A) {
+ if (keys & HidNpadButton_A) {
if (bak == false) {
rename("sdmc:/SaltySD/plugins/ReverseNX-RT.elf", "sdmc:/SaltySD/plugins/ReverseNX-RT.elf.bak");
bak = true;
@@ -185,6 +215,38 @@ class GuiTest : public tsl::Gui {
svcReadDebugProcessMemory(&isDocked, debug, docked_address, 0x1);
svcCloseHandle(debug);
}
+ if (sysclkComm && isDockedChanged && def == false && bak == false)
+ {
+ uint8_t sysclkConfArr[9];
+ u64 currentTID = GetCurrentApplicationId();
+ if (currentTID != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ {
+ for(int i = 0; i < 8; i++) // TID to hex
+ sysclkConfArr[i] = currentTID >> 8*(7-i);
+ sysclkConfArr[8] = isDocked + 1;
+
+ FILE* sysclkConf = fopen("/config/sys-clk/ReverseNX-RT.conf", "wb+");
+ fwrite(sysclkConfArr, sizeof(sysclkConfArr), 1, sysclkConf);
+ fclose(sysclkConf);
+ }
+ isDockedChanged = false;
+ }
+ if (sysclkComm && defChanged && def == true && bak == false) // change from force mode to system-controlled mode
+ {
+ uint8_t sysclkConfArr[9];
+ u64 currentTID = GetCurrentApplicationId();
+ if (currentTID != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ {
+ for(int i = 0; i < 8; i++) // TID to hex
+ sysclkConfArr[i] = currentTID >> 8*(7-i);
+ sysclkConfArr[8] = 3;
+
+ FILE* sysclkConf = fopen("/config/sys-clk/ReverseNX-RT.conf", "wb+");
+ fwrite(sysclkConfArr, sizeof(sysclkConfArr), 1, sysclkConf);
+ fclose(sysclkConf);
+ }
+ defChanged = false;
+ }
i = 0;
}
else i++;
@@ -202,7 +264,7 @@ class GuiTest : public tsl::Gui {
}
// Called once every frame to handle inputs not handled by other UI elements
- virtual bool handleInput(u64 keysDown, u64 keysHeld, touchPosition touchInput, JoystickPosition leftJoyStick, JoystickPosition rightJoyStick) override {
+ virtual bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos, HidAnalogStickState joyStickPosLeft, HidAnalogStickState joyStickPosRight) override {
return false; // Return true here to singal the inputs have been consumed
}
};
@@ -213,6 +275,7 @@ class OverlayTest : public tsl::Overlay {
virtual void initServices() override {
smInitialize();
fsdevMountSdmc();
+ pminfoInitialize();
SaltySD = CheckPort();
if (SaltySD == false) return;
@@ -234,6 +297,14 @@ class OverlayTest : public tsl::Overlay {
else return;
}
+ // Check if sys-clk exist
+ temp = fopen("/atmosphere/contents/00FF0000636C6BFF/flags/boot2.flag", "r");
+ if (temp != NULL)
+ {
+ sysclkComm = true;
+ fclose(temp);
+ }
+
if (R_FAILED(pmdmntGetApplicationProcessId(&PID))) remove("sdmc:/SaltySD/ReverseNX-RT.hex");
else {
check = true;
@@ -284,6 +355,7 @@ class OverlayTest : public tsl::Overlay {
virtual void exitServices() override {
dmntchtExit();
if (dmntcht == false) svcCloseHandle(debug);
+ pminfoExit();
fsdevUnmountDevice("sdmc");
smExit();
} // Callet at the end to clean up all services previously initialized

997
Source/Patch/sys-clk.diff Normal file
View File

@@ -0,0 +1,997 @@
diff --git a/common/src/apm_profile_table.c b/common/src/apm_profile_table.c
index 7439ff1..19f5b68 100644
--- a/common/src/apm_profile_table.c
+++ b/common/src/apm_profile_table.c
@@ -23,8 +23,8 @@ SysClkApmConfiguration sysclk_g_apm_configurations[] = {
{0x00020006, 1020000000, 384000000, 1065600000},
{0x92220007, 1020000000, 460800000, 1600000000},
{0x92220008, 1020000000, 460800000, 1331200000},
- {0x92220009, 1785000000, 76800000, 1600000000},
- {0x9222000A, 1785000000, 76800000, 1331200000},
+ {0x92220009, 1963500000, 76800000, 1600000000},
+ {0x9222000A, 1963500000, 76800000, 1331200000},
{0x9222000B, 1020000000, 76800000, 1600000000},
{0x9222000C, 1020000000, 76800000, 1331200000},
{0, 0, 0, 0},
diff --git a/common/src/clock_table.c b/common/src/clock_table.c
index a8164dc..2765962 100644
--- a/common/src/clock_table.c
+++ b/common/src/clock_table.c
@@ -11,11 +11,15 @@
#include <stdint.h>
uint32_t sysclk_g_freq_table_mem_hz[] = {
- 665600000,
- 800000000,
- 1065600000,
+ //665600000,
+ //800000000,
+ //1065600000,
1331200000,
- 1600000000,
+ //1600000000,
+ 1731200000,
+ 1862400000,
+ 1996800000,
+ 2131200000,
0,
};
@@ -32,6 +36,12 @@ uint32_t sysclk_g_freq_table_cpu_hz[] = {
1581000000,
1683000000,
1785000000,
+ 1887000000,
+ 1963500000,
+ 2091000000,
+ 2193000000,
+ 2295000000,
+ 2397000000,
0,
};
@@ -48,5 +58,14 @@ uint32_t sysclk_g_freq_table_gpu_hz[] = {
768000000,
844800000,
921600000,
+ 998400000,
+ 1075200000,
+ 1152000000,
+ 1228800000,
+ 1267200000,
+ 1305600000,
+ 1344000000,
+ //1382400000,
+ //1420800000,
0,
};
diff --git a/manager/src/advanced_settings_tab.cpp b/manager/src/advanced_settings_tab.cpp
index 325d228..6d9725e 100644
--- a/manager/src/advanced_settings_tab.cpp
+++ b/manager/src/advanced_settings_tab.cpp
@@ -77,7 +77,7 @@ AdvancedSettingsTab::AdvancedSettingsTab()
});
// MEM
- brls::SelectListItem *memFreqListItem = createFreqListItem(SysClkModule_MEM, context.overrideFreqs[SysClkModule_MEM] / 1000000);
+ /*brls::SelectListItem *memFreqListItem = createFreqListItem(SysClkModule_MEM, context.overrideFreqs[SysClkModule_MEM] / 1000000);
memFreqListItem->getValueSelectedEvent()->subscribe([](int result)
{
Result rc = result == 0 ?
@@ -90,11 +90,11 @@ AdvancedSettingsTab::AdvancedSettingsTab()
errorResult(result == 0 ? "sysclkIpcRemoveOverride" : "sysclkIpcSetOverride", rc);
// TODO: Reset selected value
}
- });
+ });*/
this->addView(cpuFreqListItem);
this->addView(gpuFreqListItem);
- this->addView(memFreqListItem);
+ //this->addView(memFreqListItem);
// Config
this->addView(new brls::Header("Configuration"));
diff --git a/manager/src/app_profile_frame.cpp b/manager/src/app_profile_frame.cpp
index 4ad9545..0ea6af3 100644
--- a/manager/src/app_profile_frame.cpp
+++ b/manager/src/app_profile_frame.cpp
@@ -116,7 +116,7 @@ void AppProfileFrame::addFreqs(brls::List* list, SysClkProfile profile)
list->addView(gpuListItem);
// MEM
- brls::SelectListItem* memListItem = createFreqListItem(SysClkModule_MEM, this->profiles.mhzMap[profile][SysClkModule_MEM]);
+ /*brls::SelectListItem* memListItem = createFreqListItem(SysClkModule_MEM, this->profiles.mhzMap[profile][SysClkModule_MEM]);
this->profiles.mhzMap[profile][SysClkModule_MEM] *= 1000000;
@@ -126,7 +126,7 @@ void AppProfileFrame::addFreqs(brls::List* list, SysClkProfile profile)
brls::Logger::debug("Caching freq for module %d and profile %d to %" PRIu32, SysClkModule_MEM, profile, this->profiles.mhzMap[profile][SysClkModule_MEM]);
});
- list->addView(memListItem);
+ list->addView(memListItem);*/
}
void AppProfileFrame::onProfileChanged()
diff --git a/manager/src/cheat_sheet_tab.cpp b/manager/src/cheat_sheet_tab.cpp
index 6823e0e..08a91bf 100644
--- a/manager/src/cheat_sheet_tab.cpp
+++ b/manager/src/cheat_sheet_tab.cpp
@@ -19,6 +19,8 @@
*/
#include "cheat_sheet_tab.h"
+#include "ipc/client.h"
+#include "utils.h"
#include <borealis.hpp>
@@ -28,8 +30,9 @@ CheatSheetTab::CheatSheetTab()
this->addView(new brls::Header("CPU Clocks"));
brls::Table *cpuTable = new brls::Table();
- cpuTable->addRow(brls::TableRowType::BODY, "Maximum", "1785 MHz");
- cpuTable->addRow(brls::TableRowType::BODY, "Official Docked and Handheld", "1020 MHz");
+ cpuTable->addRow(brls::TableRowType::BODY, "OC Suite Maximum", "2397.0 MHz");
+ cpuTable->addRow(brls::TableRowType::BODY, "Official Boost", "1785.0 MHz");
+ cpuTable->addRow(brls::TableRowType::BODY, "Official Docked and Handheld", "1020.0 MHz");
this->addView(cpuTable);
@@ -37,10 +40,10 @@ CheatSheetTab::CheatSheetTab()
this->addView(new brls::Header("GPU Clocks"));
brls::Table *gpuTable = new brls::Table();
- gpuTable->addRow(brls::TableRowType::BODY, "Maximum", "921 MHz");
- gpuTable->addRow(brls::TableRowType::BODY, "Official Docked", "768 MHz");
- gpuTable->addRow(brls::TableRowType::BODY, "Maximum Handheld", "460 MHz");
- gpuTable->addRow(brls::TableRowType::BODY, "Official Handheld", "384 MHz");
+ gpuTable->addRow(brls::TableRowType::BODY, "OC Suite Maximum", "1344.0 MHz");
+ gpuTable->addRow(brls::TableRowType::BODY, "Official Maximum", "921.6 MHz");
+ gpuTable->addRow(brls::TableRowType::BODY, "Official Docked", "768.0 MHz");
+ gpuTable->addRow(brls::TableRowType::BODY, "Official Handheld", "384.0/460.8 MHz");
this->addView(gpuTable);
@@ -48,8 +51,20 @@ CheatSheetTab::CheatSheetTab()
this->addView(new brls::Header("MEM Clocks"));
brls::Table *memTable = new brls::Table();
- memTable->addRow(brls::TableRowType::BODY, "Maximum, Official Docked", "1600 MHz");
- memTable->addRow(brls::TableRowType::BODY, "Official Handheld", "1331 MHz");
+ // Get context
+ SysClkContext context;
+ Result rc = sysclkIpcGetCurrentContext(&context);
+
+ if (R_FAILED(rc))
+ {
+ brls::Logger::error("Unable to get context");
+ errorResult("sysclkIpcGetCurrentContext", rc);
+ brls::Application::crash("Could not get the current sys-clk context, please check that it is correctly installed and enabled.");
+ return;
+ }
+
+ memTable->addRow(brls::TableRowType::BODY, "OC Suite", formatFreq(context.freqs[SysClkModule_MEM]));
+ memTable->addRow(brls::TableRowType::BODY, "Official", "1331.2/1600.0 MHz");
this->addView(memTable);
}
diff --git a/overlay/src/ui/gui/app_profile_gui.cpp b/overlay/src/ui/gui/app_profile_gui.cpp
index 29adfe5..116c803 100644
--- a/overlay/src/ui/gui/app_profile_gui.cpp
+++ b/overlay/src/ui/gui/app_profile_gui.cpp
@@ -62,7 +62,7 @@ void AppProfileGui::addProfileUI(SysClkProfile profile)
this->listElement->addItem(new tsl::elm::CategoryHeader(sysclkFormatProfile(profile, true)));
this->addModuleListItem(profile, SysClkModule_CPU, &sysclk_g_freq_table_cpu_hz[0]);
this->addModuleListItem(profile, SysClkModule_GPU, &sysclk_g_freq_table_gpu_hz[0]);
- this->addModuleListItem(profile, SysClkModule_MEM, &sysclk_g_freq_table_mem_hz[0]);
+ //this->addModuleListItem(profile, SysClkModule_MEM, &sysclk_g_freq_table_mem_hz[0]);
}
void AppProfileGui::listUI()
diff --git a/overlay/src/ui/gui/global_override_gui.cpp b/overlay/src/ui/gui/global_override_gui.cpp
index 3ea98e4..91742b7 100644
--- a/overlay/src/ui/gui/global_override_gui.cpp
+++ b/overlay/src/ui/gui/global_override_gui.cpp
@@ -62,7 +62,7 @@ void GlobalOverrideGui::listUI()
{
this->addModuleListItem(SysClkModule_CPU, &sysclk_g_freq_table_cpu_hz[0]);
this->addModuleListItem(SysClkModule_GPU, &sysclk_g_freq_table_gpu_hz[0]);
- this->addModuleListItem(SysClkModule_MEM, &sysclk_g_freq_table_mem_hz[0]);
+ //this->addModuleListItem(SysClkModule_MEM, &sysclk_g_freq_table_mem_hz[0]);
}
void GlobalOverrideGui::refresh()
diff --git a/sysmodule/src/clock_manager.cpp b/sysmodule/src/clock_manager.cpp
index 46d7207..4139f34 100644
--- a/sysmodule/src/clock_manager.cpp
+++ b/sysmodule/src/clock_manager.cpp
@@ -8,10 +8,14 @@
* --------------------------------------------------------------------------
*/
+#define FORCE_ALL_HANDHELD_MODES_TO_USE_DOCK_CLOCK
+#include <nxExt.h>
+#include "errors.h"
#include "clock_manager.h"
#include "file_utils.h"
#include "clocks.h"
#include "process_management.h"
+#include <cstring>
ClockManager* ClockManager::instance = NULL;
@@ -59,6 +63,136 @@ ClockManager::~ClockManager()
delete this->context;
}
+bool ClockManager::IsCpuBoostMode()
+{
+ std::uint32_t confId = 0;
+ Result rc = 0;
+ rc = apmExtGetCurrentPerformanceConfiguration(&confId);
+ ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
+ if(confId == 0x92220009 || confId == 0x9222000A)
+ return true;
+ else
+ return false;
+}
+
+SysClkProfile ClockManager::ReverseNXProfile(bool ForceDock)
+{
+ RealProfile = Clocks::GetCurrentProfile();
+ switch(RealProfile)
+ {
+ case SysClkProfile_HandheldChargingOfficial:
+#ifdef FORCE_ALL_HANDHELD_MODES_TO_USE_DOCK_CLOCK
+ case SysClkProfile_HandheldChargingUSB:
+ case SysClkProfile_HandheldCharging:
+ case SysClkProfile_Handheld:
+#endif
+ if (ForceDock)
+ return SysClkProfile_Docked;
+ else
+ return RealProfile;
+ case SysClkProfile_Docked:
+ if (ForceDock)
+ return SysClkProfile_Docked;
+ else
+ return FileUtils::IsDownclockDockEnabled() ? SysClkProfile_HandheldChargingOfficial : SysClkProfile_Docked;
+ default:
+ return RealProfile;
+ }
+}
+
+void ClockManager::checkReverseNXTool()
+{
+ char ReverseNXToolAsm[] = "_ZN2nn2oe18GetPerformanceModeEv.asm64"; // Checking one asm64 file is enough
+ char ReverseNXToolAsmPath[128];
+ uint8_t flag = 0;
+ snprintf(ReverseNXToolAsmPath, sizeof ReverseNXToolAsmPath, "/SaltySD/patches/%s", ReverseNXToolAsm);
+
+ FILE *readReverseNXToolAsm;
+ readReverseNXToolAsm = fopen(ReverseNXToolAsmPath, "rb");
+
+ // Enforce mode globally: Enabled
+ if(readReverseNXToolAsm != NULL)
+ {
+ checkReverseNXToolAsm(readReverseNXToolAsm, &flag);
+ switch(flag)
+ {
+ case 1:
+ FileUtils::LogLine("[mgr] ReverseNX-Tool patches detected: Enforce Handheld globally");
+ this->context->profile = ReverseNXProfile(false);
+ isDockedReverseNX = false;
+ isEnabledReverseNX = true;
+ isEnabledReverseNXTool = true;
+ break;
+ case 2:
+ FileUtils::LogLine("[mgr] ReverseNX-Tool patches detected: Enforce Docked globally");
+ this->context->profile = ReverseNXProfile(true);
+ isDockedReverseNX = true;
+ isEnabledReverseNX = true;
+ isEnabledReverseNXTool = true;
+ break;
+ }
+ }
+ else
+ {
+ snprintf(ReverseNXToolAsmPath, sizeof ReverseNXToolAsmPath, "/SaltySD/patches/%016lX/%s", this->context->applicationId, ReverseNXToolAsm);
+ readReverseNXToolAsm = fopen(ReverseNXToolAsmPath, "rb");
+ // Found game-specific setting
+ if(readReverseNXToolAsm != NULL)
+ {
+ checkReverseNXToolAsm(readReverseNXToolAsm, &flag);
+ switch(flag)
+ {
+ case 1:
+ FileUtils::LogLine("[mgr] ReverseNX-Tool patches detected: Force Handheld in %016lX", this->context->applicationId);
+ this->context->profile = ReverseNXProfile(false);
+ isDockedReverseNX = false;
+ isEnabledReverseNX = true;
+ isEnabledReverseNXTool = true;
+ break;
+ case 2:
+ FileUtils::LogLine("[mgr] ReverseNX-Tool patches detected: Force Docked in %016lX", this->context->applicationId);
+ this->context->profile = ReverseNXProfile(true);
+ isDockedReverseNX = true;
+ isEnabledReverseNX = true;
+ isEnabledReverseNXTool = true;
+ break;
+ default:
+ isEnabledReverseNXTool = false;
+ }
+ }
+ }
+}
+
+bool ClockManager::GameStartBoost()
+{
+ if (tickStartBoost && this->GetConfig()->Enabled())
+ {
+ if (Clocks::GetCurrentHz(SysClkModule_CPU) != MAX_CPU)
+ {
+ Clocks::SetHz(SysClkModule_CPU, MAX_CPU);
+ this->context->freqs[SysClkModule_CPU] = MAX_CPU;
+ }
+
+ std::uint64_t applicationId = ProcessManagement::GetCurrentApplicationId();
+ // If user exit the game
+ if (applicationId != this->context->applicationId)
+ {
+ tickStartBoost = 0;
+ return false;
+ }
+
+ if (tickStartBoost == 1)
+ {
+ FileUtils::LogLine("[mgr] Boost done, reset to stock");
+ Clocks::ResetToStock();
+ }
+ tickStartBoost--;
+ return true;
+ }
+
+ return false;
+}
+
void ClockManager::SetRunning(bool running)
{
this->running = running;
@@ -72,27 +206,75 @@ bool ClockManager::Running()
void ClockManager::Tick()
{
std::scoped_lock lock{this->contextMutex};
- if (this->RefreshContext() || this->config->Refresh())
+
+ if(!GameStartBoost())
{
- std::uint32_t hz = 0;
- for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
+ bool cpuBoost = FileUtils::IsBoostEnabled() ? IsCpuBoostMode() : false;
+ if (this->RefreshContext() || this->config->Refresh())
{
- hz = this->context->overrideFreqs[module];
-
- if(!hz)
+ std::uint32_t hz = 0;
+ std::uint32_t hzForceOverride = 0;
+ for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
- hz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile);
- }
+ hz = this->context->overrideFreqs[module];
- if (hz)
- {
- hz = Clocks::GetNearestHz((SysClkModule)module, this->context->profile, hz);
+ if(!hz)
+ {
+ hz = this->config->GetAutoClockHz(this->context->applicationId, (SysClkModule)module, this->context->profile);
+ hzForceOverride = this->config->GetAutoClockHz(0xA111111111111111, (SysClkModule)module, this->context->profile);
+ if (!hz && hzForceOverride)
+ hz = hzForceOverride;
- if (hz != this->context->freqs[module] && this->context->enabled)
+ if(isEnabledReverseNX && !hz)
+ {
+ switch(module)
+ {
+ case SysClkModule_CPU:
+ hz = 1020'000'000;
+ break;
+ case SysClkModule_GPU:
+ if (!isDockedReverseNX && ((FileUtils::IsDownclockDockEnabled() && RealProfile == SysClkProfile_Docked)
+ || RealProfile != SysClkProfile_Docked))
+ hz = 460'800'000;
+ else
+ hz = 768'000'000;
+ break;
+ }
+ }
+
+ }
+
+ if (hz)
{
- FileUtils::LogLine("[mgr] %s clock set : %u.%u Mhz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
- Clocks::SetHz((SysClkModule)module, hz);
- this->context->freqs[module] = hz;
+ hz = Clocks::GetNearestHz((SysClkModule)module, isEnabledReverseNX ? RealProfile : this->context->profile, hz);
+
+ if (hz != this->context->freqs[module] && this->context->enabled)
+ {
+ if (cpuBoost)
+ {
+ if (module == SysClkModule_CPU && hz < MAX_CPU)
+ {
+ hz = MAX_CPU;
+ FileUtils::LogLine("[mgr] CpuBoostMode detected, bump CPU to max");
+ }
+ }
+ FileUtils::LogLine("[mgr] %s clock set : %u.%u Mhz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
+ Clocks::SetHz((SysClkModule)module, hz);
+ this->context->freqs[module] = hz;
+ }
+ }
+ }
+ }
+ else if (FileUtils::IsBoostEnabled())
+ {
+ // If user doesn't set any freq but with sys-clk enabled, then boost CPU in CpuBoostMode
+ if(cpuBoost && this->GetConfig()->Enabled())
+ {
+ if(this->context->freqs[SysClkModule_CPU] != MAX_CPU)
+ {
+ FileUtils::LogLine("[mgr] CpuBoostMode detected, bump CPU to max");
+ Clocks::SetHz(SysClkModule_CPU, MAX_CPU);
+ this->context->freqs[SysClkModule_CPU] = MAX_CPU;
}
}
}
@@ -104,6 +286,56 @@ void ClockManager::WaitForNextTick()
svcSleepThread(this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs) * 1000000ULL);
}
+void ClockManager::checkReverseNXToolAsm(FILE* readFile, uint8_t* flag)
+{
+ // Copied from ReverseNXTool
+ uint8_t Docked[0x10] = {0xE0, 0x03, 0x00, 0x32, 0xC0, 0x03, 0x5F, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ uint8_t Handheld[0x10] = {0x00, 0x00, 0xA0, 0x52, 0xC0, 0x03, 0x5F, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ uint8_t filebuffer[0x10] = {0};
+ uint8_t cmpresult = 0;
+ fread(&filebuffer, 1, 16, readFile);
+ cmpresult = memcmp(filebuffer, Docked, sizeof(Docked));
+ if (cmpresult != 0)
+ {
+ cmpresult = memcmp(filebuffer, Handheld, sizeof(Handheld));
+ if (cmpresult != 0)
+ *flag = 0; // Set to default
+ else
+ *flag = 1; // Handheld
+ }
+ else
+ *flag = 2; // Docked
+
+ fclose(readFile);
+}
+
+void ClockManager::checkReverseNXRT(bool recheckReverseNX, uint8_t* flag)
+{
+ FILE* readReverseNXRTConf = fopen(FILE_REVERSENX_RT_CONF_PATH, "rb");
+ if (readReverseNXRTConf != NULL)
+ {
+ uint8_t ReverseNXRTConfArr[9];
+ fread(ReverseNXRTConfArr, 9, 1, readReverseNXRTConf);
+ fclose(readReverseNXRTConf);
+ remove(FILE_REVERSENX_RT_CONF_PATH);
+
+ uint8_t currentTid[8];
+ for(int i = 0; i < 8; i++)
+ currentTid[i] = this->context->applicationId >> 8*(7-i);
+
+ uint8_t cmpresult = memcmp(currentTid, ReverseNXRTConfArr, sizeof(currentTid));
+
+ if (cmpresult == 0)
+ *flag = ReverseNXRTConfArr[8]; // 1: Handheld, 2: Docked, 3: Reset
+ else
+ *flag = 0; // 0: Not applicable
+ }
+ else if (recheckReverseNX)
+ *flag = prevReverseNXRT; // Use previous state when profile changes
+ else
+ *flag = 0;
+}
+
bool ClockManager::RefreshContext()
{
bool hasChanged = false;
@@ -120,21 +352,103 @@ bool ClockManager::RefreshContext()
if (applicationId != this->context->applicationId)
{
FileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId);
+ prevReverseNXRT = 0; // Reset ReverseNX-RT previous state when Title ID changes
this->context->applicationId = applicationId;
hasChanged = true;
+
+ if (FileUtils::IsReverseNXEnabled() || recheckReverseNX)
+ {
+ // A new game starts or the real profile changes, then we need to check if ReverseNXTool patches are applied
+ isEnabledReverseNX = false;
+
+ // Check if ReverseNXTool patches are applied
+ if (applicationId != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ this->checkReverseNXTool();
+ }
+
+ if (FileUtils::IsBoostStartEnabled() && this->context->applicationId != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ {
+ // If a game starts and override for CPU clock is not enabled, then set MAX_CPU for 10 sec
+ std::uint32_t overcpu = this->context->overrideFreqs[SysClkModule_CPU];
+ if (!overcpu)
+ {
+ tickStartBoost = (std::uint32_t)( 10'000 / this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs) ) + 1;
+ FileUtils::LogLine("[mgr] A game starts, bump CPU to max for 10 sec");
+ return true;
+ }
+ }
}
+ if (!tickCheckReverseNXRT || recheckReverseNX)
+ {
+ uint8_t flag = 0;
+ checkReverseNXRT(recheckReverseNX, &flag);
+
+ switch(flag)
+ {
+ case 1:
+ FileUtils::LogLine("[mgr] ReverseNX-RT detected: Enforce Handheld Mode");
+ this->context->profile = ReverseNXProfile(false);
+ prevReverseNXRT = flag;
+ isEnabledReverseNX = true;
+ isDockedReverseNX = false;
+ hasChanged = true;
+ break;
+ case 2:
+ FileUtils::LogLine("[mgr] ReverseNX-RT detected: Enforce Docked Mode");
+ this->context->profile = ReverseNXProfile(true);
+ prevReverseNXRT = flag;
+ isEnabledReverseNX = true;
+ isDockedReverseNX = true;
+ hasChanged = true;
+ break;
+ case 3:
+ FileUtils::LogLine("[mgr] ReverseNX-RT disabled: Reset to System-controlled Mode and recheck ReverseNX-Tool");
+ RealProfile = Clocks::GetCurrentProfile();
+ this->context->profile = RealProfile;
+ prevReverseNXRT = 0;
+ isEnabledReverseNX = false;
+ isDockedReverseNX = false;
+ hasChanged = true;
+ if (this->context->applicationId != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ this->checkReverseNXTool();
+ break;
+ case 0:
+ if (recheckReverseNX && isEnabledReverseNXTool && this->context->applicationId != PROCESS_MANAGEMENT_QLAUNCH_TID)
+ this->checkReverseNXTool();
+ break;
+ }
+ // Check once per sec
+ tickCheckReverseNXRT = (std::uint32_t)( 1'000 / this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs) ) + 1;
+ }
+ tickCheckReverseNXRT--;
+
+ if (recheckReverseNX)
+ recheckReverseNX = false;
+
SysClkProfile profile = Clocks::GetCurrentProfile();
- if (profile != this->context->profile)
+ if (profile != this->context->profile && !isEnabledReverseNX)
{
FileUtils::LogLine("[mgr] Profile change: %s", Clocks::GetProfileName(profile, true));
this->context->profile = profile;
hasChanged = true;
}
+ if (profile != RealProfile && isEnabledReverseNX)
+ {
+ FileUtils::LogLine("[mgr] Profile change: %s, recheck ReverseNX", Clocks::GetProfileName(profile, true));
+ this->context->profile = profile;
+ RealProfile = profile;
+ hasChanged = true;
+ recheckReverseNX = true;
+ }
// restore clocks to stock values on app or profile change
if(hasChanged)
{
+ if (profile == SysClkProfile_Handheld)
+ MAX_CPU = 1963'500'000;
+ else
+ MAX_CPU = 2295'000'000;
Clocks::ResetToStock();
}
@@ -142,7 +456,9 @@ bool ClockManager::RefreshContext()
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
hz = Clocks::GetCurrentHz((SysClkModule)module);
- if (hz != 0 && hz != this->context->freqs[module])
+ uint32_t cur_mhz = hz/1000'000;
+ uint32_t be4_mhz = this->context->freqs[module]/1000'000;
+ if (hz != 0 && cur_mhz != be4_mhz)
{
FileUtils::LogLine("[mgr] %s clock change: %u.%u Mhz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
this->context->freqs[module] = hz;
diff --git a/sysmodule/src/clock_manager.h b/sysmodule/src/clock_manager.h
index 3eecb21..fd5dce2 100644
--- a/sysmodule/src/clock_manager.h
+++ b/sysmodule/src/clock_manager.h
@@ -20,14 +20,32 @@
class ClockManager
{
public:
+ std::uint32_t MAX_CPU = 1963500000;
+
static ClockManager* GetInstance();
static void Initialize();
static void Exit();
+ bool recheckReverseNX = false;
+ bool isEnabledReverseNX = false;
+ bool isEnabledReverseNXTool = false;
+ bool isDockedReverseNX = false;
+ std::uint16_t tickCheckReverseNXRT = 0;
+ std::uint16_t tickStartBoost = 0;
+ char prevReverseNXRT = 0;
+ SysClkProfile RealProfile;
+
+ bool IsCpuBoostMode();
+ SysClkProfile ReverseNXProfile(bool);
+ void checkReverseNXTool();
+ bool GameStartBoost();
+
void SetRunning(bool running);
bool Running();
void Tick();
void WaitForNextTick();
+ void checkReverseNXToolAsm(FILE*, uint8_t*);
+ void checkReverseNXRT(bool, uint8_t*);
SysClkContext GetCurrentContext();
Config* GetConfig();
diff --git a/sysmodule/src/clocks.cpp b/sysmodule/src/clocks.cpp
index 62ef40f..3ef7e15 100644
--- a/sysmodule/src/clocks.cpp
+++ b/sysmodule/src/clocks.cpp
@@ -12,6 +12,8 @@
#include "clocks.h"
#include "errors.h"
+bool Clocks::isMariko = false;
+
void Clocks::GetList(SysClkModule module, std::uint32_t **outClocks)
{
switch(module)
@@ -60,6 +62,26 @@ void Clocks::Initialize()
rc = tcInitialize();
ASSERT_RESULT_OK(rc, "tcInitialize");
}
+
+ // Check if it's Mariko
+ u64 hardware_type = 0;
+ splInitialize();
+ splGetConfig(SplConfigItem_HardwareType, &hardware_type);
+ splExit();
+
+ switch(hardware_type) {
+ case 0: //Icosa
+ case 1: //Copper
+ break;
+ case 2: //Hoag
+ case 3: //Iowa
+ case 4: //Calcio
+ case 5: //Aula
+ isMariko = true;
+ break;
+ default:
+ break;
+ }
}
void Clocks::Exit()
@@ -171,7 +193,8 @@ void Clocks::ResetToStock()
Clocks::SetHz(SysClkModule_CPU, apmConfiguration->cpu_hz);
Clocks::SetHz(SysClkModule_GPU, apmConfiguration->gpu_hz);
- Clocks::SetHz(SysClkModule_MEM, apmConfiguration->mem_hz);
+ // We don't need to set MEM freqs any more
+ //Clocks::SetHz(SysClkModule_MEM, apmConfiguration->mem_hz);
}
else
{
@@ -195,16 +218,16 @@ SysClkProfile Clocks::GetCurrentProfile()
return SysClkProfile_Docked;
}
- ChargerType chargerType;
+ PsmChargerType chargerType;
rc = psmGetChargerType(&chargerType);
ASSERT_RESULT_OK(rc, "psmGetChargerType");
- if(chargerType == ChargerType_Charger)
+ if(chargerType == PsmChargerType_EnoughPower)
{
return SysClkProfile_HandheldChargingOfficial;
}
- else if(chargerType == ChargerType_Usb)
+ else if(chargerType == PsmChargerType_LowPower || chargerType == PsmChargerType_NotSupported)
{
return SysClkProfile_HandheldChargingUSB;
}
@@ -214,6 +237,10 @@ SysClkProfile Clocks::GetCurrentProfile()
void Clocks::SetHz(SysClkModule module, std::uint32_t hz)
{
+ // We don't need to set MEM freqs any more
+ if (module == SysClkModule_MEM)
+ return;
+
Result rc = 0;
if(hosversionAtLeast(8,0,0))
@@ -222,7 +249,6 @@ void Clocks::SetHz(SysClkModule module, std::uint32_t hz)
rc = clkrstOpenSession(&session, Clocks::GetPcvModuleId(module), 3);
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
-
rc = clkrstSetClockRate(&session, hz);
ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
@@ -248,7 +274,7 @@ std::uint32_t Clocks::GetCurrentHz(SysClkModule module)
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
rc = clkrstGetClockRate(&session, &hz);
- ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
+ ASSERT_RESULT_OK(rc, "clkrstGetClockRate");
clkrstCloseSession(&session);
}
@@ -280,11 +306,11 @@ std::uint32_t Clocks::GetMaxAllowedHz(SysClkModule module, SysClkProfile profile
{
if(profile < SysClkProfile_HandheldCharging)
{
- return SYSCLK_GPU_HANDHELD_MAX_HZ;
+ return isMariko ? 1536000000 : SYSCLK_GPU_HANDHELD_MAX_HZ;
}
else if(profile <= SysClkProfile_HandheldChargingUSB)
{
- return SYSCLK_GPU_UNOFFICIAL_CHARGER_MAX_HZ;
+ return isMariko ? 1536000000 : SYSCLK_GPU_UNOFFICIAL_CHARGER_MAX_HZ;
}
}
@@ -293,6 +319,79 @@ std::uint32_t Clocks::GetMaxAllowedHz(SysClkModule module, SysClkProfile profile
std::uint32_t Clocks::GetNearestHz(SysClkModule module, std::uint32_t inHz)
{
+ // Hardcoded values to return, I don't know why it will bump to max when excessive OC
+ if(module == SysClkModule_MEM)
+ {
+ switch(inHz)
+ {
+ case 1331000000:
+ return 1331200000;
+ case 1731000000:
+ return 1731200000;
+ case 1862000000:
+ return 1862400000;
+ case 1996000000:
+ return 1996800000;
+ default:
+ return inHz;
+ }
+ }
+
+ if(module == SysClkModule_CPU)
+ {
+ switch(inHz)
+ {
+ case 1963000000:
+ return 1963500000;
+ default:
+ return inHz;
+ }
+ }
+
+ if(module == SysClkModule_GPU)
+ {
+ switch(inHz)
+ {
+ case 76000000:
+ return 76800000;
+ case 153000000:
+ return 153600000;
+ case 230000000:
+ return 230400000;
+ case 307000000:
+ return 307200000;
+ case 460000000:
+ return 460800000;
+ case 537000000:
+ return 537600000;
+ case 614000000:
+ return 614400000;
+ case 691000000:
+ return 691200000;
+ case 844000000:
+ return 844800000;
+ case 921000000:
+ return 921600000;
+ case 998000000:
+ return 998400000;
+ case 1075000000:
+ return 1075200000;
+ case 1228000000:
+ return 1228800000;
+ case 1267000000:
+ return 1267200000;
+ case 1305000000:
+ return 1305600000;
+ case 1382000000:
+ return 1382400000;
+ case 1420000000:
+ return 1420800000;
+ default:
+ return inHz;
+ }
+ }
+
+ return inHz;
std::uint32_t *clockTable = NULL;
GetList(module, &clockTable);
diff --git a/sysmodule/src/clocks.h b/sysmodule/src/clocks.h
index 7f86be8..5ff180b 100644
--- a/sysmodule/src/clocks.h
+++ b/sysmodule/src/clocks.h
@@ -16,6 +16,7 @@
class Clocks
{
public:
+ static bool isMariko;
static void Exit();
static void Initialize();
static void ResetToStock();
diff --git a/sysmodule/src/file_utils.cpp b/sysmodule/src/file_utils.cpp
index 5503f44..8f91a1a 100644
--- a/sysmodule/src/file_utils.cpp
+++ b/sysmodule/src/file_utils.cpp
@@ -9,12 +9,19 @@
*/
#include "file_utils.h"
+#include "clocks.h"
+#include <dirent.h>
+#include <filesystem>
#include <nxExt.h>
static LockableMutex g_log_mutex;
static LockableMutex g_csv_mutex;
static std::atomic_bool g_has_initialized = false;
static bool g_log_enabled = false;
+static bool g_boost_enabled = false;
+static bool g_boost_start_enabled = false;
+static bool g_downclock_dock_enabled = false;
+static bool g_reversenx_enabled = false;
static std::uint64_t g_last_flag_check = 0;
extern "C" void __libnx_init_time(void);
@@ -124,9 +131,55 @@ void FileUtils::RefreshFlags(bool force)
g_log_enabled = false;
}
+ // Only Enable Boost for Mariko
+ if (Clocks::isMariko)
+ {
+ file = fopen(FILE_BOOST_FLAG_PATH, "r");
+ if (file)
+ {
+ g_boost_enabled = true;
+ fclose(file);
+ } else {
+ g_boost_enabled = false;
+ }
+
+ file = fopen(FILE_BOOST_START_FLAG_PATH, "r");
+ if (file)
+ {
+ g_boost_start_enabled = true;
+ fclose(file);
+ } else {
+ g_boost_start_enabled = false;
+ }
+ }
+
+ file = fopen(FILE_DOWNCLOCK_DOCK_FLAG_PATH, "r");
+ if (file)
+ {
+ g_downclock_dock_enabled = true;
+ fclose(file);
+ } else {
+ g_downclock_dock_enabled = false;
+ }
+
g_last_flag_check = now;
}
+bool FileUtils::IsBoostEnabled()
+{
+ return g_boost_enabled;
+}
+
+bool FileUtils::IsBoostStartEnabled()
+{
+ return g_boost_start_enabled;
+}
+
+bool FileUtils::IsDownclockDockEnabled()
+{
+ return g_downclock_dock_enabled;
+}
+
void FileUtils::InitializeAsync()
{
Thread initThread = {0};
@@ -163,9 +216,23 @@ Result FileUtils::Initialize()
FileUtils::LogLine("=== " TARGET " " TARGET_VERSION " ===");
}
+ FILE *file = fopen(FILE_SALTYNX_PATH, "r");
+ if (file)
+ {
+ g_reversenx_enabled = true;
+ fclose(file);
+ } else {
+ g_reversenx_enabled = false;
+ }
+
return rc;
}
+bool FileUtils::IsReverseNXEnabled()
+{
+ return g_reversenx_enabled;
+}
+
void FileUtils::Exit()
{
if (!g_has_initialized)
diff --git a/sysmodule/src/file_utils.h b/sysmodule/src/file_utils.h
index 4f1642e..336e63b 100644
--- a/sysmodule/src/file_utils.h
+++ b/sysmodule/src/file_utils.h
@@ -22,6 +22,11 @@
#define FILE_CONTEXT_CSV_PATH FILE_CONFIG_DIR "/context.csv"
#define FILE_LOG_FLAG_PATH FILE_CONFIG_DIR "/log.flag"
#define FILE_LOG_FILE_PATH FILE_CONFIG_DIR "/log.txt"
+#define FILE_BOOST_FLAG_PATH FILE_CONFIG_DIR "/boost.flag"
+#define FILE_BOOST_START_FLAG_PATH FILE_CONFIG_DIR "/boost_start.flag"
+#define FILE_DOWNCLOCK_DOCK_FLAG_PATH FILE_CONFIG_DIR "/downclock_dock.flag"
+#define FILE_SALTYNX_PATH "/atmosphere/contents/0000000000534C56/flags/boot2.flag" // Just check for SaltyNX boot flag
+#define FILE_REVERSENX_RT_CONF_PATH FILE_CONFIG_DIR "/ReverseNX-RT.conf"
class FileUtils
{
@@ -30,6 +35,10 @@ class FileUtils
static Result Initialize();
static bool IsInitialized();
static bool IsLogEnabled();
+ static bool IsBoostEnabled();
+ static bool IsBoostStartEnabled();
+ static bool IsDownclockDockEnabled();
+ static bool IsReverseNXEnabled();
static void InitializeAsync();
static void LogLine(const char *format, ...);
static void WriteContextToCsv(const SysClkContext* context);