From 158d10410c659f1c979d0d7a6b905fa0892014a7 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Fri, 11 Mar 2016 01:29:14 +0100 Subject: [PATCH] Make this A9LH compatible --- source/abstraction/bs-start.s | 1 + source/fatfs/diskio.c | 7 ++-- source/fs.c | 76 ++++++++++++++++++++++------------- source/fs.h | 8 +++- source/godmode.c | 10 ++++- source/nand/aes.c | 51 +++++++++++++++++------ source/nand/aes.h | 2 + source/nand/nand.c | 33 ++++++++++++++- 8 files changed, 140 insertions(+), 48 deletions(-) diff --git a/source/abstraction/bs-start.s b/source/abstraction/bs-start.s index 2cfb33e..63629ab 100644 --- a/source/abstraction/bs-start.s +++ b/source/abstraction/bs-start.s @@ -81,6 +81,7 @@ _enable_caches: mcr p15, 0, r5, c7, c6, 0 @ flush D-cache mrc p15, 0, r4, c1, c0, 0 + orr r4, r4, #(1<<18) @ itcm enable orr r4, r4, #(1<<12) @ instruction cache enable orr r4, r4, #(1<<2) @ data cache enable orr r4, r4, #(1<<0) @ mpu enable diff --git a/source/fatfs/diskio.c b/source/fatfs/diskio.c index 59719e9..da5cf1b 100644 --- a/source/fatfs/diskio.c +++ b/source/fatfs/diskio.c @@ -78,9 +78,10 @@ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { - mode_n3ds = (GetUnitPlatform() == PLATFORM_N3DS); - sdmmc_sdcard_init(); // multiple inits should not be required (also, below) - InitNandCrypto(); + if (pdrv == 0) { // a mounted SD card is the preriquisite for everything else + mode_n3ds = (GetUnitPlatform() == PLATFORM_N3DS); + sdmmc_sdcard_init(); + } return RES_OK; } diff --git a/source/fs.c b/source/fs.c index d613288..3ebb205 100644 --- a/source/fs.c +++ b/source/fs.c @@ -2,6 +2,9 @@ #include "fs.h" #include "fatfs/ff.h" +#define MAX_FS 7 + + // don't use this area for anything else! static FATFS* fs = (FATFS*)0x20316000; @@ -14,35 +17,37 @@ static size_t main_buffer_size = 1 * 1024 * 1024; static u32 write_permission_level = 1; // number of currently open file systems -static u32 numfs = 0; +static bool fs_mounted[MAX_FS] = { false }; -bool InitFS() { +bool InitSDCardFS() { #ifndef EXEC_GATEWAY // TODO: Magic? *(u32*)0x10000020 = 0; *(u32*)0x10000020 = 0x340; #endif - for (numfs = 0; numfs < 7; numfs++) { + fs_mounted[0] = (f_mount(fs, "0:", 1) == FR_OK); + return fs_mounted[0]; +} + +bool InitNandFS() { + for (u32 i = 1; i < MAX_FS; i++) { char fsname[8]; - snprintf(fsname, 7, "%lu:", numfs); - int res = f_mount(fs + numfs, fsname, 1); - if (res != FR_OK) { - if (numfs >= 1) break; - ShowPrompt(false, "Initialising failed! (%lu/%s/%i)", numfs, fsname, res); - DeinitFS(); - return false; - } + snprintf(fsname, 7, "%lu:", i); + if (f_mount(fs + i, fsname, 1) != FR_OK) return false; + fs_mounted[i] = true; } return true; } void DeinitFS() { - for (u32 i = 0; i < numfs; i++) { - char fsname[8]; - snprintf(fsname, 7, "%lu:", numfs); - f_mount(NULL, fsname, 1); + for (u32 i = 0; i < MAX_FS; i++) { + if (fs_mounted[i]) { + char fsname[8]; + snprintf(fsname, 7, "%lu:", i); + f_mount(NULL, fsname, 1); + fs_mounted[i] = false; + } } - numfs = 0; } bool CheckWritePermissions(const char* path) { @@ -103,17 +108,29 @@ u32 GetWritePermissions() { return write_permission_level; } -bool FileCreate(const char* path, u8* data, u32 size) { +bool FileCreateData(const char* path, u8* data, size_t size) { FIL file; UINT bytes_written = 0; if (!CheckWritePermissions(path)) return false; - if (f_open(&file, path, FA_READ | FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) + if (f_open(&file, path, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) return false; f_write(&file, data, size, &bytes_written); f_close(&file); return (bytes_written == size); } +bool FileGetData(const char* path, u8* data, size_t size, size_t foffset) +{ + FIL file; + UINT bytes_read = 0; + if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) + return false; + f_lseek(&file, foffset); + f_read(&file, data, size, &bytes_read); + f_close(&file); + return (bytes_read == size); +} + bool PathCopyWorker(char* dest, char* orig, bool overwrite) { FILINFO fno = {.lfname = NULL}; bool ret = false; @@ -292,7 +309,7 @@ void CreateScreenshot() { for (u32 x = 0; x < 320; x++) for (u32 y = 0; y < 240; y++) memcpy(buffer + (y*400 + x + 40) * 3, BOT_SCREEN0 + (x*240 + y) * 3, 3); - FileCreate(filename, main_buffer, 54 + (400 * 240 * 3 * 2)); + FileCreateData(filename, main_buffer, 54 + (400 * 240 * 3 * 2)); } void DirEntryCpy(DirEntry* dest, const DirEntry* orig) { @@ -330,17 +347,20 @@ bool GetRootDirContentsWorker(DirStruct* contents) { "SYSNAND CTRNAND", "SYSNAND TWLN", "SYSNAND TWLP", "EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP" }; + u32 n_entries = 0; - for (u32 pdrv = 0; (pdrv < numfs) && (pdrv < MAX_ENTRIES); pdrv++) { - memset(contents->entry[pdrv].path, 0x00, 16); - snprintf(contents->entry[pdrv].path + 0, 4, "%lu:", pdrv); - snprintf(contents->entry[pdrv].path + 4, 32, "[%lu:] %s", pdrv, drvname[pdrv]); - contents->entry[pdrv].name = contents->entry[pdrv].path + 4; - contents->entry[pdrv].size = GetTotalSpace(contents->entry[pdrv].path); - contents->entry[pdrv].type = T_VRT_ROOT; - contents->entry[pdrv].marked = 0; + for (u32 pdrv = 0; (pdrv < MAX_FS) && (pdrv < MAX_ENTRIES); pdrv++) { + if (!fs_mounted[pdrv]) continue; + memset(contents->entry[n_entries].path, 0x00, 16); + snprintf(contents->entry[n_entries].path + 0, 4, "%lu:", pdrv); + snprintf(contents->entry[n_entries].path + 4, 32, "[%lu:] %s", pdrv, drvname[pdrv]); + contents->entry[n_entries].name = contents->entry[n_entries].path + 4; + contents->entry[n_entries].size = GetTotalSpace(contents->entry[n_entries].path); + contents->entry[n_entries].type = T_VRT_ROOT; + contents->entry[n_entries].marked = 0; + n_entries++; } - contents->n_entries = numfs; + contents->n_entries = n_entries; return contents->n_entries; } diff --git a/source/fs.h b/source/fs.h index 3f3aa55..1e9bc86 100644 --- a/source/fs.h +++ b/source/fs.h @@ -24,7 +24,8 @@ typedef struct { DirEntry entry[MAX_ENTRIES]; } DirStruct; -bool InitFS(); +bool InitSDCardFS(); +bool InitNandFS(); void DeinitFS(); /** Check if writing to this path is allowed **/ @@ -37,7 +38,10 @@ bool SetWritePermissions(u32 level); u32 GetWritePermissions(); /** Create / overwrite file and write the provided data to it **/ -bool FileCreate(const char* path, u8* data, u32 size); +bool FileCreateData(const char* path, u8* data, size_t size); + +/** Read data from file@offset **/ +bool FileGetData(const char* path, u8* data, size_t size, size_t foffset); /** Recursively copy a file or directory **/ bool PathCopy(const char* destdir, const char* orig); diff --git a/source/godmode.c b/source/godmode.c index 85b396f..597bd7b 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -2,6 +2,7 @@ #include "draw.h" #include "hid.h" #include "fs.h" +#include "nand.h" #define COLOR_TOP_BAR ((GetWritePermissions() == 0) ? COLOR_WHITE : (GetWritePermissions() == 1) ? COLOR_BRIGHTGREEN : (GetWritePermissions() == 2) ? COLOR_BRIGHTYELLOW : COLOR_RED) #define COLOR_SIDE_BAR COLOR_DARKGREY @@ -138,11 +139,16 @@ u32 GodMode() { u32 cursor = 0; ClearScreenF(true, true, COLOR_STD_BG); - if (!InitFS()) return exit_mode; + if (!InitSDCardFS()) { + ShowPrompt(false, "Initialising SD card failed!"); + return exit_mode; + } + InitNandCrypto(); + InitNandFS(); GetDirContents(current_dir, ""); clipboard->n_entries = 0; - while (true) { // this is the main loop !!! EMPTY DIRS + while (true) { // this is the main loop DrawUserInterface(current_path, &(current_dir->entry[cursor]), clipboard); DrawDirContents(current_dir, cursor); u32 pad_state = InputWait(); diff --git a/source/nand/aes.c b/source/nand/aes.c index 9991f37..725fe40 100644 --- a/source/nand/aes.c +++ b/source/nand/aes.c @@ -5,30 +5,57 @@ void setup_aeskeyX(u8 keyslot, void* keyx) { u32 * _keyx = (u32*)keyx; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; - *REG_AESKEYXFIFO = _keyx[0]; - *REG_AESKEYXFIFO = _keyx[1]; - *REG_AESKEYXFIFO = _keyx[2]; - *REG_AESKEYXFIFO = _keyx[3]; + if (keyslot > 3) { + *REG_AESKEYXFIFO = _keyx[0]; + *REG_AESKEYXFIFO = _keyx[1]; + *REG_AESKEYXFIFO = _keyx[2]; + *REG_AESKEYXFIFO = _keyx[3]; + } else { + u32 old_aescnt = *REG_AESCNT; + vu32* reg_aeskeyx = REG_AESKEY0123 + (((0x30*keyslot) + 0x10)/4); + *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); + for (u32 i = 0; i < 4; i++) + reg_aeskeyx[i] = _keyx[i]; + *REG_AESCNT = old_aescnt; + } } void setup_aeskeyY(u8 keyslot, void* keyy) { u32 * _keyy = (u32*)keyy; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; - *REG_AESKEYYFIFO = _keyy[0]; - *REG_AESKEYYFIFO = _keyy[1]; - *REG_AESKEYYFIFO = _keyy[2]; - *REG_AESKEYYFIFO = _keyy[3]; + if (keyslot > 3) { + *REG_AESKEYYFIFO = _keyy[0]; + *REG_AESKEYYFIFO = _keyy[1]; + *REG_AESKEYYFIFO = _keyy[2]; + *REG_AESKEYYFIFO = _keyy[3]; + } else { + u32 old_aescnt = *REG_AESCNT; + vu32* reg_aeskeyy = REG_AESKEY0123 + (((0x30*keyslot) + 0x20)/4); + *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); + for (u32 i = 0; i < 4; i++) + reg_aeskeyy[i] = _keyy[i]; + *REG_AESCNT = old_aescnt; + } } void setup_aeskey(u8 keyslot, void* key) { u32 * _key = (u32*)key; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; - *REG_AESKEYFIFO = _key[0]; - *REG_AESKEYFIFO = _key[1]; - *REG_AESKEYFIFO = _key[2]; - *REG_AESKEYFIFO = _key[3]; + if (keyslot > 3) { + *REG_AESKEYFIFO = _key[0]; + *REG_AESKEYFIFO = _key[1]; + *REG_AESKEYFIFO = _key[2]; + *REG_AESKEYFIFO = _key[3]; + } else { + u32 old_aescnt = *REG_AESCNT; + vu32* reg_aeskey = REG_AESKEY0123 + ((0x30*keyslot)/4); + *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); + for (u32 i = 0; i < 4; i++) + reg_aeskey[i] = _key[i]; + *REG_AESCNT = old_aescnt; + } } void use_aeskey(u32 keyno) diff --git a/source/nand/aes.h b/source/nand/aes.h index aa0f356..fae9ecf 100644 --- a/source/nand/aes.h +++ b/source/nand/aes.h @@ -22,6 +22,8 @@ #define REG_AESKEYFIFO ((volatile u32*)0x10009100) #define REG_AESKEYXFIFO ((volatile u32*)0x10009104) #define REG_AESKEYYFIFO ((volatile u32*)0x10009108) +// see https://www.3dbrew.org/wiki/AES_Registers#AES_KEY0.2F1.2F2.2F3 +#define REG_AESKEY0123 ((volatile u32*)0x10009040) #define AES_CNT_START 0x80000000 #define AES_CNT_INPUT_ORDER 0x02000000 diff --git a/source/nand/nand.c b/source/nand/nand.c index b4ddb10..e359187 100644 --- a/source/nand/nand.c +++ b/source/nand/nand.c @@ -33,9 +33,40 @@ bool InitNandCrypto(void) for(u32 i = 0; i < 16; i++) // little endian and reversed order TwlNandCtr[i] = shasum[15-i]; - // STEP #2: Calculate slot 0x3 key, set it up to slot 0x11 + // part #2: TWL KEY + // see: https://www.3dbrew.org/wiki/Memory_layout#ARM9_ITCM + u32* TwlCustId = (u32*) (0x01FFB808); + u8 TwlKeyX[16]; + u8 TwlKeyY[16]; + // thanks b1l1s & Normmatt + // see source from https://gbatemp.net/threads/release-twltool-dsi-downgrading-save-injection-etc-multitool.393488/ + const char* nintendo = "NINTENDO"; + u32* TwlKeyXW = (u32*) TwlKeyX; + TwlKeyXW[0] = (TwlCustId[0] ^ 0xB358A6AF) | 0x80000000; + TwlKeyXW[3] = TwlCustId[1] ^ 0x08C267B7; + memcpy(TwlKeyX + 4, nintendo, 8); + + // see: https://www.3dbrew.org/wiki/Memory_layout#ARM9_ITCM + u32 TwlKeyYW3 = 0xE1A00005; + memcpy(TwlKeyY, (u8*) 0x01FFD3C8, 12); + memcpy(TwlKeyY + 12, &TwlKeyYW3, 4); + + setup_aeskeyX(0x03, TwlKeyX); + setup_aeskeyY(0x03, TwlKeyY); + use_aeskey(0x03); + + // part #3: CTRNAND N3DS KEY + if (GetUnitPlatform() == PLATFORM_N3DS) { + u8 CtrNandKeyY[16]; + if (FileGetData("0:/slot0x05KeyY.bin", CtrNandKeyY, 16, 0)) { + setup_aeskeyY(0x05, CtrNandKeyY); + use_aeskey(0x05); + } + } + + return true; }