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