]> Chaos Git - corbenik/corbenik.git/commitdiff
Reboot WIP.
authorchaoskagami <chaos.kagami@gmail.com>
Mon, 6 Jun 2016 22:08:31 +0000 (18:08 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Tue, 7 Jun 2016 03:12:50 +0000 (23:12 -0400)
This is inefficient and clearly a bastardization of Luma AND Cakes' reboot code, but it seems to work.

16 files changed:
Makefile
external/Makefile
external/svc/Makefile
external/svc/patches.s [deleted file]
external/svc/reboot_code.s [new file with mode: 0644]
external/svc/reboot_hook.s [new file with mode: 0644]
source/config.h
source/firm/firm.c
source/firm/headers.h
source/menu.c
source/patch/module.c
source/patch/reboot.c [new file with mode: 0644]
source/patch_format.h
source/patcher.c
source/start.s
source/std/draw.c

index 8c8399286b5cddc93ba21113384f06fbfc590994..6971f187e9238717a1936bfdc1984c9857943530 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -46,6 +46,9 @@ patch:
 
 .PHONY: a9lh
 a9lh: $(dir_out)/arm9loaderhax.bin
+       # For the reboot patch.
+       mkdir -p $(dir_out)/corbenik/bits
+       cp $(dir_out)/arm9loaderhax.bin $(dir_out)/corbenik/bits/corbenik.bin
 
 .PHONY: reformat
 reformat:
index f30799acde727aa1f2c54110b38ba3841b2270a3..27b623f7bc104d688a1a495a4e9525f210aca596 100644 (file)
@@ -6,6 +6,8 @@ all: loader svc screeninit
        cp loader/loader.cxi ../out/corbenik/module/loader.cxi
        cp svc/7b.bin ../out/corbenik/svc/7b.bin
        cp svc/emunand.bin ../out/corbenik/bits/emunand.bin
+       cp svc/reboot_hook.bin ../out/corbenik/bits/reboot_hook.bin
+       cp svc/reboot_code.bin ../out/corbenik/bits/reboot_code.bin
        cp screeninit/build/screeninit.bin ../out/corbenik/bits/screeninit.bin
 
 .PHONY: clean
index 243b4c84af1cd4252bd792cd4c31aadbadd65469..600ae212f8b4cdd71e16400b1f702edfb5dab537 100644 (file)
@@ -1,6 +1,6 @@
 PATH := $(PATH):$(DEVKITARM)/bin
 
-all: 7b.bin stub.bin emunand.bin
+all: 7b.bin stub.bin emunand.bin reboot_hook.bin reboot_code.bin
 
 %.o: %.s
        arm-none-eabi-as -o $@ $<
diff --git a/external/svc/patches.s b/external/svc/patches.s
deleted file mode 100644 (file)
index 44eaf6f..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-.arm.little
-
-.create "patch1.bin", 0
-.arm
-nand_sd:
-    ; Original code that still needs to be executed.
-    mov r4, r0
-    mov r5, r1
-    mov r7, r2
-    mov r6, r3
-    ; End.
-
-    ; If we're already trying to access the SD, return.
-    ldr r2, [r0, #4]
-    ldr r1, [sdmmc]
-    cmp r2, r1
-    beq nand_sd_ret
-
-    str r1, [r0, #4]  ; Set object to be SD
-    ldr r2, [r0, #8]  ; Get sector to read
-    cmp r2, #0  ; For GW compatibility, see if we're trying to read the ncsd header (sector 0)
-
-    ldr r3, [nand_offset]
-    add r2, r3  ; Add the offset to the NAND in the SD.
-
-    ldreq r3, [ncsd_header_offset]
-    addeq r2, r3  ; If we're reading the ncsd header, add the offset of that sector.
-
-    str r2, [r0, #8]  ; Store sector to read
-
-    nand_sd_ret:
-        ; Restore registers.
-        mov r1, r5
-        mov r2, r7
-        mov r3, r6
-
-        ; Return 4 bytes behind where we got called,
-        ;   due to the offset of this function being stored there.
-        mov r0, lr
-        add r0, #4
-        bx r0
-.pool
-nand_offset: .ascii "NAND"  ; The starting offset of the emuNAND on the SD.
-ncsd_header_offset: .ascii "NCSD"  ; The offset of the first emuNAND sector relative to the start of the emuNAND (Used for when the first sector is placed at the end).
-sdmmc: .ascii "sdmmc"  ; The offset of the sdmmc object.
-.close
-
-.create "patch2.bin", 0
-.arm
-       .word 0x360003
-       .word 0x10100000
-       .word 0x1000001
-       .word 0x360003
-       .word 0x20000000
-       .word 0x1010101
-       .word 0x200603
-       .word 0x8000000
-       .word 0x1010101
-       .word 0x1C0603
-       .word 0x8020000
-.close
-
-.create "patch3.bin", 0
-.thumb
-       ldr r4, [_nand_sd_write]
-       blx r4
-.align 4
-_nand_sd_write: .ascii "mem"
-.close
-
-.create "patch4.bin", 0
-.thumb
-       ldr r4, [_nand_sd_read]
-       blx r4
-.align 4
-_nand_sd_read: .ascii "mem"
-.close
diff --git a/external/svc/reboot_code.s b/external/svc/reboot_code.s
new file mode 100644 (file)
index 0000000..de404f2
--- /dev/null
@@ -0,0 +1,96 @@
+.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/external/svc/reboot_hook.s b/external/svc/reboot_hook.s
new file mode 100644 (file)
index 0000000..5681b0e
--- /dev/null
@@ -0,0 +1,125 @@
+.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:
+    // Interesting registers and locations to keep in mind, set before this code is ran:
+    // - sp + 0x3A8 - 0x70: FIRM path in exefs.
+    // - r7 (which is sp + 0x3A8 - 0x198): Reserved space for file handle
+    // - *(sp + 0x3A8 - 0x198) + 0x28: fread function.
+
+    pxi_wait_recv:
+        ldr r2, =0x44846
+        ldr r0, =0x10008000
+        readPxiLoop1:
+            ldrh r1, [r0, #4]
+            lsls r1, #0x17
+            bmi readPxiLoop1
+            ldr r0, [r0, #0xC]
+        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:
+        // Open file
+        add r0, r7, #8
+        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.
+
+        // Read file
+        mov r0, r7
+        adr r1, bytes_read
+        mov r2, #firm_addr
+        mov r3, #firm_maxsize
+        ldr r6, [sp, #0x3A8-0x198]
+        ldr r6, [r6, #0x28]
+        blx r6
+
+    // Set kernel state
+    mov r0, #0
+    mov r1, #0
+    mov r2, #0
+    mov r3, #0
+    swi 0x7C
+
+    // Jump to reboot code
+    ldr r0, reboot_code
+    swi 0x7B
+
+    die:
+        b die
+
+.align 4
+bytes_read:     .word 0
+fopen:          .ascii "open"
+reboot_code:    .ascii "rebc"
+.pool
+firm_fname:     .ascii "NATF"
+twl_firm_fname: .ascii "TWLF"
+agb_firm_fname: .ascii "AGBF"
index 4d2f4b87817410e291e6686c6348df756a5ecafb..4c1d0cf5d409b9259531034fb16fe96c17b79228 100644 (file)
@@ -105,6 +105,9 @@ struct options_s
 // Dump titles' code sections as they're loaded by the loader module.
 #define OPTION_LOADER_DUMPCODE 18
 
+// Hook firmlaunches.
+#define OPTION_REBOOT 19
+
 // Save log files during boot and from loader.
 // This will slow things down a bit.
 #define OPTION_SAVE_LOGS 253
index 3ea79f994cd53e2af152cafdf517e86fb2eaf7f8..a9fcd7c5276228454890caf778f0a130180a7536 100644 (file)
@@ -433,5 +433,17 @@ boot_cfw()
     if (patch_firm_all() != 0)
         return;
 
+       if (config.options[OPTION_REBOOT] && config.options[OPTION_RECONFIGURED]) {
+               fprintf(stderr, "Saving FIRMs for reboot...");
+               if (!write_file(firm_loc, PATH_NATIVE_P, firm_size))
+                       abort("Failed to save prepatched native\n");
+
+               if (!write_file(twl_firm_loc, PATH_TWL_P, twl_firm_size))
+                       abort("Failed to save prepatched twl\n");
+
+               if (!write_file(agb_firm_loc, PATH_AGB_P, agb_firm_size))
+                       abort("Failed to save prepatched agb\n");
+       }
+
     boot_firm();
 }
index 60c0cca4e99dca3b1ee011f2c83037e8bdf05bb2..27fcd8023c81ae216937885da1fd25c0f843251b 100644 (file)
 #define ARM9BIN_MAGIC (0x47704770)
 #define LGY_ARM9BIN_MAGIC (0xB0862000)
 
-struct memory_header
-{
-    uint32_t location;
-    uint32_t size;
-} memory_header_t;
-
 typedef struct firm_section_h
 {
     uint32_t offset;
index 9af726b50e512cd16a9183ff3c948fd92f85d33c..b49d98d5260c755339825bd7e04fd4681b0eee5a 100644 (file)
@@ -21,22 +21,16 @@ static struct options_s options[] = {
     // Patches.
     { 0, "\x1b[32;40mGeneral Options\x1b[0m", "", not_option, 0, 0 },
 
-    { 0, "", "", not_option, 0, 0 },
-
     { OPTION_SVCS, "SVC Replacement", "Replaces ARM11 svc calls, including svcBackdoor. With 11.0 NATIVE_FIRM, you probably want this.", boolean_val, 0, 0 },
 
-    { 0, "", "", not_option, 0, 0 },
+    { OPTION_REBOOT, "Reboot Hook", "Hooks firmlaunch to keep the CFW resident on o3DS and allow patching TWL/AGB firms as well.", boolean_val, 0, 0 },
 
     { OPTION_EMUNAND, "Use EmuNAND", "Redirects NAND write/read to the SD.", boolean_val, 0, 0 },
     { OPTION_EMUNAND_INDEX, "  Index", "Which EmuNAND to use. Currently, 10 maximum (but this is arbitrary)", ranged_val, 0, 0x9 },
 
-    { 0, "", "", not_option, 0, 0 },
-
     { OPTION_AUTOBOOT, "Autoboot", "Boot the system automatically, unless the R key is held.", boolean_val, 0, 0 },
     { OPTION_SILENCE, "  Silent mode", "Suppress all debug output during autoboot. You'll see the screen turn on, then off.", boolean_val, 0, 0 },
 
-    { 0, "", "", not_option, 0, 0 },
-
     { OPTION_READ_ME, "Hide `Help`", "Hides the help option from the main menu.", boolean_val, 0, 0 },
 
     // space
index 69da342c38f9e6727f582386c5dd20fe007ded19..5bf79f57bf1d5bb2396cd4e258425a92c0ae0cda 100644 (file)
@@ -38,7 +38,7 @@ PATCH(modules)
             // Expand firmware module size if needed to accomodate replacement.
             if (module->contentSize > sysmodule->contentSize) {
                 uint32_t need_units = (module->contentSize - sysmodule->contentSize);
-                fprintf(stderr, "Module: Would grow %d units but NYI\n", need_units);
+                fprintf(stderr, "module: Would grow %d units but NYI\n", need_units);
                 continue;
 
                 // TODO - so in a nutshell, the reason Luma works is because it
diff --git a/source/patch/reboot.c b/source/patch/reboot.c
new file mode 100644 (file)
index 0000000..47f9db5
--- /dev/null
@@ -0,0 +1,102 @@
+#include "emunand.h"
+#include "../std/memory.h"
+#include "../std/draw.h"
+#include "../std/fs.h"
+#include "../std/abort.h"
+#include "../firm/firm.h"
+#include "../firm/fcram.h"
+#include "../fatfs/sdmmc.h"
+#include "../firm/headers.h"
+#include "../patch_format.h"
+
+int wait();
+
+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);
+       //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
+       return off - 0x204 + (*(uint32_t *)(off - 0x64) * 0x200) + 0x200;
+}
+
+void patch_reboot() {
+       //Look for firmlaunch code
+       const uint8_t pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
+
+       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);
+
+       fprintf(stderr, "reboot: proc9 mem @ %x\n", process9MemAddr);
+
+       wait();
+
+       uint8_t *off = memfind(process9Offset, process9Size, pattern, 4) - 0x10;
+
+       fprintf(stderr, "reboot: firmlaunch @ %x\n", off);
+
+       //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)) - process9Offset + process9MemAddr);
+
+       fprintf(stderr, "reboot: fopen @ %x\n", fOpenOffset);
+
+       wait();
+
+       //Copy firmlaunch code
+       FILE* f = fopen(PATH_BITS "/reboot_hook.bin", "r");
+       if (!f)
+               abort("reboot: hook not found on SD\n");
+
+       uint32_t size = fsize(f);
+       fread(off, 1, size, f);
+       fclose(f);
+
+       //Put the fOpen offset in the right location
+       uint32_t *pos_fopen = (uint32_t *)memfind(off, size, "open", 4);
+       if (!pos_fopen)
+               abort("reboot: fopen location missing\n");
+
+       *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)
+               abort("reboot: missing string placeholder?\n");
+
+       fprintf(stderr, "reboot: NATF @ %x\n", pos_native);
+       fprintf(stderr, "reboot: TWLF @ %x\n", pos_twl);
+       fprintf(stderr, "reboot: AGBF @ %x\n", pos_agb);
+
+       uint8_t* mem = (uint8_t*)0x01FF8000; // 0x8000 space that will be resident.
+
+       *pos_native = (uint32_t)mem;
+       memcpy(mem, L"sdmc:", 10);
+       mem += 10;
+       for(size_t i=0; i < sizeof(PATH_NATIVE_P); i++, mem += 2)
+               *mem = PATH_NATIVE_P[i];
+
+       *pos_twl = (uint32_t)mem;
+       memcpy(mem, L"sdmc:", 10);
+       mem += 10;
+       for(size_t i=0; i < sizeof(PATH_TWL_P); i++, mem += 2)
+               *mem = PATH_TWL_P[i];
+
+       *pos_agb = (uint32_t)mem;
+       memcpy(mem, L"sdmc:", 10);
+       mem += 10;
+       for(size_t i=0; i < sizeof(PATH_AGB_P); i++, mem += 2)
+               *mem = PATH_AGB_P[i];
+
+       uint32_t *pos_rebc    = (uint32_t*)memfind(off, size, "rebc", 4);
+       *pos_rebc = (uint32_t)mem;
+
+       fprintf(stderr, "reboot: rebc @ %x\n", pos_rebc);
+
+       f = fopen(PATH_BITS "/reboot_code.bin", "r");
+       if (!f)
+               abort("reboot: boot not found on SD\n");
+
+       fread(mem, 1, fsize(f), f);
+       fclose(f);
+}
index dc83c807295f921002de9161942e7dae37435df9..8bc587fac762c2c9346133bdbeb0a30758efc5a2 100644 (file)
 
 #define PATH_TEMP PATH_CFW "/cache"           // Files that are transient and used to speed operation
 #define PATH_LOADER_CACHE PATH_TEMP "/loader" // Cached patch bytecode for loader.
+
+#define PATH_NATIVE_P PATH_TEMP "/p_native"
+#define PATH_AGB_P PATH_TEMP "/p_agb"
+#define PATH_TWL_P PATH_TEMP "/p_twl"
+
 #define PATH_KEYS PATH_CFW "/keys"            // Keyfiles will be loaded from this dir, and
                                               // additionally the root if not found.
 #define PATH_EXEFS PATH_CFW "/exe"            // ExeFS overrides, named like '<titleid>.exefs' - NYI
index d2c60ddbb9c71e71133865b023e4242d68b3ee3d..b2be51b18486e923cf9457b2c76c6ff98d478f87 100644 (file)
@@ -13,6 +13,7 @@ uint32_t wait_key();
 
 extern int patch_services();
 extern int patch_modules();
+extern int patch_reboot();
 
 extern int doing_autoboot;
 
@@ -69,6 +70,13 @@ patch_firm_all()
         wait();
     }
 
+    // Hook firmlaunch?
+    if (config.options[OPTION_REBOOT]) {
+        patch_reboot();
+
+        wait();
+    }
+
     // Inject services?
     if (config.options[OPTION_SVCS]) {
         if (patch_services()) {
@@ -77,6 +85,7 @@ patch_firm_all()
         wait();
     }
 
+
     // Use ARM9 hook thread?
     if (config.options[OPTION_ARM9THREAD]) {
         // Yes.
index 2ec4c5e43a7189d7d2b49f5313f471fed9941620..bc0b91b942e58b3eef5e90462af90fd72917c54b 100644 (file)
@@ -2,6 +2,10 @@
 .align 4
 .global _start
 _start:
+    b mpu
+
+    nop
+mpu:
     @ Change the stack pointer
     mov sp, #0x27000000
 
index 3dc565ab5001073cf955eac797b61f6144ac9652..45225ea1e81a2ae49c915c5eaecb22cd91ae5c23 100644 (file)
@@ -49,7 +49,7 @@ clear_disp(uint8_t *screen)
     if (screen == BOTTOM_SCREEN && config.options[OPTION_SAVE_LOGS]) {
         FILE *f = fopen(PATH_CFW "/boot.log", "w");
         fseek(f, 0, SEEK_END);
-        for (int i = 0; i < TEXT_BOTTOM_HEIGHT; i++) {
+        for (int i = 0; i < TEXT_BOTTOM_HEIGHT - 1; i++) {
             char *text = text_buffer_bottom + (TEXT_BOTTOM_WIDTH * i);
                        for(int j = 0; j < TEXT_BOTTOM_WIDTH; j++) {
                                if (text[j] == 0)
@@ -225,7 +225,7 @@ putc(void *buf, const int c)
             cursor_y[0]++;
         }
 
-        while (cursor_y[0] >= height) {
+        while (cursor_y[0] >= height - 1) {
 #ifdef BUFFER
             // Scroll.
             for (unsigned int y = 0; y < height - 1; y++) {