diff options
Diffstat (limited to 'libs/multiboot2/include')
| -rw-r--r-- | libs/multiboot2/include/multiboot2/constants.hpp | 20 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/data.hpp | 135 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/ids.hpp | 81 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/iterator.hpp | 73 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/tag.hpp | 207 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/information.hpp | 232 |
6 files changed, 748 insertions, 0 deletions
diff --git a/libs/multiboot2/include/multiboot2/constants.hpp b/libs/multiboot2/include/multiboot2/constants.hpp new file mode 100644 index 0000000..0f6b82f --- /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; + + constexpr auto inline header_magic = std::uint32_t{0xe852'50d6}; + +} // 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..733ce3a --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -0,0 +1,135 @@ +#ifndef MULTIBOOT2_IMPL_DATA_HPP +#define MULTIBOOT2_IMPL_DATA_HPP + +// IWYU pragma: private + +#include "multiboot2/impl/ids.hpp" + +#include <cstdint> + +namespace multiboot2::impl +{ + template<auto Id> + struct tag_data + { + constexpr auto static inline 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 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 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. + */ + [[nodiscard]] constexpr auto available() const noexcept + { + return type == memory_type::AVAILABLE; + } + + /** + * @brief Start address of this region + */ + std::uint64_t base; + + /** + * @brief Size of this region in bytes. + */ + std::uint64_t size_in_B; + + /** + * @brief Type of this region. + */ + memory_type type; + + std::uint32_t : 0; + }; + + /** + * @brief Size of each entry present in the map + */ + std::uint32_t entry_size; + + /** + * @brief Version of each entry present in the map + */ + std::uint32_t 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..98bc1f2 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/ids.hpp @@ -0,0 +1,81 @@ +#ifndef MULTIBOOT2_IMPL_IDS_HPP +#define MULTIBOOT2_IMPL_IDS_HPP + +// IWYU pragma: private + +#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 System 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, ///< Indicates ExitBootServices wasn't called. + EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer. + EFI64_IMAGE_HANDLE, ///< EFI 64 bit image 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..5651f22 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -0,0 +1,73 @@ +#ifndef MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP +#define MULTIBOOT2_IMPL_INFORMATION_ITERATOR_HPP + +// IWYU pragma: private + +#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) + {} + + constexpr auto operator==(information_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 -> information_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 -> 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..3d0cea5 --- /dev/null +++ b/libs/multiboot2/include/multiboot2/impl/tag.hpp @@ -0,0 +1,207 @@ +#ifndef MULTIBOOT2_IMPL_TAG_HPP +#define MULTIBOOT2_IMPL_TAG_HPP + +// IWYU pragma: private + +#include "multiboot2/impl/ids.hpp" + +#include <bit> +#include <cstddef> +#include <cstdint> +#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} + {} + + [[nodiscard]] auto full_size() const noexcept -> std::size_t + { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) + return (m_size + 7) & (~7); + } + + [[nodiscard]] auto information_id() const noexcept -> impl::information_id const & + { + return m_id; + } + + [[nodiscard]] auto next() const noexcept -> tag_header const * + { + return std::bit_cast<tag_header const *>(std::bit_cast<std::uintptr_t>(this) + full_size()); + } + + [[nodiscard]] auto unaligned_size() const noexcept -> std::uint32_t + { + return m_size; + } + + private: + impl::information_id m_id; + std::uint32_t 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)} // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + {} + + 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 const>; + + 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<Data>{} + , m_vla{} + {} + + explicit vla_tag(tag_header const * header) + : tag<Data>{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() const -> const_reference + { + return m_vla.at(); + } + + [[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<std::uintptr_t>(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 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..2d60a6d --- /dev/null +++ b/libs/multiboot2/include/multiboot2/information.hpp @@ -0,0 +1,232 @@ +#ifndef JOS_MULTIBOOT2_INFORMATION_HPP +#define JOS_MULTIBOOT2_INFORMATION_HPP + +#include "impl/data.hpp" +#include "impl/iterator.hpp" +#include "impl/tag.hpp" + +#include <elf/format.hpp> +#include <elf/section_header.hpp> + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#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 + */ + [[nodiscard]] auto string() const noexcept -> range_type + { + return {data(), size()}; + } + }; + + /** + * @copydoc multiboot2::impl::elf_symbols_data + */ + template<elf::format Format> + struct elf_symbols : impl::vla_tag<impl::elf_symbols_data, elf::section_header<Format> const, std::span> + { + using base = impl::vla_tag<impl::elf_symbols_data, elf::section_header<Format> const, std::span>; + using base::base; + + [[nodiscard]] auto name(elf::section_header<Format> 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<char const *>(string_table.virtual_load_address); + return name_array + name_offset; + } + }; + + /** + * @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 + */ + [[nodiscard]] auto string() const noexcept -> std::string_view + { + return {data(), size()}; + } + }; + + /** + * @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; + + /** + * @brief The available memory regions + */ + [[nodiscard]] auto regions() const noexcept -> range_type + { + return {data(), size()}; + } + }; + + 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; + + [[nodiscard]] auto size_bytes() const noexcept -> std::size_t + { + return 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<typename Tag> + [[nodiscard]] auto has() const noexcept -> bool + { + return get<Tag>().has_value(); + } + + [[nodiscard]] auto maybe_basic_memory() const noexcept -> std::optional<basic_memory> + { + return get<multiboot2::basic_memory>(); + } + + [[nodiscard]] auto basic_memory() const -> basic_memory + { + return maybe_basic_memory().value(); + } + + [[nodiscard]] auto maybe_bios_boot_device() const noexcept -> std::optional<bios_boot_device> + { + return get<multiboot2::bios_boot_device>(); + } + + [[nodiscard]] auto bios_boot_device() const -> bios_boot_device + { + return maybe_bios_boot_device().value(); + } + + [[nodiscard]] auto maybe_command_line() const noexcept -> std::optional<command_line> + { + return get<multiboot2::command_line>(); + } + + [[nodiscard]] auto command_line() const -> command_line + { + return maybe_command_line().value(); + } + + template<elf::format Format> + [[nodiscard]] auto maybe_elf_symbols() const noexcept -> std::optional<elf_symbols<Format>> + { + return get<multiboot2::elf_symbols<Format>>().and_then( + [](auto x) -> std::optional<multiboot2::elf_symbols<Format>> { + if (x.entry_size == elf::section_header_size<Format>) + { + return std::optional{x}; + } + else + { + return std::nullopt; + } + }); + } + + template<elf::format Format> + [[nodiscard]] auto elf_symbols() const -> elf_symbols<Format> + { + return maybe_elf_symbols<Format>().value(); + } + + [[nodiscard]] auto maybe_loader_name() const noexcept -> std::optional<loader_name> + { + return get<multiboot2::loader_name>(); + } + + [[nodiscard]] auto loader_name() const -> loader_name + { + return maybe_loader_name().value(); + } + + [[nodiscard]] auto maybe_memory_map() const noexcept -> std::optional<memory_map> + { + return get<multiboot2::memory_map>(); + } + + [[nodiscard]] auto memory_map() const -> memory_map + { + return maybe_memory_map().value(); + } + + private: + template<typename Tag> + [[nodiscard]] constexpr auto 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; + } + + uint32_t m_size{}; + uint32_t : 32; + impl::tag_header m_tags{}; + }; + +} // namespace multiboot2 + +#endif
\ No newline at end of file |
