mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 07:59:42 +00:00
Start using proper 3ds executable formats (doesnt work properly yet)
This commit is contained in:
parent
70bbe0bdb1
commit
5f234f0dd1
@ -31,6 +31,12 @@ OBJ += ctr/ctr_system.o
|
||||
OBJ += ctr/ctr_memory.o
|
||||
OBJ += ctr/ctr_linear.o
|
||||
OBJ += ctr/gpu_old.o
|
||||
OBJ += ctr/exec-3dsx/exec_cia.o \
|
||||
ctr/exec-3dsx/exec_3dsx.o \
|
||||
ctr/exec-3dsx/mini-hb-menu/launch.o \
|
||||
ctr/exec-3dsx/mini-hb-menu/loaders/rosalina.o \
|
||||
ctr/exec-3dsx/mini-hb-menu/loaders/hax2.o \
|
||||
ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.o
|
||||
|
||||
ifeq ($(APP_BIG_TEXT_SECTION), 1)
|
||||
APP_USE_SVCHAX = 1
|
||||
|
@ -39,6 +39,13 @@ OBJ := ctr/ctr_system.o \
|
||||
libretro-common/hash/rhash.o \
|
||||
file_path_str.o \
|
||||
verbosity.o
|
||||
|
||||
OBJ += ctr/exec-3dsx/exec_cia.o \
|
||||
ctr/exec-3dsx/exec_3dsx.o \
|
||||
ctr/exec-3dsx/mini-hb-menu/launch.o \
|
||||
ctr/exec-3dsx/mini-hb-menu/loaders/rosalina.o \
|
||||
ctr/exec-3dsx/mini-hb-menu/loaders/hax2.o \
|
||||
ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.o
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitpro")
|
||||
|
66
ctr/exec-3dsx/exec_3dsx.c
Normal file
66
ctr/exec-3dsx/exec_3dsx.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "mini-hb-menu/common.h"
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
int exec_3dsx(const char* path, const char* args){
|
||||
struct stat sBuff;
|
||||
bool fileExists;
|
||||
bool inited;
|
||||
|
||||
if(path == NULL || path[0] == '\0'){
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fileExists = stat(path, &sBuff) == 0;
|
||||
if(!fileExists){
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
else if(S_ISDIR(sBuff.st_mode)){
|
||||
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);
|
||||
|
||||
inited = loader_Rosalina.init();
|
||||
if(inited){
|
||||
loader_Rosalina.launchFile(path, &newProgramArgs, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//should never be reached
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
1
ctr/exec-3dsx/exec_3dsx.h
Normal file
1
ctr/exec-3dsx/exec_3dsx.h
Normal file
@ -0,0 +1 @@
|
||||
int exec_3dsx(const char* path, const char* args);
|
214
ctr/exec-3dsx/exec_cia.c
Normal file
214
ctr/exec-3dsx/exec_cia.c
Normal file
@ -0,0 +1,214 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <3ds.h>
|
||||
|
||||
|
||||
#define FILE_CHUNK_SIZE 4096
|
||||
|
||||
|
||||
typedef struct{
|
||||
u32 argc;
|
||||
char args[0x300 - 0x4];
|
||||
}ciaParam;
|
||||
|
||||
|
||||
static int isCiaInstalled(u64 titleId){
|
||||
u32 titlesToRetrieve;
|
||||
u32 titlesRetrieved;
|
||||
u64* titleIds;
|
||||
Result failed;
|
||||
|
||||
failed = AM_GetTitleCount(MEDIATYPE_SD, &titlesToRetrieve);
|
||||
if(R_FAILED(failed))
|
||||
return -1;
|
||||
|
||||
titleIds = malloc(titlesToRetrieve * sizeof(uint64_t));
|
||||
if(titleIds == NULL)
|
||||
return -1;
|
||||
|
||||
failed = AM_GetTitleList(&titlesRetrieved, MEDIATYPE_SD, titlesToRetrieve, titleIds);
|
||||
if(R_FAILED(failed))
|
||||
return -1;
|
||||
|
||||
for(u32 titlesToCheck = 0; titlesToCheck < titlesRetrieved; titlesToCheck++){
|
||||
if(titleIds[titlesToCheck] == titleId){
|
||||
free(titleIds);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(titleIds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int installCia(Handle ciaFile){
|
||||
Result failed;
|
||||
Handle outputHandle;
|
||||
u64 fileSize;
|
||||
u64 fileOffset = 0;
|
||||
u32 bytesRead;
|
||||
u32 bytesWritten;
|
||||
u8 transferBuffer[FILE_CHUNK_SIZE];
|
||||
|
||||
failed = AM_StartCiaInstall(MEDIATYPE_SD, &outputHandle);
|
||||
if(R_FAILED(failed))
|
||||
return -1;
|
||||
|
||||
failed = FSFILE_GetSize(ciaFile, &fileSize);
|
||||
if(R_FAILED(failed))
|
||||
return -1;
|
||||
|
||||
while(fileOffset < fileSize){
|
||||
u64 bytesRemaining = fileSize - fileOffset;
|
||||
failed = FSFILE_Read(ciaFile, &bytesRead, fileOffset, transferBuffer, bytesRemaining < FILE_CHUNK_SIZE ? bytesRemaining : FILE_CHUNK_SIZE);
|
||||
if(R_FAILED(failed)){
|
||||
AM_CancelCIAInstall(outputHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
failed = FSFILE_Write(outputHandle, &bytesWritten, fileOffset, transferBuffer, bytesRead, 0);
|
||||
if(R_FAILED(failed)){
|
||||
AM_CancelCIAInstall(outputHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(bytesWritten != bytesRead){
|
||||
AM_CancelCIAInstall(outputHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fileOffset += bytesWritten;
|
||||
}
|
||||
|
||||
failed = AM_FinishCiaInstall(outputHandle);
|
||||
if(R_FAILED(failed))
|
||||
return -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void errorAndQuit(const char* errorStr){
|
||||
errorConf error;
|
||||
|
||||
errorInit(&error, ERROR_TEXT, CFG_LANGUAGE_EN);
|
||||
errorText(&error, errorStr);
|
||||
errorDisp(&error);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int exec_cia(const char* path, const char* args){
|
||||
struct stat sBuff;
|
||||
bool fileExists;
|
||||
bool inited;
|
||||
|
||||
if(path == NULL || path[0] == '\0'){
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fileExists = stat(path, &sBuff) == 0;
|
||||
if(!fileExists){
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
else if(S_ISDIR(sBuff.st_mode)){
|
||||
errno = EINVAL;;
|
||||
return -1;
|
||||
}
|
||||
|
||||
inited = R_SUCCEEDED(amInit()) && R_SUCCEEDED(fsInit());
|
||||
if(inited){
|
||||
Result res;
|
||||
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, ""));
|
||||
if(R_FAILED(res))
|
||||
errorAndQuit("Cant open SD FS archive.");
|
||||
|
||||
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.");
|
||||
|
||||
titleId = getCiaTitleId(ciaFile);
|
||||
if(titleId == 0x0000000000000000)
|
||||
errorAndQuit("Cant get CIA file title id.");
|
||||
|
||||
ciaInstalled = isCiaInstalled(titleId);
|
||||
if(ciaInstalled == -1){
|
||||
//error
|
||||
errorAndQuit("Could not read title id list.");
|
||||
}
|
||||
else if(ciaInstalled == 0){
|
||||
//not installed
|
||||
int error = installCia(ciaFile);
|
||||
|
||||
if(error == -1)
|
||||
errorAndQuit("Cant install CIA.");
|
||||
}
|
||||
|
||||
FSFILE_Close(ciaFile);
|
||||
FSUSER_CloseArchive(ciaArchive);
|
||||
|
||||
if(args == NULL || args[0] == '\0'){
|
||||
param.argc = 0;
|
||||
argsLength = 0;
|
||||
}
|
||||
else{
|
||||
bool inSingleQuotes = false;
|
||||
bool inDoubleQuotes = false;
|
||||
int argStringLength = strlen(args);
|
||||
int argPtr;
|
||||
param.argc = 0;
|
||||
argsLength = 0;
|
||||
|
||||
//build argument list like a terminal command on linux
|
||||
for(unsigned int argPtr = 0; argPtr < argStringLength; argPtr++){
|
||||
if(args[argPtr] == '\'')
|
||||
inSingleQuotes = !inSingleQuotes;
|
||||
else if(args[argPtr] == '\"')
|
||||
inDoubleQuotes = !inDoubleQuotes;
|
||||
else{
|
||||
if(!inSingleQuotes && !inDoubleQuotes && args[argPtr] == ' '){
|
||||
param.argc++;
|
||||
param.args[argsLength] = '\0';
|
||||
}
|
||||
else{
|
||||
param.args[argsLength] = args[argPtr];
|
||||
}
|
||||
|
||||
argsLength++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res = APT_PrepareToDoApplicationJump(0, titleId, 0x1);
|
||||
if(R_SUCCEEDED(res))
|
||||
res = APT_DoApplicationJump(¶m, sizeof(param.argc) + argsLength, __argv_hmac);
|
||||
}
|
||||
|
||||
//should never be reached
|
||||
amExit();
|
||||
fsExit();
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
1
ctr/exec-3dsx/exec_cia.h
Normal file
1
ctr/exec-3dsx/exec_cia.h
Normal file
@ -0,0 +1 @@
|
||||
int exec_cia(const char* path, const char* args);
|
95
ctr/exec-3dsx/mini-hb-menu/common.h
Normal file
95
ctr/exec-3dsx/mini-hb-menu/common.h
Normal file
@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
// C stdlib includes
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// 3DS includes
|
||||
#include <3ds.h>
|
||||
|
||||
|
||||
#define ENTRY_ARGBUFSIZE 0x400
|
||||
#define NUM_SERVICESTHATMATTER 5
|
||||
|
||||
typedef enum
|
||||
{
|
||||
StrId_Loading = 0,
|
||||
StrId_Directory,
|
||||
StrId_DefaultLongTitle,
|
||||
StrId_DefaultPublisher,
|
||||
StrId_IOError,
|
||||
StrId_CouldNotOpenFile,
|
||||
|
||||
StrId_NoAppsFound_Title,
|
||||
StrId_NoAppsFound_Msg,
|
||||
|
||||
StrId_Reboot,
|
||||
StrId_ReturnToHome,
|
||||
|
||||
StrId_TitleSelector,
|
||||
StrId_ErrorReadingTitleMetadata,
|
||||
StrId_NoTitlesFound,
|
||||
StrId_SelectTitle,
|
||||
|
||||
StrId_NoTargetTitleSupport,
|
||||
StrId_MissingTargetTitle,
|
||||
|
||||
StrId_NetLoader,
|
||||
StrId_NetLoaderUnavailable,
|
||||
StrId_NetLoaderOffline,
|
||||
StrId_NetLoaderError,
|
||||
StrId_NetLoaderActive,
|
||||
StrId_NetLoaderTransferring,
|
||||
|
||||
StrId_Max,
|
||||
} StrId;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* dst;
|
||||
u32 buf[ENTRY_ARGBUFSIZE/sizeof(u32)];
|
||||
} argData_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool scanned;
|
||||
u32 sectionSizes[3];
|
||||
bool servicesThatMatter[NUM_SERVICESTHATMATTER];
|
||||
} executableMetadata_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 num;
|
||||
u32 text_end;
|
||||
u32 data_address;
|
||||
u32 data_size;
|
||||
u32 processLinearOffset;
|
||||
u32 processHookAddress;
|
||||
u32 processAppCodeAddress;
|
||||
u32 processHookTidLow, processHookTidHigh;
|
||||
u32 mediatype;
|
||||
bool capabilities[0x10]; // {socuAccess, csndAccess, qtmAccess, nfcAccess, httpcAccess, reserved...}
|
||||
} memmap_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 src, dst, size;
|
||||
} memmap_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
memmap_header_t header;
|
||||
memmap_entry_t map[];
|
||||
} memmap_t;
|
||||
|
||||
#define memmapSize(m) (sizeof(memmap_header_t) + sizeof(memmap_entry_t)*(m)->header.num)
|
||||
|
||||
|
||||
#include "launch.h"
|
22
ctr/exec-3dsx/mini-hb-menu/launch.c
Normal file
22
ctr/exec-3dsx/mini-hb-menu/launch.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include "common.h"
|
||||
|
||||
Handle launchOpenFile(const char* path)
|
||||
{
|
||||
if (strncmp(path, "sdmc:/", 6) == 0)
|
||||
path += 5;
|
||||
else if (*path != '/')
|
||||
return 0;
|
||||
|
||||
// Convert the executable path to UTF-16
|
||||
static uint16_t __utf16path[PATH_MAX+1];
|
||||
ssize_t units = utf8_to_utf16(__utf16path, (const uint8_t*)path, PATH_MAX);
|
||||
if (units < 0 || units >= PATH_MAX) return 0;
|
||||
__utf16path[units] = 0;
|
||||
|
||||
// Open the file directly
|
||||
FS_Path apath = { PATH_EMPTY, 1, (u8*)"" };
|
||||
FS_Path fpath = { PATH_UTF16, (units+1)*2, (u8*)__utf16path };
|
||||
Handle file;
|
||||
Result res = FSUSER_OpenFileDirectly(&file, ARCHIVE_SDMC, apath, fpath, FS_OPEN_READ, 0);
|
||||
return R_SUCCEEDED(res) ? file : 0;
|
||||
}
|
24
ctr/exec-3dsx/mini-hb-menu/launch.h
Normal file
24
ctr/exec-3dsx/mini-hb-menu/launch.h
Normal file
@ -0,0 +1,24 @@
|
||||
#include "common.h"
|
||||
|
||||
extern void (*__system_retAddr)(void);
|
||||
|
||||
enum
|
||||
{
|
||||
LOADER_SHOW_REBOOT = 0x01,
|
||||
LOADER_NEED_SCAN = 0x02
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Mandatory fields
|
||||
const char* name;
|
||||
u32 flags;
|
||||
bool (* init)(void);
|
||||
void (* deinit)(void);
|
||||
void (* launchFile)(const char* path, argData_s* args, executableMetadata_s* em);
|
||||
|
||||
// Optional fields
|
||||
void (* useTitle)(u64 tid, u8 mediatype);
|
||||
} loaderFuncs_s;
|
||||
|
||||
Handle launchOpenFile(const char* path);
|
73
ctr/exec-3dsx/mini-hb-menu/loaders/hax2.c
Normal file
73
ctr/exec-3dsx/mini-hb-menu/loaders/hax2.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include "../common.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s32 processId;
|
||||
bool capabilities[0x10];
|
||||
} processEntry_s;
|
||||
|
||||
typedef void (*callBootloader_2x_fn)(Handle file, u32* argbuf, u32 arglength);
|
||||
typedef void (*callBootloaderNewProcess_2x_fn)(s32 processId, u32* argbuf, u32 arglength);
|
||||
typedef void (*callBootloaderRunTitle_2x_fn)(u8 mediatype, u32* argbuf, u32 argbuflength, u32 tid_low, u32 tid_high);
|
||||
typedef void (*callBootloaderRunTitleCustom_2x_fn)(u8 mediatype, u32* argbuf, u32 argbuflength, u32 tid_low, u32 tid_high, memmap_t* mmap);
|
||||
typedef void (*getBestProcess_2x_fn)(u32 sectionSizes[3], bool* requirements, int num_requirements, processEntry_s* out, int out_size, int* out_len);
|
||||
|
||||
#define callBootloader_2x ((callBootloader_2x_fn)0x00100000)
|
||||
#define callBootloaderNewProcess_2x ((callBootloaderNewProcess_2x_fn)0x00100008)
|
||||
#define callBootloaderRunTitle_2x ((callBootloaderRunTitle_2x_fn)0x00100010)
|
||||
#define callBootloaderRunTitleCustom_2x ((callBootloaderRunTitleCustom_2x_fn)0x00100014)
|
||||
#define getBestProcess_2x ((getBestProcess_2x_fn)0x0010000C)
|
||||
|
||||
static s32 targetProcess = -1;
|
||||
static u64 targetTid;
|
||||
static u8 targetMediatype;
|
||||
static Handle fileHandle;
|
||||
static u32 argBuf[ENTRY_ARGBUFSIZE/sizeof(u32)];
|
||||
static u32 argBufLen;
|
||||
static u32 memMapBuf[0x40];
|
||||
static bool useMemMap;
|
||||
|
||||
static bool init(void)
|
||||
{
|
||||
return R_SUCCEEDED(amInit());
|
||||
}
|
||||
|
||||
static void deinit(void)
|
||||
{
|
||||
amExit();
|
||||
}
|
||||
|
||||
static void bootloaderJump(void)
|
||||
{
|
||||
if (targetProcess == -1)
|
||||
callBootloader_2x(fileHandle, argBuf, argBufLen);
|
||||
else if (targetProcess == -2)
|
||||
{
|
||||
if (useMemMap)
|
||||
callBootloaderRunTitleCustom_2x(targetMediatype, argBuf, argBufLen, (u32)targetTid, (u32)(targetTid>>32), (memmap_t*)memMapBuf);
|
||||
else
|
||||
callBootloaderRunTitle_2x(targetMediatype, argBuf, argBufLen, (u32)targetTid, (u32)(targetTid>>32));
|
||||
}
|
||||
else
|
||||
callBootloaderNewProcess_2x(targetProcess, argBuf, argBufLen);
|
||||
}
|
||||
|
||||
static void launchFile(const char* path, argData_s* args, executableMetadata_s* em)
|
||||
{
|
||||
fileHandle = launchOpenFile(path);
|
||||
if (fileHandle==0)
|
||||
return;
|
||||
argBufLen = args->dst - (char*)args->buf;
|
||||
memcpy(argBuf, args->buf, argBufLen);
|
||||
__system_retAddr = bootloaderJump;
|
||||
}
|
||||
|
||||
const loaderFuncs_s loader_Ninjhax2 =
|
||||
{
|
||||
.name = "hax 2.x",
|
||||
.flags = LOADER_SHOW_REBOOT | LOADER_NEED_SCAN,
|
||||
.init = init,
|
||||
.deinit = deinit,
|
||||
.launchFile = launchFile,
|
||||
//.useTitle = useTitle,
|
||||
};
|
43
ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.c
Normal file
43
ctr/exec-3dsx/mini-hb-menu/loaders/ninjhax1.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include "../common.h"
|
||||
|
||||
static void (*callBootloader_1x)(Handle hb, Handle file);
|
||||
static void (*setArgs_1x)(u32* src, u32 length);
|
||||
static Handle fileHandle;
|
||||
|
||||
static bool init(void)
|
||||
{
|
||||
Result res = hbInit();
|
||||
if (R_FAILED(res))
|
||||
return false;
|
||||
|
||||
HB_GetBootloaderAddresses((void**)&callBootloader_1x, (void**)&setArgs_1x);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void deinit(void)
|
||||
{
|
||||
hbExit();
|
||||
}
|
||||
|
||||
static void bootloaderJump(void)
|
||||
{
|
||||
callBootloader_1x(0x00000000, fileHandle);
|
||||
}
|
||||
|
||||
static void launchFile(const char* path, argData_s* args, executableMetadata_s* em)
|
||||
{
|
||||
fileHandle = launchOpenFile(path);
|
||||
if (fileHandle==0)
|
||||
return;
|
||||
setArgs_1x(args->buf, sizeof(args->buf));
|
||||
__system_retAddr = bootloaderJump;
|
||||
}
|
||||
|
||||
const loaderFuncs_s loader_Ninjhax1 =
|
||||
{
|
||||
.name = "ninjhax 1.x",
|
||||
.flags = LOADER_SHOW_REBOOT,
|
||||
.init = init,
|
||||
.deinit = deinit,
|
||||
.launchFile = launchFile,
|
||||
};
|
56
ctr/exec-3dsx/mini-hb-menu/loaders/rosalina.c
Normal file
56
ctr/exec-3dsx/mini-hb-menu/loaders/rosalina.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include "../common.h"
|
||||
|
||||
static Handle hbldrHandle;
|
||||
|
||||
static bool init(void)
|
||||
{
|
||||
return R_SUCCEEDED(svcConnectToPort(&hbldrHandle, "hb:ldr"));
|
||||
}
|
||||
|
||||
static Result HBLDR_SetTarget(const char* path)
|
||||
{
|
||||
u32 pathLen = strlen(path) + 1;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(2, 0, 2); //0x20002
|
||||
cmdbuf[1] = IPC_Desc_StaticBuffer(pathLen, 0);
|
||||
cmdbuf[2] = (u32)path;
|
||||
|
||||
Result rc = svcSendSyncRequest(hbldrHandle);
|
||||
if (R_SUCCEEDED(rc)) rc = cmdbuf[1];
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result HBLDR_SetArgv(const void* buffer, u32 size)
|
||||
{
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(3, 0, 2); //0x30002
|
||||
cmdbuf[1] = IPC_Desc_StaticBuffer(size, 1);
|
||||
cmdbuf[2] = (u32)buffer;
|
||||
|
||||
Result rc = svcSendSyncRequest(hbldrHandle);
|
||||
if (R_SUCCEEDED(rc)) rc = cmdbuf[1];
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void deinit(void)
|
||||
{
|
||||
svcCloseHandle(hbldrHandle);
|
||||
}
|
||||
|
||||
static void launchFile(const char* path, argData_s* args, executableMetadata_s* em)
|
||||
{
|
||||
if (strncmp(path, "sdmc:/",6) == 0)
|
||||
path += 5;
|
||||
HBLDR_SetTarget(path);
|
||||
HBLDR_SetArgv(args->buf, sizeof(args->buf));
|
||||
}
|
||||
|
||||
const loaderFuncs_s loader_Rosalina =
|
||||
{
|
||||
.name = "Rosalina",
|
||||
.init = init,
|
||||
.deinit = deinit,
|
||||
.launchFile = launchFile,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,10 @@
|
||||
#include <compat/strl.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#if defined(_3DS)
|
||||
#include <3ds.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
@ -147,7 +151,10 @@ bool frontend_driver_get_core_extension(char *s, size_t len)
|
||||
strlcpy(s, "elf", len);
|
||||
return true;
|
||||
#elif defined(_3DS)
|
||||
strlcpy(s, "core", len);
|
||||
if (envIsHomebrew())
|
||||
strlcpy(s, "3dsx", len);
|
||||
else
|
||||
strlcpy(s, "cia", len);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user