Added OTPless installs for New 3DS (you need 10.0 NATIVE_FIRM as firm0_100.bin in /a9lh, temporarily removed support for 2xrsa

This commit is contained in:
Aurora 2016-09-28 01:57:18 +02:00
parent 4ba801938b
commit a2e44e797d
26 changed files with 656 additions and 142 deletions

3
.gitmodules vendored
View File

@ -4,6 +4,3 @@
[submodule "CakeHax"]
path = CakeHax
url = https://github.com/mid-kid/CakeHax.git
[submodule "2xrsa"]
path = 2xrsa
url = https://github.com/b1l1s/2xrsa.git

1
2xrsa

@ -1 +0,0 @@
Subproject commit c3f93cb492d61978fd0620d715510932837495dd

View File

@ -9,9 +9,9 @@ name := SafeA9LHInstaller
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
dir_source := source
dir_mset := CakeHax
dir_ninjhax := CakeBrah
dir_2xrsa := 2xrsa
dir_loader := loader
dir_cakehax := CakeHax
dir_cakebrah := CakeBrah
dir_build := build
dir_out := out
@ -24,64 +24,66 @@ objects= $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
bundled = $(dir_build)/loader.bin.o
define bin2o
bin2s $< | $(AS) -o $(@)
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $(dir_build)/bundled.h
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $(dir_build)/bundled.h
endef
.PHONY: all
all: launcher a9lh ninjhax 2xrsa
all: launcher a9lh cakebrah
.PHONY: launcher
launcher: $(dir_out)/$(name).dat
launcher: $(dir_out)/$(name).dat
.PHONY: a9lh
a9lh: $(dir_out)/arm9loaderhax.bin
.PHONY: 2xrsa
2xrsa: $(dir_out)/arm9.bin $(dir_out)/arm11.bin
.PHONY: ninjhax
ninjhax: $(dir_out)/3ds/$(name)
.PHONY: cakebrah
cakebrah: $(dir_out)/3ds/$(name)
.PHONY: release
release: $(dir_out)/$(name)$(revision).7z
.PHONY: clean
clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@$(MAKE) -C $(dir_2xrsa) clean
@$(MAKE) -C $(dir_loader) clean
@$(MAKE) $(FLAGS) -C $(dir_cakehax) clean
@$(MAKE) $(FLAGS) -C $(dir_cakebrah) clean
@rm -rf $(dir_out) $(dir_build)
$(dir_out):
@mkdir -p "$(dir_out)"
$(dir_out) $(dir_build):
@mkdir -p "$@"
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
@mkdir -p $(dir_out)
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
@$(MAKE) $(FLAGS) -C $(dir_cakehax) launcher
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
@cp -av $(dir_build)/main.bin $@
$(dir_out)/arm9.bin: $(dir_build)/main.bin $(dir_out)
@cp -av $(dir_build)/main.bin $@
$(dir_out)/arm11.bin:
@$(MAKE) -C $(dir_2xrsa)
@cp -av $(dir_2xrsa)/bin/arm11.bin $@
$(dir_out)/3ds/$(name): $(dir_out)
@mkdir -p $(dir_out)/3ds/$(name)
@$(MAKE) $(FLAGS) -C $(dir_ninjhax)
@mv $(dir_out)/$(name).3dsx $@
@mv $(dir_out)/$(name).smdh $@
@mkdir -p "$@"
@$(MAKE) $(FLAGS) -C $(dir_cakebrah)
@mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@
$(dir_out)/$(name)$(revision).7z: launcher a9lh ninjhax 2xrsa
$(dir_out)/$(name)$(revision).7z: all
@7z a -mx $@ ./$(@D)/*
$(dir_build)/main.bin: $(dir_build)/main.elf
$(OC) -S -O binary $< $@
$(dir_build)/main.elf: $(objects)
$(dir_build)/main.elf: $(bundled) $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.bin.o: $(dir_build)/%.bin
@$(bin2o)
$(dir_build)/loader.bin: $(dir_loader) $(dir_build)
@$(MAKE) -C $<
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
$(dir_build)/installer.o: CFLAGS += -DTITLE="\"$(name) $(revision)\""

67
loader/Makefile Normal file
View File

@ -0,0 +1,67 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc
AS := arm-none-eabi-as
LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy
name := $(shell basename $(CURDIR))
dir_source := source
dir_arm11 := arm11
dir_build := build
dir_out := ../$(dir_build)
ASFLAGS := -mcpu=arm946e-s
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
LDFLAGS := -nostdlib
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
bundled = $(dir_build)/arm11.bin.o
define bin2o
bin2s $< | $(AS) -o $(@)
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $(dir_build)/bundled.h
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $(dir_build)/bundled.h
endef
.PHONY: all
all: $(dir_out)/$(name).bin
.PHONY: clean
clean:
@$(MAKE) -C $(dir_arm11) clean
@rm -rf $(dir_build)
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
$(OC) -S -O binary $< $@
$(dir_build)/$(name).elf: $(bundled) $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.bin.o: $(dir_build)/%.bin
@$(bin2o)
$(dir_build)/arm11.bin: $(dir_arm11)
@mkdir -p "$(@D)"
@$(MAKE) -C $<
$(dir_build)/memory.o: CFLAGS += -O3
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d)

48
loader/arm11/Makefile Executable file
View File

@ -0,0 +1,48 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc
AS := arm-none-eabi-as
LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy
name := $(shell basename $(CURDIR))
dir_source := source
dir_build := build
dir_out := ../$(dir_build)
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
LDFLAGS := -nostdlib
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
.PHONY: all
all: $(dir_out)/$(name).bin
.PHONY: clean
clean:
@rm -rf $(dir_build)
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
$(OC) -S -O binary $< $@
$(dir_build)/$(name).elf: $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d)

12
loader/arm11/linker.ld Executable file
View File

@ -0,0 +1,12 @@
ENTRY(_start)
SECTIONS
{
. = 0x1FFF4C80;
.text.start : { *(.text.start) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
.rodata : { *(.rodata) }
. = ALIGN(4);
}

15
loader/arm11/source/main.c Executable file
View File

@ -0,0 +1,15 @@
#include "types.h"
void main(void)
{
vu32 *arm11 = (vu32 *)0x1FFFFFF8;
//Clear ARM11 entrypoint
*arm11 = 0;
//Wait for the entrypoint to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}

View File

@ -0,0 +1,8 @@
.section .text.start
.align 4
.global _start
_start:
@ Disable interrupts
CPSID aif
b main

13
loader/arm11/source/types.h Executable file
View File

@ -0,0 +1,13 @@
/*
* types.h
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#pragma once
#include <stdint.h>
//Common data types
typedef uint32_t u32;
typedef volatile u32 vu32;

11
loader/linker.ld Normal file
View File

@ -0,0 +1,11 @@
ENTRY(_start)
SECTIONS
{
. = 0x80F0000;
.text.start : { *(.text.start) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
.rodata : { *(.rodata) }
. = ALIGN(4);
}

27
loader/source/cache.h Normal file
View File

@ -0,0 +1,27 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include "types.h"
void flushCaches(void);

54
loader/source/cache.s Normal file
View File

@ -0,0 +1,54 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016 Aurora Wright, TuxSH
@
@ This program is free software: you can redistribute it and/or modify
@ it under the terms of the GNU General Public License as published by
@ the Free Software Foundation, either version 3 of the License, or
@ (at your option) any later version.
@
@ This program is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ GNU General Public License for more details.
@
@ You should have received a copy of the GNU General Public License
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
@ Notices displayed by works containing it.
.text
.arm
.align 4
.global flushCaches
.type flushCaches, %function
flushCaches:
@ Clean and flush data cache
@ Adpated from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html ,
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
@ Implemented in bootROM at address 0xffff0830
mov r1, #0 @ segment counter
outer_loop:
mov r0, #0 @ line counter
inner_loop:
orr r2, r1, r0 @ generate segment and line address
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
add r0, #0x20 @ increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
@ Flush instruction cache
mcr p15, 0, r1, c7, c5, 0
bx lr

53
loader/source/main.c Normal file
View File

@ -0,0 +1,53 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#include "cache.h"
#include "memory.h"
#include "../build/bundled.h"
#define A11_PAYLOAD_LOC 0x1FFF4C80 //Keep in mind this needs to be changed in the ld script for arm11 too
#define A11_ENTRYPOINT 0x1FFFFFF8
static inline void ownArm11(void)
{
memcpy((void *)A11_PAYLOAD_LOC, arm11_bin, arm11_bin_size);
*(vu32 *)A11_ENTRYPOINT = 1;
*(vu32 *)0x1FFAED80 = 0xE51FF004;
*(vu32 *)0x1FFAED84 = A11_PAYLOAD_LOC;
*(vu8 *)0x1FFFFFF0 = 2;
while(*(vu32 *)A11_ENTRYPOINT);
}
void main(void)
{
ownArm11();
vu32 *magic = (vu32 *)0x25000000;
magic[0] = 0xABADCAFE;
magic[1] = 0xDEADCAFE;
//Ensure that all memory transfers have completed and that the caches have been flushed
flushCaches();
((void (*)())0x23F00000)();
}

14
loader/source/memory.c Normal file
View File

@ -0,0 +1,14 @@
/*
* memory.c
*/
#include "memory.h"
void memcpy(void *dest, const void *src, u32 size)
{
u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src;
for(u32 i = 0; i < size; i++)
destc[i] = srcc[i];
}

9
loader/source/memory.h Normal file
View File

@ -0,0 +1,9 @@
/*
* memory.h
*/
#pragma once
#include "types.h"
void memcpy(void *dest, const void *src, u32 size);

86
loader/source/start.s Normal file
View File

@ -0,0 +1,86 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016 Aurora Wright, TuxSH
@
@ This program is free software: you can redistribute it and/or modify
@ it under the terms of the GNU General Public License as published by
@ the Free Software Foundation, either version 3 of the License, or
@ (at your option) any later version.
@
@ This program is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ GNU General Public License for more details.
@
@ You should have received a copy of the GNU General Public License
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@
@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
@ reasonable legal notices or author attributions in that material or in the Appropriate Legal
@ Notices displayed by works containing it.
@ Thanks to the numerous people who took part in writing this file
.section .text.start
.align 4
.global _start
_start:
@ Change the stack pointer
mov sp, #0x27000000
@ Disable interrupts
mrs r0, cpsr
orr r0, #0x1C0
msr cpsr_cx, r0
@ Disable caches / MPU
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, #(1<<12) @ - instruction cache disable
bic r0, #(1<<2) @ - data cache disable
bic r0, #(1<<0) @ - mpu disable
mcr p15, 0, r0, c1, c0, 0 @ write control register
@ Flush caches
bl flushCaches
@ Give read/write access to all the memory regions
ldr r0, =0x3333333
mcr p15, 0, r0, c5, c0, 2 @ write data access
mcr p15, 0, r0, c5, c0, 3 @ write instruction access
@ Set MPU permissions and cache settings
ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
ldr r1, =0x01FF801D @ 01ff8000 32k | itcm
ldr r2, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
ldr r3, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
ldr r4, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS)
ldr r5, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
ldr r6, =0x1800002D @ 18000000 8M | vram (+ 2MB)
mov r7, #0
mov r8, #0x15
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, c3, c0, 0 @ Write bufferable 0, 2, 4
mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 4
mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 4
@ Enable caches / MPU / ITCM
mrc p15, 0, r0, c1, c0, 0 @ read control register
orr r0, r0, #(1<<18) @ - ITCM enable
orr r0, r0, #(1<<13) @ - alternate exception vectors enable
orr r0, r0, #(1<<12) @ - instruction cache enable
orr r0, r0, #(1<<2) @ - data cache enable
orr r0, r0, #(1<<0) @ - mpu enable
mcr p15, 0, r0, c1, c0, 0 @ write control register
@ Fix mounting of SDMC
ldr r0, =0x10000020
mov r1, #0x340
str r1, [r0]
b main

