mirror of
https://github.com/libretro/RetroArch
synced 2025-02-28 03:39:59 +00:00
3ds now has proper core launching
This commit is contained in:
parent
1a6f572405
commit
052de6bcd2
@ -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
|
||||
|
@ -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*/);
|
||||
}
|
@ -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
|
@ -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.");
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user