1
0
mirror of https://github.com/SerenityOS/serenity synced 2024-07-03 11:13:38 +00:00

Prekernel: Add support for assertion printing

This is done by using a FixedStringBuffer as the foundation to perform
string formatting, which ensures that we avoid memory allocations in
the prekernel stage.
This commit is contained in:
Liav A. 2024-05-24 07:34:14 +03:00 committed by Tim Schumacher
parent 00c9a57345
commit f6e01aae9a
9 changed files with 118 additions and 23 deletions

View File

@ -12,7 +12,7 @@
#include <AK/TypedTransfer.h>
#include <AK/Userspace.h>
#ifdef KERNEL
#if defined(KERNEL) && !defined(PREKERNEL)
# include <Kernel/Arch/SafeMem.h>
# include <Kernel/Arch/SmapDisabler.h>
# include <Kernel/Memory/MemorySections.h>
@ -64,7 +64,7 @@ public:
m_storage[index] = '\0';
}
#ifdef KERNEL
#if defined(KERNEL) && !defined(PREKERNEL)
ErrorOr<void> copy_characters_from_user(Userspace<char const*> user_str, size_t user_str_size)
{
if (user_str_size > Size)

View File

@ -16,7 +16,8 @@
# include <serenity.h>
#endif
#ifdef KERNEL
#if defined(PREKERNEL)
#elif defined(KERNEL)
# include <Kernel/Tasks/Process.h>
# include <Kernel/Tasks/Thread.h>
# include <Kernel/Time/TimeManagement.h>
@ -1152,7 +1153,9 @@ void vdbg(StringView fmtstr, TypeErasedFormatParams& params, bool newline)
StringBuilder builder;
if (is_rich_debug_enabled) {
#ifdef KERNEL
#if defined(PREKERNEL)
;
#elif defined(KERNEL)
if (Kernel::Processor::is_initialized() && TimeManagement::is_initialized()) {
auto time = TimeManagement::the().monotonic_time(TimePrecision::Coarse);
if (Kernel::Thread::current()) {
@ -1195,7 +1198,7 @@ void vdbg(StringView fmtstr, TypeErasedFormatParams& params, bool newline)
auto const string = builder.string_view();
#ifdef AK_OS_SERENITY
# ifdef KERNEL
# if defined(KERNEL) && !defined(PREKERNEL)
if (!Kernel::Processor::is_initialized()) {
kernelearlyputstr(string.characters_without_null_termination(), string.length());
return;
@ -1205,7 +1208,7 @@ void vdbg(StringView fmtstr, TypeErasedFormatParams& params, bool newline)
dbgputstr(string.characters_without_null_termination(), string.length());
}
#ifdef KERNEL
#if defined(KERNEL) && !defined(PREKERNEL)
void vdmesgln(StringView fmtstr, TypeErasedFormatParams& params)
{
StringBuilder builder;

View File

@ -14,7 +14,9 @@
#include <AK/StringView.h>
#include <AK/Vector.h>
#ifdef KERNEL
#if defined(PREKERNEL)
# include <Kernel/Library/MiniStdLib.h>
#elif defined(KERNEL)
# include <Kernel/Library/StdLib.h>
#else
# include <AK/ByteString.h>

View File

@ -5,10 +5,13 @@
*/
#include <Kernel/Arch/DebugOutput.h>
#include <Kernel/Arch/Processor.h>
#include <Kernel/Arch/x86_64/BochsDebugOutput.h>
#include <Kernel/Arch/x86_64/IO.h>
#if !defined(PREKERNEL)
# include <Kernel/Arch/Processor.h>
#endif
namespace Kernel {
static constexpr u16 serial_com1_io_port = 0x3F8;
@ -35,8 +38,13 @@ void debug_output(char ch)
serial_ready = true;
}
while ((IO::in8(serial_com1_io_port + 5) & 0x20) == 0)
while ((IO::in8(serial_com1_io_port + 5) & 0x20) == 0) {
#if !defined(PREKERNEL)
Processor::wait_check();
#else
;
#endif
}
if (ch == '\n' && !was_cr)
IO::out8(serial_com1_io_port, '\r');

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) 2024, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Prekernel/DebugOutput.h>
void __assertion_failed(char const* msg, char const* file, unsigned line, char const* func)
{
write_debug_output("ASSERTION FAILED: {}\n", msg);
write_debug_output("{}:{} in {}\n", file, line, func);
halt();
}

View File

@ -1,14 +1,26 @@
set(SOURCES
../../AK/StringBuilder.cpp
../../AK/StringUtils.cpp
../../AK/StringView.cpp
../../AK/Format.cpp
UBSanitizer.cpp
../Library/MiniStdLib.cpp
Assertions.cpp
boot.S
multiboot.S
init.cpp
DebugOutput.cpp
kmalloc.cpp
Runtime.cpp
../../Userland/Libraries/LibELF/Relocation.cpp
)
if ("${SERENITY_ARCH}" STREQUAL "x86_64")
set(SOURCES
${SOURCES}
../Arch/x86_64/DebugOutput.cpp)
endif()
if ("${SERENITY_ARCH}" STREQUAL "x86_64")
set(PREKERNEL_TARGET kernel_x86-64)
elseif("${SERENITY_ARCH}" STREQUAL "aarch64")
@ -23,6 +35,8 @@ set_property(TARGET KernelObject PROPERTY
IMPORTED_OBJECTS ${CMAKE_CURRENT_BINARY_DIR}/../Kernel.o
)
add_compile_definitions(PREKERNEL)
add_executable(${PREKERNEL_TARGET} ${SOURCES} $<TARGET_OBJECTS:KernelObject>)
add_dependencies(${PREKERNEL_TARGET} Kernel)
add_dependencies(${PREKERNEL_TARGET} install_libc_headers)

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Platform.h>
#include <AK/kstdio.h>
#include <Kernel/Arch/DebugOutput.h>
#include <Kernel/Prekernel/DebugOutput.h>
#if ARCH(X86_64)
# include <Kernel/Arch/x86_64/BochsDebugOutput.h>
#endif
void debug_write_string(StringView str)
{
if (str.is_null())
return;
for (u8 ch : str.bytes()) {
Kernel::debug_output(ch);
#if ARCH(X86_64)
Kernel::bochs_debug_output(ch);
#endif
}
}
extern "C" void dbgputstr(char const* characters, size_t length)
{
if (!characters)
return;
debug_write_string(StringView { characters, length });
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/CheckedFormatString.h>
#include <AK/FixedStringBuffer.h>
#include <AK/Format.h>
#include <AK/kmalloc.h>
#include <Kernel/Prekernel/Runtime.h>
void debug_write_string(StringView str);
template<typename... Parameters>
void write_debug_output(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
{
AK::VariadicFormatParams<AK::AllowDebugOnlyFormatters::No, Parameters...> variadic_format_parameters { parameters... };
auto message_buffer_or_error = FixedStringBuffer<128>::vformatted(fmtstr.view(), variadic_format_parameters);
if (message_buffer_or_error.is_error()) {
debug_write_string("PANIC: Failed to write message buffer:\n"sv);
debug_write_string(fmtstr.view());
halt();
}
auto message_buffer = message_buffer_or_error.release_value();
debug_write_string(message_buffer.representable_view());
}

View File

@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2021-2024, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -10,6 +10,7 @@
#include <Kernel/Boot/Multiboot.h>
#include <Kernel/Memory/PhysicalAddress.h>
#include <Kernel/Memory/VirtualAddress.h>
#include <Kernel/Prekernel/DebugOutput.h>
#include <Kernel/Prekernel/Prekernel.h>
#include <Kernel/Prekernel/Runtime.h>
#include <LibELF/ELFABI.h>
@ -54,11 +55,6 @@ void __stack_chk_fail()
halt();
}
void __assertion_failed(char const*, char const*, unsigned int, char const*)
{
halt();
}
namespace Kernel {
// boot.S expects these functions to exactly have the following signatures.
@ -96,8 +92,7 @@ extern "C" [[noreturn]] void init()
// We only consider the first specified multiboot module, and ignore
// the rest of the modules.
multiboot_module_entry_t* initrd_module = (multiboot_module_entry_t*)(FlatPtr)multiboot_info_ptr->mods_addr;
if (initrd_module->start > initrd_module->end)
halt();
VERIFY(initrd_module->start < initrd_module->end);
initrd_module_start = initrd_module->start;
initrd_module_end = initrd_module->end;
@ -107,8 +102,7 @@ extern "C" [[noreturn]] void init()
// copy the ELF header and program headers because we might end up overwriting them
Elf_Ehdr kernel_elf_header = *(Elf_Ehdr*)kernel_image;
Elf_Phdr kernel_program_headers[16];
if (kernel_elf_header.e_phnum > array_size(kernel_program_headers))
halt();
VERIFY(kernel_elf_header.e_phnum < array_size(kernel_program_headers));
__builtin_memcpy(kernel_program_headers, kernel_image + kernel_elf_header.e_phoff, sizeof(Elf_Phdr) * kernel_elf_header.e_phnum);
FlatPtr kernel_physical_base = (FlatPtr)0x200000;
@ -136,10 +130,8 @@ extern "C" [[noreturn]] void init()
continue;
auto start = kernel_load_base + kernel_program_header.p_vaddr;
auto end = start + kernel_program_header.p_memsz;
if (start < (FlatPtr)end_of_prekernel_image)
halt();
if (kernel_physical_base + kernel_program_header.p_paddr < (FlatPtr)end_of_prekernel_image)
halt();
VERIFY(start > (FlatPtr)end_of_prekernel_image);
VERIFY(kernel_physical_base + kernel_program_header.p_paddr > (FlatPtr)end_of_prekernel_image);
if (end > kernel_load_end)
kernel_load_end = end;
}