From 31dc21fdc592d8eed5d99f706ecb856073f2b8f7 Mon Sep 17 00:00:00 2001 From: Jon Feldman Date: Wed, 8 Feb 2017 13:14:51 -0500 Subject: [PATCH] Put corbenik at 0x24F00000 and use a loader to get it there from non-elf-based a9lh. This is a pre-requisite for using a reentrant payload. This brings an important note; chain.bin is now required even on non-chainloader builds, and unless you are booting via the elf, arm9loaderhax.bin is a stub responsible for loading PREFIX/libexec/corbenik.bin Update chainloader to directly launch payload (chain.bin is a thing of the past now that we're further up in memory) --- Makefile.am | 9 +- boot/chainloader.c | 32 ++---- boot/linker.ld | 4 +- boot/menu.c | 4 + boot/std/fs.c | 3 - bootstub/Makefile.am | 23 ++++ bootstub/chainloader.c | 49 ++++++++ bootstub/fs.c | 1 + bootstub/linker.ld | 253 +++++++++++++++++++++++++++++++++++++++++ bootstub/memory.c | 1 + bootstub/start.s | 1 + configure.ac | 2 +- 12 files changed, 348 insertions(+), 34 deletions(-) create mode 100644 bootstub/Makefile.am create mode 100644 bootstub/chainloader.c create mode 120000 bootstub/fs.c create mode 100644 bootstub/linker.ld create mode 120000 bootstub/memory.c create mode 120000 bootstub/start.s diff --git a/Makefile.am b/Makefile.am index d9f537f..05dd191 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,11 @@ -SUBDIRS = include host external boot patch loader bits +SUBDIRS = include host external boot patch loader bits bootstub ACLOCAL_AMFLAGS = -I m4 boot: include host external patch +bootstub: boot + external: include host loader: external @@ -12,7 +14,7 @@ install: @echo "Please don't call the install target directly, it doesn't work." @exit 1 -all-local: external loader boot bits patch +all-local: external loader boot bits patch bootstub mkdir -p out mkdir -p out@prefix@ mkdir -p out@libdir@/module @@ -27,7 +29,8 @@ all-local: external loader boot bits patch mkdir -p out@libexecdir@ mkdir -p out@sysconfdir@ mkdir -p out@localstatedir@ - cp boot/corbenik.bin out/arm9loaderhax.bin + cp bootstub/bootstub.bin out/arm9loaderhax.bin + cp boot/corbenik.bin out@libexecdir@/ cp boot/corbenik out/corbenik.elf cp loader/loader.cxi out@libdir@/module/native/loader.cxi cp bits/*.bin out@libexecdir@/ diff --git a/boot/chainloader.c b/boot/chainloader.c index 12d8048..8c4f4d5 100644 --- a/boot/chainloader.c +++ b/boot/chainloader.c @@ -27,26 +27,12 @@ void chainload_file(void* data) char* chain_file_data = (char*)data; // We copy because it's possible the payload will overwrite us in memory. + FILE* f; char chain_file[256]; strncpy(chain_file, chain_file_data, 255); - char code_file[] = PATH_BITS "/chain.bin"; - - uint8_t* bootstrap = (uint8_t*)0x24F00000; - uint32_t size = 0, b_size = 0; - uint8_t* chain_data; - - FILE* f = cropen(code_file, "r"); - if (!f) { - // File missing. - panic("Missing chainloader.\n"); - } - - b_size = crsize(f); - crread(bootstrap, 1, b_size, f); - crclose(f); - - chain_data = bootstrap + b_size; + uint32_t size = 0; + uint8_t* chain_data = (uint8_t*)0x23F00000; f = cropen(chain_file, "r"); if (!f) { @@ -70,22 +56,18 @@ void chainload_file(void* data) char* arg0 = (char*)&off[1]; memcpy(arg0, chain_file, strlen(chain_file) + 1); - uint32_t* argc_off = (uint32_t*)memfind(bootstrap, b_size, "ARGC", 4); - uint32_t* argv_off = (uint32_t*)memfind(bootstrap, b_size, "ARGV", 4); - - argc_off[0] = 1; - argv_off[0] = (uint32_t)off; - fprintf(stderr, "Changing display mode and chainloading...\n"); - screen_mode(1); // TODO - Because RGBA8 screeninit is non-standard...ugh + screen_mode(1); // Because RGBA8 screeninit is non-standard...ugh // Copy CakeHax struct where it is expected (at 0x23FFFE00) // It's very very likely we'll corrupt memory with this, but we aren't coming back anyways as of the // next call, so not my problem memcpy((void*)0x23FFFE00, framebuffers, sizeof(struct framebuffers)); - ((void(*)(void*, uint32_t))0x24F00000)(chain_data, size + 256 + 8); // Size of payload + argv. + // TODO - TBH, I should really flush dcache and icache here + + ((void(*)(int, char**))0x23F00000)(1, (char**)off); while(1); } diff --git a/boot/linker.ld b/boot/linker.ld index 904e932..6c0db6b 100644 --- a/boot/linker.ld +++ b/boot/linker.ld @@ -11,8 +11,8 @@ ENTRY(_start) SECTIONS { /* Read-only sections, merged into text segment: */ - /* Changed default address to 0x23F00000 */ - PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x23F00000)); . = SEGMENT_START("text-segment", 0x23F00000); + /* Changed default address to 0x24F00000 */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x24F00000)); . = SEGMENT_START("text-segment", 0x24F00000); .interp : { *(.interp) } .note.gnu.build-id : { *(.note.gnu.build-id) } .hash : { *(.hash) } diff --git a/boot/menu.c b/boot/menu.c index db346ee..ed27bf2 100644 --- a/boot/menu.c +++ b/boot/menu.c @@ -273,6 +273,8 @@ reset() crumount(); // Unmount SD. + set_opt_u32(OPTION_SAVE_LOGS, 0); // FS unmounted, can't log anymore + // Reboot. fprintf(BOTTOM_SCREEN, "Rebooting system...\n"); @@ -286,6 +288,8 @@ poweroff() crumount(); // Unmount SD. + set_opt_u32(OPTION_SAVE_LOGS, 0); // FS unmounted, can't log anymore + // Power off fprintf(BOTTOM_SCREEN, "Powering off system...\n"); diff --git a/boot/std/fs.c b/boot/std/fs.c index b5a40fd..e511df7 100644 --- a/boot/std/fs.c +++ b/boot/std/fs.c @@ -7,7 +7,6 @@ #include "ctr9/io/ctr_sd_interface.h" // for ctr_sd_interface #include "ctr9/io/fatfs/ff.h" // for FILINFO, f_mount, ::FR_OK #include "ctr9/io/fatfs/integer.h" // for UINT -#include "option.h" // for set_opt_u32, OPTION_SAVE_LOGS #include "std/fs.h" // for SEEK_CUR, SEEK_END, SEEK_SET // ctr_nand_crypto_interface ctr_io; @@ -94,8 +93,6 @@ crumount(void) if (f_mount(NULL, "SD:", 1)) return 1; - set_opt_u32(OPTION_SAVE_LOGS, 0); // FS unmounted, can't log anymore - return 0; } diff --git a/bootstub/Makefile.am b/bootstub/Makefile.am new file mode 100644 index 0000000..9a31de3 --- /dev/null +++ b/bootstub/Makefile.am @@ -0,0 +1,23 @@ +include $(top_srcdir)/common.mk + +noinst_PROGRAMS = bootstub +bootstub_CFLAGS=$(AM_CFLAGS) -T$(srcdir)/linker.ld -nostartfiles +bootstub_LDFLAGS=$(AM_LDFLAGS) -lctr9 -Wl,-Map,bootstub.map +EXTRA_DIST = linker.ld + +install: + +all-local: bootstub.bin + +clean-local: + rm -f bootstub.bin + +bootstub.bin: bootstub + $(OBJCOPY) $(OCFLAGS) -O binary bootstub bootstub.bin + +bootstubdir = $(top_srcdir)/source + +inc_dir = $(top_srcdir)/include + +bootstub_SOURCES = \ + start.s fs.c memory.c chainloader.c diff --git a/bootstub/chainloader.c b/bootstub/chainloader.c new file mode 100644 index 0000000..688d4d5 --- /dev/null +++ b/bootstub/chainloader.c @@ -0,0 +1,49 @@ +#include // for uint32_t, uint8_t +#include // for NULL +#include // for memcpy, strlen, strncpy + +#include +#include +#include + + +__attribute__((noreturn)) +void panic() { + memset(*(uint8_t**)(0x23FFFE00), 0xFF, 320*240*3); + while(1); +} + +int main() +{ + FILE* f; + char chain_file[] = PATH_BITS "/corbenik.bin"; + + if (crmount()) { + panic(); + } + + uint8_t* bootstrap = (uint8_t*)0x24F00000; + uint32_t size = 0; + uint8_t* chain_data; + + f = cropen(chain_file, "r"); + if (!f) { + // File missing. + panic(); + } + + size = crsize(f); + char* memory = malloc(size); + crread(memory, 1, size, f); + crclose(f); + + crumount(); // It doesn't really matter if we clean up or not, but why not + + memmove(bootstrap, memory, size); // Memory is now clobbered. Any memory allocation is unsafe past this point. + + // Set args = 2, { PATH_BITS "/corbenik.bin", "-native" } + + ((int(*)(int, char**))bootstrap)(0, 0); + + panic(); +} diff --git a/bootstub/fs.c b/bootstub/fs.c new file mode 120000 index 0000000..1c3a7ce --- /dev/null +++ b/bootstub/fs.c @@ -0,0 +1 @@ +../boot/std/fs.c \ No newline at end of file diff --git a/bootstub/linker.ld b/bootstub/linker.ld new file mode 100644 index 0000000..f11c43c --- /dev/null +++ b/bootstub/linker.ld @@ -0,0 +1,253 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +/* Copyright (C) 2014 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", + "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +/* SEARCH_DIR("/opt/devkitpro/devkitARM/arm-none-eabi/lib"); */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + /* Changed default address to 0x24F00000 */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x23F00000)); . = SEGMENT_START("text-segment", 0x23F00000); + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN (__rel_iplt_end = .); + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rel.plt : + { + *(.rel.plt) + } + .rela.plt : + { + *(.rela.plt) + } + /* Make sure the start.o entry is at the beginning since that's the default alh entry */ + arm9loaderhax_entry : + { + KEEP (*(.text.start)) + } + arm9loaderhax_screeninit (INFO): + { + KEEP (*(screeninit)) + } + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) } + .iplt : { *(.iplt) } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub EXCLUDE_FILE (start.o) .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } + PROVIDE_HIDDEN (__exidx_start = .); + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + PROVIDE_HIDDEN (__exidx_end = .); + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table + .gcc_except_table.*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges + .exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array )) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array )) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } + .data : + { + __data_start = . ; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + __bss_start__ = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + _bss_end__ = . ; __bss_end__ = . ; + . = ALIGN(32 / 8); + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(32 / 8); + __end__ = . ; + _end = .; PROVIDE (end = .); + /* 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) } + .comment 0 : { *(.comment) } + /* 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 .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .stack 0x27F00000 : + { + _stack = .; + *(.stack) + } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} + diff --git a/bootstub/memory.c b/bootstub/memory.c new file mode 120000 index 0000000..abff954 --- /dev/null +++ b/bootstub/memory.c @@ -0,0 +1 @@ +../boot/std/memory.c \ No newline at end of file diff --git a/bootstub/start.s b/bootstub/start.s new file mode 120000 index 0000000..a7ba710 --- /dev/null +++ b/bootstub/start.s @@ -0,0 +1 @@ +../boot/start.s \ No newline at end of file diff --git a/configure.ac b/configure.ac index 449a2d2..ae132d7 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ AC_DEFINE_UNQUOTED([COMPILER_ID], [$COMPILER_ID]) AC_DEFINE_UNQUOTED([CONFIGURE_OPTIONS], [$CONFIGURE_OPTIONS]) -AC_CONFIG_FILES([Makefile boot/Makefile external/Makefile include/Makefile]) +AC_CONFIG_FILES([Makefile boot/Makefile external/Makefile include/Makefile bootstub/Makefile]) AC_CONFIG_SUBDIRS([external/libctr9]) -- 2.39.5