Add ability to redirect app core1 threads to core2

N3DS-only option. See config.ini for details and context. This should
make very demanding games (those which already use 3x clockrate and L2C
by default, like Pokémon US/UM) between 5 to 15% faster. Not widely
tested, and can potentially break some games and other apps.
This commit is contained in:
TuxSH 2023-01-24 22:05:57 +00:00
parent ceea6afa05
commit 7b97af473a
19 changed files with 179 additions and 5 deletions

Binary file not shown.

View File

@ -62,6 +62,7 @@ static const char *singleOptionIniNamesBoot[] = {
"use_emunand_firm_if_r_pressed", "use_emunand_firm_if_r_pressed",
"enable_external_firm_and_modules", "enable_external_firm_and_modules",
"enable_game_patching", "enable_game_patching",
"app_syscore_threads_on_core_2",
"show_system_settings_string", "show_system_settings_string",
"show_gba_boot_screen", "show_gba_boot_screen",
}; };
@ -544,7 +545,8 @@ static size_t saveLumaIniConfigToStr(char *out)
(int)CONFIG_VERSIONMAJOR, (int)CONFIG_VERSIONMINOR, (int)CONFIG_VERSIONMAJOR, (int)CONFIG_VERSIONMINOR,
(int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM), (int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM),
(int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES), (int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES),
(int)CONFIG(PATCHVERSTRING), (int)CONFIG(SHOWGBABOOT), (int)CONFIG(REDIRECTAPPTHREADS), (int)CONFIG(PATCHVERSTRING),
(int)CONFIG(SHOWGBABOOT),
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS), 1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
splashPosStr, (unsigned int)cfg->splashDurationMsec, splashPosStr, (unsigned int)cfg->splashDurationMsec,
@ -716,6 +718,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"( ) Use EmuNAND FIRM if booting with R", "( ) Use EmuNAND FIRM if booting with R",
"( ) Enable loading external FIRMs and modules", "( ) Enable loading external FIRMs and modules",
"( ) Enable game patching", "( ) Enable game patching",
"( ) Redirect app. syscore threads to core2",
"( ) Show NAND or user string in System Settings", "( ) Show NAND or user string in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM", "( ) Show GBA boot screen in patched AGB_FIRM",
}; };
@ -793,6 +796,15 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"for out-of-region games work.\n\n" "for out-of-region games work.\n\n"
"Refer to the wiki for instructions.", "Refer to the wiki for instructions.",
"Redirect app. threads that would spawn\n"
"on core1, to core2 (which is an extra\n"
"CPU core for applications that usually\n"
"remains unused).\n\n"
"This improves the performance of very\n"
"demanding games (like Pok\x82mon US/UM)\n" // CP437
"by about 10%. Can break some games\n"
"and other applications.\n",
"Enable showing the current NAND/FIRM:\n\n" "Enable showing the current NAND/FIRM:\n\n"
"\t* Sys = SysNAND\n" "\t* Sys = SysNAND\n"
"\t* Emu = EmuNAND 1\n" "\t* Emu = EmuNAND 1\n"
@ -839,6 +851,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
{ .visible = nandType == FIRMWARE_EMUNAND }, { .visible = nandType == FIRMWARE_EMUNAND },
{ .visible = true }, { .visible = true },
{ .visible = true }, { .visible = true },
{ .visible = ISN3DS },
{ .visible = true }, { .visible = true },
{ .visible = true }, { .visible = true },
}; };

View File

@ -36,7 +36,7 @@
#define CONFIG_FILE "config.bin" #define CONFIG_FILE "config.bin"
#define CONFIG_VERSIONMAJOR 3 #define CONFIG_VERSIONMAJOR 3
#define CONFIG_VERSIONMINOR 2 #define CONFIG_VERSIONMINOR 3
#define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7) #define BOOTCFG_FIRM BOOTCONFIG(3, 7)
@ -59,6 +59,7 @@ enum singleOptions
USEEMUFIRM, USEEMUFIRM,
LOADEXTFIRMSANDMODULES, LOADEXTFIRMSANDMODULES,
PATCHGAMES, PATCHGAMES,
REDIRECTAPPTHREADS,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PATCHUNITINFO, PATCHUNITINFO,

View File

@ -30,6 +30,7 @@ enum singleOptions
USEEMUFIRM, USEEMUFIRM,
LOADEXTFIRMSANDMODULES, LOADEXTFIRMSANDMODULES,
PATCHGAMES, PATCHGAMES,
REDIRECTAPPTHREADS,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PATCHUNITINFO, PATCHUNITINFO,

