From 53209b9be0c264af00fb81b32146d27f0d9498ac Mon Sep 17 00:00:00 2001 From: TuxSH Date: Tue, 23 May 2017 02:44:04 +0200 Subject: [PATCH] Begin turning Luma3DS into a proper firm Unfinished work --- Makefile | 29 +++-- arm11/Makefile | 39 +++++++ arm11/linker.ld | 14 +++ arm11/source/main.c | 207 ++++++++++++++++++++++++++++++++++ arm11/source/memory.c | 36 ++++++ arm11/source/memory.h | 31 ++++++ arm11/source/start.s | 27 +++++ arm11/source/types.h | 62 +++++++++++ injector/Makefile | 7 +- linker.ld | 2 +- loader/source/firm.c | 6 +- source/firm.c | 250 ++++++++++++++++++++++++++++-------------- source/firm.h | 13 ++- source/fs.c | 65 +---------- source/main.c | 10 +- source/patches.c | 31 ++++++ source/patches.h | 1 + source/screen.c | 240 ++++++---------------------------------- source/screen.h | 22 +++- source/start.s | 2 +- 20 files changed, 717 insertions(+), 377 deletions(-) create mode 100644 arm11/Makefile create mode 100644 arm11/linker.ld create mode 100644 arm11/source/main.c create mode 100644 arm11/source/memory.c create mode 100644 arm11/source/memory.h create mode 100644 arm11/source/start.s create mode 100644 arm11/source/types.h diff --git a/Makefile b/Makefile index 61e668b..a9a9475 100644 --- a/Makefile +++ b/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),\ diff --git a/arm11/Makefile b/arm11/Makefile new file mode 100644 index 0000000..47ddde6 --- /dev/null +++ b/arm11/Makefile @@ -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=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) $< diff --git a/arm11/linker.ld b/arm11/linker.ld new file mode 100644 index 0000000..71d4f80 --- /dev/null +++ b/arm11/linker.ld @@ -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); +} diff --git a/arm11/source/main.c b/arm11/source/main.c new file mode 100644 index 0000000..fb18a7f --- /dev/null +++ b/arm11/source/main.c @@ -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 . +* +* 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; + } +} diff --git a/arm11/source/memory.c b/arm11/source/memory.c new file mode 100644 index 0000000..b6aefe1 --- /dev/null +++ b/arm11/source/memory.c @@ -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 . +* +* 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]; +} \ No newline at end of file diff --git a/arm11/source/memory.h b/arm11/source/memory.h new file mode 100644 index 0000000..da8751a --- /dev/null +++ b/arm11/source/memory.h @@ -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 . +* +* 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); \ No newline at end of file diff --git a/arm11/source/start.s b/arm11/source/start.s new file mode 100644 index 0000000..baeaa3f --- /dev/null +++ b/arm11/source/start.s @@ -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 . +@ +@ 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 diff --git a/arm11/source/types.h b/arm11/source/types.h new file mode 100644 index 0000000..e29878b --- /dev/null +++ b/arm11/source/types.h @@ -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 . +* +* 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 +#include + +//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; diff --git a/injector/Makefile b/injector/Makefile index d583eec..5657fa8 100755 --- a/injector/Makefile +++ b/injector/Makefile @@ -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) diff --git a/linker.ld b/linker.ld index 45bd382..d4f8e38 100644 --- a/linker.ld +++ b/linker.ld @@ -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); } diff --git a/loader/source/firm.c b/loader/source/firm.c index 42de373..776d306 100644 --- a/loader/source/firm.c +++ b/loader/source/firm.c @@ -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); diff --git a/source/firm.c b/source/firm.c index 05ce9ae..afdaa75 100755 --- a/source/firm.c +++ b/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); } diff --git a/source/firm.h b/source/firm.h index 2afcfa6..6647efb 100644 --- a/source/firm.h +++ b/source/firm.h @@ -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); + diff --git a/source/fs.c b/source/fs.c index acf075f..3c935d8 100644 --- a/source/fs.c +++ b/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) diff --git a/source/main.c b/source/main.c index b684c80..3dc33b4 100644 --- a/source/main.c +++ b/source/main.c @@ -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); } diff --git a/source/patches.c b/source/patches.c index 39cc82c..a6e91d2 100644 --- a/source/patches.c +++ b/source/patches.c @@ -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; diff --git a/source/patches.h b/source/patches.h index 50f0dbd..91f4433 100644 --- a/source/patches.h +++ b/source/patches.h @@ -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); diff --git a/source/screen.c b/source/screen.c index a9ce3b5..9494f6d 100644 --- a/source/screen.c +++ b/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; } diff --git a/source/screen.h b/source/screen.h index ce22660..342db19 100644 --- a/source/screen.h +++ b/source/screen.h @@ -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); diff --git a/source/start.s b/source/start.s index 8f08112..89a88fe 100644 --- a/source/start.s +++ b/source/start.s @@ -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