diff --git a/Makefile b/Makefile index cf2c946..9995268 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,6 @@ endif dir_source := source dir_patches := patches dir_arm11 := arm11 -dir_chainloader := chainloader dir_exceptions := exceptions dir_arm9_exceptions := $(dir_exceptions)/arm9 dir_k11_extension := k11_extension @@ -60,7 +59,7 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ $(call rwildcard, $(dir_source), *.s *.c))) -bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/chainloader.bin.o $(dir_build)/arm9_exceptions.bin.o +bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/arm9_exceptions.bin.o modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi $(dir_build)/sm.cxi $(dir_build)/pxi.cxi @@ -80,7 +79,6 @@ firm: $(dir_out)/boot.firm .PHONY: clean clean: @$(MAKE) -C $(dir_arm11) clean - @$(MAKE) -C $(dir_chainloader) clean @$(MAKE) -C $(dir_arm9_exceptions) clean @$(MAKE) -C $(dir_k11_extension) clean @$(MAKE) -C $(dir_loader) clean @@ -92,7 +90,6 @@ clean: .PRECIOUS: $(dir_build)/%.bin .PHONY: $(dir_arm11) -.PHONY: $(dir_chainloader) .PHONY: $(dir_arm9_exceptions) .PHONY: $(dir_k11_extension) .PHONY: $(dir_loader) @@ -143,10 +140,6 @@ $(dir_build)/pxi.cxi: $(dir_pxi) $(dir_build)/%.bin.o: $(dir_build)/%.bin @$(bin2o) -$(dir_build)/chainloader.bin: $(dir_chainloader) - @mkdir -p "$(@D)" - @$(MAKE) -C $< - $(dir_build)/arm9_exceptions.bin: $(dir_arm9_exceptions) @mkdir -p "$(@D)" @$(MAKE) -C $< diff --git a/chainloader/Makefile b/chainloader/Makefile deleted file mode 100644 index 6ab2a45..0000000 --- a/chainloader/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) - -ifeq ($(strip $(DEVKITARM)),) -$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") -endif - -include $(DEVKITARM)/base_tools - -name := $(shell basename $(CURDIR)) - -dir_source := source -dir_build := build -dir_out := ../$(dir_build) - -ASFLAGS := -mcpu=arm946e-s -CFLAGS := -Wall -Wextra -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math -LDFLAGS := -nostartfiles -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).bin - -.PHONY: clean -clean: - @rm -rf $(dir_build) - -$(dir_out)/$(name).bin: $(dir_build)/$(name).elf - $(OBJCOPY) -S -O binary $< $@ - -$(dir_build)/$(name).elf: $(objects) - $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^ - -$(dir_build)/memory.o: CFLAGS += -O3 - -$(dir_build)/%.o: $(dir_source)/%.c - @mkdir -p "$(@D)" - $(COMPILE.c) $(OUTPUT_OPTION) $< - -$(dir_build)/%.o: $(dir_source)/%.s - @mkdir -p "$(@D)" - $(COMPILE.s) $(OUTPUT_OPTION) $< diff --git a/chainloader/linker.ld b/chainloader/linker.ld deleted file mode 100644 index c5903f0..0000000 --- a/chainloader/linker.ld +++ /dev/null @@ -1,21 +0,0 @@ -OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -OUTPUT_ARCH(arm) - -ENTRY(_start) -SECTIONS -{ - . = 0x01FF9000; - - __start__ = ABSOLUTE(.); - - .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); - - __end__ = ABSOLUTE(.); - - __stack_top__ = 0x01FFB800; - __stack_bottom__ = 0x01FFA800; -} diff --git a/linker.ld b/linker.ld index d4f8e38..2999435 100644 --- a/linker.ld +++ b/linker.ld @@ -1,15 +1,189 @@ OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") OUTPUT_ARCH(arm) - ENTRY(_start) + +/* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */ +MEMORY +{ + NULL : ORIGIN = 0x00000000, LENGTH = 0x1000 + main : ORIGIN = 0x08006000, LENGTH = 0x080F0000 - 0x08006000 + itcm : ORIGIN = 0x01FF8000, LENGTH = 0x01FFB800 - 0x01FF8000 /* Unused ITCM slice. */ +} + SECTIONS { - . = 0x08006000; + PROVIDE(__start__ = 0x08006000); + PROVIDE(__stack_top__ = 0x08100000); + PROVIDE(__stack_bottom__ = 0x080F0000); - .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } - .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } - .data : ALIGN(4) { *(.data*); . = ALIGN(4); } - .bss : ALIGN(8) { __bss_start = .; *(.bss* COMMON); . = ALIGN(8); __bss_end = .; } + . = __start__; + . = ALIGN(32); - . = ALIGN(4); + .crt0 : + { + . = ALIGN(32); + KEEP( *(.text.start) ) + KEEP( *(.init) ) + . = ALIGN(4); + } >main + + .itcm_loadable : + { + . = ALIGN(32); + PROVIDE (__itcm_start__ = .); + PROVIDE (__itcm_lma__ = LOADADDR(.itcm_loadable)); + PROVIDE(__itcm_stack_top__ = 0x01FFB800); + PROVIDE(__itcm_stack_bottom__ = 0x01FFA800); + + KEEP(*(.chainloader.text.start)) + build/chainloader.o(.text*) + build/chainloader.o(.rodata*) + build/chainloader.o(.data*) + . = ALIGN(8); + } >itcm AT>main + + .itcm_bss : + { + . = ALIGN(8); + PROVIDE (__itcm_bss_start__ = .); + build/chainloader.o(.bss* COMMON) + . = ALIGN(8); + PROVIDE (__itcm_end__ = .); + } >itcm AT>main + + .text : + { + . = ALIGN(4); + + /* .text */ + *(.text) + *(.text.*) + *(.glue_7) + *(.glue_7t) + *(.stub) + *(.gnu.warning) + *(.gnu.linkonce.t*) + . = ALIGN(4); + + /* .fini */ + KEEP( *(.fini) ) + . = ALIGN(4); + } >main + + .rodata : + { + *(.rodata) + *(.roda) + *(.rodata.*) + *all.rodata*(*) + *(.gnu.linkonce.r*) + SORT(CONSTRUCTORS) + . = ALIGN(4); + } >main + + .preinit_array ALIGN(4) : + { + PROVIDE (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE (__preinit_array_end = .); + } >main + + .init_array ALIGN(4) : + { + PROVIDE (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE (__init_array_end = .); + } >main + + .fini_array ALIGN(4) : + { + PROVIDE (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE (__fini_array_end = .); + } >main + + .ctors ALIGN(4) : + { + KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >main + + .dtors ALIGN(4) : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >main + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >main + __exidx_start = .; + ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >main + __exidx_end = .; + + .data : + { + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + CONSTRUCTORS + . = ALIGN(4); + } >main + + .bss : + { + __bss_start__ = ALIGN(32); + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b*) + *(COMMON) + . = ALIGN(8); + __bss_end__ = .; + } >main + __end__ = ABSOLUTE(.) ; + + /* ================== + ==== Metadata ==== + ================== */ + + /* Discard sections that difficult post-processing */ + /DISCARD/ : { *(.group .comment .note) } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } } diff --git a/chainloader/source/main.c b/source/chainloader.c similarity index 65% rename from chainloader/source/main.c rename to source/chainloader.c index 62c09c1..c35cd72 100644 --- a/chainloader/source/main.c +++ b/source/chainloader.c @@ -24,11 +24,37 @@ * reasonable ways as different from the original version. */ -#include "memory.h" -#include "cache.h" -#include "firm.h" +#include "chainloader.h" +#include "screen.h" -void main(int argc, char **argv, Firm *firm) +void disableMpuAndJumpToEntrypoints(int argc, char **argv, void *arm11Entry, void *arm9Entry); + +#pragma GCC optimize (3) + +static void *xmemcpy(void *dst, const void *src, u32 len) +{ + const u8 *src8 = (const u8 *)src; + u8 *dst8 = (u8 *)dst; + + for (u32 i = 0; i < len; i++) { + dst8[i] = src8[i]; + } + + return dst; +} + +static void doLaunchFirm(Firm *firm, int argc, char **argv) +{ + //Copy FIRM sections to respective memory locations + for(u32 sectionNum = 0; sectionNum < 4; sectionNum++) + xmemcpy(firm->section[sectionNum].address, (u8 *)firm + firm->section[sectionNum].offset, firm->section[sectionNum].size); + + disableMpuAndJumpToEntrypoints(argc, argv, firm->arm9Entry, firm->arm11Entry); + + __builtin_unreachable(); +} + +void chainloader_main(int argc, char **argv, Firm *firm) { char *argvPassed[2], absPath[24 + 255]; @@ -54,5 +80,5 @@ void main(int argc, char **argv, Firm *firm) argvPassed[1] = (char *)&fbs; } - launchFirm(firm, argc, argvPassed); + doLaunchFirm(firm, argc, argvPassed); } diff --git a/chainloader/source/cache.h b/source/chainloader.h similarity index 94% rename from chainloader/source/cache.h rename to source/chainloader.h index fc694c5..742fc58 100644 --- a/chainloader/source/cache.h +++ b/source/chainloader.h @@ -27,5 +27,6 @@ #pragma once #include "types.h" +#include "firm.h" -void flushCaches(void); +void chainload(int argc, char **argv, Firm *firm); \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index a4d18c4..1e3ecba 100755 --- a/source/firm.c +++ b/source/firm.c @@ -37,6 +37,7 @@ #include "crypto.h" #include "screen.h" #include "fmt.h" +#include "chainloader.h" #include "../build/bundled.h" static Firm *firm = (Firm *)0x20001000; @@ -528,12 +529,6 @@ u32 patch1x2xNativeAndSafeFirm(void) void launchFirm(int argc, char **argv) { - u32 *chainloaderAddress = (u32 *)0x01FF9000; - prepareArm11ForFirmlaunch(); - - memcpy(chainloaderAddress, chainloader_bin, chainloader_bin_size); - - // No need to flush caches here, the chainloader is in ITCM - ((void (*)(int, char **, Firm *))chainloaderAddress)(argc, argv, firm); + chainload(argc, argv, firm); } diff --git a/source/start.s b/source/start.s index aa5e37f..54f3560 100644 --- a/source/start.s +++ b/source/start.s @@ -109,13 +109,67 @@ _start: mcr p15, 0, r0, c1, c0, 0 @ write control register @ Clear BSS - ldr r0, =__bss_start + ldr r0, =__bss_start__ mov r1, #0 - ldr r2, =__bss_end + ldr r2, =__bss_end__ sub r2, r0 bl memset32 + @ Set additional sections up + ldr r0, =__itcm_start__ + ldr r1, =__itcm_lma__ + ldr r2, =__itcm_bss_start__ + sub r2, r0 + bl memcpy + + ldr r0, =__itcm_bss_start__ + mov r1, #0 + ldr r2, =__itcm_end__ + sub r2, r0 + bl memset32 + + @ bl __libc_init_array + mov r0, r9 mov r1, r10 mov r2, r11 b main + +.section .chainloader.text.start, "ax", %progbits +.align 4 +.global chainload +.type chainload, %function +chainload: + ldr sp, =__itcm_stack_top__ + b chainloader_main + +.global disableMpuAndJumpToEntrypoints +.type disableMpuAndJumpToEntrypoints, %function +disableMpuAndJumpToEntrypoints: + mov r4, r0 + mov r5, r1 + mov r6, r2 + mov r7, r3 + + @ Flush caches + ldr r12, =0xFFFF0830 + blx r12 + ldr r12, =0xFFFF0AB4 + blx r12 + + @ Disable caches / MPU + mrc p15, 0, r0, c1, c0, 0 @ read control register + bic r0, #(1<<12) @ - instruction cache disable + bic r0, #(1<<2) @ - data cache disable + bic r0, #(1<<0) @ - MPU disable + mcr p15, 0, r0, c1, c0, 0 @ write control register + + @ Set the ARM11 entrypoint + mov r0, #0x20000000 + str r7, [r0, #-4] + + @ Jump to the ARM9 entrypoint + mov r0, r4 + mov r1, r5 + ldr r2, =0x3BEEF + bx r6