Begin turning Luma3DS into a proper firm
Unfinished work
This commit is contained in:
parent
8308e1a8b8
commit
53209b9be0
29
Makefile
29
Makefile
@ -12,6 +12,7 @@ commit := $(shell git rev-parse --short=8 HEAD)
|
||||
|
||||
dir_source := source
|
||||
dir_patches := patches
|
||||
dir_arm11 := arm11
|
||||
dir_loader := loader
|
||||
dir_injector := injector
|
||||
dir_exceptions := exceptions
|
||||
@ -29,7 +30,9 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||
|
||||
bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/svcGetCFWInfo.bin.o $(dir_build)/k11modules.bin.o \
|
||||
$(dir_build)/injector.bin.o $(dir_build)/loader.bin.o $(dir_build)/arm9_exceptions.bin.o $(dir_build)/arm11_exceptions.bin.o
|
||||
$(dir_build)/loader.bin.o $(dir_build)/arm9_exceptions.bin.o $(dir_build)/arm11_exceptions.bin.o
|
||||
|
||||
modules = $(dir_build)/injector.cxi
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
@ -46,6 +49,7 @@ firm: $(dir_out)/boot.firm
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(MAKE) -C $(dir_arm11) clean
|
||||
@$(MAKE) -C $(dir_loader) clean
|
||||
@$(MAKE) -C $(dir_arm9_exceptions) clean
|
||||
@$(MAKE) -C $(dir_arm11_exceptions) clean
|
||||
@ -54,6 +58,7 @@ clean:
|
||||
|
||||
.PRECIOUS: $(dir_build)/%.bin
|
||||
|
||||
.PHONY: $(dir_arm11)
|
||||
.PHONY: $(dir_loader)
|
||||
.PHONY: $(dir_arm9_exceptions)
|
||||
.PHONY: $(dir_arm11_exceptions)
|
||||
@ -63,20 +68,28 @@ $(dir_out)/$(name)$(revision).7z: all
|
||||
@mkdir -p "$(@D)"
|
||||
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py
|
||||
|
||||
$(dir_out)/boot.firm: $(dir_build)/main.elf
|
||||
$(dir_out)/boot.firm: $(dir_build)/modules.bin $(dir_build)/arm11.elf $(dir_build)/main.elf
|
||||
@mkdir -p "$(@D)"
|
||||
@firmtool build $@ -e 0 -D $^ -C NDMA
|
||||
@firmtool build $@ -D $^ -A 0x1FF60000 -C XDMA XDMA NDMA
|
||||
|
||||
$(dir_build)/modules.bin: $(modules)
|
||||
@mkdir -p "$(@D)"
|
||||
cat $^ > $@
|
||||
|
||||
$(dir_build)/arm11.elf: $(dir_arm11)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/main.elf: $(bundled) $(objects)
|
||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
|
||||
$(dir_build)/%.bin.o: $(dir_build)/%.bin
|
||||
@$(bin2o)
|
||||
|
||||
$(dir_build)/injector.bin: $(dir_injector)
|
||||
$(dir_build)/injector.cxi: $(dir_injector)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/%.bin.o: $(dir_build)/%.bin
|
||||
@$(bin2o)
|
||||
|
||||
$(dir_build)/loader.bin: $(dir_loader)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
@ -96,6 +109,8 @@ $(dir_build)/%.bin: $(dir_patches)/%.s
|
||||
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
||||
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)"
|
||||
$(dir_build)/firm.o: $(dir_build)/modules.bin
|
||||
$(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell du -b $(dir_build)/modules.bin | cut -f1)"
|
||||
|
||||
$(dir_build)/bundled.h: $(bundled)
|
||||
@$(foreach f, $(bundled),\
|
||||
|
39
arm11/Makefile
Normal file
39
arm11/Makefile
Normal file
@ -0,0 +1,39 @@
|
||||
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)/base_tools
|
||||
|
||||
name := $(shell basename $(CURDIR))
|
||||
|
||||
dir_source := source
|
||||
dir_build := build
|
||||
dir_out := ../$(dir_build)
|
||||
|
||||
ASFLAGS := -mcpu=mpcore
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostdlib -Wl,--nmagic
|
||||
|
||||
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).elf
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
$(dir_out)/$(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) $<
|
14
arm11/linker.ld
Normal file
14
arm11/linker.ld
Normal file
@ -0,0 +1,14 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x1FFFE000;
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
207
arm11/source/main.c
Normal file
207
arm11/source/main.c
Normal file
@ -0,0 +1,207 @@
|
||||
/** This file is part of Luma3DS
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others
|
||||
* LCD deinit code by tiniVi
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "memory.h"
|
||||
|
||||
static volatile Arm11Operation *operation = (volatile Arm11Operation *)0x1FFFFFF0;
|
||||
|
||||
static void initScreensSequence(u32 brightnessLevel)
|
||||
{
|
||||
*(vu32 *)0x10141200 = 0x1007F;
|
||||
*(vu32 *)0x10202014 = 0x00000001;
|
||||
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
*(vu32 *)0x10202244 = 0x1023E;
|
||||
*(vu32 *)0x10202A44 = 0x1023E;
|
||||
|
||||
//Top screen
|
||||
*(vu32 *)0x10400400 = 0x000001c2;
|
||||
*(vu32 *)0x10400404 = 0x000000d1;
|
||||
*(vu32 *)0x10400408 = 0x000001c1;
|
||||
*(vu32 *)0x1040040c = 0x000001c1;
|
||||
*(vu32 *)0x10400410 = 0x00000000;
|
||||
*(vu32 *)0x10400414 = 0x000000cf;
|
||||
*(vu32 *)0x10400418 = 0x000000d1;
|
||||
*(vu32 *)0x1040041c = 0x01c501c1;
|
||||
*(vu32 *)0x10400420 = 0x00010000;
|
||||
*(vu32 *)0x10400424 = 0x0000019d;
|
||||
*(vu32 *)0x10400428 = 0x00000002;
|
||||
*(vu32 *)0x1040042c = 0x00000192;
|
||||
*(vu32 *)0x10400430 = 0x00000192;
|
||||
*(vu32 *)0x10400434 = 0x00000192;
|
||||
*(vu32 *)0x10400438 = 0x00000001;
|
||||
*(vu32 *)0x1040043c = 0x00000002;
|
||||
*(vu32 *)0x10400440 = 0x01960192;
|
||||
*(vu32 *)0x10400444 = 0x00000000;
|
||||
*(vu32 *)0x10400448 = 0x00000000;
|
||||
*(vu32 *)0x1040045C = 0x00f00190;
|
||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
||||
*(vu32 *)0x10400464 = 0x01920002;
|
||||
*(vu32 *)0x10400468 = 0x18300000;
|
||||
*(vu32 *)0x10400470 = 0x80341;
|
||||
*(vu32 *)0x10400474 = 0x00010501;
|
||||
*(vu32 *)0x10400478 = 0;
|
||||
*(vu32 *)0x10400490 = 0x000002D0;
|
||||
*(vu32 *)0x1040049C = 0x00000000;
|
||||
|
||||
//Disco register
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
*(vu32 *)0x10400484 = 0x10101 * i;
|
||||
|
||||
//Bottom screen
|
||||
*(vu32 *)0x10400500 = 0x000001c2;
|
||||
*(vu32 *)0x10400504 = 0x000000d1;
|
||||
*(vu32 *)0x10400508 = 0x000001c1;
|
||||
*(vu32 *)0x1040050c = 0x000001c1;
|
||||
*(vu32 *)0x10400510 = 0x000000cd;
|
||||
*(vu32 *)0x10400514 = 0x000000cf;
|
||||
*(vu32 *)0x10400518 = 0x000000d1;
|
||||
*(vu32 *)0x1040051c = 0x01c501c1;
|
||||
*(vu32 *)0x10400520 = 0x00010000;
|
||||
*(vu32 *)0x10400524 = 0x0000019d;
|
||||
*(vu32 *)0x10400528 = 0x00000052;
|
||||
*(vu32 *)0x1040052c = 0x00000192;
|
||||
*(vu32 *)0x10400530 = 0x00000192;
|
||||
*(vu32 *)0x10400534 = 0x0000004f;
|
||||
*(vu32 *)0x10400538 = 0x00000050;
|
||||
*(vu32 *)0x1040053c = 0x00000052;
|
||||
*(vu32 *)0x10400540 = 0x01980194;
|
||||
*(vu32 *)0x10400544 = 0x00000000;
|
||||
*(vu32 *)0x10400548 = 0x00000011;
|
||||
*(vu32 *)0x1040055C = 0x00f00140;
|
||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
||||
*(vu32 *)0x10400564 = 0x01920052;
|
||||
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
||||
*(vu32 *)0x10400570 = 0x80301;
|
||||
*(vu32 *)0x10400574 = 0x00010501;
|
||||
*(vu32 *)0x10400578 = 0;
|
||||
*(vu32 *)0x10400590 = 0x000002D0;
|
||||
*(vu32 *)0x1040059C = 0x00000000;
|
||||
|
||||
//Disco register
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
*(vu32 *)0x10400584 = 0x10101 * i;
|
||||
}
|
||||
|
||||
static void setupFramebuffers(struct fb *fbs)
|
||||
{
|
||||
*(vu32 *)0x10400468 = (u32)fbs[0].top_left;
|
||||
*(vu32 *)0x1040046c = (u32)fbs[1].top_left;
|
||||
*(vu32 *)0x10400494 = (u32)fbs[0].top_right;
|
||||
*(vu32 *)0x10400498 = (u32)fbs[1].top_right;
|
||||
*(vu32 *)0x10400568 = (u32)fbs[0].bottom;
|
||||
*(vu32 *)0x1040056c = (u32)fbs[1].bottom;
|
||||
}
|
||||
|
||||
static void clearScreens(struct fb *fb)
|
||||
{
|
||||
//Setting up two simultaneous memory fills using the GPU
|
||||
|
||||
vu32 *REGs_PSC0 = (vu32 *)0x10400010,
|
||||
*REGs_PSC1 = (vu32 *)0x10400020;
|
||||
|
||||
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address
|
||||
REGs_PSC0[1] = (u32)(fb->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address
|
||||
REGs_PSC0[2] = 0; //Fill value
|
||||
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address
|
||||
REGs_PSC1[1] = (u32)(fb->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address
|
||||
REGs_PSC1[2] = 0; //Fill value
|
||||
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
|
||||
}
|
||||
|
||||
static void swapFramebuffers(bool isAlternate)
|
||||
{
|
||||
u32 isAlternateTmp = isAlternate ? 1 : 0;
|
||||
*(vu32 *)0x10400478 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp;
|
||||
*(vu32 *)0x10400578 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp;
|
||||
}
|
||||
|
||||
static void updateBrightness(u32 brightnessLevel)
|
||||
{
|
||||
//Change brightness
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
}
|
||||
|
||||
static void deinitScreens(void)
|
||||
{
|
||||
//Shutdown LCDs
|
||||
*(vu32 *)0x10202A44 = 0;
|
||||
*(vu32 *)0x10202244 = 0;
|
||||
*(vu32 *)0x10202014 = 0;
|
||||
}
|
||||
|
||||
static void prepareForFirmlaunch(void)
|
||||
{
|
||||
*ARM11_CORE0_MAILBOX_ENTRYPOINT = 0;
|
||||
while(*ARM11_CORE0_MAILBOX_ENTRYPOINT == 0);
|
||||
((void (*)(void))*ARM11_CORE0_MAILBOX_ENTRYPOINT)();
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
*operation = NO_ARM11_OPERATION;
|
||||
|
||||
while(true)
|
||||
{
|
||||
switch(*operation)
|
||||
{
|
||||
case NO_ARM11_OPERATION:
|
||||
break;
|
||||
case INIT_SCREENS_SEQUENCE:
|
||||
initScreensSequence(*(vu32 *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case SETUP_FRAMEBUFFERS:
|
||||
setupFramebuffers((struct fb *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case CLEAR_SCREENS:
|
||||
clearScreens((struct fb *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case SWAP_FRAMEBUFFERS:
|
||||
swapFramebuffers(*(volatile bool *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case UPDATE_BRIGHTNESS:
|
||||
updateBrightness(*(vu32 *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case DEINIT_SCREENS:
|
||||
deinitScreens();
|
||||
break;
|
||||
case PREPARE_ARM11_FOR_FIRMLAUNCH:
|
||||
memcpy((void *)0x1FFFFC00, (void *)prepareForFirmlaunch, 0x2C);
|
||||
*operation = NO_ARM11_OPERATION;
|
||||
((void (*)(void))0x1FFFFC00)();
|
||||
break;
|
||||
}
|
||||
|
||||
*operation = NO_ARM11_OPERATION;
|
||||
}
|
||||
}
|
36
arm11/source/memory.c
Normal file
36
arm11/source/memory.c
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.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];
|
||||
}
|
31
arm11/source/memory.h
Normal file
31
arm11/source/memory.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void memcpy(void *dest, const void *src, u32 size);
|
27
arm11/source/start.s
Normal file
27
arm11/source/start.s
Normal file
@ -0,0 +1,27 @@
|
||||
@ This file is part of Luma3DS
|
||||
@ Copyright (C) 2017 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.
|
||||
|
||||
.section .text.start
|
||||
.align 4
|
||||
.global _start
|
||||
_start:
|
||||
cpsid aif
|
||||
ldr sp, =0x1FFFE000
|
||||
b main
|
62
arm11/source/types.h
Normal file
62
arm11/source/types.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2017 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 <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;
|
||||
|
||||
#define SCREEN_TOP_WIDTH 400
|
||||
#define SCREEN_BOTTOM_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
|
||||
#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
|
||||
#define ARM11_CORE0_MAILBOX_ENTRYPOINT ((vu32 *)0x1FFFFFFC)
|
||||
#define ARM11_PARAMETERS_ADDRESS 0x1FFFC000
|
||||
|
||||
struct fb {
|
||||
u8 *top_left;
|
||||
u8 *top_right;
|
||||
u8 *bottom;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NO_ARM11_OPERATION = 0,
|
||||
INIT_SCREENS_SEQUENCE,
|
||||
SETUP_FRAMEBUFFERS,
|
||||
CLEAR_SCREENS,
|
||||
SWAP_FRAMEBUFFERS,
|
||||
UPDATE_BRIGHTNESS,
|
||||
DEINIT_SCREENS,
|
||||
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
||||
} Arm11Operation;
|
@ -33,7 +33,7 @@ define bin2o
|
||||
endef
|
||||
|
||||
.PHONY: all
|
||||
all: $(dir_out)/$(name).bin
|
||||
all: $(dir_out)/$(name).cxi
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@ -41,10 +41,7 @@ clean:
|
||||
|
||||
.PRECIOUS: $(dir_build)/%.bin
|
||||
|
||||
$(dir_build):
|
||||
@mkdir -p "$@"
|
||||
|
||||
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
||||
$(dir_out)/$(name).cxi: $(dir_build)/$(name).elf
|
||||
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
|
||||
|
||||
$(dir_build)/$(name).elf: $(bundled) $(objects)
|
||||
|
@ -4,7 +4,7 @@ OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x23F00000;
|
||||
. = 0x08006000;
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
|
@ -30,12 +30,12 @@ void launchFirm(Firm *firm, int argc, char **argv)
|
||||
for(u32 sectionNum = 0; sectionNum < 4 && firm->section[sectionNum].size != 0; sectionNum++)
|
||||
memcpy(firm->section[sectionNum].address, (u8 *)firm + firm->section[sectionNum].offset, firm->section[sectionNum].size);
|
||||
|
||||
//Set ARM11 entrypoint
|
||||
*(vu32 *)0x1FFFFFFC = (u32)firm->arm11Entry;
|
||||
|
||||
//Ensure that all memory transfers have completed and that the caches have been flushed
|
||||
flushCaches();
|
||||
|
||||
//Set ARM11 entrypoint
|
||||
*(vu32 *)0x1FFFFFFC = (u32)firm->arm11Entry;
|
||||
|
||||
//Jump to ARM9 entrypoint. Also give it additional arguments it can dismiss
|
||||
((void (*)(int, char**, u32))firm->arm9Entry)(argc, argv, 0x0000BEEF);
|
||||
|
||||
|
250
source/firm.c
250
source/firm.c
@ -38,11 +38,11 @@
|
||||
static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||
{
|
||||
const char *firmwareFiles[] = {
|
||||
"firmware.bin",
|
||||
"firmware_twl.bin",
|
||||
"firmware_agb.bin",
|
||||
"firmware_safe.bin",
|
||||
"firmware_sysupdater.bin"
|
||||
"native.firm",
|
||||
"twl.firm",
|
||||
"agb.firm",
|
||||
"safe.firm",
|
||||
"sysupdater.firm"
|
||||
},
|
||||
*cetkFiles[] = {
|
||||
"cetk",
|
||||
@ -74,6 +74,93 @@ static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
||||
{
|
||||
u32 maxModuleSize = firmType == NATIVE_FIRM ? 0x60000 : 0x600000,
|
||||
srcModuleSize;
|
||||
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
||||
|
||||
u32 nbModules = 0;
|
||||
u32 nbCustomModules = 0;
|
||||
struct
|
||||
{
|
||||
char name[8];
|
||||
u8 *src;
|
||||
u32 size;
|
||||
} moduleList[8];
|
||||
|
||||
//1) Parse info concerning Nintendo's modules
|
||||
for(u8 *src = (u8 *)firm + firm->section[0].offset, *srcEnd = src + firm->section[0].size; src < srcEnd; src += srcModuleSize)
|
||||
{
|
||||
memcpy(moduleList[nbModules].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
|
||||
moduleList[nbModules].src = src;
|
||||
srcModuleSize = moduleList[nbModules++].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
}
|
||||
|
||||
//2) Merge that info with our own modules'
|
||||
for(u8 *src = (u8 *)0x1FF60000; src < (u8 *)(0x1FF60000 + LUMA_SECTION0_SIZE); src += srcModuleSize)
|
||||
{
|
||||
const char *name = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
|
||||
|
||||
u32 i;
|
||||
for(i = 0; i < nbModules && memcmp(name, moduleList[i].name, 8) != 0; i++);
|
||||
u32 index = i < nbModules || firmType != NATIVE_FIRM ? i : nbModules + nbCustomModules++;
|
||||
|
||||
memcpy(moduleList[index].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
|
||||
moduleList[index].src = src;
|
||||
srcModuleSize = moduleList[index].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
}
|
||||
|
||||
nbModules += nbCustomModules;
|
||||
|
||||
//4) Read or copy the modules
|
||||
u8 *dst = firm->section[0].address;
|
||||
for(u32 i = 0; i < nbModules; i++)
|
||||
{
|
||||
const char *moduleName = moduleList[i].name;
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
char fileName[24];
|
||||
|
||||
//Read modules from files if they exist
|
||||
sprintf(fileName, "sysmodules/%.8s.cxi", moduleList[i].name);
|
||||
|
||||
u32 dstModuleSize = getFileSize(fileName);
|
||||
|
||||
if(dstModuleSize != 0)
|
||||
{
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
if(dstModuleSize <= sizeof(Cxi) + 0x200 ||
|
||||
fileRead(dst, fileName, dstModuleSize) != dstModuleSize ||
|
||||
memcmp(((Cxi *)dst)->ncch.magic, "NCCH", 4) != 0 ||
|
||||
memcmp(moduleName, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0)
|
||||
error("An external FIRM module is invalid or corrupted.");
|
||||
|
||||
dst += dstModuleSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dst, moduleList[i].src, moduleList[i].size);
|
||||
dst += moduleList[i].size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dst, moduleList[i].src, moduleList[i].size);
|
||||
dst += moduleList[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
//5) Patch NATIVE_FIRM if necessary
|
||||
if(nbCustomModules != 0)
|
||||
{
|
||||
if(patchK11ModuleLoading(firm->section[0].size, dst - firm->section[0].address, nbCustomModules, firm->section[1].address, firm->section[1].size) != 0)
|
||||
error("Failed to inject custom sysmodule");
|
||||
}
|
||||
}
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
|
||||
{
|
||||
//Load FIRM from CTRNAND
|
||||
@ -111,7 +198,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers)
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
|
||||
*arm11Section1 = (u8 *)firm + firm->section[1].offset;
|
||||
@ -209,10 +296,13 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
|
||||
}
|
||||
}
|
||||
|
||||
mergeSection0(NATIVE_FIRM, loadFromStorage);
|
||||
firm->section[0].size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch)
|
||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||
|
||||
@ -242,10 +332,16 @@ u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch)
|
||||
//Apply UNITINFO patch
|
||||
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
mergeSection0(TWL_FIRM, true);
|
||||
firm->section[0].size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchAgbFirm(bool doUnitinfoPatch)
|
||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||
|
||||
@ -270,6 +366,12 @@ u32 patchAgbFirm(bool doUnitinfoPatch)
|
||||
//Apply UNITINFO patch
|
||||
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
mergeSection0(AGB_FIRM, true);
|
||||
firm->section[0].size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -306,85 +408,69 @@ u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void copySection0AndInjectSystemModules(FirmwareType firmType, bool loadFromStorage)
|
||||
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
u32 maxModuleSize = firmType == NATIVE_FIRM ? 0x80000 : 0x600000,
|
||||
srcModuleSize,
|
||||
dstModuleSize;
|
||||
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
||||
|
||||
for(u8 *src = (u8 *)firm + firm->section[0].offset, *srcEnd = src + firm->section[0].size, *dst = firm->section[0].address;
|
||||
src < srcEnd; src += srcModuleSize, dst += dstModuleSize, maxModuleSize -= dstModuleSize)
|
||||
{
|
||||
srcModuleSize = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
const char *moduleName = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
char fileName[24];
|
||||
|
||||
//Read modules from files if they exist
|
||||
sprintf(fileName, "sysmodules/%.8s.cxi", moduleName);
|
||||
|
||||
dstModuleSize = getFileSize(fileName);
|
||||
|
||||
if(dstModuleSize != 0)
|
||||
{
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
if(dstModuleSize <= sizeof(Cxi) + 0x200 ||
|
||||
fileRead(dst, fileName, dstModuleSize) != dstModuleSize ||
|
||||
memcmp(((Cxi *)dst)->ncch.magic, "NCCH", 4) != 0 ||
|
||||
memcmp(moduleName, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0)
|
||||
error("An external FIRM module is invalid or corrupted.");
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const u8 *module;
|
||||
|
||||
if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0)
|
||||
{
|
||||
module = injector_bin;
|
||||
dstModuleSize = injector_bin_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
module = src;
|
||||
dstModuleSize = srcModuleSize;
|
||||
}
|
||||
|
||||
if(dstModuleSize > maxModuleSize) error(extModuleSizeError);
|
||||
|
||||
memcpy(dst, module, dstModuleSize);
|
||||
}
|
||||
if (as <= bs && bs <= ae)
|
||||
return true;
|
||||
else if (bs <= as && as <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void launchFirm(FirmwareType firmType, bool loadFromStorage)
|
||||
bool checkFirmPayload(void)
|
||||
{
|
||||
//Allow module injection and/or inject 3ds_injector on new NATIVE_FIRMs and LGY FIRMs
|
||||
u32 sectionNum;
|
||||
if(firmType == NATIVE_FIRM || (loadFromStorage && (firmType == TWL_FIRM || firmType == AGB_FIRM)))
|
||||
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
|
||||
return false;
|
||||
|
||||
u32 size = 0x200;
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
size += firm->section[i].size;
|
||||
|
||||
bool arm9EpFound = false,
|
||||
arm11EpFound = false;
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
copySection0AndInjectSystemModules(firmType, loadFromStorage);
|
||||
sectionNum = 1;
|
||||
__attribute__((aligned(4))) u8 hash[0x20];
|
||||
|
||||
FirmSection *section = &firm->section[i];
|
||||
|
||||
//Allow empty sections
|
||||
if(section->size == 0)
|
||||
continue;
|
||||
|
||||
if((section->offset < 0x200) ||
|
||||
(section->address + section->size < section->address) || //Overflow check
|
||||
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000 - 0x1000, 0x28000000)) ||
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm + section->offset, (u32)firm + size)))
|
||||
return false;
|
||||
|
||||
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
|
||||
|
||||
if(memcmp(hash, section->hash, 0x20) != 0)
|
||||
return false;
|
||||
|
||||
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
|
||||
arm9EpFound = true;
|
||||
|
||||
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
|
||||
arm11EpFound = true;
|
||||
}
|
||||
else sectionNum = 0;
|
||||
|
||||
//Copy FIRM sections to respective memory locations
|
||||
for(; sectionNum < 4 && firm->section[sectionNum].size != 0; sectionNum++)
|
||||
memcpy(firm->section[sectionNum].address, (u8 *)firm + firm->section[sectionNum].offset, firm->section[sectionNum].size);
|
||||
|
||||
if(!isFirmlaunch) deinitScreens();
|
||||
|
||||
//Set ARM11 kernel entrypoint
|
||||
*ARM11_CORE0_MAILBOX_ENTRYPOINT = (u32)firm->arm11Entry;
|
||||
|
||||
//Ensure that all memory transfers have completed and that the caches have been flushed
|
||||
flushEntireDCache();
|
||||
flushEntireICache();
|
||||
|
||||
//Final jump to ARM9 kernel
|
||||
((void (*)())firm->arm9Entry)();
|
||||
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
|
||||
}
|
||||
|
||||
void launchFirm(int argc, char **argv)
|
||||
{
|
||||
u32 *loaderAddress = (u32 *)0x27FFE000;
|
||||
|
||||
prepareArm11ForFirmlaunch();
|
||||
|
||||
memcpy(loaderAddress, loader_bin, loader_bin_size);
|
||||
|
||||
flushDCacheRange(loaderAddress, loader_bin_size);
|
||||
flushICacheRange(loaderAddress, loader_bin_size);
|
||||
|
||||
((void (*)(int, char **, u32))loaderAddress)(argc, argv, 0x0000BEEF);
|
||||
}
|
||||
|
@ -25,11 +25,14 @@
|
||||
#include "types.h"
|
||||
#include "3dsheaders.h"
|
||||
|
||||
static Firm *const firm = (Firm *const)0x24000000;
|
||||
static Firm *const firm = (Firm *const)0x20001000;
|
||||
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
|
||||
u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch);
|
||||
u32 patchAgbFirm(bool doUnitinfoPatch);
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
|
||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers);
|
||||
void launchFirm(FirmwareType firmType, bool loadFromStorage);
|
||||
|
||||
bool checkFirmPayload(void);
|
||||
void launchFirm(int argc, char **argv);
|
||||
|
||||
|
65
source/fs.c
65
source/fs.c
@ -118,64 +118,10 @@ void fileDelete(const char *path)
|
||||
f_unlink(path);
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
if (as <= bs && bs <= ae)
|
||||
return true;
|
||||
else if (bs <= as && as <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkFirmPayload(void)
|
||||
{
|
||||
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
|
||||
return false;
|
||||
|
||||
u32 size = 0x200;
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
size += firm->section[i].size;
|
||||
|
||||
bool arm9EpFound = false,
|
||||
arm11EpFound = false;
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
__attribute__((aligned(4))) u8 hash[0x20];
|
||||
|
||||
FirmSection *section = &firm->section[i];
|
||||
|
||||
//Allow empty sections
|
||||
if(section->size == 0)
|
||||
continue;
|
||||
|
||||
if((section->offset < 0x200) ||
|
||||
(section->address + section->size < section->address) || //Overflow check
|
||||
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000 - 0x1000, 0x28000000)) ||
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)))
|
||||
return false;
|
||||
|
||||
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
|
||||
|
||||
if(memcmp(hash, section->hash, 0x20) != 0)
|
||||
return false;
|
||||
|
||||
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
|
||||
arm9EpFound = true;
|
||||
|
||||
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
|
||||
arm11EpFound = true;
|
||||
}
|
||||
|
||||
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
|
||||
}
|
||||
|
||||
void loadPayload(u32 pressed, const char *payloadPath)
|
||||
{
|
||||
u32 *loaderAddress = (u32 *)0x27FFE000;
|
||||
u32 payloadSize = 0,
|
||||
maxPayloadSize = (u32)((u8 *)loaderAddress - (u8 *)firm);
|
||||
maxPayloadSize = (u32)((u8 *)0x27FFE000 - (u8 *)firm);
|
||||
|
||||
char absPath[24 + _MAX_LFN];
|
||||
char path[10 + _MAX_LFN];
|
||||
@ -225,14 +171,11 @@ void loadPayload(u32 pressed, const char *payloadPath)
|
||||
sprintf(absPath, "sdmc:/luma/%s", path);
|
||||
|
||||
char *argv[1] = {absPath};
|
||||
memcpy(loaderAddress, loader_bin, loader_bin_size);
|
||||
|
||||
initScreens();
|
||||
|
||||
flushDCacheRange(loaderAddress, loader_bin_size);
|
||||
flushICacheRange(loaderAddress, loader_bin_size);
|
||||
|
||||
((void (*)(int, char **, u32))loaderAddress)(1, argv, 0x0000BEEF);
|
||||
if((u8 *)firm + payloadSize < (u8 *)0x23FFFE00)
|
||||
memcpy((void *)0x23FFFE00, fbs, sizeof(fbs));
|
||||
launchFirm(1, argv);
|
||||
}
|
||||
|
||||
void payloadMenu(void)
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "crypto.h"
|
||||
#include "fmt.h"
|
||||
#include "memory.h"
|
||||
#include "screen.h"
|
||||
|
||||
extern CfgData configData;
|
||||
extern ConfigurationStatus needConfig;
|
||||
@ -290,13 +291,13 @@ boot:
|
||||
switch(firmType)
|
||||
{
|
||||
case NATIVE_FIRM:
|
||||
res = patchNativeFirm(firmVersion, nandType, emuHeader, isSafeMode, doUnitinfoPatch, enableExceptionHandlers);
|
||||
res = patchNativeFirm(firmVersion, nandType, emuHeader, loadFromStorage, isSafeMode, doUnitinfoPatch, enableExceptionHandlers);
|
||||
break;
|
||||
case TWL_FIRM:
|
||||
res = patchTwlFirm(firmVersion, doUnitinfoPatch);
|
||||
res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
|
||||
break;
|
||||
case AGB_FIRM:
|
||||
res = patchAgbFirm(doUnitinfoPatch);
|
||||
res = patchAgbFirm(loadFromStorage, doUnitinfoPatch);
|
||||
break;
|
||||
case SAFE_FIRM:
|
||||
case SYSUPDATER_FIRM:
|
||||
@ -311,5 +312,6 @@ boot:
|
||||
error(errbuf);
|
||||
}
|
||||
|
||||
launchFirm(firmType, loadFromStorage);
|
||||
if(!isFirmlaunch) deinitScreens();
|
||||
launchFirm(0, NULL);
|
||||
}
|
||||
|
@ -237,6 +237,37 @@ u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u32 nbCustomModules, u8 *startPos, u32 size)
|
||||
{
|
||||
const u8 moduleLoadingPattern[] = {
|
||||
0x01, 0x70, 0x87, 0xE2, // add r7, #1
|
||||
0x05, 0x00, 0x57, 0xE3, // cmp r7, #5
|
||||
};
|
||||
|
||||
//GetSystemInfo
|
||||
const u8 modulePidPattern[] = {
|
||||
0x00, 0xF0, 0x20, 0xE3, // nop
|
||||
0x05, 0x00, 0xA0, 0xE3, // mov r0, #5
|
||||
};
|
||||
|
||||
u8 *off = memsearch(startPos, moduleLoadingPattern, size, 8);
|
||||
if(off == NULL) return 1;
|
||||
off[4] += nbCustomModules;
|
||||
|
||||
u32 *off32;
|
||||
for(off32 = (u32 *)off; *off32 != 0xE59F0000; off32++);
|
||||
off32 += 2;
|
||||
off32[1] = off32[0] + modulesSize;
|
||||
for(; *off32 != section0size; off32++);
|
||||
*off32 += ((modulesSize + 0x1FF) >> 9) << 9;
|
||||
|
||||
off = memsearch(startPos, modulePidPattern, size, 8);
|
||||
if(off == NULL) return 1;
|
||||
off[4] = 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space)
|
||||
{
|
||||
if(arm11SvcTable[0x7B] != 0) return 0;
|
||||
|
@ -46,6 +46,7 @@ u32 patchOldFirmWrites(u8 *pos, u32 size);
|
||||
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion);
|
||||
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size);
|
||||
u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size);
|
||||
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u32 nbCustomModules, u8 *startPos, u32 size);
|
||||
u32 patchCheckForDevCommonKey(u8 *pos, u32 size);
|
||||
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space);
|
||||
u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA);
|
||||
|
240
source/screen.c
240
source/screen.c
@ -42,244 +42,77 @@
|
||||
#include "i2c.h"
|
||||
#include "utils.h"
|
||||
|
||||
static vu32 *arm11Entry = ARM11_CORE0_MAILBOX_ENTRYPOINT;
|
||||
|
||||
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
||||
|
||||
void __attribute__((naked)) arm11Stub(void)
|
||||
static volatile Arm11Operation *operation = (volatile Arm11Operation *)0x1FFFFFF0;
|
||||
|
||||
struct fb fbs[2];
|
||||
|
||||
static void invokeArm11Function(Arm11Operation op)
|
||||
{
|
||||
WAIT_FOR_ARM9();
|
||||
while(*operation != NO_ARM11_OPERATION);
|
||||
*operation = op;
|
||||
while(*operation != NO_ARM11_OPERATION);
|
||||
}
|
||||
|
||||
static void invokeArm11Function(void (*func)())
|
||||
void prepareArm11ForFirmlaunch(void)
|
||||
{
|
||||
static bool hasCopiedStub = false;
|
||||
|
||||
if(!hasCopiedStub)
|
||||
{
|
||||
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x2C);
|
||||
hasCopiedStub = true;
|
||||
}
|
||||
|
||||
*arm11Entry = (u32)func;
|
||||
while(*arm11Entry);
|
||||
*arm11Entry = ARM11_STUB_ADDRESS;
|
||||
while(*arm11Entry);
|
||||
invokeArm11Function(PREPARE_ARM11_FOR_FIRMLAUNCH);
|
||||
}
|
||||
|
||||
void deinitScreens(void)
|
||||
{
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
//Shutdown LCDs
|
||||
*(vu32 *)0x10202A44 = 0;
|
||||
*(vu32 *)0x10202244 = 0;
|
||||
*(vu32 *)0x10202014 = 0;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
if(ARESCREENSINITIALIZED) invokeArm11Function(ARM11);
|
||||
if(ARESCREENSINITIALIZED) invokeArm11Function(DEINIT_SCREENS);
|
||||
}
|
||||
|
||||
void updateBrightness(u32 brightnessIndex)
|
||||
{
|
||||
static u32 brightnessLevel;
|
||||
brightnessLevel = brightness[brightnessIndex];
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
//Change brightness
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
flushDCacheRange(&brightnessLevel, 4);
|
||||
invokeArm11Function(ARM11);
|
||||
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[brightnessIndex];
|
||||
invokeArm11Function(UPDATE_BRIGHTNESS);
|
||||
}
|
||||
|
||||
void swapFramebuffers(bool isAlternate)
|
||||
{
|
||||
static u32 isAlternateTmp;
|
||||
isAlternateTmp = isAlternate ? 1 : 0;
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
*(vu32 *)0x10400478 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp;
|
||||
*(vu32 *)0x10400578 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
flushDCacheRange(&isAlternateTmp, 4);
|
||||
invokeArm11Function(ARM11);
|
||||
*(volatile bool *)ARM11_PARAMETERS_ADDRESS = isAlternate;
|
||||
invokeArm11Function(SWAP_FRAMEBUFFERS);
|
||||
}
|
||||
|
||||
void clearScreens(bool isAlternate)
|
||||
{
|
||||
static volatile struct fb *fbTmp;
|
||||
fbTmp = isAlternate ? &fbs[1] : &fbs[0];
|
||||
struct fb *fbTemp = isAlternate ? &fbs[1] : &fbs[0];
|
||||
|
||||
void __attribute__((naked)) ARM11(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
*(volatile struct fb *)ARM11_PARAMETERS_ADDRESS = *fbTemp;
|
||||
invokeArm11Function(CLEAR_SCREENS);
|
||||
}
|
||||
|
||||
//Setting up two simultaneous memory fills using the GPU
|
||||
static void initScreensSequence(void)
|
||||
{
|
||||
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[MULTICONFIG(BRIGHTNESS)];
|
||||
invokeArm11Function(INIT_SCREENS_SEQUENCE);
|
||||
}
|
||||
|
||||
vu32 *REGs_PSC0 = (vu32 *)0x10400010,
|
||||
*REGs_PSC1 = (vu32 *)0x10400020;
|
||||
static void setupFramebuffers(void)
|
||||
{
|
||||
fbs[0].top_left = (u8 *)0x18300000;
|
||||
fbs[1].top_left = (u8 *)0x18400000;
|
||||
fbs[0].top_right = (u8 *)0x18300000;
|
||||
fbs[1].top_right = (u8 *)0x18400000;
|
||||
fbs[0].bottom = (u8 *)0x18346500;
|
||||
fbs[1].bottom = (u8 *)0x18446500;
|
||||
|
||||
REGs_PSC0[0] = (u32)fbTmp->top_left >> 3; //Start address
|
||||
REGs_PSC0[1] = (u32)(fbTmp->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address
|
||||
REGs_PSC0[2] = 0; //Fill value
|
||||
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
REGs_PSC1[0] = (u32)fbTmp->bottom >> 3; //Start address
|
||||
REGs_PSC1[1] = (u32)(fbTmp->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address
|
||||
REGs_PSC1[2] = 0; //Fill value
|
||||
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
flushDCacheRange((void *)fbTmp, sizeof(struct fb));
|
||||
flushDCacheRange(&fbTmp, 4);
|
||||
invokeArm11Function(ARM11);
|
||||
memcpy((void *)ARM11_PARAMETERS_ADDRESS, fbs, sizeof(fbs));
|
||||
invokeArm11Function(SETUP_FRAMEBUFFERS);
|
||||
}
|
||||
|
||||
void initScreens(void)
|
||||
{
|
||||
void __attribute__((naked)) initSequence(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
u32 brightnessLevel = brightness[MULTICONFIG(BRIGHTNESS)];
|
||||
|
||||
*(vu32 *)0x10141200 = 0x1007F;
|
||||
*(vu32 *)0x10202014 = 0x00000001;
|
||||
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
*(vu32 *)0x10202244 = 0x1023E;
|
||||
*(vu32 *)0x10202A44 = 0x1023E;
|
||||
|
||||
//Top screen
|
||||
*(vu32 *)0x10400400 = 0x000001c2;
|
||||
*(vu32 *)0x10400404 = 0x000000d1;
|
||||
*(vu32 *)0x10400408 = 0x000001c1;
|
||||
*(vu32 *)0x1040040c = 0x000001c1;
|
||||
*(vu32 *)0x10400410 = 0x00000000;
|
||||
*(vu32 *)0x10400414 = 0x000000cf;
|
||||
*(vu32 *)0x10400418 = 0x000000d1;
|
||||
*(vu32 *)0x1040041c = 0x01c501c1;
|
||||
*(vu32 *)0x10400420 = 0x00010000;
|
||||
*(vu32 *)0x10400424 = 0x0000019d;
|
||||
*(vu32 *)0x10400428 = 0x00000002;
|
||||
*(vu32 *)0x1040042c = 0x00000192;
|
||||
*(vu32 *)0x10400430 = 0x00000192;
|
||||
*(vu32 *)0x10400434 = 0x00000192;
|
||||
*(vu32 *)0x10400438 = 0x00000001;
|
||||
*(vu32 *)0x1040043c = 0x00000002;
|
||||
*(vu32 *)0x10400440 = 0x01960192;
|
||||
*(vu32 *)0x10400444 = 0x00000000;
|
||||
*(vu32 *)0x10400448 = 0x00000000;
|
||||
*(vu32 *)0x1040045C = 0x00f00190;
|
||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
||||
*(vu32 *)0x10400464 = 0x01920002;
|
||||
*(vu32 *)0x10400468 = 0x18300000;
|
||||
*(vu32 *)0x10400470 = 0x80341;
|
||||
*(vu32 *)0x10400474 = 0x00010501;
|
||||
*(vu32 *)0x10400478 = 0;
|
||||
*(vu32 *)0x10400490 = 0x000002D0;
|
||||
*(vu32 *)0x1040049C = 0x00000000;
|
||||
|
||||
//Disco register
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
*(vu32 *)0x10400484 = 0x10101 * i;
|
||||
|
||||
//Bottom screen
|
||||
*(vu32 *)0x10400500 = 0x000001c2;
|
||||
*(vu32 *)0x10400504 = 0x000000d1;
|
||||
*(vu32 *)0x10400508 = 0x000001c1;
|
||||
*(vu32 *)0x1040050c = 0x000001c1;
|
||||
*(vu32 *)0x10400510 = 0x000000cd;
|
||||
*(vu32 *)0x10400514 = 0x000000cf;
|
||||
*(vu32 *)0x10400518 = 0x000000d1;
|
||||
*(vu32 *)0x1040051c = 0x01c501c1;
|
||||
*(vu32 *)0x10400520 = 0x00010000;
|
||||
*(vu32 *)0x10400524 = 0x0000019d;
|
||||
*(vu32 *)0x10400528 = 0x00000052;
|
||||
*(vu32 *)0x1040052c = 0x00000192;
|
||||
*(vu32 *)0x10400530 = 0x00000192;
|
||||
*(vu32 *)0x10400534 = 0x0000004f;
|
||||
*(vu32 *)0x10400538 = 0x00000050;
|
||||
*(vu32 *)0x1040053c = 0x00000052;
|
||||
*(vu32 *)0x10400540 = 0x01980194;
|
||||
*(vu32 *)0x10400544 = 0x00000000;
|
||||
*(vu32 *)0x10400548 = 0x00000011;
|
||||
*(vu32 *)0x1040055C = 0x00f00140;
|
||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
||||
*(vu32 *)0x10400564 = 0x01920052;
|
||||
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
||||
*(vu32 *)0x10400570 = 0x80301;
|
||||
*(vu32 *)0x10400574 = 0x00010501;
|
||||
*(vu32 *)0x10400578 = 0;
|
||||
*(vu32 *)0x10400590 = 0x000002D0;
|
||||
*(vu32 *)0x1040059C = 0x00000000;
|
||||
|
||||
//Disco register
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
*(vu32 *)0x10400584 = 0x10101 * i;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
//Set CakeBrah framebuffers
|
||||
void __attribute__((naked)) setupFramebuffers(void)
|
||||
{
|
||||
//Disable interrupts
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
fbs[0].top_left = (u8 *)0x18300000;
|
||||
fbs[1].top_left = (u8 *)0x18400000;
|
||||
fbs[0].top_right = (u8 *)0x18300000;
|
||||
fbs[1].top_right = (u8 *)0x18400000;
|
||||
fbs[0].bottom = (u8 *)0x18346500;
|
||||
fbs[1].bottom = (u8 *)0x18446500;
|
||||
|
||||
*(vu32 *)0x10400468 = (u32)fbs[0].top_left;
|
||||
*(vu32 *)0x1040046c = (u32)fbs[1].top_left;
|
||||
*(vu32 *)0x10400494 = (u32)fbs[0].top_right;
|
||||
*(vu32 *)0x10400498 = (u32)fbs[1].top_right;
|
||||
*(vu32 *)0x10400568 = (u32)fbs[0].bottom;
|
||||
*(vu32 *)0x1040056c = (u32)fbs[1].bottom;
|
||||
|
||||
WAIT_FOR_ARM9();
|
||||
}
|
||||
|
||||
static bool needToSetup = true;
|
||||
|
||||
if(needToSetup)
|
||||
{
|
||||
if(!ARESCREENSINITIALIZED)
|
||||
{
|
||||
flushDCacheRange(&configData, sizeof(CfgData));
|
||||
invokeArm11Function(initSequence);
|
||||
initScreensSequence();
|
||||
|
||||
//Turn on backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||
@ -287,8 +120,7 @@ void initScreens(void)
|
||||
}
|
||||
else updateBrightness(MULTICONFIG(BRIGHTNESS));
|
||||
|
||||
flushDCacheRange((void *)fbs, 2 * sizeof(struct fb));
|
||||
invokeArm11Function(setupFramebuffers);
|
||||
setupFramebuffers();
|
||||
needToSetup = false;
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,7 @@
|
||||
|
||||
#define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1)
|
||||
|
||||
#define ARM11_STUB_ADDRESS 0x1FFFFF00
|
||||
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
|
||||
#define ARM11_PARAMETERS_ADDRESS 0x1FFFC000
|
||||
|
||||
#define SCREEN_TOP_WIDTH 400
|
||||
#define SCREEN_BOTTOM_WIDTH 320
|
||||
@ -42,14 +41,29 @@
|
||||
#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
|
||||
#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
|
||||
|
||||
static volatile struct fb {
|
||||
struct fb {
|
||||
u8 *top_left;
|
||||
u8 *top_right;
|
||||
u8 *bottom;
|
||||
} __attribute__((packed)) *const fbs = (volatile struct fb *)0x23FFFE00;
|
||||
} __attribute__((packed)); //*const fbs = (volatile struct fb *)0x23FFFE00;
|
||||
|
||||
extern struct fb fbs[2];
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NO_ARM11_OPERATION = 0,
|
||||
INIT_SCREENS_SEQUENCE,
|
||||
SETUP_FRAMEBUFFERS,
|
||||
CLEAR_SCREENS,
|
||||
SWAP_FRAMEBUFFERS,
|
||||
UPDATE_BRIGHTNESS,
|
||||
DEINIT_SCREENS,
|
||||
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
||||
} Arm11Operation;
|
||||
|
||||
extern CfgData configData;
|
||||
|
||||
void prepareArm11ForFirmlaunch(void);
|
||||
void deinitScreens(void);
|
||||
void swapFramebuffers(bool isAlternate);
|
||||
void updateBrightness(u32 brightnessIndex);
|
||||
|
@ -37,7 +37,7 @@ _start:
|
||||
mov r10, r1
|
||||
|
||||
@ Change the stack pointer
|
||||
mov sp, #0x27000000
|
||||
mov sp, #0x08100000
|
||||
|
||||
@ Disable caches / MPU
|
||||
mrc p15, 0, r4, c1, c0, 0 @ read control register
|
||||
|
Reference in New Issue
Block a user