mirror of
https://github.com/AuroraWright/SafeA9LHInstaller.git
synced 2025-06-25 21:22:45 +00:00
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:
parent
4ba801938b
commit
a2e44e797d
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
2xrsa
@ -1 +0,0 @@
|
||||
Subproject commit c3f93cb492d61978fd0620d715510932837495dd
|
62
Makefile
62
Makefile
@ -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
67
loader/Makefile
Normal 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
48
loader/arm11/Makefile
Executable 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
12
loader/arm11/linker.ld
Executable 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
15
loader/arm11/source/main.c
Executable 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)();
|
||||
}
|
8
loader/arm11/source/start.s
Normal file
8
loader/arm11/source/start.s
Normal 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
13
loader/arm11/source/types.h
Executable 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
11
loader/linker.ld
Normal 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
27
loader/source/cache.h
Normal 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
54
loader/source/cache.s
Normal 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
53
loader/source/main.c
Normal 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
14
loader/source/memory.c
Normal 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
9
loader/source/memory.h
Normal 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
86
loader/source/start.s
Normal 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
37
loader/source/types.h
Normal 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;
|
@ -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)
|
||||
|
@ -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);
|
10
source/fs.c
10
source/fs.c
@ -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;
|
||||
|
@ -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);
|
@ -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
|
||||
|
@ -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);
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -24,4 +24,5 @@
|
||||
extern u32 posY;
|
||||
|
||||
u32 waitInput(void);
|
||||
void mcuReboot(void);
|
||||
void shutdown(u32 mode, const char *message);
|
Loading…
x
Reference in New Issue
Block a user