View File

@ -54,6 +54,7 @@ extern void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 o
extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this); extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
extern Result (*CreateThread)(Handle *outThreadHandle, u32 ep, u32 arg, u32 stackTop, s32 priority, s32 processorId);
extern void (*SleepThread)(s64 ns); extern void (*SleepThread)(s64 ns);
extern Result (*CloseHandle)(Handle handle); extern Result (*CloseHandle)(Handle handle);
extern Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type); extern Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);

View File

@ -1162,7 +1162,7 @@ offsetof(classname##O3DSPre8x, field)))
#define KPROCESSHWINFO_GET_RVALUE(obj, field) *(KPROCESSHWINFO_GET_PTR(obj, field)) #define KPROCESSHWINFO_GET_RVALUE(obj, field) *(KPROCESSHWINFO_GET_PTR(obj, field))
#define KPROCESSHWINFO_GET_RVALUE_TYPE(type, obj, field) *(KPROCESSHWINFO_GET_PTR_TYPE(type, obj, field)) #define KPROCESSHWINFO_GET_RVALUE_TYPE(type, obj, field) *(KPROCESSHWINFO_GET_PTR_TYPE(type, obj, field))
extern u32 pidOffsetKProcess, hwInfoOffsetKProcess, codeSetOffsetKProcess, handleTableOffsetKProcess, debugOffsetKProcess; extern u32 pidOffsetKProcess, hwInfoOffsetKProcess, codeSetOffsetKProcess, handleTableOffsetKProcess, debugOffsetKProcess, flagsKProcess;
static inline u32 idOfProcess(KProcess *process) static inline u32 idOfProcess(KProcess *process)
{ {
@ -1195,6 +1195,13 @@ static inline KDebug *debugOfProcess(KProcess *process)
return debug; return debug;
} }
static inline u32 flagsOfProcess(KProcess *process)
{
u32 flags;
memcpy(&flags, (const u8 *)process + flagsKProcess, 4);
return flags;
}
static inline const char *classNameOfAutoObject(KAutoObject *object) static inline const char *classNameOfAutoObject(KAutoObject *object)
{ {
const char *name; const char *name;

View File

@ -0,0 +1,32 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2023 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "utils.h"
#include "kernel.h"
#include "svc.h"
Result CreateThreadHookWrapper(Handle *outThreadHandle, u32 ep, u32 arg, u32 stackTop, s32 priority, s32 processorId);
Result CreateThreadHook(Handle *outThreadHandle, u32 ep, u32 arg, u32 stackTop, s32 priority, s32 processorId);

View File

@ -50,6 +50,7 @@ void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSched
void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this); void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
Result (*CreateThread)(Handle *outThreadHandle, u32 ep, u32 arg, u32 stackTop, s32 priority, s32 processorId);
void (*SleepThread)(s64 ns); void (*SleepThread)(s64 ns);
Result (*CloseHandle)(Handle handle); Result (*CloseHandle)(Handle handle);
Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type); Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
@ -114,4 +115,4 @@ u32 stolenSystemMemRegionSize;
vu32 rosalinaState; vu32 rosalinaState;
bool hasStartedRosalinaNetworkFuncsOnce; bool hasStartedRosalinaNetworkFuncsOnce;
u32 pidOffsetKProcess, hwInfoOffsetKProcess, codeSetOffsetKProcess, handleTableOffsetKProcess, debugOffsetKProcess; u32 pidOffsetKProcess, hwInfoOffsetKProcess, codeSetOffsetKProcess, handleTableOffsetKProcess, debugOffsetKProcess, flagsKProcess;

View File

@ -127,6 +127,7 @@ void configHook(vu8 *cfgPage)
codeSetOffsetKProcess = KPROCESS_OFFSETOF(codeSet); codeSetOffsetKProcess = KPROCESS_OFFSETOF(codeSet);
handleTableOffsetKProcess = KPROCESS_OFFSETOF(handleTable); handleTableOffsetKProcess = KPROCESS_OFFSETOF(handleTable);
debugOffsetKProcess = KPROCESS_OFFSETOF(debug); debugOffsetKProcess = KPROCESS_OFFSETOF(debug);
flagsKProcess = KPROCESS_OFFSETOF(kernelFlags);
} }
static void findUsefulSymbols(void) static void findUsefulSymbols(void)
@ -240,6 +241,7 @@ static void findUsefulSymbols(void)
// The official prototype of ControlMemory doesn't have that extra param' // The official prototype of ControlMemory doesn't have that extra param'
ControlMemory = (Result (*)(u32 *, u32, u32, u32, MemOp, MemPerm, bool)) ControlMemory = (Result (*)(u32 *, u32, u32, u32, MemOp, MemPerm, bool))
decodeArmBranch((u32 *)officialSVCs[0x01] + 5); decodeArmBranch((u32 *)officialSVCs[0x01] + 5);
CreateThread = (Result (*)(Handle *, u32, u32, u32, s32, s32))decodeArmBranch((u32 *)officialSVCs[0x08] + 5);
SleepThread = (void (*)(s64))officialSVCs[0x0A]; SleepThread = (void (*)(s64))officialSVCs[0x0A];
CloseHandle = (Result (*)(Handle))officialSVCs[0x23]; CloseHandle = (Result (*)(Handle))officialSVCs[0x23];
GetHandleInfo = (Result (*)(s64 *, Handle, u32))decodeArmBranch((u32 *)officialSVCs[0x29] + 3); GetHandleInfo = (Result (*)(s64 *, Handle, u32))decodeArmBranch((u32 *)officialSVCs[0x29] + 3);

