diff --git a/fusee/fusee-primary/fusee-primary-main/linker.ld b/fusee/fusee-primary/fusee-primary-main/linker.ld index 0e46aa6b4..cc397c02d 100644 --- a/fusee/fusee-primary/fusee-primary-main/linker.ld +++ b/fusee/fusee-primary/fusee-primary-main/linker.ld @@ -32,6 +32,11 @@ SECTIONS KEEP( *(.text.start) ) KEEP( *(.init) ) . = ALIGN(32); + PROVIDE (__reboot_start__ = ABSOLUTE(.)); + KEEP( *(.reboot*) ) + . = ALIGN(4); + PROVIDE (__reboot_end__ = ABSOLUTE(.)); + . = ALIGN(32); } >main :crt0 .chainloader_loadable : @@ -59,6 +64,7 @@ SECTIONS { . = ALIGN(32); /* .text */ + *(.text.reboot_to_self) *(.text) *(.text.*) *(.glue_7) diff --git a/fusee/fusee-primary/fusee-primary-main/src/reboot_start.s b/fusee/fusee-primary/fusee-primary-main/src/reboot_start.s new file mode 100644 index 000000000..e2bbe8bb1 --- /dev/null +++ b/fusee/fusee-primary/fusee-primary-main/src/reboot_start.s @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +.macro CLEAR_GPR_REG_ITER + mov r\@, #0 +.endm + +.section .reboot.start, "ax", %progbits +.arm +.align 5 +.global reboot_start +.type reboot_start, %function +reboot_start: + /* Switch to system mode, mask all interrupts, clear all flags */ + msr cpsr_cxsf, #0xDF + + /* Relocate reboot start to 0x4003E000. */ + ldr r0, =0x4003E000 + adr r1, reboot_start + cmp r0, r1 + beq 1f + + mov r2, #0x1000 +0: + ldmia r1!, {r5-r12} + stmia r0!, {r5-r12} + subs r2, #0x20 + bne 0b + + ldr r0, =0x4003E000 + adr r1, reboot_start + adr r2, 1f + sub r2, r2, r1 + add r2, r2, r0 + bx r2 + +1: + + /* Restore our low iram code. */ + ldr r0, =0x40008000 + ldr r1, =0x40030000 + mov r2, #0x8000 +0: + ldmia r1!, {r5-r12} + stmia r0!, {r5-r12} + subs r2, #0x20 + bne 0b + + /* Restore our upper stub code. */ + ldr r0, =0x40010000 + ldr r1, =0x4003D000 + mov r2, #0x1000 +0: + ldmia r1!, {r5-r12} + stmia r0!, {r5-r12} + subs r2, #0x20 + bne 0b + + /* Jump to start. */ + ldr r0, =0x40008000 + bx r0 + +0: b 0b \ No newline at end of file diff --git a/fusee/fusee-primary/fusee-primary-main/src/utils.c b/fusee/fusee-primary/fusee-primary-main/src/utils.c index 8b407446b..96eb0591b 100644 --- a/fusee/fusee-primary/fusee-primary-main/src/utils.c +++ b/fusee/fusee-primary/fusee-primary-main/src/utils.c @@ -37,6 +37,8 @@ #undef u8 #undef u32 +extern uint8_t __reboot_start__[], __reboot_end__[]; + void wait(uint32_t microseconds) { uint32_t old_time = TIMERUS_CNTR_1US_0; while (TIMERUS_CNTR_1US_0 - old_time <= microseconds) { @@ -80,8 +82,31 @@ __attribute__((noreturn)) void reboot_to_self(void) { write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i)); } + /* Copy our low part into safe IRAM. */ + for (size_t i = 0; i < 0x8000; i += sizeof(uint32_t)) { + write32le((void *)0x40030000, i, read32le((void *)0x40008000, i)); + } + + /* Copy our start page into fatal IRAM. */ + for (size_t i = 0; i < 0x1000; i += sizeof(uint32_t)) { + write32le((void *)0x4003D000, i, read32le((void *)0x40010000, i)); + } + + /* Copy our reboot handler to the rebootstub target. */ + for (size_t i = 0; i < (__reboot_end__ - __reboot_start__); i += sizeof(uint32_t)) { + write32le((void *)0x40010000, i, read32le(__reboot_start__, i)); + } + /* Trigger warm reboot. */ - pmc_reboot(1 << 0); + APBDEV_PMC_SCRATCH0_0 = (1 << 0); + + /* Reset the processor. */ + APBDEV_PMC_CONTROL = BIT(4); + + while (true) { + /* Wait for reboot. */ + } + } __attribute__((noreturn)) void wait_for_button_and_reboot(void) {