EFIPrekernel: Add basic skeleton

This commit is contained in:
Sönke Holz
2024-07-21 21:24:53 +02:00
committed by Tim Schumacher
parent 9e306b858a
commit faeb9ff521
10 changed files with 281 additions and 1 deletions

View File

@@ -908,7 +908,9 @@ endif()
serenity_install_headers(Kernel)
serenity_install_sources(Kernel)
# Only x86 needs a Prekernel
# Only x86 uses the Multiboot Prekernel
if ("${SERENITY_ARCH}" STREQUAL "x86_64")
add_subdirectory(Prekernel)
endif()
add_subdirectory(EFIPrekernel)

View File

@@ -0,0 +1,69 @@
set(PREKERNEL_KERNEL_IMAGE_PATH ${CMAKE_CURRENT_BINARY_DIR}/../Kernel_shared_object)
configure_file(KernelImage.S.in KernelImage.S @ONLY)
set(SOURCES
init.cpp
DebugOutput.cpp
Panic.cpp
Runtime.cpp
kmalloc.cpp
KernelImage.S
../Firmware/EFI/EFI.cpp
../Library/MiniStdLib.cpp
../Prekernel/UBSanitizer.cpp
../../AK/Format.cpp
../../AK/StringBuilder.cpp
../../AK/StringUtils.cpp
../../AK/StringView.cpp
)
set_source_files_properties(KernelImage.S PROPERTIES OBJECT_DEPENDS ${PREKERNEL_KERNEL_IMAGE_PATH})
add_compile_definitions(PREKERNEL)
add_executable(EFIPrekernel ${SOURCES})
add_dependencies(EFIPrekernel Kernel)
add_dependencies(EFIPrekernel install_libc_headers)
target_compile_options(EFIPrekernel PRIVATE -fno-threadsafe-statics)
target_link_options(EFIPrekernel PRIVATE LINKER:-T ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld LINKER:--no-dynamic-linker -nostdlib)
set_target_properties(EFIPrekernel PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(EFIPrekernel PRIVATE gcc)
# Prevent naively implemented string functions (like strlen) from being "optimized" into a call to themselves.
set_source_files_properties(../Library/MiniStdLib.cpp
PROPERTIES COMPILE_FLAGS "-fno-tree-loop-distribution -fno-tree-loop-distribute-patterns")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
target_link_libraries(EFIPrekernel PRIVATE clang_rt.builtins)
endif()
# The PrekernelPEImageGenerator doesn't support RELR relocations.
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
target_link_options(EFIPrekernel PRIVATE LINKER:-z,nopack-relative-relocs LINKER:--pack-dyn-relocs=none)
elseif("${SERENITY_ARCH}" STREQUAL "x86_64")
target_link_options(EFIPrekernel PRIVATE LINKER:-z,nopack-relative-relocs)
endif()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Kernel.efi
COMMAND $<TARGET_FILE:Lagom::PrekernelPEImageGenerator> ${CMAKE_CURRENT_BINARY_DIR}/EFIPrekernel ${CMAKE_CURRENT_BINARY_DIR}/Kernel.efi
VERBATIM
DEPENDS EFIPrekernel Lagom::PrekernelPEImageGenerator
)
add_custom_target(generate_kernel_efi_image ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Kernel.efi)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Kernel.efi DESTINATION boot)
# Remove options which the Prekernel environment doesn't support.
get_target_property(EFI_PREKERNEL_COMPILE_OPTIONS EFIPrekernel COMPILE_OPTIONS)
list(REMOVE_ITEM EFI_PREKERNEL_COMPILE_OPTIONS "-fsanitize-coverage=trace-pc")
list(REMOVE_ITEM EFI_PREKERNEL_COMPILE_OPTIONS "-fsanitize=kernel-address")
set_target_properties(EFIPrekernel PROPERTIES COMPILE_OPTIONS "${EFI_PREKERNEL_COMPILE_OPTIONS}")

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Error.h>
#include <Kernel/Firmware/EFI/EFI.h>
namespace Kernel {
template<typename T>
using EFIErrorOr = ErrorOr<T, EFI::Status>;
}

View File

