TuxSH 1d7cca25d1 Fix long-standing bug affecting hbldr TID change option
This was a long-standing bug since Luma3DS v8.0.

If you changed the homebrew title and didn't immediately reboot, then
the ExHeader during termination would not match the ExHeader that was
was used for loading the process, and thus sysmodule process refcounts
would get all messed up.

The obvious solution to this is to ensure no application is running
while changing the hbldr titleID (hence the changes in custom PM).

This was quite possibly one of the cause of homebrew failing to load
when using N3DS H&S.
2023-02-08 16:14:59 +00:00

270 lines
8.0 KiB
C

/*
* This file is part of Luma3DS
* Copyright (C) 2016-2021 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 <3ds.h>
#include "memory.h"
#include "menu.h"
#include "service_manager.h"
#include "errdisp.h"
#include "utils.h"
#include "MyThread.h"
#include "menus/miscellaneous.h"
#include "menus/debugger.h"
#include "menus/screen_filters.h"
#include "menus/cheats.h"
#include "menus/sysconfig.h"
#include "input_redirection.h"
#include "minisoc.h"
#include "draw.h"
#include "bootdiag.h"
#include "shell.h"
#include "task_runner.h"
bool isN3DS;
Result __sync_init(void);
Result __sync_fini(void);
void __libc_init_array(void);
void __libc_fini_array(void);
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
// this is called after main exits
void __wrap_exit(int rc)
{
(void)rc;
// TODO: make pm terminate rosalina
__libc_fini_array();
// Kernel will take care of it all
/*
pmDbgExit();
fsExit();
svcCloseHandle(*fsRegGetSessionHandle());
srvExit();
__sync_fini();*/
svcExitProcess();
}
// this is called before main
void initSystem(void)
{
s64 out;
Result res;
__sync_init();
mappableInit(0x10000000, 0x14000000);
isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0;
svcGetSystemInfo(&out, 0x10000, 0x101);
menuCombo = out == 0 ? DEFAULT_MENU_COMBO : (u32)out;
svcGetSystemInfo(&out, 0x10000, 0x103);
lastNtpTzOffset = (s16)out;
for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL))
{
res = srvInit();
if(R_FAILED(res) && res != (Result)0xD88007FA)
svcBreak(USERBREAK_PANIC);
}
if (R_FAILED(pmAppInit()) || R_FAILED(pmDbgInit()))
svcBreak(USERBREAK_PANIC);
if (R_FAILED(fsInit()))
svcBreak(USERBREAK_PANIC);
if (R_FAILED(FSUSER_SetPriority(-16)))
svcBreak(USERBREAK_PANIC);
miscellaneousMenu.items[0].title = Luma_SharedConfig->selected_hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID ?
"Switch the hb. title to the current app." :
"Switch the hb. title to " HBLDR_DEFAULT_3DSX_TITLE_NAME;
// **** DO NOT init services that don't come from KIPs here ****
// Instead, init the service only where it's actually init (then deinit it).
__libc_init_array();
// ROSALINA HACKJOB END
// Rosalina specific:
u32 *tls = (u32 *)getThreadLocalStorage();
memset(tls, 0, 0x80);
tls[0] = 0x21545624;
// ROSALINA HACKJOB BEGIN
// NORMAL APPS SHOULD NOT DO THIS, EVER
srvSetBlockingPolicy(true); // GetServiceHandle nonblocking if service port is full
}
bool menuShouldExit = false;
bool preTerminationRequested = false;
Handle preTerminationEvent;
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 also fired on system init.
// Sequence goes like this: MCU fires notif. 0x200 on shell open
// and shell close, then NS demuxes it and fires 0x213 and 0x214.
handleShellOpened();
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);
// Ask the debugger to terminate in approx 2 * 100ms
debuggerDisable(100 * 1000 * 1000LL);
// Kill the ac session if needed
if(isConnectionForced)
{
acExit();
isConnectionForced = false;
SysConfigMenu_UpdateStatus(true);
}
Draw_Lock();
if (isHidInitialized)
hidExit();
// Termination request
menuShouldExit = true;
preTerminationRequested = true;
svcSignalEvent(preTerminationEvent);
Draw_Unlock();
}
static void handleNextApplicationDebuggedByForce(u32 notificationId)
{
(void)notificationId;
// Following call needs to be async because pm -> Loader depends on rosalina hb:ldr, handled in this very thread.
TaskRunner_RunTask(debuggerFetchAndSetNextApplicationDebugHandleTask, NULL, 0);
}
#if 0
static void handleRestartHbAppNotification(u32 notificationId)
{
(void)notificationId;
TaskRunner_RunTask(HBLDR_RestartHbApplication, NULL, 0);
}
#endif
static const ServiceManagerServiceEntry services[] = {
{ NULL },
};
static const ServiceManagerNotificationEntry notifications[] = {
{ 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 },
{ 0x000, NULL },
};
int main(void)
{
if(R_FAILED(svcCreateEvent(&preTerminationEvent, RESET_STICKY)))
svcBreak(USERBREAK_ASSERT);
Draw_Init();
Cheat_SeedRng(svcGetSystemTick());
MyThread *menuThread = menuCreateThread();
MyThread *taskRunnerThread = taskRunnerCreateThread();
MyThread *errDispThread = errDispCreateThread();
bootdiagCreateThread();
if (R_FAILED(ServiceManager_Run(services, notifications, NULL)))
svcBreak(USERBREAK_PANIC);
TaskRunner_Terminate();
MyThread_Join(menuThread, -1LL);
MyThread_Join(taskRunnerThread, -1LL);
MyThread_Join(errDispThread, -1LL);
return 0;
}