diff --git a/.concat.conf b/.concat.conf deleted file mode 100644 index eb1182c1..00000000 --- a/.concat.conf +++ /dev/null @@ -1,2 +0,0 @@ -alkos/ -scripts/ diff --git a/CMakeLists.txt b/CMakeLists.txt index c7e3544f..44774d73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,8 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(ValidationHelpers) include(SourceHelpers) include(RuntimeHelpers) +include(BashConfigHelpers) +include(MiscHelpers) add_library(alkos.target.properties.interface INTERFACE) # Populated by the toolchain file @@ -30,6 +32,9 @@ set(CMAKE_ROOT_DIR ${CMAKE_SOURCE_DIR}) # Conf file # ################################################################################ +set(BASH_CONF_FILE "${CMAKE_ROOT_DIR}/config/conf.generated.bash") +alkos_init_bash_config() + set(CMAKE_CONF_FILE "${CMAKE_ROOT_DIR}/config/conf.generated.cmake") # Check if configuration was done @@ -90,9 +95,11 @@ file(MAKE_DIRECTORY ${CMAKE_SYSROOT}/boot/grub) set(SYSTEM_LIB_TYPE k) -add_subdirectory(libs) +alkos_add_subdirs(libs) add_subdirectory(generated) add_subdirectory(kernel) +add_subdirectory(userspace) +add_subdirectory(rootfs) ################################################################################ # Aliases # diff --git a/cmake/BashConfigHelpers.cmake b/cmake/BashConfigHelpers.cmake new file mode 100644 index 00000000..bff4f0f3 --- /dev/null +++ b/cmake/BashConfigHelpers.cmake @@ -0,0 +1,64 @@ +# +# This module provides a function for working with bash config files +# + +#============================================================================ +# alkos_init_bash_config +#============================================================================ +function(alkos_init_bash_config) + file(WRITE "${BASH_CONF_FILE}" "#!/bin/bash\n") + file(APPEND "${BASH_CONF_FILE}" "# Autogenerated config for ${ARCH}\n") + file(APPEND "${BASH_CONF_FILE}" "# Do not try to edit this by hand!\n") + file(APPEND "${BASH_CONF_FILE}" "\n") +endfunction() + +#=============================================================================== +# alkos_add_to_bash_config +#=============================================================================== +function(alkos_add_to_bash_config VARIABLE_NAME VARIABLE_VALUE) + if(NOT EXISTS "${BASH_CONF_FILE}") + message(FATAL_ERROR "Bash config file ${BASH_CONF_FILE} does not exist. Please call alkos_init_bash_config first.") + endif() + + # Update existing variable if it exists, otherwise append at the end + file(READ "${BASH_CONF_FILE}" BASH_CONF_CONTENTS) + if(BASH_CONF_CONTENTS MATCHES "export ${VARIABLE_NAME}=") + string(REGEX REPLACE "export ${VARIABLE_NAME}=\"[^\"]*\"" "export ${VARIABLE_NAME}=\"${VARIABLE_VALUE}\"" UPDATED_BASH_CONF_CONTENTS "${BASH_CONF_CONTENTS}") + file(WRITE "${BASH_CONF_FILE}" "${UPDATED_BASH_CONF_CONTENTS}\n") + else() + file(APPEND "${BASH_CONF_FILE}" "export ${VARIABLE_NAME}=\"${VARIABLE_VALUE}\"\n") + endif() +endfunction() + +#=============================================================================== +# alkos_bash_config_append_to_list +#=============================================================================== +function(alkos_bash_config_append_to_list VARIABLE_NAME VALUES_TO_APPEND) + if(NOT EXISTS "${BASH_CONF_FILE}") + message(FATAL_ERROR "Bash config file ${BASH_CONF_FILE} does not exist. Please call alkos_init_bash_config first.") + endif() + + # This is how you pass list arguments to a bash script from CMake + string(REPLACE ";" " " VALUES_TO_APPEND "${VALUES_TO_APPEND}") + + # Read the current value of the variable from the bash config + file(READ "${BASH_CONF_FILE}" BASH_CONF_CONTENTS) + if(BASH_CONF_CONTENTS MATCHES "export ${VARIABLE_NAME}=\"[^\"]*\"") + string(REGEX MATCH "export ${VARIABLE_NAME}=\"([^\"]*)\"" "\\1" _ "${BASH_CONF_CONTENTS}") + + # Append the new value to the existing list + set(CURRENT_VALUE "${CMAKE_MATCH_1}") + if(CURRENT_VALUE STREQUAL "") + set(CURRENT_VALUE "${VALUES_TO_APPEND}") + else() + set(CURRENT_VALUE "${CURRENT_VALUE} ${VALUES_TO_APPEND}") + endif() + + # Update the variable in the bash config + string(REGEX REPLACE "export ${VARIABLE_NAME}=\"[^\"]*\"" "export ${VARIABLE_NAME}=\"${CURRENT_VALUE}\"" UPDATED_BASH_CONF_CONTENTS "${BASH_CONF_CONTENTS}") + file(WRITE "${BASH_CONF_FILE}" "${UPDATED_BASH_CONF_CONTENTS}\n") + else() + # Variable does not exist, create it + alkos_add_to_bash_config("${VARIABLE_NAME}" "${VALUES_TO_APPEND}") + endif() +endfunction() diff --git a/cmake/MiscHelpers.cmake b/cmake/MiscHelpers.cmake new file mode 100644 index 00000000..c6ff61bc --- /dev/null +++ b/cmake/MiscHelpers.cmake @@ -0,0 +1,28 @@ +# +# Miscellaneous CMake helper functions +# + +#=============================================================================== +# alkos_add_subdirs +#=============================================================================== +# Recursively adds all subdirectories in the given BASE_DIR. +## Parameters: +# BASE_DIR The base directory to search for subdirectories. +## Example: +# alkos_add_subdirs(modules) +# alkos_add_subdirs(${CMAKE_CURRENT_SOURCE_DIR}/modules) +# +function(alkos_add_subdirs BASE_DIR) + if(IS_ABSOLUTE "${BASE_DIR}") + set(base_dir "${BASE_DIR}") + else() + set(base_dir "${CMAKE_CURRENT_SOURCE_DIR}/${BASE_DIR}") + endif() + + file(GLOB subdirs RELATIVE "${base_dir}" "${base_dir}/*") + foreach(subdir ${subdirs}) + if(IS_DIRECTORY "${base_dir}/${subdir}") + add_subdirectory("${base_dir}/${subdir}") + endif() + endforeach() +endfunction() diff --git a/cmake/RuntimeHelpers.cmake b/cmake/RuntimeHelpers.cmake index b3bb7c45..522f193a 100644 --- a/cmake/RuntimeHelpers.cmake +++ b/cmake/RuntimeHelpers.cmake @@ -4,6 +4,7 @@ # include(ValidationHelpers) +include(BashConfigHelpers) #=============================================================================== # alkos_register_runtime_environment @@ -61,29 +62,19 @@ function(alkos_register_runtime_environment) PATHS ${MAKE_ISO_SCRIPT_PATH} ${RUN_ALKOS_SCRIPT_PATH} ${RUN_TESTS_SCRIPT_PATH} ) - # This is how you pass list arguments to a bash script from CMake - string(REPLACE ";" " " KERNEL_MODULES_FORMATTED "${ARG_MODULES}") - string(REPLACE ";" " " KERNEL_COMMANDS_FORMATTED "${ARG_MODULE_COMMANDS}") - - # Write a bash config file specific to this architecture - set(BASH_CONF_FILE "${CMAKE_ROOT_DIR}/config/conf.generated.bash") - - file(WRITE "${BASH_CONF_FILE}" "#!/bin/bash\n") - file(APPEND "${BASH_CONF_FILE}" "# Autogenerated config for ${ARG_ARCH_NAME}\n") - file(APPEND "${BASH_CONF_FILE}" "# Do not try to edit this by hand!\n") - file(APPEND "${BASH_CONF_FILE}" "\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_ARCH=\"${ARG_ARCH_NAME}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_BUILD_TYPE=\"${CMAKE_BUILD_TYPE}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_SYSROOT=\"${CMAKE_SYSROOT}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_BOOTABLE_KERNEL_EXEC=\"${ARG_BOOTABLE_EXECUTABLE}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_ISO_PATH=\"${ALKOS_ISO_PATH}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_KERNEL_MODULES=\"${KERNEL_MODULES_FORMATTED}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_KERNEL_COMMANDS=\"${KERNEL_COMMANDS_FORMATTED}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_BUILD_DIR=\"${CMAKE_BINARY_DIR}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_TOOL_DIR=\"${TOOL_BINARIES_DIR}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_QEMU_COMMAND=\"${ARG_QEMU_COMMAND}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_QEMU_NORMAL_FLAGS=\"${ARG_QEMU_NORMAL_FLAGS}\"\n") - file(APPEND "${BASH_CONF_FILE}" "export CONF_QEMU_TEST_FLAGS=\"${ARG_QEMU_TEST_FLAGS}\"\n") + # Add architecture-specific variables to the bash config + alkos_add_to_bash_config("CONF_ARCH" "${ARG_ARCH_NAME}") + alkos_add_to_bash_config("CONF_BUILD_TYPE" "${CMAKE_BUILD_TYPE}") + alkos_add_to_bash_config("CONF_SYSROOT" "${CMAKE_SYSROOT}") + alkos_add_to_bash_config("CONF_BOOTABLE_KERNEL_EXEC" "${ARG_BOOTABLE_EXECUTABLE}") + alkos_add_to_bash_config("CONF_ISO_PATH" "${ALKOS_ISO_PATH}") + alkos_bash_config_append_to_list("CONF_KERNEL_MODULES" "${ARG_MODULES}") + alkos_bash_config_append_to_list("CONF_KERNEL_COMMANDS" "${ARG_MODULE_COMMANDS}") + alkos_add_to_bash_config("CONF_BUILD_DIR" "${CMAKE_BINARY_DIR}") + alkos_add_to_bash_config("CONF_TOOL_DIR" "${TOOL_BINARIES_DIR}") + alkos_add_to_bash_config("CONF_QEMU_COMMAND" "${ARG_QEMU_COMMAND}") + alkos_add_to_bash_config("CONF_QEMU_NORMAL_FLAGS" "${ARG_QEMU_NORMAL_FLAGS}") + alkos_add_to_bash_config("CONF_QEMU_TEST_FLAGS" "${ARG_QEMU_TEST_FLAGS}") add_custom_target(iso-${ARG_ARCH_NAME} COMMAND ${MAKE_ISO_SCRIPT_PATH} -v @@ -123,3 +114,85 @@ function(alkos_register_runtime_environment) ) endif() endfunction() +#------------------------------------------------------------------------------- +# register_filesystem +#------------------------------------------------------------------------------- +# A filesystem registration helper that configures the rootfs +# generation. It can be used to create either an initrd within the sysroot +# or a standalone filesystem image within the build binaries folder. +# +# Parameters (oneValueArgs): +# TYPE Either INITRD or IMAGE +# ROOTFS_TYPE Type of rootfs to create (e.g., fat, ext4) +# ROOTFS_DIR Staging directory for building rootfs contents +# ROOTFS_TARGET_PATH Target image path to generate (optional; defaults based on TYPE) +# ROOTFS_OVERLAY_DIR Overlay directory to copy into the rootfs +# MODULE Optional module target name to include in the ISO +# MODULE_COMMAND Optional bootloader command for the module +# +#------------------------------------------------------------------------------- +function(register_filesystem) + set(options) + set(oneValueArgs + TYPE + ROOTFS_TYPE + ROOTFS_TARGET_PATH + ROOTFS_OVERLAY_DIR + MODULE + MODULE_COMMAND + ) + set(multiValueArgs) + + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + alkos_ensure_called_once(NAME ${CMAKE_CURRENT_FUNCTION}) + + alkos_ensure_defined( + VARS ARG_TYPE ARG_ROOTFS_TYPE ARG_ROOTFS_TARGET_PATH ARG_ROOTFS_OVERLAY_DIR + ) + + # Resolve target defaults and feature flags + if(ARG_TYPE STREQUAL "INITRD") + alkos_ensure_feature_enabled( + FLAG CMAKE_FEATURE_FLAG_RAMDISK + MESSAGE "Initial RAM filesystem support is disabled." + ) + elseif(ARG_TYPE NOT STREQUAL "IMAGE") + message(FATAL_ERROR "register_filesystem: Unknown TYPE='${ARG_TYPE}'. Expected INITRD or IMAGE.") + endif() + + # Export variables for the rootfs maker + alkos_add_to_bash_config("CONF_ROOTFS_TARGET_PATH" "${ARG_ROOTFS_TARGET_PATH}") + alkos_add_to_bash_config("CONF_ROOTFS_OVERLAY_DIR" "${ARG_ROOTFS_OVERLAY_DIR}") + + if(ARG_TYPE STREQUAL "INITRD") + alkos_ensure_defined(VARS ARG_MODULE ARG_MODULE_COMMAND) + + alkos_bash_config_append_to_list("CONF_KERNEL_MODULES" "${ARG_MODULE}") + alkos_bash_config_append_to_list("CONF_KERNEL_COMMANDS" "${ARG_MODULE_COMMAND}") + endif() + + # Create the targets + set(MAKE_ROOTFS_SCRIPT_PATH ${CMAKE_SOURCE_DIR}/scripts/actions/make_rootfs.bash) + alkos_ensure_path_exists(PATHS ${MAKE_ROOTFS_SCRIPT_PATH}) + + add_custom_target(rootfs + # Ensure the staging directory is clean before building the rootfs. + # Remove the directory and recreate it so the generator starts from + # an empty staging area. + COMMAND ${CMAKE_COMMAND} -E rm -rf "${ROOTFS_DIR}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${ROOTFS_DIR}" + COMMAND ${MAKE_ROOTFS_SCRIPT_PATH} -v -- ${ARG_ROOTFS_TYPE} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Building root filesystem" + ) + add_dependencies(iso-${ARCH} rootfs) + + add_custom_target(mountfs + DEPENDS rootfs + COMMAND sudo umount /mnt || true + COMMAND sudo mount -o loop ${ARG_ROOTFS_TARGET_PATH} /mnt + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Mounting root filesystem" + ) +endfunction() diff --git a/cmake/ValidationHelpers.cmake b/cmake/ValidationHelpers.cmake index 2a2d5d58..93e17594 100644 --- a/cmake/ValidationHelpers.cmake +++ b/cmake/ValidationHelpers.cmake @@ -168,3 +168,67 @@ function(alkos_ensure_path_exists) message(FATAL_ERROR "${error_message}") endif() endfunction() + +#=============================================================================== +# alkos_ensure_feature_flag_enabled +#=============================================================================== +# +# Checks if a specified feature flag is enabled and halts with a +# fatal error if it is not. +# +# Parameters: +# FLAG The name of the feature flag variable to check. +# MESSAGE (Optional) A supplementary message to append to the +# standard error output. This is useful for providing +# additional context or instructions to the user. +# +# Example: +# # Assume CMAKE_FEATURE_FLAG_DEBUG_OUTPUT must be enabled. +# alkos_ensure_feature_flag_enabled( +# FLAG CMAKE_FEATURE_FLAG_DEBUG_OUTPUT +# MESSAGE "Debug output must be enabled for this build." +# ) +# +function(alkos_ensure_feature_enabled) + set(options) + set(oneValueArgs FLAG MESSAGE) + set(multiValueArgs) + + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT ARG_FLAG) + message(FATAL_ERROR "alkos_ensure_feature_enabled() called without a feature to check.") + endif() + + if(NOT DEFINED ${ARG_FLAG} OR NOT ${ARG_FLAG}) + set(error_message "The feature flag '${ARG_FLAG}' must be enabled.") + + if(ARG_MESSAGE) + string(APPEND error_message "\n${ARG_MESSAGE}") + endif() + + message(FATAL_ERROR "${error_message}") + endif() +endfunction() + +#=============================================================================== +# alkos_ensure_called_once +#=============================================================================== +function(alkos_ensure_called_once) + set(options) + set(oneValueArgs NAME) + set(multiValueArgs) + + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT ARG_NAME) + message(FATAL_ERROR "alkos_ensure_called_once() called without a NAME to check.") + endif() + + get_property(already_called GLOBAL PROPERTY ALKOS_CALLED_${ARG_NAME}) + if(already_called) + message(FATAL_ERROR "The function '${ARG_NAME}' has already been called. It can only be called once.") + endif() + + set_property(GLOBAL PROPERTY ALKOS_CALLED_${ARG_NAME} TRUE) +endfunction() diff --git a/generated/.gitignore b/generated/.gitignore new file mode 100644 index 00000000..7841db52 --- /dev/null +++ b/generated/.gitignore @@ -0,0 +1 @@ +include/autogen/* diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index f2bca76b..95eb5ce3 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -68,6 +68,17 @@ target_link_libraries(cpp PUBLIC target_compile_definitions(c PRIVATE __ALKOS_KERNEL_LIBC__) target_compile_definitions(cpp PRIVATE __ALKOS_KERNEL_LIBCPP__) +########################### Graphics Library ################################# + +add_library(kernel.libgraphics STATIC ${LIBGRAPHICS_SOURCES}) + +target_link_libraries(kernel.libgraphics PUBLIC + alkos.libgraphics.interface + alkos.target.properties.interface +) + +target_compile_definitions(kernel.libgraphics PRIVATE __ALKOS_KERNEL_LIBGRAPHICS__) + ########################## Configure for given Arch ########################## add_subdirectory(arch/${ARCH}) @@ -89,6 +100,7 @@ target_link_libraries(alkos.kernel PRIVATE alkos.autogen.interface c cpp + kernel.libgraphics ) ############## Linker Configuration for CXX Global Constructors ############## diff --git a/kernel/arch/x86_64/CMakeLists.txt b/kernel/arch/x86_64/CMakeLists.txt index 9a9917cd..7d5271f0 100644 --- a/kernel/arch/x86_64/CMakeLists.txt +++ b/kernel/arch/x86_64/CMakeLists.txt @@ -58,9 +58,9 @@ alkos_register_runtime_environment( QEMU_COMMAND "qemu-system-x86_64" QEMU_NORMAL_FLAGS - "-serial stdio -enable-kvm -cpu max -display default,show-cursor=on -m 4G -smp sockets=1,cores=4,threads=1" + "-serial stdio -enable-kvm -cpu max,+invtsc,migratable=off -machine type=q35,accel=kvm -display default,show-cursor=on -k en-us -m 4G -smp sockets=1,cores=4,threads=1 -no-reboot" QEMU_TEST_FLAGS - "-serial stdio -enable-kvm -cpu max -display none -m 4G -smp sockets=1,cores=4,threads=1" + "-serial stdio -enable-kvm -cpu max,+invtsc,migratable=off -machine type=q35,accel=kvm -display none -m 4G -smp sockets=1,cores=4,threads=1 -no-reboot" MODULES alkos.boot.loader.64 alkos.kernel diff --git a/kernel/arch/x86_64/boot/lib/abi/transition_data.hpp b/kernel/arch/x86_64/boot/lib/abi/transition_data.hpp index fc3f495c..191d0072 100644 --- a/kernel/arch/x86_64/boot/lib/abi/transition_data.hpp +++ b/kernel/arch/x86_64/boot/lib/abi/transition_data.hpp @@ -1,8 +1,8 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_ABI_TRANSITION_DATA_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_ABI_TRANSITION_DATA_HPP_ +#include #include -#include #include "mem/pmm.hpp" #include "mem/vmm.hpp" @@ -18,14 +18,40 @@ struct alignas(64) TransitionData { }; struct PACK alignas(64) KernelArguments { + /// Kernel Mem Layout u64 kernel_start_addr; u64 kernel_end_addr; + /// VMem u64 pml_4_table_phys_addr; + /// Memory Bitmap u64 mem_info_bitmap_addr; u64 mem_info_total_pages; + /// Framebuffer + u64 fb_addr; + u32 fb_width; + u32 fb_height; + u32 fb_pitch; + u32 fb_bpp; // Bits per pixel + + // RGB Format + u8 fb_red_pos; + u8 fb_red_mask; + u8 fb_green_pos; + u8 fb_green_mask; + u8 fb_blue_pos; + u8 fb_blue_mask; + + /// Ramdisk + u64 ramdisk_start; + u64 ramdisk_end; + + /// ACPI + u64 acpi_rsdp_phys_addr; + + /// Multiboot u64 multiboot_info_addr; u64 multiboot_header_start_addr; u64 multiboot_header_end_addr; diff --git a/kernel/arch/x86_64/boot/lib/cpu/utils.hpp b/kernel/arch/x86_64/boot/lib/cpu/utils.hpp index 163e12a7..831b0680 100644 --- a/kernel/arch/x86_64/boot/lib/cpu/utils.hpp +++ b/kernel/arch/x86_64/boot/lib/cpu/utils.hpp @@ -1,8 +1,8 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_CPU_UTILS_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_CPU_UTILS_HPP_ +#include #include -#include #include "hw/io.hpp" /** diff --git a/kernel/arch/x86_64/boot/lib/debug_trace.hpp b/kernel/arch/x86_64/boot/lib/debug_trace.hpp index 732fba4d..6e8dd5ab 100644 --- a/kernel/arch/x86_64/boot/lib/debug_trace.hpp +++ b/kernel/arch/x86_64/boot/lib/debug_trace.hpp @@ -1,8 +1,7 @@ -#ifndef ALKOS_LIBC_INCLUDE_EXTENSIONS_DEBUG_HPP_ -#define ALKOS_LIBC_INCLUDE_EXTENSIONS_DEBUG_HPP_ +#ifndef KERNEL_ARCH_X86_64_BOOT_LIB_DEBUG_TRACE_HPP_ +#define KERNEL_ARCH_X86_64_BOOT_LIB_DEBUG_TRACE_HPP_ #include -#include #include "platform.h" @@ -57,4 +56,4 @@ void FormatTrace(const char *format, Args... args) #define TRACE_SUCCESS(message, ...) \ TRACE(TRACE_FORMAT_SUCCESS(message), 0ull __VA_OPT__(, ) __VA_ARGS__) -#endif // ALKOS_LIBC_INCLUDE_EXTENSIONS_DEBUG_HPP_ +#endif // KERNEL_ARCH_X86_64_BOOT_LIB_DEBUG_TRACE_HPP_ diff --git a/kernel/arch/x86_64/boot/lib/elf/elf_64.cpp b/kernel/arch/x86_64/boot/lib/elf/elf_64.cpp index 75e80390..2711da0e 100644 --- a/kernel/arch/x86_64/boot/lib/elf/elf_64.cpp +++ b/kernel/arch/x86_64/boot/lib/elf/elf_64.cpp @@ -51,7 +51,7 @@ std::expected Load(const byte *elf_ptr, u64 destination_addr) const u64 segment_source_size = program_header_entry->size_in_file_bytes; TRACE_INFO( - "Segment %d: dest=0x%llX, dest_size=0x%sB, source=0x%llX, source_size=0x%sB", i + 1, + "Segment %d: dest=0x%llX, dest_size=%sB, source=0x%llX, source_size=%sB", i + 1, segment_dest, FormatMetricUint(segment_dest_size), segment_source, FormatMetricUint(segment_source_size) ); diff --git a/kernel/arch/x86_64/boot/lib/elf/elf_64.hpp b/kernel/arch/x86_64/boot/lib/elf/elf_64.hpp index 10a0cd02..1e9cdadf 100644 --- a/kernel/arch/x86_64/boot/lib/elf/elf_64.hpp +++ b/kernel/arch/x86_64/boot/lib/elf/elf_64.hpp @@ -3,9 +3,9 @@ #include +#include #include #include -#include #include "elf/error.hpp" diff --git a/kernel/arch/x86_64/boot/lib/elf/elf_dynamic.hpp b/kernel/arch/x86_64/boot/lib/elf/elf_dynamic.hpp index 5f0ab2b1..67a6d52c 100644 --- a/kernel/arch/x86_64/boot/lib/elf/elf_dynamic.hpp +++ b/kernel/arch/x86_64/boot/lib/elf/elf_dynamic.hpp @@ -1,8 +1,8 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_ELF_ELF_DYNAMIC_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_ELF_ELF_DYNAMIC_HPP_ +#include #include -#include #include "elf/error.hpp" diff --git a/kernel/arch/x86_64/boot/lib/elf/error.hpp b/kernel/arch/x86_64/boot/lib/elf/error.hpp index a4ec0299..f0377da2 100644 --- a/kernel/arch/x86_64/boot/lib/elf/error.hpp +++ b/kernel/arch/x86_64/boot/lib/elf/error.hpp @@ -1,5 +1,5 @@ -#ifndef ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_ELF_ERROR_HPP_ -#define ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_ELF_ERROR_HPP_ +#ifndef KERNEL_ARCH_X86_64_BOOT_LIB_ELF_ERROR_HPP_ +#define KERNEL_ARCH_X86_64_BOOT_LIB_ELF_ERROR_HPP_ namespace Elf64 { @@ -14,4 +14,4 @@ enum class Error { } // namespace Elf64 -#endif // ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_ELF_ERROR_HPP_ +#endif // KERNEL_ARCH_X86_64_BOOT_LIB_ELF_ERROR_HPP_ diff --git a/kernel/arch/x86_64/boot/lib/hw/io.hpp b/kernel/arch/x86_64/boot/lib/hw/io.hpp index 528128be..dbf2f79c 100644 --- a/kernel/arch/x86_64/boot/lib/hw/io.hpp +++ b/kernel/arch/x86_64/boot/lib/hw/io.hpp @@ -2,8 +2,8 @@ #define KERNEL_ARCH_X86_64_BOOT_LIB_HW_IO_HPP_ #include +#include #include -#include FAST_CALL byte inb(const u16 port) { diff --git a/kernel/arch/x86_64/boot/lib/hw/pci.hpp b/kernel/arch/x86_64/boot/lib/hw/pci.hpp index 2803299f..bae1f519 100644 --- a/kernel/arch/x86_64/boot/lib/hw/pci.hpp +++ b/kernel/arch/x86_64/boot/lib/hw/pci.hpp @@ -1,8 +1,8 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_HW_PCI_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_HW_PCI_HPP_ +#include #include -#include #include "hw/io.hpp" #include "trace_framework.hpp" diff --git a/kernel/arch/x86_64/boot/lib/hw/serial/qemu.cpp b/kernel/arch/x86_64/boot/lib/hw/serial/qemu.cpp index 3aa4466b..db6a7974 100644 --- a/kernel/arch/x86_64/boot/lib/hw/serial/qemu.cpp +++ b/kernel/arch/x86_64/boot/lib/hw/serial/qemu.cpp @@ -142,8 +142,6 @@ void QemuTerminalInit() /* Switch to normal operation mode with final modem configuration */ outb(kModemControlReg, kModemConfFlags); - - TRACE_SUCCESS("QemuTerminalInit() returned with success"); } /** diff --git a/kernel/arch/x86_64/boot/lib/hw/serial/qemu.hpp b/kernel/arch/x86_64/boot/lib/hw/serial/qemu.hpp index c611faa5..cf650ddc 100644 --- a/kernel/arch/x86_64/boot/lib/hw/serial/qemu.hpp +++ b/kernel/arch/x86_64/boot/lib/hw/serial/qemu.hpp @@ -1,7 +1,7 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_HW_SERIAL_QEMU_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_HW_SERIAL_QEMU_HPP_ -#include +#include /** * @file serial_qemu.hpp diff --git a/kernel/arch/x86_64/boot/lib/hw/vga.cpp b/kernel/arch/x86_64/boot/lib/hw/vga.cpp index 7241a9c9..b6476372 100644 --- a/kernel/arch/x86_64/boot/lib/hw/vga.cpp +++ b/kernel/arch/x86_64/boot/lib/hw/vga.cpp @@ -1,6 +1,6 @@ #include +#include #include -#include #include "hw/vga.hpp" diff --git a/kernel/arch/x86_64/boot/lib/hw/vga.hpp b/kernel/arch/x86_64/boot/lib/hw/vga.hpp index e1998662..78ce8600 100644 --- a/kernel/arch/x86_64/boot/lib/hw/vga.hpp +++ b/kernel/arch/x86_64/boot/lib/hw/vga.hpp @@ -1,7 +1,7 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_HW_VGA_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_HW_VGA_HPP_ -#include +#include /** * @file vga.hpp diff --git a/kernel/arch/x86_64/boot/lib/mem/error.hpp b/kernel/arch/x86_64/boot/lib/mem/error.hpp index 1db77ab6..7ea6b3ae 100644 --- a/kernel/arch/x86_64/boot/lib/mem/error.hpp +++ b/kernel/arch/x86_64/boot/lib/mem/error.hpp @@ -1,9 +1,9 @@ -#ifndef ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_MEM_ERROR_HPP_ -#define ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_MEM_ERROR_HPP_ +#ifndef KERNEL_ARCH_X86_64_BOOT_LIB_MEM_ERROR_HPP_ +#define KERNEL_ARCH_X86_64_BOOT_LIB_MEM_ERROR_HPP_ enum class MemError { OutOfMemory, InvalidArgument, }; -#endif // ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_MEM_ERROR_HPP_ +#endif // KERNEL_ARCH_X86_64_BOOT_LIB_MEM_ERROR_HPP_ diff --git a/kernel/arch/x86_64/boot/lib/mem/page_map.hpp b/kernel/arch/x86_64/boot/lib/mem/page_map.hpp index 537b195a..792a39c3 100644 --- a/kernel/arch/x86_64/boot/lib/mem/page_map.hpp +++ b/kernel/arch/x86_64/boot/lib/mem/page_map.hpp @@ -1,9 +1,9 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_MEM_PAGE_MAP_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_MEM_PAGE_MAP_HPP_ +#include #include #include -#include #include "mem/physical_ptr.hpp" diff --git a/kernel/arch/x86_64/boot/lib/mem/physical_ptr.hpp b/kernel/arch/x86_64/boot/lib/mem/physical_ptr.hpp index 59a84032..bc1b9bdd 100644 --- a/kernel/arch/x86_64/boot/lib/mem/physical_ptr.hpp +++ b/kernel/arch/x86_64/boot/lib/mem/physical_ptr.hpp @@ -1,8 +1,8 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_MEM_PHYSICAL_PTR_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_MEM_PHYSICAL_PTR_HPP_ +#include #include -#include template class PhysicalPtr diff --git a/kernel/arch/x86_64/boot/lib/mem/pmm.cpp b/kernel/arch/x86_64/boot/lib/mem/pmm.cpp index 0a45421f..80a2ed53 100644 --- a/kernel/arch/x86_64/boot/lib/mem/pmm.cpp +++ b/kernel/arch/x86_64/boot/lib/mem/pmm.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "debug_trace.hpp" @@ -274,6 +275,7 @@ std::expected PhysicalMemoryManager::IterateToNextFreePage32() std::tuple PhysicalMemoryManager::CalcBitmapSize(Multiboot::MemoryMap &mem_map) { using namespace Multiboot; + using namespace internal; u64 maximum_physical_address = 0; for (MmapEntry &entry : mem_map) { @@ -283,9 +285,8 @@ std::tuple PhysicalMemoryManager::CalcBitmapSize(Multiboot::MemoryMap maximum_physical_address = std::max(maximum_physical_address, entry.addr + entry.len); } - // Round up division TODO Add to libc - const u64 total_pages = static_cast(maximum_physical_address + kPageSize - 1) / kPageSize; - const u64 bitmap_size = (static_cast(total_pages) + 7) / 8; + const u64 total_pages = DivRoundUp(maximum_physical_address, kPageSize); + const u64 bitmap_size = DivRoundUp(total_pages, 8); TRACE_DEBUG( "Max avaliable physical address: %#018llx, total pages: %llu, bitmap size: %sB", diff --git a/kernel/arch/x86_64/boot/lib/mem/vmm.cpp b/kernel/arch/x86_64/boot/lib/mem/vmm.cpp index 463873f3..28763507 100644 --- a/kernel/arch/x86_64/boot/lib/mem/vmm.cpp +++ b/kernel/arch/x86_64/boot/lib/mem/vmm.cpp @@ -1,7 +1,7 @@ +#include #include #include #include -#include #include "debug_trace.hpp" #include "mem/error.hpp" diff --git a/kernel/arch/x86_64/boot/lib/mem/vmm.tpp b/kernel/arch/x86_64/boot/lib/mem/vmm.tpp index dda0a7e3..4fd25fca 100644 --- a/kernel/arch/x86_64/boot/lib/mem/vmm.tpp +++ b/kernel/arch/x86_64/boot/lib/mem/vmm.tpp @@ -43,7 +43,7 @@ void VirtualMemoryManager::Map( MapOnePageTag, const u64 virt_addr, const u64 phys_addr, const u64 flags ) { - static constexpr u64 kDefaultFlags = kPresentBit | kWriteBit | kUserAccessibleBit; + static constexpr u64 kDefaultFlags = kPresentBit | kWriteBit; // !!! // Note: Has to be understood that this whole function diff --git a/kernel/arch/x86_64/boot/lib/multiboot2/error.hpp b/kernel/arch/x86_64/boot/lib/multiboot2/error.hpp index 3b4bff5e..bed81f6a 100644 --- a/kernel/arch/x86_64/boot/lib/multiboot2/error.hpp +++ b/kernel/arch/x86_64/boot/lib/multiboot2/error.hpp @@ -1,5 +1,5 @@ -#ifndef ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_ERROR_HPP_ -#define ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_ERROR_HPP_ +#ifndef KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_ERROR_HPP_ +#define KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_ERROR_HPP_ namespace Multiboot { @@ -10,4 +10,4 @@ enum class Error { } // namespace Multiboot -#endif // ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_ERROR_HPP_ +#endif // KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_ERROR_HPP_ diff --git a/kernel/arch/x86_64/boot/lib/multiboot2/info.hpp b/kernel/arch/x86_64/boot/lib/multiboot2/info.hpp index 86854e36..4bc30004 100644 --- a/kernel/arch/x86_64/boot/lib/multiboot2/info.hpp +++ b/kernel/arch/x86_64/boot/lib/multiboot2/info.hpp @@ -1,11 +1,11 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_INFO_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_INFO_HPP_ +#include #include #include #include #include -#include #include "multiboot2/error.hpp" #include "multiboot2/multiboot2.h" diff --git a/kernel/arch/x86_64/boot/lib/multiboot2/memory_map.hpp b/kernel/arch/x86_64/boot/lib/multiboot2/memory_map.hpp index 2cb73d36..1ea7822f 100644 --- a/kernel/arch/x86_64/boot/lib/multiboot2/memory_map.hpp +++ b/kernel/arch/x86_64/boot/lib/multiboot2/memory_map.hpp @@ -1,9 +1,9 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_MEMORY_MAP_HPP_ #define KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_MEMORY_MAP_HPP_ +#include #include #include -#include #include "multiboot2/multiboot2.h" diff --git a/kernel/arch/x86_64/boot/lib/multiboot2/multiboot2.h b/kernel/arch/x86_64/boot/lib/multiboot2/multiboot2.h index d08dcba4..602720a1 100644 --- a/kernel/arch/x86_64/boot/lib/multiboot2/multiboot2.h +++ b/kernel/arch/x86_64/boot/lib/multiboot2/multiboot2.h @@ -1,7 +1,7 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_MULTIBOOT2_H_ #define KERNEL_ARCH_X86_64_BOOT_LIB_MULTIBOOT2_MULTIBOOT2_H_ -#include +#include namespace Multiboot { @@ -271,9 +271,7 @@ struct TagFramebufferCommon { static constexpr u8 kFramebufferTypeEgaText = 2; }; -struct TagFramebuffer { - struct TagFramebufferCommon common; - +struct TagFramebuffer : public TagFramebufferCommon { union { struct { u16 framebuffer_palette_num_colors; diff --git a/kernel/arch/x86_64/boot/lib/sys/libc_backend.cpp b/kernel/arch/x86_64/boot/lib/sys/libc_backend.cpp index c5cc87f2..011ce98c 100644 --- a/kernel/arch/x86_64/boot/lib/sys/libc_backend.cpp +++ b/kernel/arch/x86_64/boot/lib/sys/libc_backend.cpp @@ -16,42 +16,9 @@ void __platform_panic(const char *msg) OsHang(); } -void __platform_get_clock_value(ClockType /*type*/, TimeVal *time, Timezone *time_zone) -{ - if (time != nullptr) { - time->seconds = 0; - time->remainder = 0; - } - - if (time_zone != nullptr) { - time_zone->west_offset_minutes = 0; - time_zone->dst_time_offset_minutes = 0; - time_zone->dst_time_start_seconds = 0; - time_zone->dst_time_end_seconds = 0; - } -} - -u64 __platform_get_clock_ticks_in_second(ClockType /*type*/) { return 1; } - -void __platform_get_timezone(Timezone *time_zone) -{ - if (time_zone != nullptr) { - time_zone->west_offset_minutes = 0; - time_zone->dst_time_offset_minutes = 0; - time_zone->dst_time_start_seconds = 0; - time_zone->dst_time_end_seconds = 0; - } -} - void __platform_debug_write(const char *buffer) { if constexpr (FeatureEnabled) { QemuTerminalWriteString(buffer); } } - -size_t __platform_debug_read_line(char * /*buffer*/, size_t /*buffer_size*/) -{ - /* Not implemented in loader */ - return 0; -} diff --git a/kernel/arch/x86_64/boot/lib/sys/panic.hpp b/kernel/arch/x86_64/boot/lib/sys/panic.hpp index e7a1e267..45f6aba1 100644 --- a/kernel/arch/x86_64/boot/lib/sys/panic.hpp +++ b/kernel/arch/x86_64/boot/lib/sys/panic.hpp @@ -1,5 +1,5 @@ -#ifndef ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_SYS_PANIC_HPP_ -#define ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_SYS_PANIC_HPP_ +#ifndef KERNEL_ARCH_X86_64_BOOT_LIB_SYS_PANIC_HPP_ +#define KERNEL_ARCH_X86_64_BOOT_LIB_SYS_PANIC_HPP_ #include @@ -22,4 +22,4 @@ FAST_CALL NO_RET void KernelPanicFormat(const char *fmt, Args... args) KernelPanic(buffer); } -#endif // ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_SYS_PANIC_HPP_ +#endif // KERNEL_ARCH_X86_64_BOOT_LIB_SYS_PANIC_HPP_ diff --git a/kernel/arch/x86_64/boot/lib/todo.hpp b/kernel/arch/x86_64/boot/lib/todo.hpp index 7890490f..fb4e07e1 100644 --- a/kernel/arch/x86_64/boot/lib/todo.hpp +++ b/kernel/arch/x86_64/boot/lib/todo.hpp @@ -1,5 +1,5 @@ -#ifndef ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_TODO_HPP_ -#define ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_TODO_HPP_ +#ifndef KERNEL_ARCH_X86_64_BOOT_LIB_TODO_HPP_ +#define KERNEL_ARCH_X86_64_BOOT_LIB_TODO_HPP_ /** * @brief This file's purpose is to define a set of macros used as placeholders @@ -16,4 +16,4 @@ #define TODO_BY_THE_END_OF_MILESTONE0 #define TODO_WHEN_DEBUGGING_FRAMEWORK -#endif // ALKOS_KERNEL_ARCH_X86_64_BOOT_LIB_TODO_HPP_ +#endif // KERNEL_ARCH_X86_64_BOOT_LIB_TODO_HPP_ diff --git a/kernel/arch/x86_64/boot/loader_32/build/multiboot_header.nasm b/kernel/arch/x86_64/boot/loader_32/build/multiboot_header.nasm index 97663235..3f5d4375 100644 --- a/kernel/arch/x86_64/boot/loader_32/build/multiboot_header.nasm +++ b/kernel/arch/x86_64/boot/loader_32/build/multiboot_header.nasm @@ -53,6 +53,8 @@ MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED equ 1 MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED equ 2 + FRAMEBUFFER_REQUIRED_DEPTH equ 32 + ; Multiboot header section .multiboot align 8 @@ -78,9 +80,9 @@ multiboot_start: dw MULTIBOOT_HEADER_TAG_FRAMEBUFFER dw MULTIBOOT_HEADER_TAG_OPTIONAL dd (.framebuffer_tag_end - .framebuffer_tag_start) - dd 0 ; width - no preference - dd 0 ; height - no preference - dd 0 ; depth - no preference + dd 800 ; width - no preference + dd 600 ; height - no preference + dd FRAMEBUFFER_REQUIRED_DEPTH ; depth .framebuffer_tag_end: ; End tag (required) diff --git a/kernel/arch/x86_64/boot/loader_32/src/error.hpp b/kernel/arch/x86_64/boot/loader_32/src/error.hpp index 252d3701..0910dd3b 100644 --- a/kernel/arch/x86_64/boot/loader_32/src/error.hpp +++ b/kernel/arch/x86_64/boot/loader_32/src/error.hpp @@ -1,5 +1,5 @@ -#ifndef ALKOS_KERNEL_ARCH_X86_64_BOOT_LOADER_32_SRC_ERROR_HPP_ -#define ALKOS_KERNEL_ARCH_X86_64_BOOT_LOADER_32_SRC_ERROR_HPP_ +#ifndef KERNEL_ARCH_X86_64_BOOT_LOADER_32_SRC_ERROR_HPP_ +#define KERNEL_ARCH_X86_64_BOOT_LOADER_32_SRC_ERROR_HPP_ namespace loader32 { @@ -15,4 +15,4 @@ enum class Error { } // namespace loader32 -#endif // ALKOS_KERNEL_ARCH_X86_64_BOOT_LOADER_32_SRC_ERROR_HPP_ +#endif // KERNEL_ARCH_X86_64_BOOT_LOADER_32_SRC_ERROR_HPP_ diff --git a/kernel/arch/x86_64/boot/loader_64/src/error.hpp b/kernel/arch/x86_64/boot/loader_64/src/error.hpp index 418ec3b6..d4af71b7 100644 --- a/kernel/arch/x86_64/boot/loader_64/src/error.hpp +++ b/kernel/arch/x86_64/boot/loader_64/src/error.hpp @@ -1,5 +1,5 @@ -#ifndef ALKOS_KERNEL_ARCH_X86_64_BOOT_LOADER_64_SRC_ERROR_HPP_ -#define ALKOS_KERNEL_ARCH_X86_64_BOOT_LOADER_64_SRC_ERROR_HPP_ +#ifndef KERNEL_ARCH_X86_64_BOOT_LOADER_64_SRC_ERROR_HPP_ +#define KERNEL_ARCH_X86_64_BOOT_LOADER_64_SRC_ERROR_HPP_ namespace loader64 { @@ -13,4 +13,4 @@ enum class Error { } // namespace loader64 -#endif // ALKOS_KERNEL_ARCH_X86_64_BOOT_LOADER_64_SRC_ERROR_HPP_ +#endif // KERNEL_ARCH_X86_64_BOOT_LOADER_64_SRC_ERROR_HPP_ diff --git a/kernel/arch/x86_64/boot/loader_64/src/main.cpp b/kernel/arch/x86_64/boot/loader_64/src/main.cpp index 8238d66d..505db757 100644 --- a/kernel/arch/x86_64/boot/loader_64/src/main.cpp +++ b/kernel/arch/x86_64/boot/loader_64/src/main.cpp @@ -150,7 +150,7 @@ static u64 LoadKernelIntoMemory( auto mmap_tag_res = multiboot_info.FindTag(); ASSERT_TRUE(mmap_tag_res, "Failed to find memory map tag in multiboot info"); - vmm.Alloc(kKernelVirtualAddressStart, kernel_info.size, kPresentBit | kWriteBit); + vmm.Alloc(kKernelVirtualAddressStart, kernel_info.size, kPresentBit | kWriteBit | kGlobalBit); // Load the ELF file from the module into the newly mapped memory byte *module_start = reinterpret_cast(kernel_info.tag->mod_start); @@ -160,6 +160,27 @@ static u64 LoadKernelIntoMemory( return entry_point_res.value(); } +void FindRamdiskInMemory(MultibootInfo &multiboot_info, MemoryManagers &mms) +{ + auto &pmm = mms.pmm; + + auto ramdisk_module_res = multiboot_info.FindTag([](TagModule *tag) { + return strcmp(tag->cmdline, kInitrdModuleCmdline) == 0; + }); + ASSERT_TRUE(ramdisk_module_res, "Failed to find the ramdisk module"); + const TagModule *ramdisk_tag = ramdisk_module_res.value(); + + const size_t ramdisk_size = ramdisk_tag->mod_end - ramdisk_tag->mod_start; + TRACE_DEBUG( + "Ramdisk located at 0x%llX - 0x%llX (size: %sB)", ramdisk_tag->mod_start, + ramdisk_tag->mod_end, FormatMetricUint(ramdisk_size) + ); + pmm.Reserve(PhysicalPtr(ramdisk_tag->mod_start), ramdisk_size); + + gKernelInitialParams.ramdisk_start = ramdisk_tag->mod_start; + gKernelInitialParams.ramdisk_end = ramdisk_tag->mod_end; +} + static void EstablishDirectMemMapping(MemoryManagers &mms) { auto &vmm = mms.vmm; @@ -175,15 +196,15 @@ static void EstablishDirectMemMapping(MemoryManagers &mms) ); } -NO_RET static void TransitionToKernel( - u64 kernel_entry_point, const TransitionData *transition_data, - const KernelModuleInfo &kernel_info, MemoryManagers mem_managers +static void PrepareKernelArgs( + const TransitionData *transition_data, const KernelModuleInfo &kernel_info, + MemoryManagers mem_managers, MultibootInfo &multiboot_info ) { auto &pmm = mem_managers.pmm; auto &vmm = mem_managers.vmm; - TRACE_INFO("Preparing to transition to kernel..."); + TRACE_INFO("Preparing kernel arguments..."); // Prepare parameters for the kernel gKernelInitialParams.kernel_start_addr = kernel_info.lower_bound; @@ -196,6 +217,91 @@ NO_RET static void TransitionToKernel( gKernelInitialParams.mem_info_total_pages = pmm.GetTotalPages(); gKernelInitialParams.pml_4_table_phys_addr = vmm.GetPml4Table().Value(); + // Framebuffer + auto fb_tag_res = multiboot_info.FindTag(); + if (fb_tag_res) { + const auto *fb_tag = fb_tag_res.value(); + bool is_rgb = fb_tag->framebuffer_type == TagFramebufferCommon::kFramebufferTypeRgb; + bool is_32bpp = fb_tag->framebuffer_bpp == 32; + + if (is_rgb && is_32bpp) { + gKernelInitialParams.fb_addr = fb_tag->framebuffer_addr; + gKernelInitialParams.fb_width = fb_tag->framebuffer_width; + gKernelInitialParams.fb_height = fb_tag->framebuffer_height; + gKernelInitialParams.fb_pitch = fb_tag->framebuffer_pitch; + gKernelInitialParams.fb_bpp = fb_tag->framebuffer_bpp; + + gKernelInitialParams.fb_red_pos = fb_tag->framebuffer_red_field_position; + gKernelInitialParams.fb_red_mask = fb_tag->framebuffer_red_mask_size; + gKernelInitialParams.fb_green_pos = fb_tag->framebuffer_green_field_position; + gKernelInitialParams.fb_green_mask = fb_tag->framebuffer_green_mask_size; + gKernelInitialParams.fb_blue_pos = fb_tag->framebuffer_blue_field_position; + gKernelInitialParams.fb_blue_mask = fb_tag->framebuffer_blue_mask_size; + + TRACE_INFO( + "Framebuffer found: addr=0x%llX, res=%dx%d, bpp=%d", gKernelInitialParams.fb_addr, + gKernelInitialParams.fb_width, gKernelInitialParams.fb_height, + gKernelInitialParams.fb_bpp + ); + } else { + TRACE_WARNING( + "Framebuffer found but not RGB 32-bit (type=%d, bpp=%d). Ignoring.", + fb_tag->framebuffer_type, fb_tag->framebuffer_bpp + ); + gKernelInitialParams.fb_addr = 0; + gKernelInitialParams.fb_width = 0; + gKernelInitialParams.fb_height = 0; + gKernelInitialParams.fb_pitch = 0; + gKernelInitialParams.fb_bpp = 0; + } + } else { + TRACE_WARNING( + "No framebuffer tag found in multiboot info, framebuffer will not be available" + ); + gKernelInitialParams.fb_addr = 0; + gKernelInitialParams.fb_width = 0; + gKernelInitialParams.fb_height = 0; + gKernelInitialParams.fb_pitch = 0; + gKernelInitialParams.fb_bpp = 0; + } + + // Ramdisk + if constexpr (FeatureEnabled) { + FindRamdiskInMemory(multiboot_info, mem_managers); + } else { + TRACE_INFO("Ramdisk feature disabled, skipping ramdisk setup"); + gKernelInitialParams.ramdisk_start = 0; + gKernelInitialParams.ramdisk_end = 0; + } + + // ACPI + auto acpi_new_tag_res = multiboot_info.FindTag(); + if (acpi_new_tag_res) { + const auto *tag = acpi_new_tag_res.value(); + gKernelInitialParams.acpi_rsdp_phys_addr = reinterpret_cast(tag->rsdp); + TRACE_INFO("ACPI RSDP (v2) found at: 0x%llX", gKernelInitialParams.acpi_rsdp_phys_addr); + } else { + auto acpi_old_tag_res = multiboot_info.FindTag(); + if (acpi_old_tag_res) { + const auto *tag = acpi_old_tag_res.value(); + gKernelInitialParams.acpi_rsdp_phys_addr = reinterpret_cast(tag->rsdp); + TRACE_INFO("ACPI RSDP (v1) found at: 0x%llX", gKernelInitialParams.acpi_rsdp_phys_addr); + } else { + TRACE_WARNING("No ACPI RSDP tag found!"); + gKernelInitialParams.acpi_rsdp_phys_addr = 0; + } + } +} + +NO_RET static void TransitionToKernel( + u64 kernel_entry_point, const TransitionData *transition_data, + const KernelModuleInfo &kernel_info, MemoryManagers mem_managers +) +{ + auto &pmm = mem_managers.pmm; + + TRACE_INFO("Preparing to transition to kernel..."); + const u64 ld_start_addr = reinterpret_cast(loader_64_start); const u64 ld_end_addr = reinterpret_cast(loader_64_end); const u64 al_ld_start_addr = AlignDown(ld_start_addr, PageSize()); @@ -207,17 +313,37 @@ NO_RET static void TransitionToKernel( " Kernel Arguments:\n" " kernel_start_addr: 0x%llX\n" " kernel_end_addr: 0x%llX\n" + " ramdisk_start_addr 0x%llX\n" + " ramdisk_end_addr: 0x%llX\n" " pml_4_table_phys_addr: 0x%llX\n" " mem_info_bitmap_addr: 0x%llX\n" " mem_info_total_pages: %llu\n" " multiboot_info_addr: 0x%llX\n" " multiboot_header_start_addr: 0x%llX\n" - " multiboot_header_end_addr: 0x%llX\n", + " multiboot_header_end_addr: 0x%llX\n" + " Framebuffer Arguments:\n" + " fb_addr: 0x%llX\n" + " fb_width: %u\n" + " fb_height: %u\n" + " fb_pitch: %u\n" + " fb_bpp: %u\n" + " fb_red_pos: %hhu\n" + " fb_red_mask: %hhu\n" + " fb_green_pos: %hhu\n" + " fb_green_mask: %hhu\n" + " fb_blue_pos: %hhu\n" + " fb_blue_mask: %hhu\n", gKernelInitialParams.kernel_start_addr, gKernelInitialParams.kernel_end_addr, + gKernelInitialParams.ramdisk_start, gKernelInitialParams.ramdisk_end, gKernelInitialParams.pml_4_table_phys_addr, gKernelInitialParams.mem_info_bitmap_addr, gKernelInitialParams.mem_info_total_pages, gKernelInitialParams.multiboot_info_addr, gKernelInitialParams.multiboot_header_start_addr, - gKernelInitialParams.multiboot_header_end_addr + gKernelInitialParams.multiboot_header_end_addr, gKernelInitialParams.fb_addr, + gKernelInitialParams.fb_width, gKernelInitialParams.fb_height, + gKernelInitialParams.fb_pitch, gKernelInitialParams.fb_bpp, gKernelInitialParams.fb_red_pos, + gKernelInitialParams.fb_red_mask, gKernelInitialParams.fb_green_pos, + gKernelInitialParams.fb_green_mask, gKernelInitialParams.fb_blue_pos, + gKernelInitialParams.fb_blue_mask ); TRACE_INFO("Jumping to kernel at entry point: 0x%llX", kernel_entry_point); @@ -240,5 +366,7 @@ extern "C" void MainLoader64(TransitionData *transition_data) EstablishDirectMemMapping(mms); + PrepareKernelArgs(transition_data, kernel_info, mms, multiboot_info); + TransitionToKernel(kernel_entry_point, transition_data, kernel_info, mms); } diff --git a/kernel/arch/x86_64/boot/settings/settings.hpp b/kernel/arch/x86_64/boot/settings/settings.hpp index 2011bc54..e6cdd806 100644 --- a/kernel/arch/x86_64/boot/settings/settings.hpp +++ b/kernel/arch/x86_64/boot/settings/settings.hpp @@ -1,8 +1,8 @@ #ifndef KERNEL_ARCH_X86_64_BOOT_SETTINGS_SETTINGS_HPP_ #define KERNEL_ARCH_X86_64_BOOT_SETTINGS_SETTINGS_HPP_ +#include #include -#include static constexpr u64 kKernelVirtualAddressStart = kBitMaskLeft; static constexpr u64 kDirectMemMapAddrStart = kBitMaskLeft; @@ -10,5 +10,6 @@ static constexpr u64 kDirectMemMapSizeGb = 512; static constexpr const char *kKernelModuleCmdline = "kernel"; static constexpr const char *kLoader64ModuleCmdline = "loader64"; +static constexpr const char *kInitrdModuleCmdline = "initrd"; #endif // KERNEL_ARCH_X86_64_BOOT_SETTINGS_SETTINGS_HPP_ diff --git a/kernel/arch/x86_64/build/kernel.ld b/kernel/arch/x86_64/build/kernel.ld index ed6d5668..ff19bbdf 100644 --- a/kernel/arch/x86_64/build/kernel.ld +++ b/kernel/arch/x86_64/build/kernel.ld @@ -8,14 +8,14 @@ SECTIONS . = kKernelBase; .init BLOCK(4K) : ALIGN(4K) - { - *(.init) - } - - .fini BLOCK(4K) : ALIGN(4K) - { - *(.fini) - } + { + *(.init) + } + + .fini BLOCK(4K) : ALIGN(4K) + { + *(.fini) + } .text BLOCK(4K) : ALIGN(4K) { diff --git a/kernel/arch/x86_64/src/abi/boot_args.hpp b/kernel/arch/x86_64/src/abi/boot_args.hpp index 9d769143..2d44ff2a 100644 --- a/kernel/arch/x86_64/src/abi/boot_args.hpp +++ b/kernel/arch/x86_64/src/abi/boot_args.hpp @@ -1,8 +1,8 @@ #ifndef KERNEL_ARCH_X86_64_SRC_ABI_BOOT_ARGS_HPP_ #define KERNEL_ARCH_X86_64_SRC_ABI_BOOT_ARGS_HPP_ +#include #include -#include struct alignas(64) RawBootArguments { }; diff --git a/kernel/arch/x86_64/src/cpu/control_registers.hpp b/kernel/arch/x86_64/src/cpu/control_registers.hpp index bb45d7ff..b8843205 100644 --- a/kernel/arch/x86_64/src/cpu/control_registers.hpp +++ b/kernel/arch/x86_64/src/cpu/control_registers.hpp @@ -1,9 +1,9 @@ #ifndef KERNEL_ARCH_X86_64_SRC_CPU_CONTROL_REGISTERS_HPP_ #define KERNEL_ARCH_X86_64_SRC_CPU_CONTROL_REGISTERS_HPP_ +#include #include #include -#include /** * @file control_registers.hpp diff --git a/kernel/arch/x86_64/src/cpu/enable_nxe.nasm b/kernel/arch/x86_64/src/cpu/enable_nxe.nasm new file mode 100644 index 00000000..f3d84779 --- /dev/null +++ b/kernel/arch/x86_64/src/cpu/enable_nxe.nasm @@ -0,0 +1,47 @@ +bits 64 + + %include "startup/panic.nasm" + + ; Extended Feature Enable Register (EFER) + EFER_MSR equ 0xC0000080 + EFER_NXE_BIT equ 1 << 11 + + ; CPUID Extended Processor Info + CPUID_EXT_FUNC equ 0x80000001 + CPUID_NX_BIT equ 1 << 20 ; In EDX + + section .rodata + FAIL_NX db "CPU does not support No-Execute (NX) bit. Halting.", 0 + + section .text + global EnableNXE + +EnableNXE: + push rbx + push rcx + push rdx + + ; Check if CPU supports NX (CPUID 0x80000001, Bit 20 of EDX) + mov eax, 0x80000000 + cpuid + cmp eax, CPUID_EXT_FUNC + jb .no_nx_support ; Extended functions not supported + + mov eax, CPUID_EXT_FUNC + cpuid + test edx, CPUID_NX_BIT + jz .no_nx_support + + ; Enable NXE in EFER MSR + mov ecx, EFER_MSR + rdmsr ; Read EFER into EDX:EAX + bts eax, 11 ; Set bit 11 (NXE) + wrmsr ; Write EFER back + + pop rdx + pop rcx + pop rbx + ret + +.no_nx_support: + panic FAIL_NX diff --git a/kernel/arch/x86_64/src/cpu/gdt.cpp b/kernel/arch/x86_64/src/cpu/gdt.cpp new file mode 100644 index 00000000..3a83045b --- /dev/null +++ b/kernel/arch/x86_64/src/cpu/gdt.cpp @@ -0,0 +1,84 @@ +#include "gdt.hpp" + +#include + +void cpu::DefaultEntryInit( + GdtEntry<> &entry, const AccessByte access, const GdtEntry<>::Flags flags +) +{ + entry.limit = 0xFFFF; + entry.base = 0; + entry.base_mid = 0; + entry.access = access; + entry.limit_high = 0xF; + entry.base_high = 0; + + // Flags + entry.reserved = 0; + entry.long_mode_flag = flags.long_mode_flag; + entry.granularity_flag = flags.granularity_flag; + entry.size_flag = flags.size_flag; +} + +void cpu::DefaultTssEntryInit(GdtSystemSegmentDescriptor &entry, const u64 tss_address) +{ + static constexpr u32 kLimit = sizeof(TSS) - 1; + + // encode limit + entry.low.limit = kLimit & kBitMask16; + entry.low.limit_high = (kLimit >> 16) & kBitMask4; + + // encode base + entry.low.base = tss_address & kBitMask16; + entry.low.base_mid = (tss_address >> 16) & kBitMask8; + entry.low.base_high = (tss_address >> 24) & kBitMask8; + entry.base_upper32 = (tss_address >> 32) & kBitMask32; + + // setup access + entry.low.access.present_bit = SystemSegmentAccessByte::PresentBit::kPresent; + entry.low.access.type_bit = SystemSegmentAccessByte::DescriptorTypeBit::kSystemSegment; + entry.low.access.dpl_bits = SystemSegmentAccessByte::DescriptorPrivilegeLevel::kKernel; + entry.low.access.type = static_cast(SystemSegmentAccessByte::LongModeTypes::kTSS); + + entry.low.reserved = 0; + entry.reserved = 0; +} + +void cpu::DefaultGdtInit(GDT &gdt, const u64 tss_address) +{ + AccessByte access_kernel_code{}; + access_kernel_code.present_bit = AccessByte::PresentBit::kPresent; + access_kernel_code.executable_bit = AccessByte::ExecutableBit::kExecutable; + access_kernel_code.type_bit = AccessByte::DescriptorTypeBit::kUsualSegment; + access_kernel_code.dpl_bit = AccessByte::DescriptorPrivilegeLevel::kKernel; + GdtEntry<>::Flags flags{}; + flags.long_mode_flag = GdtEntry<>::LongModeFlag::kLongModeEnabled; + + DefaultEntryInit(gdt.kernel_code, access_kernel_code, flags); + + AccessByte access_kernel_data{}; + access_kernel_data.present_bit = AccessByte::PresentBit::kPresent; + access_kernel_data.type_bit = AccessByte::DescriptorTypeBit::kUsualSegment; + access_kernel_data.rw_bit = AccessByte::RWBit::kAllowed; + access_kernel_data.dpl_bit = AccessByte::DescriptorPrivilegeLevel::kKernel; + + DefaultEntryInit(gdt.kernel_data, access_kernel_data, {}); + + AccessByte access_user_code{}; + access_user_code.present_bit = AccessByte::PresentBit::kPresent; + access_user_code.executable_bit = AccessByte::ExecutableBit::kExecutable; + access_user_code.type_bit = AccessByte::DescriptorTypeBit::kUsualSegment; + access_user_code.dpl_bit = AccessByte::DescriptorPrivilegeLevel::kUser; + + DefaultEntryInit(gdt.user_code, access_user_code, flags); + + AccessByte access_user_data{}; + access_user_data.present_bit = AccessByte::PresentBit::kPresent; + access_user_data.type_bit = AccessByte::DescriptorTypeBit::kUsualSegment; + access_user_data.rw_bit = AccessByte::RWBit::kAllowed; + access_user_data.dpl_bit = AccessByte::DescriptorPrivilegeLevel::kUser; + + DefaultEntryInit(gdt.user_data, access_user_data, {}); + + DefaultTssEntryInit(gdt.tss_descriptor, tss_address); +} diff --git a/kernel/arch/x86_64/src/cpu/gdt.hpp b/kernel/arch/x86_64/src/cpu/gdt.hpp new file mode 100644 index 00000000..560acda9 --- /dev/null +++ b/kernel/arch/x86_64/src/cpu/gdt.hpp @@ -0,0 +1,175 @@ +#ifndef KERNEL_ARCH_X86_64_SRC_CPU_GDT_HPP_ +#define KERNEL_ARCH_X86_64_SRC_CPU_GDT_HPP_ + +#include +#include +#include + +#include "tss.hpp" + +namespace cpu +{ +struct PACK AccessByte { + enum class AccessedBit : u8 { + kNotAccessed = 0, + kAccessed = 1, + }; + + enum class RWBit : u8 { + kUnallowed = 0, + kAllowed = 1, + }; + + enum class DirectionBit : u8 { + kUp = 0, + kDown = 1, + }; + + enum class ConformingBit : u8 { + kExecutionOnlyByDPL = 0, + kExecutionByLowerThanDPL = 1, + }; + + enum class ExecutableBit : u8 { + kNonExecutable = 0, + kExecutable = 1, + }; + + enum class DescriptorTypeBit : u8 { + kSystemSegment = 0, + kUsualSegment = 1, + }; + + enum class DescriptorPrivilegeLevel : u8 { + kKernel = 0, + kRing1 = 1, + kRing2 = 2, + kUser = 3, + }; + + enum class PresentBit : u8 { + kPresent = 1, + kNotPresent = 0, + }; + + AccessedBit accessed_bit : 1; + RWBit rw_bit : 1; + u8 dc_bit : 1; + ExecutableBit executable_bit : 1; + DescriptorTypeBit type_bit : 1; + DescriptorPrivilegeLevel dpl_bit : 2; + PresentBit present_bit : 1; +}; +static_assert(sizeof(AccessByte) == 1); + +struct PACK SystemSegmentAccessByte { + enum class DescriptorTypeBit : u8 { + kSystemSegment = 0, + kUsualSegment = 1, + }; + + enum class DescriptorPrivilegeLevel : u8 { + kKernel = 0, + kRing1 = 1, + kRing2 = 2, + kUser = 3, + }; + + enum class PresentBit : u8 { + kPresent = 1, + kNotPresent = 0, + }; + + enum class ProtectedModeTypes : u8 { + kTSS16Bit = 1, + kLDT = 2, + kTSS16BitBusy = 3, + kTSS32Bit = 9, + kTSS32BitBusy = 11, + }; + + enum class LongModeTypes : u8 { + kLDT = 2, + kTSS = 9, + kTSSBusy = 11, + }; + + u8 type : 4; + DescriptorTypeBit type_bit : 1; + DescriptorPrivilegeLevel dpl_bits : 2; + PresentBit present_bit : 1; +}; +static_assert(sizeof(AccessByte) == 1); + +template +struct PACK GdtEntry { + enum class LongModeFlag : u8 { + kLongModeDisabled = 0, + kLongModeEnabled = 1, + }; + + enum class SizeFlag : u8 { + k16BitMode = 0, + k32BitMode = 1, + }; + + enum class GranularityFlag : u8 { + kByteGranularity = 0, + kPageGranularity = 1, + }; + + struct PACK Flags { + u8 reserved : 1; + LongModeFlag long_mode_flag : 1; + SizeFlag size_flag : 1; + GranularityFlag granularity_flag : 1; + }; + + u16 limit; + u16 base; + u8 base_mid; + AccessByteT access; + u8 limit_high : 4; + u8 reserved : 1; + LongModeFlag long_mode_flag : 1; + SizeFlag size_flag : 1; + GranularityFlag granularity_flag : 1; + u8 base_high; +}; +static_assert(sizeof(GdtEntry<>) == 8); +static_assert(sizeof(GdtEntry) == 8); + +struct PACK GdtSystemSegmentDescriptor { + GdtEntry low; + u32 base_upper32; + u32 reserved; +}; +static_assert(sizeof(GdtSystemSegmentDescriptor) == 16); + +struct PACK Gdtr { + u16 limit; + u64 base; +}; + +struct alignas(16) PACK GDT { + static constexpr u16 kKernelCodeSelector = 0x08; + static constexpr u16 kKernelDataSelector = 0x10; + static constexpr u16 kUserCodeSelector = 0x1B; + static constexpr u16 kUserDataSelector = 0x23; + static constexpr u16 kTssSelector = 0x28; + + GdtEntry<> null_entry; + GdtEntry<> kernel_code; + GdtEntry<> kernel_data; + GdtEntry<> user_code; + GdtEntry<> user_data; + GdtSystemSegmentDescriptor tss_descriptor; +}; + +void DefaultEntryInit(GdtEntry<> &entry, AccessByte access, GdtEntry<>::Flags flags); +void DefaultTssEntryInit(GdtSystemSegmentDescriptor &entry, u64 tss_address); +void DefaultGdtInit(GDT &gdt, u64 tss_address); + +} // namespace cpu + +#endif // KERNEL_ARCH_X86_64_SRC_CPU_GDT_HPP_ diff --git a/kernel/arch/x86_64/src/cpu/gdt_flush.nasm b/kernel/arch/x86_64/src/cpu/gdt_flush.nasm new file mode 100644 index 00000000..24de553f --- /dev/null +++ b/kernel/arch/x86_64/src/cpu/gdt_flush.nasm @@ -0,0 +1,32 @@ +bits 64 + +global GdtFlush + +section .text + +GdtFlush: + ; void GdtFlush(cpu::Gdtr* gdtr, u64 kernel_code_offset, u64 kernel_data_offset); + ; Layout: + ; rdi = gdtr pointer + ; rsi = kernel code selector + ; rdx = kernel data selector + ; rax = return address + + lgdt [rdi] ; load new gdt + + ; load data segments + mov ds, dx + mov es, dx + mov fs, dx + mov gs, dx + mov ss, dx + + ; load code segments + push rsi + lea rax, [rel .next] ; push next label address on the stack to return nicely after far jump + push rax + + retfq + +.next: + ret diff --git a/kernel/arch/x86_64/src/cpu/msrs.hpp b/kernel/arch/x86_64/src/cpu/msrs.hpp index 4b5a4c7f..089ce15d 100644 --- a/kernel/arch/x86_64/src/cpu/msrs.hpp +++ b/kernel/arch/x86_64/src/cpu/msrs.hpp @@ -1,7 +1,9 @@ #ifndef KERNEL_ARCH_X86_64_SRC_CPU_MSRS_HPP_ #define KERNEL_ARCH_X86_64_SRC_CPU_MSRS_HPP_ -#include +#include + +#include namespace cpu { diff --git a/kernel/arch/x86_64/src/cpu/tss.hpp b/kernel/arch/x86_64/src/cpu/tss.hpp new file mode 100644 index 00000000..d181ffa4 --- /dev/null +++ b/kernel/arch/x86_64/src/cpu/tss.hpp @@ -0,0 +1,25 @@ +#ifndef KERNEL_ARCH_X86_64_SRC_CPU_TSS_HPP_ +#define KERNEL_ARCH_X86_64_SRC_CPU_TSS_HPP_ + +#include +#include + +namespace cpu +{ +struct PACK TSS { + u32 reserved0; + u64 rsp0; + u64 rsp1; + u64 rsp2; + u64 reserved1; + u64 ist[7]; + u64 reserved2; + u16 reserved3; + u16 iopb_offset; +}; + +FAST_CALL void LoadTss(u16 selector) { __asm__ volatile("ltr %0" : : "r"(selector) : "memory"); } + +} // namespace cpu + +#endif // KERNEL_ARCH_X86_64_SRC_CPU_TSS_HPP_ diff --git a/kernel/arch/x86_64/src/cpu/utils.cpp b/kernel/arch/x86_64/src/cpu/utils.cpp index df0eed6f..ba744baa 100644 --- a/kernel/arch/x86_64/src/cpu/utils.cpp +++ b/kernel/arch/x86_64/src/cpu/utils.cpp @@ -1,74 +1,26 @@ #include "cpu/utils.hpp" +#include "trace_framework.hpp" -#include -#include -#include - -/** - * @brief Capture current CPU register state - * - * @return CpuState structure containing current register values - */ -CpuState DumpCpuState() -{ - CpuState cpu_state{}; - - __asm__ volatile("movq %%rax, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kRax])); - __asm__ volatile("movq %%rbx, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kRbx])); - __asm__ volatile("movq %%rcx, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kRcx])); - __asm__ volatile("movq %%rdx, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kRdx])); - __asm__ volatile("movq %%rsi, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kRsi])); - __asm__ volatile("movq %%rdi, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kRdi])); - __asm__ volatile("movq %%rbp, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kRbp])); - __asm__ volatile("movq %%rsp, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kRsp])); - __asm__ volatile("movq %%r8, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kR8])); - __asm__ volatile("movq %%r9, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kR9])); - __asm__ volatile("movq %%r10, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kR10])); - __asm__ volatile("movq %%r11, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kR11])); - __asm__ volatile("movq %%r12, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kR12])); - __asm__ volatile("movq %%r13, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kR13])); - __asm__ volatile("movq %%r14, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kR14])); - __asm__ volatile("movq %%r15, %0" : "=m"(cpu_state.general_purpose_registers[CpuState::kR15])); - - return cpu_state; -} - -/** - * Simply formats the CPU state into a human-readable string. - * - * @param buff - buffer to write to - * @param buff_size - size of buffer - */ -void CpuState::GetStateDesc(char *buff, const size_t buff_size) const +void TraceDumpedRegisters(const DumpedRegisters *regs) { - static constexpr const char *kRegNames[]{"rax", "rbx", "rcx", "rdx", "rsi", "rdi", - "rbp", "rsp", "r8", "r9", "r10", "r11", - "r12", "r13", "r14", "r15"}; + static constexpr const char *kRegNames[] = {"rax", "rbx", "rcx", "rdx", "rsi", "rdi", + "rbp", "rsp", "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", "rip", "rflags", + "cr0", "cr2", "cr3", "cr4"}; + static constexpr size_t kBuffSize = 1024; + char buff[kBuffSize]; size_t offset = 0; - for (int i = 0; i < kGprLast && offset < buff_size; ++i) { - const int written = snprintf( - buff + offset, buff_size - offset, "%s: 0x%016llx\n", kRegNames[i], - general_purpose_registers[i] + for (size_t i = 0; i < regs->flat.size() && offset < kBuffSize; ++i) { + int written = snprintf( + buff + offset, kBuffSize - offset, "%s: 0x%016llx\n", kRegNames[i], + static_cast(regs->flat[i]) ); - + ASSERT_GT(written, 0); + ASSERT_LT(written + offset, kBuffSize); offset += written; - ASSERT_NEQ(offset, buff_size); } -} - -/** - * @brief Print formatted dump of CPU register state - * - * Outputs current values of all general-purpose registers - * to the terminal in a human-readable format. - */ -void CpuState::DumpStateDesc() const -{ - static constexpr size_t kSizeBuff = 2048; - char buff[kSizeBuff]; - GetStateDesc(buff, kSizeBuff); - hal::TerminalWriteString(buff); + TRACE_INFO_GENERAL("Dumped registers:\n%s", buff); } diff --git a/kernel/arch/x86_64/src/cpu/utils.hpp b/kernel/arch/x86_64/src/cpu/utils.hpp index 85f48ef1..4a658e9d 100644 --- a/kernel/arch/x86_64/src/cpu/utils.hpp +++ b/kernel/arch/x86_64/src/cpu/utils.hpp @@ -1,9 +1,11 @@ #ifndef KERNEL_ARCH_X86_64_SRC_CPU_UTILS_HPP_ #define KERNEL_ARCH_X86_64_SRC_CPU_UTILS_HPP_ -#include -#include -#include "include/io.hpp" +#include +#include +#include