From 247109cee67ee2103175b671e051d02b9afdd704 Mon Sep 17 00:00:00 2001 From: Timon Kruiper Date: Sun, 8 Jan 2023 14:01:31 +0100 Subject: [PATCH] Kernel/aarch64: Execute kernel with SP_EL1 instead of SP_EL0 Until now the kernel was always executing with SP_EL0, as this made the initial dropping to EL1 a bit easier. This commit changes this behaviour to use the corresponding SP_ELx for each exception level. To make sure that the execution of the C++ code can continue, the current stack pointer is copied into the corresponding SP_ELx just before dropping an exception level. --- Kernel/Arch/aarch64/ASM_wrapper.h | 12 ++++++++++-- Kernel/Arch/aarch64/Exceptions.cpp | 8 ++------ Kernel/Arch/aarch64/Processor.cpp | 4 ++-- Kernel/Arch/aarch64/boot.S | 1 - Kernel/Arch/aarch64/vector_table.S | 18 +++++++++--------- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Kernel/Arch/aarch64/ASM_wrapper.h b/Kernel/Arch/aarch64/ASM_wrapper.h index 963d2572290..0b11c88e4cf 100644 --- a/Kernel/Arch/aarch64/ASM_wrapper.h +++ b/Kernel/Arch/aarch64/ASM_wrapper.h @@ -75,7 +75,11 @@ inline void load_el1_vector_table(void* vector_table) inline void enter_el2_from_el3() { - asm volatile(" adr x0, entered_el2\n" + // NOTE: This also copies the current stack pointer into SP_EL2, as + // the processor is set up to use SP_EL2 when jumping into EL2. + asm volatile(" mov x0, sp\n" + " msr sp_el2, x0\n" + " adr x0, entered_el2\n" " msr elr_el3, x0\n" " eret\n" "entered_el2:" :: @@ -84,7 +88,11 @@ inline void enter_el2_from_el3() inline void enter_el1_from_el2() { - asm volatile(" adr x0, entered_el1\n" + // NOTE: This also copies the current stack pointer into SP_EL1, as + // the processor is set up to use SP_EL1 when jumping into EL1. + asm volatile(" mov x0, sp\n" + " msr sp_el1, x0\n" + " adr x0, entered_el1\n" " msr elr_el2, x0\n" " eret\n" "entered_el1:" :: diff --git a/Kernel/Arch/aarch64/Exceptions.cpp b/Kernel/Arch/aarch64/Exceptions.cpp index 116f7e00367..cc03e3ff9ca 100644 --- a/Kernel/Arch/aarch64/Exceptions.cpp +++ b/Kernel/Arch/aarch64/Exceptions.cpp @@ -34,7 +34,7 @@ static void drop_el3_to_el2() saved_program_status_register_el3.D = 1; // Indicate EL1 as exception origin mode (so we go back there) - saved_program_status_register_el3.M = Aarch64::SPSR_EL3::Mode::EL2t; + saved_program_status_register_el3.M = Aarch64::SPSR_EL3::Mode::EL2h; // Set the register Aarch64::SPSR_EL3::write(saved_program_status_register_el3); @@ -49,10 +49,6 @@ static void drop_el2_to_el1() hypervisor_configuration_register_el2.RW = 1; // EL1 to use 64-bit mode Aarch64::HCR_EL2::write(hypervisor_configuration_register_el2); - // Set up initial exception stack - // FIXME: Define in linker script - Aarch64::Asm::set_sp_el1(0x40000); - Aarch64::SPSR_EL2 saved_program_status_register_el2 = {}; // Mask (disable) all interrupts @@ -61,7 +57,7 @@ static void drop_el2_to_el1() saved_program_status_register_el2.F = 1; // Indicate EL1 as exception origin mode (so we go back there) - saved_program_status_register_el2.M = Aarch64::SPSR_EL2::Mode::EL1t; + saved_program_status_register_el2.M = Aarch64::SPSR_EL2::Mode::EL1h; Aarch64::SPSR_EL2::write(saved_program_status_register_el2); Aarch64::Asm::enter_el1_from_el2(); diff --git a/Kernel/Arch/aarch64/Processor.cpp b/Kernel/Arch/aarch64/Processor.cpp index 81e29fafc58..d421cf65057 100644 --- a/Kernel/Arch/aarch64/Processor.cpp +++ b/Kernel/Arch/aarch64/Processor.cpp @@ -252,9 +252,9 @@ FlatPtr Processor::init_context(Thread& thread, bool leave_crit) saved_program_status_register_el1.I = 0; saved_program_status_register_el1.F = 0; - // Set exception origin mode to EL1t, so when the context is restored, we'll be executing in EL1 with SP_EL0 + // Set exception origin mode to EL1h, so when the context is restored, we'll be executing in EL1 with SP_EL1 // FIXME: This must be EL0t when aarch64 supports userspace applications. - saved_program_status_register_el1.M = Aarch64::SPSR_EL1::Mode::EL1t; + saved_program_status_register_el1.M = Aarch64::SPSR_EL1::Mode::EL1h; memcpy(&eretframe.spsr_el1, &saved_program_status_register_el1, sizeof(u64)); // Push a TrapFrame onto the stack diff --git a/Kernel/Arch/aarch64/boot.S b/Kernel/Arch/aarch64/boot.S index d5610ba0acb..da8c8baf2a9 100644 --- a/Kernel/Arch/aarch64/boot.S +++ b/Kernel/Arch/aarch64/boot.S @@ -18,7 +18,6 @@ start: // Let stack start before .text for now. // 512 kiB (0x80000) of stack are probably not sufficient, especially once we give the other cores some stack too, // but for now it's ok. - msr SPSel, #0 //Use the same SP as we descend into EL1 adrp x14, start add x14, x14, :lo12:start mov sp, x14 diff --git a/Kernel/Arch/aarch64/vector_table.S b/Kernel/Arch/aarch64/vector_table.S index f6222918bc9..80a44f3d5bc 100644 --- a/Kernel/Arch/aarch64/vector_table.S +++ b/Kernel/Arch/aarch64/vector_table.S @@ -6,7 +6,7 @@ .section .text.vector_table -#define TRAP_FRAME_SIZE 272 +#define REGISTER_STATE_SIZE 272 #define SPSR_EL1_SLOT (31 * 8) #define ELR_EL1_SLOT (32 * 8) #define TPIDR_EL0_SLOT (33 * 8) @@ -34,7 +34,7 @@ // .macro save_current_context // Allocate stack space for Trap Frame - sub sp, sp, #TRAP_FRAME_SIZE + sub sp, sp, #REGISTER_STATE_SIZE stp x0, x1, [sp, #(0 * 0)] stp x2, x3, [sp, #(2 * 8)] @@ -60,10 +60,12 @@ str x0, [sp, #ELR_EL1_SLOT] mrs x0, tpidr_el0 str x0, [sp, #TPIDR_EL0_SLOT] + mrs x0, sp_el0 + str x0, [sp, #SP_EL0_SLOT] // Set up TrapFrame struct on the stack - sub sp, sp, #16 mov x0, sp + sub sp, sp, #16 str x0, [sp, #(1 * 8)] str xzr, [sp, #(0 * 0)] @@ -83,6 +85,8 @@ msr elr_el1, x0 ldr x0, [sp, #TPIDR_EL0_SLOT] msr tpidr_el0, x0 + ldr x0, [sp, #SP_EL0_SLOT] + msr sp_el0, x0 ldp x0, x1, [sp, #(0 * 0)] ldp x2, x3, [sp, #(2 * 8)] @@ -101,7 +105,7 @@ ldp x28, x29, [sp, #(28 * 8)] ldr x30, [sp, #(30 * 8)] - add sp, sp, #TRAP_FRAME_SIZE + add sp, sp, #REGISTER_STATE_SIZE .endm .global vector_table_el1 @@ -143,7 +147,7 @@ synchronous_current_elsp_elx: irq_current_elsp_elx: save_current_context - bl exception_common + bl handle_interrupt restore_previous_context eret @@ -166,10 +170,6 @@ synchronous_current_elsp_el0: eret irq_current_elsp_el0: - // An IRQ will always switch the stack pointer to SP_EL1, however we want to use SP_EL0, so switch - // to SP_EL0. This means that the stack of the currently executing thread is used as the irq stack. - msr SPSel, #0 - save_current_context bl handle_interrupt restore_previous_context