diff options
author | James Mintram <me@jamesrm.com> | 2021-11-21 00:34:12 +0000 |
---|---|---|
committer | Brian Gianforcaro <b.gianfo@gmail.com> | 2021-11-28 22:01:21 -0800 |
commit | 68b5d00f422bb05ca7d4ffdc692dd0c38411332e (patch) | |
tree | a8c83b0c304f7676d5f4091b65e0f39aa36279b5 /Kernel | |
parent | 18f1530c8463fa4de58a02a8b36f1ee696cc1c76 (diff) | |
download | serenity-68b5d00f422bb05ca7d4ffdc692dd0c38411332e.zip |
Kernel: Split prekernel exception level code into its own file
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.S | 33 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.h | 9 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/Prekernel.h | 23 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/PrekernelCommon.cpp | 25 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/PrekernelExceptions.cpp | 100 | ||||
-rw-r--r-- | Kernel/Prekernel/Arch/aarch64/init.cpp | 157 | ||||
-rw-r--r-- | Kernel/Prekernel/CMakeLists.txt | 10 |
7 files changed, 188 insertions, 169 deletions
diff --git a/Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.S b/Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.S index 4e3f9c511d..e9eba54b8f 100644 --- a/Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.S +++ b/Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.S @@ -23,25 +23,20 @@ Lstart: bne Lstart ret -.global return_from_el2 -.type return_from_el2, @function -return_from_el2: - adr x0, jump_to_os_start - msr elr_el2, x0 - eret - -.global return_from_el3 -.type return_from_el3, @function -return_from_el3: - adr x0, jump_to_os_start +.global enter_el2_from_el3 +.type enter_el2_from_el3, @function +enter_el2_from_el3: + adr x0, entered_el2 msr elr_el3, x0 eret +entered_el2: + ret -jump_to_os_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. - ldr x14, =start - mov sp, x14 - - b os_start +.global enter_el1_from_el2 +.type enter_el1_from_el2, @function +enter_el1_from_el2: + adr x0, entered_el1 + msr elr_el2, x0 + eret +entered_el1: + ret diff --git a/Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.h b/Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.h index 16877548b0..f95d89f754 100644 --- a/Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.h +++ b/Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.h @@ -6,7 +6,14 @@ #pragma once -extern "C" uint8_t get_current_exception_level(); +enum class ExceptionLevel : u8 { + EL0 = 0, + EL1 = 1, + EL2 = 2, + EL3 = 3, +}; + +extern "C" ExceptionLevel get_current_exception_level(); extern "C" void wait_cycles(int n); // CPU initialization functions diff --git a/Kernel/Prekernel/Arch/aarch64/Prekernel.h b/Kernel/Prekernel/Arch/aarch64/Prekernel.h new file mode 100644 index 0000000000..94e31de607 --- /dev/null +++ b/Kernel/Prekernel/Arch/aarch64/Prekernel.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021, James Mintram <me@jamesrm.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +namespace Prekernel { + +void drop_to_exception_level_1(); +void init_prekernel_page_tables(); + +[[noreturn]] void panic(const char* msg); + +[[noreturn]] inline void halt() +{ + for (;;) { + asm volatile("wfi"); + } +} + +} diff --git a/Kernel/Prekernel/Arch/aarch64/PrekernelCommon.cpp b/Kernel/Prekernel/Arch/aarch64/PrekernelCommon.cpp new file mode 100644 index 0000000000..87a8d37dae --- /dev/null +++ b/Kernel/Prekernel/Arch/aarch64/PrekernelCommon.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021, James Mintram <me@jamesrm.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Kernel/Prekernel/Arch/aarch64/Prekernel.h> + +#include <Kernel/Arch/aarch64/Aarch64Asm.h> +#include <Kernel/Prekernel/Arch/aarch64/UART.h> + +namespace Prekernel { + +[[noreturn]] void panic(const char* msg) +{ + auto& uart = Prekernel::UART::the(); + + if (msg) { + uart.print_str(msg); + } + + Kernel::halt(); +} + +} diff --git a/Kernel/Prekernel/Arch/aarch64/PrekernelExceptions.cpp b/Kernel/Prekernel/Arch/aarch64/PrekernelExceptions.cpp new file mode 100644 index 0000000000..052675399a --- /dev/null +++ b/Kernel/Prekernel/Arch/aarch64/PrekernelExceptions.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021, James Mintram <me@jamesrm.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Kernel/Arch/aarch64/Aarch64Registers.h> +#include <Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.h> +#include <Kernel/Prekernel/Arch/aarch64/Prekernel.h> + +extern "C" void enter_el2_from_el3(); +extern "C" void enter_el1_from_el2(); + +using namespace Kernel; + +namespace Prekernel { + +static void drop_to_el2() +{ + Aarch64_SCR_EL3 secure_configuration_register_el3 = {}; + + secure_configuration_register_el3.ST = 1; // Don't trap access to Counter-timer Physical Secure registers + secure_configuration_register_el3.RW = 1; // Lower level to use Aarch64 + secure_configuration_register_el3.NS = 1; // Non-secure state + secure_configuration_register_el3.HCE = 1; // Enable Hypervisor instructions at all levels + + Aarch64_SCR_EL3::write(secure_configuration_register_el3); + + Aarch64_SPSR_EL3 saved_program_status_register_el3 = {}; + + // Mask (disable) all interrupts + saved_program_status_register_el3.A = 1; + saved_program_status_register_el3.I = 1; + saved_program_status_register_el3.F = 1; + 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; + + // Set the register + Aarch64_SPSR_EL3::write(saved_program_status_register_el3); + + // This will jump into os_start() below + enter_el2_from_el3(); +} +static void drop_to_el1() +{ + Aarch64_HCR_EL2 hypervisor_configuration_register_el2 = {}; + hypervisor_configuration_register_el2.RW = 1; // EL1 to use 64-bit mode + Aarch64_HCR_EL2::write(hypervisor_configuration_register_el2); + + Aarch64_SPSR_EL2 saved_program_status_register_el2 = {}; + + // Mask (disable) all interrupts + saved_program_status_register_el2.A = 1; + saved_program_status_register_el2.I = 1; + 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; + + Aarch64_SPSR_EL2::write(saved_program_status_register_el2); + enter_el1_from_el2(); +} + +static void set_up_el1() +{ + Aarch64_SCTLR_EL1 system_control_register_el1 = Aarch64_SCTLR_EL1::reset_value(); + + system_control_register_el1.UCT = 1; // Don't trap access to CTR_EL0 + system_control_register_el1.nTWE = 1; // Don't trap WFE instructions + system_control_register_el1.nTWI = 1; // Don't trap WFI instructions + system_control_register_el1.DZE = 1; // Don't trap DC ZVA instructions + system_control_register_el1.UMA = 1; // Don't trap access to DAIF (debugging) flags of EFLAGS register + system_control_register_el1.SA0 = 1; // Enable stack access alignment check for EL0 + system_control_register_el1.SA = 1; // Enable stack access alignment check for EL1 + system_control_register_el1.A = 1; // Enable memory access alignment check + + Aarch64_SCTLR_EL1::write(system_control_register_el1); +} + +void drop_to_exception_level_1() +{ + switch (get_current_exception_level()) { + case ExceptionLevel::EL3: + drop_to_el2(); + [[fallthrough]]; + case ExceptionLevel::EL2: + drop_to_el1(); + [[fallthrough]]; + case ExceptionLevel::EL1: + set_up_el1(); + break; + default: { + Prekernel::panic("FATAL: CPU booted in unsupported exception mode!\r\n"); + } + } +} + +} diff --git a/Kernel/Prekernel/Arch/aarch64/init.cpp b/Kernel/Prekernel/Arch/aarch64/init.cpp index a81e5c0728..ced40d4f64 100644 --- a/Kernel/Prekernel/Arch/aarch64/init.cpp +++ b/Kernel/Prekernel/Arch/aarch64/init.cpp @@ -6,27 +6,21 @@ */ #include <AK/Types.h> -#include <Kernel/Arch/aarch64/Aarch64Registers.h> + #include <Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.h> #include <Kernel/Prekernel/Arch/aarch64/BootPPMParser.h> #include <Kernel/Prekernel/Arch/aarch64/Framebuffer.h> #include <Kernel/Prekernel/Arch/aarch64/Mailbox.h> +#include <Kernel/Prekernel/Arch/aarch64/Prekernel.h> #include <Kernel/Prekernel/Arch/aarch64/Timer.h> #include <Kernel/Prekernel/Arch/aarch64/UART.h> #include <Kernel/Prekernel/Arch/aarch64/Utils.h> -extern "C" [[noreturn]] void halt(); -extern "C" [[noreturn]] void init(); -extern "C" [[noreturn]] void os_start(); - -static void set_up_el1_mode(); -static void set_up_el2_mode(); -static void set_up_el3_mode(); -static void print_current_exception_level(const char* msg); static void draw_logo(); static u32 query_firmware_version(); -[[noreturn]] static void jump_to_os_start_from_el2(); -[[noreturn]] static void jump_to_os_start_from_el3(); + +extern "C" [[noreturn]] void halt(); +extern "C" [[noreturn]] void init(); extern "C" [[noreturn]] void init() { @@ -41,31 +35,12 @@ extern "C" [[noreturn]] void init() uart.print_num(firmware_version); uart.print_str("\r\n"); - print_current_exception_level("CPU started in:"); - - set_up_el2_mode(); - set_up_el1_mode(); - - auto current_exception_level = get_current_exception_level(); - switch (current_exception_level) { - case 2: - jump_to_os_start_from_el2(); - break; - case 3: - set_up_el3_mode(); - jump_to_os_start_from_el3(); - break; - default: - uart.print_str("FATAL: CPU booted in unsupported exception mode!\r\n"); - halt(); - } -} - -extern "C" [[noreturn]] void os_start() -{ - auto& uart = Prekernel::UART::the(); + uart.print_str("CPU started in: EL"); + uart.print_num(static_cast<u64>(get_current_exception_level())); + uart.print_str("\r\n"); - print_current_exception_level("CPU switched to:"); + uart.print_str("Drop CPU to EL1\r\n"); + Prekernel::drop_to_exception_level_1(); auto& framebuffer = Prekernel::Framebuffer::the(); if (framebuffer.initialized()) { @@ -107,118 +82,6 @@ void __stack_chk_fail() halt(); } -static void set_up_el1_mode() -{ - Kernel::Aarch64_SCTLR_EL1 system_control_register_el1 = {}; - - // Those bits are reserved on ARMv8.0 - system_control_register_el1.LSMAOE = 1; - system_control_register_el1.nTLSMD = 1; - system_control_register_el1.SPAN = 1; - system_control_register_el1.IESB = 1; - - // Don't trap access to CTR_EL0 - system_control_register_el1.UCT = 1; - - // Don't trap WFE instructions - system_control_register_el1.nTWE = 1; - - // Don't trap WFI instructions - system_control_register_el1.nTWI = 1; - - // Don't trap DC ZVA instructions - system_control_register_el1.DZE = 1; - - // Don't trap access to DAIF (debugging) flags of EFLAGS register - system_control_register_el1.UMA = 1; - - // Enable stack access alignment check for EL0 - system_control_register_el1.SA0 = 1; - - // Enable stack access alignment check for EL1 - system_control_register_el1.SA = 1; - - // Enable memory access alignment check - system_control_register_el1.A = 1; - - Kernel::Aarch64_SCTLR_EL1::write(system_control_register_el1); -} - -static void set_up_el2_mode() -{ - Kernel::Aarch64_HCR_EL2 hypervisor_configuration_register_el2 = {}; - - // EL1 to use 64-bit mode - hypervisor_configuration_register_el2.RW = 1; - - Kernel::Aarch64_HCR_EL2::write(hypervisor_configuration_register_el2); -} - -static void set_up_el3_mode() -{ - Kernel::Aarch64_SCR_EL3 secure_configuration_register_el3 = {}; - - // Don't trap access to Counter-timer Physical Secure registers - secure_configuration_register_el3.ST = 1; - - // Lower level to use Aarch64 - secure_configuration_register_el3.RW = 1; - - // Enable Hypervisor instructions at all levels - secure_configuration_register_el3.HCE = 1; - - Kernel::Aarch64_SCR_EL3::write(secure_configuration_register_el3); -} - -[[noreturn]] static void jump_to_os_start_from_el2() -{ - // Processor state to set when returned from this function (in new EL1 world) - Kernel::Aarch64_SPSR_EL2 saved_program_status_register_el2 = {}; - - // Mask (disable) all interrupts - saved_program_status_register_el2.A = 1; - saved_program_status_register_el2.I = 1; - saved_program_status_register_el2.F = 1; - - // Indicate EL1 as exception origin mode (so we go back there) - saved_program_status_register_el2.M = Kernel::Aarch64_SPSR_EL2::Mode::EL1h; - - Kernel::Aarch64_SPSR_EL2::write(saved_program_status_register_el2); - - // This will jump into os_start() - return_from_el2(); -} - -[[noreturn]] static void jump_to_os_start_from_el3() -{ - // Processor state to set when returned from this function (in new EL1 world) - Kernel::Aarch64_SPSR_EL3 saved_program_status_register_el3 = {}; - - // Mask (disable) all interrupts - saved_program_status_register_el3.A = 1; - saved_program_status_register_el3.I = 1; - saved_program_status_register_el3.F = 1; - - // Indicate EL1 as exception origin mode (so we go back there) - saved_program_status_register_el3.M = Kernel::Aarch64_SPSR_EL3::Mode::EL1h; - - Kernel::Aarch64_SPSR_EL3::write(saved_program_status_register_el3); - - // This will jump into os_start() below - return_from_el3(); -} - -static void print_current_exception_level(const char* msg) -{ - auto& uart = Prekernel::UART::the(); - - auto exception_level = get_current_exception_level(); - uart.print_str(msg); - uart.print_str(" EL"); - uart.print_num(exception_level); - uart.print_str("\r\n"); -} - class QueryFirmwareVersionMboxMessage : Prekernel::Mailbox::Message { public: u32 version; diff --git a/Kernel/Prekernel/CMakeLists.txt b/Kernel/Prekernel/CMakeLists.txt index 5000b7087c..859d85856c 100644 --- a/Kernel/Prekernel/CMakeLists.txt +++ b/Kernel/Prekernel/CMakeLists.txt @@ -14,9 +14,15 @@ if ("${SERENITY_ARCH}" STREQUAL "aarch64") Arch/aarch64/Timer.cpp Arch/aarch64/UART.cpp Arch/aarch64/Utils.cpp - Arch/aarch64/Aarch64_asm_utils.S - Arch/aarch64/boot.S + + # Preload specific Arch/aarch64/init.cpp + Arch/aarch64/PrekernelExceptions.cpp + Arch/aarch64/PrekernelCommon.cpp + + # Assembly + Arch/aarch64/boot.S + Arch/aarch64/Aarch64_asm_utils.S ) else() set(SOURCES |