Begin turning Luma3DS into a proper firm

Unfinished work
This commit is contained in:
TuxSH 2017-05-23 02:44:04 +02:00
parent 8308e1a8b8
commit 53209b9be0
20 changed files with 717 additions and 377 deletions

View File

@ -12,6 +12,7 @@ commit := $(shell git rev-parse --short=8 HEAD)
dir_source := source dir_source := source
dir_patches := patches dir_patches := patches
dir_arm11 := arm11
dir_loader := loader dir_loader := loader
dir_injector := injector dir_injector := injector
dir_exceptions := exceptions dir_exceptions := exceptions
@ -29,7 +30,9 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c))) $(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 \ 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 define bin2o
bin2s $< | $(AS) -o $(@) bin2s $< | $(AS) -o $(@)
@ -46,6 +49,7 @@ firm: $(dir_out)/boot.firm
.PHONY: clean .PHONY: clean
clean: clean:
@$(MAKE) -C $(dir_arm11) clean
@$(MAKE) -C $(dir_loader) clean @$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_arm9_exceptions) clean @$(MAKE) -C $(dir_arm9_exceptions) clean
@$(MAKE) -C $(dir_arm11_exceptions) clean @$(MAKE) -C $(dir_arm11_exceptions) clean
@ -54,6 +58,7 @@ clean:
.PRECIOUS: $(dir_build)/%.bin .PRECIOUS: $(dir_build)/%.bin
.PHONY: $(dir_arm11)
.PHONY: $(dir_loader) .PHONY: $(dir_loader)
.PHONY: $(dir_arm9_exceptions) .PHONY: $(dir_arm9_exceptions)
.PHONY: $(dir_arm11_exceptions) .PHONY: $(dir_arm11_exceptions)
@ -63,20 +68,28 @@ $(dir_out)/$(name)$(revision).7z: all
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py @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)" @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) $(dir_build)/main.elf: $(bundled) $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^ $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.bin.o: $(dir_build)/%.bin $(dir_build)/injector.cxi: $(dir_injector)
@$(bin2o)
$(dir_build)/injector.bin: $(dir_injector)
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
@$(MAKE) -C $< @$(MAKE) -C $<
$(dir_build)/%.bin.o: $(dir_build)/%.bin
@$(bin2o)
$(dir_build)/loader.bin: $(dir_loader) $(dir_build)/loader.bin: $(dir_loader)
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
@$(MAKE) -C $< @$(MAKE) -C $<
@ -96,6 +109,8 @@ $(dir_build)/%.bin: $(dir_patches)/%.s
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3 $(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\"" $(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)" $(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) $(dir_build)/bundled.h: $(bundled)
@$(foreach f, $(bundled),\ @$(foreach f, $(bundled),\

39
arm11/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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;

View File

@ -33,7 +33,7 @@ define bin2o
endef endef
.PHONY: all .PHONY: all
all: $(dir_out)/$(name).bin all: $(dir_out)/$(name).cxi
.PHONY: clean .PHONY: clean
clean: clean:
@ -41,10 +41,7 @@ clean:
.PRECIOUS: $(dir_build)/%.bin .PRECIOUS: $(dir_build)/%.bin
$(dir_build): $(dir_out)/$(name).cxi: $(dir_build)/$(name).elf
@mkdir -p "$@"
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $< @makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
$(dir_build)/$(name).elf: $(bundled) $(objects) $(dir_build)/$(name).elf: $(bundled) $(objects)

View File

@ -4,7 +4,7 @@ OUTPUT_ARCH(arm)
ENTRY(_start) ENTRY(_start)
SECTIONS SECTIONS
{ {
. = 0x23F00000; . = 0x08006000;
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }

View File

@ -30,12 +30,12 @@ void launchFirm(Firm *firm, int argc, char **argv)
for(u32 sectionNum = 0; sectionNum < 4 && firm->section[sectionNum].size != 0; sectionNum++) 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); 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 //Ensure that all memory transfers have completed and that the caches have been flushed
flushCaches(); flushCaches();
//Set ARM11 entrypoint
*(vu32 *)0x1FFFFFFC = (u32)firm->arm11Entry;
//Jump to ARM9 entrypoint. Also give it additional arguments it can dismiss //Jump to ARM9 entrypoint. Also give it additional arguments it can dismiss
((void (*)(int, char**, u32))firm->arm9Entry)(argc, argv, 0x0000BEEF); ((void (*)(int, char**, u32))firm->arm9Entry)(argc, argv, 0x0000BEEF);

View File

@ -38,11 +38,11 @@
static inline bool loadFirmFromStorage(FirmwareType firmType) static inline bool loadFirmFromStorage(FirmwareType firmType)
{ {
const char *firmwareFiles[] = { const char *firmwareFiles[] = {
"firmware.bin", "native.firm",
"firmware_twl.bin", "twl.firm",
"firmware_agb.bin", "agb.firm",
"firmware_safe.bin", "safe.firm",
"firmware_sysupdater.bin" "sysupdater.firm"
}, },
*cetkFiles[] = { *cetkFiles[] = {
"cetk", "cetk",
@ -74,6 +74,93 @@ static inline bool loadFirmFromStorage(FirmwareType firmType)
return true; 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) u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
{ {
//Load FIRM from CTRNAND //Load FIRM from CTRNAND
@ -111,7 +198,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
return firmVersion; 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, u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
*arm11Section1 = (u8 *)firm + firm->section[1].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; return ret;
} }
u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch) u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch)
{ {
u8 *arm9Section = (u8 *)firm + firm->section[3].offset; u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
@ -242,10 +332,16 @@ u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch)
//Apply UNITINFO patch //Apply UNITINFO patch
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size); if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
if(loadFromStorage)
{
mergeSection0(TWL_FIRM, true);
firm->section[0].size = 0;
}
return ret; return ret;
} }
u32 patchAgbFirm(bool doUnitinfoPatch) u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch)
{ {
u8 *arm9Section = (u8 *)firm + firm->section[3].offset; u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
@ -270,6 +366,12 @@ u32 patchAgbFirm(bool doUnitinfoPatch)
//Apply UNITINFO patch //Apply UNITINFO patch
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size); if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
if(loadFromStorage)
{
mergeSection0(AGB_FIRM, true);
firm->section[0].size = 0;
}
return ret; return ret;
} }
@ -306,85 +408,69 @@ u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers)
return ret; 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, if (as <= bs && bs <= ae)
srcModuleSize, return true;
dstModuleSize; else if (bs <= as && as <= be)
const char *extModuleSizeError = "The external FIRM modules are too large."; return true;
return false;
}
for(u8 *src = (u8 *)firm + firm->section[0].offset, *srcEnd = src + firm->section[0].size, *dst = firm->section[0].address; bool checkFirmPayload(void)
src < srcEnd; src += srcModuleSize, dst += dstModuleSize, maxModuleSize -= dstModuleSize) {
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++)
{ {
srcModuleSize = ((Cxi *)src)->ncch.contentSize * 0x200; __attribute__((aligned(4))) u8 hash[0x20];
const char *moduleName = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
if(loadFromStorage) FirmSection *section = &firm->section[i];
{
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.");
//Allow empty sections
if(section->size == 0)
continue; 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;
} }
const u8 *module; return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
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);
}
} }
void launchFirm(FirmwareType firmType, bool loadFromStorage) void launchFirm(int argc, char **argv)
{ {
//Allow module injection and/or inject 3ds_injector on new NATIVE_FIRMs and LGY FIRMs u32 *loaderAddress = (u32 *)0x27FFE000;
u32 sectionNum;
if(firmType == NATIVE_FIRM || (loadFromStorage && (firmType == TWL_FIRM || firmType == AGB_FIRM)))
{
copySection0AndInjectSystemModules(firmType, loadFromStorage);
sectionNum = 1;
}
else sectionNum = 0;
//Copy FIRM sections to respective memory locations prepareArm11ForFirmlaunch();
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(); memcpy(loaderAddress, loader_bin, loader_bin_size);
//Set ARM11 kernel entrypoint flushDCacheRange(loaderAddress, loader_bin_size);
*ARM11_CORE0_MAILBOX_ENTRYPOINT = (u32)firm->arm11Entry; flushICacheRange(loaderAddress, loader_bin_size);
//Ensure that all memory transfers have completed and that the caches have been flushed ((void (*)(int, char **, u32))loaderAddress)(argc, argv, 0x0000BEEF);
flushEntireDCache();
flushEntireICache();
//Final jump to ARM9 kernel
((void (*)())firm->arm9Entry)();
} }

