From 052de6bcd263001e1e988deef7bb6f73201bd13e Mon Sep 17 00:00:00 2001 From: meepingsnesroms Date: Tue, 15 May 2018 10:30:34 -0700 Subject: [PATCH] 3ds now has proper core launching --- config.def.h | 2 +- ctr/exec-3dsx/exec_3dsx.c | 67 +++++++++++++++++------------ ctr/exec-3dsx/exec_3dsx.h | 3 +- ctr/exec-3dsx/exec_cia.c | 52 +++++++++++----------- ctr/exec-3dsx/mini-hb-menu/launch.c | 61 ++++++++++++++++++++++++++ ctr/exec-3dsx/mini-hb-menu/launch.h | 5 +++ frontend/drivers/platform_ctr.c | 33 ++++++++------ 7 files changed, 156 insertions(+), 67 deletions(-) diff --git a/config.def.h b/config.def.h index 155fa181b6..cf5988c5bf 100644 --- a/config.def.h +++ b/config.def.h @@ -181,7 +181,7 @@ static unsigned swap_interval = 1; static const bool video_threaded = false; #if defined(HAVE_THREADS) -#if defined(GEKKO) || defined(PSP) || defined(_3DS) +#if defined(GEKKO) || defined(PSP) /* For single-core consoles right now it's better to have this be disabled. */ static const bool threaded_data_runloop_enable = false; #else diff --git a/ctr/exec-3dsx/exec_3dsx.c b/ctr/exec-3dsx/exec_3dsx.c index 0cda976eee..63e5404852 100644 --- a/ctr/exec-3dsx/exec_3dsx.c +++ b/ctr/exec-3dsx/exec_3dsx.c @@ -10,11 +10,13 @@ extern const loaderFuncs_s loader_Ninjhax1; extern const loaderFuncs_s loader_Ninjhax2; extern const loaderFuncs_s loader_Rosalina; -static argData_s newProgramArgs;;//the argv variable must remain in memory even when the application exits for the new program to load properly +static void (*launch_3dsx)(const char* path, argData_s* args, executableMetadata_s* em); -int exec_3dsx(const char* path, const char* args){ +static int exec_3dsx_actual(const char* path, const char* args, bool appendPath){ struct stat sBuff; + argData_s newProgramArgs; + char* writeableString[0x400]; bool fileExists; bool inited; @@ -29,39 +31,50 @@ int exec_3dsx(const char* path, const char* args){ return -1; } else if(S_ISDIR(sBuff.st_mode)){ - errno = EINVAL;; + errno = EINVAL; return -1; } - - if(args == NULL || args[0] == '\0') - args = path; - - int argsSize = strlen(args); - strncpy((char*)newProgramArgs.buf , args, ENTRY_ARGBUFSIZE); - if(argsSize >= ENTRY_ARGBUFSIZE) - ((char*)&newProgramArgs.buf[0])[ENTRY_ARGBUFSIZE - 1] = '\0'; - newProgramArgs.dst = (char*)newProgramArgs.buf + (argsSize < ENTRY_ARGBUFSIZE ? argsSize : ENTRY_ARGBUFSIZE); + + //args the string functions write to the passed string, this will cause a write to read only memory sot the string must be cloned + memset(newProgramArgs.buf, '\0', sizeof(newProgramArgs.buf)); + newProgramArgs.dst = (char*)&newProgramArgs.buf[1]; + if(appendPath){ + strcpy(writeableString, path); + launchAddArg(&newProgramArgs, writeableString); + } + if(args != NULL && args[0] != '\0'){ + strcpy(writeableString, args); + launchAddArgsFromString(&newProgramArgs, writeableString); + } inited = loader_Rosalina.init(); - if(inited){ - loader_Rosalina.launchFile(path, &newProgramArgs, NULL); - //exit(0); + launch_3dsx = loader_Rosalina.launchFile; + + if(!inited){ + inited = loader_Ninjhax2.init(); + launch_3dsx = loader_Ninjhax2.launchFile; + } + + if(!inited){ + inited = loader_Ninjhax1.init(); + launch_3dsx = loader_Ninjhax1.launchFile; } - inited = loader_Ninjhax2.init(); if(inited){ - loader_Ninjhax2.launchFile(path, &newProgramArgs, NULL); - //exit(0); - } - - inited = loader_Ninjhax1.init(); - if(inited){ - loader_Ninjhax1.launchFile(path, &newProgramArgs, NULL); - //exit(0); + osSetSpeedupEnable(false); + launch_3dsx(path, &newProgramArgs, NULL); + exit(0); } //should never be reached - //errno = ENOTSUP; - //return -1; - return 0; + errno = ENOTSUP; + return -1; +} + +int exec_3dsx(const char* path, const char* args){ + return exec_3dsx_actual(path, args, true/*appendPath*/); +} + +int exec_3dsx_no_path_in_args(const char* path, const char* args){ + return exec_3dsx_actual(path, args, false/*appendPath*/); } \ No newline at end of file diff --git a/ctr/exec-3dsx/exec_3dsx.h b/ctr/exec-3dsx/exec_3dsx.h index 29301a64aa..888596dba9 100644 --- a/ctr/exec-3dsx/exec_3dsx.h +++ b/ctr/exec-3dsx/exec_3dsx.h @@ -2,7 +2,8 @@ #define EXEC_3DSX_H //since 3dsx programs are not guaranteed access to the OS, the 3dsx bootloader run by the exploit must run the next program -//your program must call this then exit gracefully to work, exit() also doesnt work +//your program must have no extra threads running when this is called, these limits do not apply to exec_cia +int exec_3dsx_no_path_in_args(const char* path, const char* args); int exec_3dsx(const char* path, const char* args); #endif \ No newline at end of file diff --git a/ctr/exec-3dsx/exec_cia.c b/ctr/exec-3dsx/exec_cia.c index 50d63926f0..f7d568d545 100644 --- a/ctr/exec-3dsx/exec_cia.c +++ b/ctr/exec-3dsx/exec_cia.c @@ -14,6 +14,9 @@ typedef struct{ }ciaParam; +char argvHmac[0x20] = {0x1d, 0x78, 0xff, 0xb9, 0xc5, 0xbc, 0x78, 0xb7, 0xac, 0x29, 0x1d, 0x3e, 0x16, 0xd0, 0xcf, 0x53, 0xef, 0x12, 0x58, 0x83, 0xb6, 0x9e, 0x2f, 0x79, 0x47, 0xf9, 0x35, 0x61, 0xeb, 0x50, 0xd7, 0x67}; + + static void errorAndQuit(const char* errorStr){ errorConf error; @@ -23,10 +26,12 @@ static void errorAndQuit(const char* errorStr){ exit(0); } -static int isCiaInstalled(u64 titleId){ +static int isCiaInstalled(u64 titleId, u16 version){ u32 titlesToRetrieve; u32 titlesRetrieved; u64* titleIds; + bool titleExists = false; + AM_TitleEntry titleInfo; Result failed; failed = AM_GetTitleCount(MEDIATYPE_SD, &titlesToRetrieve); @@ -43,12 +48,22 @@ static int isCiaInstalled(u64 titleId){ for(u32 titlesToCheck = 0; titlesToCheck < titlesRetrieved; titlesToCheck++){ if(titleIds[titlesToCheck] == titleId){ - free(titleIds); - return 1; + titleExists = true; + break; } } free(titleIds); + + if(titleExists){ + failed = AM_GetTitleInfo(MEDIATYPE_SD, 1 /*titleCount*/, &titleId, &titleInfo); + if(R_FAILED(failed)) + return -1; + + if(titleInfo.version == version) + return 1; + } + return 0; } @@ -100,17 +115,6 @@ static int installCia(Handle ciaFile){ return 1; } -static u64 getCiaTitleId(Handle ciaFile){ - Result failed; - AM_TitleEntry ciaInfo; - - failed = AM_GetCiaFileInfo(MEDIATYPE_SD, &ciaInfo, ciaFile); - if(R_FAILED(failed)) - return 0x0000000000000000; - - return ciaInfo.titleID; -} - int exec_cia(const char* path, const char* args){ struct stat sBuff; bool fileExists; @@ -134,14 +138,12 @@ int exec_cia(const char* path, const char* args){ inited = R_SUCCEEDED(amInit()) && R_SUCCEEDED(fsInit()); if(inited){ Result res; - int error; + AM_TitleEntry ciaInfo; FS_Archive ciaArchive; Handle ciaFile; - u64 titleId; int ciaInstalled; ciaParam param; int argsLength; - extern char __argv_hmac[0x20]; //open cia file res = FSUSER_OpenArchive(&ciaArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")); @@ -151,12 +153,12 @@ int exec_cia(const char* path, const char* args){ res = FSUSER_OpenFile(&ciaFile, ciaArchive, fsMakePath(PATH_ASCII, path + 5/*skip "sdmc:"*/), FS_OPEN_READ, 0); if(R_FAILED(res)) errorAndQuit("Cant open CIA file."); + + res = AM_GetCiaFileInfo(MEDIATYPE_SD, &ciaInfo, ciaFile); + if(R_FAILED(res)) + errorAndQuit("Cant get CIA file info."); - titleId = getCiaTitleId(ciaFile); - if(titleId == 0x0000000000000000) - errorAndQuit("Cant get CIA file title id."); - - ciaInstalled = isCiaInstalled(titleId); + ciaInstalled = isCiaInstalled(ciaInfo.titleID, ciaInfo.version); if(ciaInstalled == -1){ //error errorAndQuit("Could not read title id list."); @@ -164,7 +166,6 @@ int exec_cia(const char* path, const char* args){ else if(ciaInstalled == 0){ //not installed int error = installCia(ciaFile); - if(error == -1) errorAndQuit("Cant install CIA."); } @@ -180,7 +181,6 @@ int exec_cia(const char* path, const char* args){ bool inSingleQuotes = false; bool inDoubleQuotes = false; int argStringLength = strlen(args); - int argPtr; param.argc = 0; argsLength = 0; @@ -204,11 +204,11 @@ int exec_cia(const char* path, const char* args){ } } - res = APT_PrepareToDoApplicationJump(0, titleId, 0x1); + res = APT_PrepareToDoApplicationJump(0, ciaInfo.titleID, 0x1); if(R_FAILED(res)) errorAndQuit("CIA cant run, cant prepare."); - res = APT_DoApplicationJump(¶m, sizeof(param.argc) + argsLength, __argv_hmac); + res = APT_DoApplicationJump(¶m, sizeof(param.argc) + argsLength, argvHmac); if(R_FAILED(res)) errorAndQuit("CIA cant run, cant jump."); diff --git a/ctr/exec-3dsx/mini-hb-menu/launch.c b/ctr/exec-3dsx/mini-hb-menu/launch.c index e5adf30581..e9f6460427 100644 --- a/ctr/exec-3dsx/mini-hb-menu/launch.c +++ b/ctr/exec-3dsx/mini-hb-menu/launch.c @@ -1,5 +1,66 @@ #include "common.h" +size_t launchAddArg(argData_s* ad, const char* arg) +{ + size_t len = strlen(arg)+1; + if ((ad->dst+len) >= (char*)(ad+1)) return len; // Overflow + ad->buf[0]++; + strcpy(ad->dst, arg); + ad->dst += len; + return len; +} + +void launchAddArgsFromString(argData_s* ad, char* arg) +{ + char c, *pstr, *str=arg, *endarg = arg+strlen(arg); + + do + { + do + { + c = *str++; + } while ((c == ' ' || c == '\t') && str < endarg); + + pstr = str-1; + + if (c == '\"') + { + pstr++; + while(*str++ != '\"' && str < endarg); + } + else + if (c == '\'') + { + pstr++; + while(*str++ != '\'' && str < endarg); + } + else + { + do + { + c = *str++; + } while (c != ' ' && c != '\t' && str < endarg); + } + + str--; + + if (str == (endarg - 1)) + { + if(*str == '\"' || *str == '\'') + *(str++) = 0; + else + str++; + } + else + { + *(str++) = '\0'; + } + + launchAddArg(ad, pstr); + + } while(strd_name) > strlen(extension) && !strcmp(ent->d_name + strlen(ent->d_name) - strlen(extension), extension)) { - strcpy(path_return, "sdmc:/retroarch/cores"); - strcat(path_return, "/"); + strcpy(path_return, "sdmc:/retroarch/cores"); + strcat(path_return, "/"); strcat(path_return, ent->d_name); break; } @@ -188,7 +188,7 @@ static void frontend_ctr_exec(const char* path, bool should_load_game) DEBUG_VAR(path); DEBUG_STR(path); - strlcpy(args, elf_path_cst, sizeof(args)); + strncpy(args, elf_path_cst, sizeof(args)); RARCH_LOG("Attempt to load core: [%s].\n", path); #ifndef IS_SALAMANDER @@ -205,10 +205,10 @@ static void frontend_ctr_exec(const char* path, bool should_load_game) struct stat sbuff; bool file_exists; - fileExists = stat(path, &sBuff) == 0; - if (!fileExists) + file_exists = stat(path, &sbuff) == 0; + if (!file_exists) { - char core_path[512]; + char core_path[PATH_MAX]; /* find first valid core and load it if the target core doesnt exist */ get_first_valid_core(&core_path[0]); @@ -225,14 +225,23 @@ static void frontend_ctr_exec(const char* path, bool should_load_game) } #endif if (envIsHomebrew()) - error = exec_3dsx(path, args); + { + exec_3dsx_no_path_in_args(path, args); + } else - error = exec_cia(path, args); + { + RARCH_LOG("\n"); + RARCH_LOG("\n"); + RARCH_LOG("Warning:\n"); + RARCH_LOG("First core launch may take 20 seconds!\n"); + RARCH_LOG("Do not force quit before then or your memory card may be corrupted!\n"); + RARCH_LOG("\n"); + RARCH_LOG("\n"); + exec_cia(path, args); + } + exit(0);//couldnt launch new core, but context is corrupt so we have to quit } - - if (error) - RARCH_LOG("Cant execute new core:%s.\n", strerror(errno)); } #ifndef IS_SALAMANDER