@@ -0,0 +1,11 @@
// The kernel image has to be in a writable section, so we can apply relocations while EFI boot services are still available
// (we are not allowed to change page tables until we call ExitBootServices()).
.section .data
.global start_of_kernel_image
.global end_of_kernel_image
.p2align 12
start_of_kernel_image:
.incbin "@PREKERNEL_KERNEL_IMAGE_PATH@"
end_of_kernel_image:

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <Kernel/EFIPrekernel/DebugOutput.h>
#include <Kernel/EFIPrekernel/Panic.h>
#include <Kernel/EFIPrekernel/Runtime.h>
namespace Kernel {
[[noreturn]] void __panic(char const* file, unsigned int line, char const* function)
{
dbgln("at {}:{} in {}", file, line, function);
halt();
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Format.h>
#include <Kernel/EFIPrekernel/DebugOutput.h>
namespace Kernel {
[[noreturn]] void __panic(char const* file, unsigned int line, char const* function);
#define PANIC(...) \
do { \
::Kernel::ucs2_dbgln(u"PREKERNEL PANIC! :^("); \
dbgln(__VA_ARGS__); \
::Kernel::__panic(__FILE__, __LINE__, __PRETTY_FUNCTION__); \
} while (0)
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Platform.h>
#include <Kernel/EFIPrekernel/Runtime.h>
namespace Kernel {
[[noreturn]] void halt()
{
for (;;) {
#if ARCH(AARCH64)
asm volatile("msr daifset, #2; wfi");
#elif ARCH(RISCV64)
asm volatile("csrw sie, zero; wfi");
#elif ARCH(X86_64)
asm volatile("cli; hlt");
#else
# error Unknown architecture
#endif
}
}
}

View File

@@ -0,0 +1,13 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
namespace Kernel {
[[noreturn]] void halt();
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
#include <Kernel/Sections.h>
namespace Kernel {
// Kernel virtual memory layout:
// Kernel stack | BootInfo | Quickmap page table | EFI memory map | Kernel
// ^ KERNEL_MAPPING_BASE
// NOTE: If the memory map overflows into the kernel memory range, we catch that in the map_pages function (a page is not allowed to be remapped)
static constexpr size_t KERNEL_STACK_SIZE = 64 * KiB;
static_assert(KERNEL_STACK_SIZE % PAGE_SIZE == 0);
static constexpr FlatPtr KERNEL_STACK_VADDR = KERNEL_MAPPING_BASE;
static constexpr FlatPtr BOOT_INFO_VADDR = KERNEL_MAPPING_BASE + KERNEL_STACK_SIZE;
static constexpr FlatPtr QUICKMAP_PAGE_TABLE_VADDR = round_up_to_power_of_two(BOOT_INFO_VADDR + sizeof(BootInfo), PAGE_SIZE);
// This assumes PAGE_SIZE == PAGE_TABLE_SIZE
static constexpr FlatPtr EFI_MEMORY_MAP_VADDR = QUICKMAP_PAGE_TABLE_VADDR + PAGE_SIZE;
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Firmware/EFI/EFI.h>
#include <Kernel/Firmware/EFI/SystemTable.h>
#include <Kernel/EFIPrekernel/DebugOutput.h>
#include <Kernel/EFIPrekernel/Panic.h>
#include <Kernel/EFIPrekernel/Runtime.h>
// FIXME: Initialize the __stack_chk_guard with a random value via the EFI_RNG_PROTOCOL or other arch-specific methods.
uintptr_t __stack_chk_guard __attribute__((used));
namespace Kernel {
extern "C" [[noreturn]] void __stack_chk_fail();
extern "C" [[noreturn]] void __stack_chk_fail()
{
PANIC("Stack protector failure, stack smashing detected!");
}
EFI::Handle g_efi_image_handle = 0;
EFI::SystemTable* g_efi_system_table = nullptr;
static_assert(EFI::EFI_PAGE_SIZE == PAGE_SIZE, "The EFIPrekernel assumes that EFI_PAGE_SIZE == PAGE_SIZE");
extern "C" EFIAPI EFI::Status init(EFI::Handle image_handle, EFI::SystemTable* system_table);
extern "C" EFIAPI EFI::Status init(EFI::Handle image_handle, EFI::SystemTable* system_table)
{
// We use some EFI 1.10 functions from the System Table, so reject older versions.
static constexpr u32 efi_version_1_10 = (1 << 16) | 10;
if (system_table->hdr.signature != EFI::SystemTable::signature || system_table->hdr.revision < efi_version_1_10)
return EFI::Status::Unsupported;
g_efi_image_handle = image_handle;
g_efi_system_table = system_table;
system_table->con_out->set_attribute(system_table->con_out,
EFI::TextAttribute {
.foreground_color = EFI::TextAttribute::ForegroundColor::White,
.background_color = EFI::TextAttribute::BackgroundColor::Black,
});
// Clear the screen. This also removes the manufacturer logo, if present.
system_table->con_out->clear_screen(system_table->con_out);
ucs2_dbgln(u"SerenityOS EFI Prekernel");
TODO();
}
}
void __assertion_failed(char const* msg, char const* file, unsigned int line, char const* func)
{
dbgln("ASSERTION FAILED: {}", msg);
dbgln("{}:{} in {}", file, line, func);
Kernel::halt();
}