Refactored vmem.c, added support for reading MCU

This commit is contained in:
Myria 2017-08-25 14:00:30 +02:00 committed by d0k3
parent 3407b3d5da
commit ff7b9749ad

View File

@ -2,7 +2,10 @@
#include "unittype.h"
#include "sha.h"
#include "aes.h"
#include "itcm.h"
#include "i2c.h"
#define VFLAG_CALLBACK (1UL<<27)
#define VFLAG_BOOT9 (1UL<<28)
#define VFLAG_BOOT11 (1UL<<29)
#define VFLAG_OTP (1UL<<30)
@ -14,6 +17,10 @@
#define BOOT9_LEN 0x00010000
#define BOOT11_LEN 0x00010000
// checks for boot9 / boot11
#define HAS_BOOT9 (sha_cmp(boot9_sha256, (u8*) BOOT9_POS, BOOT9_LEN, SHA256_MODE) == 0)
#define HAS_BOOT11 (sha_cmp(boot11_sha256, (u8*) BOOT11_POS, BOOT11_LEN, SHA256_MODE) == 0)
// see: https://www.youtube.com/watch?v=wogNzUypLuI
u8 boot9_sha256[0x20] = {
0x2F, 0x88, 0x74, 0x4F, 0xEE, 0xD7, 0x17, 0x85, 0x63, 0x86, 0x40, 0x0A, 0x44, 0xBB, 0xA4, 0xB9,
@ -27,24 +34,49 @@ u8 boot11_sha256[0x20] = {
// see: https://github.com/SciresM/CTRAesEngine/blob/8312adc74b911a6b9cb9e03982ba3768b8e2e69c/CTRAesEngine/AesEngine.cs#L672-L688
#define OTP_KEY ((u8*) BOOT9_POS + ((IS_DEVKIT) ? + 0xD700 : 0xD6E0))
#define OTP_IV (OTP_KEY + 0x10)
#define OTP_POS 0x10012000
#define OTP_LEN sizeof(Otp)
// Custom read/write handlers.
typedef int ReadVMemFileCallback(const VirtualFile* vfile, void* buffer, u64 offset, u64 count);
enum VMemCallbackType {
VMEM_CALLBACK_OTP_DECRYPTED,
VMEM_CALLBACK_MCU_REGISTERS,
VMEM_NUM_CALLBACKS
};
ReadVMemFileCallback ReadVMemOTPDecrypted;
ReadVMemFileCallback ReadVMemMCURegisters;
static ReadVMemFileCallback* const vMemCallbacks[] = {
ReadVMemOTPDecrypted,
ReadVMemMCURegisters,
};
STATIC_ASSERT(sizeof(vMemCallbacks) / sizeof(vMemCallbacks[0]) == VMEM_NUM_CALLBACKS);
// see: http://3dbrew.org/wiki/Memory_layout#ARM9
static const VirtualFile vMemFileTemplates[] = {
{ "itcm.mem" , 0x01FF8000, 0x00008000, 0xFF, 0 },
{ "arm9.mem" , 0x08000000, 0x00100000, 0xFF, 0 },
{ "arm9ext.mem" , 0x08100000, 0x00080000, 0xFF, VFLAG_N3DS_ONLY },
{ "boot9.bin" , BOOT9_POS , BOOT9_LEN , 0xFF, VFLAG_BOOT9 },
{ "boot11.bin" , BOOT11_POS, BOOT11_LEN, 0xFF, VFLAG_BOOT11 },
{ "boot9.bin" , BOOT9_POS , BOOT9_LEN , 0xFF, VFLAG_READONLY | VFLAG_BOOT9 },
{ "boot11.bin" , BOOT11_POS, BOOT11_LEN, 0xFF, VFLAG_READONLY | VFLAG_BOOT11 },
{ "vram.mem" , 0x18000000, 0x00600000, 0xFF, 0 },
{ "dsp.mem" , 0x1FF00000, 0x00080000, 0xFF, 0 },
{ "axiwram.mem" , 0x1FF80000, 0x00080000, 0xFF, 0 },
{ "fcram.mem" , 0x20000000, 0x08000000, 0xFF, 0 },
{ "fcramext.mem" , 0x28000000, 0x08000000, 0xFF, VFLAG_N3DS_ONLY },
{ "dtcm.mem" , 0x30008000, 0x00004000, 0xFF, 0 },
{ "otp.mem" , 0x10012000, 0x00000100, 0xFF, VFLAG_OTP },
{ "otp_dec.mem" , 0x10012000, 0x00000100, 0x11, VFLAG_OTP | VFLAG_BOOT9 },
{ "otp.mem" , OTP_POS , OTP_LEN , 0xFF, VFLAG_READONLY | VFLAG_OTP },
// { "bootrom.mem" , 0xFFFF0000, 0x00010000, 0xFF, 0 },
// { "bootrom_unp.mem" , 0xFFFF0000, 0x00008000, 0xFF, 0 }
// Custom callback implementations.
// Keyslot field has arbitrary meaning, and may not actually be a keyslot.
{ "otp_dec.mem" , VMEM_CALLBACK_OTP_DECRYPTED, OTP_LEN , 0x11, VFLAG_CALLBACK | VFLAG_READONLY | VFLAG_OTP | VFLAG_BOOT9 },
{ "mcu_3ds_regs.bin" , VMEM_CALLBACK_MCU_REGISTERS, 0x00000100, I2C_DEV_MCU, VFLAG_CALLBACK | VFLAG_READONLY },
{ "mcu_dsi_regs.bin" , VMEM_CALLBACK_MCU_REGISTERS, 0x00000100, I2C_DEV_POWER, VFLAG_CALLBACK | VFLAG_READONLY },
};
bool ReadVMemDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir object generated in virtual.c
@ -58,8 +90,8 @@ bool ReadVMemDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir
// process special flags
if (((vfile->flags & VFLAG_N3DS_ONLY) && (IS_O3DS)) || // this is not on O3DS consoles
((vfile->flags & VFLAG_OTP) && !(IS_UNLOCKED)) || // OTP still locked
((vfile->flags & VFLAG_BOOT9) && (sha_cmp(boot9_sha256, (u8*) BOOT9_POS, BOOT9_LEN, SHA256_MODE) != 0)) || // boot9 not found
((vfile->flags & VFLAG_BOOT11) && (sha_cmp(boot11_sha256, (u8*) BOOT11_POS, BOOT11_LEN, SHA256_MODE) != 0))) // boot11 not found
((vfile->flags & VFLAG_BOOT9) && !(HAS_BOOT9)) || // boot9 not found
((vfile->flags & VFLAG_BOOT11) && !(HAS_BOOT11))) // boot11 not found
continue;
// found if arriving here
@ -69,29 +101,52 @@ bool ReadVMemDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir
return false;
}
int ReadVMemFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
if ((vfile->flags & VFLAG_OTP) && (vfile->keyslot == 0x11)) {
u8 __attribute__((aligned(32))) otp_local[vfile->size];
u8 __attribute__((aligned(32))) otp_iv[0x10];
u8* otp_mem = (u8*) (u32) vfile->offset;
memcpy(otp_iv, OTP_IV, 0x10);
setup_aeskey(0x11, OTP_KEY);
use_aeskey(0x11);
cbc_decrypt(otp_mem, otp_local, vfile->size / 0x10, AES_CNT_TITLEKEY_DECRYPT_MODE, otp_iv);
memcpy(buffer, otp_local + offset, count);
} else {
u32 foffset = vfile->offset + offset;
memcpy(buffer, (u8*) foffset, count);
}
// Read decrypted OTP.
int ReadVMemOTPDecrypted(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
(void) vfile;
alignas(32) u8 otp_local[OTP_LEN];
alignas(32) u8 otp_iv[0x10];
u8* otp_mem = (u8*) OTP_POS;
memcpy(otp_iv, OTP_IV, 0x10);
setup_aeskey(0x11, OTP_KEY);
use_aeskey(0x11);
cbc_decrypt(otp_mem, otp_local, OTP_LEN / 0x10, AES_CNT_TITLEKEY_DECRYPT_MODE, otp_iv);
memcpy(buffer, otp_local + offset, count);
return 0;
}
// Read MCU registers.
int ReadVMemMCURegisters(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
// While it is possible to write MCU registers, that's a good way to
// brick your system in a way that even ntrboothax can't fix.
// The table puts the device ID into the keyslot field.
u8 device = (u8) vfile->keyslot;
// Read the data.
u8* dest = (u8*) buffer;
return (I2C_readRegBuf(device, (u8) offset, dest, (u32) count)) ? 0 : 1;
}
int ReadVMemFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
if (vfile->flags & VFLAG_CALLBACK) {
if ((offset + count > vfile->size) || (0u + offset + count < offset))
return 1;
return vMemCallbacks[vfile->offset](vfile, buffer, offset, count);
} else {
u32 foffset = vfile->offset + offset;
memcpy(buffer, (u8*) foffset, count);
return 0;
}
}
int WriteVMemFile(const VirtualFile* vfile, const void* buffer, u64 offset, u64 count) {
if (vfile->flags & (VFLAG_OTP|VFLAG_BOOT9|VFLAG_BOOT11)) {
if (vfile->flags & (VFLAG_READONLY|VFLAG_CALLBACK)) {
return 1; // not writable / writes blocked
} else {
u32 foffset = vfile->offset + offset;
memcpy((u8*) foffset, buffer, count);
return 0;
}
return 0;
}