TuxSH ceea6afa05 loader: add external CXI loading.
When "load external firms and modules" is enabled, Loader will load the
sysmodule from /luma/sysmodule/<titleid>.cxi (all uppercase, and with
the N3DS title ID bit if relevant) and skip patching. Note that this is
a title ID here, not a process name (unlike what we do for KIPs).

While this is aimed at enabling people to easily load replacements for
official sysmodules, you can load your own custom sysmodules that don't
correspond to anything installed. You can use gdb to do so:

  set remote exec-file <tid>
  run
2023-01-23 19:53:01 +00:00

105 lines
2.5 KiB
C

#pragma once
#include <3ds/types.h>
#include <3ds/result.h>
#include <3ds/os.h>
#include <3ds/srv.h>
#define REG32(reg) (*(vu32 *)reg)
#define REG64(reg) (*(vu64 *)reg)
#define TRY(expr) if(R_FAILED(res = (expr))) return res;
#define TRYG(expr, label) if(R_FAILED(res = (expr))) goto label;
typedef struct Ncch {
u8 sig[0x100]; //RSA-2048 signature of the NCCH header, using SHA-256
char magic[4]; //NCCH
u32 contentSize; //Media unit
u8 partitionId[8];
u8 makerCode[2];
u16 version;
u8 reserved1[4];
u8 programID[8];
u8 reserved2[0x10];
u8 logoHash[0x20]; //Logo Region SHA-256 hash
char productCode[0x10];
u8 exHeaderHash[0x20]; //Extended header SHA-256 hash
u32 exHeaderSize; //Extended header size
u32 reserved3;
u8 flags[8];
u32 plainOffset; //Media unit
u32 plainSize; //Media unit
u32 logoOffset; //Media unit
u32 logoSize; //Media unit
u32 exeFsOffset; //Media unit
u32 exeFsSize; //Media unit
u32 exeFsHashSize; //Media unit
u32 reserved4;
u32 romFsOffset; //Media unit
u32 romFsSize; //Media unit
u32 romFsHashSize; //Media unit
u32 reserved5;
u8 exeFsHash[0x20]; //ExeFS superblock SHA-256 hash
u8 romFsHash[0x20]; //RomFS superblock SHA-256 hash
} Ncch;
typedef struct ExeFsFileHeader {
char name[8];
u32 offset;
u32 size;
} ExeFsFileHeader;
typedef struct ExeFsHeader {
ExeFsFileHeader fileHeaders[10];
u8 _reserved_0xa0[0xC0 - 0xA0];
u8 fileHashes[10][32];
} ExeFsHeader;
#ifdef XDS
static void hexItoa(u64 number, char *out, u32 digits, bool uppercase)
{
const char hexDigits[] = "0123456789ABCDEF";
const char hexDigitsLowercase[] = "0123456789abcdef";
u32 i = 0;
while(number > 0)
{
out[digits - 1 - i++] = uppercase ? hexDigits[number & 0xF] : hexDigitsLowercase[number & 0xF];
number >>= 4;
}
while(i < digits) out[digits - 1 - i++] = '0';
}
static inline void debugOutputHex(u64 number, u32 digits)
{
char buf[16+2];
hexItoa(number, buf, digits, false);
buf[digits] = '\n';
buf[digits + 1] = '\0';
svcOutputDebugString(buf, digits + 1);
}
#endif
static void __attribute__((noinline)) panic(Result res)
{
#ifndef XDS
(void)res;
__builtin_trap();
#else
debugOutputHex(res, 8);
svcBreak(USERBREAK_PANIC);
#endif
}
static inline Result assertSuccess(Result res)
{
if(R_FAILED(res)) {
panic(res);
}
return res;
}