
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
105 lines
2.5 KiB
C
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;
|
|
}
|