View File

@ -28,6 +28,7 @@
#include "synchronization.h" #include "synchronization.h"
#include "svc.h" #include "svc.h"
#include "svc/ControlMemory.h" #include "svc/ControlMemory.h"
#include "svc/CreateThread.h"
#include "svc/GetHandleInfo.h" #include "svc/GetHandleInfo.h"
#include "svc/GetSystemInfo.h" #include "svc/GetSystemInfo.h"
#include "svc/GetProcessInfo.h" #include "svc/GetProcessInfo.h"
@ -63,6 +64,8 @@ void buildAlteredSvcTable(void)
alteredSvcTable[0x01] = ControlMemoryHookWrapper; alteredSvcTable[0x01] = ControlMemoryHookWrapper;
if (isN3DS)
alteredSvcTable[0x08] = CreateThreadHookWrapper;
alteredSvcTable[0x29] = GetHandleInfoHookWrapper; alteredSvcTable[0x29] = GetHandleInfoHookWrapper;
alteredSvcTable[0x2A] = GetSystemInfoHookWrapper; alteredSvcTable[0x2A] = GetSystemInfoHookWrapper;
alteredSvcTable[0x2B] = GetProcessInfoHookWrapper; alteredSvcTable[0x2B] = GetProcessInfoHookWrapper;

View File

@ -0,0 +1,37 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2023 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "svc/CreateThread.h"
Result CreateThreadHook(Handle *outThreadHandle, u32 ep, u32 arg, u32 stackTop, s32 priority, s32 processorId)
{
u32 flags = flagsOfProcess(currentCoreContext->objectContext.currentProcess);
if (isN3DS && CONFIG(REDIRECTAPPTHREADS) && processorId == 1 && (flags & 0xF00) == 0x100)
processorId = 2;
return CreateThread(outThreadHandle, ep, arg, stackTop, priority, processorId);
}

View File

