diff --git a/thermosphere/linker.ld b/thermosphere/linker.ld index 60cb854c8..7f17ebf82 100644 --- a/thermosphere/linker.ld +++ b/thermosphere/linker.ld @@ -135,9 +135,11 @@ SECTIONS __end__ = ABSOLUTE(.); } >main + . = ALIGN(0x1000); __end__ = ABSOLUTE(.) ; - __stacks_top__ = ABSOLUTE(. + 0x1000); + __stacks_top__ = ABSOLUTE(. + 0x2000); + __excep_stacks_top__ = ABSOLUTE(. + 0x4000); /* Note: potentially overwrites warmboot firmware. */ . = ALIGN(8); diff --git a/thermosphere/src/exceptions.s b/thermosphere/src/exception_vectors.s similarity index 66% rename from thermosphere/src/exceptions.s rename to thermosphere/src/exception_vectors.s index f7dcda342..3402246b1 100644 --- a/thermosphere/src/exceptions.s +++ b/thermosphere/src/exception_vectors.s @@ -51,7 +51,49 @@ .endm .macro save_all_regs - sub sp, sp, #0x110 + stp x30, xzr, [sp, #-0x130] + bl _save_all_regs +.endm + +.macro pivot_stack_for_crash + // Ditch sp_el0 & elr_el1 + // We don't use E2H so that's fine. + msr elr_el1, x0 + mov x0, sp + msr sp_el0, x0 // save stack pointer for the crash + bic x0, x0, #0xFF + bic x0, x0, #0x700 + add x0, x0, #0x1000 + add x0, x0, #0x800 + mov sp, x0 + mrs x0, elr_el1 +.endm + +/* Actual Vectors for Thermosphere. */ +.global thermosphere_vectors +vector_base thermosphere_vectors + +/* Current EL, SP0 */ +/* Those are unused by us, except on same-EL double-faults. */ +.global unknown_exception +unknown_exception: +vector_entry synch_sp0 + pivot_stack_for_crash + mov x0, x30 + adr x1, thermosphere_vectors + 4 + sub x0, x0, x1 + bl handleUnknownException + b . + check_vector_size synch_sp0 + +vector_entry irq_sp0 + bl unknown_exception + .endfunc + .cfi_endproc + /* To save space, insert in an unused vector segment. */ + _save_all_regs: + + sub sp, sp, #0x120 stp x0, x1, [sp, #0x00] stp x2, x3, [sp, #0x10] stp x4, x5, [sp, #0x20] @@ -68,100 +110,35 @@ stp x26, x27, [sp, #0xD0] stp x28, x29, [sp, #0xE0] + mov x29, x30 + ldp x30, xzr, [sp, #-0x10] // See save_all_regs macro + mrs x20, sp_el1 - mrs x21, elr_el2 - mrs x22, spsr_el2 + mrs x21, sp_el0 + mrs x22, elr_el2 + mrs x23, spsr_el2 stp x30, x20, [sp, #0xF0] stp x21, x22, [sp, #0x100] -.endm + stp x23, xzr, [sp, #0x110] -/* Actual Vectors for Exosphere. */ -.global exosphere_vectors -vector_base exosphere_vectors - -/* Current EL, SP0 */ -.global unknown_exception -unknown_exception: -vector_entry synch_sp0 - b . - check_vector_size synch_sp0 - -vector_entry irq_sp0 - b unknown_exception - check_vector_size irq_sp0 + mov x30, x29 + ret vector_entry fiq_sp0 - b unknown_exception - check_vector_size fiq_sp0 - -vector_entry serror_sp0 - b unknown_exception - check_vector_size serror_sp0 - -/* Current EL, SPx */ -vector_entry synch_spx - b unknown_exception - check_vector_size synch_spx - -vector_entry irq_spx - b unknown_exception - check_vector_size irq_spx - -vector_entry fiq_spx - b unknown_exception - check_vector_size fiq_spx - -vector_entry serror_spx - b unknown_exception - check_vector_size serror_spx - -/* Lower EL, A64 */ -vector_entry synch_a64 - save_all_regs - - mov x0, sp - mrs x1, esr_el2 - - bl . // FIXME! - - b _restore_all_regs - check_vector_size synch_a64 - -vector_entry irq_a64 - b unknown_exception - check_vector_size irq_a64 - -vector_entry fiq_a64 - b unknown_exception - check_vector_size fiq_a64 - -vector_entry serror_a64 - b unknown_exception - check_vector_size serror_a64 - - -/* Lower EL, A32 */ -vector_entry synch_a32 - b unknown_exception - check_vector_size synch_a32 - -vector_entry irq_a32 - b unknown_exception - check_vector_size irq_a32 - -vector_entry fiq_a32 - b fiq_a64 + bl unknown_exception .endfunc .cfi_endproc -/* To save space, insert in an unused vector segment. */ -_restore_all_regs: + /* To save space, insert in an unused vector segment. */ + _restore_all_regs: ldp x30, x20, [sp, #0xF0] ldp x21, x22, [sp, #0x100] + ldp x23, xzr, [sp, #0x110] msr sp_el1, x20 - msr elr_el2, x21 - msr spsr_el2, x22 + msr sp_el0, x21 + msr elr_el2, x22 + msr spsr_el2, x23 ldp x0, x1, [sp, #0x00] ldp x2, x3, [sp, #0x10] @@ -179,9 +156,77 @@ _restore_all_regs: ldp x26, x27, [sp, #0xD0] ldp x28, x29, [sp, #0xE0] - add sp, sp, #0x110 + add sp, sp, #0x210 eret +vector_entry serror_sp0 + bl unknown_exception + check_vector_size serror_sp0 + +/* Current EL, SPx */ +vector_entry synch_spx + /* Only crashes go through there! */ + pivot_stack_for_crash + + save_all_regs + + mov x0, sp + mrs x1, esr_el2 + + bl handleSameElSyncException + b . + check_vector_size synch_spx + +vector_entry irq_spx + bl unknown_exception + check_vector_size irq_spx + +vector_entry fiq_spx + bl unknown_exception + check_vector_size fiq_spx + +vector_entry serror_spx + bl unknown_exception + check_vector_size serror_spx + +/* Lower EL, A64 */ +vector_entry synch_a64 + save_all_regs + + mov x0, sp + mrs x1, esr_el2 + + bl handleLowerElSyncException + + b _restore_all_regs + check_vector_size synch_a64 + +vector_entry irq_a64 + bl unknown_exception + check_vector_size irq_a64 + +vector_entry fiq_a64 + bl unknown_exception + check_vector_size fiq_a64 + +vector_entry serror_a64 + bl unknown_exception + check_vector_size serror_a64 + + +/* Lower EL, A32 */ +vector_entry synch_a32 + bl unknown_exception + check_vector_size synch_a32 + +vector_entry irq_a32 + bl unknown_exception + check_vector_size irq_a32 + +vector_entry fiq_a32 + b fiq_a64 + check_vector_size fiq_a32 + vector_entry serror_a32 - b unknown_exception + bl unknown_exception check_vector_size serror_a32 diff --git a/thermosphere/src/exceptions.c b/thermosphere/src/exceptions.c new file mode 100644 index 000000000..c40d2a784 --- /dev/null +++ b/thermosphere/src/exceptions.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 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 . + */ + +#include "exceptions.h" +#include "log.h" + +static void dumpStackFrame(const ExceptionStackFrame *frame, bool sameEl) +{ +#ifndef NDEBUG + for (u32 i = 0; i < 30; i += 2) { + serialLog("x%d\t\t%08lx\t\tx%d\t\t%08lx\r\n", i, frame->x[i], i + 1, frame->x[i + 1]); + } + + serialLog("x30\t\t%08lx\r\n\r\n", frame->x[30]); + serialLog("elr_el2\t\t%08lx\r\n", frame->elr_el2); + serialLog("spsr_el2\t%08lx\r\n", frame->spsr_el2); + if (sameEl) { + serialLog("sp_el2\t\t%08lx\r\n", frame->sp_el2); + } else { + serialLog("sp_el0\t\t%08lx\r\n", frame->sp_el0); + } + serialLog("sp_el1\t\t%08lx\r\n", frame->sp_el1); +#endif +} + +void handleLowerElSyncException(ExceptionStackFrame *frame, u32 esr) +{ + serialLog("Lower EL sync exception, ESR = 0x%08lx\r\n", esr); + dumpStackFrame(frame, false); +} + +void handleSameElSyncException(ExceptionStackFrame *frame, u32 esr) +{ + serialLog("Same EL sync exception, ESR = 0x%08lx\r\n", esr); + dumpStackFrame(frame, true); +} + +void handleUnknownException(u32 offset) +{ + serialLog("Unknown exception! (offset 0x%03lx)\r\n", offset); +} \ No newline at end of file diff --git a/thermosphere/src/exceptions.h b/thermosphere/src/exceptions.h new file mode 100644 index 000000000..b6968b5db --- /dev/null +++ b/thermosphere/src/exceptions.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 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 . + */ + +#pragma once +#include "utils.h" + +typedef struct ExceptionStackFrame { + u64 x[31]; // x0 .. x30 + u64 sp_el1; + union { + u64 sp_el2; + u64 sp_el0; + }; + u64 elr_el2; + u64 spsr_el2; +} ExceptionStackFrame; \ No newline at end of file diff --git a/thermosphere/src/main.c b/thermosphere/src/main.c index 3e51e7a58..dac20ed81 100644 --- a/thermosphere/src/main.c +++ b/thermosphere/src/main.c @@ -8,5 +8,6 @@ int main(void) //uart_send(UART_C, "0123\n", 3); serialLog("Hello from Thermosphere!\r\n"); + __builtin_trap(); return 0; } diff --git a/thermosphere/src/start.s b/thermosphere/src/start.s index 16d492173..1b0e11da5 100644 --- a/thermosphere/src/start.s +++ b/thermosphere/src/start.s @@ -32,8 +32,9 @@ g_kernelEntrypoint: .quad 0 start: - // Disable interrupts + // Disable interrupts, select sp_el2 msr daifset, 0b1111 + msr spsel, #1 // Save arg, load entrypoint & spsr mov x19, x0 diff --git a/thermosphere/tegra.mem b/thermosphere/tegra.mem index 8d767effb..6f3ce7c75 100644 --- a/thermosphere/tegra.mem +++ b/thermosphere/tegra.mem @@ -1,5 +1,5 @@ MEMORY { NULL : ORIGIN = 0, LENGTH = 0x1000 - main : ORIGIN = 0x80000000, LENGTH = 0xD000 - 0x1000 /* 0x1000 for stacks. */ + main : ORIGIN = 0x80000000, LENGTH = 0xD000 - 0x2000 /* 0x2000 for stacks. */ } \ No newline at end of file