Change OTPless installation approach
This commit is contained in:
parent
d605111e28
commit
b1d596177a
23
Makefile
23
Makefile
@ -15,8 +15,6 @@ name := SafeA9LHInstaller
|
|||||||
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
||||||
|
|
||||||
dir_source := source
|
dir_source := source
|
||||||
dir_loader := loader
|
|
||||||
dir_arm11 := arm11
|
|
||||||
dir_cakehax := CakeHax
|
dir_cakehax := CakeHax
|
||||||
dir_cakebrah := CakeBrah
|
dir_cakebrah := CakeBrah
|
||||||
dir_build := build
|
dir_build := build
|
||||||
@ -31,14 +29,6 @@ objects= $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
bundled = $(dir_build)/loader.bin.o $(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
|
.PHONY: all
|
||||||
all: launcher a9lh cakebrah
|
all: launcher a9lh cakebrah
|
||||||
|
|
||||||
@ -56,8 +46,6 @@ release: $(dir_out)/$(name)$(revision).7z
|
|||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@$(MAKE) -C $(dir_loader) clean
|
|
||||||
@$(MAKE) -C $(dir_arm11) clean
|
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_cakehax) clean
|
@$(MAKE) $(FLAGS) -C $(dir_cakehax) clean
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_cakebrah) clean
|
@$(MAKE) $(FLAGS) -C $(dir_cakebrah) clean
|
||||||
@rm -rf $(dir_out) $(dir_build)
|
@rm -rf $(dir_out) $(dir_build)
|
||||||
@ -83,18 +71,9 @@ $(dir_out)/$(name)$(revision).7z: all
|
|||||||
$(dir_build)/main.bin: $(dir_build)/main.elf
|
$(dir_build)/main.bin: $(dir_build)/main.elf
|
||||||
$(OC) -S -O binary $< $@
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
$(dir_build)/main.elf: $(bundled) $(objects)
|
$(dir_build)/main.elf: $(objects)
|
||||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
$(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)/arm11.bin: $(dir_arm11) $(dir_build)
|
|
||||||
@$(MAKE) -C $<
|
|
||||||
|
|
||||||
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||||
$(dir_build)/installer.o: CFLAGS += -DTITLE="\"$(name) $(revision)\""
|
$(dir_build)/installer.o: CFLAGS += -DTITLE="\"$(name) $(revision)\""
|
||||||
|
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
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)
|
|
@ -1,12 +0,0 @@
|
|||||||
ENTRY(_start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0x1FFF4C80;
|
|
||||||
.text.start : { *(.text.start) }
|
|
||||||
.text : { *(.text) }
|
|
||||||
.data : { *(.data) }
|
|
||||||
.bss : { *(.bss COMMON) }
|
|
||||||
.rodata : { *(.rodata) }
|
|
||||||
. = ALIGN(4);
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
#include "types.h"
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
vu32 *arm11Entry = (vu32 *)0x1FFFFFF8;
|
|
||||||
|
|
||||||
//Clear ARM11 entrypoint
|
|
||||||
*arm11Entry = 0;
|
|
||||||
|
|
||||||
//Wait for the entrypoint to be set
|
|
||||||
while(!*arm11Entry);
|
|
||||||
|
|
||||||
//Jump to it
|
|
||||||
((void (*)())*arm11Entry)();
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
.section .text.start
|
|
||||||
.align 4
|
|
||||||
.global _start
|
|
||||||
_start:
|
|
||||||
@ Disable interrupts
|
|
||||||
CPSID aif
|
|
||||||
|
|
||||||
b main
|
|
@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
//Common data types
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef volatile u32 vu32;
|
|
@ -1,48 +0,0 @@
|
|||||||
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=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)))
|
|
||||||
|
|
||||||
.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)
|
|
@ -1,11 +0,0 @@
|
|||||||
ENTRY(_start)
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0x1FF8000;
|
|
||||||
.text.start : { *(.text.start) }
|
|
||||||
.text : { *(.text) }
|
|
||||||
.data : { *(.data) }
|
|
||||||
.bss : { *(.bss COMMON) }
|
|
||||||
.rodata : { *(.rodata) }
|
|
||||||
. = ALIGN(4);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "types.h"
|
|
||||||
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
vu32 *payloadAddress = (vu32 *)0x23F00000;
|
|
||||||
payloadAddress[1] = 0xDEADCAFE;
|
|
||||||
|
|
||||||
//Ensure that all memory transfers have completed and that the caches have been flushed
|
|
||||||
((void (*)())0xFFFF0830)();
|
|
||||||
((void (*)())0xFFFF0AB4)();
|
|
||||||
|
|
||||||
((void (*)())payloadAddress)();
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
@ 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:
|
|
||||||
@ Disable interrupts
|
|
||||||
mrs r0, cpsr
|
|
||||||
orr r0, #0x1C0
|
|
||||||
msr cpsr_cx, r0
|
|
||||||
|
|
||||||
@ Change the stack pointer
|
|
||||||
mov sp, #0x27000000
|
|
||||||
|
|
||||||
@ 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
|
|
||||||
|
|
||||||
@ 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
|
|
||||||
|
|
||||||
@ Flush caches
|
|
||||||
ldr r0, =0xFFFF0830
|
|
||||||
blx r0
|
|
||||||
ldr r0, =0xFFFF0AB4
|
|
||||||
blx r0
|
|
||||||
|
|
||||||
@ Enable caches / MPU
|
|
||||||
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
|
||||||
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
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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>
|
|
||||||
|
|
||||||
//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;
|
|
@ -277,10 +277,10 @@ static u8 nandSlot;
|
|||||||
static u32 fatStart;
|
static u32 fatStart;
|
||||||
__attribute__((aligned(4))) const u8 key2s[5][AES_BLOCK_SIZE] = {
|
__attribute__((aligned(4))) const u8 key2s[5][AES_BLOCK_SIZE] = {
|
||||||
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
|
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
|
||||||
{0x08, 0x24, 0xD3, 0xCB, 0x4A, 0xE9, 0x4D, 0x62, 0x4D, 0xAA, 0x52, 0x60, 0x47, 0xC5, 0x93, 0x94},
|
{0xA5, 0x25, 0x87, 0x11, 0x8F, 0x42, 0x9F, 0x3D, 0x65, 0x1D, 0xDD, 0x58, 0x0B, 0x6D, 0xF2, 0x17},
|
||||||
{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},
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xF5, 0xF6},
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xF5, 0xF6},
|
||||||
{0xA5, 0x25, 0x87, 0x11, 0x8F, 0x42, 0x9F, 0x3D, 0x65, 0x1D, 0xDD, 0x58, 0x0B, 0x6D, 0xF2, 0x17}
|
{0x08, 0x24, 0xD3, 0xCB, 0x4A, 0xE9, 0x4D, 0x62, 0x4D, 0xAA, 0x52, 0x60, 0x47, 0xC5, 0x93, 0x94}
|
||||||
},
|
},
|
||||||
devKey2s[2][AES_BLOCK_SIZE] = {
|
devKey2s[2][AES_BLOCK_SIZE] = {
|
||||||
{0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25},
|
{0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25},
|
||||||
@ -383,7 +383,7 @@ void generateSector(u8 *keySector, u32 mode)
|
|||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
memcpy(keySector + AES_BLOCK_SIZE, keySector, AES_BLOCK_SIZE);
|
memcpy(keySector + AES_BLOCK_SIZE, keySector, AES_BLOCK_SIZE);
|
||||||
break;
|
return;
|
||||||
case 2:
|
case 2:
|
||||||
memcpy(keySector + AES_BLOCK_SIZE, !ISDEVUNIT ? key2s[0] : devKey2s[0], AES_BLOCK_SIZE);
|
memcpy(keySector + AES_BLOCK_SIZE, !ISDEVUNIT ? key2s[0] : devKey2s[0], AES_BLOCK_SIZE);
|
||||||
break;
|
break;
|
||||||
@ -392,13 +392,10 @@ void generateSector(u8 *keySector, u32 mode)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode != 1)
|
//Encrypt key sector
|
||||||
{
|
aes_use_keyslot(0x11);
|
||||||
//Encrypt key sector
|
for(u32 i = 0; i < 32; i++)
|
||||||
aes_use_keyslot(0x11);
|
aes(keySector + (AES_BLOCK_SIZE * i), keySector + (AES_BLOCK_SIZE * i), 1, NULL, AES_ECB_ENCRYPT_MODE, 0);
|
||||||
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)
|
||||||
@ -406,13 +403,12 @@ void getSector(u8 *keySector)
|
|||||||
//Read keysector from NAND
|
//Read keysector from NAND
|
||||||
sdmmc_nand_readsectors(0x96, 1, keySector);
|
sdmmc_nand_readsectors(0x96, 1, keySector);
|
||||||
|
|
||||||
if(ISA9LH || ISDEVUNIT)
|
if(!ISA9LH && !ISDEVUNIT) return;
|
||||||
{
|
|
||||||
//Decrypt key sector
|
//Decrypt key sector
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
for(u32 i = 0; i < 32; i++)
|
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);
|
aes(keySector + (AES_BLOCK_SIZE * i), keySector + (AES_BLOCK_SIZE * i), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verifyHash(const void *data, u32 size, const u8 *hash)
|
bool verifyHash(const void *data, u32 size, const u8 *hash)
|
||||||
@ -427,23 +423,22 @@ u32 decryptExeFs(Cxi *cxi)
|
|||||||
{
|
{
|
||||||
u32 exeFsSize = 0;
|
u32 exeFsSize = 0;
|
||||||
|
|
||||||
if(memcmp(cxi->ncch.magic, "NCCH", 4) == 0)
|
if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return exeFsSize;
|
||||||
{
|
|
||||||
u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200;
|
|
||||||
exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200;
|
|
||||||
__attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0};
|
|
||||||
|
|
||||||
for(u32 i = 0; i < 8; i++)
|
u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200;
|
||||||
ncchCtr[7 - i] = cxi->ncch.partitionId[i];
|
exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200;
|
||||||
ncchCtr[8] = 2;
|
__attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0};
|
||||||
|
|
||||||
aes_setkey(0x2C, cxi, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
for(u32 i = 0; i < 8; i++)
|
||||||
aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
ncchCtr[7 - i] = cxi->ncch.partitionId[i];
|
||||||
aes_use_keyslot(0x2C);
|
ncchCtr[8] = 2;
|
||||||
aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
|
|
||||||
if(memcmp(cxi, "FIRM", 4) != 0) exeFsSize = 0;
|
aes_setkey(0x2C, cxi, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_use_keyslot(0x2C);
|
||||||
|
aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
|
if(memcmp(cxi, "FIRM", 4) != 0) exeFsSize = 0;
|
||||||
|
|
||||||
return exeFsSize;
|
return exeFsSize;
|
||||||
}
|
}
|
@ -472,10 +472,11 @@ void sdmmc_get_cid(bool isNand, u32 *info)
|
|||||||
sdmmc_send_command(device, 0x10507, device->initarg << 0x10);
|
sdmmc_send_command(device, 0x10507, device->initarg << 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sdmmc_sdcard_init(bool isOtpless)
|
bool sdmmc_sdcard_init(bool initSd, bool initNand)
|
||||||
{
|
{
|
||||||
InitSD();
|
InitSD();
|
||||||
int nand_ret = Nand_Init();
|
int ret = 0;
|
||||||
if(isOtpless) return true;
|
if(initNand) ret |= Nand_Init();
|
||||||
return (nand_ret | SD_Init()) == 0;
|
if(initSd) ret |= SD_Init();
|
||||||
|
return ret == 0;
|
||||||
}
|
}
|
@ -91,7 +91,7 @@ typedef struct mmcdevice {
|
|||||||
u32 res;
|
u32 res;
|
||||||
} mmcdevice;
|
} mmcdevice;
|
||||||
|
|
||||||
bool sdmmc_sdcard_init(bool isOtpless);
|
bool sdmmc_sdcard_init(bool initSd, bool initNand);
|
||||||
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||||
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
|
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
|
||||||
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||||
|
90
source/fs.c
90
source/fs.c
@ -40,16 +40,14 @@ void unmountCtrNand(void)
|
|||||||
u32 fileRead(void *dest, const char *path, u32 maxSize)
|
u32 fileRead(void *dest, const char *path, u32 maxSize)
|
||||||
{
|
{
|
||||||
FIL file;
|
FIL file;
|
||||||
u32 ret;
|
u32 ret = 0;
|
||||||
|
|
||||||
if(f_open(&file, path, FA_READ) != FR_OK) ret = 0;
|
if(f_open(&file, path, FA_READ) != FR_OK) return ret;
|
||||||
else
|
|
||||||
{
|
u32 size = f_size(&file);
|
||||||
u32 size = f_size(&file);
|
if(size <= maxSize)
|
||||||
if(size <= maxSize)
|
f_read(&file, dest, size, (unsigned int *)&ret);
|
||||||
f_read(&file, dest, size, (unsigned int *)&ret);
|
f_close(&file);
|
||||||
f_close(&file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -57,7 +55,6 @@ u32 fileRead(void *dest, const char *path, u32 maxSize)
|
|||||||
bool fileWrite(const void *buffer, const char *path, u32 size)
|
bool fileWrite(const void *buffer, const char *path, u32 size)
|
||||||
{
|
{
|
||||||
FIL file;
|
FIL file;
|
||||||
bool ret;
|
|
||||||
|
|
||||||
switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS))
|
switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS))
|
||||||
{
|
{
|
||||||
@ -68,8 +65,7 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
|
|||||||
f_truncate(&file);
|
f_truncate(&file);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
|
|
||||||
ret = (u32)written == size;
|
return (u32)written == size;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case FR_NO_PATH:
|
case FR_NO_PATH:
|
||||||
for(u32 i = 1; path[i] != 0; i++)
|
for(u32 i = 1; path[i] != 0; i++)
|
||||||
@ -81,19 +77,20 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
|
|||||||
f_mkdir(folder);
|
f_mkdir(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fileWrite(buffer, path, size);
|
return fileWrite(buffer, path, size);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ret = false;
|
return false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
void fileDelete(const char *path)
|
||||||
|
{
|
||||||
|
f_unlink(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 firmRead(void *dest)
|
u32 firmRead(void *dest)
|
||||||
{
|
{
|
||||||
const char *firmFolders[] = { "00000002", "20000002" };
|
const char *firmFolders[] = {"00000002", "20000002"};
|
||||||
char path[48] = "1:/title/00040138/";
|
char path[48] = "1:/title/00040138/";
|
||||||
concatenateStrings(path, firmFolders[ISN3DS ? 1 : 0]);
|
concatenateStrings(path, firmFolders[ISN3DS ? 1 : 0]);
|
||||||
concatenateStrings(path, "/content");
|
concatenateStrings(path, "/content");
|
||||||
@ -103,42 +100,41 @@ u32 firmRead(void *dest)
|
|||||||
u32 firmVersion = 0xFFFFFFFF,
|
u32 firmVersion = 0xFFFFFFFF,
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
if(f_opendir(&dir, path) == FR_OK)
|
if(f_opendir(&dir, path) != FR_OK) goto exit;
|
||||||
|
|
||||||
|
FILINFO info;
|
||||||
|
|
||||||
|
//Parse the target directory
|
||||||
|
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
|
||||||
{
|
{
|
||||||
FILINFO info;
|
//Not a cxi
|
||||||
|
if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue;
|
||||||
|
|
||||||
//Parse the target directory
|
//Multiple cxis were found
|
||||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
|
if(firmVersion != 0xFFFFFFFF) ret = 1;
|
||||||
{
|
|
||||||
//Not a cxi
|
|
||||||
if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue;
|
|
||||||
|
|
||||||
//Multiple cxis were found
|
u32 tempVersion = hexAtoi(info.altname, 8);
|
||||||
if(firmVersion != 0xFFFFFFFF) ret = 1;
|
|
||||||
|
|
||||||
u32 tempVersion = hexAtoi(info.altname, 8);
|
//FIRM is equal or newer than 11.0
|
||||||
|
if(!ISDEVUNIT && tempVersion >= (ISN3DS ? 0x21 : 0x52)) ret = tempVersion <= (ISN3DS ? 0x28 : 0x58) ? 5 : 2;
|
||||||
|
|
||||||
//FIRM is equal or newer than 11.0
|
//Found an older cxi
|
||||||
if(!ISDEVUNIT && tempVersion >= (ISN3DS ? 0x21 : 0x52)) ret = tempVersion <= (ISN3DS ? 0x28 : 0x58) ? 5 : 2;
|
if(tempVersion < firmVersion) firmVersion = tempVersion;
|
||||||
|
|
||||||
//Found an older cxi
|
|
||||||
if(tempVersion < firmVersion) firmVersion = tempVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
f_closedir(&dir);
|
|
||||||
|
|
||||||
if(ret != 1 && firmVersion != 0xFFFFFFFF)
|
|
||||||
{
|
|
||||||
//Complete the string with the .app name
|
|
||||||
concatenateStrings(path, "/00000000.app");
|
|
||||||
|
|
||||||
//Convert back the .app name from integer to array
|
|
||||||
hexItoa(firmVersion, path + 35, 8);
|
|
||||||
|
|
||||||
if(!fileRead(dest, path, 0x100000)) ret = 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f_closedir(&dir);
|
||||||
|
|
||||||
|
if(ret == 1 || firmVersion == 0xFFFFFFFF) goto exit;
|
||||||
|
|
||||||
|
//Complete the string with the .app name
|
||||||
|
concatenateStrings(path, "/00000000.app");
|
||||||
|
|
||||||
|
//Convert back the .app name from integer to array
|
||||||
|
hexItoa(firmVersion, path + 35, 8);
|
||||||
|
|
||||||
|
if(!fileRead(dest, path, 0x100000)) ret = 3;
|
||||||
|
|
||||||
|
exit:
|
||||||
if(firmVersion == 0xFFFFFFFF) ret = 4;
|
if(firmVersion == 0xFFFFFFFF) ret = 4;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -28,4 +28,5 @@ bool mountFs(bool isSd);
|
|||||||
void unmountCtrNand(void);
|
void unmountCtrNand(void);
|
||||||
u32 fileRead(void *dest, const char *path, u32 maxSize);
|
u32 fileRead(void *dest, const char *path, u32 maxSize);
|
||||||
bool fileWrite(const void *buffer, const char *path, u32 size);
|
bool fileWrite(const void *buffer, const char *path, u32 size);
|
||||||
|
void fileDelete(const char *path);
|
||||||
u32 firmRead(void *dest);
|
u32 firmRead(void *dest);
|
@ -11,7 +11,6 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "installer.h"
|
#include "installer.h"
|
||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
#include "../build/bundled.h"
|
|
||||||
|
|
||||||
static const u8 sectorHashRetail[SHA_256_HASH_SIZE] = {
|
static const u8 sectorHashRetail[SHA_256_HASH_SIZE] = {
|
||||||
0x82, 0xF2, 0x73, 0x0D, 0x2C, 0x2D, 0xA3, 0xF3, 0x01, 0x65, 0xF9, 0x87, 0xFD, 0xCC, 0xAC, 0x5C,
|
0x82, 0xF2, 0x73, 0x0D, 0x2C, 0x2D, 0xA3, 0xF3, 0x01, 0x65, 0xF9, 0x87, 0xFD, 0xCC, 0xAC, 0x5C,
|
||||||
@ -29,13 +28,9 @@ static const u8 sectorHashRetail[SHA_256_HASH_SIZE] = {
|
|||||||
0x68, 0x52, 0xCC, 0x21, 0x89, 0xAE, 0x28, 0x38, 0x1A, 0x75, 0x90, 0xE7, 0x38, 0x23, 0x48, 0x41,
|
0x68, 0x52, 0xCC, 0x21, 0x89, 0xAE, 0x28, 0x38, 0x1A, 0x75, 0x90, 0xE7, 0x38, 0x23, 0x48, 0x41,
|
||||||
0x8E, 0x80, 0x78, 0x75, 0x27, 0x64, 0x04, 0xD6, 0x28, 0xD6, 0xFA, 0x39, 0xA8, 0x6F, 0xB0, 0x3F
|
0x8E, 0x80, 0x78, 0x75, 0x27, 0x64, 0x04, 0xD6, 0x28, 0xD6, 0xFA, 0x39, 0xA8, 0x6F, 0xB0, 0x3F
|
||||||
},
|
},
|
||||||
firm0100Hash[SHA_256_HASH_SIZE] = {
|
firm1HashRetail[SHA_256_HASH_SIZE] = {
|
||||||
0xD8, 0x2D, 0xB7, 0xB4, 0x38, 0x2B, 0x07, 0x88, 0x99, 0x77, 0x91, 0x0C, 0xC6, 0xEC, 0x6D, 0x87,
|
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
|
0x7D, 0x21, 0x79, 0x23, 0xD7, 0x60, 0xAF, 0x4E, 0x8B, 0x3A, 0xAB, 0xB2, 0x63, 0xE4, 0x21, 0xC6
|
||||||
},
|
|
||||||
firm1HashRetail[SHA_256_HASH_SIZE] = {
|
|
||||||
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
|
|
||||||
},
|
},
|
||||||
firm104O3DSHash[SHA_256_HASH_SIZE] = {
|
firm104O3DSHash[SHA_256_HASH_SIZE] = {
|
||||||
0x5D, 0x33, 0xD9, 0xCE, 0xE3, 0x39, 0x05, 0xD5, 0xCE, 0x37, 0xFE, 0xFB, 0xB5, 0xEC, 0x73, 0x6A,
|
0x5D, 0x33, 0xD9, 0xCE, 0xE3, 0x39, 0x05, 0xD5, 0xCE, 0x37, 0xFE, 0xFB, 0xB5, 0xEC, 0x73, 0x6A,
|
||||||
@ -62,11 +57,12 @@ static const u8 sectorHashRetail[SHA_256_HASH_SIZE] = {
|
|||||||
0xF2, 0x38, 0x14, 0x58, 0x10, 0x83, 0x56, 0x4F, 0x0D, 0x5A, 0xDB, 0x29, 0x12, 0xD8, 0xA9, 0x84
|
0xF2, 0x38, 0x14, 0x58, 0x10, 0x83, 0x56, 0x4F, 0x0D, 0x5A, 0xDB, 0x29, 0x12, 0xD8, 0xA9, 0x84
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static vu32 *otplessOffset = (vu32 *)0x80FD0FC;
|
||||||
u32 posY;
|
u32 posY;
|
||||||
|
|
||||||
static void drawTitle(bool isOtpless)
|
static void drawTitle(void)
|
||||||
{
|
{
|
||||||
initScreens(isOtpless);
|
initScreens();
|
||||||
|
|
||||||
posY = drawString(TITLE, 10, 10, COLOR_TITLE);
|
posY = drawString(TITLE, 10, 10, COLOR_TITLE);
|
||||||
posY = drawString("Thanks to delebile, #cakey and StandardBus", 10, posY + SPACING_Y, COLOR_WHITE);
|
posY = drawString("Thanks to delebile, #cakey and StandardBus", 10, posY + SPACING_Y, COLOR_WHITE);
|
||||||
@ -74,11 +70,11 @@ static void drawTitle(bool isOtpless)
|
|||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
bool isOtpless = ISA9LH && magic == 0xDEADCAFE;
|
bool isOtpless = ISA9LH && otplessOffset[0] == 0xEAFE4AA3 && otplessOffset[1] == 0xDEADCAFE;
|
||||||
|
|
||||||
if(!isOtpless) drawTitle(false);
|
if(!isOtpless) drawTitle();
|
||||||
|
|
||||||
if(!sdmmc_sdcard_init(isOtpless))
|
if(!sdmmc_sdcard_init(!isOtpless, true) && !isOtpless)
|
||||||
shutdown(1, "Error: failed to initialize SD and NAND");
|
shutdown(1, "Error: failed to initialize SD and NAND");
|
||||||
|
|
||||||
u32 pressed;
|
u32 pressed;
|
||||||
@ -191,15 +187,6 @@ static inline void installer(bool isOtpless)
|
|||||||
|
|
||||||
if(!ISA9LH || updateKey2 || isOtpless) generateSector(keySector, (!ISA9LH && ISN3DS && !ISDEVUNIT) ? 1 : 0);
|
if(!ISA9LH || updateKey2 || isOtpless) generateSector(keySector, (!ISA9LH && ISN3DS && !ISDEVUNIT) ? 1 : 0);
|
||||||
|
|
||||||
if(!ISA9LH && ISN3DS && !ISDEVUNIT)
|
|
||||||
{
|
|
||||||
//Read 10.0 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ISA9LH || updateFirm0)
|
if(!ISA9LH || updateFirm0)
|
||||||
{
|
{
|
||||||
//Read FIRM0
|
//Read FIRM0
|
||||||
@ -218,6 +205,9 @@ static inline void installer(bool isOtpless)
|
|||||||
shutdown(1, "Error: firm1.bin is invalid or corrupted");
|
shutdown(1, "Error: firm1.bin is invalid or corrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!ISA9LH && ISN3DS && !ISDEVUNIT && !fileWrite((void *)0x23F00000, "arm9loaderhax.bin", 0x10000))
|
||||||
|
shutdown(1, "Error: couldn't write arm9loaderhax.bin");
|
||||||
|
|
||||||
if(!isOtpless)
|
if(!isOtpless)
|
||||||
{
|
{
|
||||||
bool missingStage1Hash,
|
bool missingStage1Hash,
|
||||||
@ -274,23 +264,24 @@ static inline void installer(bool isOtpless)
|
|||||||
|
|
||||||
if(!ISA9LH || updateFirm1) writeFirm((u8 *)FIRM1_OFFSET, true, FIRM1_SIZE);
|
if(!ISA9LH || updateFirm1) writeFirm((u8 *)FIRM1_OFFSET, true, FIRM1_SIZE);
|
||||||
if(!ISA9LH || updateKey2 || isOtpless) sdmmc_nand_writesectors(0x96, 1, keySector);
|
if(!ISA9LH || updateKey2 || isOtpless) sdmmc_nand_writesectors(0x96, 1, keySector);
|
||||||
|
if(!isOtpless) writeFirm((u8 *)FIRM0_OFFSET, false, FIRM0_SIZE);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
otplessOffset[0] = otplessOffset[1] = 0;
|
||||||
|
sdmmc_sdcard_init(true, false);
|
||||||
|
mountFs(true);
|
||||||
|
fileDelete("arm9loaderhax.bin");
|
||||||
|
drawTitle();
|
||||||
|
}
|
||||||
|
|
||||||
if(!ISA9LH && ISN3DS && !ISDEVUNIT)
|
if(!ISA9LH && ISN3DS && !ISDEVUNIT)
|
||||||
{
|
{
|
||||||
const u8 ldrAndBranch[] = {0x00, 0x00, 0x9F, 0xE5, 0x10, 0xFF, 0x2F, 0xE1, 0x00, 0x80, 0xFF, 0x01};
|
otplessOffset[0] = 0xEAFE4AA3;
|
||||||
|
otplessOffset[1] = 0xDEADCAFE;
|
||||||
memcpy((void *)0x80FD0FC, ldrAndBranch, sizeof(ldrAndBranch));
|
|
||||||
memcpy((void *)0x1FF8000, loader_bin, loader_bin_size);
|
|
||||||
|
|
||||||
writeFirm((u8 *)FIRM0_100_OFFSET, false, FIRM0100_SIZE);
|
|
||||||
|
|
||||||
mcuReboot();
|
mcuReboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFirm((u8 *)FIRM0_OFFSET, false, FIRM0_SIZE);
|
|
||||||
|
|
||||||
if(isOtpless) drawTitle(true);
|
|
||||||
|
|
||||||
shutdown(2, ISA9LH && !isOtpless ? "Update: success!" : "Full install: success!");
|
shutdown(2, ISA9LH && !isOtpless ? "Update: success!" : "Full install: success!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,18 +9,15 @@
|
|||||||
#define OTP_FROM_MEM 0x10012000
|
#define OTP_FROM_MEM 0x10012000
|
||||||
#define FIRM0_OFFSET 0x24000000
|
#define FIRM0_OFFSET 0x24000000
|
||||||
#define SECTION2_POSITION 0x66A00
|
#define SECTION2_POSITION 0x66A00
|
||||||
#define FIRM0_100_OFFSET 0x24100000
|
#define FIRM1_OFFSET 0x24100000
|
||||||
#define FIRM1_OFFSET 0x24200000
|
|
||||||
#define FIRM0_SIZE 0xF3000
|
#define FIRM0_SIZE 0xF3000
|
||||||
#define FIRM0100_SIZE 0xF2000
|
|
||||||
#define FIRM1_SIZE 0xF2000
|
#define FIRM1_SIZE 0xF2000
|
||||||
#define STAGE1_POSITION 0xF0590
|
#define STAGE1_POSITION 0xF0590
|
||||||
#define STAGE1_OFFSET FIRM0_OFFSET + STAGE1_POSITION
|
#define STAGE1_OFFSET FIRM0_OFFSET + STAGE1_POSITION
|
||||||
#define STAGE2_OFFSET 0x24300000
|
#define STAGE2_OFFSET 0x24200000
|
||||||
#define MAX_STAGE1_SIZE 0x1E70
|
#define MAX_STAGE1_SIZE 0x1E70
|
||||||
#define MAX_STAGE2_SIZE 0x89A00
|
#define MAX_STAGE2_SIZE 0x89A00
|
||||||
|
|
||||||
extern u32 magic;
|
|
||||||
extern const u8 key2s[5][AES_BLOCK_SIZE],
|
extern const u8 key2s[5][AES_BLOCK_SIZE],
|
||||||
devKey2s[2][AES_BLOCK_SIZE];
|
devKey2s[2][AES_BLOCK_SIZE];
|
||||||
|
|
||||||
|
@ -39,21 +39,9 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "../build/bundled.h"
|
|
||||||
|
|
||||||
vu32 *arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY;
|
vu32 *arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY;
|
||||||
|
|
||||||
static inline void ownArm11(void)
|
|
||||||
{
|
|
||||||
memcpy((void *)A11_PAYLOAD_LOC, arm11_bin, arm11_bin_size);
|
|
||||||
|
|
||||||
*arm11Entry = 1;
|
|
||||||
*(vu32 *)0x1FFAED80 = 0xE51FF004;
|
|
||||||
*(vu32 *)0x1FFAED84 = A11_PAYLOAD_LOC;
|
|
||||||
*(vu8 *)0x1FFFFFF0 = 2;
|
|
||||||
while(*arm11Entry != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void invokeArm11Function(void (*func)())
|
static void invokeArm11Function(void (*func)())
|
||||||
{
|
{
|
||||||
*arm11Entry = (u32)func;
|
*arm11Entry = (u32)func;
|
||||||
@ -87,7 +75,7 @@ void clearScreens(void)
|
|||||||
invokeArm11Function(ARM11);
|
invokeArm11Function(ARM11);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initScreens(bool isOtpless)
|
void initScreens(void)
|
||||||
{
|
{
|
||||||
void __attribute__((naked)) initSequence(void)
|
void __attribute__((naked)) initSequence(void)
|
||||||
{
|
{
|
||||||
@ -195,10 +183,6 @@ void initScreens(bool isOtpless)
|
|||||||
|
|
||||||
if(!ARESCREENSINITED)
|
if(!ARESCREENSINITED)
|
||||||
{
|
{
|
||||||
wait(3ULL);
|
|
||||||
|
|
||||||
if(isOtpless) ownArm11();
|
|
||||||
|
|
||||||
invokeArm11Function(initSequence);
|
invokeArm11Function(initSequence);
|
||||||
|
|
||||||
//Turn on backlight
|
//Turn on backlight
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#define ARESCREENSINITED (PDN_GPU_CNT != 1)
|
#define ARESCREENSINITED (PDN_GPU_CNT != 1)
|
||||||
|
|
||||||
#define BRAHMA_ARM11_ENTRY 0x1FFFFFF8
|
#define BRAHMA_ARM11_ENTRY 0x1FFFFFF8
|
||||||
#define A11_PAYLOAD_LOC 0x1FFF4C80
|
|
||||||
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
|
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
|
||||||
|
|
||||||
#define SCREEN_TOP_WIDTH 400
|
#define SCREEN_TOP_WIDTH 400
|
||||||
@ -49,4 +48,4 @@ static struct fb {
|
|||||||
} *const fb = (struct fb *)0x23FFFE00;
|
} *const fb = (struct fb *)0x23FFFE00;
|
||||||
|
|
||||||
void clearScreens(void);
|
void clearScreens(void);
|
||||||
void initScreens(bool isOtpless);
|
void initScreens(void);
|
@ -24,13 +24,6 @@
|
|||||||
.align 4
|
.align 4
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
b start
|
|
||||||
|
|
||||||
.global magic
|
|
||||||
magic:
|
|
||||||
.word 0
|
|
||||||
|
|
||||||
start:
|
|
||||||
@ Disable interrupts
|
@ Disable interrupts
|
||||||
mrs r0, cpsr
|
mrs r0, cpsr
|
||||||
orr r0, #0x1C0
|
orr r0, #0x1C0
|
||||||
|
@ -8,56 +8,32 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
|
|
||||||
static void startChrono(void)
|
|
||||||
{
|
|
||||||
REG_TIMER_CNT(0) = 0; //67MHz
|
|
||||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
|
|
||||||
|
|
||||||
for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = 0;
|
|
||||||
|
|
||||||
REG_TIMER_CNT(0) = 0x80; //67MHz; enabled
|
|
||||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 chrono(void)
|
|
||||||
{
|
|
||||||
u64 res;
|
|
||||||
for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
|
|
||||||
|
|
||||||
res /= (TICKS_PER_SEC / 1000);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 waitInput(void)
|
u32 waitInput(void)
|
||||||
{
|
{
|
||||||
bool pressedKey = false;
|
|
||||||
u32 key,
|
u32 key,
|
||||||
oldKey = HID_PAD;
|
oldKey = HID_PAD;
|
||||||
|
|
||||||
while(!pressedKey)
|
while(true)
|
||||||
{
|
{
|
||||||
key = HID_PAD;
|
key = HID_PAD;
|
||||||
|
|
||||||
if(!key) oldKey = key;
|
if(!key)
|
||||||
else if(key != oldKey)
|
|
||||||
{
|
{
|
||||||
//Make sure the key is pressed
|
oldKey = 0;
|
||||||
u32 i;
|
continue;
|
||||||
for(i = 0; i < 0x13000 && key == HID_PAD; i++);
|
|
||||||
if(i == 0x13000) pressedKey = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(key == oldKey) continue;
|
||||||
|
|
||||||
|
//Make sure the key is pressed
|
||||||
|
u32 i;
|
||||||
|
for(i = 0; i < 0x13000 && key == HID_PAD; i++);
|
||||||
|
if(i == 0x13000) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait(u64 amount)
|
|
||||||
{
|
|
||||||
startChrono();
|
|
||||||
while(chrono() < amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mcuReboot(void)
|
void mcuReboot(void)
|
||||||
{
|
{
|
||||||
clearScreens();
|
clearScreens();
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
extern u32 posY;
|
extern u32 posY;
|
||||||
|
|
||||||
u32 waitInput(void);
|
u32 waitInput(void);
|
||||||
void wait(u64 amount);
|
|
||||||
void mcuReboot(void);
|
void mcuReboot(void);
|
||||||
void inputSequence(void);
|
void inputSequence(void);
|
||||||
void shutdown(u32 mode, const char *message);
|
void shutdown(u32 mode, const char *message);
|
Loading…
x
Reference in New Issue
Block a user