Start using proper 3ds executable formats (doesnt work properly yet)

This commit is contained in:
meepingsnesroms 2018-05-09 15:55:48 -07:00
parent 70bbe0bdb1
commit 5f234f0dd1
14 changed files with 1186 additions and 565 deletions

View File

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

View File

@ -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
View 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;
}

View File

@ -0,0 +1 @@
int exec_3dsx(const char* path, const char* args);

214
ctr/exec-3dsx/exec_cia.c Normal file
View 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(&param, 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
View File

@ -0,0 +1 @@
int exec_cia(const char* path, const char* args);

View 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"

View 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;
}

View 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);

View 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,
};

View 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,
};

View 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

View File

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