View File

@ -25,11 +25,14 @@
#include "types.h" #include "types.h"
#include "3dsheaders.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 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
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);
u32 patchTwlFirm(u32 firmVersion, bool doUnitinfoPatch); u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
u32 patchAgbFirm(bool doUnitinfoPatch); u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers); u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers);
void launchFirm(FirmwareType firmType, bool loadFromStorage);
bool checkFirmPayload(void);
void launchFirm(int argc, char **argv);

View File

@ -118,64 +118,10 @@ void fileDelete(const char *path)
f_unlink(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) void loadPayload(u32 pressed, const char *payloadPath)
{ {
u32 *loaderAddress = (u32 *)0x27FFE000;
u32 payloadSize = 0, u32 payloadSize = 0,
maxPayloadSize = (u32)((u8 *)loaderAddress - (u8 *)firm); maxPayloadSize = (u32)((u8 *)0x27FFE000 - (u8 *)firm);
char absPath[24 + _MAX_LFN]; char absPath[24 + _MAX_LFN];
char path[10 + _MAX_LFN]; char path[10 + _MAX_LFN];
@ -225,14 +171,11 @@ void loadPayload(u32 pressed, const char *payloadPath)
sprintf(absPath, "sdmc:/luma/%s", path); sprintf(absPath, "sdmc:/luma/%s", path);
char *argv[1] = {absPath}; char *argv[1] = {absPath};
memcpy(loaderAddress, loader_bin, loader_bin_size);
initScreens(); initScreens();
flushDCacheRange(loaderAddress, loader_bin_size); if((u8 *)firm + payloadSize < (u8 *)0x23FFFE00)
flushICacheRange(loaderAddress, loader_bin_size); memcpy((void *)0x23FFFE00, fbs, sizeof(fbs));
launchFirm(1, argv);
((void (*)(int, char **, u32))loaderAddress)(1, argv, 0x0000BEEF);
} }
void payloadMenu(void) void payloadMenu(void)

