From dec3c3b0387ec477125db21e741bc492d3475db5 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 22 Apr 2026 09:32:22 +0200 Subject: multiboot2: rearrange project structure --- libs/multiboot2/CMakeLists.txt | 2 +- libs/multiboot2/include/multiboot2/constants.hpp | 15 - .../multiboot2/constants/architecture_id.hpp | 22 -- .../multiboot2/constants/information_id.hpp | 86 ------ .../include/multiboot2/constants/memory_type.hpp | 33 --- .../include/multiboot2/constants/tag_id.hpp | 29 -- libs/multiboot2/include/multiboot2/information.hpp | 308 --------------------- .../include/multiboot2/information/data.hpp | 184 ------------ .../include/multiboot2/information/iterator.hpp | 73 ----- .../include/multiboot2/information/tag.hpp | 206 -------------- libs/multiboot2/multiboot2/constants.hpp | 15 + .../multiboot2/constants/architecture_id.hpp | 22 ++ .../multiboot2/constants/information_id.hpp | 86 ++++++ .../multiboot2/constants/memory_type.hpp | 33 +++ libs/multiboot2/multiboot2/constants/tag_id.hpp | 29 ++ libs/multiboot2/multiboot2/information.hpp | 308 +++++++++++++++++++++ libs/multiboot2/multiboot2/information/data.hpp | 184 ++++++++++++ .../multiboot2/multiboot2/information/iterator.hpp | 73 +++++ libs/multiboot2/multiboot2/information/tag.hpp | 206 ++++++++++++++ 19 files changed, 957 insertions(+), 957 deletions(-) delete mode 100644 libs/multiboot2/include/multiboot2/constants.hpp delete mode 100644 libs/multiboot2/include/multiboot2/constants/architecture_id.hpp delete mode 100644 libs/multiboot2/include/multiboot2/constants/information_id.hpp delete mode 100644 libs/multiboot2/include/multiboot2/constants/memory_type.hpp delete mode 100644 libs/multiboot2/include/multiboot2/constants/tag_id.hpp delete mode 100644 libs/multiboot2/include/multiboot2/information.hpp delete mode 100644 libs/multiboot2/include/multiboot2/information/data.hpp delete mode 100644 libs/multiboot2/include/multiboot2/information/iterator.hpp delete mode 100644 libs/multiboot2/include/multiboot2/information/tag.hpp create mode 100644 libs/multiboot2/multiboot2/constants.hpp create mode 100644 libs/multiboot2/multiboot2/constants/architecture_id.hpp create mode 100644 libs/multiboot2/multiboot2/constants/information_id.hpp create mode 100644 libs/multiboot2/multiboot2/constants/memory_type.hpp create mode 100644 libs/multiboot2/multiboot2/constants/tag_id.hpp create mode 100644 libs/multiboot2/multiboot2/information.hpp create mode 100644 libs/multiboot2/multiboot2/information/data.hpp create mode 100644 libs/multiboot2/multiboot2/information/iterator.hpp create mode 100644 libs/multiboot2/multiboot2/information/tag.hpp (limited to 'libs') diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt index b56b0ba..da5fb53 100644 --- a/libs/multiboot2/CMakeLists.txt +++ b/libs/multiboot2/CMakeLists.txt @@ -50,7 +50,7 @@ target_sources("multiboot2" INTERFACE ) target_include_directories("multiboot2" INTERFACE - "include" + "${CMAKE_CURRENT_SOURCE_DIR}" ) target_link_libraries("multiboot2" INTERFACE diff --git a/libs/multiboot2/include/multiboot2/constants.hpp b/libs/multiboot2/include/multiboot2/constants.hpp deleted file mode 100644 index 2198210..0000000 --- a/libs/multiboot2/include/multiboot2/constants.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef MULTIBOOT2_CONSTANTS_HPP -#define MULTIBOOT2_CONSTANTS_HPP - -#include "constants/architecture_id.hpp" // IWYU pragma: export - -#include - -namespace multiboot2 -{ - - constexpr auto inline header_magic = std::uint32_t{0xe852'50d6}; - -} // namespace multiboot2 - -#endif diff --git a/libs/multiboot2/include/multiboot2/constants/architecture_id.hpp b/libs/multiboot2/include/multiboot2/constants/architecture_id.hpp deleted file mode 100644 index e13c471..0000000 --- a/libs/multiboot2/include/multiboot2/constants/architecture_id.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MULTIBOOT2_CONSTANTS_ARCHITECTURE_ID_HPP -#define MULTIBOOT2_CONSTANTS_ARCHITECTURE_ID_HPP - -// IWYU pragma: private, include - -#include - -namespace multiboot2 -{ - - //! The IDs of the supported system architectures. - enum struct architecture_id : std::uint32_t - { - //! 32-bit protected mode i386 - i386 = 0, - //! 32-bit MIPS - mips32 = 4, - }; - -} // namespace multiboot2 - -#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/constants/information_id.hpp b/libs/multiboot2/include/multiboot2/constants/information_id.hpp deleted file mode 100644 index 27c5300..0000000 --- a/libs/multiboot2/include/multiboot2/constants/information_id.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef MULTIBOOT2_CONSTANTS_INFORMATION_ID_HPP -#define MULTIBOOT2_CONSTANTS_INFORMATION_ID_HPP - -// IWYU pragma: private, include - -#include - -namespace multiboot2 -{ - - //! The IDs of all Multiboot2 information tags. - //! - //! Each tag provided by the boot loader will be tagged with one of these IDs. A tags data format can thus be deduced - //! from it's ID. - enum struct information_id : std::uint32_t - { - //! Signals final tag for the multiboot2 information structure. - end, - - //! The command line string. - command_line, - - //! The name of the boot loader booting the kernel. - boot_loader_name, - - //! Indicates the boot module which was loaded along the kernel image. - module, - - //! The amount of lower and upper (above 1 MiB) memory. - basic_memory_information, - - //! Indicates which BIOS disk device the hoot loader has loaded the OS image from. - boot_device, - - //! Describes the memory layout of the system with individual areas and their flags. - memory_map, - - //! Includes information to access and utilize the device GPU. - vbe_information, - - //! VBE framebuffer information. - framebuferr_information, - - //! Includes list of all section headers from the loaded ELF kernel. - elf_sections, - - //! Advanced Power Management information. - apm_information, - - //! The pointer to the EFI 32 bit system table. - efi32_system_table_pointer, - - //! The pointer to the EFI 64 bit system table. - efi64_system_table_pointer, - - //! A copy of all System Management BIOS tables. - smbios_tables, - - //! A copy of RSDP as defined per ACPI 1.0 specification. - acpi_rsdp, - - //! A copy of XSDP as defined per ACPI 2.0 or later specification. - acpi_xsdp, - - //! The network information specified specified as per DHCP. - networking_information, - - //! The memory map as provided by the EFI. - efi_memory_map, - - //! Indicates ExitBootServices wasn't called. - boot_services_not_terminated, - - //! EFI 32 bit image handle pointer. - efi32_image_handle_pointer, - - //! EFI 64 bit image handle pointer. - efi64_image_handle_pointer, - - //! The physical image load base address. - image_load_base_address - }; - -} // namespace multiboot2 - -#endif diff --git a/libs/multiboot2/include/multiboot2/constants/memory_type.hpp b/libs/multiboot2/include/multiboot2/constants/memory_type.hpp deleted file mode 100644 index 6be94bd..0000000 --- a/libs/multiboot2/include/multiboot2/constants/memory_type.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef MULTIBOOT2_CONSTANTS_MEMORY_TYPE_HPP -#define MULTIBOOT2_CONSTANTS_MEMORY_TYPE_HPP - -// IWYU pragma: private, include - -#include - -namespace multiboot2 -{ - - //! The types of memory potentially present in the detailed memory map. - enum struct memory_type : std::uint32_t - { - //! The memory is available for general use by the operating system. - available = 1, - - //! The memory is reserved for firmware or other purposes and must not be used for general purposes by the operating - //! system. - reserved, - - //! The memory contains ACPI data and can be reclaimed when ACPI is not in use. - acpi_reclaimable, - - //! The memory is reserved for non-volatile storage. - non_volatile_storage, - - //! The memory range is occupied by defective RAM. - bad_ram, - }; - -} // namespace multiboot2 - -#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/constants/tag_id.hpp b/libs/multiboot2/include/multiboot2/constants/tag_id.hpp deleted file mode 100644 index 23d39cc..0000000 --- a/libs/multiboot2/include/multiboot2/constants/tag_id.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MULTIBOOT2_CONSTANTS_TAG_ID_HPP -#define MULTIBOOT2_CONSTANTS_TAG_ID_HPP - -// IWYU pragma: private, include - -#include - -namespace multiboot2 -{ - - //! The IDs for tags to be used in the image header. - 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_image, - }; - -} // namespace multiboot2 - -#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/information.hpp b/libs/multiboot2/include/multiboot2/information.hpp deleted file mode 100644 index a2ded56..0000000 --- a/libs/multiboot2/include/multiboot2/information.hpp +++ /dev/null @@ -1,308 +0,0 @@ -#ifndef MULTIBOOT2_INFORMATION_HPP -#define MULTIBOOT2_INFORMATION_HPP - -#include "information/data.hpp" // IWYU pragma: export -#include "information/iterator.hpp" // IWYU pragma: export -#include "information/tag.hpp" // IWYU pragma: export - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace multiboot2 -{ - - /** - * @copydoc multiboot2::data::basic_memory - */ - struct basic_memory : tag - { - using tag::tag; - }; - - /** - * @copydoc multiboot2::data::bios_boot_device - */ - struct bios_boot_device : tag - { - using tag::tag; - }; - - /** - * @copydoc multiboot2::data::command_line - */ - struct command_line : vla_tag - { - using vla_tag::vla_tag; - - /** - * @brief The command line string - */ - [[nodiscard]] auto string() const noexcept -> range_type - { - return {data(), size()}; - } - }; - - /** - * @copydoc multiboot2::data::elf_symbols - */ - template - struct elf_symbols : vla_tag const, std::span> - { - using base = vla_tag const, std::span>; - using base::base; - - [[nodiscard]] auto name(elf::section_header const & section) const noexcept -> std::string_view - { - if (!this->string_table_index) - { - std::abort(); - } - - auto string_table = this->begin()[this->string_table_index]; - auto name_offset = section.name_offset; - auto name_array = std::bit_cast(string_table.virtual_load_address); - return name_array + name_offset; - } - }; - - /** - * @copydoc multiboot2::data::loader_name - */ - struct loader_name : vla_tag - { - using vla_tag::vla_tag; - - /** - * @brief The name of the bootloader - */ - [[nodiscard]] auto string() const noexcept -> std::string_view - { - return {data(), size()}; - } - }; - - /** - * @copydoc multiboot2::data::memory_map - */ - struct memory_map : vla_tag - { - using vla_tag::vla_tag; - - /** - * @brief The available memory regions - */ - [[nodiscard]] auto regions() const noexcept -> range_type - { - return {data(), size()}; - } - }; - - /** - * @copydoc multiboot2::data::module - */ - struct module : vla_tag - { - using vla_tag::vla_tag; - - /** - * @brief The module command line or name. - */ - [[nodiscard]] auto string() const noexcept -> std::string_view - { - return {data(), vla_tag::size()}; - } - - [[nodiscard]] constexpr auto size() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{end_address - start_address}; - } - }; - - struct acpi_rsdp : vla_tag - { - using vla_tag::vla_tag; - - [[nodiscard]] auto pointer() const noexcept -> range_type - { - return {data(), size()}; - } - }; - - struct acpi_xsdp : vla_tag - { - using vla_tag::vla_tag; - - [[nodiscard]] auto pointer() const noexcept -> range_type - { - return {data(), size()}; - } - }; - - struct information_view - { - using iterator = iterator; - using value_type = iterator::value_type; - using pointer = iterator::pointer; - using reference = iterator::reference; - - [[nodiscard]] auto size() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{m_size}; - } - - // Range access - - [[nodiscard]] auto begin() const noexcept -> iterator - { - return iterator{&m_tags}; - } - - [[nodiscard]] auto end() const noexcept -> iterator - { - return iterator{}; - } - - // Tag access - - template - [[nodiscard]] auto has() const noexcept -> bool - { - return get().has_value(); - } - - [[nodiscard]] auto maybe_basic_memory() const noexcept -> std::optional - { - return get(); - } - - [[nodiscard]] auto basic_memory() const -> basic_memory - { - return maybe_basic_memory().value(); - } - - [[nodiscard]] auto maybe_bios_boot_device() const noexcept -> std::optional - { - return get(); - } - - [[nodiscard]] auto bios_boot_device() const -> bios_boot_device - { - return maybe_bios_boot_device().value(); - } - - [[nodiscard]] auto maybe_command_line() const noexcept -> std::optional - { - return get(); - } - - [[nodiscard]] auto command_line() const -> command_line - { - return maybe_command_line().value(); - } - - template - [[nodiscard]] auto maybe_elf_symbols() const noexcept -> std::optional> - { - return get>().and_then( - [](auto x) -> std::optional> { - if (x.entry_size_in_B == elf::section_header_size) - { - return std::optional{x}; - } - else - { - return std::nullopt; - } - }); - } - - template - [[nodiscard]] auto elf_symbols() const -> elf_symbols - { - return maybe_elf_symbols().value(); - } - - [[nodiscard]] auto maybe_loader_name() const noexcept -> std::optional - { - return get(); - } - - [[nodiscard]] auto loader_name() const -> loader_name - { - return maybe_loader_name().value(); - } - - [[nodiscard]] auto maybe_memory_map() const noexcept -> std::optional - { - return get(); - } - - [[nodiscard]] auto memory_map() const -> memory_map - { - return maybe_memory_map().value(); - } - - [[nodiscard]] auto modules() const noexcept - { - auto filter_modules = [](auto const & tag) { - return tag.information_id() == module::id; - }; - auto transform_module = [](auto const & tag) { - return module{&tag}; - }; - return std::ranges::subrange(begin(), end()) | std::views::filter(filter_modules) | - std::views::transform(transform_module); - } - - [[nodiscard]] auto maybe_acpi_rsdp() const noexcept -> std::optional - { - return get(); - } - - [[nodiscard]] auto acpi_rsdp() const noexcept -> acpi_rsdp - { - return maybe_acpi_rsdp().value(); - } - - [[nodiscard]] auto maybe_acpi_xsdp() const noexcept -> std::optional - { - return get(); - } - - [[nodiscard]] auto acpi_xsdp() const noexcept -> acpi_xsdp - { - return maybe_acpi_xsdp().value(); - } - - private: - template - [[nodiscard]] constexpr auto get() const noexcept -> std::optional - { - if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); - found != end()) - { - return Tag{&*found}; - } - return std::nullopt; - } - - uint32_t m_size{}; - uint32_t : 32; - tag_header m_tags{}; - }; - -} // namespace multiboot2 - -#endif diff --git a/libs/multiboot2/include/multiboot2/information/data.hpp b/libs/multiboot2/include/multiboot2/information/data.hpp deleted file mode 100644 index 315eb39..0000000 --- a/libs/multiboot2/include/multiboot2/information/data.hpp +++ /dev/null @@ -1,184 +0,0 @@ -#ifndef MULTIBOOT2_INFORMATION_DATA_HPP -#define MULTIBOOT2_INFORMATION_DATA_HPP - -// IWYU pragma: private, include - -#include "multiboot2/constants/information_id.hpp" -#include "multiboot2/constants/memory_type.hpp" - -#include - -#include - -namespace multiboot2 -{ - //! A simple base mixin providing all data classes with an ID accessor. - template - struct tag_data - { - //! The ID of this data class. - constexpr auto static inline id = Id; - }; - - namespace data - { - - //! Basic system memory information - //! - //! This tag contains the amount of lower memory and upper memory present in the system as detected by the boot - //! loader. - struct basic_memory : tag_data - { - [[nodiscard]] constexpr auto lower() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{lower_KiB * 1024}; - } - - [[nodiscard]] constexpr auto upper() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{upper_KiB * 1024}; - } - - //! The amount of lower memory available to the system. - //! - //! Any memory below the 1 MiB address boundary is considered to be lower memory. The maximum possible value for - //! this field is 640 KiB. - std::uint32_t lower_KiB; - - //! The amount of upper memory available to the system. - //! - //! Any memory above the 1 MiB address boundary is considered to be upper memory. The maximum possible value for - //! this field is the address of the first upper memory hole minus 1MiB. - std::uint32_t upper_KiB; - }; - - //! The BIOS disk the image got loaded from - //! - //! This tag is present iff. the image was loaded from a BIOS disk device. - struct bios_boot_device : tag_data - { - //! BIOS device number the image was loaded from, as understood by INT 13h. - //! - //! For example, the first floppy drive will receive id 0x00, while the first hard disk will receive id 0x80. - std::uint32_t device_number; - - //! The partition number of the primary partition the image was loaded from. - std::uint32_t partition_number; - - //! The sub-partition number of the primary partition the image was loaded from. - std::uint32_t sub_partition_number; - }; - - //! The command line supplied to the image during boot. - //! - //! @note This structure is intentionally left blank, since it is of variable size and the contained information - //! starts at the first byte of this structure. - struct command_line : tag_data - { - }; - - //! The ELF sections of the image. - //! - //! @note The actual section header array is not part of this type's definition. The reason being that the size of - //! the array, in terms of entry count, as well as the size and format of each array element is unknown at compile - //! time. The array begins after the last member of this structure. - struct elf_symbols : tag_data - { - [[nodiscard]] constexpr auto entry_size() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{entry_size_in_B}; - } - - //! The number of section header table entries. - std::uint32_t count; - - //! The size of each section header table entry. - std::uint32_t entry_size_in_B; - - //! The section number of the string table containing the section names. - std::uint32_t string_table_index; - }; - - //! The name of the boot loader that loaded the image. - //! - //! @note This structure is intentionally left blank, since it is of variable size and the contained information - //! starts at the first byte of this structure. - struct loader_name : tag_data - { - }; - - //! The detailed memory map of this system. - struct memory_map : tag_data - { - //! A single region of memory - struct region - { - //! Check if the memory described by this region is available for use. - [[nodiscard]] constexpr auto available() const noexcept - { - return type == memory_type::available; - } - - [[nodiscard]] constexpr auto size() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{size_in_B}; - } - - //! The physical start address of this region - std::uint64_t base; - - //! The size of this region in bytes. - std::uint64_t size_in_B; - - //! The type of this region. - //! - //! @see multiboot::memory_types - memory_type type; - - //! This field is reserved for padding and use in future extensions. - std::uint32_t : 0; - }; - - [[nodiscard]] constexpr auto entry_size() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{entry_size_in_B}; - } - - //! The size of each entry present in the map. - //! - //! This field is present to allow for future extension of the entry format. Each entry's size is guaranteed to - //! always be an integer multiple of 8. - std::uint32_t entry_size_in_B; - - //! The version of each entry present in the map - std::uint32_t entry_version; - }; - - //! A module loaded by the bootloader. - //! - //! @note the command line associated with this module is not part of this structure, since it is of variable size - //! and the contained information starts at the end of this structure. - struct module : tag_data - { - //! The physical start address of this module. - std::uint32_t start_address; - - //! The physical end address of this module. - std::uint32_t end_address; - }; - - //! A copy of the ACPI RSDP - struct acpi_rsdp : tag_data - { - }; - - //! A copy of the ACPI XSDP - struct acpi_xsdp : tag_data - { - }; - - } // namespace data - -} // namespace multiboot2 - -#endif diff --git a/libs/multiboot2/include/multiboot2/information/iterator.hpp b/libs/multiboot2/include/multiboot2/information/iterator.hpp deleted file mode 100644 index 62c267d..0000000 --- a/libs/multiboot2/include/multiboot2/information/iterator.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef MULTIBOOT2_INFORMATION_ITERATOR_HPP -#define MULTIBOOT2_INFORMATION_ITERATOR_HPP - -// IWYU pragma: private, include - -#include "multiboot2/constants/information_id.hpp" -#include "tag.hpp" - -#include -#include -#include - -namespace multiboot2 -{ - - struct iterator - { - using iterator_category = std::forward_iterator_tag; - using value_type = tag_header; - using pointer = value_type const *; - using reference = value_type const &; - using difference_type = std::ptrdiff_t; - - constexpr iterator() = default; - - constexpr explicit iterator(tag_header const * offset) - : m_current(offset) - {} - - constexpr auto operator==(iterator const &) const noexcept -> bool = default; - - constexpr auto operator*() const noexcept -> reference - { - return *(m_current.value()); - } - - constexpr auto operator->() const noexcept -> pointer - { - return m_current.value(); - } - - constexpr auto operator++() noexcept -> iterator & - { - if (m_current) - { - if (auto next = m_current.value()->next(); next->information_id() != information_id::end) - { - m_current = next; - } - else - { - m_current.reset(); - } - } - return *this; - } - - constexpr auto operator++(int) noexcept -> iterator - { - auto copy = *this; - ++(*this); - return copy; - } - - private: - std::optional m_current{}; - }; - - static_assert(std::input_or_output_iterator); - -} // namespace multiboot2 - -#endif \ No newline at end of file diff --git a/libs/multiboot2/include/multiboot2/information/tag.hpp b/libs/multiboot2/include/multiboot2/information/tag.hpp deleted file mode 100644 index 8d90790..0000000 --- a/libs/multiboot2/include/multiboot2/information/tag.hpp +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef MULTIBOOT2_INFORMATION_TAG_HPP -#define MULTIBOOT2_INFORMATION_TAG_HPP - -// IWYU pragma: private, include - -#include "multiboot2/constants/information_id.hpp" - -#include -#include -#include -#include - -namespace multiboot2 -{ - - /** - * @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} - {} - - [[nodiscard]] auto full_size() const noexcept -> std::size_t - { - return (m_size + 7) & (~7); - } - - [[nodiscard]] auto information_id() const noexcept -> information_id const & - { - return m_id; - } - - [[nodiscard]] auto next() const noexcept -> tag_header const * - { - return std::bit_cast(std::bit_cast(this) + full_size()); - } - - [[nodiscard]] auto unaligned_size() const noexcept -> std::uint32_t - { - return m_size; - } - - private: - enum information_id m_id; - std::uint32_t m_size; - }; - - /** - * @brief A tag containing no variable length array data. - */ - template - 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(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 Range> - struct vla_tag : tag - { - using range_type = Range; - - using value_type = range_type::value_type; - using reference = range_type::const_reference; - using const_reference = range_type::const_reference; - using pointer = range_type::const_pointer; - using const_pointer = range_type::const_pointer; - - using iterator = range_type::const_iterator; - using const_iterator = range_type::const_iterator; - using reverse_iterator = range_type::const_reverse_iterator; - using const_reverse_iterator = range_type::const_reverse_iterator; - using size_type = range_type::size_type; - using difference_type = range_type::difference_type; - - vla_tag() - : tag{} - , m_vla{} - {} - - explicit vla_tag(tag_header const * header) - : tag{header} - , m_vla{vla_start(header), vla_size(header)} - {} - - [[nodiscard]] auto begin() const noexcept -> const_iterator - { - return m_vla.begin(); - } - - [[nodiscard]] auto end() const noexcept -> const_iterator - { - return m_vla.end(); - } - - [[nodiscard]] auto cbegin() const noexcept -> const_iterator - { - return begin(); - } - - [[nodiscard]] auto cend() const noexcept -> const_iterator - { - return end(); - } - - [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator - { - return m_vla.rbegin(); - } - - [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator - { - return m_vla.rend(); - } - - [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator - { - return rbegin(); - } - - [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator - { - return rend(); - } - - [[nodiscard]] auto front() const noexcept -> const_reference - { - return m_vla.front(); - } - - [[nodiscard]] auto back() const noexcept -> const_reference - { - return m_vla.back(); - } - - [[nodiscard]] auto size() const noexcept -> std::size_t - { - return m_vla.size(); - } - - [[nodiscard]] auto empty() const noexcept -> bool - { - return m_vla.empty(); - } - - [[nodiscard]] auto data() const noexcept -> const_pointer - { - return m_vla.data(); - } - - [[nodiscard]] auto at(std::size_t index) const -> const_reference - { - return m_vla.at(index); - } - - [[nodiscard]] auto operator[](std::size_t index) const noexcept -> const_reference - { - return m_vla[index]; - } - - private: - auto static vla_start(tag_header const * header) noexcept -> VlaData * - { - auto raw = std::bit_cast(header); - auto start = raw + sizeof(tag); - return std::bit_cast(start); - } - - auto static vla_size(tag_header const * header) noexcept -> std::size_t - { - auto size = (header->unaligned_size() - sizeof(tag) - - std::is_same_v> * 1) / - sizeof(VlaData); - return size; - } - - range_type m_vla; - }; - -} // namespace multiboot2 - -#endif \ No newline at end of file diff --git a/libs/multiboot2/multiboot2/constants.hpp b/libs/multiboot2/multiboot2/constants.hpp new file mode 100644 index 0000000..2198210 --- /dev/null +++ b/libs/multiboot2/multiboot2/constants.hpp @@ -0,0 +1,15 @@ +#ifndef MULTIBOOT2_CONSTANTS_HPP +#define MULTIBOOT2_CONSTANTS_HPP + +#include "constants/architecture_id.hpp" // IWYU pragma: export + +#include + +namespace multiboot2 +{ + + constexpr auto inline header_magic = std::uint32_t{0xe852'50d6}; + +} // namespace multiboot2 + +#endif diff --git a/libs/multiboot2/multiboot2/constants/architecture_id.hpp b/libs/multiboot2/multiboot2/constants/architecture_id.hpp new file mode 100644 index 0000000..e13c471 --- /dev/null +++ b/libs/multiboot2/multiboot2/constants/architecture_id.hpp @@ -0,0 +1,22 @@ +#ifndef MULTIBOOT2_CONSTANTS_ARCHITECTURE_ID_HPP +#define MULTIBOOT2_CONSTANTS_ARCHITECTURE_ID_HPP + +// IWYU pragma: private, include + +#include + +namespace multiboot2 +{ + + //! The IDs of the supported system architectures. + enum struct architecture_id : std::uint32_t + { + //! 32-bit protected mode i386 + i386 = 0, + //! 32-bit MIPS + mips32 = 4, + }; + +} // namespace multiboot2 + +#endif \ No newline at end of file diff --git a/libs/multiboot2/multiboot2/constants/information_id.hpp b/libs/multiboot2/multiboot2/constants/information_id.hpp new file mode 100644 index 0000000..27c5300 --- /dev/null +++ b/libs/multiboot2/multiboot2/constants/information_id.hpp @@ -0,0 +1,86 @@ +#ifndef MULTIBOOT2_CONSTANTS_INFORMATION_ID_HPP +#define MULTIBOOT2_CONSTANTS_INFORMATION_ID_HPP + +// IWYU pragma: private, include + +#include + +namespace multiboot2 +{ + + //! The IDs of all Multiboot2 information tags. + //! + //! Each tag provided by the boot loader will be tagged with one of these IDs. A tags data format can thus be deduced + //! from it's ID. + enum struct information_id : std::uint32_t + { + //! Signals final tag for the multiboot2 information structure. + end, + + //! The command line string. + command_line, + + //! The name of the boot loader booting the kernel. + boot_loader_name, + + //! Indicates the boot module which was loaded along the kernel image. + module, + + //! The amount of lower and upper (above 1 MiB) memory. + basic_memory_information, + + //! Indicates which BIOS disk device the hoot loader has loaded the OS image from. + boot_device, + + //! Describes the memory layout of the system with individual areas and their flags. + memory_map, + + //! Includes information to access and utilize the device GPU. + vbe_information, + + //! VBE framebuffer information. + framebuferr_information, + + //! Includes list of all section headers from the loaded ELF kernel. + elf_sections, + + //! Advanced Power Management information. + apm_information, + + //! The pointer to the EFI 32 bit system table. + efi32_system_table_pointer, + + //! The pointer to the EFI 64 bit system table. + efi64_system_table_pointer, + + //! A copy of all System Management BIOS tables. + smbios_tables, + + //! A copy of RSDP as defined per ACPI 1.0 specification. + acpi_rsdp, + + //! A copy of XSDP as defined per ACPI 2.0 or later specification. + acpi_xsdp, + + //! The network information specified specified as per DHCP. + networking_information, + + //! The memory map as provided by the EFI. + efi_memory_map, + + //! Indicates ExitBootServices wasn't called. + boot_services_not_terminated, + + //! EFI 32 bit image handle pointer. + efi32_image_handle_pointer, + + //! EFI 64 bit image handle pointer. + efi64_image_handle_pointer, + + //! The physical image load base address. + image_load_base_address + }; + +} // namespace multiboot2 + +#endif diff --git a/libs/multiboot2/multiboot2/constants/memory_type.hpp b/libs/multiboot2/multiboot2/constants/memory_type.hpp new file mode 100644 index 0000000..6be94bd --- /dev/null +++ b/libs/multiboot2/multiboot2/constants/memory_type.hpp @@ -0,0 +1,33 @@ +#ifndef MULTIBOOT2_CONSTANTS_MEMORY_TYPE_HPP +#define MULTIBOOT2_CONSTANTS_MEMORY_TYPE_HPP + +// IWYU pragma: private, include + +#include + +namespace multiboot2 +{ + + //! The types of memory potentially present in the detailed memory map. + enum struct memory_type : std::uint32_t + { + //! The memory is available for general use by the operating system. + available = 1, + + //! The memory is reserved for firmware or other purposes and must not be used for general purposes by the operating + //! system. + reserved, + + //! The memory contains ACPI data and can be reclaimed when ACPI is not in use. + acpi_reclaimable, + + //! The memory is reserved for non-volatile storage. + non_volatile_storage, + + //! The memory range is occupied by defective RAM. + bad_ram, + }; + +} // namespace multiboot2 + +#endif \ No newline at end of file diff --git a/libs/multiboot2/multiboot2/constants/tag_id.hpp b/libs/multiboot2/multiboot2/constants/tag_id.hpp new file mode 100644 index 0000000..23d39cc --- /dev/null +++ b/libs/multiboot2/multiboot2/constants/tag_id.hpp @@ -0,0 +1,29 @@ +#ifndef MULTIBOOT2_CONSTANTS_TAG_ID_HPP +#define MULTIBOOT2_CONSTANTS_TAG_ID_HPP + +// IWYU pragma: private, include + +#include + +namespace multiboot2 +{ + + //! The IDs for tags to be used in the image header. + 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_image, + }; + +} // namespace multiboot2 + +#endif \ No newline at end of file diff --git a/libs/multiboot2/multiboot2/information.hpp b/libs/multiboot2/multiboot2/information.hpp new file mode 100644 index 0000000..a2ded56 --- /dev/null +++ b/libs/multiboot2/multiboot2/information.hpp @@ -0,0 +1,308 @@ +#ifndef MULTIBOOT2_INFORMATION_HPP +#define MULTIBOOT2_INFORMATION_HPP + +#include "information/data.hpp" // IWYU pragma: export +#include "information/iterator.hpp" // IWYU pragma: export +#include "information/tag.hpp" // IWYU pragma: export + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace multiboot2 +{ + + /** + * @copydoc multiboot2::data::basic_memory + */ + struct basic_memory : tag + { + using tag::tag; + }; + + /** + * @copydoc multiboot2::data::bios_boot_device + */ + struct bios_boot_device : tag + { + using tag::tag; + }; + + /** + * @copydoc multiboot2::data::command_line + */ + struct command_line : vla_tag + { + using vla_tag::vla_tag; + + /** + * @brief The command line string + */ + [[nodiscard]] auto string() const noexcept -> range_type + { + return {data(), size()}; + } + }; + + /** + * @copydoc multiboot2::data::elf_symbols + */ + template + struct elf_symbols : vla_tag const, std::span> + { + using base = vla_tag const, std::span>; + using base::base; + + [[nodiscard]] auto name(elf::section_header const & section) const noexcept -> std::string_view + { + if (!this->string_table_index) + { + std::abort(); + } + + auto string_table = this->begin()[this->string_table_index]; + auto name_offset = section.name_offset; + auto name_array = std::bit_cast(string_table.virtual_load_address); + return name_array + name_offset; + } + }; + + /** + * @copydoc multiboot2::data::loader_name + */ + struct loader_name : vla_tag + { + using vla_tag::vla_tag; + + /** + * @brief The name of the bootloader + */ + [[nodiscard]] auto string() const noexcept -> std::string_view + { + return {data(), size()}; + } + }; + + /** + * @copydoc multiboot2::data::memory_map + */ + struct memory_map : vla_tag + { + using vla_tag::vla_tag; + + /** + * @brief The available memory regions + */ + [[nodiscard]] auto regions() const noexcept -> range_type + { + return {data(), size()}; + } + }; + + /** + * @copydoc multiboot2::data::module + */ + struct module : vla_tag + { + using vla_tag::vla_tag; + + /** + * @brief The module command line or name. + */ + [[nodiscard]] auto string() const noexcept -> std::string_view + { + return {data(), vla_tag::size()}; + } + + [[nodiscard]] constexpr auto size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{end_address - start_address}; + } + }; + + struct acpi_rsdp : vla_tag + { + using vla_tag::vla_tag; + + [[nodiscard]] auto pointer() const noexcept -> range_type + { + return {data(), size()}; + } + }; + + struct acpi_xsdp : vla_tag + { + using vla_tag::vla_tag; + + [[nodiscard]] auto pointer() const noexcept -> range_type + { + return {data(), size()}; + } + }; + + struct information_view + { + using iterator = iterator; + using value_type = iterator::value_type; + using pointer = iterator::pointer; + using reference = iterator::reference; + + [[nodiscard]] auto size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{m_size}; + } + + // Range access + + [[nodiscard]] auto begin() const noexcept -> iterator + { + return iterator{&m_tags}; + } + + [[nodiscard]] auto end() const noexcept -> iterator + { + return iterator{}; + } + + // Tag access + + template + [[nodiscard]] auto has() const noexcept -> bool + { + return get().has_value(); + } + + [[nodiscard]] auto maybe_basic_memory() const noexcept -> std::optional + { + return get(); + } + + [[nodiscard]] auto basic_memory() const -> basic_memory + { + return maybe_basic_memory().value(); + } + + [[nodiscard]] auto maybe_bios_boot_device() const noexcept -> std::optional + { + return get(); + } + + [[nodiscard]] auto bios_boot_device() const -> bios_boot_device + { + return maybe_bios_boot_device().value(); + } + + [[nodiscard]] auto maybe_command_line() const noexcept -> std::optional + { + return get(); + } + + [[nodiscard]] auto command_line() const -> command_line + { + return maybe_command_line().value(); + } + + template + [[nodiscard]] auto maybe_elf_symbols() const noexcept -> std::optional> + { + return get>().and_then( + [](auto x) -> std::optional> { + if (x.entry_size_in_B == elf::section_header_size) + { + return std::optional{x}; + } + else + { + return std::nullopt; + } + }); + } + + template + [[nodiscard]] auto elf_symbols() const -> elf_symbols + { + return maybe_elf_symbols().value(); + } + + [[nodiscard]] auto maybe_loader_name() const noexcept -> std::optional + { + return get(); + } + + [[nodiscard]] auto loader_name() const -> loader_name + { + return maybe_loader_name().value(); + } + + [[nodiscard]] auto maybe_memory_map() const noexcept -> std::optional + { + return get(); + } + + [[nodiscard]] auto memory_map() const -> memory_map + { + return maybe_memory_map().value(); + } + + [[nodiscard]] auto modules() const noexcept + { + auto filter_modules = [](auto const & tag) { + return tag.information_id() == module::id; + }; + auto transform_module = [](auto const & tag) { + return module{&tag}; + }; + return std::ranges::subrange(begin(), end()) | std::views::filter(filter_modules) | + std::views::transform(transform_module); + } + + [[nodiscard]] auto maybe_acpi_rsdp() const noexcept -> std::optional + { + return get(); + } + + [[nodiscard]] auto acpi_rsdp() const noexcept -> acpi_rsdp + { + return maybe_acpi_rsdp().value(); + } + + [[nodiscard]] auto maybe_acpi_xsdp() const noexcept -> std::optional + { + return get(); + } + + [[nodiscard]] auto acpi_xsdp() const noexcept -> acpi_xsdp + { + return maybe_acpi_xsdp().value(); + } + + private: + template + [[nodiscard]] constexpr auto get() const noexcept -> std::optional + { + if (auto found = std::ranges::find_if(*this, [](auto tag) { return tag.information_id() == Tag::id; }); + found != end()) + { + return Tag{&*found}; + } + return std::nullopt; + } + + uint32_t m_size{}; + uint32_t : 32; + tag_header m_tags{}; + }; + +} // namespace multiboot2 + +#endif diff --git a/libs/multiboot2/multiboot2/information/data.hpp b/libs/multiboot2/multiboot2/information/data.hpp new file mode 100644 index 0000000..315eb39 --- /dev/null +++ b/libs/multiboot2/multiboot2/information/data.hpp @@ -0,0 +1,184 @@ +#ifndef MULTIBOOT2_INFORMATION_DATA_HPP +#define MULTIBOOT2_INFORMATION_DATA_HPP + +// IWYU pragma: private, include + +#include "multiboot2/constants/information_id.hpp" +#include "multiboot2/constants/memory_type.hpp" + +#include + +#include + +namespace multiboot2 +{ + //! A simple base mixin providing all data classes with an ID accessor. + template + struct tag_data + { + //! The ID of this data class. + constexpr auto static inline id = Id; + }; + + namespace data + { + + //! Basic system memory information + //! + //! This tag contains the amount of lower memory and upper memory present in the system as detected by the boot + //! loader. + struct basic_memory : tag_data + { + [[nodiscard]] constexpr auto lower() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{lower_KiB * 1024}; + } + + [[nodiscard]] constexpr auto upper() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{upper_KiB * 1024}; + } + + //! The amount of lower memory available to the system. + //! + //! Any memory below the 1 MiB address boundary is considered to be lower memory. The maximum possible value for + //! this field is 640 KiB. + std::uint32_t lower_KiB; + + //! The amount of upper memory available to the system. + //! + //! Any memory above the 1 MiB address boundary is considered to be upper memory. The maximum possible value for + //! this field is the address of the first upper memory hole minus 1MiB. + std::uint32_t upper_KiB; + }; + + //! The BIOS disk the image got loaded from + //! + //! This tag is present iff. the image was loaded from a BIOS disk device. + struct bios_boot_device : tag_data + { + //! BIOS device number the image was loaded from, as understood by INT 13h. + //! + //! For example, the first floppy drive will receive id 0x00, while the first hard disk will receive id 0x80. + std::uint32_t device_number; + + //! The partition number of the primary partition the image was loaded from. + std::uint32_t partition_number; + + //! The sub-partition number of the primary partition the image was loaded from. + std::uint32_t sub_partition_number; + }; + + //! The command line supplied to the image during boot. + //! + //! @note This structure is intentionally left blank, since it is of variable size and the contained information + //! starts at the first byte of this structure. + struct command_line : tag_data + { + }; + + //! The ELF sections of the image. + //! + //! @note The actual section header array is not part of this type's definition. The reason being that the size of + //! the array, in terms of entry count, as well as the size and format of each array element is unknown at compile + //! time. The array begins after the last member of this structure. + struct elf_symbols : tag_data + { + [[nodiscard]] constexpr auto entry_size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{entry_size_in_B}; + } + + //! The number of section header table entries. + std::uint32_t count; + + //! The size of each section header table entry. + std::uint32_t entry_size_in_B; + + //! The section number of the string table containing the section names. + std::uint32_t string_table_index; + }; + + //! The name of the boot loader that loaded the image. + //! + //! @note This structure is intentionally left blank, since it is of variable size and the contained information + //! starts at the first byte of this structure. + struct loader_name : tag_data + { + }; + + //! The detailed memory map of this system. + struct memory_map : tag_data + { + //! A single region of memory + struct region + { + //! Check if the memory described by this region is available for use. + [[nodiscard]] constexpr auto available() const noexcept + { + return type == memory_type::available; + } + + [[nodiscard]] constexpr auto size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{size_in_B}; + } + + //! The physical start address of this region + std::uint64_t base; + + //! The size of this region in bytes. + std::uint64_t size_in_B; + + //! The type of this region. + //! + //! @see multiboot::memory_types + memory_type type; + + //! This field is reserved for padding and use in future extensions. + std::uint32_t : 0; + }; + + [[nodiscard]] constexpr auto entry_size() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{entry_size_in_B}; + } + + //! The size of each entry present in the map. + //! + //! This field is present to allow for future extension of the entry format. Each entry's size is guaranteed to + //! always be an integer multiple of 8. + std::uint32_t entry_size_in_B; + + //! The version of each entry present in the map + std::uint32_t entry_version; + }; + + //! A module loaded by the bootloader. + //! + //! @note the command line associated with this module is not part of this structure, since it is of variable size + //! and the contained information starts at the end of this structure. + struct module : tag_data + { + //! The physical start address of this module. + std::uint32_t start_address; + + //! The physical end address of this module. + std::uint32_t end_address; + }; + + //! A copy of the ACPI RSDP + struct acpi_rsdp : tag_data + { + }; + + //! A copy of the ACPI XSDP + struct acpi_xsdp : tag_data + { + }; + + } // namespace data + +} // namespace multiboot2 + +#endif diff --git a/libs/multiboot2/multiboot2/information/iterator.hpp b/libs/multiboot2/multiboot2/information/iterator.hpp new file mode 100644 index 0000000..62c267d --- /dev/null +++ b/libs/multiboot2/multiboot2/information/iterator.hpp @@ -0,0 +1,73 @@ +#ifndef MULTIBOOT2_INFORMATION_ITERATOR_HPP +#define MULTIBOOT2_INFORMATION_ITERATOR_HPP + +// IWYU pragma: private, include + +#include "multiboot2/constants/information_id.hpp" +#include "tag.hpp" + +#include +#include +#include + +namespace multiboot2 +{ + + struct iterator + { + using iterator_category = std::forward_iterator_tag; + using value_type = tag_header; + using pointer = value_type const *; + using reference = value_type const &; + using difference_type = std::ptrdiff_t; + + constexpr iterator() = default; + + constexpr explicit iterator(tag_header const * offset) + : m_current(offset) + {} + + constexpr auto operator==(iterator const &) const noexcept -> bool = default; + + constexpr auto operator*() const noexcept -> reference + { + return *(m_current.value()); + } + + constexpr auto operator->() const noexcept -> pointer + { + return m_current.value(); + } + + constexpr auto operator++() noexcept -> iterator & + { + if (m_current) + { + if (auto next = m_current.value()->next(); next->information_id() != information_id::end) + { + m_current = next; + } + else + { + m_current.reset(); + } + } + return *this; + } + + constexpr auto operator++(int) noexcept -> iterator + { + auto copy = *this; + ++(*this); + return copy; + } + + private: + std::optional m_current{}; + }; + + static_assert(std::input_or_output_iterator); + +} // namespace multiboot2 + +#endif \ No newline at end of file diff --git a/libs/multiboot2/multiboot2/information/tag.hpp b/libs/multiboot2/multiboot2/information/tag.hpp new file mode 100644 index 0000000..8d90790 --- /dev/null +++ b/libs/multiboot2/multiboot2/information/tag.hpp @@ -0,0 +1,206 @@ +#ifndef MULTIBOOT2_INFORMATION_TAG_HPP +#define MULTIBOOT2_INFORMATION_TAG_HPP + +// IWYU pragma: private, include + +#include "multiboot2/constants/information_id.hpp" + +#include +#include +#include +#include + +namespace multiboot2 +{ + + /** + * @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} + {} + + [[nodiscard]] auto full_size() const noexcept -> std::size_t + { + return (m_size + 7) & (~7); + } + + [[nodiscard]] auto information_id() const noexcept -> information_id const & + { + return m_id; + } + + [[nodiscard]] auto next() const noexcept -> tag_header const * + { + return std::bit_cast(std::bit_cast(this) + full_size()); + } + + [[nodiscard]] auto unaligned_size() const noexcept -> std::uint32_t + { + return m_size; + } + + private: + enum information_id m_id; + std::uint32_t m_size; + }; + + /** + * @brief A tag containing no variable length array data. + */ + template + 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(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 Range> + struct vla_tag : tag + { + using range_type = Range; + + using value_type = range_type::value_type; + using reference = range_type::const_reference; + using const_reference = range_type::const_reference; + using pointer = range_type::const_pointer; + using const_pointer = range_type::const_pointer; + + using iterator = range_type::const_iterator; + using const_iterator = range_type::const_iterator; + using reverse_iterator = range_type::const_reverse_iterator; + using const_reverse_iterator = range_type::const_reverse_iterator; + using size_type = range_type::size_type; + using difference_type = range_type::difference_type; + + vla_tag() + : tag{} + , m_vla{} + {} + + explicit vla_tag(tag_header const * header) + : tag{header} + , m_vla{vla_start(header), vla_size(header)} + {} + + [[nodiscard]] auto begin() const noexcept -> const_iterator + { + return m_vla.begin(); + } + + [[nodiscard]] auto end() const noexcept -> const_iterator + { + return m_vla.end(); + } + + [[nodiscard]] auto cbegin() const noexcept -> const_iterator + { + return begin(); + } + + [[nodiscard]] auto cend() const noexcept -> const_iterator + { + return end(); + } + + [[nodiscard]] auto rbegin() const noexcept -> const_reverse_iterator + { + return m_vla.rbegin(); + } + + [[nodiscard]] auto rend() const noexcept -> const_reverse_iterator + { + return m_vla.rend(); + } + + [[nodiscard]] auto crbegin() const noexcept -> const_reverse_iterator + { + return rbegin(); + } + + [[nodiscard]] auto crend() const noexcept -> const_reverse_iterator + { + return rend(); + } + + [[nodiscard]] auto front() const noexcept -> const_reference + { + return m_vla.front(); + } + + [[nodiscard]] auto back() const noexcept -> const_reference + { + return m_vla.back(); + } + + [[nodiscard]] auto size() const noexcept -> std::size_t + { + return m_vla.size(); + } + + [[nodiscard]] auto empty() const noexcept -> bool + { + return m_vla.empty(); + } + + [[nodiscard]] auto data() const noexcept -> const_pointer + { + return m_vla.data(); + } + + [[nodiscard]] auto at(std::size_t index) const -> const_reference + { + return m_vla.at(index); + } + + [[nodiscard]] auto operator[](std::size_t index) const noexcept -> const_reference + { + return m_vla[index]; + } + + private: + auto static vla_start(tag_header const * header) noexcept -> VlaData * + { + auto raw = std::bit_cast(header); + auto start = raw + sizeof(tag); + return std::bit_cast(start); + } + + auto static vla_size(tag_header const * header) noexcept -> std::size_t + { + auto size = (header->unaligned_size() - sizeof(tag) - + std::is_same_v> * 1) / + sizeof(VlaData); + return size; + } + + range_type m_vla; + }; + +} // namespace multiboot2 + +#endif \ No newline at end of file -- cgit v1.2.3