aboutsummaryrefslogtreecommitdiff
path: root/libs
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
parent116f9332a206767c45095950f09f7c7447b561cf (diff)
parenta9eeec745e29d89afd48ee43d09432eb6fc35be7 (diff)
downloadkernel-7b9482ae637126ac9337876e60f519b493437711.tar.xz
kernel-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')
-rw-r--r--libs/CMakeLists.txt3
-rw-r--r--libs/elf/CMakeLists.txt19
-rw-r--r--libs/elf/include/elf/format.hpp15
-rw-r--r--libs/elf/include/elf/section_header.hpp99
-rw-r--r--libs/kstd/CMakeLists.txt40
-rw-r--r--libs/kstd/include/kstd/asm_ptr77
-rw-r--r--libs/kstd/include/kstd/bits/os.hpp34
-rw-r--r--libs/kstd/include/kstd/bits/shared_ptr.hpp269
-rw-r--r--libs/kstd/include/kstd/bits/unique_ptr.hpp206
-rw-r--r--libs/kstd/include/kstd/ext/bitfield_enum65
-rw-r--r--libs/kstd/include/kstd/memory7
-rw-r--r--libs/kstd/include/kstd/mutex71
-rw-r--r--libs/kstd/include/kstd/stack201
-rw-r--r--libs/kstd/include/kstd/vector599
-rw-r--r--libs/kstd/kstd.dox14
-rw-r--r--libs/kstd/src/bits/os.cpp10
-rw-r--r--libs/kstd/src/libc/stdlib.cpp19
-rw-r--r--libs/kstd/src/libc/string.cpp32
-rw-r--r--libs/kstd/src/mutex.cpp24
-rw-r--r--libs/multiboot2/CMakeLists.txt27
-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
26 files changed, 2579 insertions, 0 deletions
diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
new file mode 100644
index 0000000..58d9796
--- /dev/null
+++ b/libs/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory("elf" EXCLUDE_FROM_ALL SYSTEM)
+add_subdirectory("kstd" EXCLUDE_FROM_ALL SYSTEM)
+add_subdirectory("multiboot2" EXCLUDE_FROM_ALL SYSTEM) \ No newline at end of file
diff --git a/libs/elf/CMakeLists.txt b/libs/elf/CMakeLists.txt
new file mode 100644
index 0000000..66e59ee
--- /dev/null
+++ b/libs/elf/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_library("elf" INTERFACE)
+add_library("libs::elf" ALIAS "elf")
+
+target_sources("elf" INTERFACE
+ FILE_SET HEADERS
+ BASE_DIRS "include"
+ FILES
+ "include/elf/format.hpp"
+ "include/elf/section_header.hpp"
+
+)
+
+target_include_directories("elf" INTERFACE
+ "include"
+)
+
+set_target_properties("elf" PROPERTIES
+ VERIFY_INTERFACE_HEADER_SETS YES
+) \ No newline at end of file
diff --git a/libs/elf/include/elf/format.hpp b/libs/elf/include/elf/format.hpp
new file mode 100644
index 0000000..b3220f5
--- /dev/null
+++ b/libs/elf/include/elf/format.hpp
@@ -0,0 +1,15 @@
+#ifndef ELF_FORMAT_HPP
+#define ELF_FORMAT_HPP
+
+namespace elf
+{
+
+ enum struct format
+ {
+ elf32,
+ elf64,
+ };
+
+} // namespace elf
+
+#endif \ No newline at end of file
diff --git a/libs/elf/include/elf/section_header.hpp b/libs/elf/include/elf/section_header.hpp
new file mode 100644
index 0000000..3afe334
--- /dev/null
+++ b/libs/elf/include/elf/section_header.hpp
@@ -0,0 +1,99 @@
+#ifndef ELF_SECTION_HEADER_HPP
+#define ELF_SECTION_HEADER_HPP
+
+#include "format.hpp"
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace elf
+{
+
+ template<format Format>
+ constexpr auto inline section_header_size = std::numeric_limits<std::size_t>::max();
+
+ template<>
+ constexpr auto inline section_header_size<format::elf32> = 40uz;
+
+ template<>
+ constexpr auto inline section_header_size<format::elf64> = 64uz;
+
+ template<format Format>
+ struct section_header
+ {
+ using format_uint = std::conditional_t<Format == format::elf32, std::uint32_t, std::uint64_t>;
+
+ enum struct header_type : std::uint32_t
+ {
+ null = 0, ///< Is inactive
+ program_data = 1, ///< Contains program data
+ symbol_table = 2, ///< Contains a symbol table
+ string_table = 3, ///< Contains a string table
+ relocation_entries_with_addends = 4, ///< Contains relocation information with addends
+ hash_table = 5, ///< Contains a symbol hash table
+ dynamic_linking_entries = 6, ///< Contains dynamic linking information
+ notes = 7, ///< Contains additional notes about the object file
+ no_content = 8, ///< Contains no data
+ relocation_entries_without_addends = 9, ///< Contains relocation information without addends
+ reserved = 10, ///< Reserved for future use
+ dynamic_linker_symbol_table = 11, ///< Contains the dynamic linker symbol table
+ init_array = 14, ///< Contains an array of constructor pointers
+ fini_array = 15, ///< Contains an array of destructor pointers
+ preinit_array = 16, ///< Contains an array of pre-constructor pointers
+ group_table = 17, ///< Defines a section group
+ extended_section_header_indices = 18, ///< Contains extended section header indices
+ };
+
+ enum struct header_flags : format_uint
+ {
+ writeable = 0x1, ///< Contains writable data
+ allocated = 0x2, ///< Occupies memory during execution
+ executable = 0x4, ///< Contains executable instructions
+ mergeable = 0x10, ///< Contained data may be merged for deduplication
+ strings = 0x20, ///< Contains null-terminated strings
+ info_link = 0x40, ///< Contains the section header index of linked section
+ link_order = 0x80, ///< Must respect linking location relative to linked section
+ os_specific = 0x100, ///< Must be handled in an OS specific way
+ group_member = 0x200, ///< Is a member of a section group
+ thread_local_storage = 0x400, ///< Contains thread local storage data
+ compressed = 0x800, ///< Is compressed
+ };
+
+ //! Check if the section is allocated
+ [[nodiscard]] constexpr auto allocated() const noexcept -> bool
+ {
+ return std::to_underlying(flags) & std::to_underlying(header_flags::allocated);
+ }
+
+ //! Check if the section is executable
+ [[nodiscard]] constexpr auto executable() const noexcept -> bool
+ {
+ return std::to_underlying(flags) & std::to_underlying(header_flags::executable);
+ }
+
+ //! Check if the section is writeable
+ [[nodiscard]] constexpr auto writable() const noexcept -> bool
+ {
+ return std::to_underlying(flags) & std::to_underlying(header_flags::writeable);
+ }
+
+ std::uint32_t name_offset; ///< Offset into the section header string table, defining the section name
+ header_type type; ///< Type of this section
+ header_flags flags; ///< Flags of this section
+ format_uint virtual_load_address; ///< Virtual address where this section is loaded
+ format_uint file_offset; ///< Offset of the start of this section's data in the file
+ format_uint size; ///< Size of this section in memory
+ std::uint32_t linked_section; ///< Index of a section this section is linked to
+ std::uint32_t extra_info; ///< Additional information for this section (type and flag dependent)
+ format_uint alignment; ///< Alignment requirement of this section in memory
+ format_uint entry_size; ///< Size of the entries inside this section (if any)
+ };
+
+ static_assert(sizeof(section_header<format::elf32>) == section_header_size<format::elf32>);
+ static_assert(sizeof(section_header<format::elf64>) == section_header_size<format::elf64>);
+
+} // namespace elf
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt
new file mode 100644
index 0000000..d83e704
--- /dev/null
+++ b/libs/kstd/CMakeLists.txt
@@ -0,0 +1,40 @@
+add_library("kstd" STATIC)
+add_library("libs::kstd" ALIAS "kstd")
+
+set(KSTD_LIBC_SYMBOLS
+ "abort"
+ "strlen"
+ "memcmp"
+)
+
+target_sources("kstd" PRIVATE
+ "src/bits/os.cpp"
+ "src/libc/stdlib.cpp"
+ "src/libc/string.cpp"
+ "src/mutex.cpp"
+)
+
+target_sources("kstd" PUBLIC
+ FILE_SET HEADERS
+ BASE_DIRS "include"
+ FILES
+ "include/kstd/bits/os.hpp"
+ "include/kstd/bits/shared_ptr.hpp"
+ "include/kstd/bits/unique_ptr.hpp"
+
+ "include/kstd/ext/bitfield_enum"
+
+ "include/kstd/asm_ptr"
+ "include/kstd/memory"
+ "include/kstd/mutex"
+ "include/kstd/stack"
+ "include/kstd/vector"
+)
+
+target_include_directories("kstd" PUBLIC
+ "include"
+)
+
+list(TRANSFORM KSTD_LIBC_SYMBOLS PREPEND "-Wl,--undefined=")
+
+target_link_options("kstd" INTERFACE ${KSTD_LIBC_SYMBOLS}) \ No newline at end of file
diff --git a/libs/kstd/include/kstd/asm_ptr b/libs/kstd/include/kstd/asm_ptr
new file mode 100644
index 0000000..e8636c3
--- /dev/null
+++ b/libs/kstd/include/kstd/asm_ptr
@@ -0,0 +1,77 @@
+#ifndef KSTD_ASM_POINTER_HPP
+#define KSTD_ASM_POINTER_HPP
+
+#include <bit>
+
+namespace kstd
+{
+
+ /**
+ * @brief A pointer that is defined in some assembly source file.
+ *
+ * @tparam Type The type of the pointer
+ */
+ template<typename Type>
+ struct asm_ptr
+ {
+ using value_type = Type;
+ using pointer = value_type *;
+ using const_pointer = value_type const *;
+ using reference = value_type &;
+ using const_reference = value_type const &;
+
+ asm_ptr() = delete;
+ asm_ptr(asm_ptr const &) = delete;
+ asm_ptr(asm_ptr &&) = delete;
+ ~asm_ptr() = delete;
+
+ constexpr auto operator=(asm_ptr const &) = delete;
+ constexpr auto operator=(asm_ptr &&) = delete;
+
+ auto get() const noexcept -> pointer
+ {
+ return m_ptr;
+ }
+
+ constexpr auto operator+(std::ptrdiff_t offset) const noexcept -> pointer
+ {
+ return std::bit_cast<pointer>(m_ptr) + offset;
+ }
+
+ constexpr auto operator*() noexcept -> reference
+ {
+ return *(std::bit_cast<pointer>(m_ptr));
+ }
+
+ constexpr auto operator*() const noexcept -> const_reference
+ {
+ return *(std::bit_cast<const_pointer>(m_ptr));
+ }
+
+ constexpr auto operator[](std::ptrdiff_t offset) noexcept -> reference
+ {
+ return *(*this + offset);
+ }
+
+ constexpr auto operator[](std::ptrdiff_t offset) const noexcept -> const_reference
+ {
+ return *(*this + offset);
+ }
+
+ constexpr auto operator->() noexcept -> pointer
+ {
+ return m_ptr;
+ }
+
+ constexpr auto operator->() const noexcept -> const_pointer
+ {
+ return m_ptr;
+ }
+
+ private:
+ pointer m_ptr;
+ };
+
+} // namespace kstd
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/bits/os.hpp b/libs/kstd/include/kstd/bits/os.hpp
new file mode 100644
index 0000000..0474f16
--- /dev/null
+++ b/libs/kstd/include/kstd/bits/os.hpp
@@ -0,0 +1,34 @@
+#ifndef KSTD_OS_HPP
+#define KSTD_OS_HPP
+
+#include <source_location>
+#include <string_view>
+
+namespace kstd::os
+{
+ /**
+ * @brief Handle an unrecoverable library error.
+ *
+ * The operating system kernel may choose to implement this function in order to try to perform additional cleanup
+ * before terminating execution. If the kernel does not implement this function, the default implementation will be
+ * chosen. This default implementation doest nothing.
+ */
+ [[noreturn]]
+ auto abort() -> void;
+
+ /**
+ * @brief Terminate execution of the operating system.
+ *
+ * The operating system must implement this function. This function must terminate the execution of the operating
+ * system kernel as is. It may choose to restart the kernel or to halt execution entirely. The implementation must
+ * guarantee that execution never return from this function.
+ *
+ * @param message A message describing the reason for termination of execution.
+ * @param where The source code location at which the panic was triggered. In general, no argument shall be provided
+ * for this parameter, thus implicitly capturing the location at which the call originates.
+ */
+ [[noreturn]]
+ auto panic(std::string_view message, std::source_location where = std::source_location::current()) -> void;
+} // namespace kstd::os
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/bits/shared_ptr.hpp b/libs/kstd/include/kstd/bits/shared_ptr.hpp
new file mode 100644
index 0000000..4bcf499
--- /dev/null
+++ b/libs/kstd/include/kstd/bits/shared_ptr.hpp
@@ -0,0 +1,269 @@
+#ifndef KSTD_BITS_SHARED_PTR_HPP
+#define KSTD_BITS_SHARED_PTR_HPP
+
+#include <atomic>
+
+namespace kstd
+{
+ /**
+ * @brief Shared_pointer is a smart pointer that retains shared ownership of an object through a pointer. Several
+ * shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of
+ * the following happens: the last remaining shared_ptr owning the object is destroyed; the last remaining
+ * shared_ptr owning the object is assigned another pointer via operator= or reset(). A
+ * shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used
+ * to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(),
+ * the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count
+ * reaches zero.
+ *
+ * @tparam T The type of the managed object.
+ */
+ template<typename T>
+ struct shared_ptr
+ {
+ /**
+ * @brief Constructor.
+ *
+ * @param pointer A pointer to an object to manage (default is nullptr).
+ */
+ [[gnu::section(".stl_text")]]
+ explicit shared_ptr(T * pointer = nullptr)
+ : pointer(pointer)
+ , ref_count(new std::atomic<std::size_t>(pointer != nullptr ? 1 : 0))
+ {
+ // Nothing to do.
+ }
+
+ /**
+ * @brief Copy constructor.
+ *
+ * @param other The shared_ptr to copy from.
+ */
+ [[gnu::section(".stl_text")]]
+ shared_ptr(shared_ptr const & other)
+ : pointer(other.pointer)
+ , ref_count(other.ref_count)
+ {
+ if (pointer != nullptr)
+ {
+ ++(*ref_count);
+ }
+ }
+
+ /**
+ * @brief Move constructor.
+ *
+ * @param other The shared_ptr to move from.
+ */
+ [[gnu::section(".stl_text")]]
+ shared_ptr(shared_ptr && other) noexcept
+ : pointer(other.pointer)
+ , ref_count(other.ref_count)
+ {
+ other.pointer = nullptr;
+ other.ref_count = nullptr;
+ }
+
+ /**
+ * @brief Copy assignment operator. Replaces the managed object with the one managed by r. Shares ownership of the
+ * object managed by r. If r manages no object, *this manages no object too. Equivalent to
+ * shared_ptr<T>(r).swap(*this).
+ *
+ * @param other Another smart pointer to share the ownership with.
+ * @return Reference to this shared pointer.
+ */
+ [[gnu::section(".stl_text")]]
+ shared_ptr & operator=(shared_ptr const & other)
+ {
+ if (this != &other)
+ {
+ cleanup();
+ pointer = other.pointer;
+ ref_count = other.ref_count;
+
+ if (pointer != nullptr)
+ {
+ ++(*ref_count);
+ }
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Move assignment operator. Move-assigns a shared_ptr from r. After the assignment, *this contains a copy of
+ * the previous state of r, and r is empty. Equivalent to shared_ptr<T>(std::move(r)).swap(*this).
+ *
+ * @param other Another smart pointer to acquire the ownership from.
+ * @return Reference to this shared pointer.
+ */
+ [[gnu::section(".stl_text")]]
+ shared_ptr & operator=(shared_ptr && other) noexcept
+ {
+ if (this != &other)
+ {
+ cleanup();
+ pointer = other.pointer;
+ ref_count = other.ref_count;
+ other.pointer = nullptr;
+ other.ref_count = nullptr;
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Destructor. Cleans up resources if necessary.
+ */
+ [[gnu::section(".stl_text")]]
+ ~shared_ptr()
+ {
+ cleanup();
+ }
+
+ /**
+ * @brief Replaces the managed object.
+ *
+ * @param ptr Pointer to a new object to manage (default = nullptr).
+ */
+ [[gnu::section(".stl_text")]]
+ void reset(T * ptr = nullptr)
+ {
+ cleanup();
+ pointer = ptr;
+ ref_count = new std::atomic<std::size_t>(ptr != nullptr ? 1 : 0);
+ }
+
+ /**
+ * @brief Exchanges the stored pointer values and the ownerships of *this and r. Reference counts, if any, are not
+ * adjusted.
+ *
+ * @param other The shared_ptr to swap with.
+ */
+ [[gnu::section(".stl_text")]]
+ void swap(shared_ptr & other)
+ {
+ std::swap(pointer, other.pointer);
+ std::swap(ref_count, other.ref_count);
+ }
+
+ /**
+ * @brief Dereference operator. If get() is a null pointer, the behavior is undefined.
+ *
+ * @return Returns the object owned by *this, equivalent to *get().
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator*() const -> T &
+ {
+ return *pointer;
+ }
+
+ /**
+ * @brief Member access operator.
+ *
+ * @return Returns a pointer to the object owned by *this, i.e. get().
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator->() const -> T *
+ {
+ return pointer;
+ }
+
+ /**
+ * @brief Returns a pointer to the managed object or nullptr if no object is owned.
+ *
+ * @return Pointer to the managed object or nullptr if no object is owned.
+ */
+ [[gnu::section(".stl_text")]]
+ auto get() const -> T *
+ {
+ return pointer;
+ }
+
+ /**
+ * @brief Returns the number of different shared_ptr instances (*this included) managing the current object. If
+ * there is no managed object, ​0​ is returned.
+ *
+ * @note Common use cases include comparison with ​0​. If use_count returns zero, the shared pointer is empty
+ * and manages no objects (whether or not its stored pointer is nullptr). Comparison with 1. If use_count returns 1,
+ * there are no other owners.
+ *
+ * @return The number of Shared_pointer instances managing the current object or ​0​ if there is no managed
+ * object.
+ */
+ [[gnu::section(".stl_text")]]
+ auto use_count() const -> std::size_t
+ {
+ if (pointer != nullptr)
+ {
+ return *ref_count;
+ }
+
+ return 0;
+ }
+
+ /**
+ * @brief Checks whether *this owns an object, i.e. whether get() != nullptr.
+ *
+ * @return true if *this owns an object, false otherwise.
+ */
+ [[gnu::section(".stl_text")]]
+ explicit operator bool() const
+ {
+ return pointer != nullptr;
+ }
+
+ /**
+ * @brief Defaulted three-way comparator operator.
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator<=>(shared_ptr const & other) const = default;
+
+ private:
+ /**
+ * @brief Releases ownership and deletes the object if this was the last reference to the owned managed object.
+ */
+ [[gnu::section(".stl_text")]]
+ auto cleanup() -> void
+ {
+ if (pointer != nullptr && ref_count != nullptr && --(*ref_count) == 0)
+ {
+ delete pointer;
+ delete ref_count;
+ }
+ }
+
+ T * pointer; ///< The managed object.
+ std::atomic<std::size_t> * ref_count; ///< Reference count.
+ };
+
+ /**
+ * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls
+ * lhs.swap(rhs).
+ *
+ * @tparam T Type of the managed object.
+ * @param lhs, rhs Smart pointers whose contents to swap.
+ */
+ template<typename T>
+ auto swap(shared_ptr<T> & lhs, shared_ptr<T> & rhs) -> void
+ {
+ lhs.swap(rhs);
+ }
+
+ /**
+ * @brief Constructs an object of type T and wraps it in a shared_ptr. Constructs a non-array type T. The
+ * arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is
+ * not an array type. The function is equivalent to: shared_ptr<T>(new T(std::forward<Args>(args)...)).
+ *
+ * @tparam T Type of the managed object.
+ * @tparam Args Argument types for T's constructor.
+ * @param args List of arguments with which an instance of T will be constructed.
+ * @returns Shared_pointer of an instance of type T.
+ */
+ template<typename T, typename... Args>
+ auto make_shared(Args &&... args) -> shared_ptr<T>
+ {
+ return shared_ptr<T>(new T(std::forward<Args>(args)...));
+ }
+} // namespace kstd
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/bits/unique_ptr.hpp b/libs/kstd/include/kstd/bits/unique_ptr.hpp
new file mode 100644
index 0000000..5f54848
--- /dev/null
+++ b/libs/kstd/include/kstd/bits/unique_ptr.hpp
@@ -0,0 +1,206 @@
+#ifndef KSTD_BITS_UNIQUE_POINTER_HPP
+#define KSTD_BITS_UNIQUE_POINTER_HPP
+
+#include <utility>
+
+namespace kstd
+{
+ /**
+ * @brief Unique_pointer is a smart pointer that owns (is responsible for) and manages another object via a pointer
+ * and subsequently disposes of that object when the unique_ptr goes out of scope.
+ *
+ * @tparam T Type of the managed object.
+ */
+ template<typename T>
+ struct unique_ptr
+ {
+ /**
+ * @brief Constructor.
+ *
+ * @param ptr A pointer to an object to manage (default is nullptr).
+ */
+ [[gnu::section(".stl_text")]]
+ explicit unique_ptr(T * ptr = nullptr)
+ : pointer(ptr)
+ {
+ // Nothing to do.
+ }
+
+ /**
+ * @brief Destructor that deletes the managed object.
+ */
+ [[gnu::section(".stl_text")]]
+ ~unique_ptr()
+ {
+ delete pointer;
+ }
+
+ /**
+ * @brief Deleted copy constructor to enforce unique ownership.
+ */
+ unique_ptr(unique_ptr const &) = delete;
+
+ /**
+ * @brief Deleted copy assignment operator to enforce unique ownership.
+ */
+ auto operator=(unique_ptr const &) -> unique_ptr & = delete;
+
+ /**
+ * @brief Move constructor.
+ *
+ * @param other Unique pointer to move from.
+ */
+ [[gnu::section(".stl_text")]]
+ unique_ptr(unique_ptr && other) noexcept
+ : pointer(other.pointer)
+ {
+ other.pointer = nullptr;
+ }
+
+ /**
+ * @brief Move assignment operator. Transfers ownership from other to *this as if by calling reset(r.release()).
+ *
+ * @param other Smart pointer from which ownership will be transferred.
+ * @return Reference to this unique pointer.
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator=(unique_ptr && other) noexcept -> unique_ptr &
+ {
+ if (this != &other)
+ {
+ delete pointer;
+ pointer = other.pointer;
+ other.pointer = nullptr;
+ }
+ return *this;
+ }
+
+ /**
+ * @brief Dereference operator. If get() is a null pointer, the behavior is undefined.
+ *
+ * @return Returns the object owned by *this, equivalent to *get().
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator*() const -> T &
+ {
+ return *pointer;
+ }
+
+ /**
+ * @brief Member access operator.
+ *
+ * @return Returns a pointer to the object owned by *this, i.e. get().
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator->() const -> T *
+ {
+ return pointer;
+ }
+
+ /**
+ * @brief Returns a pointer to the managed object or nullptr if no object is owned.
+ *
+ * @return Pointer to the managed object or nullptr if no object is owned.
+ */
+ [[gnu::section(".stl_text")]]
+ auto get() const -> T *
+ {
+ return pointer;
+ }
+
+ /**
+ * @brief Checks whether *this owns an object, i.e. whether get() != nullptr.
+ *
+ * @return true if *this owns an object, false otherwise.
+ */
+ [[gnu::section(".stl_text")]]
+ explicit operator bool() const noexcept
+ {
+ return pointer != nullptr;
+ }
+
+ /**
+ * @brief Releases the ownership of the managed object, if any.
+ * get() returns nullptr after the call.
+ * The caller is responsible for cleaning up the object (e.g. by use of get_deleter()).
+ *
+ * @return Pointer to the managed object or nullptr if there was no managed object, i.e. the value which would be
+ * returned by get() before the call.
+ */
+ [[gnu::section(".stl_text")]]
+ auto release() -> T *
+ {
+ T * temp = pointer;
+ pointer = nullptr;
+ return temp;
+ }
+
+ /**
+ * @brief Replaces the managed object.
+ *
+ * @note A test for self-reset, i.e. whether ptr points to an object already managed by *this, is not performed,
+ * except where provided as a compiler extension or as a debugging assert. Note that code such as
+ * p.reset(p.release()) does not involve self-reset, only code like p.reset(p.get()) does.
+ *
+ * @param ptr Pointer to a new object to manage (default = nullptr).
+ */
+ [[gnu::section(".stl_text")]]
+ auto reset(T * ptr = nullptr) -> void
+ {
+ delete pointer;
+ pointer = ptr;
+ }
+
+ /**
+ * @brief Swaps the managed objects and associated deleters of *this and another unique_ptr object other.
+ *
+ * @param other Another unique_ptr object to swap the managed object and the deleter with.
+ */
+ [[gnu::section(".stl_text")]]
+ auto swap(unique_ptr & other) -> void
+ {
+ using std::swap;
+ swap(pointer, other.pointer);
+ }
+
+ /**
+ * @brief Defaulted three-way comparator operator.
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator<=>(unique_ptr const & other) const = default;
+
+ private:
+ T * pointer; ///< The managed pointer.
+ };
+
+ /**
+ * @brief Specializes the std::swap algorithm for stl::unique_ptr. Swaps the contents of lhs and rhs. Calls
+ * lhs.swap(rhs).
+ *
+ * @tparam T Type of the managed object.
+ * @param lhs, rhs Smart pointers whose contents to swap.
+ */
+ template<typename T>
+ auto swap(unique_ptr<T> & lhs, unique_ptr<T> & rhs) -> void
+ {
+ lhs.swap(rhs);
+ }
+
+ /**
+ * @brief Constructs an object of type T and wraps it in a unique_ptr. Constructs a non-array type T. The
+ * arguments args are passed to the constructor of T. This overload participates in overload resolution only if T is
+ * not an array type. The function is equivalent to: unique_ptr<T>(new T(std::forward<Args>(args)...)).
+ *
+ * @tparam T Type of the managed object.
+ * @tparam Args Argument types for T's constructor.
+ * @param args List of arguments with which an instance of T will be constructed.
+ * @returns Unique_pointer of an instance of type T.
+ */
+ template<typename T, typename... Args>
+ auto make_unique(Args &&... args) -> unique_ptr<T>
+ {
+ return unique_ptr<T>(new T(std::forward<Args>(args)...));
+ }
+} // namespace kstd
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/ext/bitfield_enum b/libs/kstd/include/kstd/ext/bitfield_enum
new file mode 100644
index 0000000..80fe9d2
--- /dev/null
+++ b/libs/kstd/include/kstd/ext/bitfield_enum
@@ -0,0 +1,65 @@
+#ifndef KSTD_EXT_BITFIELD_ENUM_HPP
+#define KSTD_EXT_BITFIELD_ENUM_HPP
+
+#include <bit>
+#include <type_traits>
+#include <utility>
+
+namespace kstd::ext
+{
+
+ template<typename EnumType>
+ requires std::is_enum_v<EnumType>
+ struct is_bitfield_enum : std::false_type
+ {
+ };
+
+ //! @concept Specifies that an enum is to be used to define bits in a bitfield.
+ template<typename EnumType>
+ concept bitfield_enum = is_bitfield_enum<EnumType>::value;
+
+}; // namespace kstd::ext
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator|(EnumType lhs, EnumType rhs) -> EnumType
+{
+ return std::bit_cast<EnumType>(std::to_underlying(lhs) | std::to_underlying(rhs));
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator|=(EnumType & lhs, EnumType rhs) -> EnumType &
+{
+ return lhs = lhs | rhs;
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator&(EnumType lhs, EnumType rhs) -> EnumType
+{
+ return std::bit_cast<EnumType>(std::to_underlying(lhs) & std::to_underlying(rhs));
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator&=(EnumType & lhs, EnumType rhs) -> EnumType &
+{
+ return lhs = lhs & rhs;
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator^(EnumType lhs, EnumType rhs) -> EnumType
+{
+ return std::bit_cast<EnumType>(std::to_underlying(lhs) ^ std::to_underlying(rhs));
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator^=(EnumType & lhs, EnumType rhs) -> EnumType &
+{
+ return lhs = lhs ^ rhs;
+}
+
+template<kstd::ext::bitfield_enum EnumType>
+constexpr auto operator~(EnumType lhs) -> EnumType
+{
+ return std::bit_cast<EnumType>(~std::to_underlying(lhs));
+}
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/memory b/libs/kstd/include/kstd/memory
new file mode 100644
index 0000000..cab2fba
--- /dev/null
+++ b/libs/kstd/include/kstd/memory
@@ -0,0 +1,7 @@
+#ifndef KSTD_SHARED_POINTER_HPP
+#define KSTD_SHARED_POINTER_HPP
+
+#include "kstd/bits/shared_ptr.hpp" // IWYU pragma: export
+#include "kstd/bits/unique_ptr.hpp" // IWYU pragma: export
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/mutex b/libs/kstd/include/kstd/mutex
new file mode 100644
index 0000000..6ae3adf
--- /dev/null
+++ b/libs/kstd/include/kstd/mutex
@@ -0,0 +1,71 @@
+#ifndef KSTD_MUTEX_HPP
+#define KSTD_MUTEX_HPP
+
+#include <atomic>
+
+namespace kstd
+{
+ /**
+ * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in
+ * use by another thread or not.
+ */
+ struct mutex
+ {
+ /**
+ * @brief Defaulted constructor.
+ */
+ mutex() = default;
+
+ /**
+ * @brief Defaulted destructor.
+ */
+ ~mutex() = default;
+
+ /**
+ * @brief Deleted copy constructor.
+ */
+ mutex(mutex const &) = delete;
+
+ /**
+ * @brief Deleted move constructor.
+ *
+ */
+ mutex(mutex &&) = delete;
+
+ /**
+ * @brief Deleted copy assignment operator.
+ */
+ auto operator=(mutex const &) -> mutex & = delete;
+
+ /**
+ * @brief Deleted move assignment operator.
+ */
+ auto operator=(mutex &&) -> mutex & = delete;
+
+ /**
+ * @brief Lock the mutex (blocks for as long as it is not available).
+ */
+ [[gnu::section(".stl_text")]]
+ auto lock() -> void;
+
+ /**
+ * @brief Try to lock the mutex (non-blocking).
+ *
+ * @return True if lock has been acquired and false otherwise.
+ */
+ [[gnu::section(".stl_text")]]
+ auto try_lock() -> bool;
+
+ /**
+ * @brief Unlock the mutex.
+ */
+ [[gnu::section(".stl_text")]]
+ auto unlock() -> void;
+
+ private:
+ std::atomic<bool> locked = {false}; // Atomic boolean to track if mutex is locked or not.
+ };
+
+} // namespace kstd
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/include/kstd/stack b/libs/kstd/include/kstd/stack
new file mode 100644
index 0000000..8cd208a
--- /dev/null
+++ b/libs/kstd/include/kstd/stack
@@ -0,0 +1,201 @@
+#ifndef KSTD_STACK_HPP
+#define KSTD_STACK_HPP
+
+#include "kstd/vector"
+#include <utility>
+
+namespace kstd
+{
+ /**
+ * @brief Custom stack implementation mirroring the std::stack to allow for the usage of STL functionality with our
+ * custom memory management.
+ *
+ * @tparam T Element the stack instance should contain.
+ * @tparam Container Actual underlying container that should be wrapped to provide stack functionality. Requires
+ * access to pop_back(), push_back(), back(), size(), empty() and emplace_back()
+ */
+ template<typename T, typename Container = kstd::vector<T>>
+ struct stack
+ {
+ using container_type = Container; ///< Type of the underlying container used to implement stack-like interface.
+ using value_type = Container::value_type; ///< Type of the elements contained in the underlying container.
+ using size_type = Container::size_type; ///< Type of the size in the underlying container.
+ using reference = Container::reference; ///< Type of reference to the elements.
+ using const_reference = Container::const_reference; ///< Type of constant reference to the elements.
+
+ /**
+ * @brief Default Constructor.
+ */
+ stack() = default;
+
+ stack(stack const &) = delete;
+ stack(stack &&) = delete;
+ auto operator=(stack const &) -> stack & = delete;
+ auto operator=(stack &&) -> stack & = delete;
+ /**
+ * @brief Constructs data with the given amount of elements containing the given value or alternatively the default
+ * constructed value.
+ *
+ * @param n Amount of elements we want to create and set the given value for.
+ * @param initial Inital value of all elements in the underlying data array.
+ */
+ [[gnu::section(".stl_text")]]
+ explicit stack(size_type n, value_type initial = value_type{})
+ : _container(n, initial)
+ {
+ // Nothing to do.
+ }
+
+ /**
+ * @brief Constructs data by copying all element from the given exclusive range.
+ *
+ * @tparam InputIterator Template that should have atleast input iterator characteristics.
+ * @param first Input iterator to the first element in the range we want to copy from.
+ * @param last Input iterator to one past the last element in the range we want to copy from.
+ */
+ template<typename InputIterator>
+ [[gnu::section(".stl_text")]]
+ explicit stack(InputIterator first, InputIterator last)
+ : _container(first, last)
+ {
+ // Nothing to do.
+ }
+
+ /**
+ * @brief Construct data by copying all elements from the initializer list.
+ *
+ * @param elements List we want to copy all elements from.
+ */
+ [[gnu::section(".stl_text")]]
+ explicit stack(std::initializer_list<T> elements)
+ : _container(elements)
+ {
+ // Nothing to do.
+ }
+
+ /**
+ * @brief Copy constructor.
+ *
+ * @note Allocates underlying data container with the same capacity as stack we are copying from and copies all
+ * elements from it.
+ *
+ * @param other Other instance of stack we want to copy the data from.
+ */
+ [[gnu::section(".stl_text")]]
+ stack(stack<T> const & other)
+ : _container(other)
+ {
+ // Nothing to do.
+ }
+
+ /**
+ * @brief Destructor.
+ */
+ ~stack() = default;
+
+ /**
+ * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If
+ * that is the case the capacity is increased automatically.
+ *
+ * @return Current amount of elements.
+ */
+ [[gnu::section(".stl_text")]]
+ auto size() const -> size_type
+ {
+ return _container.size();
+ }
+
+ /**
+ * @brief Returns a reference to the last element in the container. Calling back on an empty container causes
+ * undefined behavior.
+ *
+ * @return Reference to the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto top() -> reference
+ {
+ return _container.back();
+ }
+
+ /**
+ * @brief Returns a reference to the last element in the container. Calling back on an empty container causes
+ * undefined behavior.
+ *
+ * @return Reference to the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto top() const -> const_reference
+ {
+ return _container.back();
+ }
+
+ /**
+ * @brief Appends the given element value to the end of the container. The element is assigned through the
+ * assignment operator of the template type. The value is forwarded to the constructor as
+ * std::forward<U>(value), meaning it is either moved (rvalue) or copied (lvalue).
+ *
+ * @note If after the operation the new size() is greater than old capacity() a reallocation takes place,
+ * in which case all iterators (including the end() iterator) and all references to the elements are invalidated.
+ * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which
+ * allows the template method to be used by both lvalue and rvalues and compile a different implementation.
+ *
+ * @param value The value of the element to append.
+ */
+ template<class U>
+ [[gnu::section(".stl_text")]]
+ auto push(U && value) -> void
+ {
+ _container.push_back(std::forward<U>(value));
+ }
+
+ /**
+ * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the
+ * template type. The arguments args... are forwarded to the constructor as std::forward<Args>(args)....
+ *
+ * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case
+ * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only
+ * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which
+ * allows the template method to be used by both lvalue and rvalues and compile a different implementation.
+ *
+ * @tparam Args
+ * @param args Arguments to forward to the constructor of the element
+ * @return value_type&
+ */
+ template<class... Args>
+ [[gnu::section(".stl_text")]]
+ auto emplace(Args &&... args) -> reference
+ {
+ _container.emplace_back(std::forward<Args>(args)...);
+ }
+
+ /**
+ * @brief Removes the last element of the container.
+ *
+ * @note Calling pop_back on an empty container results in halting the
+ * further execution. Iterators and references to the last element are invalidated. The end()
+ * iterator is also invalidated.
+ */
+ [[gnu::section(".stl_text")]]
+ auto pop() -> void
+ {
+ _container.pop_back();
+ }
+
+ /**
+ * @brief Whether there are currently any items this container or not.
+ *
+ * @return True if there are no elements, false if there are.
+ */
+ [[gnu::section(".stl_text")]]
+ auto empty() const -> bool
+ {
+ return _container.empty();
+ }
+
+ private:
+ container_type _container = {}; ///< Underlying container used by the stack to actually save the data.
+ };
+
+} // namespace kstd
+
+#endif
diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector
new file mode 100644
index 0000000..9d96eb8
--- /dev/null
+++ b/libs/kstd/include/kstd/vector
@@ -0,0 +1,599 @@
+#ifndef KSTD_VECTOR_HPP
+#define KSTD_VECTOR_HPP
+
+#include "bits/os.hpp"
+
+#include <algorithm>
+
+namespace kstd
+{
+ /**
+ * @brief Custom vector implementation mirroring the std::vector to allow for the usage of STL functionality with our
+ * custom memory management.
+ *
+ * @tparam T Element the vector instance should contain.
+ */
+ template<typename T>
+ struct vector
+ {
+ using value_type = T; ///< Type of the elements contained in the container.
+ using size_type = std::size_t; ///< Type of the size in the container.
+ using reference = value_type &; ///< Type of reference to the elements.
+ using const_reference = value_type const &; ///< Type of constant reference to the elements.
+ using pointer = value_type *; ///< Type of pointer to the elements.
+ using const_pointer = value_type const *; ///< Type of constant pointer to the elements.
+
+ /**
+ * @brief Default Constructor.
+ */
+ vector() = default;
+
+ /**
+ * @brief Constructs data with the given amount of elements containing the given value or alternatively the default
+ * constructed value.
+ *
+ * @param n Amount of elements we want to create and set the given value for.
+ * @param initial Inital value of all elements in the underlying data array.
+ */
+ explicit vector(size_type n, value_type initial = value_type{})
+ : _size(n)
+ , _capacity(n)
+ , _data(new value_type[_capacity]{})
+ {
+ std::ranges::fill(*this, initial);
+ }
+
+ /**
+ * @brief Constructs data by copying all element from the given exclusive range.
+ *
+ * @tparam InputIterator Template that should have atleast input iterator characteristics.
+ * @param first Input iterator to the first element in the range we want to copy from.
+ * @param last Input iterator to one past the last element in the range we want to copy from.
+ */
+ template<typename InputIterator>
+ explicit vector(InputIterator first, InputIterator last)
+ : _size(std::distance(first, last))
+ , _capacity(std::distance(first, last))
+ , _data(new value_type[_capacity]{})
+ {
+ std::ranges::copy(first, last, _data);
+ }
+
+ /**
+ * @brief Construct data by copying all elements from the initializer list.
+ *
+ * @param initalizer_list List we want to copy all elements from.
+ */
+ explicit vector(std::initializer_list<value_type> initalizer_list)
+ : _size(initalizer_list.size())
+ , _capacity(initalizer_list.size())
+ , _data(new value_type[_capacity]{})
+ {
+ std::ranges::copy(initalizer_list, _data);
+ }
+
+ /**
+ * @brief Copy constructor.
+ *
+ * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all
+ * elements from it.
+ *
+ * @param other Other instance of vector we want to copy the data from.
+ */
+ vector(vector<value_type> const & other)
+ : _size(other._size)
+ , _capacity(other._capacity)
+ {
+ delete[] _data;
+ _data = new value_type[_capacity]{};
+ std::ranges::copy(other, _data);
+ }
+
+ /**
+ * @brief Copy assignment operator.
+ *
+ * @note Allocates underlying data container with the same capacity as vector we are copying from and copies all
+ * elements from it.
+ *
+ * @param other Other instance of vector we want to copy the data from.
+ * @return Newly created copy.
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator=(vector const & other) -> vector<value_type> &
+ {
+ delete[] _data;
+ _size = other._size;
+ _capacity = other._capacity;
+ _data = new value_type[_capacity]{};
+ std::ranges::copy(other, _data);
+ return *this;
+ }
+
+ /**
+ * @brief Destructor.
+ */
+ ~vector()
+ {
+ delete[] _data;
+ }
+
+ /**
+ * @brief Amount of elements currently contained in this vector, will fill up until we have reached the capacity. If
+ * that is the case the capacity is increased automatically.
+ *
+ * @return Current amount of elements.
+ */
+ [[gnu::section(".stl_text")]]
+ auto size() const -> size_type
+ {
+ return _size;
+ }
+
+ /**
+ * @brief Amount of space the vector currently has, can be different than the size, because we allocate more than we
+ * exactly require to decrease the amount of allocations and deallocation to improve speed.
+ *
+ * @return Current amount of space the vector has for elements.
+ */
+ [[gnu::section(".stl_text")]]
+ auto capacity() const -> size_type
+ {
+ return _capacity;
+ }
+
+ /**
+ * @brief Array indexing operator. Allowing to access element at the given index.
+ *
+ * @note Does not do any bounds checks use at() for that.
+ *
+ * @param index Index we want to access elements at.
+ * @return Reference to the underlying element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator[](size_type index) -> reference
+ {
+ return _data[index];
+ }
+
+ /**
+ * @brief Array indexing operator. Allowing to access element at the given index.
+ *
+ * @note Does not do any bounds checks use at() for that.
+ *
+ * @param index Index we want to access elements at.
+ * @return Reference to the underlying element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto operator[](size_type index) const -> const_reference
+ {
+ return _data[index];
+ }
+
+ /**
+ * @brief Array indexing operator. Allowing to access element at the given index.
+ *
+ * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted.
+ *
+ * @param index Index we want to access elements at.
+ * @return Reference to the underlying element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto at(size_type index) -> reference
+ {
+ throw_if_out_of_range(index);
+ return this->operator[](index);
+ }
+
+ /**
+ * @brief Array indexing operator. Allowing to access element at the given index.
+ *
+ * @note Ensures we do not access element outside of the bounds of the array, if we do further execution is halted.
+ *
+ * @param index Index we want to access elements at.
+ * @return Reference to the underlying element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto at(size_type index) const -> const_reference
+ {
+ throw_if_out_of_range(index);
+ return this->operator[](index);
+ }
+
+ /**
+ * @brief Appends the given element value to the end of the container. The element is assigned through the
+ * assignment operator of the template type. The value is forwarded to the constructor as
+ * std::forward<U>(value), meaning it is either moved (rvalue) or copied (lvalue).
+ *
+ * @note If after the operation the new size() is greater than old capacity() a reallocation takes place,
+ * in which case all iterators (including the end() iterator) and all references to the elements are invalidated.
+ * Otherwise only the end() iterator is invalidated. Uses a forward reference for the actual value passed, which
+ * allows the template method to be used by both lvalue and rvalues and compile a different implementation.
+ *
+ * @param value The value of the element to append.
+ */
+ template<class U>
+ [[gnu::section(".stl_text")]]
+ auto push_back(U && value) -> void
+ {
+ increase_capacity_if_full();
+ _data[_size] = std::forward<U>(value);
+ (void)_size++;
+ }
+
+ /**
+ * @brief Appends a new element to the end of the container. The element is constructed through a constructor of the
+ * template type. The arguments args... are forwarded to the constructor as std::forward<Args>(args)....
+ *
+ * If after the operation the new size() is greater than old capacity() a reallocation takes place, in which case
+ * all iterators (including the end() iterator) and all references to the elements are invalidated. Otherwise only
+ * the end() iterator is invalidated. Uses a forward reference for the actual value passed, which
+ * allows the template method to be used by both lvalue and rvalues and compile a different implementation.
+ *
+ * @tparam Args
+ * @param args Arguments to forward to the constructor of the element
+ * @return value_type&
+ */
+ template<class... Args>
+ [[gnu::section(".stl_text")]]
+ auto emplace_back(Args &&... args) -> value_type &
+ {
+ increase_capacity_if_full();
+ _data[_size] = value_type{std::forward<Args>(args)...};
+ auto const index = _size++;
+ return _data[index];
+ }
+
+ /**
+ * @brief Removes the last element of the container. Calling pop_back on an empty container results in halting the
+ * further execution. Iterators and references to the last element are invalidated. The end()
+ * iterator is also invalidated.
+ */
+ [[gnu::section(".stl_text")]]
+ auto pop_back() -> void
+ {
+ throw_if_empty();
+ (void)_size--;
+ }
+
+ /**
+ * @brief Returns an iterator to the first element of the vector.
+ * If the vector is empty, the returned iterator will be equal to end().
+ *
+ * @return Iterator to the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto begin() noexcept -> pointer
+ {
+ return _data;
+ }
+
+ /**
+ * @brief Returns an iterator to the first element of the vector.
+ * If the vector is empty, the returned iterator will be equal to end().
+ *
+ * @return Iterator to the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto begin() const noexcept -> const_pointer
+ {
+ return _data;
+ }
+
+ /**
+ * @brief Returns an iterator to the first element of the vector.
+ * If the vector is empty, the returned iterator will be equal to end().
+ *
+ * @return Iterator to the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto cbegin() const noexcept -> const_pointer
+ {
+ return begin();
+ }
+
+ /**
+ * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element
+ * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend().
+ *
+ * @return Reverse iterator to the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto rbegin() noexcept -> pointer
+ {
+ return _data + _size - 1;
+ }
+
+ /**
+ * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element
+ * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend().
+ *
+ * @return Reverse iterator to the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto rbegin() const noexcept -> const_pointer
+ {
+ return _data + _size - 1;
+ }
+
+ /**
+ * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element
+ * of the non-reversed vector. If the vector is empty, the returned iterator will be equal to rend().
+ *
+ * @return Reverse iterator to the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto crbegin() const noexcept -> const_pointer
+ {
+ return rbegin();
+ }
+
+ /**
+ * @brief Returns an iterator to the element following the last element of the vector. This element acts as a
+ * placeholder, attempting to access it results in undefined behavior.
+ *
+ * @return Iterator to the element following the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto end() noexcept -> pointer
+ {
+ return _data + _size;
+ }
+
+ /**
+ * @brief Returns an iterator to the element following the last element of the vector. This element acts as a
+ * placeholder, attempting to access it results in undefined behavior.
+ *
+ * @return Iterator to the element following the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto end() const noexcept -> const_pointer
+ {
+ return _data + _size;
+ }
+
+ /**
+ * @brief Returns an iterator to the element following the last element of the vector. This element acts as a
+ * placeholder, attempting to access it results in undefined behavior.
+ *
+ * @return Iterator to the element following the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto cend() const noexcept -> const_pointer
+ {
+ return end();
+ }
+
+ /**
+ * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It
+ * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a
+ * placeholder, attempting to access it results in undefined behavior.
+ *
+ * @return Reverse iterator to the element following the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto rend() noexcept -> pointer
+ {
+ return _data + size() - 1;
+ }
+
+ /**
+ * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It
+ * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a
+ * placeholder, attempting to access it results in undefined behavior.
+ *
+ * @return Reverse iterator to the element following the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto rend() const noexcept -> const_pointer
+ {
+ return _data + size() - 1;
+ }
+
+ /**
+ * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It
+ * corresponds to the element preceding the first element of the non-reversed vector. This element acts as a
+ * placeholder, attempting to access it results in undefined behavior.
+ *
+ * @return Reverse iterator to the element following the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto crend() const noexcept -> const_pointer
+ {
+ return rbegin();
+ }
+
+ /**
+ * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range
+ * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable
+ * in that case).
+ *
+ * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal
+ * to the address of the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto data() -> pointer
+ {
+ return _data;
+ }
+
+ /**
+ * @brief Returns a pointer to the underlying array serving as element storage. The pointer is such that range
+ * [data(), data() + size()) is always a valid range, even if the container is empty (data() is not dereferenceable
+ * in that case).
+ *
+ * @return Pointer to the underlying element storage. For non-empty containers, the returned pointer compares equal
+ * to the address of the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto data() const -> const_pointer
+ {
+ return _data;
+ }
+
+ /**
+ * @brief Returns a reference to the first element in the container. Calling front on an empty container causes
+ * undefined behavior.
+ *
+ * @return Reference to the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto front() -> reference
+ {
+ throw_if_empty();
+ return *begin();
+ }
+
+ /**
+ * @brief Returns a reference to the first element in the container. Calling front on an empty container causes
+ * undefined behavior.
+ *
+ * @return Reference to the first element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto front() const -> const_reference
+ {
+ throw_if_empty();
+ return *begin();
+ }
+
+ /**
+ * @brief Returns a reference to the last element in the container. Calling back on an empty container causes
+ * undefined behavior.
+ *
+ * @return Reference to the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto back() -> reference
+ {
+ throw_if_empty();
+ return *rbegin();
+ }
+
+ /**
+ * @brief Returns a reference to the last element in the container. Calling back on an empty container causes
+ * undefined behavior.
+ *
+ * @return Reference to the last element.
+ */
+ [[gnu::section(".stl_text")]]
+ auto back() const -> const_reference
+ {
+ throw_if_empty();
+ return *rbegin();
+ }
+
+ /**
+ * @brief Increase the capacity of the vector (the total number of elements that the vector can hold without
+ * requiring reallocation) to a value that's greater or equal to new_cap. If new_cap is greater than the current
+ * capacity(), new storage is allocated, otherwise the function does nothing.
+ *
+ * reserve() does not change the size of the vector.
+ *
+ * If new_cap is greater than capacity(), all iterators (including the end() iterator) and all references to the
+ * elements are invalidated. Otherwise, no iterators or references are invalidated.
+ *
+ * After a call to reserve(), insertions will not trigger reallocation unless the insertion would make the size of
+ * the vector greater than the value of capacity().
+ *
+ * @note Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for
+ * instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing
+ * the capacity to grow linearly rather than exponentially) and result in increased computational complexity and
+ * decreased performance. For example, a function that receives an arbitrary vector by reference and appends
+ * elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage
+ * characteristics.
+ *
+ * When inserting a range, the range version of insert() is generally preferable as it preserves the correct
+ * capacity growth behavior, unlike reserve() followed by a series of push_back()s.
+ *
+ * reserve() cannot be used to reduce the capacity of the container; to that end shrink_to_fit() is provided.
+ *
+ * @param new_capacity New capacity of the vector, in number of elements
+ */
+ [[gnu::section(".stl_text")]]
+ auto reserve(size_type new_capacity) -> void
+ {
+ if (new_capacity <= _capacity)
+ {
+ return;
+ }
+
+ _capacity = new_capacity;
+ value_type * temp = new value_type[_capacity]{};
+ std::ranges::copy(begin(), end(), temp);
+ delete[] _data;
+ _data = temp;
+ }
+
+ /**
+ * @brief Requests the removal of unused capacity. Meaning it requests to reduce capacity() to size().
+ *
+ * If reallocation occurs, all iterators (including the end() iterator) and all references to the elements are
+ * invalidated. If no reallocation occurs, no iterators or references are invalidated.
+ */
+ [[gnu::section(".stl_text")]]
+ auto shrink_to_fit() -> void
+ {
+ if (_size == _capacity)
+ {
+ return;
+ }
+
+ _capacity = _size;
+ value_type * temp = new value_type[_capacity]{};
+ std::ranges::copy(begin(), end(), temp);
+ delete[] _data;
+ _data = temp;
+ }
+
+ /**
+ * @brief Wheter there are currently any items this container or not.
+ *
+ * @return True if there are no elements, false if there are.
+ */
+ [[gnu::section(".stl_text")]]
+ auto empty() const -> bool
+ {
+ return _size <= 0;
+ }
+
+ private:
+ /**
+ * @brief Halts the execution of the application if the data container is currently empty.
+ */
+ auto throw_if_empty() const -> void
+ {
+ if (empty())
+ {
+ os::panic("[Vector] Attempted to access element of currently empty vector");
+ }
+ }
+
+ auto throw_if_out_of_range(size_type index) const -> void
+ {
+ if (index >= _size)
+ {
+ os::panic("[Vector] Attempted to read element at invalid index");
+ }
+ }
+
+ /**
+ * @brief Increases the internal capacity to 1 if it was previously 0 and to * 2 after that, meaning exponential
+ * growth. This is done to decrease the amount of single allocations done and because a power of 2 in memory size is
+ * normally perferable for the cache.
+ */
+ auto increase_capacity_if_full() -> void
+ {
+ if (_size == _capacity)
+ {
+ reserve(_capacity == 0U ? 1U : _capacity * 2U);
+ }
+ }
+
+ size_type _size = {}; ///< Amount of elements in the underlying data container
+ size_type _capacity = {}; ///< Amount of space for elements in the underlying data container
+ value_type * _data = {}; ///< Pointer to the first element in the underlying data container
+ };
+
+} // namespace kstd
+
+#endif
diff --git a/libs/kstd/kstd.dox b/libs/kstd/kstd.dox
new file mode 100644
index 0000000..5920a3c
--- /dev/null
+++ b/libs/kstd/kstd.dox
@@ -0,0 +1,14 @@
+//! @namespace kstd
+//! The TeachOS Standard Library.
+//!
+//! This namespace provides implementation for Standard Library functionality that is not usually provided in a
+//! freestanding environment, since it relies on operating system support (e.g. memory allocation). The implementations
+//! found here, aim to be reasonably close to the specifications found in the C++ language standard (ISO14482).
+//! However, some differences exists, for example the lack of exceptions.
+
+//! @namespace kstd::ext
+//! Extensions to the Standard Library.
+//!
+//! This namespace includes custom extensions to what is defined for the C++ Standard Library. These extensions not
+//! portable per-se, since they are not implemented by other Standard Library implementations. Whenever possible,
+//! Standard Library conformant types, functions, etc. should be used throughout the TeachOS codebase.
diff --git a/libs/kstd/src/bits/os.cpp b/libs/kstd/src/bits/os.cpp
new file mode 100644
index 0000000..e6edbfd
--- /dev/null
+++ b/libs/kstd/src/bits/os.cpp
@@ -0,0 +1,10 @@
+#include "kstd/bits/os.hpp"
+
+namespace kstd::os
+{
+ [[gnu::weak, noreturn]]
+ auto abort() -> void
+ {
+ os::panic("Abort called.");
+ }
+} // namespace kstd::os \ No newline at end of file
diff --git a/libs/kstd/src/libc/stdlib.cpp b/libs/kstd/src/libc/stdlib.cpp
new file mode 100644
index 0000000..a0f062a
--- /dev/null
+++ b/libs/kstd/src/libc/stdlib.cpp
@@ -0,0 +1,19 @@
+#include "kstd/bits/os.hpp"
+
+namespace kstd::libc
+{
+
+ extern "C"
+ {
+ [[noreturn]] auto abort() -> void
+ {
+ kstd::os::abort();
+ }
+
+ [[noreturn, gnu::weak]] auto free(void *) -> void
+ {
+ kstd::os::panic("Tried to call free.");
+ }
+ }
+
+} // namespace kstd::libc \ No newline at end of file
diff --git a/libs/kstd/src/libc/string.cpp b/libs/kstd/src/libc/string.cpp
new file mode 100644
index 0000000..319f6fd
--- /dev/null
+++ b/libs/kstd/src/libc/string.cpp
@@ -0,0 +1,32 @@
+#include <algorithm>
+#include <bit>
+#include <cstddef>
+#include <iterator>
+#include <span>
+
+namespace kstd::libc
+{
+
+ extern "C"
+ {
+ auto strlen(char const * string) -> std::size_t
+ {
+ return std::distance(string, std::ranges::find(string, nullptr, '\0'));
+ }
+
+ auto memcmp(void const * lhs, void const * rhs, std::size_t size) -> std::size_t
+ {
+ auto left_span = std::span{static_cast<std::byte const *>(lhs), size};
+ auto right_span = std::span{static_cast<std::byte const *>(rhs), size};
+ auto mismatched = std::ranges::mismatch(left_span, right_span);
+
+ if (mismatched.in1 == left_span.end())
+ {
+ return 0;
+ }
+
+ return std::bit_cast<char>(*mismatched.in1) - std::bit_cast<char>(*mismatched.in2);
+ }
+ }
+
+} // namespace kstd::libc \ No newline at end of file
diff --git a/libs/kstd/src/mutex.cpp b/libs/kstd/src/mutex.cpp
new file mode 100644
index 0000000..5a26154
--- /dev/null
+++ b/libs/kstd/src/mutex.cpp
@@ -0,0 +1,24 @@
+#include "kstd/mutex"
+
+#include <atomic>
+
+namespace kstd
+{
+ auto mutex::lock() -> void
+ {
+ while (!try_lock())
+ {
+ asm volatile("nop");
+ }
+ }
+
+ auto mutex::try_lock() -> bool
+ {
+ return !locked.exchange(true, std::memory_order_acquire);
+ }
+
+ auto mutex::unlock() -> void
+ {
+ locked.store(false, std::memory_order_release);
+ }
+} // namespace kstd
diff --git a/libs/multiboot2/CMakeLists.txt b/libs/multiboot2/CMakeLists.txt
new file mode 100644
index 0000000..350a996
--- /dev/null
+++ b/libs/multiboot2/CMakeLists.txt
@@ -0,0 +1,27 @@
+add_library("multiboot2" INTERFACE)
+add_library("libs::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"
+)
+
+target_link_libraries("multiboot2" INTERFACE
+ "libs::elf"
+)
+
+set_target_properties("multiboot2" PROPERTIES
+ VERIFY_INTERFACE_HEADER_SETS YES
+) \ No newline at end of file
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