View File

@ -33,6 +33,7 @@
#include "crypto.h" #include "crypto.h"
#include "fmt.h" #include "fmt.h"
#include "memory.h" #include "memory.h"
#include "screen.h"
extern CfgData configData; extern CfgData configData;
extern ConfigurationStatus needConfig; extern ConfigurationStatus needConfig;
@ -290,13 +291,13 @@ boot:
switch(firmType) switch(firmType)
{ {
case NATIVE_FIRM: case NATIVE_FIRM:
res = patchNativeFirm(firmVersion, nandType, emuHeader, isSafeMode, doUnitinfoPatch, enableExceptionHandlers); res = patchNativeFirm(firmVersion, nandType, emuHeader, loadFromStorage, isSafeMode, doUnitinfoPatch, enableExceptionHandlers);
break; break;
case TWL_FIRM: case TWL_FIRM:
res = patchTwlFirm(firmVersion, doUnitinfoPatch); res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
break; break;
case AGB_FIRM: case AGB_FIRM:
res = patchAgbFirm(doUnitinfoPatch); res = patchAgbFirm(loadFromStorage, doUnitinfoPatch);
break; break;
case SAFE_FIRM: case SAFE_FIRM:
case SYSUPDATER_FIRM: case SYSUPDATER_FIRM:
@ -311,5 +312,6 @@ boot:
error(errbuf); error(errbuf);
} }
launchFirm(firmType, loadFromStorage); if(!isFirmlaunch) deinitScreens();
launchFirm(0, NULL);
} }

View File

@ -237,6 +237,37 @@ u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
return 0; 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) u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space)
{ {
if(arm11SvcTable[0x7B] != 0) return 0; if(arm11SvcTable[0x7B] != 0) return 0;

View File

@ -46,6 +46,7 @@ u32 patchOldFirmWrites(u8 *pos, u32 size);
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion); u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion);
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size); u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size);
u32 patchNandNcchEncryptionCheck(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 patchCheckForDevCommonKey(u8 *pos, u32 size);
u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space); u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space);
u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA); u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA);

View File

