Newer
Older
minerva / Kernel / Arch / aarch64 / pre_init.cpp
@minerva minerva on 13 Jul 2 KB Initial commit
/*
 * Copyright (c) 2023, Timon Kruiper <timonkruiper@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <AK/StringView.h>
#include <AK/Types.h>
#include <Kernel/Arch/aarch64/CPU.h>
#include <Kernel/Sections.h>

// We arrive here from boot.S with the MMU disabled and in an unknown exception level (EL).
// The kernel is linked at the virtual address, so we have to be really carefull when accessing
// global variables, as the MMU is not yet enabled.

// FIXME: This should probably be shared with the Prekernel.

namespace Kernel {

extern "C" [[noreturn]] void init();

extern "C" [[noreturn]] void pre_init(PhysicalPtr flattened_devicetree_paddr);
extern "C" [[noreturn]] void pre_init(PhysicalPtr flattened_devicetree_paddr)
{
    // We want to drop to EL1 as soon as possible, because that is the
    // exception level the kernel should run at.
    initialize_exceptions();

    // Next step is to set up page tables and enable the MMU.
    Memory::init_page_tables(flattened_devicetree_paddr);

    // At this point the MMU is enabled, physical memory is identity mapped,
    // and the kernel is also mapped into higher virtual memory. However we are still executing
    // from the physical memory address, so we have to jump to the kernel in high memory. We also need to
    // switch the stack pointer to high memory, such that we can unmap the identity mapping.

    // Continue execution at high virtual address.
    asm volatile(
        "adrp x0, 1f \n"
        "add x0, x0, :lo12:1f \n"
        "add x0, x0, %[base] \n"
        "br x0 \n"
        "1: \n" ::[base] "r"(g_boot_info.physical_to_virtual_offset)
        : "x0");

    // Add kernel_mapping_base to the stack pointer, such that it is also using the mapping
    // in high virtual memory.
    asm volatile(
        "mov x0, %[base] \n"
        "add sp, sp, x0 \n" ::[base] "r"(g_boot_info.physical_to_virtual_offset)
        : "x0");

    // We can now unmap the identity map as everything is running in high virtual memory at this point.
    Memory::unmap_identity_map();

    // Clear the frame pointer (x29) and link register (x30) to make sure the kernel cannot backtrace
    // into this code, and jump to actual init function in the kernel.
    register FlatPtr const x0 asm("x0") = bit_cast<FlatPtr>(&g_boot_info);
    asm volatile(
        "mov x29, xzr \n"
        "mov x30, xzr \n"
        "b init \n" ::"r"(x0));

    VERIFY_NOT_REACHED();
}

}