Compare commits

...

19 Commits

Author SHA1 Message Date
Aurora
4bdba9f8e9 Even moar clean-up 2016-03-06 16:31:16 +01:00
Aurora
99829b3cf7 (Hopefully last) clean-up 2016-03-06 05:04:28 +01:00
Aurora
d4a3ce2d0d Clean-up of the filesystem functions 2016-03-05 23:33:11 +01:00
Aurora
a58cb05f2c Previous release broke .dat booting from a 9.0 NAND if A9LH was installed
Also, more clean-up
2016-03-05 20:22:31 +01:00
Aurora
9ab6d107b4 Not needed 2016-03-05 18:47:47 +01:00
Aurora
42cbead456 Remove redundancies 2016-03-05 16:16:25 +01:00
Aurora
90ebe78c8e Added forcing of boot options on A9LH
Always prevents losing AGB_FIRM saves, forces the last used options on a MCU reboot (can be overridden with A)
2016-03-05 15:42:40 +01:00
Aurora
bf81ec252e Even more clean-up 2016-03-05 00:56:35 +01:00
Aurora
899ad1887a Some clean-up 2016-03-05 00:41:42 +01:00
Aurora
cb06cf83ff Added flag to use a pre-patched FIRM (skips all decrypting and patching)
Original patch by @Fix94
2016-03-05 00:01:54 +01:00
Aurora
aede5a5331 Not needed 2016-03-02 04:33:20 +01:00
Aurora
5a41663ddc Minor splash fixes 2016-03-02 00:49:14 +01:00
Aurora
7f6ef45f37 Avoid overflows with menuhax generated splashes 2016-02-29 17:01:16 +01:00
Aurora
32e2b85f3a Get up-to-date with official build 2016-02-29 16:28:43 +01:00
Aurora
6fe748f58c Not needed 2016-02-28 16:20:06 +01:00
Aurora
e74eda16ce Fixed reboot patch on N3DS
Yay, 178 MB content!
2016-02-26 02:48:42 +01:00
Aurora
eea2076123 This is not needed anymore 2016-02-25 20:38:31 +01:00
Aurora
23fd26630f New reboot patch (works on N3DS, no more GBA/DS or 80 MB games toggle), fixed N3DS 3D bug (thanks TiniVi and Cakes), code cleanup, new universal MPU code (thanks Cakes)
Thanks to a very skilled reverser for the reboot patch!
2016-02-25 20:22:10 +01:00
Aurora
e53c186144 Prep work for A9LH screen init 2016-02-24 20:35:15 +01:00
21 changed files with 584 additions and 792 deletions

View File

@@ -33,7 +33,7 @@ objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
.PHONY: all
all: launcher a9lh emunand emunando3ds reboot rebootntr ninjhax
all: launcher a9lh emunand reboot ninjhax
.PHONY: launcher
launcher: $(dir_out)/$(name).dat
@@ -42,16 +42,10 @@ launcher: $(dir_out)/$(name).dat
a9lh: $(dir_out)/arm9loaderhax.bin
.PHONY: emunand
emunand: $(dir_out)/rei-n3ds/emunand/emunand.bin
.PHONY: emunando3ds
emunando3ds: $(dir_out)/rei-o3ds/emunand/emunand.bin
emunand: $(dir_out)/rei/emunand/emunand.bin
.PHONY: reboot
reboot: $(dir_out)/rei-o3ds/reboot/reboot1.bin $(dir_out)/rei-o3ds/reboot/reboot2.bin
.PHONY: rebootntr
rebootntr: $(dir_out)/ntr-o3ds/reboot/reboot1.bin $(dir_out)/ntr-o3ds/reboot/reboot2.bin
reboot: $(dir_out)/rei/reboot/reboot.bin
.PHONY: ninjhax
ninjhax: $(dir_out)/3ds/$(name)
@@ -62,11 +56,11 @@ clean:
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
rm -rf $(dir_out) $(dir_build)
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)/rei-n3ds/ $(dir_out)/rei-o3ds/
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)/rei
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)/rei-n3ds/ $(dir_out)/rei-o3ds/
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)/rei
@cp -av $(dir_build)/main.bin $(dir_out)/arm9loaderhax.bin
$(dir_out)/3ds/$(name):
@@ -75,36 +69,18 @@ $(dir_out)/3ds/$(name):
@mv $(dir_out)/$(name).3dsx $@
@mv $(dir_out)/$(name).smdh $@
$(dir_out)/rei-n3ds/:
@mkdir -p "$(dir_out)/rei-n3ds"
$(dir_out)/rei:
@mkdir -p "$(dir_out)/rei"
$(dir_out)/rei-o3ds/:
@mkdir -p "$(dir_out)/rei-o3ds"
$(dir_out)/rei-n3ds/emunand/emunand.bin: $(dir_emu)/emuCode.s
$(dir_out)/rei/emunand/emunand.bin: $(dir_emu)/emuCode.s
@armips $<
@mkdir -p "$(dir_out)/rei-n3ds/emunand"
@cp -av emunand.bin $(dir_out)/rei-n3ds/emunand
@mkdir -p "$(dir_out)/rei/emunand"
@mv emunand.bin $(dir_out)/rei/emunand
$(dir_out)/rei-o3ds/emunand/emunand.bin: emunand.bin
@mkdir -p "$(dir_out)/rei-o3ds/emunand"
@mv emunand.bin $(dir_out)/rei-o3ds/emunand
$(dir_out)/rei-o3ds/reboot/reboot1.bin: $(dir_reboot)/rebootCode.s
$(dir_out)/rei/reboot/reboot.bin: $(dir_reboot)/rebootCode.s
@armips $<
@mkdir -p "$(dir_out)/rei-o3ds/reboot"
@mv reboot1.bin $(dir_out)/rei-o3ds/reboot
$(dir_out)/rei-o3ds/reboot/reboot2.bin: reboot2.bin
@cp -av reboot2.bin $(dir_out)/rei-o3ds/reboot
$(dir_out)/ntr-o3ds/reboot/reboot1.bin: $(dir_reboot)/rebootCodeNtr.s
@armips $<
@mkdir -p "$(dir_out)/ntr-o3ds/reboot"
@mv reboot1.bin $(dir_out)/ntr-o3ds/reboot
$(dir_out)/ntr-o3ds/reboot/reboot2.bin: reboot2.bin
@mv reboot2.bin $(dir_out)/ntr-o3ds/reboot
@mkdir -p "$(dir_out)/rei/reboot"
@mv reboot.bin $(dir_out)/rei/reboot
$(dir_build)/main.bin: $(dir_build)/main.elf
$(OC) -S -O binary $< $@

View File

