From 08b76e2e17c58fbfbd74c83857e2e7e372adb9b1 Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Mon, 9 Jan 2023 23:23:19 +0000 Subject: [PATCH] apt: fix dirty homebrew chainload Fix chainload method used when HM is not launched. We now wait for custom PM to change our launch flag and ask us to terminate. We previously had a few issues: - a potential race condition where we exit before PM changes our runflags (not observed) - a kernel deadlock between ExitProcess and TerminateProcess (observed, this is due to Nintendo's lack of barrier in many of their atomics code) - debuggers reporting that we were terminated, instead of exiting gracefully (not desirable) --- libctru/source/services/apt.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index baf1517..e507897 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -345,6 +345,7 @@ void aptExit(void) if (AtomicDecrement(&aptRefCount)) return; bool closeAptLock = true; + bool doDirtyChainload = false; if (!aptIsCrippled()) { @@ -378,7 +379,7 @@ void aptExit(void) { // XX: HOME menu doesn't exist, so we need to use a workaround provided by Luma3DS APT_Finalize(envGetAptAppId()); - srvPublishToSubscriber(0x3000, 0); + doDirtyChainload = true; } // After a chainload has been applied, we don't need to manually close @@ -413,6 +414,30 @@ void aptExit(void) if (closeAptLock) svcCloseHandle(aptLockHandle); + + if (doDirtyChainload) + { + // Provided by Luma3DS + Handle notificationHandle = 0; + Result res = 0; + u32 notificationNumber = 0; + srvEnableNotification(¬ificationHandle); + + // Not needed, but official (sysmodule) code does this: + srvSubscribe(0x100); + + // Make PM modify our run flags and ask us to terminate + srvPublishToSubscriber(0x3000, 0); + + do + { + // Bail out after 3 seconds, we don't want to wait forever for this + res = svcWaitSynchronization(notificationHandle, 3 * 1000 * 1000LL); + res = res == 0 ? srvReceiveNotification(¬ificationNumber) : res; + } while(res == 0 && notificationNumber != 0x100); + + svcCloseHandle(notificationHandle); + } } void aptEventHandler(void *arg)