thermosphere: start exception handling

This commit is contained in:
TuxSH 2019-07-22 01:04:53 +02:00
parent ada6b180cc
commit 4e0eef2784
7 changed files with 219 additions and 87 deletions

View file

@ -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);

View file

@ -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

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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;

View file

@ -8,5 +8,6 @@ int main(void)
//uart_send(UART_C, "0123\n", 3);
serialLog("Hello from Thermosphere!\r\n");
__builtin_trap();
return 0;
}

View file

@ -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

View file

@ -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. */
}