37
loader/source/types.h Normal file
View File

@ -0,0 +1,37 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
//Common data types
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;

View File

@ -275,13 +275,14 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
static u8 __attribute__((aligned(4))) nandCtr[AES_BLOCK_SIZE];
static u8 nandSlot;
static u32 fatStart;
const u8 __attribute__((aligned(4))) key2s[3][AES_BLOCK_SIZE] = {
const u8 __attribute__((aligned(4))) key2s[4][AES_BLOCK_SIZE] = {
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xF5, 0xF6},
{0x65, 0x29, 0x3E, 0x12, 0x56, 0x0C, 0x0B, 0xD1, 0xDD, 0xB5, 0x63, 0x1C, 0xB6, 0xD9, 0x52, 0x75}
{0x65, 0x29, 0x3E, 0x12, 0x56, 0x0C, 0x0B, 0xD1, 0xDD, 0xB5, 0x63, 0x1C, 0xB6, 0xD9, 0x52, 0x75},
{0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}
};
void getNandCTR(void)
void getNandCtr(void)
{
u8 __attribute__((aligned(4))) cid[AES_BLOCK_SIZE];
u8 __attribute__((aligned(4))) shaSum[SHA_256_HASH_SIZE];
@ -293,7 +294,7 @@ void getNandCTR(void)
void ctrNandInit(void)
{
getNandCTR();
getNandCtr();
if(isN3DS)
{
@ -355,7 +356,7 @@ void writeFirm(u8 *inbuf, bool isFirm1, u32 size)
sdmmc_nand_writesectors(offset / 0x200, size / 0x200, inbuf);
}
void setupKeyslot0x11(bool isA9lh, const void *otp)
void setupKeyslot0x11(const void *otp, bool isA9lh)
{
u8 __attribute__((aligned(4))) shasum[SHA_256_HASH_SIZE];
u8 __attribute__((aligned(4))) keyX[AES_BLOCK_SIZE];
@ -377,23 +378,31 @@ void setupKeyslot0x11(bool isA9lh, const void *otp)
void generateSector(u8 *keySector, u32 mode)
{
//Inject key2
memcpy(keySector + AES_BLOCK_SIZE, mode ? key2s[0] : key2s[2], AES_BLOCK_SIZE);
if(mode == 0) memcpy(keySector + AES_BLOCK_SIZE, key2s[2], AES_BLOCK_SIZE);
else if(mode == 1) memcpy(keySector + AES_BLOCK_SIZE, keySector, AES_BLOCK_SIZE);
else memcpy(keySector + AES_BLOCK_SIZE, key2s[0], AES_BLOCK_SIZE);
//Encrypt key sector
aes_use_keyslot(0x11);
for(u32 i = 0; i < 32; i++)
aes(keySector + (AES_BLOCK_SIZE * i), keySector + (AES_BLOCK_SIZE * i), 1, NULL, AES_ECB_ENCRYPT_MODE, 0);
if(mode != 1)
{
//Encrypt key sector
aes_use_keyslot(0x11);
for(u32 i = 0; i < 32; i++)
aes(keySector + (AES_BLOCK_SIZE * i), keySector + (AES_BLOCK_SIZE * i), 1, NULL, AES_ECB_ENCRYPT_MODE, 0);
}
}
void getSector(u8 *keySector)
void getSector(u8 *keySector, bool isA9lh)
{
//Read keysector from NAND
sdmmc_nand_readsectors(0x96, 1, keySector);
//Decrypt key sector
aes_use_keyslot(0x11);
for(u32 i = 0; i < 32; i++)
aes(keySector + (AES_BLOCK_SIZE * i), keySector + (AES_BLOCK_SIZE * i), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
if(isA9lh)
{
//Decrypt key sector
aes_use_keyslot(0x11);
for(u32 i = 0; i < 32; i++)
aes(keySector + (AES_BLOCK_SIZE * i), keySector + (AES_BLOCK_SIZE * i), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
}
}
u32 verifyHash(const void *data, u32 size, const u8 *hash)

View File

@ -80,15 +80,15 @@
#define SHA_1_HASH_SIZE (160 / 8)
extern bool isN3DS;
const u8 key2s[3][0x10];
const u8 key2s[4][AES_BLOCK_SIZE];
void getNandCTR(void);
void getNandCtr(void);
void ctrNandInit(void);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void readFirm0(u8 *outbuf, u32 size);
void writeFirm(u8 *inbuf, bool isFirm1, u32 size);
void setupKeyslot0x11(bool isA9lh, const void *otp);
void setupKeyslot0x11(const void *otp, bool isA9lh);
void generateSector(u8 *keySector, u32 mode);
void getSector(u8 *keySector);
void getSector(u8 *keySector, bool isA9lh);
u32 verifyHash(const void *data, u32 size, const u8 *hash);
u32 decryptExeFs(u8 *inbuf);

View File

@ -27,12 +27,12 @@
static FATFS fs;
u32 mountSD(void)
bool mountSd(void)
{
return f_mount(&fs, "0:", 1) == FR_OK;
}
u32 mountCTRNAND(void)
bool mountCtrNand(void)
{
return f_mount(&fs, "1:", 1) == FR_OK;
}
@ -45,9 +45,8 @@ u32 fileRead(void *dest, const char *path, u32 maxSize)
if(f_open(&file, path, FA_READ) == FR_OK)
{
u32 size = f_size(&file);
if(dest == NULL) ret = size;
else if(!(maxSize > 0 && size > maxSize))
f_read(&file, dest, size, (unsigned int *)&ret);
if(!(size > maxSize))
f_read(&file, dest, size, (unsigned int *)ret);
f_close(&file);
}
@ -64,6 +63,7 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
{
unsigned int written;
f_write(&file, buffer, size, &written);
f_truncate(&file);
f_close(&file);
return true;

View File

@ -26,8 +26,8 @@
extern bool isN3DS;
u32 mountSD(void);
u32 mountCTRNAND(void);
bool mountSd(void);
bool mountCtrNand(void);
u32 fileRead(void *dest, const char *path, u32 maxSize);
bool fileWrite(const void *buffer, const char *path, u32 size);
u32 firmRead(void *dest);

View File

@ -9,7 +9,10 @@
#include "screen.h"
#include "draw.h"
#include "utils.h"
#include "cache.h"
#include "types.h"
#include "fatfs/sdmmc/sdmmc.h"
#include "../build/bundled.h"
static const u8 sectorHash[0x20] = {
0x82, 0xF2, 0x73, 0x0D, 0x2C, 0x2D, 0xA3, 0xF3, 0x01, 0x65, 0xF9, 0x87, 0xFD, 0xCC, 0xAC, 0x5C,
@ -26,6 +29,11 @@ static const u8 firm0A9lhHash[0x20] = {
0x8E, 0xF0, 0x4A, 0xB1, 0xA6, 0x7F, 0xCD, 0xAB, 0x0C, 0x0A, 0xC0, 0x69, 0xA7, 0x9D, 0xC5, 0x04
};
static const u8 firm0100Hash[0x20] = {
0xD8, 0x2D, 0xB7, 0xB4, 0x38, 0x2B, 0x07, 0x88, 0x99, 0x77, 0x91, 0x0C, 0xC6, 0xEC, 0x6D, 0x87,
0x7D, 0x21, 0x79, 0x23, 0xD7, 0x60, 0xAF, 0x4E, 0x8B, 0x3A, 0xAB, 0xB2, 0x63, 0xE4, 0x21, 0xC6
};
static const u8 firm1Hash[0x20] = {
0xD2, 0x53, 0xC1, 0xCC, 0x0A, 0x5F, 0xFA, 0xC6, 0xB3, 0x83, 0xDA, 0xC1, 0x82, 0x7C, 0xFB, 0x3B,
0x2D, 0x3D, 0x56, 0x6C, 0x6A, 0x1A, 0x8E, 0x52, 0x54, 0xE3, 0x89, 0xC2, 0x95, 0x06, 0x23, 0xE5
@ -36,37 +44,50 @@ bool isN3DS;
void main(void)
{
initScreens();
sdmmc_sdcard_init();
//Determine if booting with A9LH
bool isA9lh = !PDN_SPI_CNT;
//Detect the console being used
isN3DS = PDN_MPCORE_CFG == 7;
vu32 *magic = (vu32 *)0x25000000;
bool isOtpless = isA9lh && magic[0] == 0xABADCAFE && magic[1] == 0xDEADCAFE;
sdmmc_sdcard_init();
initScreens();
drawString(TITLE, 10, 10, COLOR_TITLE);
posY = drawString("Thanks to delebile, #cakey and StandardBus", 10, 40, COLOR_WHITE);
posY = drawString(isA9lh ? "Press SELECT to update A9LH, START to uninstall" : "Press SELECT for a full install", 10, posY + SPACING_Y, COLOR_WHITE);
posY = drawString("Press any other button to shutdown", 10, posY, COLOR_WHITE);
u32 pressed = waitInput();
u32 pressed;
if(pressed == BUTTON_SELECT) installer(isA9lh);
if(!isOtpless)
{
posY = drawString(isA9lh ? "Press SELECT to update A9LH, START to uninstall" : "Press SELECT for a full install", 10, posY + SPACING_Y, COLOR_WHITE);
posY = drawString("Press any other button to shutdown", 10, posY, COLOR_WHITE);
pressed = waitInput();
}
else
{
posY = drawString("Finalizing install...", 10, posY + SPACING_Y, COLOR_WHITE);
pressed = 0;
}
if(isOtpless || pressed == BUTTON_SELECT) installer(isA9lh, isOtpless);
if(pressed == BUTTON_START && isA9lh) uninstaller();
shutdown(0, NULL);
}
static inline void installer(bool isA9lh)
static inline void installer(bool isA9lh, bool isOtpless)
{
if(!mountSD())
if(!isOtpless && !mountSd())
shutdown(1, "Error: failed to mount the SD card");
bool updateA9lh = false;
//If making a first install, we need the OTP
if(!isA9lh)
//If making a first install on O3DS, we need the OTP
if(!isA9lh && !isN3DS)
{
const char otpPath[] = "a9lh/otp.bin";
const u8 zeroes[256] = {0};
@ -75,7 +96,7 @@ static inline void installer(bool isA9lh)
if(memcmp((void *)OTP_FROM_MEM, zeroes, 256) == 0)
{
// Read OTP from file
if(!fileRead((void *)OTP_OFFSET, otpPath, 256))
if(fileRead((void *)OTP_OFFSET, otpPath, 256) != 256)
shutdown(1, "Error: otp.bin doesn't exist and can't be dumped");
}
else
@ -87,86 +108,108 @@ static inline void installer(bool isA9lh)
}
//Setup the key sector de/encryption with the SHA register or otp.bin
setupKeyslot0x11(isA9lh, (void *)OTP_OFFSET);
if(isA9lh || !isN3DS) setupKeyslot0x11((void *)OTP_OFFSET, isA9lh);
//Calculate the CTR for the 3DS partitions
getNandCTR();
getNandCtr();
//Get NAND FIRM0 and test that the CTR is correct
readFirm0((u8 *)FIRM0_OFFSET, FIRM0_SIZE);
if(memcmp((void *)FIRM0_OFFSET, "FIRM", 4) != 0)
shutdown(1, "Error: failed to setup FIRM encryption");
if(!isOtpless)
{
readFirm0((u8 *)FIRM0_OFFSET, FIRM0_SIZE);
if(memcmp((void *)FIRM0_OFFSET, "FIRM", 4) != 0)
shutdown(1, "Error: failed to setup FIRM encryption");
}
//If booting from A9LH or on N3DS, we can use the key sector from NAND
if(isA9lh || isN3DS)
{
getSector((u8 *)SECTOR_OFFSET);
u32 i;
for(i = 0; i < 3; i++)
if(memcmp((void *)(SECTOR_OFFSET + 0x10), key2s[i], 0x10) == 0) break;
if(i == 3) shutdown(1, isA9lh ? "Error: the OTP hash or the NAND key sector\nare invalid" :
"Error: the otp.bin or the NAND key sector\nare invalid");
else if(i == 1) updateA9lh = true;
}
if(isA9lh || isN3DS) getSector((u8 *)SECTOR_OFFSET, isA9lh);
else
{
//Read decrypted key sector
if(!fileRead((void *)SECTOR_OFFSET, "a9lh/secret_sector.bin", 0x200))
if(fileRead((void *)SECTOR_OFFSET, "a9lh/secret_sector.bin", 0x200) != 0x200)
shutdown(1, "Error: secret_sector.bin doesn't exist or has\na wrong size");
if(!verifyHash((void *)SECTOR_OFFSET, 0x200, sectorHash))
shutdown(1, "Error: secret_sector.bin is invalid or corrupted");
}
if(!isA9lh || updateA9lh)
if(isA9lh && !isOtpless)
{
//Generate and encrypt a per-console A9LH key sector
generateSector((u8 *)SECTOR_OFFSET, 0);
u32 i;
for(i = 0; i < 4; i++)
if(memcmp((void *)(SECTOR_OFFSET + 0x10), key2s[i], 0x10) == 0) break;
//Read FIRM0
if(!fileRead((void *)FIRM0_OFFSET, "a9lh/firm0.bin", FIRM0_SIZE))
shutdown(1, "Error: firm0.bin doesn't exist or has a wrong size");
if(!verifyHash((void *)FIRM0_OFFSET, FIRM0_SIZE, firm0Hash))
shutdown(1, "Error: firm0.bin is invalid or corrupted");
if(i == 4) shutdown(1, "Error: the OTP hash or the NAND key sector\nare invalid");
if(i == 0) updateA9lh = true;
}
else if(!verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm0A9lhHash))
shutdown(1, "Error: NAND FIRM0 is invalid");
if(!isA9lh)
{
//Read FIRM1
if(!fileRead((void *)FIRM1_OFFSET, "a9lh/firm1.bin", FIRM1_SIZE))
if(fileRead((void *)FIRM1_OFFSET, "a9lh/firm1.bin", FIRM1_SIZE) != FIRM1_SIZE)
shutdown(1, "Error: firm1.bin doesn't exist or has a wrong size");
if(!verifyHash((void *)FIRM1_OFFSET, FIRM1_SIZE, firm1Hash))
shutdown(1, "Error: firm1.bin is invalid or corrupted");
if(isN3DS)
{
//Read FIRM0
if(fileRead((void *)FIRM0_100_OFFSET, "a9lh/firm0_100.bin", FIRM0100_SIZE) != FIRM0100_SIZE)
shutdown(1, "Error: firm0_100.bin doesn't exist or has a wrong size");
if(!verifyHash((void *)FIRM0_100_OFFSET, FIRM0100_SIZE, firm0100Hash))
shutdown(1, "Error: firm0_100.bin is invalid or corrupted");
}
}
//Inject stage1
memset32((void *)STAGE1_OFFSET, 0, MAX_STAGE1_SIZE);
if(!fileRead((void *)STAGE1_OFFSET, "a9lh/payload_stage1.bin", MAX_STAGE1_SIZE))
shutdown(1, "Error: payload_stage1.bin doesn't exist or\nexceeds max size");
if(!isA9lh || updateA9lh || isOtpless) generateSector((u8 *)SECTOR_OFFSET, (isN3DS && !isA9lh) ? 1 : 0);
const u8 zeroes[688] = {0};
if(memcmp(zeroes, (void *)STAGE1_OFFSET, 688) == 0)
shutdown(1, "Error: the payload_stage1.bin you're attempting\nto install is not compatible");
if(!isA9lh || updateA9lh)
{
//Read FIRM0
if(fileRead((void *)FIRM0_OFFSET, "a9lh/firm0.bin", FIRM0_SIZE) != FIRM0_SIZE)
shutdown(1, "Error: firm0.bin doesn't exist or has a wrong size");
if(!verifyHash((void *)FIRM0_OFFSET, FIRM0_SIZE, firm0Hash))
shutdown(1, "Error: firm0.bin is invalid or corrupted");
}
else if(!isOtpless && !verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm0A9lhHash))
shutdown(1, "Error: NAND FIRM0 is invalid");
//Read stage2
memset32((void *)STAGE2_OFFSET, 0, MAX_STAGE2_SIZE);
if(!fileRead((void *)STAGE2_OFFSET, "a9lh/payload_stage2.bin", MAX_STAGE2_SIZE))
shutdown(1, "Error: payload_stage2.bin doesn't exist or\nexceeds max size");
if(!isOtpless)
{
//Inject stage1
memset32((void *)STAGE1_OFFSET, 0, MAX_STAGE1_SIZE);
if(!fileRead((void *)STAGE1_OFFSET, "a9lh/payload_stage1.bin", MAX_STAGE1_SIZE))
shutdown(1, "Error: payload_stage1.bin doesn't exist or\nexceeds max size");
posY = drawString("All checks passed, installing...", 10, posY + SPACING_Y, COLOR_WHITE);
const u8 zeroes[688] = {0};
if(memcmp(zeroes, (void *)STAGE1_OFFSET, 688) == 0)
shutdown(1, "Error: the payload_stage1.bin you're attempting\nto install is not compatible");
//Read stage2
memset32((void *)STAGE2_OFFSET, 0, MAX_STAGE2_SIZE);
if(!fileRead((void *)STAGE2_OFFSET, "a9lh/payload_stage2.bin", MAX_STAGE2_SIZE))
shutdown(1, "Error: payload_stage2.bin doesn't exist or\nexceeds max size");
posY = drawString("All checks passed, installing...", 10, posY + SPACING_Y, COLOR_WHITE);
sdmmc_nand_writesectors(0x5C000, MAX_STAGE2_SIZE / 0x200, (u8 *)STAGE2_OFFSET);
}
//Point of no return, install stuff in the safest order
sdmmc_nand_writesectors(0x5C000, MAX_STAGE2_SIZE / 0x200, (u8 *)STAGE2_OFFSET);
if(!isA9lh) writeFirm((u8 *)FIRM1_OFFSET, true, FIRM1_SIZE);
if(!isA9lh || updateA9lh) sdmmc_nand_writesectors(0x96, 1, (u8 *)SECTOR_OFFSET);
if(!isA9lh || updateA9lh || isOtpless) sdmmc_nand_writesectors(0x96, 1, (u8 *)SECTOR_OFFSET);
if(!isA9lh && isN3DS)
{
*(u32 *)0x80FD0FC = 0xEAFFCBBF; //B 0x80F0000
memcpy((void *)0x80F0000, loader_bin, loader_bin_size);
writeFirm((u8 *)FIRM0_100_OFFSET, false, FIRM0_SIZE);
mcuReboot();
}
writeFirm((u8 *)FIRM0_OFFSET, false, FIRM0_SIZE);
shutdown(2, isA9lh ? "Update: success!" : "Full install: success!");
shutdown(2, isA9lh && !isOtpless ? "Update: success!" : "Full install: success!");
}
static inline void uninstaller(void)
@ -188,15 +231,15 @@ static inline void uninstaller(void)
//New 3DSes need a key sector with a proper key2, Old 3DSes have a blank key sector
if(isN3DS)
{
setupKeyslot0x11(1, NULL);
getSector((u8 *)SECTOR_OFFSET);
setupKeyslot0x11(NULL, true);
getSector((u8 *)SECTOR_OFFSET, true);
if(memcmp((void *)(SECTOR_OFFSET + 0x10), key2s[1], 0x10) != 0 && memcmp((void *)(SECTOR_OFFSET + 0x10), key2s[2], 0x10) != 0)
shutdown(1, "Error: the OTP hash or the NAND key sector\nare invalid");
generateSector((u8 *)SECTOR_OFFSET, 1);
generateSector((u8 *)SECTOR_OFFSET, 2);
}
else memset32((void *)SECTOR_OFFSET, 0, 0x200);
if(!mountCTRNAND())
if(!mountCtrNand())
shutdown(1, "Error: failed to mount CTRNAND");
//Read FIRM cxi from CTRNAND

View File

@ -13,15 +13,17 @@
#define OTP_OFFSET 0x24000000
#define SECTOR_OFFSET 0x24100000
#define FIRM0_OFFSET 0x24200000
#define FIRM1_OFFSET 0x24300000
#define FIRM0_100_OFFSET 0x24300000
#define FIRM1_OFFSET 0x24400000
#define FIRM0_SIZE 0xF3000
#define FIRM0100_SIZE 0xF2000
#define SECTION2_POSITION 0x66A00
#define FIRM1_SIZE 0xF2000
#define STAGE1_POSITION 0xF0590
#define STAGE1_OFFSET FIRM0_OFFSET + STAGE1_POSITION
#define STAGE2_OFFSET 0x24400000
#define STAGE2_OFFSET 0x24500000
#define MAX_STAGE1_SIZE 0x1E70
#define MAX_STAGE2_SIZE 0x89A00
static inline void installer(bool isA9lh);
static inline void installer(bool isA9lh, bool isOtpless);
static inline void uninstaller(void);

View File

@ -35,7 +35,6 @@
*/
#include "screen.h"
#include "draw.h"
#include "cache.h"
#include "i2c.h"
@ -92,8 +91,8 @@ void initScreens(void)
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = 0x45;
*(vu32 *)0x10202A40 = 0x45;
*(vu32 *)0x10202240 = 0x4C;
*(vu32 *)0x10202A40 = 0x4C;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
@ -188,22 +187,16 @@ void initScreens(void)
WAIT_FOR_ARM9();
}
static bool needToSetup = true;
if(needToSetup)
if(PDN_GPU_CNT == 1)
{
if(PDN_GPU_CNT == 1)
{
invokeArm11Function(initSequence);
invokeArm11Function(initSequence);
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(setupFramebuffers);
needToSetup = false;
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(setupFramebuffers);
clearScreens();
}

View File

@ -35,6 +35,17 @@ u32 waitInput(void)
return key;
}
void mcuReboot(void)
{
if(PDN_GPU_CNT != 1) clearScreens();
//Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireDCache();
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
while(true);
}
void shutdown(u32 mode, const char *message)
{
if(mode)
@ -45,7 +56,10 @@ void shutdown(u32 mode, const char *message)
}
if(PDN_GPU_CNT != 1) clearScreens();
//Ensure that all memory transfers have completed and that the data cache has been flushed
flushEntireDCache();
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
while(true);
}

View File

@ -24,4 +24,5 @@
extern u32 posY;
u32 waitInput(void);
void mcuReboot(void);
void shutdown(u32 mode, const char *message);