diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-07-14 15:21:32 +0000 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-07-14 15:21:32 +0000 |
| commit | 22fbbf849497c32f5b237ab70e9ed8aef63e54cf (patch) | |
| tree | ce44e8cd25661f2818181bdbe3f0668d3c6e0837 /libs/multiboot2 | |
| parent | 9bfd5652e865505ae73f5ae3ba70f384d7418e84 (diff) | |
| download | teachos-22fbbf849497c32f5b237ab70e9ed8aef63e54cf.tar.xz teachos-22fbbf849497c32f5b237ab70e9ed8aef63e54cf.zip | |
libs: extract multiboot library
Diffstat (limited to 'libs/multiboot2')
| -rw-r--r-- | libs/multiboot2/CMakeLists.txt | 26 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/constants.hpp | 20 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/data.hpp | 130 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/ids.hpp | 79 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/iterator.hpp | 63 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/tag.hpp | 113 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/information.hpp | 160 |
7 files changed, 591 insertions, 0 deletions
diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt new file mode 100644 index 0000000..af56d5a --- /dev/null +++ b/libs/multiboot2/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION "3.27") + +project("multiboot2" + LANGUAGES CXX + VERSION "1.0.0" +) + +add_library("multiboot2" INTERFACE) +add_library("multiboot2::multiboot2" ALIAS "multiboot2") + +target_sources("multiboot2" INTERFACE + FILE_SET HEADERS + BASE_DIRS "include" + FILES + "include/multiboot2/constants.hpp" + "include/multiboot2/information.hpp" + + "include/multiboot2/impl/data.hpp" + "include/multiboot2/impl/ids.hpp" + "include/multiboot2/impl/iterator.hpp" + "include/multiboot2/impl/tag.hpp" +) + +target_include_directories("multiboot2" INTERFACE + "include" +) diff --git a/libs/multiboot2/include/multiboot2/constants.hpp b/libs/multiboot2/include/multiboot2/constants.hpp new file mode 100644 index 0000000..30d52d0 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/constants.hpp @@ -0,0 +1,20 @@ +#ifndef MULTIBOOT2_CONSTANTS_HPP +#define MULTIBOOT2_CONSTANTS_HPP + +#include "impl/ids.hpp" // IWYU pragma: export + +#include <cstdint> + +namespace multiboot2 +{ + + using impl::architecture_id; + using impl::information_id; + using impl::memory_type; + using impl::tag_id; + + auto constexpr inline header_magic = std::uint32_t{0xe85250d6}; + +} // namespace multiboot2 + +#endif diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp new file mode 100644 index 0000000..367e8cb --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -0,0 +1,130 @@ +#ifndef MULTIBOOT2_IMPL_DATA_HPP +#define MULTIBOOT2_IMPL_DATA_HPP + +#include "multiboot2/impl/ids.hpp" + +#include <cstdint> + +namespace multiboot2::impl +{ + template<auto Id> + struct tag_data + { + auto constexpr inline static id = Id; + }; + + /** + * @brief Basic system memory information + */ + struct basic_memory_data : tag_data<information_id::BASIC_MEMORY_INFO> + { + /** + * @brief Amount of lower memory (below 1MiB) available to the system. + * + * The maximum possible value for this field is 640 KiB. + */ + std::uint32_t const lower_KiB; + + /** + * @brief Amount of upper memory (above 1MiB) available to the system. + * + * The maximum possible value for this field is the address of the first upper memory hole minus 1MiB. + */ + std::uint32_t const upper_KiB; + }; + + /** + * @brief Device the image got loaded from + */ + struct bios_boot_device_data : tag_data<information_id::BOOTDEV> + { + /** + * @brief BIOS device number as understood by INT 13h. + */ + std::uint32_t device_number; + + /** + * @brief Number of the primary partition. + */ + std::uint32_t partition_number; + + /** + * @brief Number the sub-partion on the primary partition. + */ + std::uint32_t sub_partition_number; + }; + + /** + * @brief Supplied image command line + */ + struct command_line_data : tag_data<information_id::CMDLINE> + { + /* This struct intentionally left blank. */ + }; + + /** + * @brief ELF symbols of the image + */ + struct elf_symbols_data : tag_data<information_id::ELF_SECTIONS> + { + std::uint32_t count; + std::uint32_t entry_size; + std::uint32_t string_table_index; + }; + + /** + * @brief Name of the boot loader + */ + struct loader_name_data : tag_data<information_id::BOOT_LOADER_NAME> + { + /* This struct intentionally left blank. */ + }; + + /** + * @brief Detailed map of the memory regions present in the system + * + */ + struct memory_map_data : tag_data<information_id::MEMORY_MAP> + { + /** + * @brief A region of memory + */ + struct region + { + /** + * @brief Check if the memory described by this region is available for use. + */ + auto constexpr available() const noexcept { return type == memory_type::AVAILABLE; } + + /** + * @brief Start address of this region + */ + std::uint64_t const base; + + /** + * @brief Size of this region in bytes. + */ + std::uint64_t const size_in_B; + + /** + * @brief Type of this region. + */ + memory_type const type; + + std::uint32_t : 0; + }; + + /** + * @brief Size of each entry present in the map + */ + std::uint32_t const entry_size; + + /** + * @brief Version of each entry present in the map + */ + std::uint32_t const entry_version; + }; + +} // namespace multiboot2::impl + +#endif
\ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/impl/ids.hpp b/libs/multiboot2/include/multiboot2/impl/ids.hpp new file mode 100644 index 0000000..3a7215e --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/ids.hpp @@ -0,0 +1,79 @@ +#ifndef MULTIBOOT2_IMPL_IDS_HPP +#define MULTIBOOT2_IMPL_IDS_HPP + +#include <cstdint> + +namespace multiboot2::impl +{ + + /** + * @brief Information tag IDs. + */ + enum struct information_id : std::uint32_t + { + END, ///< Signals final tag for the multiboot2 information structure. + CMDLINE, ///< Contains the command line string. + BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel. + MODULE, ///< Indicates the boot module which was loaded along the kernel image. + BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address). + BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from. + MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags. + VBE_INFO, ///< Includes information to access and utilize the device GPU. + FRAMEBUFFER, ///< VBE framebuffer information. + ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel. + APM_INFO, ///< Advanced Power Management information. + EFI32, ///< EFI 32 bit system table pointer. + EFI64, ///< EFI 64 bit system table pointer. + SMBIOS, ///< Contains copy of all Sytem Management BIOS tables. + ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification. + ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification. + NETWORK, ///< Contains network information specified specified as DHCP. + EFI_MEMORY_MAP, ///< Contains EFI memory map. + EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called. + EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer. + EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer. + LOAD_BASE_ADDRESS ///< Contains image load base physical address. + }; + + /** + * @brief Header tag IDs. + */ + enum struct tag_id : std::uint32_t + { + END, + INFORMATION_REQUEST, + ADDRESSES, + ENTRY_ADDRESS, + CONSOLE_FLAGS, + PREFERRED_FRAMEBUFFER_MODE, + PAGE_ALIGN_MODULES, + EFI_BOOT_SERVICES_SUPPORTED, + EFI32_ENTRY_ADDRESS, + EFI64_ENTRY_ADDRESS, + RELOCATABLE, + }; + + /** + * @brief System architecture IDs. + */ + enum struct architecture_id : std::uint32_t + { + I386 = 0, + MIPS32 = 4, + }; + + /** + * @brief Memory type IDs. + */ + enum struct memory_type : std::uint32_t + { + AVAILABLE = 1, + RESERVED, + ACPI_RECLAIMABLE, + NON_VOLATILE_STORAGE, + BAD_RAM, + }; + +} // namespace multiboot2::impl + +#endif
\ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp new file mode 100644 index 0000000..b84ef2c --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -0,0 +1,63 @@ +#ifndef MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP +#define MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP + +#include "multiboot2/impl/ids.hpp" +#include "multiboot2/impl/tag.hpp" + +#include <cstddef> +#include <iterator> +#include <optional> + +namespace multiboot2::impl +{ + + struct information_iterator + { + using iterator_category = std::forward_iterator_tag; + using value_type = impl::tag_header; + using pointer = value_type const *; + using reference = value_type const &; + using difference_type = std::ptrdiff_t; + + constexpr information_iterator() = default; + + constexpr explicit information_iterator(impl::tag_header const * offset) + : m_current(offset) + { + } + + auto constexpr operator==(information_iterator const &) const noexcept -> bool = default; + + auto constexpr operator*() const noexcept -> reference { return *(m_current.value()); } + + auto constexpr operator->() const noexcept -> pointer { return m_current.value(); } + + auto constexpr operator++() noexcept -> information_iterator & + { + if (m_current) + { + if (auto next = m_current.value()->next(); next->information_id() != information_id::END) + { + m_current = next; + } + m_current.reset(); + } + return *this; + } + + auto constexpr operator++(int) noexcept -> information_iterator + { + auto copy = *this; + ++(*this); + return copy; + } + + private: + std::optional<impl::tag_header const *> m_current{}; + }; + + static_assert(std::input_or_output_iterator<information_iterator>); + +} // namespace multiboot2::impl + +#endif
\ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/impl/tag.hpp b/libs/multiboot2/include/multiboot2/impl/tag.hpp new file mode 100644 index 0000000..f7471a4 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -0,0 +1,113 @@ +#ifndef MULTIBOOT2_IMPL_TAG_HPP +#define MULTIBOOT2_IMPL_TAG_HPP + +#include "multiboot2/impl/ids.hpp" + +#include <bit> +#include <cstddef> +#include <string_view> + +namespace multiboot2::impl +{ + + /** + * @brief Header data and functionality shared by all tags. + */ + struct tag_header + { + tag_header() + : m_id{} + , m_size{} + { + } + + tag_header(tag_header const * data) + : tag_header{*data} + { + } + + auto full_size() const noexcept -> std::size_t { return (m_size + 7) & (~7); } + + auto information_id() const noexcept -> impl::information_id const & { return m_id; } + + auto next() const noexcept -> tag_header const * + { + return std::bit_cast<tag_header const *>(std::bit_cast<std::byte const *>(this) + full_size()); + } + + auto unaligned_size() const noexcept -> std::uint32_t { return m_size; } + + protected: + impl::information_id const m_id; + std::uint32_t const m_size; + }; + + /** + * @brief A tag containing no variable length array data. + */ + template<typename Data> + struct tag : tag_header, Data + { + tag() + : tag_header{} + , Data{} + { + } + + explicit tag(tag_header const * header) + requires(sizeof(tag) > sizeof(tag_header)) + : tag_header{header} + , Data{*std::bit_cast<Data const *>(header + 1)} + { + } + + explicit tag(tag_header const * header) + requires(sizeof(tag) == sizeof(tag_header)) + : tag_header{header} + , Data{} + { + } + }; + + /** + * @brief A tag containing variable length array data. + */ + template<typename Data, typename VlaData, template<typename> typename Range> + struct vla_tag : tag<Data> + { + using range_type = Range<VlaData>; + + vla_tag() + : tag<Data>{} + , m_vla{} + { + } + + explicit vla_tag(tag_header const * header) + : tag<Data>{header} + , m_vla{vla_start(header), vla_size(header)} + { + } + + protected: + auto static vla_start(tag_header const * header) noexcept -> VlaData * + { + auto raw = std::bit_cast<std::byte const *>(header); + auto start = raw + sizeof(tag<Data>); + return std::bit_cast<VlaData *>(start); + } + + auto static vla_size(tag_header const * header) noexcept -> std::size_t + { + auto size = (header->unaligned_size() - sizeof(tag<Data>) - + std::is_same_v<range_type, std::basic_string_view<VlaData>> * 1) / + sizeof(VlaData); + return size; + } + + range_type const m_vla; + }; + +} // namespace multiboot2::impl + +#endif
\ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp new file mode 100644 index 0000000..04ba183 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -0,0 +1,160 @@ +#ifndef JOS_MULTIBOOT2_INFORMATION_HPP +#define JOS_MULTIBOOT2_INFORMATION_HPP + +#include "impl/data.hpp" +#include "impl/iterator.hpp" +#include "impl/tag.hpp" + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <optional> +#include <span> +#include <string_view> + +namespace multiboot2 +{ + + /** + * @copydoc multiboot2::impl::basic_memory_data + */ + struct basic_memory : impl::tag<impl::basic_memory_data> + { + using tag::tag; + }; + + /** + * @copydoc multiboot2::impl::bios_boot_device_data + */ + struct bios_boot_device : impl::tag<impl::bios_boot_device_data> + { + using tag::tag; + }; + + /** + * @copydoc multiboot2::impl::command_line_data + */ + struct command_line : impl::vla_tag<impl::command_line_data, char, std::basic_string_view> + { + using vla_tag::vla_tag; + + /** + * @brief The command line string + */ + auto string() const noexcept -> range_type { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::elf_symbols_data + */ + struct elf_symbols : impl::vla_tag<impl::elf_symbols_data, std::byte const, std::span> + { + using vla_tag::vla_tag; + + using iterator = range_type::iterator; + + auto data() const noexcept -> range_type { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::loader_name_data + */ + struct loader_name : impl::vla_tag<impl::loader_name_data, char, std::basic_string_view> + { + using vla_tag::vla_tag; + + /** + * @brief The name of the bootloader + */ + auto string() const noexcept -> std::string_view { return m_vla; } + }; + + /** + * @copydoc multiboot2::impl::memory_map_data + */ + struct memory_map : impl::vla_tag<impl::memory_map_data, impl::memory_map_data::region, std::span> + { + using vla_tag::vla_tag; + + using iterator = range_type::iterator; + + auto begin() const noexcept -> iterator { return regions().begin(); } + + auto end() const noexcept -> iterator { return regions().end(); } + + /** + * @brief The available memory regions + */ + auto regions() const noexcept -> range_type { return m_vla; } + }; + + struct information_view + { + using iterator = impl::information_iterator; + using value_type = impl::information_iterator::value_type; + using pointer = impl::information_iterator::pointer; + using reference = impl::information_iterator::reference; + + auto size_bytes() const noexcept -> std::size_t { return m_size; } + + // Range access + + auto begin() const noexcept -> iterator { return iterator{&m_tags}; } + + auto end() const noexcept -> iterator { return iterator{}; } + + // Tag access + + template<typename Tag> + auto has() const noexcept -> bool + { + return get<Tag>().has_value(); + } + + auto maybe_basic_memory() const noexcept -> std::optional<basic_memory> { return get<multiboot2::basic_memory>(); } + + auto basic_memory() const -> basic_memory { return maybe_basic_memory().value(); } + + auto maybe_bios_boot_device() const noexcept -> std::optional<bios_boot_device> + { + return get<multiboot2::bios_boot_device>(); + } + + auto bios_boot_device() const -> bios_boot_device { return maybe_bios_boot_device().value(); } + + auto maybe_command_line() const noexcept -> std::optional<command_line> { return get<multiboot2::command_line>(); } + + auto command_line() const -> command_line { return maybe_command_line().value(); } + + auto maybe_elf_symbols() const noexcept -> std::optional<elf_symbols> { return get<multiboot2::elf_symbols>(); } + + auto elf_symbols() const -> elf_symbols { return maybe_elf_symbols().value(); } + + auto maybe_loader_name() const noexcept -> std::optional<loader_name> { return get<multiboot2::loader_name>(); } + + auto loader_name() const -> loader_name { return maybe_loader_name().value(); } + + auto maybe_memory_map() const noexcept -> std::optional<memory_map> { return get<multiboot2::memory_map>(); } + + auto memory_map() const -> memory_map { return maybe_memory_map().value(); } + + private: + template<typename Tag> + auto constexpr get() const noexcept -> std::optional<Tag> + { + if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); + found != end()) + { + return Tag{&*found}; + } + return std::nullopt; + } + + [[maybe_unused]] uint32_t const m_size{}; + uint32_t : 32; + impl::tag_header const m_tags{}; + }; + +} // namespace multiboot2 + +#endif
\ No newline at end of file |
