1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 04:57:44 +00:00

Kernel: Split prekernel exception level code into its own file

This commit is contained in:
James Mintram 2021-11-21 00:34:12 +00:00 committed by Brian Gianforcaro
parent 18f1530c84
commit 68b5d00f42
7 changed files with 188 additions and 169 deletions

View file

@ -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:");
uart.print_str("CPU started in: EL");
uart.print_num(static_cast<u64>(get_current_exception_level()));
uart.print_str("\r\n");
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();
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;