From 3185387daf355dad1c9b3b7e22f929d10c751b77 Mon Sep 17 00:00:00 2001 From: Nicolet Date: Thu, 23 Oct 2025 21:18:33 -0500 Subject: [PATCH 1/3] stealth autoboot --- fatfs/ff_utf8.c | 7 ++++ fatfs/ff_utf8.h | 1 + loader/include/global.h | 4 ++- loader/source/global.c | 31 ++++++++++------- loader/source/main.c | 74 ++++++++++++++++++----------------------- loader/source/menu.c | 2 +- 6 files changed, 64 insertions(+), 55 deletions(-) diff --git a/fatfs/ff_utf8.c b/fatfs/ff_utf8.c index 1cfabfd02..534deaaaf 100644 --- a/fatfs/ff_utf8.c +++ b/fatfs/ff_utf8.c @@ -86,6 +86,13 @@ FRESULT f_mount_char(FATFS* fs, const char* path, BYTE opt) return f_mount(fs, tmpwchar.u16, opt); } +FRESULT f_stat_char(const char* path, FILINFO* fno) +{ + if (!char_to_wchar(path)) + return FR_INVALID_NAME; + return f_stat(tmpwchar.u16, fno); +} + #if !_FS_READONLY FRESULT f_mkdir_char(const char* path) { diff --git a/fatfs/ff_utf8.h b/fatfs/ff_utf8.h index 3d6e390f9..1ea96bd43 100644 --- a/fatfs/ff_utf8.h +++ b/fatfs/ff_utf8.h @@ -19,6 +19,7 @@ const char *wchar_to_char(const WCHAR *wcs); FRESULT f_open_char(FIL* fp, const char* path, BYTE mode); FRESULT f_mount_char(FATFS* fs, const char* path, BYTE opt); +FRESULT f_stat_char(const char* path, FILINFO* fno); #if !_FS_READONLY FRESULT f_mkdir_char(const char* path); diff --git a/loader/include/global.h b/loader/include/global.h index f451e0c08..5b8177f08 100644 --- a/loader/include/global.h +++ b/loader/include/global.h @@ -142,10 +142,12 @@ typedef struct // FIXME: This return type isn't quite correct... const char* const GetRootDevice(); void RAMInit(void); -void Initialise(bool autoboot); +void Initialise(void); +void InitialiseBg(void); void unzip_data(const void *input, const unsigned int input_size, void **output, unsigned int *output_size); +bool IsStealth(void); /** * Load the configuration file from the root device. * @return True if loaded successfully; false if not. diff --git a/loader/source/global.c b/loader/source/global.c index a3efc573c..179e44d71 100644 --- a/loader/source/global.c +++ b/loader/source/global.c @@ -175,9 +175,8 @@ static unsigned int font_ttf_size = 0; * This also loads the background image. * @param autoboot Set if autobooting. (This disables the fade-in.) */ -void Initialise(bool autoboot) +void Initialise(void) { - int i; AUDIO_Init(NULL); DSP_Init(); AUDIO_StopDMA(); @@ -197,18 +196,20 @@ void Initialise(bool autoboot) bg_xScale = 1.0f; bg_xPos = 0; - if(autoboot == false) + gprintf("Initialize Finished\r\n"); +} + +void InitialiseBg(void) +{ + int i; + // Fade background image by incrementing opacity + for (i=0; i<255; i +=5) { - // Fade background image by incrementing opacity - for (i=0; i<255; i +=5) - { - GRRLIB_DrawImg(bg_xPos, 0, background, 0, bg_xScale, 1, - RGBA(255, 255, 255, i)); - GRRLIB_Render(); - } - ClearScreen(); + GRRLIB_DrawImg(bg_xPos, 0, background, 0, bg_xScale, 1, + RGBA(255, 255, 255, i)); + GRRLIB_Render(); } - gprintf("Initialize Finished\r\n"); + ClearScreen(); } static void (*stub)() = (void*)0x80001800; @@ -305,6 +306,12 @@ void LoaderShutdown() while(1) usleep(20000); } +bool IsStealth(void) +{ + FILINFO fno; + return f_stat_char("/enable_stealth_autoboot.txt", &fno) == FR_OK; +} + /** * Load the configuration file from the root device. * @return True if loaded successfully; false if not. diff --git a/loader/source/main.c b/loader/source/main.c index 0058bad79..358367d67 100644 --- a/loader/source/main.c +++ b/loader/source/main.c @@ -532,7 +532,7 @@ int main(int argc, char **argv) } } - Initialise(argsboot); + Initialise(); //for BT.c CONF_GetPadDevices((conf_pads*)0x932C0000); @@ -543,10 +543,7 @@ int main(int argc, char **argv) s32 fd; - // Preparing IOS58 Kernel... - if(argsboot == false) - ShowMessageScreen("Preparing IOS58 Kernel..."); - + //Preparing IOS58 Kernel... //Disables MEMPROT for patches write16(MEM_PROT, 0); @@ -588,10 +585,7 @@ int main(int argc, char **argv) memcpy( (void*)0x939F0348, ESBootPatch, sizeof(ESBootPatch) ); DCFlushRange( (void*)0x939F0348, sizeof(ESBootPatch) ); - // Loading IOS58 Kernel... - if(argsboot == false) - ShowMessageScreen("Loading IOS58 Kernel..."); - + //Loading IOS58 Kernel... //libogc still has that, lets close it __ES_Close(); fd = IOS_Open( dev_es, 0 ); @@ -604,10 +598,7 @@ int main(int argc, char **argv) //Disables MEMPROT for patches write16(MEM_PROT, 0); - // Preparing Nintendont Kernel... - if(argsboot == false) - ShowMessageScreen("Preparing Nintendont Kernel..."); - + //Preparing Nintendont Kernel... //inject nintendont thread void *kernel_bin = NULL; unsigned int kernel_bin_size = 0; @@ -622,9 +613,6 @@ int main(int argc, char **argv) DCFlushRange((void*)0x92FFFE00,kernelboot_bin_size); //Loading Nintendont Kernel... - if(argsboot == false) - ShowMessageScreen("Loading Nintendont Kernel..."); - //close in case this is wii vc __ES_Close(); memset( STATUS, 0, 0x20 ); @@ -643,8 +631,6 @@ int main(int argc, char **argv) fd = IOS_Open( dev_es, 0 ); IOS_IoctlvAsync(fd, 0x1F, 0, 0, &IOCTL_Buf, NULL, NULL); //Waiting for Nintendont... - if(argsboot == false) - ShowMessageScreen("Waiting for Nintendont..."); while(1) { DCInvalidateRange( STATUS, 0x20 ); @@ -660,10 +646,6 @@ int main(int argc, char **argv) gprintf("Nintendont at your service!\r\n%s\r\n", NIN_GIT_VERSION); KernelLoaded = 1; - // Checking for storage devices... - if(argsboot == false) - ShowMessageScreen("Checking storage devices..."); - // Initialize devices. // TODO: Only mount the device Nintendont was launched from // Mount the other device asynchronously. @@ -686,9 +668,11 @@ int main(int argc, char **argv) // aborting here. if (!devices[DEV_SD] && !devices[DEV_USB]) { - ClearScreen(); gprintf("No FAT device found!\n"); - PrintFormat(DEFAULT_SIZE, MAROON, MENU_POS_X, 232, "No FAT device found!"); + InitialiseBg(); + ShowMessageScreen("Checking storage devices..."); + PrintFormat(DEFAULT_SIZE, MAROON, MENU_POS_X, MENU_POS_Y + 20*20, + "No FAT device found!"); ExitToLoader(1); } // Seems like some programs start without any args @@ -739,26 +723,34 @@ int main(int argc, char **argv) if (!got_nick) memcpy(slippi_settings->nickname, DEFAULT_NICKNAME, 32); - // Prevent autobooting if B is pressed - int i = 0; - while((ncfg->Config & NIN_CFG_AUTO_BOOT) && i < 1000000) + if (IsStealth() && ncfg->Config & NIN_CFG_AUTO_BOOT) + argsboot = true; + + if (argsboot == false) { - if (i == 0) - { - PrintBuildInfo(); - PrintFormat(DEFAULT_SIZE, BLACK, 320 - 90, - MENU_POS_Y + 20*10, "B: Cancel Autoboot"); - GRRLIB_Render(); - ClearScreen(); - } + InitialiseBg(); - FPAD_Update(); - if (FPAD_Cancel(0)) + // Prevent autobooting if B is pressed + int i = 0; + while((ncfg->Config & NIN_CFG_AUTO_BOOT) && i < 1000000) { - ncfg->Config &= ~NIN_CFG_AUTO_BOOT; - break; - } - i++; + if (i == 0) + { + PrintBuildInfo(); + PrintFormat(DEFAULT_SIZE, BLACK, 320 - 90, + MENU_POS_Y + 20*10, "B: Cancel Autoboot"); + GRRLIB_Render(); + ClearScreen(); + } + + FPAD_Update(); + if (FPAD_Cancel(0)) + { + ncfg->Config &= ~NIN_CFG_AUTO_BOOT; + break; + } + i++; + } } } diff --git a/loader/source/menu.c b/loader/source/menu.c index 91694625e..93858f02c 100644 --- a/loader/source/menu.c +++ b/loader/source/menu.c @@ -1940,7 +1940,7 @@ void ReconfigVideo(GXRModeObj *vidmode) */ void PrintLoadKernelError(LoadKernelError_t iosErr, int err) { - ClearScreen(); + InitialiseBg(); PrintBuildInfo(); PrintFormat(DEFAULT_SIZE, MAROON, MENU_POS_X, MENU_POS_Y + 20*4, "Failed to load IOS58 from NAND:"); From d9f21e3a95bb5ba0e65653bf6d8b891661fd8fb1 Mon Sep 17 00:00:00 2001 From: Nicolet Date: Tue, 24 Mar 2026 19:20:03 -0500 Subject: [PATCH 2/3] missed a bg --- loader/source/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/source/main.c b/loader/source/main.c index 358367d67..497312e0c 100644 --- a/loader/source/main.c +++ b/loader/source/main.c @@ -562,6 +562,7 @@ int main(int argc, char **argv) // Load and patch IOS58. if (LoadKernel() < 0) { + InitialiseBg(); // NOTE: Attempting to initialize controllers here causes a crash. // Hence, we can't wait for the user to press the HOME button, so // we'll just wait for a timeout instead. From 66ad0ba45b12d5a6acce7a982c739e483e7f5a1e Mon Sep 17 00:00:00 2001 From: Nicolet Date: Thu, 26 Mar 2026 15:43:13 -0500 Subject: [PATCH 3/3] only poll if not stealth autoboot --- loader/source/main.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/loader/source/main.c b/loader/source/main.c index 497312e0c..6b7b4070f 100644 --- a/loader/source/main.c +++ b/loader/source/main.c @@ -684,12 +684,6 @@ int main(int argc, char **argv) } gprintf("launch_dir = %s\r\n", launch_dir); - // Initialize controllers. - // FIXME: Initialize before storage devices. - // Doing that right now causes usbstorage to fail... - FPAD_Init(); - FPAD_Update(); - // Read IPL Font before doing any patches void *fontbuffer = memalign(32, 0x50000); __SYS_ReadROM((void*)fontbuffer,0x50000,0x1AFF00); @@ -731,6 +725,10 @@ int main(int argc, char **argv) { InitialiseBg(); + // Initialize controllers. + FPAD_Init(); + FPAD_Update(); + // Prevent autobooting if B is pressed int i = 0; while((ncfg->Config & NIN_CFG_AUTO_BOOT) && i < 1000000)