diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 11d093b..fd79937 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -7,13 +7,13 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload -- THIS IS NOT A SUPPORT FORUM! For support go here: -- Nintendo Homebrew: https://discord.gg/MjzatM8 -- --- Rosalina feature requests go here: https://github.com/AuroraWright/Luma3DS/issues/752 +-- Rosalina feature requests go here: https://github.com/LumaTeam/Luma3DS/issues/752 -- --- Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue. +-- Also check the Wiki (https://github.com/LumaTeam/Luma3DS/wiki) before making an issue. -- -- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: use https://github.com/MechanicalDragon0687/TWLFix-CFW and update your system. -- If you're using an emu/redNAND try installing anything on it to sysNAND. --- Please make sure to read "Enable game patching" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s). +-- Please make sure to read "Enable game patching" https://github.com/LumaTeam/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s). -- -- Luma updaters that don't support Boot9Strap/Sighax won't work. -- This is due to support for non-B9S/Sighax entrypoints being dropped. @@ -21,7 +21,7 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload -- Please fill in the placeholders.--> **System model:** -[e.g. 2DS, New 3DS, Old 3DS] +[New 2DS XL, New 3DS XL, New 3DS, Old 2DS, Old 3DS XL, Old 3DS] **SysNAND version (+emu/redNAND version if applicable):** @@ -34,7 +34,7 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload **Luma3DS version:** -[e.g. v10.1.3 stable or if using non-releases specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/0543c208fd154e6326ea5da8cbf66ffcbdef010c] +[e.g. v10.2 stable or if using non-releases specify the commit like this https://github.com/LumaTeam/Luma3DS/commit/0543c208fd154e6326ea5da8cbf66ffcbdef010c] **Luma3DS configuration/options:** @@ -50,7 +50,7 @@ Splash duration: ( ) PIN lock: ( ) New 3DS CPU: ( ) - + -- @@ -70,12 +70,13 @@ Show NAND or user string in System Settings: ( ) Show GBA boot screen in patched AGB_FIRM: ( ) -Patch Arm9 access: ( ) - Set developer UNITINFO: ( ) Disable Arm11 exception handlers: ( ) +Enable Rosalina on SAFE_FIRM: ( ) + + -- diff --git a/.gitignore b/.gitignore index e9a1bf2..8705440 100644 --- a/.gitignore +++ b/.gitignore @@ -13,9 +13,12 @@ exceptions/arm11/build *.d *.elf *.cxi +*.3dsx .DS_Store *.dmp .project .cproject .settings .idea/ + +Luma3DS*.zip diff --git a/Makefile b/Makefile index 7dae32d..54c3153 100644 --- a/Makefile +++ b/Makefile @@ -15,9 +15,10 @@ release: $(NAME)$(REVISION).zip clean: @$(foreach dir, $(SUBFOLDERS), $(MAKE) -C $(dir) clean &&) true - @rm -rf *.firm *.zip + @rm -rf *.firm *.zip *.3dsx -$(NAME)$(REVISION).zip: boot.firm exception_dump_parser +# boot.3dsx comes from https://github.com/fincs/new-hbmenu/releases +$(NAME)$(REVISION).zip: boot.firm boot.3dsx @zip -r $@ $^ -x "*.DS_Store*" "*__MACOSX*" boot.firm: $(SUBFOLDERS) @@ -25,5 +26,9 @@ boot.firm: $(SUBFOLDERS) -A 0x18180000 -C XDMA XDMA NDMA XDMA @echo built... $(notdir $@) +boot.3dsx: + @curl -sSL "https://github.com/fincs/new-hbmenu/releases/latest/download/boot.3dsx" -o "$@" + @echo downloaded... $(notdir $@) + $(SUBFOLDERS): @$(MAKE) -C $@ all diff --git a/arm9/source/exceptions.c b/arm9/source/exceptions.c index ca45a77..e21bb03 100644 --- a/arm9/source/exceptions.c +++ b/arm9/source/exceptions.c @@ -34,6 +34,8 @@ #include "buttons.h" #include "arm9_exception_handlers.h" +// See https://github.com/LumaTeam/luma3ds_exception_dump_parser + void installArm9Handlers(void) { vu32 *dstVeneers = (vu32 *)0x08000000; diff --git a/exception_dump_parser/luma3ds_exception_dump_parser/__init__.py b/exception_dump_parser/luma3ds_exception_dump_parser/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/exception_dump_parser/setup.py b/exception_dump_parser/setup.py deleted file mode 100644 index 13a6915..0000000 --- a/exception_dump_parser/setup.py +++ /dev/null @@ -1,13 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name='luma3ds_exception_dump_parser', - version='1.2', - url='https://github.com/AuroraWright/Luma3DS', - author='TuxSH', - license='GPLv3', - description='Parses Luma3DS exception dumps', - install_requires=[''], - packages=find_packages(), - entry_points={'console_scripts': ['luma3ds_exception_dump_parser=luma3ds_exception_dump_parser.__main__:main']}, -) diff --git a/k11_extension/include/synchronization.h b/k11_extension/include/synchronization.h index 32635a7..b577e2e 100644 --- a/k11_extension/include/synchronization.h +++ b/k11_extension/include/synchronization.h @@ -36,11 +36,12 @@ void executeFunctionOnCores(SGI0Handler_t func, u8 targetList, u8 targetListFilt void KScheduler__TriggerCrossCoreInterrupt(KScheduler *this); void KThread__DebugReschedule(KThread *this, bool lock); -bool rosalinaThreadLockPredicate(KThread *thread); + +bool rosalinaThreadLockPredicate(KThread *thread, u32 mask); void rosalinaRescheduleThread(KThread *thread, bool lock); -void rosalinaLockThread(KThread *thread); -void rosalinaLockAllThreads(void); -void rosalinaUnlockAllThreads(void); + +void rosalinaLockThreads(u32 mask); +void rosalinaUnlockThreads(u32 mask); // Taken from ctrulib: @@ -49,6 +50,11 @@ static inline void __dsb(void) __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 4" :: [val] "r" (0) : "memory"); } +static inline void __dmb(void) +{ + __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); +} + static inline void __clrex(void) { __asm__ __volatile__("clrex" ::: "memory"); diff --git a/k11_extension/source/svc.c b/k11_extension/source/svc.c index 3a21430..722c301 100644 --- a/k11_extension/source/svc.c +++ b/k11_extension/source/svc.c @@ -89,7 +89,7 @@ void signalSvcReturn(u8 *pageEnd) void postprocessSvc(void) { KThread *currentThread = currentCoreContext->objectContext.currentThread; - if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread)) + if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread, rosalinaState & 5)) rosalinaRescheduleThread(currentThread, true); officialPostProcessSvc(); diff --git a/k11_extension/source/svc/KernelSetState.c b/k11_extension/source/svc/KernelSetState.c index 7f8679f..8533735 100644 --- a/k11_extension/source/svc/KernelSetState.c +++ b/k11_extension/source/svc/KernelSetState.c @@ -105,14 +105,22 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3) __ldrex((s32 *)&rosalinaState); } while(__strex((s32 *)&rosalinaState, (s32)(rosalinaState ^ varg1))); + __dmb(); - if(rosalinaState & 2) + if(rosalinaState & 0x10) hasStartedRosalinaNetworkFuncsOnce = true; - if(rosalinaState & 1) - rosalinaLockAllThreads(); - else if(varg1 & 1) - rosalinaUnlockAllThreads(); + // 1: all applet/app/dsp/csnd... threads 2: gsp 4: hid/ir + for (u32 v = 4; v != 0; v >>= 1) + { + if (varg1 & v) + { + if (rosalinaState & v) + rosalinaLockThreads(v); + else + rosalinaUnlockThreads(v); + } + } break; } diff --git a/k11_extension/source/svc/SendSyncRequest.c b/k11_extension/source/svc/SendSyncRequest.c index 0834254..507b32e 100644 --- a/k11_extension/source/svc/SendSyncRequest.c +++ b/k11_extension/source/svc/SendSyncRequest.c @@ -28,9 +28,16 @@ #include "svc/SendSyncRequest.h" #include "ipc.h" +static inline bool isNdmuWorkaround(const SessionInfo *info, u32 pid) +{ + return info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce && pid >= nbSection0Modules; +} + Result SendSyncRequestHook(Handle handle) { - KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; + KProcessHandleTable *handleTable = handleTableOfProcess(currentProcess); + u32 pid = idOfProcess(currentProcess); KClientSession *clientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, handle); u32 *cmdbuf = (u32 *)((u8 *)currentCoreContext->objectContext.currentThread->threadLocalStorage + 0x80); @@ -47,7 +54,7 @@ Result SendSyncRequestHook(Handle handle) case 0x10042: { SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); - if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce) + if(isNdmuWorkaround(info, pid)) { cmdbuf[0] = 0x10040; cmdbuf[1] = 0; @@ -87,7 +94,7 @@ Result SendSyncRequestHook(Handle handle) case 0x20002: { SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); - if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce) + if(isNdmuWorkaround(info, pid)) { cmdbuf[0] = 0x20040; cmdbuf[1] = 0; @@ -129,7 +136,7 @@ Result SendSyncRequestHook(Handle handle) if(!hasStartedRosalinaNetworkFuncsOnce) break; SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); - skip = info != NULL && strcmp(info->name, "ndm:u") == 0; // SuspendScheduler + skip = isNdmuWorkaround(info, pid); // SuspendScheduler if(skip) cmdbuf[1] = 0; break; @@ -140,7 +147,7 @@ Result SendSyncRequestHook(Handle handle) if(!hasStartedRosalinaNetworkFuncsOnce) break; SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); - if(info != NULL && strcmp(info->name, "ndm:u") == 0) // ResumeScheduler + if(isNdmuWorkaround(info, pid)) // ResumeScheduler { cmdbuf[0] = 0x90040; cmdbuf[1] = 0; diff --git a/k11_extension/source/synchronization.c b/k11_extension/source/synchronization.c index eb88c6a..4b00072 100644 --- a/k11_extension/source/synchronization.c +++ b/k11_extension/source/synchronization.c @@ -66,17 +66,12 @@ void KThread__DebugReschedule(KThread *this, bool lock) KRecursiveLock__Unlock(criticalSectionLock); } -bool rosalinaThreadLockPredicate(KThread *thread) +static void rosalinaLockThread(KThread *thread) { - KProcess *process = thread->ownerProcess; - if(process == NULL) - return false; + KThread *syncThread = synchronizationMutex->owner; - u64 titleId = codeSetOfProcess(process)->titleId; - u32 highTitleId = (u32)(titleId >> 32), lowTitleId = (u32)(titleId & ~0xF0000001); // clear N3DS and SAFE_FIRM bits - return - ((rosalinaState & 1) && idOfProcess(process) >= nbSection0Modules && - (highTitleId != 0x00040130 || (highTitleId == 0x00040130 && (lowTitleId == 0x1A02 || lowTitleId == 0x1C02)))); + if(syncThread == NULL || syncThread != thread) + rosalinaRescheduleThread(thread, true); } void rosalinaRescheduleThread(KThread *thread, bool lock) @@ -89,20 +84,45 @@ void rosalinaRescheduleThread(KThread *thread, bool lock) else thread->schedulingMask &= ~0x40; - KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask); + if (oldSchedulingMask != thread->schedulingMask) + KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask); KRecursiveLock__Unlock(criticalSectionLock); } -void rosalinaLockThread(KThread *thread) +bool rosalinaThreadLockPredicate(KThread *thread, u32 mask) { - KThread *syncThread = synchronizationMutex->owner; + KProcess *process = thread->ownerProcess; + if(process == NULL || idOfProcess(process) < nbSection0Modules) + return false; - if(syncThread == NULL || syncThread != thread) - rosalinaRescheduleThread(thread, true); + u64 titleId = codeSetOfProcess(process)->titleId; + u32 highTitleId = (u32)(titleId >> 32), lowTitleId = (u32)(titleId & ~0xF0000001); // clear N3DS and SAFE_FIRM bits + + if (mask & 1) + { + if (highTitleId != 0x00040130) // non-sysmodules + return true; + else + return lowTitleId == 0x1A02 || lowTitleId == 0x2702; // dsp, csnd + } + if (mask & 2) + { + if (highTitleId != 0x00040130) // non-sysmodules + false; + return lowTitleId == 0x1C02; // gsp + } + if (mask & 4) + { + if (highTitleId != 0x00040130) // non-sysmodules + return false; + return lowTitleId == 0x1D02 || lowTitleId == 0x3302; + } + + return false; } -void rosalinaLockAllThreads(void) +void rosalinaLockThreads(u32 mask) { bool currentThreadsFound = false; @@ -110,7 +130,7 @@ void rosalinaLockAllThreads(void) for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next) { KThread *thread = (KThread *)node->key; - if(!rosalinaThreadLockPredicate(thread)) + if(!rosalinaThreadLockPredicate(thread, mask)) continue; if(thread == coreCtxs[thread->coreId].objectContext.currentThread) currentThreadsFound = true; @@ -123,7 +143,7 @@ void rosalinaLockAllThreads(void) for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next) { KThread *thread = (KThread *)node->key; - if(!rosalinaThreadLockPredicate(thread)) + if(!rosalinaThreadLockPredicate(thread, mask)) continue; if(!(thread->schedulingMask & 0x40)) { @@ -145,7 +165,7 @@ void rosalinaLockAllThreads(void) KRecursiveLock__Unlock(criticalSectionLock); } -void rosalinaUnlockAllThreads(void) +void rosalinaUnlockThreads(u32 mask) { for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next) { @@ -154,7 +174,7 @@ void rosalinaUnlockAllThreads(void) if((thread->schedulingMask & 0xF) == 2) // thread is terminating continue; - if(thread->schedulingMask & 0x40) + if((thread->schedulingMask & 0x40) && rosalinaThreadLockPredicate(thread, mask)) rosalinaRescheduleThread(thread, false); } } diff --git a/sysmodules/loader/source/hbldr.h b/sysmodules/loader/source/hbldr.h index 34e22c4..4da0c12 100644 --- a/sysmodules/loader/source/hbldr.h +++ b/sysmodules/loader/source/hbldr.h @@ -2,8 +2,6 @@ #include <3ds/exheader.h> -#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100) - Result hbldrInit(void); void hbldrExit(void); diff --git a/sysmodules/loader/source/loader.c b/sysmodules/loader/source/loader.c index 26aaf4b..dc4f55e 100644 --- a/sysmodules/loader/source/loader.c +++ b/sysmodules/loader/source/loader.c @@ -4,6 +4,7 @@ #include "ifile.h" #include "util.h" #include "hbldr.h" +#include "luma_shared_config.h" extern u32 config, multiConfig, bootConfig; extern bool isN3DS, isSdMode; @@ -91,6 +92,11 @@ static int lzss_decompress(u8 *end) return ret; } +static inline bool hbldrIs3dsxTitle(u64 tid) +{ + return Luma_SharedConfig->use_hbldr && tid == Luma_SharedConfig->hbldr_3dsx_tid; +} + static Result allocateSharedMem(prog_addrs_t *shared, prog_addrs_t *vaddr, int flags) { u32 dummy; @@ -184,11 +190,8 @@ static Result GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle) } } - s64 nbSection0Modules; - svcGetSystemInfo(&nbSection0Modules, 26, 0); - // Tweak 3dsx placeholder title exheaderInfo - if (nbSection0Modules == 6 && exheaderInfo->aci.local_caps.title_id == HBLDR_3DSX_TID) + if (hbldrIs3dsxTitle(exheaderInfo->aci.local_caps.title_id)) { assertSuccess(hbldrInit()); HBLDR_PatchExHeaderInfo(exheaderInfo); @@ -219,7 +222,7 @@ static Result LoadProcess(Handle *process, u64 programHandle) u64 titleId; // make sure the cached info corrosponds to the current programHandle - if (g_cached_programHandle != programHandle || g_exheaderInfo.aci.local_caps.title_id == HBLDR_3DSX_TID) + if (g_cached_programHandle != programHandle || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id)) { res = GetProgramInfo(&g_exheaderInfo, programHandle); g_cached_programHandle = programHandle; @@ -245,7 +248,7 @@ static Result LoadProcess(Handle *process, u64 programHandle) titleId = g_exheaderInfo.aci.local_caps.title_id; ExHeader_CodeSetInfo *csi = &g_exheaderInfo.sci.codeset_info; - if (titleId == HBLDR_3DSX_TID) + if (hbldrIs3dsxTitle(titleId)) { assertSuccess(hbldrInit()); assertSuccess(HBLDR_LoadProcess(&codeset, csi->text.address, flags & 0xF00, titleId, csi->name)); @@ -425,7 +428,7 @@ void loaderHandleCommands(void *ctx) break; case 4: // GetProgramInfo memcpy(&programHandle, &cmdbuf[1], 8); - if (programHandle != g_cached_programHandle || g_exheaderInfo.aci.local_caps.title_id == HBLDR_3DSX_TID) + if (programHandle != g_cached_programHandle || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id)) { res = GetProgramInfo(&g_exheaderInfo, programHandle); g_cached_programHandle = R_SUCCEEDED(res) ? programHandle : 0; diff --git a/sysmodules/loader/source/luma_shared_config.h b/sysmodules/loader/source/luma_shared_config.h new file mode 100644 index 0000000..f956a83 --- /dev/null +++ b/sysmodules/loader/source/luma_shared_config.h @@ -0,0 +1,28 @@ +/* This paricular file is licensed under the following terms: */ + +/* +* This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable +* for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it +* and redistribute it freely, subject to the following restrictions: +* +* The origin of this software must not be misrepresented; you must not claim that you wrote the original software. +* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +* +* Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +* This notice may not be removed or altered from any source distribution. +*/ + +#pragma once + +#include <3ds/types.h> + +/// Luma shared config type. +typedef struct LumaSharedConfig { + u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading. + bool use_hbldr; ///< Whether or not Loader should use hb:ldr (Rosalina writes 1). +} LumaSharedConfig; + +/// Luma shared config. +#define Luma_SharedConfig ((volatile LumaSharedConfig *)(OS_SHAREDCFG_VADDR + 0x800)) diff --git a/sysmodules/pm/README.md b/sysmodules/pm/README.md index 64b7ee4..ecf4f64 100644 --- a/sysmodules/pm/README.md +++ b/sysmodules/pm/README.md @@ -3,7 +3,7 @@ Open source replacement of the Arm11 PM system module. This is licensed under the MIT license. # Usage -To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/), build this project and copy the generated CXI file to `/luma/sysmodules/pm.cxi`. +To run this system module, use a recent release or commit of [Luma3DS](https://github.com/LumaTeam/Luma3DS/), build this project and copy the generated CXI file to `/luma/sysmodules/pm.cxi`. # Credits @fincs diff --git a/sysmodules/pm/source/launch.c b/sysmodules/pm/source/launch.c index be6accf..efc40a4 100644 --- a/sysmodules/pm/source/launch.c +++ b/sysmodules/pm/source/launch.c @@ -218,8 +218,9 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const programInfoUpdate = (launchFlags & PMLAUNCHFLAG_USE_UPDATE_TITLE) ? programInfoUpdate : programInfo; TRY(registerProgram(&programHandle, programInfo, programInfoUpdate)); + u32 coreVer = OS_KernelConfig->kernel_syscore_ver; res = LOADER_GetProgramInfo(exheaderInfo, programHandle); - res = R_SUCCEEDED(res) && SYSCOREVER == 2 && exheaderInfo->aci.local_caps.core_info.core_version != SYSCOREVER ? (Result)0xC8A05800 : res; + res = R_SUCCEEDED(res) && coreVer == 2 && exheaderInfo->aci.local_caps.core_info.core_version != coreVer ? (Result)0xC8A05800 : res; if (R_FAILED(res)) { LOADER_UnregisterProgram(programHandle); @@ -227,7 +228,7 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const } // Change APPMEMALLOC if needed - if (IS_N3DS && APPMEMTYPE == 6 && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) { + if (IS_N3DS && OS_KernelConfig->app_memtype == 6 && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) { u32 limitMb; SystemMode n3dsSystemMode = exheaderInfo->aci.local_caps.core_info.n3ds_system_mode; bool forceO3dsAppMem = (launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) != 0; @@ -332,9 +333,11 @@ Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFla u32 tidh = (u32)(programInfo->programId >> 32); u32 tidl = (u32)programInfo->programId; - if ((tidh == 0x00040030 || tidh == 0x00040130) && (tidl & 0xFF) != SYSCOREVER) { + u32 coreVer = OS_KernelConfig->kernel_syscore_ver; + if (coreVer == 2 && (tidh == 0x00040030 || tidh == 0x00040130) && (tidl & 0xFF) != coreVer) { // Panic if launching SAFE_MODE sysmodules or applets (note: exheader syscorever check above only done for applications in official PM) // Official PM also hardcodes SYSCOREVER = 2 here. + // NATIVE_FIRM-only. panic(4); } @@ -520,8 +523,8 @@ Result autolaunchSysmodules(void) FS_ProgramInfo programInfo = { .mediaType = MEDIATYPE_NAND }; // Launch NS - if (NSTID != 0) { - programInfo.programId = NSTID; + if (OS_KernelConfig->ns_tid != 0) { + programInfo.programId = OS_KernelConfig->ns_tid; TRY(launchTitleImplWrapper(NULL, NULL, &programInfo, &programInfo, PMLAUNCHFLAG_LOAD_DEPENDENCIES)); } diff --git a/sysmodules/pm/source/process_monitor.c b/sysmodules/pm/source/process_monitor.c index cf65958..c2847d6 100644 --- a/sysmodules/pm/source/process_monitor.c +++ b/sysmodules/pm/source/process_monitor.c @@ -29,7 +29,7 @@ static void cleanupProcess(ProcessData *process) ProcessList_Lock(&g_manager.processList); if (g_manager.runningApplicationData != NULL && process->handle == g_manager.runningApplicationData->handle) { - if (IS_N3DS && APPMEMTYPE == 6) { + if (IS_N3DS && OS_KernelConfig->app_memtype == 6) { assertSuccess(resetAppMemLimit()); } g_manager.runningApplicationData = NULL; diff --git a/sysmodules/pm/source/reslimit.c b/sysmodules/pm/source/reslimit.c index 824c1aa..4dad971 100644 --- a/sysmodules/pm/source/reslimit.c +++ b/sysmodules/pm/source/reslimit.c @@ -252,7 +252,8 @@ static ReslimitValues *fixupReslimitValues(void) // Note: we lie in the reslimit and make as if neither KExt nor Roslina existed, to avoid breakage - u32 sysmemalloc = SYSMEMALLOC + (hasKExt() ? getStolenSystemMemRegionSize() : 0); + u32 appmemalloc = OS_KernelConfig->memregion_sz[0]; + u32 sysmemalloc = OS_KernelConfig->memregion_sz[1] + (hasKExt() ? getStolenSystemMemRegionSize() : 0); ReslimitValues *values = !IS_N3DS ? g_o3dsReslimitValues : g_n3dsReslimitValues; static const u32 minAppletMemAmount = 0x1200000; @@ -261,7 +262,7 @@ static ReslimitValues *fixupReslimitValues(void) u32 baseRegionSize = !IS_N3DS ? 0x1400000 : 0x2000000; if (sysmemalloc < minAppletMemAmount) { - values[1][0] = SYSMEMALLOC - minAppletMemAmount / 3; + values[1][0] = sysmemalloc - minAppletMemAmount / 3; values[2][0] = 0; values[3][0] = baseRegionSize + otherMinOvercommitAmount; } else { @@ -271,8 +272,8 @@ static ReslimitValues *fixupReslimitValues(void) values[3][0] = baseRegionSize + (otherMinOvercommitAmount + excess / 4); } - values[0][0] = APPMEMALLOC; - g_defaultAppMemLimit = APPMEMALLOC; + values[0][0] = appmemalloc; + g_defaultAppMemLimit = appmemalloc; return values; } diff --git a/sysmodules/pm/source/util.h b/sysmodules/pm/source/util.h index 0a3cf20..4618a4c 100644 --- a/sysmodules/pm/source/util.h +++ b/sysmodules/pm/source/util.h @@ -8,13 +8,7 @@ #define REG32(reg) (*(vu32 *)reg) #define REG64(reg) (*(vu64 *)reg) -#define NSTID REG64(0x1FF80008) -#define SYSCOREVER REG32(0x1FF80010) -#define APPMEMTYPE REG32(0x1FF80030) -#define APPMEMALLOC REG32(0x1FF80040) -#define SYSMEMALLOC REG32(0x1FF80044) - -#define IS_N3DS (*(vu32 *)0x1FF80030 >= 6) // APPMEMTYPE. Hacky but doesn't use APT +#define IS_N3DS (OS_KernelConfig->app_memtype >= 6) // APPMEMTYPE. Hacky but doesn't use APT #define N3DS_TID_MASK 0xF0000000ULL #define N3DS_TID_BIT 0x20000000ULL diff --git a/sysmodules/pxi/README.md b/sysmodules/pxi/README.md index 2687003..37a2768 100644 --- a/sysmodules/pxi/README.md +++ b/sysmodules/pxi/README.md @@ -3,7 +3,7 @@ Open source replacement of the Arm11 PXI system module. This is licensed under the MIT license. # Usage -To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/. +To run this system module, use a recent release or commit of [Luma3DS](https://github.com/LumaTeam/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/. # Credits This list is not complete at all: diff --git a/sysmodules/rosalina/include/hbloader.h b/sysmodules/rosalina/include/hbloader.h index a6fb94d..b2fbcca 100644 --- a/sysmodules/rosalina/include/hbloader.h +++ b/sysmodules/rosalina/include/hbloader.h @@ -31,7 +31,6 @@ #include "MyThread.h" #define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL -#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100) void HBLDR_RestartHbApplication(void *p); void HBLDR_HandleCommands(void *ctx); diff --git a/sysmodules/rosalina/include/luma_shared_config.h b/sysmodules/rosalina/include/luma_shared_config.h new file mode 100644 index 0000000..b63c433 --- /dev/null +++ b/sysmodules/rosalina/include/luma_shared_config.h @@ -0,0 +1,30 @@ +/* This paricular file is licensed under the following terms: */ + +/* +* This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable +* for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it +* and redistribute it freely, subject to the following restrictions: +* +* The origin of this software must not be misrepresented; you must not claim that you wrote the original software. +* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +* +* Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +* This notice may not be removed or altered from any source distribution. +*/ + +#pragma once + +#include <3ds/types.h> + +#include <3ds/types.h> + +/// Luma shared config type. +typedef struct LumaSharedConfig { + u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading. + bool use_hbldr; ///< Whether or not Loader should use hb:ldr (Rosalina writes 1). +} LumaSharedConfig; + +/// Luma shared config. +#define Luma_SharedConfig ((volatile LumaSharedConfig *)(OS_SHAREDCFG_VADDR + 0x800)) diff --git a/sysmodules/rosalina/include/luminance.h b/sysmodules/rosalina/include/luminance.h new file mode 100644 index 0000000..1b48036 --- /dev/null +++ b/sysmodules/rosalina/include/luminance.h @@ -0,0 +1,33 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016-2020 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 . +* +* 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. +*/ + +#pragma once + +#include <3ds/types.h> + +u32 getMinLuminancePreset(void); +u32 getMaxLuminancePreset(void); +u32 getCurrentLuminance(bool top); diff --git a/sysmodules/rosalina/include/menus/screen_filters.h b/sysmodules/rosalina/include/menus/screen_filters.h index 72323b9..d624cb4 100644 --- a/sysmodules/rosalina/include/menus/screen_filters.h +++ b/sysmodules/rosalina/include/menus/screen_filters.h @@ -32,6 +32,8 @@ extern Menu screenFiltersMenu; extern int screenFiltersCurrentTemperature; +void ScreenFiltersMenu_RestoreCct(void); + void ScreenFiltersMenu_SetDefault(void); // 6500K (default) void ScreenFiltersMenu_SetAquarium(void); // 10000K diff --git a/sysmodules/rosalina/include/minisoc.h b/sysmodules/rosalina/include/minisoc.h index 6040bc8..c735171 100644 --- a/sysmodules/rosalina/include/minisoc.h +++ b/sysmodules/rosalina/include/minisoc.h @@ -21,6 +21,10 @@ extern bool miniSocEnabled; Result miniSocInit(void); + +void miniSocLockState(void); +void miniSocUnlockState(bool force); + Result miniSocExitDirect(void); Result miniSocExit(void); diff --git a/sysmodules/rosalina/include/utils.h b/sysmodules/rosalina/include/utils.h index bb84620..333f085 100644 --- a/sysmodules/rosalina/include/utils.h +++ b/sysmodules/rosalina/include/utils.h @@ -31,6 +31,7 @@ #include <3ds/result.h> #include <3ds/ipc.h> #include "csvc.h" +#include "luma_shared_config.h" // For accessing physmem uncached (and directly) #define PA_PTR(addr) (void *)((u32)(addr) | 1 << 31) diff --git a/sysmodules/rosalina/source/hbloader.c b/sysmodules/rosalina/source/hbloader.c index d3f2775..6c45478 100644 --- a/sysmodules/rosalina/source/hbloader.c +++ b/sysmodules/rosalina/source/hbloader.c @@ -36,9 +36,6 @@ #include "gdb/server.h" #include "pmdbgext.h" -#define SYSCOREVER (*(vu32 *)0x1FF80010) -#define APPMEMTYPE (*(vu32 *)0x1FF80030) - extern GDBContext *nextApplicationGdbCtx; extern GDBServer gdbServer; @@ -148,7 +145,7 @@ static const u32 kernelCaps[] = 0xFF81FF78, // RW static mapping: 0x1FF78000 0xFF91F000, // RO static mapping: 0x1F000000 0xFF91F600, // RO static mapping: 0x1F600000 - 0xFF002101, // Exflags: APPLICATION memtype + "Allow debug" + "Access core2" + 0xFF002109, // Exflags: APPLICATION memtype + "Shared page writing" + "Allow debug" + "Access core2" 0xFE000200, // Handle table size: 0x200 }; @@ -310,21 +307,22 @@ void HBLDR_HandleCommands(void *ctx) memcpy(&exhi->sci.codeset_info.stack_size, &stacksize, 4); memset(&exhi->sci.dependencies, 0, sizeof(exhi->sci.dependencies)); - if (SYSCOREVER == 2) + u32 coreVer = OS_KernelConfig->kernel_syscore_ver; + if (coreVer == 2) memcpy(exhi->sci.dependencies, dependencyListNativeFirm, sizeof(dependencyListNativeFirm)); - else if (SYSCOREVER == 3) + else if (coreVer == 3) memcpy(exhi->sci.dependencies, dependencyListSafeFirm, sizeof(dependencyListSafeFirm)); ExHeader_Arm11SystemLocalCapabilities* localcaps0 = &exhi->aci.local_caps; - localcaps0->core_info.core_version = SYSCOREVER; + localcaps0->core_info.core_version = coreVer; localcaps0->core_info.use_cpu_clockrate_804MHz = false; localcaps0->core_info.enable_l2c = false; localcaps0->core_info.ideal_processor = 0; localcaps0->core_info.affinity_mask = BIT(0); localcaps0->core_info.priority = 0x30; - u32 appmemtype = APPMEMTYPE; + u32 appmemtype = OS_KernelConfig->app_memtype; localcaps0->core_info.o3ds_system_mode = appmemtype < 6 ? (SystemMode)appmemtype : SYSMODE_O3DS_PROD; localcaps0->core_info.n3ds_system_mode = appmemtype >= 6 ? (SystemMode)(appmemtype - 6 + 1) : SYSMODE_N3DS_PROD; @@ -334,7 +332,7 @@ void HBLDR_HandleCommands(void *ctx) // See the big comment in sysmodules/pm/source/reslimit.c for technical details. localcaps0->reslimits[0] = BIT(7) | 89; - //localcaps0->storage_info.fs_access_info = 0xFFFFFFFF; // Give access to everything + localcaps0->storage_info.fs_access_info = 0xFFFFFFFF; // Give access to everything localcaps0->storage_info.no_romfs = true; localcaps0->storage_info.use_extended_savedata_access = true; // Whatever @@ -351,7 +349,7 @@ void HBLDR_HandleCommands(void *ctx) // Set kernel release version to the current kernel version kcaps0->descriptors[0] = 0xFC000000 | (osGetKernelVersion() >> 16); - if (GET_VERSION_MINOR(osGetKernelVersion()) >= 50 && SYSCOREVER == 2) // 9.6+ NFIRM + if (GET_VERSION_MINOR(osGetKernelVersion()) >= 50 && coreVer == 2) // 9.6+ NFIRM { u64 lastdep = sizeof(dependencyListNativeFirm)/8; exhi->sci.dependencies[lastdep++] = 0x0004013000004002ULL; // nfc diff --git a/sysmodules/rosalina/source/input_redirection.c b/sysmodules/rosalina/source/input_redirection.c index 33d4443..9174c48 100644 --- a/sysmodules/rosalina/source/input_redirection.c +++ b/sysmodules/rosalina/source/input_redirection.c @@ -177,6 +177,248 @@ void inputRedirectionThreadMain(void) void hidCodePatchFunc(void); void irCodePatchFunc(void); +static Result InputRedirection_DoUndoIrPatches(Handle processHandle, bool doPatch) +{ + static u32* hookLoc = NULL; + static u32* syncLoc = NULL; + static u32* cppFlagLoc = NULL; + static u32 origIrSync = 0; + static u32 origCppFlag = 0; + + static bool patchPrepared = false; + + static u32 irOrigReadingCode[5] = { + 0xE5940000, // ldr r0, [r4] + 0xE1A01005, // mov r1, r5 + 0xE3A03005, // mov r3, #5 + 0xE3A02011, // mov r2, #17 + 0x00000000 // (bl i2c_read_raw goes here) + }; + + static u32 irHook[] = { + 0xE5940000, // ldr r0, [r4] + 0xE1A01005, // mov r1, r5 + 0xE59FC000, // ldr r12, [pc] (actually +8) + 0xE12FFF3C, // blx r12 + 0x00000000 // irCodePhys goes here + }; + + static u32 syncHookCode[] = { + 0xE5900000, // ldr r0, [r0] + 0xEF000024, // svc 0x24 + 0xE3A00000, // mov r0, #0 + 0xE51FF004, // ldr pc, [pc, #-4] + 0x00000000, // (return address goes here) + }; + + // Find offsets for required patches + s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + u32 totalSize; + Result res; + + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); + + svcGetProcessInfo(&startAddress, processHandle, 0x10005); + res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, totalSize); + + if(R_SUCCEEDED(res) && !patchPrepared) + { + static const u32 irOrigWaitSyncCode[] = { + 0xEF000024, // svc 0x24 (WaitSynchronization) + 0xE1B01FA0, // movs r1, r0, lsr#31 + 0xE1A0A000, // mov r10, r0 + }, irOrigWaitSyncCodeOld[] = { + 0xE0AC6000, // adc r6, r12, r0 + 0xE5D70000, // ldrb r0, [r7] + }; // pattern for 8.1 + + static const u32 irOrigCppFlagCode[] = { + 0xE3550000, // cmp r5, #0 + 0xE3A0B080, // mov r11, #0x80 + }; + + svcGetProcessInfo(&startAddress, processHandle, 0x10005); + res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize); + u32 irDataPhys = (u32)PA_FROM_VA_PTR(irData); + u32 irCodePhys = (u32)PA_FROM_VA_PTR(&irCodePatchFunc); + + u32 *off = (u32 *)memsearch((u8 *)0x00100000, &irOrigReadingCode, totalSize, sizeof(irOrigReadingCode) - 4); + if(off == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -1; + } + + u32 *off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCode, totalSize, sizeof(irOrigWaitSyncCode)); + if(off2 == NULL) + { + off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCodeOld, totalSize, sizeof(irOrigWaitSyncCodeOld)); + if(off2 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -2; + } + } + + u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &irOrigCppFlagCode, totalSize, sizeof(irOrigCppFlagCode)); + if(off3 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -3; + } + + origIrSync = *off2; + origCppFlag = *off3; + + *(void **)(irCodePhys + 8) = decodeArmBranch(off + 4); + *(void **)(irCodePhys + 12) = (void*)irDataPhys; + + irHook[4] = irCodePhys; + irOrigReadingCode[4] = off[4]; // Copy the branch. + syncHookCode[4] = (u32)off2 + 4; // Hook return address + + hookLoc = PA_FROM_VA_PTR(off); + syncLoc = PA_FROM_VA_PTR(off2); + cppFlagLoc = PA_FROM_VA_PTR(off3); + + patchPrepared = true; + } + + if (R_SUCCEEDED(res)) + { + if (doPatch) + { + memcpy(hookLoc, &irHook, sizeof(irHook)); + + // We keep the WaitSynchronization1 to avoid general slowdown because of the high cpu load + if (*syncLoc == 0xEF000024) // svc 0x24 (WaitSynchronization) + { + syncLoc[-1] = 0xE51FF004; + syncLoc[0] = (u32)PA_FROM_VA_PTR(&syncHookCode); + } + else + { + // This "NOP"s out a WaitSynchronisation1 (on the event bound to the 'IR' interrupt) or the check of a previous one + *syncLoc = 0xE3A00000; // mov r0, #0 + } + + // This NOPs out a flag check in ir:user's CPP emulation + *cppFlagLoc = 0xE3150000; // tst r5, #0 + } + else + { + memcpy(hookLoc, irOrigReadingCode, sizeof(irOrigReadingCode)); + + if (*syncLoc == 0xE3A00000) + *syncLoc = origIrSync; + else + { + syncLoc[-1] = 0xE5900000; // ldr r0, [r0] + syncLoc[0] = 0xEF000024; // svc 0x24 + } + + *cppFlagLoc = origCppFlag; + } + } + + svcInvalidateEntireInstructionCache(); + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + + return res; +} + +static Result InputRedirection_DoUndoHidPatches(Handle processHandle, bool doPatches) +{ + static const u32 hidOrigRegisterAndValue[] = { 0x1EC46000, 0x4001 }; + static const u32 hidOrigCode[] = { + 0xE92D4070, // push {r4-r6, lr} + 0xE1A05001, // mov r5, r1 + 0xEE1D4F70, // mrc p15, 0, r4, c13, c0, 3 + 0xE3A01801, // mov r1, #0x10000 + 0xE5A41080, // str r1, [r4,#0x80]! + }; + + static bool patchPrepared = false; + static u32 *hidRegPatchOffsets[2]; + static u32 *hidPatchJumpLoc; + + // Find offsets for required patches + s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + u32 totalSize; + Result res; + + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); + + svcGetProcessInfo(&startAddress, processHandle, 0x10005); + res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, totalSize); + + if (R_SUCCEEDED(res) && !patchPrepared) + { + u32 *off = (u32 *)memsearch((u8 *)0x00100000, &hidOrigRegisterAndValue, totalSize, sizeof(hidOrigRegisterAndValue)); + if(off == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -1; + } + + u32 *off2 = (u32 *)memsearch((u8 *)off + sizeof(hidOrigRegisterAndValue), &hidOrigRegisterAndValue, totalSize - ((u32)off - 0x00100000), sizeof(hidOrigRegisterAndValue)); + if(off2 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -2; + } + + u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &hidOrigCode, totalSize, sizeof(hidOrigCode)); + if(off3 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -3; + } + + hidRegPatchOffsets[0] = off; + hidRegPatchOffsets[1] = off2; + hidPatchJumpLoc = off3; + + patchPrepared = true; + } + + if(R_SUCCEEDED(res)) + { + if (doPatches) + { + u32 hidDataPhys = (u32)PA_FROM_VA_PTR(hidData); + u32 hidCodePhys = (u32)PA_FROM_VA_PTR(&hidCodePatchFunc); + u32 hidHook[] = { + 0xE59F3004, // ldr r3, [pc, #4] + 0xE59FC004, // ldr r12, [pc, #4] + 0xE12FFF1C, // bx r12 + hidDataPhys, + hidCodePhys, + }; + + *hidRegPatchOffsets[0] = *hidRegPatchOffsets[1] = hidDataPhys; + memcpy(hidPatchJumpLoc, &hidHook, sizeof(hidHook)); + } + else + { + memcpy(hidRegPatchOffsets[0], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); + memcpy(hidRegPatchOffsets[1], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); + memcpy(hidPatchJumpLoc, &hidOrigCode, sizeof(hidOrigCode)); + } + } + + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return res; +} + Result InputRedirection_Disable(s64 timeout) { if(!inputRedirectionEnabled) @@ -195,209 +437,46 @@ Result InputRedirection_Disable(s64 timeout) Result InputRedirection_DoOrUndoPatches(void) { - s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; - u32 totalSize; - Handle processHandle; - - Result res = OpenProcessByName("hid", &processHandle); static bool hidPatched = false; static bool irPatched = false; + Handle hidProcHandle = 0, irProcHandle = 0; + + // Prevent hid and ir from running, in any case + + svcKernelSetState(0x10000, 4); + + Result res = OpenProcessByName("hid", &hidProcHandle); + if (R_FAILED(res)) + goto cleanup; + + res = OpenProcessByName("ir", &irProcHandle); + if (R_FAILED(res)) + goto cleanup; + if(R_SUCCEEDED(res)) { - svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data - svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); - svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); - - totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); - - svcGetProcessInfo(&startAddress, processHandle, 0x10005); - res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize); - - if(R_SUCCEEDED(res)) - { - static const u32 hidOrigRegisterAndValue[] = { 0x1EC46000, 0x4001 }; - static const u32 hidOrigCode[] = { - 0xE92D4070, // push {r4-r6, lr} - 0xE1A05001, // mov r5, r1 - 0xEE1D4F70, // mrc p15, 0, r4, c13, c0, 3 - 0xE3A01801, // mov r1, #0x10000 - 0xE5A41080, // str r1, [r4,#0x80]! - }; - - static u32 *hidRegPatchOffsets[2]; - static u32 *hidPatchJumpLoc; - - if(hidPatched) - { - memcpy(hidRegPatchOffsets[0], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); - memcpy(hidRegPatchOffsets[1], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); - memcpy(hidPatchJumpLoc, &hidOrigCode, sizeof(hidOrigCode)); - hidPatched = false; - } - else - { - u32 hidDataPhys = (u32)PA_FROM_VA_PTR(hidData); - u32 hidCodePhys = (u32)PA_FROM_VA_PTR(&hidCodePatchFunc); - u32 hidHook[] = { - 0xE59F3004, // ldr r3, [pc, #4] - 0xE59FC004, // ldr r12, [pc, #4] - 0xE12FFF1C, // bx r12 - hidDataPhys, - hidCodePhys, - }; - - u32 *off = (u32 *)memsearch((u8 *)0x00100000, &hidOrigRegisterAndValue, totalSize, sizeof(hidOrigRegisterAndValue)); - if(off == NULL) - { - svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize); - return -1; - } - - u32 *off2 = (u32 *)memsearch((u8 *)off + sizeof(hidOrigRegisterAndValue), &hidOrigRegisterAndValue, totalSize - ((u32)off - 0x00100000), sizeof(hidOrigRegisterAndValue)); - if(off2 == NULL) - { - svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize); - return -2; - } - - u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &hidOrigCode, totalSize, sizeof(hidOrigCode)); - if(off3 == NULL) - { - svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize); - return -3; - } - - hidRegPatchOffsets[0] = off; - hidRegPatchOffsets[1] = off2; - hidPatchJumpLoc = off3; - - *off = *off2 = hidDataPhys; - memcpy(off3, &hidHook, sizeof(hidHook)); - hidPatched = true; - } - } - - res = svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize); + res = InputRedirection_DoUndoHidPatches(hidProcHandle, !hidPatched); + if (R_SUCCEEDED(res)) + hidPatched = !hidPatched; } - svcCloseHandle(processHandle); - res = OpenProcessByName("ir", &processHandle); if(R_SUCCEEDED(res) && GET_VERSION_MINOR(osGetKernelVersion()) >= 44) { - svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data - svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); - svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); - - totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); - - svcGetProcessInfo(&startAddress, processHandle, 0x10005); - res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize); - - if(R_SUCCEEDED(res)) + res = InputRedirection_DoUndoIrPatches(irProcHandle, !irPatched); + if (R_SUCCEEDED(res)) + irPatched = !irPatched; + else if (!irPatched) { - static bool useOldSyncCode; - static u32 irOrigReadingCode[5] = { - 0xE5940000, // ldr r0, [r4] - 0xE1A01005, // mov r1, r5 - 0xE3A03005, // mov r3, #5 - 0xE3A02011, // mov r2, #17 - 0x00000000 // (bl i2c_read_raw goes here) - }; - - static const u32 irOrigWaitSyncCode[] = { - 0xEF000024, // svc 0x24 (WaitSynchronization) - 0xE1B01FA0, // movs r1, r0, lsr#31 - 0xE1A0A000, // mov r10, r0 - }, irOrigWaitSyncCodeOld[] = { - 0xE0AC6000, // adc r6, r12, r0 - 0xE5D70000, // ldrb r0, [r7] - }; // pattern for 8.1 - - static const u32 irOrigCppFlagCode[] = { - 0xE3550000, // cmp r5, #0 - 0xE3A0B080, // mov r11, #0x80 - }; - - static u32 *irHookLoc, *irWaitSyncLoc, *irCppFlagLoc; - - if(irPatched) - { - memcpy(irHookLoc, &irOrigReadingCode, sizeof(irOrigReadingCode)); - if(useOldSyncCode) - memcpy(irWaitSyncLoc, &irOrigWaitSyncCodeOld, sizeof(irOrigWaitSyncCodeOld)); - else - memcpy(irWaitSyncLoc, &irOrigWaitSyncCode, sizeof(irOrigWaitSyncCode)); - memcpy(irCppFlagLoc, &irOrigCppFlagCode, sizeof(irOrigCppFlagCode)); - - irPatched = false; - } - else - { - u32 irDataPhys = (u32)PA_FROM_VA_PTR(irData); - u32 irCodePhys = (u32)PA_FROM_VA_PTR(&irCodePatchFunc); - - u32 irHook[] = { - 0xE5940000, // ldr r0, [r4] - 0xE1A01005, // mov r1, r5 - 0xE59FC000, // ldr r12, [pc] (actually +8) - 0xE12FFF3C, // blx r12 - irCodePhys, - }; - - u32 *off = (u32 *)memsearch((u8 *)0x00100000, &irOrigReadingCode, totalSize, sizeof(irOrigReadingCode) - 4); - if(off == NULL) - { - svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize); - return -4; - } - - u32 *off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCode, totalSize, sizeof(irOrigWaitSyncCode)); - if(off2 == NULL) - { - off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCodeOld, totalSize, sizeof(irOrigWaitSyncCodeOld)); - if(off2 == NULL) - { - svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize); - return -5; - } - - useOldSyncCode = true; - } - else - useOldSyncCode = false; - - u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &irOrigCppFlagCode, totalSize, sizeof(irOrigCppFlagCode)); - if(off3 == NULL) - { - svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize); - return -6; - } - - *(void **)(irCodePhys + 8) = decodeArmBranch(off + 4); - *(void **)(irCodePhys + 12) = (void*)irDataPhys; - - irHookLoc = off; - irWaitSyncLoc = off2; - irCppFlagLoc = off3; - - irOrigReadingCode[4] = off[4]; // Copy the branch. - - memcpy(irHookLoc, &irHook, sizeof(irHook)); - - // This "NOP"s out a WaitSynchronisation1 (on the event bound to the 'IR' interrupt) or the check of a previous one - *irWaitSyncLoc = 0xE3A00000; // mov r0, #0 - - // This NOPs out a flag check in ir:user's CPP emulation - *irCppFlagLoc = 0xE3150000; // tst r5, #0 - - irPatched = true; - } + InputRedirection_DoUndoHidPatches(hidProcHandle, false); + hidPatched = false; } - - res = svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize); } - svcCloseHandle(processHandle); +cleanup: + svcKernelSetState(0x10000, 4); + + svcCloseHandle(hidProcHandle); + svcCloseHandle(irProcHandle); return res; } diff --git a/sysmodules/rosalina/source/luminance.c b/sysmodules/rosalina/source/luminance.c new file mode 100644 index 0000000..cc12787 --- /dev/null +++ b/sysmodules/rosalina/source/luminance.c @@ -0,0 +1,122 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016-2020 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 . +* +* 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 <3ds.h> +#include +#include "luminance.h" +#include "utils.h" + +extern bool isN3DS; + +typedef struct BlPwmData +{ + float coeffs[3][3]; + u8 numLevels; + u8 unk; + u16 luminanceLevels[7]; + u16 brightnessMax; + u16 brightnessMin; +} BlPwmData; + +// Calibration, with (dubious) default values as fallback +static BlPwmData s_blPwmData = { + .coeffs = { + { 0.00111639f, 1.41412f, 0.07178809f }, + { 0.000418169f, 0.66567f, 0.06098654f }, + { 0.00208543f, 1.55639f, 0.0385939f } + }, + .numLevels = 5, + .unk = 0, + .luminanceLevels = { 20, 43, 73, 95, 117, 172, 172 }, + .brightnessMax = 512, + .brightnessMin = 13, +}; + +static inline float getPwmRatio(u32 brightnessMax, u32 pwmCnt) +{ + u32 val = (pwmCnt & 0x10000) ? pwmCnt & 0x3FF : 511; // check pwm enabled flag + return (float)brightnessMax / (val + 1); +} + +// nn's asm has rounding errors (originally at 10^-3) +static inline u32 luminanceToBrightness(u32 luminance, const float coeffs[3], u32 minLuminance, float pwmRatio) +{ + float x = (float)luminance; + float y = coeffs[0]*x*x + coeffs[1]*x + coeffs[2]; + y = (y <= minLuminance ? (float)minLuminance : y) / pwmRatio; + + return (u32)(y + 0.5f); +} + +static inline u32 brightnessToLuminance(u32 brightness, const float coeffs[3], float pwmRatio) +{ + // Find polynomial root of ax^2 + bx + c = y + + float y = (float)brightness * pwmRatio; + float a = coeffs[0]; + float b = coeffs[1]; + float c = coeffs[2] - y; + + float x0 = (-b + sqrtf(b*b - 4.0f*a*c)) / (a + a); + + return (u32)(x0 + 0.5f); +} + +static void readCalibration(void) +{ + static bool calibRead = false; + + if (!calibRead) { + cfguInit(); + calibRead = R_SUCCEEDED(CFG_GetConfigInfoBlk8(sizeof(BlPwmData), 0x50002, &s_blPwmData)); + cfguExit(); + } +} + +u32 getMinLuminancePreset(void) +{ + readCalibration(); + return s_blPwmData.luminanceLevels[0]; +} + +u32 getMaxLuminancePreset(void) +{ + readCalibration(); + return s_blPwmData.luminanceLevels[s_blPwmData.numLevels - 1]; +} + +u32 getCurrentLuminance(bool top) +{ + u32 regbase = top ? 0x10202200 : 0x10202A00; + + readCalibration(); + + const float *coeffs = s_blPwmData.coeffs[top ? (isN3DS ? 2 : 1) : 0]; + u32 brightness = REG32(regbase + 0x40); + float ratio = getPwmRatio(s_blPwmData.brightnessMax, REG32(regbase + 0x44)); + + return brightnessToLuminance(brightness, coeffs, ratio); +} diff --git a/sysmodules/rosalina/source/main.c b/sysmodules/rosalina/source/main.c index dbb2664..f07f6c8 100644 --- a/sysmodules/rosalina/source/main.c +++ b/sysmodules/rosalina/source/main.c @@ -83,13 +83,15 @@ void initSystem(void) isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0; svcGetSystemInfo(&out, 0x10000, 0x100); - HBLDR_3DSX_TID = out == 0 ? HBLDR_DEFAULT_3DSX_TID : (u64)out; + Luma_SharedConfig->hbldr_3dsx_tid = out == 0 ? HBLDR_DEFAULT_3DSX_TID : (u64)out; + Luma_SharedConfig->use_hbldr = true; svcGetSystemInfo(&out, 0x10000, 0x101); menuCombo = out == 0 ? DEFAULT_MENU_COMBO : (u32)out; - miscellaneousMenu.items[0].title = HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID ? "Switch the hb. title to the current app." : - "Switch the hb. title to hblauncher_loader"; + miscellaneousMenu.items[0].title = Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID ? + "Switch the hb. title to the current app." : + "Switch the hb. title to hblauncher_loader"; for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL)) { @@ -104,6 +106,9 @@ void initSystem(void) if (R_FAILED(fsInit())) svcBreak(USERBREAK_PANIC); + if (R_FAILED(FSUSER_SetPriority(-16))) + svcBreak(USERBREAK_PANIC); + // **** DO NOT init services that don't come from KIPs here **** // Instead, init the service only where it's actually init (then deinit it). @@ -131,11 +136,53 @@ static void handleTermNotification(u32 notificationId) (void)notificationId; } +static void handleSleepNotification(u32 notificationId) +{ + ptmSysmInit(); + s32 ackValue = ptmSysmGetNotificationAckValue(notificationId); + switch (notificationId) + { + case PTMNOTIFID_SLEEP_REQUESTED: + menuShouldExit = true; + PTMSYSM_ReplyToSleepQuery(miniSocEnabled); // deny sleep request if we have network stuff running + break; + case PTMNOTIFID_GOING_TO_SLEEP: + case PTMNOTIFID_SLEEP_ALLOWED: + case PTMNOTIFID_FULLY_WAKING_UP: + case PTMNOTIFID_HALF_AWAKE: + PTMSYSM_NotifySleepPreparationComplete(ackValue); + break; + case PTMNOTIFID_SLEEP_DENIED: + case PTMNOTIFID_FULLY_AWAKE: + menuShouldExit = false; + break; + default: + break; + } + ptmSysmExit(); +} + +static void handleShellNotification(u32 notificationId) +{ + if (notificationId == 0x213) { + // Shell opened + // Note that this notification is fired on system init + ScreenFiltersMenu_RestoreCct(); + menuShouldExit = false; + } else { + // Shell closed + menuShouldExit = true; + } + +} + static void handlePreTermNotification(u32 notificationId) { (void)notificationId; // Might be subject to a race condition, but heh. + miniSocUnlockState(true); + // Disable input redirection InputRedirection_Disable(100 * 1000 * 1000LL); @@ -180,11 +227,19 @@ static const ServiceManagerServiceEntry services[] = { }; static const ServiceManagerNotificationEntry notifications[] = { - { 0x100 , handleTermNotification }, - //{ 0x103 , handlePreTermNotification }, // Sleep mode entry <=== causes issues - { 0x1000, handleNextApplicationDebuggedByForce }, - { 0x2000, handlePreTermNotification }, - { 0x3000, handleRestartHbAppNotification }, + { 0x100 , handleTermNotification }, + { PTMNOTIFID_SLEEP_REQUESTED, handleSleepNotification }, + { PTMNOTIFID_SLEEP_DENIED, handleSleepNotification }, + { PTMNOTIFID_SLEEP_ALLOWED, handleSleepNotification }, + { PTMNOTIFID_GOING_TO_SLEEP, handleSleepNotification }, + { PTMNOTIFID_FULLY_WAKING_UP, handleSleepNotification }, + { PTMNOTIFID_FULLY_AWAKE, handleSleepNotification }, + { PTMNOTIFID_HALF_AWAKE, handleSleepNotification }, + { 0x213, handleShellNotification }, + { 0x214, handleShellNotification }, + { 0x1000, handleNextApplicationDebuggedByForce }, + { 0x2000, handlePreTermNotification }, + { 0x3000, handleRestartHbAppNotification }, { 0x000, NULL }, }; diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c index 40c5f55..a8addf6 100644 --- a/sysmodules/rosalina/source/menu.c +++ b/sysmodules/rosalina/source/menu.c @@ -193,6 +193,7 @@ void menuThreadMain(void) while(!preTerminationRequested) { + svcSleepThread(50 * 1000 * 1000LL); if (menuShouldExit) continue; @@ -226,13 +227,13 @@ void menuEnter(void) if(!menuShouldExit && menuRefCount == 0) { menuRefCount++; - svcKernelSetState(0x10000, 1); + svcKernelSetState(0x10000, 2 | 1); svcSleepThread(5 * 1000 * 100LL); if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE))) { // Oops menuRefCount = 0; - svcKernelSetState(0x10000, 1); + svcKernelSetState(0x10000, 2 | 1); svcSleepThread(5 * 1000 * 100LL); } else @@ -250,7 +251,7 @@ void menuLeave(void) { Draw_RestoreFramebuffer(); Draw_FreeFramebufferCache(); - svcKernelSetState(0x10000, 1); + svcKernelSetState(0x10000, 2 | 1); } Draw_Unlock(); } diff --git a/sysmodules/rosalina/source/menus.c b/sysmodules/rosalina/source/menus.c index 642d4b2..08b6ae8 100644 --- a/sysmodules/rosalina/source/menus.c +++ b/sysmodules/rosalina/source/menus.c @@ -40,6 +40,7 @@ #include "memory.h" #include "fmt.h" #include "process_patches.h" +#include "luminance.h" Menu rosalinaMenu = { "Rosalina menu", @@ -64,7 +65,11 @@ Menu rosalinaMenu = { bool rosalinaMenuShouldShowDebugInfo(void) { - return true; + // Don't show on release builds + + s64 out; + svcGetSystemInfo(&out, 0x10000, 0x200); + return out == 0; } void RosalinaMenu_ShowDebugInfo(void) @@ -119,8 +124,8 @@ void RosalinaMenu_ShowCredits(void) Draw_DrawString(10, posY, COLOR_WHITE, ( "Special thanks to:\n" - " Bond697, WinterMute, piepie62, yifanlu\n" - " Luma3DS contributors, ctrulib contributors,\n" + " fincs, WinterMute, mtheall, piepie62,\n" + " Luma3DS contributors, libctru contributors,\n" " other people" )); @@ -140,7 +145,7 @@ void RosalinaMenu_Reboot(void) do { Draw_Lock(); - Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu"); + Draw_DrawString(10, 10, COLOR_TITLE, "Reboot"); Draw_DrawString(10, 30, COLOR_WHITE, "Press A to reboot, press B to go back."); Draw_FlushFramebuffer(); Draw_Unlock(); @@ -158,107 +163,102 @@ void RosalinaMenu_Reboot(void) while(!menuShouldExit); } -static u32 gspPatchAddrN3ds, gspPatchValuesN3ds[2]; -static bool gspPatchDoneN3ds; - -static Result RosalinaMenu_PatchN3dsGspForBrightness(u32 size) -{ - u32 *off = (u32 *)0x00100000; - u32 *end = (u32 *)(0x00100000 + size); - - for (; off < end && (off[0] != 0xE92D4030 || off[1] != 0xE1A04000 || off[2] != 0xE2805C01 || off[3] != 0xE5D0018C); off++); - - if (off >= end) { - return -1; - } - - gspPatchAddrN3ds = (u32)off; - gspPatchValuesN3ds[0] = off[26]; - gspPatchValuesN3ds[1] = off[50]; - - // NOP brightness changing in GSP - off[26] = 0xE1A00000; - off[50] = 0xE1A00000; - - return 0; -} -static Result RosalinaMenu_RevertN3dsGspPatch(u32 size) -{ - (void)size; - - u32 *off = (u32 *)gspPatchAddrN3ds; - off[26] = gspPatchValuesN3ds[0]; - off[50] = gspPatchValuesN3ds[1]; - - return 0; -} - void RosalinaMenu_ChangeScreenBrightness(void) { - Result patchResult = 0; - if (isN3DS && !gspPatchDoneN3ds) - { - patchResult = PatchProcessByName("gsp", RosalinaMenu_PatchN3dsGspForBrightness); - gspPatchDoneN3ds = R_SUCCEEDED(patchResult); - } - Draw_Lock(); Draw_ClearFramebuffer(); Draw_FlushFramebuffer(); Draw_Unlock(); + // gsp:LCD GetLuminance is stubbed on O3DS so we have to implement it ourselves... damn it. + // Assume top and bottom screen luminances are the same (should be; if not, we'll set them to the same values). + u32 luminance = getCurrentLuminance(false); + u32 minLum = getMinLuminancePreset(); + u32 maxLum = getMaxLuminancePreset(); + do { - // Assume the current brightness for both screens are the same. - s32 brightness = (s32)(LCD_TOP_BRIGHTNESS & 0xFF); - Draw_Lock(); - Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu"); + Draw_DrawString(10, 10, COLOR_TITLE, "Screen brightness"); u32 posY = 30; - posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Current brightness (0..255): %3lu\n\n", brightness); - if (R_SUCCEEDED(patchResult)) - { - posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press Up/Down for +-1, Right/Left for +-10.\n"); - posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press Y to revert the GSP patch and exit.\n\n"); - - posY = Draw_DrawString(10, posY, COLOR_RED, "WARNING: \n"); - posY = Draw_DrawString(10, posY, COLOR_WHITE, " * avoid using values far higher than the presets.\n"); - posY = Draw_DrawString(10, posY, COLOR_WHITE, " * normal brightness mngmt. is now broken on N3DS.\nYou'll need to press Y to revert"); - } - else - Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Failed to patch GSP (0x%08lx).", (u32)patchResult); + posY = Draw_DrawFormattedString( + 10, + posY, + COLOR_WHITE, + "Current luminance: %lu (min. %lu, max. %lu)\n\n", + luminance, + minLum, + maxLum + ); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Controls: Up/Down for +-1, Right/Left for +-10.\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press A to start, B to exit.\n\n"); + posY = Draw_DrawString(10, posY, COLOR_RED, "WARNING: \n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, " * value will be limited by the presets.\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, " * bottom framebuffer will be restored until\nyou exit."); Draw_FlushFramebuffer(); Draw_Unlock(); u32 pressed = waitInputWithTimeout(1000); - if ((pressed & DIRECTIONAL_KEYS) && R_SUCCEEDED(patchResult)) - { - if (pressed & KEY_UP) - brightness += 1; - else if (pressed & KEY_DOWN) - brightness -= 1; - else if (pressed & KEY_RIGHT) - brightness += 10; - else if (pressed & KEY_LEFT) - brightness -= 10; + if (pressed & KEY_A) + break; - brightness = brightness < 0 ? 0 : brightness; - brightness = brightness > 255 ? 255 : brightness; - LCD_TOP_BRIGHTNESS = (u32)brightness; - LCD_BOT_BRIGHTNESS = (u32)brightness; - } - else if ((pressed & KEY_Y) && gspPatchDoneN3ds) - { - patchResult = PatchProcessByName("gsp", RosalinaMenu_RevertN3dsGspPatch); - gspPatchDoneN3ds = !R_SUCCEEDED(patchResult); - return; - } - else if (pressed & KEY_B) + if (pressed & KEY_B) return; } while (!menuShouldExit); + + Draw_Lock(); + + Draw_RestoreFramebuffer(); + Draw_FreeFramebufferCache(); + + svcKernelSetState(0x10000, 2); // unblock gsp + gspLcdInit(); // assume it doesn't fail. If it does, brightness won't change, anyway. + + // gsp:LCD will normalize the brightness between top/bottom screen, handle PWM, etc. + + s32 lum = (s32)luminance; + + do + { + u32 pressed = waitInputWithTimeout(1000); + if (pressed & DIRECTIONAL_KEYS) + { + if (pressed & KEY_UP) + lum += 1; + else if (pressed & KEY_DOWN) + lum -= 1; + else if (pressed & KEY_RIGHT) + lum += 10; + else if (pressed & KEY_LEFT) + lum -= 10; + + lum = lum < 0 ? 0 : lum; + + // We need to call gsp here because updating the active duty LUT is a bit tedious (plus, GSP has internal state). + // This is actually SetLuminance: + GSPLCD_SetBrightnessRaw(BIT(GSP_SCREEN_TOP) | BIT(GSP_SCREEN_BOTTOM), lum); + } + + if (pressed & KEY_B) + break; + } + while (!menuShouldExit); + + gspLcdExit(); + svcKernelSetState(0x10000, 2); // block gsp again + + if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE))) + { + // Shouldn't happen + __builtin_trap(); + } + else + Draw_SetupFramebuffer(); + + Draw_Unlock(); } void RosalinaMenu_PowerOff(void) // Soft shutdown. @@ -271,7 +271,7 @@ void RosalinaMenu_PowerOff(void) // Soft shutdown. do { Draw_Lock(); - Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu"); + Draw_DrawString(10, 10, COLOR_TITLE, "Power off"); Draw_DrawString(10, 30, COLOR_WHITE, "Press A to power off, press B to go back."); Draw_FlushFramebuffer(); Draw_Unlock(); diff --git a/sysmodules/rosalina/source/menus/debugger.c b/sysmodules/rosalina/source/menus/debugger.c index 70bf67a..0a00ebf 100644 --- a/sysmodules/rosalina/source/menus/debugger.c +++ b/sysmodules/rosalina/source/menus/debugger.c @@ -102,7 +102,6 @@ Result debuggerDisable(s64 timeout) svcCloseHandle(dummy); PMDBG_DebugNextApplicationByForce(false); nextApplicationGdbCtx = NULL; - svcKernelSetState(0x10000, 2); } return res; diff --git a/sysmodules/rosalina/source/menus/miscellaneous.c b/sysmodules/rosalina/source/menus/miscellaneous.c index c4e66af..579bd78 100644 --- a/sysmodules/rosalina/source/menus/miscellaneous.c +++ b/sysmodules/rosalina/source/menus/miscellaneous.c @@ -55,7 +55,7 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void) Result res; char failureReason[64]; - if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID) + if(Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID) { FS_ProgramInfo progInfo; u32 pid; @@ -63,7 +63,7 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void) res = PMDBG_GetCurrentAppInfo(&progInfo, &pid, &launchFlags); if(R_SUCCEEDED(res)) { - HBLDR_3DSX_TID = progInfo.programId; + Luma_SharedConfig->hbldr_3dsx_tid = progInfo.programId; miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader"; } else @@ -75,7 +75,7 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void) else { res = 0; - HBLDR_3DSX_TID = HBLDR_DEFAULT_3DSX_TID; + Luma_SharedConfig->hbldr_3dsx_tid = HBLDR_DEFAULT_3DSX_TID; miscellaneousMenu.items[0].title = "Switch the hb. title to the current app."; } @@ -205,7 +205,7 @@ Result SaveSettings(void) configData.config = config; configData.multiConfig = multiConfig; configData.bootConfig = bootConfig; - configData.hbldr3dsxTitleId = HBLDR_3DSX_TID; + configData.hbldr3dsxTitleId = Luma_SharedConfig->hbldr_3dsx_tid; configData.rosalinaMenuCombo = menuCombo; configData.rosalinaFlags = PluginLoader__IsEnabled(); @@ -331,7 +331,21 @@ void MiscellaneousMenu_InputRedirection(void) else { if(res == 0) - Draw_DrawString(10, 30, COLOR_WHITE, "InputRedirection stopped successfully."); + { + u32 posY = 30; + posY = Draw_DrawString(10, posY, COLOR_WHITE, "InputRedirection stopped successfully.\n\n"); + if (isN3DS) + { + posY = Draw_DrawString( + 10, + posY, + COLOR_WHITE, + "This might cause a key press to be repeated in\n" + "Home Menu for no reason.\n\n" + "Just pressing ZL/ZR on the console is enough to fix\nthis.\n" + ); + } + } else Draw_DrawString(10, 30, COLOR_WHITE, buf); } diff --git a/sysmodules/rosalina/source/menus/screen_filters.c b/sysmodules/rosalina/source/menus/screen_filters.c index 7fe3f9e..1d3d257 100644 --- a/sysmodules/rosalina/source/menus/screen_filters.c +++ b/sysmodules/rosalina/source/menus/screen_filters.c @@ -32,26 +32,29 @@ #include "redshift/redshift.h" #include "redshift/colorramp.h" -typedef struct { - u8 r; - u8 g; - u8 b; - u8 z; +typedef union { + struct { + u8 r; + u8 g; + u8 b; + u8 z; + }; + u32 raw; } Pixel; static u16 g_c[0x600]; static Pixel g_px[0x400]; -int screenFiltersCurrentTemperature = 6500; +int screenFiltersCurrentTemperature = -1; -static void ScreenFiltersMenu_WriteLut(const u32* lut) +static void ScreenFiltersMenu_WriteLut(const Pixel* lut) { GPU_FB_TOP_COL_LUT_INDEX = 0; GPU_FB_BOTTOM_COL_LUT_INDEX = 0; for (int i = 0; i <= 255; i++) { - GPU_FB_TOP_COL_LUT_ELEM = *lut; - GPU_FB_BOTTOM_COL_LUT_ELEM = *lut; + GPU_FB_TOP_COL_LUT_ELEM = lut->raw; + GPU_FB_BOTTOM_COL_LUT_ELEM = lut->raw; lut++; } } @@ -84,7 +87,7 @@ static void ScreenFiltersMenu_ApplyColorSettings(color_setting_t* cs) g_px[i].b = *(g_c + i + 0x200) >> 8; } while(++i); - ScreenFiltersMenu_WriteLut((u32*)g_px); + ScreenFiltersMenu_WriteLut(g_px); } static void ScreenFiltersMenu_SetCct(int cct) @@ -101,7 +104,6 @@ static void ScreenFiltersMenu_SetCct(int cct) ScreenFiltersMenu_ApplyColorSettings(&cs); } - Menu screenFiltersMenu = { "Screen filters menu", { @@ -126,6 +128,20 @@ void ScreenFiltersMenu_Set##name(void)\ ScreenFiltersMenu_SetCct(temp);\ } +void ScreenFiltersMenu_RestoreCct(void) +{ + // Not initialized: return + if (screenFiltersCurrentTemperature == -1) + return; + + // Wait for GSP to restore the CCT table + while (GPU_FB_TOP_COL_LUT_ELEM != g_px[0].raw) + svcSleepThread(10 * 1000 * 1000LL); + + svcSleepThread(10 * 1000 * 1000LL); + ScreenFiltersMenu_WriteLut(g_px); +} + DEF_CCT_SETTER(6500, Default) DEF_CCT_SETTER(10000, Aquarium) diff --git a/sysmodules/rosalina/source/menus/sysconfig.c b/sysmodules/rosalina/source/menus/sysconfig.c index 4a357dd..babf15b 100644 --- a/sysmodules/rosalina/source/menus/sysconfig.c +++ b/sysmodules/rosalina/source/menus/sysconfig.c @@ -35,10 +35,10 @@ Menu sysconfigMenu = { "System configuration menu", { + { "Control Wireless connection", METHOD, .method = &SysConfigMenu_ControlWifi }, { "Toggle LEDs", METHOD, .method = &SysConfigMenu_ToggleLEDs }, { "Toggle Wireless", METHOD, .method = &SysConfigMenu_ToggleWireless }, { "Toggle Power Button", METHOD, .method=&SysConfigMenu_TogglePowerButton }, - { "Control Wireless connection", METHOD, .method = &SysConfigMenu_ControlWifi }, {}, } }; diff --git a/sysmodules/rosalina/source/minisoc.c b/sysmodules/rosalina/source/minisoc.c index d52d48c..252c81d 100644 --- a/sysmodules/rosalina/source/minisoc.c +++ b/sysmodules/rosalina/source/minisoc.c @@ -1,3 +1,4 @@ + /* * This file is part of Luma3DS. * Copyright (C) 2016-2020 Aurora Wright, TuxSH @@ -7,18 +8,16 @@ #include "minisoc.h" #include -#include <3ds/ipc.h> -#include <3ds/os.h> -#include <3ds/synchronization.h> -#include <3ds/result.h> +#include <3ds.h> #include -#include "csvc.h" +#include "utils.h" s32 miniSocRefCount = 0; static u32 socContextAddr = 0x08000000; static u32 socContextSize = 0x60000; static Handle miniSocHandle; static Handle miniSocMemHandle; +static bool exclusiveStateEntered = false; bool miniSocEnabled = false; @@ -56,6 +55,41 @@ static Result SOCU_Shutdown(void) return cmdbuf[1]; } +// unsafe but what can I do? +void miniSocLockState(void) +{ + Result res = 0; + __dmb(); + if (!exclusiveStateEntered && isServiceUsable("ndm:u")) + { + ndmuInit(); + res = NDMU_EnterExclusiveState(NDM_EXCLUSIVE_STATE_INFRASTRUCTURE); + if (R_SUCCEEDED(res)) + res = NDMU_LockState(); // prevents ndm from switching to StreetPass when the lid is closed + exclusiveStateEntered = R_SUCCEEDED(res); + __dmb(); + } +} + +void miniSocUnlockState(bool force) +{ + Result res = 0; + + __dmb(); + if (exclusiveStateEntered) + { + if (!force) + { + res = NDMU_UnlockState(); + if (R_SUCCEEDED(res)) + res = NDMU_LeaveExclusiveState(); + } + ndmuExit(); + exclusiveStateEntered = R_FAILED(res); + __dmb(); + } +} + Result miniSocInit(void) { if(AtomicPostIncrement(&miniSocRefCount)) @@ -89,8 +123,11 @@ Result miniSocInit(void) ret = SOCU_Initialize(miniSocMemHandle, socContextSize); if(ret != 0) goto cleanup; - svcKernelSetState(0x10000, 2); + miniSocLockState(); + + svcKernelSetState(0x10000, 0x10); miniSocEnabled = true; + return 0; cleanup: @@ -117,7 +154,6 @@ cleanup: Result miniSocExitDirect(void) { - //if (miniSocRefCount != 0) __builtin_trap(); Result ret = 0; u32 tmp; @@ -132,8 +168,10 @@ Result miniSocExitDirect(void) svcControlMemory(&tmp, socContextAddr, socContextAddr, socContextSize, MEMOP_FREE, MEMPERM_DONTCARE); if(ret == 0) { - svcKernelSetState(0x10000, 2); + miniSocUnlockState(false); + miniSocEnabled = false; + svcKernelSetState(0x10000, 0x10); } return ret; } diff --git a/sysmodules/sm/README.md b/sysmodules/sm/README.md index b63f514..34a8318 100644 --- a/sysmodules/sm/README.md +++ b/sysmodules/sm/README.md @@ -3,7 +3,7 @@ Open source replacement of the Arm11 SM system module. This is licensed under the MIT license. # Usage -To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/), build this project and copy sm.cxi to /luma/sysmodules/. +To run this system module, use a recent release or commit of [Luma3DS](https://github.com/LumaTeam/Luma3DS/), build this project and copy sm.cxi to /luma/sysmodules/. # Credits Everyone that helped me fix some of stupid bugs I had been making: @fincs, @Hikari-chin, etc. diff --git a/sysmodules/sm/source/notifications.c b/sysmodules/sm/source/notifications.c index 7a69004..07f2694 100644 --- a/sysmodules/sm/source/notifications.c +++ b/sysmodules/sm/source/notifications.c @@ -8,6 +8,18 @@ This is part of 3ds_sm, which is licensed under the MIT license (see LICENSE for #include "notifications.h" #include "processes.h" +#include + +static bool isNotificationInhibited(const ProcessData *processData, u32 notificationId) +{ + (void)processData; + switch(notificationId) + { + default: + return false; + } +} + static bool doPublishNotification(ProcessData *processData, u32 notificationId, u32 flags) { if((flags & 1) && processData->nbPendingNotifications != 0) // only send if not already pending @@ -126,7 +138,7 @@ Result PublishToSubscriber(u32 notificationId, u32 flags) { for(ProcessData *node = processDataInUseList.first; node != NULL; node = node->next) { - if(!node->notificationEnabled) + if(!node->notificationEnabled || isNotificationInhibited(node, notificationId)) continue; u16 i; @@ -146,7 +158,7 @@ Result PublishAndGetSubscriber(u32 *pidCount, u32 *pidList, u32 notificationId, u32 nb = 0; for(ProcessData *node = processDataInUseList.first; node != NULL; node = node->next) { - if(!node->notificationEnabled) + if(!node->notificationEnabled || isNotificationInhibited(node, notificationId)) continue; u16 i; diff --git a/sysmodules/sm/source/notifications.h b/sysmodules/sm/source/notifications.h index 42b640f..40855e7 100644 --- a/sysmodules/sm/source/notifications.h +++ b/sysmodules/sm/source/notifications.h @@ -17,3 +17,5 @@ Result PublishToSubscriber(u32 notificationId, u32 flags); Result PublishAndGetSubscriber(u32 *pidCount, u32 *pidList, u32 notificationId, u32 flags); Result PublishToProcess(Handle process, u32 notificationId); Result PublishToAll(u32 notificationId); + +Result AddToNdmuWorkaroundCount(s32 count);