summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorJames Mintram <me@jamesrm.com>2021-11-21 00:34:12 +0000
committerBrian Gianforcaro <b.gianfo@gmail.com>2021-11-28 22:01:21 -0800
commit68b5d00f422bb05ca7d4ffdc692dd0c38411332e (patch)
treea8c83b0c304f7676d5f4091b65e0f39aa36279b5 /Kernel
parent18f1530c8463fa4de58a02a8b36f1ee696cc1c76 (diff)
downloadserenity-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.S33
-rw-r--r--Kernel/Prekernel/Arch/aarch64/Aarch64_asm_utils.h9
-rw-r--r--Kernel/Prekernel/Arch/aarch64/Prekernel.h23
-rw-r--r--Kernel/Prekernel/Arch/aarch64/PrekernelCommon.cpp25
-rw-r--r--Kernel/Prekernel/Arch/aarch64/PrekernelExceptions.cpp100
-rw-r--r--Kernel/Prekernel/Arch/aarch64/init.cpp157
-rw-r--r--Kernel/Prekernel/CMakeLists.txt10
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