@@ -1,159 +1,221 @@
.nds
.create "reboot.bin", 0
firm_size equ 0x000EA000
firm_addr equ 0x24000000
fopen equ 0x08059D10
fread equ 0x0804CC54
pxi_wait_recv equ 0x08054134
byteswritten equ 0x2000E000
externalFirm equ 0x2000A000
kernelCode equ 0x080F0000
buffer equ 0x24000000
fileOpen equ 0x4E45504F ;dummy
.macro svc, num
.if isArm()
.word 0xEF000000 | num
.else
.if num > 0xFF
.error "bitch you crazu"
.endif
.halfword 0xDF00 | num
.endif
.endmacro
.create "reboot1.bin", 0x080849DC
.org 0x080849DC
.arm
patch005:
ldr r0, =0x2000E000
mov r1, #0x200
mov r2, #0
add r1, r1, r0
@@memset_loop:
str r2, [r0]
add r0, r0, #4
cmp r0, r1
blt @@memset_loop
ldr r0, =0x2000E000
ldr r1, =firm_fname
mov r2, #1
blx fopen
ldr r0, =0x2000E000
ldr r1, =0x2000E100
mov r2, #firm_addr
mov r3, #firm_size
blx fread
//Code jumps here right after the sprintf call
process9Reboot:
doPxi:
ldr r4, =0x44846
ldr r0, =0x10008000
readPxiLoop1:
ldrh r1, [r0,#4]
.word 0xE1B01B81 //lsls r1, r1, #0x17
bmi readPxiLoop1
ldr r0, [r0,#0xC]
cmp r0, r4
bne doPxi
GetFirmPath:
add r0, sp, #0x3A8-0x70+0x24
ldr r1, [r0], #4
ldr r2, =0x00300030
cmp r1, r2
ldreq r1, [r0], #4
ldreq r2, =0x002F0032
cmpeq r1, r2
OpenFirm:
ldreq r1, =(FileName - OpenFirm - 12)
addeq r1, pc
addne r1, sp, #0x3A8-0x70
ldr r0, =externalFirm
moveq r2, #1
movne r2, #0
str r2, [r0]
mov r2, #1
add r0, r7, #8
ldr r6, =fileOpen
blx r6
SeekFirm:
ldr r0, =externalFirm
ldr r0, [r0]
cmp r0, #1
moveq r0, r7
ldreq r1, =byteswritten
ldreq r2, =buffer
ldreq r3, =0x0
ldreq r6, [sp,#0x3A8-0x198]
ldreq r6, [r6,#0x28] //fread function stored here
blxeq r6
ReadFirm:
mov r0, r7
ldr r1, =byteswritten
ldr r2, =buffer
ldr r3, =0x200000
ldr r6, [sp,#0x3A8-0x198]
ldr r6, [r6,#0x28] //fread function stored here
blx r6
ldr r4, =0x44846
blx pxi_wait_recv
cmp r0, r4
bne patch005
mov r2, #0
mov r3, r2
mov r1, r2
mov r0, r2
svc 0x7C
ldr r0, =0x80FF4FC
svc 0x7B
KernelSetState:
mov r2, #0
mov r3, r2
mov r1, r2
mov r0, r2
.word 0xEF00007C //SVC 0x7C
GoToReboot:
ldr r0, =(KernelCodeStart - GoToReboot - 12)
add r0, pc
ldr r1, =kernelCode
ldr r2, =0x300
bl Memcpy
ldr r0, =kernelCode
.word 0xEF00007B //SVC 0x7B
InfiniteLoop:
b InfiniteLoop
Memcpy:
MOV R12, LR
STMFD SP!, {R0-R4}
ADD R2, R2, R0
memcpyLoop:
LDR R3, [R0],#4
STR R3, [R1],#4
CMP R0, R2
BLT memcpyLoop
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
FileName:
.dcw "sdmc:/rei/patched_firmware_sys.bin"
.word 0x0
@@inf_loop:
b @@inf_loop
.pool
firm_fname:
.close
.create "reboot2.bin", 0x080933CC
.org 0x080933CC
.arm
stmfd sp!, {r4-r11,lr}
sub sp, sp, #0x3C
mrc p15, 0, r0, c2, c0, 0 ; dcacheable
mrc p15, 0, r12, c2, c0, 1 ; icacheable
mrc p15, 0, r1, c3, c0, 0 ; write bufferable
mrc p15, 0, r2, c5, c0, 2 ; daccess
mrc p15, 0, r3, c5, c0, 3 ; iaccess
ldr r4, =0x18000035 ; 0x18000000 128M
bic r2, r2, #0xF0000 ; unprotect region 4
bic r3, r3, #0xF0000 ; unprotect region 4
orr r0, r0, #0x10 ; dcacheable region 4
orr r2, r2, #0x30000 ; region 4 r/w
orr r3, r3, #0x30000 ; region 4 r/w
orr r12, r12, #0x10 ; icacheable region 4
orr r1, r1, #0x10 ; write bufferable region 4
mcr p15, 0, r0, c2, c0, 0
mcr p15, 0, r12, c2, c0, 1
mcr p15, 0, r1, c3, c0, 0 ; write bufferable
mcr p15, 0, r2, c5, c0, 2 ; daccess
mcr p15, 0, r3, c5, c0, 3 ; iaccess
mcr p15, 0, r4, c6, c4, 0 ; region 4 (hmmm)
mrc p15, 0, r0, c2, c0, 0 ; dcacheable
mrc p15, 0, r1, c2, c0, 1 ; icacheable
mrc p15, 0, r2, c3, c0, 0 ; write bufferable
orr r0, r0, #0x20 ; dcacheable region 5
orr r1, r1, #0x20 ; icacheable region 5
orr r2, r2, #0x20 ; write bufferable region 5
mcr p15, 0, r0, c2, c0, 0 ; dcacheable
mcr p15, 0, r1, c2, c0, 1 ; icacheable
mcr p15, 0, r2, c3, c0, 0 ; write bufferable
mov r4, #firm_addr
add r3, r4, #0x40
ldr r0, [r3] ; offset
add r0, r0, r4 ; src
ldr r1, [r3,#4] ; dst
ldr r2, [r3,#8] ; size
bl memcpy32
add r3, r4, #0x70
ldr r0, [r3]
add r0, r0, r4 ; src
ldr r1, [r3,#4] ; dst
ldr r2, [r3,#8] ; size
bl memcpy32
add r3, r4, #0xA0
ldr r0, [r3]
add r0, r0, r4 ; src
ldr r1, [r3,#4] ; dst
ldr r2, [r3,#8] ; size
bl memcpy32
mov r2, #0
mov r1, r2
@flush_cache:
mov r0, #0
mov r3, r2, lsl#30
@flush_cache_inner_loop:
orr r12, r3, r0, lsl#5
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
mcr p15, 0, r12, c7, c14, 2 ; clean and flush dcache entry (index and segment)
add r0, r0, #1
cmp r0, #0x20
bcc @flush_cache_inner_loop
add r2, r2, #1
cmp r2, #4
bcc @flush_cache
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
@mpu_enable:
ldr r0, =0x42078 ; alt vector select, enable itcm
mcr p15, 0, r0, c1, c0, 0
mcr p15, 0, r1, c7, c5, 0 ; flush dcache
mcr p15, 0, r1, c7, c6, 0 ; flush icache
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
mov r0, #firm_addr
mov r1, 0X1FFFFFFC
ldr r2, [r0,#8] ; arm11 entry
str r2, [r1]
ldr r0, [r0,#0xC] ; arm9 entry
add sp, sp, #0x3C
ldmfd sp!, {r4-r11,lr}
bx r0
.pool
memcpy32: ; memcpy32(void *src, void *dst, unsigned int size)
mov r12, lr
stmfd sp!, {r0-r4}
add r2, r2, r0
@memcpy_loop:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r0, r2
blt @memcpy_loop
ldmfd sp!, {r0-r4}
mov lr, r12
bx lr
.pool
// Kernel Code
.align 4
KernelCodeStart:
memorySetting:
MRC p15, 0, R0,c2,c0, 0
MRC p15, 0, R12,c2,c0, 1
MRC p15, 0, R1,c3,c0, 0
MRC p15, 0, R2,c5,c0, 2
MRC p15, 0, R3,c5,c0, 3
LDR R4, =0x18000035
BIC R2, R2, #0xF0000
BIC R3, R3, #0xF0000
ORR R0, R0, #0x10
ORR R2, R2, #0x30000
ORR R3, R3, #0x30000
ORR R12, R12, #0x10
ORR R1, R1, #0x10
MCR p15, 0, R0,c2,c0, 0
MCR p15, 0, R12,c2,c0, 1
MCR p15, 0, R1,c3,c0, 0
MCR p15, 0, R2,c5,c0, 2
MCR p15, 0, R3,c5,c0, 3
MCR p15, 0, R4,c6,c4, 0
MRC p15, 0, R0,c2,c0, 0
MRC p15, 0, R1,c2,c0, 1
MRC p15, 0, R2,c3,c0, 0
ORR R0, R0, #0x20
ORR R1, R1, #0x20
ORR R2, R2, #0x20
MCR p15, 0, R0,c2,c0, 0
MCR p15, 0, R1,c2,c0, 1
MCR p15, 0, R2,c3,c0, 0
copyFirmPartitions:
LDR R4, =buffer
ADD R3, R4, #0x40
LDR R0, [R3]
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
ADD R3, R4, #0x70
LDR R0, [R3]
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
ADD R3, R4, #0xA0
LDR R0, [R3]
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
ADD R3, R4, #0xD0
LDR R0, [R3]
CMP R0, #0
BEQ invalidateDataCache
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
invalidateDataCache:
MOV R2, #0
MOV R1, R2
loc_809460C:
MOV R0, #0
MOV R3, R2,LSL#30
loc_8094614:
ORR R12, R3, R0,LSL#5
MCR p15, 0, R1,c7,c10, 4
MCR p15, 0, R12,c7,c14, 2
ADD R0, R0, #1
CMP R0, #0x20
BCC loc_8094614
ADD R2, R2, #1
CMP R2, #4
BCC loc_809460C
jumpToEntrypoint:
MCR p15, 0, R1,c7,c10, 4
LDR R0, =0x42078
MCR p15, 0, R0,c1,c0, 0
MCR p15, 0, R1,c7,c5, 0
MCR p15, 0, R1,c7,c6, 0
MCR p15, 0, R1,c7,c10, 4
LDR R4, =buffer
MOV R1, #0x1FFFFFFC
LDR R2, [R4,#8]
STR R2, [R1]
LDR R0, [R4,#0xC]
BX R0
.pool
KernelMemcpy:
MOV R12, LR
STMFD SP!, {R0-R4}
ADD R2, R2, R0
kmemcpyLoop:
LDR R3, [R0],#4
STR R3, [R1],#4
CMP R0, R2
BLT kmemcpyLoop
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
.pool
KernelCodeEnd:
.close

View File

@@ -1,59 +0,0 @@
.nds
firm_size equ 0x000EB000
firm_addr equ 0x24000000
fopen equ 0x0805B180
fread equ 0x0804D9B0
pxi_wait_recv equ 0x08055178
.macro svc, num
.if isArm()
.word 0xEF000000 | num
.else
.if num > 0xFF
.error "bitch you crazu"
.endif
.halfword 0xDF00 | num
.endif
.endmacro
.create "reboot1.bin", 0x080859C8
.org 0x080859C8
.arm
patch005:
ldr r0, =0x2000E000
mov r1, #0x200
mov r2, #0
add r1, r1, r0
@@memset_loop:
str r2, [r0]
add r0, r0, #4
cmp r0, r1
blt @@memset_loop
ldr r0, =0x2000E000
ldr r1, =firm_fname
mov r2, #1
blx fopen
ldr r0, =0x2000E000
ldr r1, =0x2000E100
mov r2, #firm_addr
mov r3, #firm_size
blx fread
ldr r4, =0x44846
blx pxi_wait_recv
cmp r0, r4
bne patch005
mov r2, #0
mov r3, r2
mov r1, r2
mov r0, r2
svc 0x7C
ldr r0, =0x80FF4FC
svc 0x7B
@@inf_loop:
b @@inf_loop
.pool
firm_fname:
.close

View File

@@ -1,11 +1,8 @@
// From http://github.com/b1l1s/ctr
#include "crypto.h"
#include <stddef.h>
#include "memory.h"
#include "fatfs/sdmmc/sdmmc.h"
#include "fatfs/ff.h"
/****************************************************************
* Crypto Libs
@@ -226,147 +223,24 @@ void aes(void* dst, const void* src, u32 blockCount, void* iv, u32 mode, u32 ivM
}
}
void sha_wait_idle()
{
while(*REG_SHA_CNT & 1);
}
void sha(void* res, const void* src, u32 size, u32 mode)
{
sha_wait_idle();
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
const u32* src32 = (const u32*)src;
int i;
while(size >= 0x40)
{
sha_wait_idle();
for(i = 0; i < 4; ++i)
{
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
*REG_SHA_INFIFO = *src32++;
}
size -= 0x40;
}
sha_wait_idle();
memcpy((void*)REG_SHA_INFIFO, src32, size);
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
sha_wait_idle();
u32 hashSize = SHA_256_HASH_SIZE;
if(mode == SHA_224_MODE)
hashSize = SHA_224_HASH_SIZE;
else if(mode == SHA_1_MODE)
hashSize = SHA_1_HASH_SIZE;
memcpy(res, (void*)REG_SHA_HASH, hashSize);
}
void rsa_wait_idle()
{
while(*REG_RSA_CNT & 1);
}
void rsa_use_keyslot(u32 keyslot)
{
*REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4);
}
void rsa_setkey(u32 keyslot, const void* mod, const void* exp, u32 mode)
{
rsa_wait_idle();
*REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4) | RSA_IO_BE | RSA_IO_NORMAL;
u32 size = mode * 4;
volatile u32* keyslotCnt = REG_RSA_SLOT0 + (keyslot << 4);
keyslotCnt[0] &= ~(RSA_SLOTCNT_KEY_SET | RSA_SLOTCNT_WPROTECT);
keyslotCnt[1] = mode;
memcpy((void*)REG_RSA_MOD_END - size, mod, size);
if(exp == NULL)
{
size -= 4;
while(size)
{
*REG_RSA_EXPFIFO = 0;
size -= 4;
}
*REG_RSA_EXPFIFO = 0x01000100; // 0x00010001 byteswapped
}
else
{
const u32* exp32 = (const u32*)exp;
while(size)
{
*REG_RSA_EXPFIFO = *exp32++;
size -= 4;
}
}
}
int rsa_iskeyset(u32 keyslot)
{
return *(REG_RSA_SLOT0 + (keyslot << 4)) & 1;
}
void rsa(void* dst, const void* src, u32 size)
{
u32 keyslot = (*REG_RSA_CNT & RSA_CNT_KEYSLOTS) >> 4;
if(rsa_iskeyset(keyslot) == 0)
return;
rsa_wait_idle();
*REG_RSA_CNT |= RSA_IO_BE | RSA_IO_NORMAL;
// Pad the message with zeroes so that it's a multiple of 8
// and write the message with the end aligned with the register
u32 padSize = ((size + 7) & ~7) - size;
memset((void*)REG_RSA_TXT_END - (size + padSize), 0, padSize);
memcpy((void*)REG_RSA_TXT_END - size, src, size);
// Start
*REG_RSA_CNT |= RSA_CNT_START;
rsa_wait_idle();
memcpy(dst, (void*)REG_RSA_TXT_END - size, size);
}
int rsa_verify(const void* data, u32 size, const void* sig, u32 mode)
{
u8 dataHash[SHA_256_HASH_SIZE];
sha(dataHash, data, size, SHA_256_MODE);
u8 decSig[0x100]; // Way too big, need to request a work area
u32 sigSize = mode * 4;
rsa(decSig, sig, sigSize);
return memcmp(dataHash, decSig + (sigSize - SHA_256_HASH_SIZE), SHA_256_HASH_SIZE) == 0;
}
/****************************************************************
* Nand/FIRM Crypto stuff
****************************************************************/
//Nand key#2 (0x12C10)
u8 key2[0x10] = {
0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0
};
//Get Nand CTR key
void getNandCTR(u8 *buf, u8 console) {
u8 *addr = console ? (u8*)0x080D8BBC : (u8*)0x080D797C;
u8 keyLen = 0x10; //CTR length
addr += 0x0F;
while (keyLen --) { *(buf++) = *(addr--); }
void getNandCTR(u8 *buf, u8 console){
u8 *addr = (console ? (u8*)0x080D8BBC : (u8*)0x080D797C) + 0x0F;
for(u8 keyLen = 0x10; keyLen; keyLen--)
*(buf++) = *(addr--);
}
//Read firm0 from NAND and write to buffer
void nandFirm0(u8 *outbuf, const u32 size, u8 console){
void nandFirm0(u8 *outbuf, u32 size, u8 console){
u8 CTR[0x10];
getNandCTR(CTR, console);
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL);
@@ -375,48 +249,52 @@ void nandFirm0(u8 *outbuf, const u32 size, u8 console){
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
//Emulates the Arm9loader process
void arm9loader(void *armHdr, u8 mode){
//Nand key#2 (0x12C10)
u8 key2[0x10] = {
0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0
};
//Decrypts the N3DS arm9bin
void decArm9Bin(void *armHdr, u8 mode){
//Firm keys
u8 keyX[0x10];
u8 keyY[0x10];
u8 CTR[0x10];
u32 slot = mode ? 0x16 : 0x15;
u8 slot = mode ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption
memcpy((u8*)keyY, (void *)((uintptr_t)armHdr+0x10), 0x10);
memcpy((u8*)CTR, (void *)((uintptr_t)armHdr+0x20), 0x10);
u32 size = atoi((void *)((uintptr_t)armHdr+0x30));
memcpy(keyY, armHdr+0x10, 0x10);
memcpy(CTR, armHdr+0x20, 0x10);
u32 size = 0;
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
for(u8 *tmp = armHdr+0x30; *tmp; tmp++)
size = (size<<3)+(size<<1)+(*tmp)-'0';
if(mode){
u8 keyX[0x10];
//Set 0x11 to key2 for the arm9bin and misc keys
aes_setkey(0x11, (u8*)key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11);
aes((u8*)keyX, (void *)((uintptr_t)armHdr+0x60), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, (u8*)keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
aes(keyX, armHdr+0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
}
aes_setkey(slot, (u8*)keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv((u8*)CTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(slot);
//Decrypt arm9bin
aes((void *)(armHdr+0x800), (void *)(armHdr+0x800), size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
if(mode){
//Set keys 0x19..0x1F keyXs
u8* decKey = (void *)((uintptr_t)armHdr+0x89824);
aes_use_keyslot(0x11);
for(slot = 0x19; slot < 0x20; slot++) {
aes_setkey(0x11, (u8*)key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes(decKey, (void *)((uintptr_t)armHdr+0x89814), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, (u8*)decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
*(u8 *)((void *)((uintptr_t)armHdr+0x89814+0xF)) += 1;
}
//Decrypt arm9bin
aes(armHdr+0x800, armHdr+0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
//Sets the N3DS 9.6 KeyXs
void setKeyXs(void *armHdr){
void *keyData = armHdr+0x89814;
void *decKey = keyData+0x10;
//Set keys 0x19..0x1F keyXs
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++){
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
*(u8*)(keyData+0xF) += 1;
}
}

View File

@@ -1,21 +1,10 @@
// From http://github.com/b1l1s/ctr
#ifndef __CRYPTO_H
#define __CRYPTO_H
#ifndef CRYPTO_INC
#define CRYPTO_INC
#include <stdint.h>
#include "types.h"
#define FIRM_TYPE_ARM9 0
#define FIRM_TYPE_ARM11 1
#define MEDIA_UNITS 0x200
#define NCCH_MAGIC (0x4843434E)
#define NCSD_MAGIC (0x4453434E)
#define FIRM_MAGIC (0x4D524946)
#define ARM9BIN_MAGIC (0x47704770)
/**************************AES****************************/
#define REG_AESCNT ((volatile u32*)0x10009000)
#define REG_AESBLKCNT ((volatile u32*)0x10009004)
@@ -52,8 +41,6 @@
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
#define AES_INPUT_REVERSED 0
#define AES_TEMP_KEYSLOT 0x11
#define AES_BLOCK_SIZE 0x10
#define AES_KEYCNT_WRITE (1 << 0x7)
@@ -61,78 +48,9 @@
#define AES_KEYX 1
#define AES_KEYY 2
/**************************SHA****************************/
#define REG_SHA_CNT ((volatile u32*)0x1000A000)
#define REG_SHA_BLKCNT ((volatile u32*)0x1000A004)
#define REG_SHA_HASH ((volatile u32*)0x1000A040)
#define REG_SHA_INFIFO ((volatile u32*)0x1000A080)
#define SHA_CNT_STATE 0x00000003
#define SHA_CNT_UNK2 0x00000004
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
#define SHA_CNT_MODE 0x00000030
#define SHA_CNT_ENABLE 0x00010000
#define SHA_CNT_ACTIVE 0x00020000
#define SHA_HASH_READY 0x00000000
#define SHA_NORMAL_ROUND 0x00000001
#define SHA_FINAL_ROUND 0x00000002
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
#define SHA_OUTPUT_LE 0
#define SHA_256_MODE 0
#define SHA_224_MODE 0x00000010
#define SHA_1_MODE 0x00000020
#define SHA_256_HASH_SIZE (256 / 8)
#define SHA_224_HASH_SIZE (224 / 8)
#define SHA_1_HASH_SIZE (160 / 8)
/**************************RSA****************************/
#define REG_RSA_CNT ((volatile u32*)0x1000B000)
#define REG_RSA_SLOT0 ((volatile u32*)0x1000B100)
#define REG_RSA_SLOT1 ((volatile u32*)0x1000B110)
#define REG_RSA_SLOT2 ((volatile u32*)0x1000B120)
#define REG_RSA_SLOT3 ((volatile u32*)0x1000B130)
#define REG_RSA_EXPFIFO ((volatile u32*)0x1000B200)
#define REG_RSA_MOD_END ((volatile u32*)0x1000B500)
#define REG_RSA_TXT_END ((volatile u32*)0x1000B900)
#define RSA_CNT_START 0x00000001
#define RSA_CNT_KEYSLOTS 0x000000F0
#define RSA_CNT_IO_ENDIAN 0x00000100
#define RSA_CNT_IO_ORDER 0x00000200
#define RSA_SLOTCNT_KEY_SET 0x00000001
#define RSA_SLOTCNT_WPROTECT 0x00000002 // Write protect
#define RSA_IO_BE RSA_CNT_IO_ENDIAN
#define RSA_IO_LE 0
#define RSA_IO_NORMAL RSA_CNT_IO_ORDER
#define RSA_IO_REVERSED 0
#define RSA_TEMP_KEYSLOT 0
#define RSA_1024_MODE 0x20
#define RSA_2048_MODE 0x40
//Crypto Libs
void aes_setkey(u8 keyslot, const void* key, u32 keyType, u32 mode);
void aes_use_keyslot(u8 keyslot);
void aes(void* dst, const void* src, u32 blockCount, void* iv, u32 mode, u32 ivMode);
void aes_setiv(const void* iv, u32 mode);
void aes_advctr(void* ctr, u32 val, u32 mode);
void aes_change_ctrmode(void* ctr, u32 fromMode, u32 toMode);
void aes_batch(void* dst, const void* src, u32 blockCount);
void sha(void* res, const void* src, u32 size, u32 mode);
void rsa_setkey(u32 keyslot, const void* mod, const void* exp, u32 mode);
void rsa_use_keyslot(u32 keyslot);
int rsa_verify(const void* data, u32 size, const void* sig, u32 mode);
//NAND/FIRM stuff
void getNandCTR(u8 *buf, u8 console);
void nandFirm0(u8 *outbuf, const u32 size, u8 console);
void arm9loader(void *armHdr, u8 mode);
void nandFirm0(u8 *outbuf, u32 size, u8 console);
void decArm9Bin(void *armHdr, u8 mode);
void setKeyXs(void *armHdr);
#endif /*__CRYPTO_H*/
#endif

View File

@@ -8,16 +8,36 @@
#include "fs.h"
#include "memory.h"
static struct fb* fb = (struct fb*) 0x23FFFE00;
static struct fb *fb = (struct fb *)0x23FFFE00;
void shutdownLCD(void){
vu32 *arm11 = (vu32*)0x1FFFFFF8;
//Clear ARM11 entry offset
*arm11 = 0;
//Shutdown LCDs
*(vu32*)0x10202A44 = 0;
*(vu32*)0x10202244 = 0;
*(vu32*)0x10202014 = 0;
//Wait for the ARM11 entrypoint to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}
void clearScreen(void){
memset(fb->top_left, 0, 0x38400);
memset(fb->top_right, 0, 0x38400);
memset(fb->top_left, 0, 0x46500);
memset(fb->top_right, 0, 0x46500);
memset(fb->bottom, 0, 0x38400);
}
void loadSplash(void){
//Check if it's a no-screen-init A9LH boot via PDN_GPU_CNT
if(*(u8*)0x10141200 == 0x1) return;
clearScreen();
if(fileRead(fb->top_left, "/rei/splash.bin", 0x46500) != 0) return;
unsigned i,t; for(t=220;t>0;t--){for(i=0xFFFF;i>0;i--);}; //Ghetto sleep func
if(!fileRead(fb->top_left, "/rei/splash.bin", 0x46500)) return;
u64 i = 0xFFFFFF; while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
}

View File

@@ -4,6 +4,9 @@
* Copyright (c) 2015 All Rights Reserved
*/
#ifndef DRAW_INC
#define DRAW_INC
#include "types.h"
struct fb {
@@ -12,5 +15,7 @@ struct fb {
u8 *bottom;
};
void clearScreen(void);
void loadSplash(void);
void loadSplash(void);
void shutdownLCD(void);
#endif

View File

@@ -6,15 +6,14 @@
#include "emunand.h"
#include "memory.h"
#include "fatfs/ff.h"
#include "fatfs/sdmmc/sdmmc.h"
static u8 *temp = (u8*)0x24300000;
void getEmunandSect(u32 *off, u32 *head){
u32 nandSize = getMMCDevice(0)->total_size;
if (sdmmc_sdcard_readsectors(nandSize, 1, temp) == 0) {
if (*(u32*)(temp + 0x100) == NCSD_MAGIC) {
if(sdmmc_sdcard_readsectors(nandSize, 1, temp) == 0){
if(*(u32*)(temp + 0x100) == NCSD_MAGIC){
*off = 0;
*head = nandSize;
}
@@ -27,17 +26,17 @@ void getSDMMC(void *pos, u32 *off, u32 size){
*off = (u32)memsearch(pos, pattern, size, 4) - 1;
//Get DCD values
unsigned char buf[4];
int p;
u8 buf[4],
p;
u32 addr = 0,
additive = 0;
memcpy((void*)buf, (void*)(*off+0x0A), 4);
memcpy(buf, (void *)(*off+0x0A), 4);
for (p = 0; p < 4; p++) addr |= ((u32) buf[p]) << (8 * p);
memcpy((void*)buf, (void*)(*off+0x0E), 4);
memcpy(buf, (void *)(*off+0x0E), 4);
for (p = 0; p < 4; p++) additive |= ((u32) buf[p]) << (8 * p);
//Return result
*off = addr + additive;
*off = addr + additive;
}
void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff){

View File

@@ -4,8 +4,8 @@
* Copyright (c) 2015 All Rights Reserved
*/
#ifndef EMU_INC
#define EMU_INC
#ifndef EMUNAND_INC
#define EMUNAND_INC
#include "types.h"

View File

@@ -10,23 +10,35 @@
#include "fs.h"
#include "emunand.h"
#include "crypto.h"
#include "draw.h"
firmHeader *firmLocation = (firmHeader *)0x24000000;
firmSectionHeader *section;
u32 firmSize = 0;
u8 mode = 1,
console = 1,
emuNAND = 0,
a9lhSetup = 0,
updatedSys = 0;
updatedSys = 0,
usePatchedFirm = 0;
u16 pressed;
char *firmPathPatched = NULL;
//Load firm into FCRAM
u8 loadFirm(u8 a9lhBoot){
void setupCFW(void){
//Determine if booting with A9LH via PDN_SPI_CNT
u8 a9lhBoot = (*(u8*)0x101401C0 == 0x0) ? 1 : 0;
//Retrieve the last booted FIRM via CFG_BOOTENV
u8 previousFirm = *(u8*)0x10010000;
u8 overrideConfig = 0;
const char lastConfigPath[] = "rei/lastbootcfg";
//Detect the console being used
if(PDN_MPCORE_CFG == 1) console = 0;
//Get pressed buttons
pressed = HID_PAD;
//Determine if A9LH is installed
if(a9lhBoot || fileExists("/rei/installeda9lh")){
a9lhSetup = 1;
@@ -34,33 +46,81 @@ u8 loadFirm(u8 a9lhBoot){
if(fileExists("/rei/updatedsysnand")) updatedSys = 1;
}
section = firmLocation->section;
//If booting with A9LH and it's a MCU reboot, try to force boot options
if(a9lhBoot && previousFirm && fileExists(lastConfigPath)){
u8 tempConfig;
fileRead(&tempConfig, lastConfigPath, 1);
/* If L is pressed, and on an updated SysNAND setup the SAFE MODE combo
is not pressed, boot 9.0 FIRM */
if((pressed & BUTTON_L1) && !(updatedSys && pressed == SAFEMODE)) mode = 0;
//Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 0x7) {
if(!updatedSys) mode = tempConfig & 0x1;
overrideConfig = 1;
//Else, force the last used boot options unless A is pressed
} else if(!(pressed & BUTTON_A)) {
mode = tempConfig & 0x1;
emuNAND = (tempConfig >> 1) & 0x1;
overrideConfig = 1;
}
}
//If not using an A9LH setup, do so by decrypting FIRM0
if(!a9lhSetup && !mode){
if(!overrideConfig){
/* If L is pressed, and on an updated SysNAND setup the SAFE MODE combo
is not pressed, boot 9.0 FIRM */
if((pressed & BUTTON_L1) && !(updatedSys && pressed == SAFEMODE)) mode = 0;
/* If L or R aren't pressed on a 9.0/9.2 SysNAND, or the 9.0 FIRM is selected
or R is pressed on a > 9.2 SysNAND, boot emuNAND */
if((updatedSys && (!mode || ((pressed & BUTTON_R1) && pressed != SAFEMODE))) ||
(!updatedSys && mode && !(pressed & BUTTON_R1))) emuNAND = 1;
//Write the current boot options on A9LH
if(a9lhBoot){
u8 tempConfig = (mode | (emuNAND << 1)) & 0x3;
fileWrite(&tempConfig, lastConfigPath, 1);
}
}
if(mode) firmPathPatched = emuNAND ? "/rei/patched_firmware_emu.bin" :
"/rei/patched_firmware_sys.bin";
//Skip decrypting and patching FIRM
if(fileExists("/rei/usepatchedfw")){
//Only needed with this flag
if(!mode) firmPathPatched = "/rei/patched_firmware90.bin";
if(fileExists(firmPathPatched)) usePatchedFirm = 1;
}
}
//Load firm into FCRAM
u8 loadFirm(void){
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
if(!usePatchedFirm && !a9lhSetup && !mode){
//Read FIRM from NAND and write to FCRAM
firmSize = console ? 0xF2000 : 0xE9000;
nandFirm0((u8*)firmLocation, firmSize, console);
if(memcmp((u8*)firmLocation, "FIRM", 4) != 0) return 1;
//Check for correct decryption
if(memcmp((u8*)firmLocation, "FIRM", 4) != 0) return 0;
}
//Load FIRM from SD
else{
char firmPath[] = "/rei/firmware.bin";
char firmPath2[] = "/rei/firmware90.bin";
char *pathPtr = mode ? firmPath : firmPath2;
firmSize = fileSize(pathPtr);
if (!firmSize) return 1;
fileRead((u8*)firmLocation, pathPtr, firmSize);
const char *path = usePatchedFirm ? firmPathPatched :
(mode ? "/rei/firmware.bin" : "/rei/firmware90.bin");
firmSize = fileSize(path);
if(!firmSize) return 0;
fileRead((u8*)firmLocation, path, firmSize);
}
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) return 1;
if(console) arm9loader((u8*)firmLocation + section[2].offset, mode);
section = firmLocation->section;
return 0;
//Check that the loaded FIRM matches the console
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) return 0;
if(console && !usePatchedFirm)
decArm9Bin((u8*)firmLocation + section[2].offset, mode);
return 1;
}
//Nand redirection
@@ -75,20 +135,19 @@ u8 loadEmu(void){
emuCodeOffset = 0;
//Read emunand code from SD
char path[] = "/rei/emunand/emunand.bin";
const char path[] = "/rei/emunand/emunand.bin";
u32 size = fileSize(path);
if (!size) return 1;
if(!size) return 0;
if(!console || !mode) nandRedir[5] = 0xA4;
//Find offset for emuNAND code from the offset in nandRedir
u8 *emuCodeTmp = &nandRedir[4];
emuCodeOffset = *(u32*)emuCodeTmp - (u32)section[2].address +
emuCodeOffset = *(u32 *)(nandRedir + 4) - (u32)section[2].address +
section[2].offset + (u32)firmLocation;
fileRead((u8*)emuCodeOffset, path, size);
//Find and patch emunand related offsets
u32 *pos_sdmmc = memsearch((u32*)emuCodeOffset, "SDMC", size, 4);
u32 *pos_offset = memsearch((u32*)emuCodeOffset, "NAND", size, 4);
u32 *pos_header = memsearch((u32*)emuCodeOffset, "NCSD", size, 4);
u32 *pos_sdmmc = (u32 *)memsearch((u32*)emuCodeOffset, "SDMC", size, 4);
u32 *pos_offset = (u32 *)memsearch((u32*)emuCodeOffset, "NAND", size, 4);
u32 *pos_header = (u32 *)memsearch((u32*)emuCodeOffset, "NCSD", size, 4);
getSDMMC(firmLocation, &sdmmcOffset, firmSize);
getEmunandSect(&emuOffset, &emuHeader);
getEmuRW(firmLocation, firmSize, &emuRead, &emuWrite);
@@ -96,108 +155,102 @@ u8 loadEmu(void){
*pos_sdmmc = sdmmcOffset;
*pos_offset = emuOffset;
*pos_header = emuHeader;
//Patch emuNAND code in memory for O3DS and 9.0 N3DS
if(!console || !mode){
u32 *pos_instr = memsearch((u32*)emuCodeOffset, "\xA6\x01\x08\x30", size, 4);
memcpy((u8*)pos_instr, emuInstr, sizeof(emuInstr));
void *pos_instr = memsearch((u32*)emuCodeOffset, "\xA6\x01\x08\x30", size, 4);
memcpy(pos_instr, emuInstr, sizeof(emuInstr));
}
//Add emunand hooks
memcpy((u8*)emuRead, nandRedir, sizeof(nandRedir));
memcpy((u8*)emuWrite, nandRedir, sizeof(nandRedir));
memcpy((void *)emuRead, nandRedir, sizeof(nandRedir));
memcpy((void *)emuWrite, nandRedir, sizeof(nandRedir));
//Set MPU for emu code region
memcpy((u8*)mpuOffset, mpu, sizeof(mpu));
memcpy((void *)mpuOffset, mpu, sizeof(mpu));
return 0;
return 1;
}
//Patches
u8 patchFirm(void){
/* If L or R aren't pressed on a 9.0/9.2 SysNAND, or the 9.0 FIRM is selected
or R is pressed on a > 9.2 SysNAND, boot emuNAND */
if((updatedSys && (!mode || ((pressed & BUTTON_R1) && pressed != SAFEMODE))) ||
(!updatedSys && mode && !(pressed & (BUTTON_L1 | BUTTON_R1)))){
if (loadEmu()) return 1;
//Skip patching
if(usePatchedFirm) return 1;
//Apply emuNAND patches
if(emuNAND){
if(!loadEmu()) return 0;
}
else if(a9lhSetup){
//Patch FIRM partitions writes on SysNAND to protect A9LH
u32 writeOffset = 0;
getFIRMWrite(firmLocation, firmSize, &writeOffset);
memcpy((u8*)writeOffset, FIRMblock, sizeof(FIRMblock));
memcpy((void *)writeOffset, FIRMblock, sizeof(FIRMblock));
}
//Disable signature checks
u32 sigOffset = 0,
sigOffset2 = 0;
//Disable signature checks
getSignatures(firmLocation, firmSize, &sigOffset, &sigOffset2);
memcpy((u8*)sigOffset, sigPat1, sizeof(sigPat1));
memcpy((u8*)sigOffset2, sigPat2, sizeof(sigPat2));
memcpy((void *)sigOffset, sigPat1, sizeof(sigPat1));
memcpy((void *)sigOffset2, sigPat2, sizeof(sigPat2));
//Apply FIRM reboot patch. Not needed on N3DS
if(!console && mode && pressed != SAFEMODE &&
fileExists("/rei/reversereboot") == (pressed & BUTTON_A)){
u32 rebootOffset = 0,
rebootOffset2 = 0;
//Read reboot code from SD and write patched FIRM path in memory
char path[] = "/rei/reboot/reboot1.bin";
u32 size = fileSize(path);
if (!size) return 1;
getReboot(firmLocation, firmSize, &rebootOffset, &rebootOffset2);
fileRead((u8*)rebootOffset, path, size);
memcpy((u8*)rebootOffset + size, L"sdmc:", 10);
memcpy((u8*)rebootOffset + size + 10, L"" PATCHED_FIRM_PATH, sizeof(PATCHED_FIRM_PATH) * 2);
path[18] = '2';
size = fileSize(path);
if (!size) return 1;
fileRead((u8*)rebootOffset2, path, size);
//Write patched FIRM to SD
if (fileWrite((u8*)firmLocation, PATCHED_FIRM_PATH, firmSize) != 0) return 1;
//Patch ARM9 entrypoint on N3DS to skip arm9loader
if(console){
u32 *arm9 = (u32*)&firmLocation->arm9Entry;
*arm9 = 0x801B01C;
}
return 0;
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
if(mode){
u32 rebootOffset = 0,
fOpenOffset = 0;
//Read reboot code from SD
const char path[] = "/rei/reboot/reboot.bin";
u32 size = fileSize(path);
if(!size) return 0;
getReboot(firmLocation, firmSize, &rebootOffset);
fileRead((u8*)rebootOffset, path, size);
//Calculate the fOpen offset and put it in the right location
u32 *pos_fopen = (u32 *)memsearch((u32*)rebootOffset, "OPEN", size, 4);
getfOpen(firmLocation, firmSize, &fOpenOffset);
*pos_fopen = fOpenOffset;
//Patch path for emuNAND-patched FIRM
if(emuNAND){
void *pos_path = memsearch((u32*)rebootOffset, L"sy", size, 4);
memcpy(pos_path, L"emu", 5);
}
}
//Write patched FIRM to SD if needed
if(firmPathPatched)
if(!fileWrite((u8*)firmLocation, firmPathPatched, firmSize)) return 0;
return 1;
}
//Firmlaunchhax
void launchFirm(void){
//Set MPU
__asm__ (
"msr cpsr_c, #0xDF\n\t" //Set system mode, disable interrupts
"ldr r0, =0x10000035\n\t" //Memory area 0x10000000-0x18000000, enabled, 128MB
"ldr r4, =0x18000035\n\t" //Memory area 0x18000000-0x20000000, enabled, 128MB
"mcr p15, 0, r0, c6, c3, 0\n\t" //Set memory area 3 (0x10000000-0x18000000)
"mcr p15, 0, r4, c6, c4, 0\n\t" //Set memory area 4 (0x18000000-0x20000000)
"mrc p15, 0, r0, c2, c0, 0\n\t" //read data cacheable bit
"mrc p15, 0, r4, c2, c0, 1\n\t" //read inst cacheable bit
"mrc p15, 0, r1, c3, c0, 0\n\t" //read data writeable
"mrc p15, 0, r2, c5, c0, 2\n\t" //read data access permission
"mrc p15, 0, r3, c5, c0, 3\n\t" //read inst access permission
"orr r0, r0, #0x30\n\t"
"orr r4, r4, #0x30\n\t"
"orr r1, r1, #0x30\n\t"
"bic r2, r2, #0xF0000\n\t"
"bic r3, r3, #0xF0000\n\t"
"orr r2, r2, #0x30000\n\t"
"orr r3, r3, #0x30000\n\t"
"mcr p15, 0, r0, c2, c0, 0\n\t" //write data cacheable bit
"mcr p15, 0, r4, c2, c0, 1\n\t" //write inst cacheable bit
"mcr p15, 0, r1, c3, c0, 0\n\t" //write data writeable
"mcr p15, 0, r2, c5, c0, 2\n\t" //write data access permission
"mcr p15, 0, r3, c5, c0, 3\n\t" //write inst access permission
::: "r0", "r1", "r2", "r3", "r4"
);
if(console && mode) setKeyXs((u8*)firmLocation + section[2].offset);
//Copy firm partitions to respective memory locations
memcpy(section[0].address, (u8*)firmLocation + section[0].offset, section[0].size);
memcpy(section[1].address, (u8*)firmLocation + section[1].offset, section[1].size);
memcpy(section[2].address, (u8*)firmLocation + section[2].offset, section[2].size);
*(u32 *)0x1FFFFFF8 = (u32)firmLocation->arm11Entry;
//Run ARM11 screen stuff
vu32 *arm11 = (vu32*)0x1FFFFFF8;
*arm11 = (u32)shutdownLCD;
while (*arm11);
//Set ARM11 kernel
*arm11 = (u32)firmLocation->arm11Entry;
//Final jump to arm9 binary
console ? ((void (*)())0x801B01C)() : ((void (*)())firmLocation->arm9Entry)();
((void (*)())firmLocation->arm9Entry)();
}

View File

@@ -3,6 +3,7 @@
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#ifndef FIRM_INC
#define FIRM_INC
@@ -14,10 +15,9 @@
#define BUTTON_L1 (1 << 9)
#define BUTTON_A 1
#define SAFEMODE (BUTTON_L1 | BUTTON_R1 | BUTTON_A | (1 << 6))
#define PATCHED_FIRM_PATH "/rei/patched_firmware.bin"
u8 loadFirm(u8 a9lhBoot);
u8 loadEmu(void);
void setupCFW(void);
u8 loadFirm(void);
u8 patchFirm(void);
void launchFirm(void);

View File

@@ -2,96 +2,60 @@
* fs.c
*/
#include <stddef.h>
#include "fs.h"
#include "fatfs/ff.h"
static FATFS fs;
int mountSD()
{
if (f_mount(&fs, "0:", 1) != FR_OK) {
//printF("Failed to mount SD card!");
return 1;
}
//printF("Mounted SD card");
return 0;
u8 mountSD(void){
if(f_mount(&fs, "0:", 1) != FR_OK) return 0;
return 1;
}
int unmountSD()
{
if (f_mount(NULL, "0:", 1) != FR_OK) {
//printF("Failed to mount SD card!");
return 1;
}
//printF("Unmounted SD card");
return 0;
}
int fileReadOffset(u8 *dest, const char *path, u32 size, u32 offset){
u8 fileRead(u8 *dest, const char *path, u32 size){
FRESULT fr;
FIL fp;
unsigned int br = 0;
fr = f_open(&fp, path, FA_READ);
if (fr != FR_OK)goto error;
if (!size) size = f_size(&fp);
if (offset) {
fr = f_lseek(&fp, offset);
if (fr != FR_OK) goto error;
if(fr == FR_OK){
if(!size) size = f_size(&fp);
fr = f_read(&fp, dest, size, &br);
}
fr = f_read(&fp, dest, size, &br);
if (fr != FR_OK) goto error;
fr = f_close(&fp);
if (fr != FR_OK) goto error;
return 0;
error:
f_close(&fp);
return fr;
return fr ? 0 : 1;
}
int fileRead(u8 *dest, const char *path, u32 size){
return fileReadOffset(dest, path, size, 0);
}
int fileWrite(const u8 *buffer, const char *path, u32 size){
FRESULT fr = 1;
u8 fileWrite(const u8 *buffer, const char *path, u32 size){
FRESULT fr;
FIL fp;
unsigned int br = 0;
f_unlink(path);
if(f_open(&fp, path, FA_WRITE | FA_OPEN_ALWAYS) == FR_OK){
fr = f_write(&fp, buffer, size, &br);
f_close(&fp);
if (fr == FR_OK && br == size) return 0;
}
return fr;
fr = f_open(&fp, path, FA_WRITE | FA_OPEN_ALWAYS);
if(fr == FR_OK) fr = f_write(&fp, buffer, size, &br);
f_close(&fp);
return fr ? 0 : 1;
}
int fileSize(const char* path){
FRESULT fr;
u32 fileSize(const char* path){
FIL fp;
int size = 0;
u32 size = 0;
fr = f_open(&fp, path, FA_READ);
if (fr != FR_OK)goto error;
size = f_size(&fp);
error:
f_close(&fp);
return size;
if(f_open(&fp, path, FA_READ) == FR_OK)
size = f_size(&fp);
f_close(&fp);
return size;
}
int fileExists(const char* path){
FRESULT fr;
u8 fileExists(const char* path){
FIL fp;
int exists = 1;
fr = f_open(&fp, path, FA_READ);
if (fr != FR_OK)exists = 0;
u8 exists = 0;
if(f_open(&fp, path, FA_READ) == FR_OK) exists = 1;
f_close(&fp);
return exists;
}

View File

@@ -2,17 +2,15 @@
* fs.h
*/
#ifndef __fs_h__
#define __fs_h__
#ifndef FS_INC
#define FS_INC
#include "types.h"
int mountSD();
int unmountSD();
int fileReadOffset(u8 *dest, const char *path, u32 size, u32 offset);
int fileRead(u8 *dest, const char *path, u32 size);
int fileWrite(const u8 *buffer, const char *path, u32 size);
int fileSize(const char* path);
int fileExists(const char* path);
u8 mountSD(void);
u8 fileRead(u8 *dest, const char *path, u32 size);
u8 fileWrite(const u8 *buffer, const char *path, u32 size);
u32 fileSize(const char* path);
u8 fileExists(const char* path);
#endif
#endif

View File

@@ -10,15 +10,12 @@
#include "firm.h"
#include "draw.h"
u8 a9lhBoot = 0;
u8 main(){
mountSD();
//Detect an A9LH boot checking PDN_GPU_CNT register
if (*((u8*)0x10141200) == 0x1) a9lhBoot = 1;
else loadSplash();
if (loadFirm(a9lhBoot)) return 1;
if (patchFirm()) return 1;
loadSplash();
setupCFW();
if(!loadFirm()) return 0;
if(!patchFirm()) return 0;
launchFirm();
return 0;
return 1;
}

View File

@@ -3,40 +3,35 @@
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#include "memory.h"
void memcpy32(u32 *dest, u32 *src, u32 size){
for (u32 i = 0; i < size; i++) dest[i] = src[i];
}
void memcpy(void *dest, const void *src, u32 size){
char *destc = (char *)dest;
const char *srcc = (const char *)src;
u32 i; for (i = 0; i < size; i++) {
u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src;
for(u32 i = 0; i < size; i++)
destc[i] = srcc[i];
}
}
void memset(void *dest, int filler, u32 size){
char *destc = (char *)dest;
u32 i; for (i = 0; i < size; i++) {
destc[i] = filler;
}
u8 *destc = (u8 *)dest;
for(u32 i = 0; i < size; i++)
destc[i] = (u8)filler;
}
int memcmp(const void *buf1, const void *buf2, u32 size){
const char *buf1c = (const char *)buf1;
const char *buf2c = (const char *)buf2;
u32 i; for (i = 0; i < size; i++) {
const u8 *buf1c = (const u8 *)buf1;
const u8 *buf2c = (const u8 *)buf2;
for(u32 i = 0; i < size; i++){
int cmp = buf1c[i] - buf2c[i];
if (cmp) return cmp;
if(cmp) return cmp;
}
return 0;
}
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search){
for (void *pos = start_pos + size - size_search; pos >= start_pos; pos--) {
if (memcmp(pos, search, size_search) == 0) return pos;
for(void *pos = start_pos + size - size_search; pos >= start_pos; pos--){
if(memcmp(pos, search, size_search) == 0) return pos;
}
return NULL;
}

View File

@@ -3,13 +3,13 @@
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#ifndef MEM_INC
#define MEM_INC
#ifndef MEMORY_INC
#define MEMORY_INC
#include "types.h"
void memcpy(void *dest, const void *src, u32 size);
void memcpy32(u32 *dest, u32 *src, u32 size);
void memset(void *dest, int filler, u32 size);
int memcmp(const void *buf1, const void *buf2, u32 size);
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search);

View File

@@ -11,9 +11,6 @@
* Patches
**************************************************/
/*
* MPU
*/
u8 mpu[0x2C] = { //MPU shit
0x03, 0x00, 0x36, 0x00, 0x00, 0x00, 0x10, 0x10, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x36, 0x00,
0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08,
@@ -22,12 +19,11 @@ u8 mpu[0x2C] = { //MPU shit
u8 nandRedir[0x08] = {0x00, 0x4C, 0xA0, 0x47, 0xC0, 0xA5, 0x01, 0x08}; //Branch to emunand function
/*
* Sig checks
*/
u8 sigPat1[2] = {0x00, 0x20};
u8 sigPat2[4] = {0x00, 0x20, 0x70, 0x47};
u8 FIRMblock[4] = {0x00, 0x20, 0xC0, 0x46};
u8 emuInstr[5] = {0xA5, 0x01, 0x08, 0x30, 0xA5};
/**************************************************
@@ -43,13 +39,20 @@ void getSignatures(void *pos, u32 size, u32 *off, u32 *off2){
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
}
void getReboot(void *pos, u32 size, u32 *off, u32 *off2){
void getReboot(void *pos, u32 size, u32 *off){
//Look for FIRM reboot code
unsigned char pattern[] = {0x8D, 0xE5, 0x00, 0xC0, 0x91};
unsigned char pattern2[] = {0xF0, 0x4F, 0x2D, 0xE9, 0x3C};
unsigned char pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
*off = (u32)memsearch(pos, pattern, size, 5) + 2;
*off2 = (u32)memsearch(pos, pattern2, size, 5);
*off = (u32)memsearch(pos, pattern, size, 4) - 0x10;
}
void getfOpen(void *pos, u32 size, u32 *off){
//Calculate fOpen
u32 p9addr = *(u32*)(memsearch(pos, "ess9", size, 4) + 0xC);
u32 p9off = (u32)(memsearch(pos, "code", size, 4) + 0x1FF);
unsigned char pattern[] = {0xB0, 0x04, 0x98, 0x0D};
*off = (u32)memsearch(pos, pattern, size, 4) - 2 - p9off + p9addr;
}
void getFIRMWrite(void *pos, u32 size, u32 *off){

View File

@@ -3,6 +3,7 @@
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#ifndef PATCHES_INC
#define PATCHES_INC
@@ -22,7 +23,8 @@ u8 emuInstr[5];
* Functions
**************************************************/
void getSignatures(void *pos, u32 size, u32 *off, u32 *off2);
void getReboot(void *pos, u32 size, u32 *off, u32 *off2);
void getReboot(void *pos, u32 size, u32 *off);
void getfOpen(void *pos, u32 size, u32 *off);
void getFIRMWrite(void *pos, u32 size, u32 *off);
#endif

View File

@@ -5,39 +5,49 @@ _start:
@ Change the stack pointer
mov sp, #0x27000000
@ Give read/write access to all the memory regions
ldr r5, =0x33333333
mcr p15, 0, r5, c5, c0, 2 @ write data access
mcr p15, 0, r5, c5, c0, 3 @ write instruction access
@ Sets MPU permissions and cache settings
ldr r0, =0xFFFF001D @ ffff0000 32k
ldr r1, =0x01FF801D @ 01ff8000 32k
ldr r2, =0x08000027 @ 08000000 1M
ldr r3, =0x10000021 @ 10000000 128k
ldr r4, =0x10100025 @ 10100000 512k
ldr r5, =0x20000035 @ 20000000 128M
ldr r6, =0x2800801B @ 28008000 16k
ldr r7, =0x1800002D @ 18000000 8M
ldr r8, =0x33333336
ldr r9, =0x60600666
mov r10, #0x25
mov r11, #0x25
mov r12, #0x25
mcr p15, 0, r0, c6, c0, 0
mcr p15, 0, r1, c6, c1, 0
mcr p15, 0, r2, c6, c2, 0
mcr p15, 0, r3, c6, c3, 0
mcr p15, 0, r4, c6, c4, 0
mcr p15, 0, r5, c6, c5, 0
mcr p15, 0, r6, c6, c6, 0
mcr p15, 0, r7, c6, c7, 0
mcr p15, 0, r8, c5, c0, 2 @ Enable data r/w for all regions
mcr p15, 0, r9, c5, c0, 3 @ Enable inst read for 0, 1, 2, 5, 7
mcr p15, 0, r10, c3, c0, 0 @ Write bufferable 0, 2, 5
mcr p15, 0, r11, c2, c0, 0 @ Data cacheable 0, 2, 5
mcr p15, 0, r12, c2, c0, 1 @ Inst cacheable 0, 2, 5
ldr r0, =0xFFFF001D @ ffff0000 32k
ldr r1, =0x01FF801D @ 01ff8000 32k
ldr r2, =0x08000027 @ 08000000 1M
ldr r3, =0x10000021 @ 10000000 128k
ldr r4, =0x10100025 @ 10100000 512k
ldr r5, =0x20000035 @ 20000000 128M
ldr r6, =0x1FF00027 @ 1FF00000 1M
ldr r7, =0x1800002D @ 18000000 8M
mov r10, #0x25
mov r11, #0x25
mov r12, #0x25
mcr p15, 0, r0, c6, c0, 0
mcr p15, 0, r1, c6, c1, 0
mcr p15, 0, r2, c6, c2, 0
mcr p15, 0, r3, c6, c3, 0
mcr p15, 0, r4, c6, c4, 0
mcr p15, 0, r5, c6, c5, 0
mcr p15, 0, r6, c6, c6, 0
mcr p15, 0, r7, c6, c7, 0
mcr p15, 0, r10, c3, c0, 0 @ Write bufferable 0, 2, 5
mcr p15, 0, r11, c2, c0, 0 @ Data cacheable 0, 2, 5
mcr p15, 0, r12, c2, c0, 1 @ Inst cacheable 0, 2, 5
@ Enables all the settings we specified above
ldr r0, =0x5307D
mcr p15, 0, r0, c1, c0, 0 @ cp15 ctl register enable mpu, enable cache and use alt vector table
@ Enable caches
mrc p15, 0, r4, c1, c0, 0 @ read control register
orr r4, r4, #(1<<12) @ - instruction cache enable
orr r4, r4, #(1<<2) @ - data cache enable
orr r4, r4, #(1<<0) @ - mpu enable
mcr p15, 0, r4, c1, c0, 0 @ write control register
@ Undocumented: Fixes mounting of SDMC
@ Flush caches
mov r5, #0
mcr p15, 0, r5, c7, c5, 0 @ flush I-cache
mcr p15, 0, r5, c7, c6, 0 @ flush D-cache
mcr p15, 0, r5, c7, c10, 4 @ drain write buffer
@ Fixes mounting of SDMC
ldr r0, =0x10000020
mov r1, #0x340
str r1, [r0]

View File

@@ -1,34 +0,0 @@
.section .text.start
.align 4
.global _start
_start:
@ Change the stack pointer
mov sp, #0x27000000
@ Give read/write access to all the memory regions
ldr r5, =0x33333333
mcr p15, 0, r5, c5, c0, 2 @ write data access
mcr p15, 0, r5, c5, c0, 3 @ write instruction access
@ Enable caches
mrc p15, 0, r4, c1, c0, 0 @ read control register
orr r4, r4, #(1<<12) @ - instruction cache enable
orr r4, r4, #(1<<2) @ - data cache enable
orr r4, r4, #(1<<0) @ - mpu enable
mcr p15, 0, r4, c1, c0, 0 @ write control register
@ Flush caches
mov r5, #0
mcr p15, 0, r5, c7, c5, 0 @ flush I-cache
mcr p15, 0, r5, c7, c6, 0 @ flush D-cache
mcr p15, 0, r5, c7, c10, 4 @ drain write buffer
@ Fixes mounting of SDMC
ldr r0, =0x10000020
mov r1, #0x340
str r1, [r0]
bl main
.die:
b .die

View File

@@ -3,6 +3,7 @@
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#ifndef TYPES_INC
#define TYPES_INC
@@ -14,6 +15,10 @@ typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef volatile uint8_t vu8;
typedef volatile uint16_t vu16;
typedef volatile uint32_t vu32;
typedef volatile uint64_t vu64;
//FIRM Header layout
typedef struct firmSectionHeader {