3ds now has proper core launching

This commit is contained in:
meepingsnesroms 2018-05-15 10:30:34 -07:00
parent 1a6f572405
commit 052de6bcd2
7 changed files with 156 additions and 67 deletions

View File

@ -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

View File

@ -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*/);
}

View File

@ -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

View File

@ -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(&param, sizeof(param.argc) + argsLength, __argv_hmac);
res = APT_DoApplicationJump(&param, sizeof(param.argc) + argsLength, argvHmac);
if(R_FAILED(res))
errorAndQuit("CIA cant run, cant jump.");

View File

@ -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(str<endarg);
}
Handle launchOpenFile(const char* path)
{
if (strncmp(path, "sdmc:/", 6) == 0)

View File

@ -1,3 +1,5 @@
#pragma once
#include "common.h"
extern void (*__system_retAddr)(void);
@ -21,4 +23,7 @@ typedef struct
void (* useTitle)(u64 tid, u8 mediatype);
} loaderFuncs_s;
size_t launchAddArg(argData_s* ad, const char* arg);
void launchAddArgsFromString(argData_s* ad, char* arg);
Handle launchOpenFile(const char* path);

View File

@ -65,7 +65,7 @@ static void get_first_valid_core(char* path_return)
{
DIR* dir;
struct dirent* ent;
const char* extension = envIsHomebrew() ? "3dsx" : "cia";
const char* extension = envIsHomebrew() ? ".3dsx" : ".cia";
path_return[0] = '\0';
@ -78,8 +78,8 @@ static void get_first_valid_core(char* path_return)
break;
if (strlen(ent->d_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