2019-04-18 19:48:01 +02:00
|
|
|
#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;
|
|
|
|
|
|
2023-01-23 19:48:13 +00:00
|
|
|
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;
|
|
|
|
|
|
2019-04-18 19:48:01 +02:00
|
|
|
#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';
|
|
|
|
|
}
|
2020-12-07 20:17:30 +00:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-18 19:48:01 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static void __attribute__((noinline)) panic(Result res)
|
|
|
|
|
{
|
|
|
|
|
#ifndef XDS
|
|
|
|
|
(void)res;
|
|
|
|
|
__builtin_trap();
|
|
|
|
|
#else
|
2020-12-07 20:17:30 +00:00
|
|
|
debugOutputHex(res, 8);
|
2019-04-18 19:48:01 +02:00
|
|
|
svcBreak(USERBREAK_PANIC);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline Result assertSuccess(Result res)
|
|
|
|
|
{
|
|
|
|
|
if(R_FAILED(res)) {
|
|
|
|
|
panic(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|