@ -84,3 +84,16 @@ ControlMemoryEx:
ldr r1, [sp, #12] ldr r1, [sp, #12]
add sp, #20 add sp, #20
pop {pc} pop {pc}
.global CreateThreadHookWrapper
.type CreateThreadHookWrapper, %function
CreateThreadHookWrapper:
push {lr}
sub sp, #12
str r4, [sp, #4]
str r0, [sp]
add r0, sp, #8
bl CreateThreadHook
ldr r1, [sp, #8]
add sp, sp, #12
pop {pc}

View File

@ -33,6 +33,7 @@ enum singleOptions
USEEMUFIRM, USEEMUFIRM,
LOADEXTFIRMSANDMODULES, LOADEXTFIRMSANDMODULES,
PATCHGAMES, PATCHGAMES,
REDIRECTAPPTHREADS,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PATCHUNITINFO, PATCHUNITINFO,

View File

@ -3,6 +3,23 @@
#include "luma.h" #include "luma.h"
#include "util.h" #include "util.h"
u32 config, multiConfig, bootConfig;
void readLumaConfig(void)
{
s64 out = 0;
bool isLumaWithKext = svcGetSystemInfo(&out, 0x20000, 0) == 1;
if (isLumaWithKext)
{
svcGetSystemInfo(&out, 0x10000, 3);
config = (u32)out;
svcGetSystemInfo(&out, 0x10000, 4);
multiConfig = (u32)out;
svcGetSystemInfo(&out, 0x10000, 5);
bootConfig = (u32)out;
}
}
bool hasKExt(void) bool hasKExt(void)
{ {
s64 val; s64 val;

View File

@ -2,6 +2,42 @@
#include <3ds/types.h> #include <3ds/types.h>
#define CONFIG(a) (((config >> (a)) & 1) != 0)
#define MULTICONFIG(a) ((multiConfig >> (2 * (a))) & 3)
#define BOOTCONFIG(a, b) ((bootConfig >> (a)) & (b))
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1)
#define BOOTCFG_NTRCARDBOOT BOOTCONFIG(7, 1)
enum multiOptions
{
DEFAULTEMU = 0,
BRIGHTNESS,
SPLASH,
PIN,
NEWCPU,
AUTOBOOTMODE,
};
enum singleOptions
{
AUTOBOOTEMU = 0,
USEEMUFIRM,
LOADEXTFIRMSANDMODULES,
PATCHGAMES,
REDIRECTAPPTHREADS,
PATCHVERSTRING,
SHOWGBABOOT,
PATCHUNITINFO,
DISABLEARM11EXCHANDLERS,
ENABLESAFEFIRMROSALINA,
};
extern u32 config, multiConfig, bootConfig;
void readLumaConfig(void);
bool hasKExt(void); bool hasKExt(void);
u32 getKExtSize(void); u32 getKExtSize(void);
u32 getStolenSystemMemRegionSize(void); u32 getStolenSystemMemRegionSize(void);

View File

@ -13,6 +13,7 @@
#include "util.h" #include "util.h"
#include "my_thread.h" #include "my_thread.h"
#include "service_manager.h" #include "service_manager.h"
#include "luma.h"
static MyThread processMonitorThread, taskRunnerThread; static MyThread processMonitorThread, taskRunnerThread;
static u8 ALIGN(8) processDataBuffer[0x40 * sizeof(ProcessData)] = {0}; static u8 ALIGN(8) processDataBuffer[0x40 * sizeof(ProcessData)] = {0};
@ -34,6 +35,7 @@ Result __sync_init(void);
void initSystem() void initSystem()
{ {
__sync_init(); __sync_init();
readLumaConfig();
//__libc_init_array(); //__libc_init_array();
// Wait for sm // Wait for sm

View File

@ -308,6 +308,11 @@ Result resetAppMemLimit(void)
Result setAppCpuTimeLimit(s64 limit) Result setAppCpuTimeLimit(s64 limit)
{ {
// Prevent apps from enabling preemption on core1 (and kernel will
// redirect apps threads from core 1 to 2).
if (IS_N3DS && CONFIG(REDIRECTAPPTHREADS))
return 0;
ResourceLimitType category = RESLIMIT_CPUTIME; ResourceLimitType category = RESLIMIT_CPUTIME;
return svcSetResourceLimitValues(g_manager.reslimits[0], &category, &limit, 1); return svcSetResourceLimitValues(g_manager.reslimits[0], &category, &limit, 1);
} }

View File

@ -49,6 +49,7 @@ enum singleOptions
USEEMUFIRM, USEEMUFIRM,
LOADEXTFIRMSANDMODULES, LOADEXTFIRMSANDMODULES,
PATCHGAMES, PATCHGAMES,
REDIRECTAPPTHREADS,
PATCHVERSTRING, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PATCHUNITINFO, PATCHUNITINFO,
@ -315,7 +316,8 @@ static size_t saveLumaIniConfigToStr(char *out, const CfgData *cfg)
(int)cfg->formatVersionMajor, (int)cfg->formatVersionMinor, (int)cfg->formatVersionMajor, (int)cfg->formatVersionMinor,
(int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM), (int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM),
(int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES), (int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES),
(int)CONFIG(PATCHVERSTRING), (int)CONFIG(SHOWGBABOOT), (int)CONFIG(REDIRECTAPPTHREADS), (int)CONFIG(PATCHVERSTRING),
(int)CONFIG(SHOWGBABOOT),
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS), 1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
splashPosStr, (unsigned int)cfg->splashDurationMsec, splashPosStr, (unsigned int)cfg->splashDurationMsec,