aboutsummaryrefslogtreecommitdiff
path: root/libs/multiboot2/include
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2025-12-15 17:13:12 +0100
committerFelix Morgner <felix.morgner@ost.ch>2025-12-15 17:13:12 +0100
commit7b9482ae637126ac9337876e60f519b493437711 (patch)
tree6fc71a253c8b0325d303bd34c95b564ba536ed14 /libs/multiboot2/include
parent116f9332a206767c45095950f09f7c7447b561cf (diff)
parenta9eeec745e29d89afd48ee43d09432eb6fc35be7 (diff)
downloadteachos-7b9482ae637126ac9337876e60f519b493437711.tar.xz
teachos-7b9482ae637126ac9337876e60f519b493437711.zip
os: rework kernel architecture
Rework the code structure and architecture of the kernel by separating platform-dependent and platform-independent code more cleanly. As of this patchset, full feature parity has not been achieved. Nonetheless, a sufficient subset of functionality has been ported to the new architecture to demonstrate the feasibility of the new structure.
Diffstat (limited to 'libs/multiboot2/include')
-rw-r--r--libs/multiboot2/include/multiboot2/constants.hpp20
-rw-r--r--libs/multiboot2/include/multiboot2/impl/data.hpp135
-rw-r--r--libs/multiboot2/include/multiboot2/impl/ids.hpp81
-rw-r--r--libs/multiboot2/include/multiboot2/impl/iterator.hpp73
-rw-r--r--libs/multiboot2/include/multiboot2/impl/tag.hpp207
-rw-r--r--libs/multiboot2/include/multiboot2/information.hpp232
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