From: Jon Feldman Date: Thu, 9 Feb 2017 12:41:19 +0000 (-0500) Subject: Clean up a lot of logic related to the reboot hook. X-Git-Tag: v0.3.1~10 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=d11b7da898a008993443b963b0c713c1ab3e7bfd;p=corbenik%2Fcorbenik.git Clean up a lot of logic related to the reboot hook. I can confirm that we now get into corbenik's payload on firmlaunch (the good old power off on button approach) but some step of initialization is resulting in a hang. Not there yet, sadly. --- diff --git a/bits/Makefile b/bits/Makefile index 814e965..0ea3a0a 100644 --- a/bits/Makefile +++ b/bits/Makefile @@ -6,7 +6,7 @@ OBJECTS=$(patsubst %.s, %.bin, $(SOURCES)) all: $(OBJECTS) %.o: %.s - arm-none-eabi-as -o $@ $< + arm-none-eabi-as -I$(shell pwd)/../include -o $@ $< %.elf: %.o arm-none-eabi-ld -T link.ld -o $@ $< diff --git a/bits/reboot_code.s b/bits/reboot_code.s deleted file mode 100644 index de404f2..0000000 --- a/bits/reboot_code.s +++ /dev/null @@ -1,96 +0,0 @@ -.set firm_addr, 0x24000000 // Temporary location where we'll load the FIRM to -.set firm_maxsize, 0x200000 // Random value that's bigger than any of the currently known firm's sizes. - -.section .text -.global _start -_start: - - // Set MPU settings - mrc p15, 0, r0, c2, c0, 0 // dcacheable - mrc p15, 0, r12, c2, c0, 1 // icacheable - mrc p15, 0, r1, c3, c0, 0 // write bufferable - mrc p15, 0, r2, c5, c0, 2 // daccess - mrc p15, 0, r3, c5, c0, 3 // iaccess - ldr r4, =0x18000035 // 0x18000000 128M - bic r2, r2, #0xF0000 // unprotect region 4 - bic r3, r3, #0xF0000 // unprotect region 4 - orr r0, r0, #0x10 // dcacheable region 4 - orr r2, r2, #0x30000 // region 4 r/w - orr r3, r3, #0x30000 // region 4 r/w - orr r12, r12, #0x10 // icacheable region 4 - orr r1, r1, #0x10 // write bufferable region 4 - mcr p15, 0, r0, c2, c0, 0 - mcr p15, 0, r12, c2, c0, 1 - mcr p15, 0, r1, c3, c0, 0 // write bufferable - mcr p15, 0, r2, c5, c0, 2 // daccess - mcr p15, 0, r3, c5, c0, 3 // iaccess - mcr p15, 0, r4, c6, c4, 0 // region 4 (hmmm) - - mrc p15, 0, r0, c2, c0, 0 // dcacheable - mrc p15, 0, r1, c2, c0, 1 // icacheable - mrc p15, 0, r2, c3, c0, 0 // write bufferable - orr r0, r0, #0x20 // dcacheable region 5 - orr r1, r1, #0x20 // icacheable region 5 - orr r2, r2, #0x20 // write bufferable region 5 - mcr p15, 0, r0, c2, c0, 0 // dcacheable - mcr p15, 0, r1, c2, c0, 1 // icacheable - mcr p15, 0, r2, c3, c0, 0 // write bufferable - - // Copy the firmware - mov r4, #firm_addr - add r5, r4, #0x40 // Start of loop - add r6, r5, #0x30 * 3 // End of loop (scan 4 entries) - - copy_firm_loop: - ldr r0, [r5] - cmp r0, #0 - addne r0, r4 // src - ldrne r1, [r5, #4] // dest - ldrne r2, [r5, #8] // size - blne memcpy32 - - cmp r5, r6 - addlo r5, #0x30 - blo copy_firm_loop - - // Flush cache - mov r2, #0 - mov r1, r2 - flush_cache: - mov r0, #0 - mov r3, r2, lsl #30 - flush_cache_inner_loop: - orr r12, r3, r0, lsl#5 - mcr p15, 0, r1, c7, c10, 4 // drain write buffer - mcr p15, 0, r12, c7, c14, 2 // clean and flush dcache entry (index and segment) - add r0, #1 - cmp r0, #0x20 - bcc flush_cache_inner_loop - add r2, #1 - cmp r2, #4 - bcc flush_cache - - // Enable MPU - ldr r0, =0x42078 // alt vector select, enable itcm - mcr p15, 0, r0, c1, c0, 0 - mcr p15, 0, r1, c7, c5, 0 // flush dcache - mcr p15, 0, r1, c7, c6, 0 // flush icache - mcr p15, 0, r1, c7, c10, 4 // drain write buffer - mov r0, #firm_addr - - // Boot FIRM - mov r1, #0x1FFFFFFC - ldr r2, [r0, #8] // arm11 entry - str r2, [r1] - ldr r0, [r0, #0xC] // arm9 entry - bx r0 -.pool - -memcpy32: // memcpy32(void *src, void *dst, unsigned int size) - add r2, r0 - memcpy32_loop: - ldmia r0!, {r3} - stmia r1!, {r3} - cmp r0, r2 - blo memcpy32_loop - bx lr diff --git a/bits/reboot_hook.s b/bits/reboot_hook.s index 5681b0e..18bc435 100644 --- a/bits/reboot_hook.s +++ b/bits/reboot_hook.s @@ -1,5 +1,5 @@ -.set firm_addr, 0x24000000 // Temporary location where we'll load the FIRM to -.set firm_maxsize, 0x200000 // Random value that's bigger than any of the currently known firm's sizes. +.set load_addr, 0x24F00000 +.set load_maxsize, 0x200000 // Random value that's bigger than corbenik .section .text .global _start @@ -20,84 +20,25 @@ _start: cmp r0, r2 bne pxi_wait_recv - // Convert 2 bytes of the path string - // This will be the method of getting the lower 2 bytes of the title ID - // until someone bothers figuring out where the value is derived from. - mov r0, #0 // Result - add r1, sp, #0x3A8 - 0x70 - add r1, #0x22 // The significant bytes - mov r2, #4 // Maximum loops (amount of bytes * 2) - - hex_string_to_int_loop: - ldr r3, [r1], #2 // 2 because it's a utf-16 string. - and r3, #0xFF - - // Check if it"s a number - cmp r3, #'0' - blo hex_string_to_int_end - sub r3, #'0' - cmp r3, #9 - bls hex_string_to_int_calc - - // Check if it"s a capital letter - cmp r3, #'A' - '0' - blo hex_string_to_int_end - sub r3, #'A' - '0' - 0xA // Make the correct value: 0xF >= al >= 0xA - cmp r3, #0xF - bls hex_string_to_int_calc - - // Incorrect value: x > "A" - bhi hex_string_to_int_end - - hex_string_to_int_calc: - orr r0, r3, r0, lsl #4 - subs r2, #1 - bne hex_string_to_int_loop - hex_string_to_int_end: - - // Get the FIRM path - cmp r0, #0x0002 // NATIVE_FIRM - ldreq r1, firm_fname - beq check_fname - - ldr r5, =0x0102 // TWL_FIRM - cmp r0, r5 - ldreq r1, twl_firm_fname - beq check_fname - - ldr r5, =0x0202 // AGB_FIRM - cmp r0, r5 - ldreq r1, agb_firm_fname - beq check_fname - - fallback: - // Fallback: Load specified FIRM from exefs - add r1, sp, #0x3A8-0x70 // Location of exefs string. - b load_firm - - check_fname: - // Check the given string offset - cmp r1, #0 - beq fallback - - load_firm: + load_file: // Open file add r0, r7, #8 + adr r1, boot_fname mov r2, #1 ldr r6, fopen orr r6, #1 blx r6 cmp r0, #0 // Check if we were able to load the FIRM - bne fallback // Otherwise, try again with the FIRM from exefs. - // This will loop indefinitely if the exefs FIRM fails to load, but whatever. + bne die // Otherwise, hang. - // Read file + read_file: + // Read file to the proper base. mov r0, r7 adr r1, bytes_read - mov r2, #firm_addr - mov r3, #firm_maxsize - ldr r6, [sp, #0x3A8-0x198] + ldr r2, =load_addr + ldr r3, =load_maxsize + ldr r6, [r7] ldr r6, [r6, #0x28] blx r6 @@ -108,18 +49,47 @@ _start: mov r3, #0 swi 0x7C - // Jump to reboot code - ldr r0, reboot_code - swi 0x7B + jump_to_kernel: + // Jump to reboot code in kernel mode + ldr r0, koffset_base + add r0, pc + swi 0x7B die: b die -.align 4 -bytes_read: .word 0 -fopen: .ascii "open" -reboot_code: .ascii "rebc" +bytes_read: .word 0 +fopen: .ascii "OPEN" +koffset_base: .word kernel_code-jump_to_kernel-12 +.pool + +kernel_code: + // Disable MPU + ldr r0, =0x42078 + mcr p15, 0, r0, c1, c0, 0 + + // Flush cache + mov r2, #0 + mov r1, r2 + flush_cache: + mov r0, #0 + mov r3, r2, lsl #30 + flush_cache_inner_loop: + orr r12, r3, r0, lsl#5 + mcr p15, 0, r12, c7, c14, 2 // clean and flush dcache entry (index and segment) + add r0, #1 + cmp r0, #0x20 + bcc flush_cache_inner_loop + add r2, #1 + cmp r2, #4 + bcc flush_cache + + mcr p15, 0, r1, c7, c10, 4 // drain write buffer + + mcr p15, 0, r1, c7, c5, 0 // Flush icache + + ldr r0, =load_addr + bx r0 + .pool -firm_fname: .ascii "NATF" -twl_firm_fname: .ascii "TWLF" -agb_firm_fname: .ascii "AGBF" +boot_fname: // This gets appended at insert-time diff --git a/boot/arm11.c b/boot/arm11.c index 1cc97b7..54d6892 100644 --- a/boot/arm11.c +++ b/boot/arm11.c @@ -37,7 +37,6 @@ #include // for ctr_cache_clean_and_flush_all #include // for i2cWriteRegister, I2C_DEV_MCU #include // for memalign -#include // for get_opt_u32, OPTION_BRIGHTNESS #include // for framebuffers struct framebuffers *framebuffers; @@ -161,10 +160,10 @@ void set_fb_struct() { } } -void screen_mode(uint32_t mode) { +void screen_mode(uint32_t mode, uint32_t bright_level) { static uint32_t stride, init_top, init_bottom, bright; - bright = brightness[get_opt_u32(OPTION_BRIGHTNESS)]; + bright = brightness[bright_level]; stride = 240; switch(mode) { diff --git a/boot/chainloader.c b/boot/chainloader.c index 8c4f4d5..fead361 100644 --- a/boot/chainloader.c +++ b/boot/chainloader.c @@ -12,6 +12,7 @@ #include // for crclose, cropen, crread, crsize, recur... #include // for memfind, strdup_self #include // for PATH_BITS, PATH_CHAINS +#include // for get_opt_u32 #include "ctr9/io/fatfs/ff.h" // for FILINFO, f_stat, ::FR_OK, AM_DIR uint32_t current_chain_index = 0; @@ -58,7 +59,7 @@ void chainload_file(void* data) fprintf(stderr, "Changing display mode and chainloading...\n"); - screen_mode(1); // Because RGBA8 screeninit is non-standard...ugh + screen_mode(1, get_opt_u32(OPTION_BRIGHTNESS)); // 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 diff --git a/boot/corbenik.c b/boot/corbenik.c index 4a192ea..737ec27 100644 --- a/boot/corbenik.c +++ b/boot/corbenik.c @@ -2,6 +2,7 @@ #include #include // for screen_mode, RGBA8, installArm11Stub, set_... #include // for ctr_hid_get_buttons, CTR_HID_RT +#include // for ctr_system_poweroff #include // for prepatch_firm, boot_firm #include // for prepatch_firm, boot_firm #include // for wait @@ -26,6 +27,9 @@ extern int changed_consoles; int main(int argc, char** argv) { + if (ctr_hid_get_buttons() & CTR_HID_LT) + ctr_system_poweroff(); + int have_bg = 0; int si = 0; @@ -37,7 +41,7 @@ main(int argc, char** argv) std_init(); if (crmount()) - poweroff(); // Failed to mount SD. Bomb out. + ctr_system_poweroff(); // We can't use poweroff here, since that does n/a cleanup that will cause a hang. load_config(); // Load configuration. @@ -69,7 +73,7 @@ main(int argc, char** argv) shut_up(); // This does exactly what it sounds like. if (have_bg && !si) { - screen_mode(RGBA8); // Use RGBA8 mode. + screen_mode(RGBA8, get_opt_u32(OPTION_BRIGHTNESS)); // Use RGBA8 mode. si = 1; clear_disp(TOP_SCREEN); @@ -77,7 +81,7 @@ main(int argc, char** argv) } } else { if (!si) { - screen_mode(RGBA8); // Use RGBA8 mode. + screen_mode(RGBA8, get_opt_u32(OPTION_BRIGHTNESS)); // Use RGBA8 mode. si = 1; clear_disp(TOP_SCREEN); diff --git a/boot/patch/reboot.c b/boot/patch/reboot.c index b31fb3e..5f423a2 100644 --- a/boot/patch/reboot.c +++ b/boot/patch/reboot.c @@ -15,11 +15,14 @@ uint8_t* getProcess9(uint8_t *pos, uint32_t size, uint32_t *process9Size, uint32_t *process9MemAddr) { - uint8_t *off = memfind(pos, size, "ess9", 4); - *process9Size = *(uint32_t *)(off - 0x60) * 0x200; - *process9MemAddr = *(uint32_t *)(off + 0xC); + uint8_t *magic = memfind(pos, size, "NCCH", 4); + cxi_h* cxi = (cxi_h*)(magic - 0x100); + + *process9Size = (cxi->ncch.exeFSSize - 1) * 0x200; + *process9MemAddr = cxi->exheader.sci.textCodeSet.address; + // Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size) - return off - 0x204 + (*(uint32_t *)(off - 0x64) * 0x200) + 0x200; + return (uint8_t*)cxi + (cxi->ncch.exeFSOffset + 1) * 0x200; } int @@ -30,9 +33,10 @@ patch_reboot(firm_h* firm_loc) uint32_t process9Size, process9MemAddr; uint8_t *process9Offset = - getProcess9((uint8_t *)firm_loc + firm_loc->section[2].offset + 0x15000, firm_loc->section[2].size - 0x15000, &process9Size, &process9MemAddr); + getProcess9((uint8_t *)firm_loc + firm_loc->section[2].offset, firm_loc->section[2].size, &process9Size, &process9MemAddr); fprintf(stderr, "reboot: proc9 mem @ %lx\n", (uint32_t)process9MemAddr); + fprintf(stderr, "reboot: proc9 off @ %lx\n", (uint32_t)process9Offset); wait(); @@ -48,7 +52,7 @@ patch_reboot(firm_h* firm_loc) // Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1 uint32_t fOpenOffset = (uint32_t)(off + 9 - (-((*(uint32_t *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - (uint32_t)process9Offset + process9MemAddr); - fprintf(stderr, "reboot: cropen @ %lx\n", fOpenOffset); + fprintf(stderr, "reboot: fopen @ %lx\n", fOpenOffset); wait(); @@ -62,65 +66,23 @@ patch_reboot(firm_h* firm_loc) crclose(f); // Put the fOpen offset in the right location - uint32_t *pos_cropen = (uint32_t *)memfind(off, size, "open", 4); - if (!pos_cropen) + uint32_t *pos_fopen = (uint32_t *)memfind(off, size, "OPEN", 4); + if (!pos_fopen) return 1; - *pos_cropen = fOpenOffset; + *pos_fopen = fOpenOffset; - uint32_t *pos_native = (uint32_t *)memfind(off, size, "NATF", 4); - uint32_t *pos_twl = (uint32_t *)memfind(off, size, "TWLF", 4); - uint32_t *pos_agb = (uint32_t *)memfind(off, size, "AGBF", 4); - - if (!pos_native && !pos_twl && !pos_agb) - return 1; + // The path is positioned at the end of our assembly to avoid reservation of space. + // We append it here. + uint8_t path[] = "sdmc:" PATH_BITS "/corbenik.bin"; - fprintf(stderr, "reboot: NATF @ %lx\n", (uint32_t)pos_native); - fprintf(stderr, "reboot: TWLF @ %lx\n", (uint32_t)pos_twl); - fprintf(stderr, "reboot: AGBF @ %lx\n", (uint32_t)pos_agb); - - uint8_t *mem = (uint8_t *)0x01FF8000; // 0x8000 space that will be resident. This is AXI WRAM. We have about 0x3700 bytes here. - // According to 3dbrew, this space's props from userland: - // [L2L] VA fff00000..fff20000 -> PA 1ff80000..1ffa0000 [ X ] [ Priv: R-, User: -- ] - // It can be executed by the system but not written (and can only be executed with privs) - // This seems to be the perfect place to stick some code to be resident in memory. Beyond this, - // it might be needed to replace a svc call to access it. I'm rather sure that NTR does this. - - *pos_native = (uint32_t)mem; - memcpy(mem, u"sdmc:", 10); - mem += 10; - for (size_t i = 0; i < sizeof(PATH_NATIVE_P); i++, mem += 2) { - *mem = PATH_NATIVE_P[i]; - *(mem + 1) = 0; - } - - *pos_twl = (uint32_t)mem; - memcpy(mem, u"sdmc:", 10); - mem += 10; - for (size_t i = 0; i < sizeof(PATH_TWL_P); i++, mem += 2) { - *mem = PATH_TWL_P[i]; - *(mem + 1) = 0; - } + uint16_t *pos = (uint16_t*)(off + size); - *pos_agb = (uint32_t)mem; - memcpy(mem, u"sdmc:", 10); - mem += 10; - for (size_t i = 0; i < sizeof(PATH_AGB_P); i++, mem += 2) { - *mem = PATH_AGB_P[i]; - *(mem + 1) = 0; + for(int i=0; path[i] != 0; i++) { + pos[0] = path[i]; + pos++; } - - uint32_t *pos_rebc = (uint32_t *)memfind(off, size, "rebc", 4); - *pos_rebc = (uint32_t)mem; - - fprintf(stderr, "reboot: rebc @ %lx\n", (uint32_t)pos_rebc); - - f = cropen(PATH_REBOOT_CODE, "r"); - if (!f) - return 1; - - crread(mem, 1, crsize(f), f); - crclose(f); + pos[0] = 0; return 0; } diff --git a/bootstub/chainloader.c b/bootstub/chainloader.c index 688d4d5..c0d921e 100644 --- a/bootstub/chainloader.c +++ b/bootstub/chainloader.c @@ -2,6 +2,9 @@ #include // for NULL #include // for memcpy, strlen, strncpy +#include +#include + #include #include #include @@ -9,7 +12,7 @@ __attribute__((noreturn)) void panic() { - memset(*(uint8_t**)(0x23FFFE00), 0xFF, 320*240*3); + ctr_system_poweroff(); while(1); } @@ -42,8 +45,9 @@ int main() memmove(bootstrap, memory, size); // Memory is now clobbered. Any memory allocation is unsafe past this point. // Set args = 2, { PATH_BITS "/corbenik.bin", "-native" } + ctr_cache_clean_and_flush_all(); - ((int(*)(int, char**))bootstrap)(0, 0); + ((int(*)(int, char**))bootstrap)(0, NULL); panic(); } diff --git a/include/arm11.h b/include/arm11.h index 983cbd9..57e9c8f 100644 --- a/include/arm11.h +++ b/include/arm11.h @@ -47,7 +47,7 @@ * * \param mode Screen mode to initialize in, one of RGBA8, BGR8, RGB565_OES, RGB5_A1_OES, or RGBA4_OES */ -void screen_mode(uint32_t mode); +void screen_mode(uint32_t mode, uint32_t bright_level); /* Invokes a bare ARM11 function. For usage, see arm11.c. *