@ -42,219 +42,57 @@
#include "i2c.h" #include "i2c.h"
#include "utils.h" #include "utils.h"
static vu32 *arm11Entry = ARM11_CORE0_MAILBOX_ENTRYPOINT;
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26}; 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; invokeArm11Function(PREPARE_ARM11_FOR_FIRMLAUNCH);
if(!hasCopiedStub)
{
memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x2C);
hasCopiedStub = true;
}
*arm11Entry = (u32)func;
while(*arm11Entry);
*arm11Entry = ARM11_STUB_ADDRESS;
while(*arm11Entry);
} }
void deinitScreens(void) void deinitScreens(void)
{ {
void __attribute__((naked)) ARM11(void) if(ARESCREENSINITIALIZED) invokeArm11Function(DEINIT_SCREENS);
{
//Disable interrupts
__asm(".word 0xF10C01C0");
//Shutdown LCDs
*(vu32 *)0x10202A44 = 0;
*(vu32 *)0x10202244 = 0;
*(vu32 *)0x10202014 = 0;
WAIT_FOR_ARM9();
}
if(ARESCREENSINITIALIZED) invokeArm11Function(ARM11);
} }
void updateBrightness(u32 brightnessIndex) void updateBrightness(u32 brightnessIndex)
{ {
static u32 brightnessLevel; *(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[brightnessIndex];
brightnessLevel = brightness[brightnessIndex]; invokeArm11Function(UPDATE_BRIGHTNESS);
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);
} }
void swapFramebuffers(bool isAlternate) void swapFramebuffers(bool isAlternate)
{ {
static u32 isAlternateTmp; *(volatile bool *)ARM11_PARAMETERS_ADDRESS = isAlternate;
isAlternateTmp = isAlternate ? 1 : 0; invokeArm11Function(SWAP_FRAMEBUFFERS);
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);
} }
void clearScreens(bool isAlternate) void clearScreens(bool isAlternate)
{ {
static volatile struct fb *fbTmp; struct fb *fbTemp = isAlternate ? &fbs[1] : &fbs[0];
fbTmp = isAlternate ? &fbs[1] : &fbs[0];
void __attribute__((naked)) ARM11(void) *(volatile struct fb *)ARM11_PARAMETERS_ADDRESS = *fbTemp;
{ invokeArm11Function(CLEAR_SCREENS);
//Disable interrupts
__asm(".word 0xF10C01C0");
//Setting up two simultaneous memory fills using the GPU
vu32 *REGs_PSC0 = (vu32 *)0x10400010,
*REGs_PSC1 = (vu32 *)0x10400020;
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);
} }
void initScreens(void) static void initScreensSequence(void)
{ {
void __attribute__((naked)) initSequence(void) *(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[MULTICONFIG(BRIGHTNESS)];
{ invokeArm11Function(INIT_SCREENS_SEQUENCE);
//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");
static void setupFramebuffers(void)
{
fbs[0].top_left = (u8 *)0x18300000; fbs[0].top_left = (u8 *)0x18300000;
fbs[1].top_left = (u8 *)0x18400000; fbs[1].top_left = (u8 *)0x18400000;
fbs[0].top_right = (u8 *)0x18300000; fbs[0].top_right = (u8 *)0x18300000;
@ -262,24 +100,19 @@ void initScreens(void)
fbs[0].bottom = (u8 *)0x18346500; fbs[0].bottom = (u8 *)0x18346500;
fbs[1].bottom = (u8 *)0x18446500; fbs[1].bottom = (u8 *)0x18446500;
*(vu32 *)0x10400468 = (u32)fbs[0].top_left; memcpy((void *)ARM11_PARAMETERS_ADDRESS, fbs, sizeof(fbs));
*(vu32 *)0x1040046c = (u32)fbs[1].top_left; invokeArm11Function(SETUP_FRAMEBUFFERS);
*(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();
}
void initScreens(void)
{
static bool needToSetup = true; static bool needToSetup = true;
if(needToSetup) if(needToSetup)
{ {
if(!ARESCREENSINITIALIZED) if(!ARESCREENSINITIALIZED)
{ {
flushDCacheRange(&configData, sizeof(CfgData)); initScreensSequence();
invokeArm11Function(initSequence);
//Turn on backlight //Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
@ -287,8 +120,7 @@ void initScreens(void)
} }
else updateBrightness(MULTICONFIG(BRIGHTNESS)); else updateBrightness(MULTICONFIG(BRIGHTNESS));
flushDCacheRange((void *)fbs, 2 * sizeof(struct fb)); setupFramebuffers();
invokeArm11Function(setupFramebuffers);
needToSetup = false; needToSetup = false;
} }

View File

@ -33,8 +33,7 @@
#define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1) #define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1)
#define ARM11_STUB_ADDRESS 0x1FFFFF00 #define ARM11_PARAMETERS_ADDRESS 0x1FFFC000
#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
#define SCREEN_TOP_WIDTH 400 #define SCREEN_TOP_WIDTH 400
#define SCREEN_BOTTOM_WIDTH 320 #define SCREEN_BOTTOM_WIDTH 320
@ -42,14 +41,29 @@
#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT) #define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT) #define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
static volatile struct fb { struct fb {
u8 *top_left; u8 *top_left;
u8 *top_right; u8 *top_right;
u8 *bottom; 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; extern CfgData configData;
void prepareArm11ForFirmlaunch(void);
void deinitScreens(void); void deinitScreens(void);
void swapFramebuffers(bool isAlternate); void swapFramebuffers(bool isAlternate);
void updateBrightness(u32 brightnessIndex); void updateBrightness(u32 brightnessIndex);

View File

@ -37,7 +37,7 @@ _start:
mov r10, r1 mov r10, r1
@ Change the stack pointer @ Change the stack pointer
mov sp, #0x27000000 mov sp, #0x08100000
@ Disable caches / MPU @ Disable caches / MPU
mrc p15, 0, r4, c1, c0, 0 @ read control register mrc p15, 0, r4, c1, c0, 0 @ read control register