aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/include/arch/io/port_io.hpp1
-rw-r--r--arch/x86_64/include/arch/memory/frame_allocator.hpp86
-rw-r--r--arch/x86_64/include/arch/memory/multiboot.hpp345
-rw-r--r--arch/x86_64/src/kernel/main.cpp3
-rw-r--r--arch/x86_64/src/memory/multiboot.cpp41
5 files changed, 331 insertions, 145 deletions
diff --git a/arch/x86_64/include/arch/io/port_io.hpp b/arch/x86_64/include/arch/io/port_io.hpp
index c0f1ef3..1945261 100644
--- a/arch/x86_64/include/arch/io/port_io.hpp
+++ b/arch/x86_64/include/arch/io/port_io.hpp
@@ -8,7 +8,6 @@
namespace teachos::arch::io
{
-
/**
* @brief An I/O port of a given size at a given address.
*
diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp
index 35d7360..3989cdf 100644
--- a/arch/x86_64/include/arch/memory/frame_allocator.hpp
+++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp
@@ -4,6 +4,7 @@
#include "multiboot.hpp"
#include <cstddef>
#include <optional>
+#include <type_traits>
namespace teachos::arch::memory
{
@@ -12,51 +13,74 @@ namespace teachos::arch::memory
const std::size_t PAGE_FRAME_SIZE = 4096U;
}
+ /**
+ * @brief Specific frame containing helper functions to determine if a specific address is in that frame or not
+ */
struct frame
{
- std::size_t frame_number;
+ std::size_t frame_number; ///< Index number of the current frame, used to distinguish it from other frames
+ /**
+ * @brief Constructor
+ *
+ * @param frame_number Index number that should be assigned to this frame
+ */
frame(std::size_t frame_number)
: frame_number(frame_number)
{
// Nothing to do
}
+ /**
+ * @brief Returns the frame the given address is contained in
+ *
+ * @param address Address we want to get the corresponding frame for
+ * @return Frame the given address is contained in
+ */
static auto containing_address(std::size_t address) -> frame { return frame{address / PAGE_FRAME_SIZE}; }
- constexpr bool operator==(const frame & other) const noexcept { return frame_number == other.frame_number; }
- constexpr bool operator>(const frame & other) const noexcept { return frame_number > other.frame_number; }
- constexpr bool operator<(const frame & other) const noexcept { return frame_number < other.frame_number; }
- constexpr bool operator>=(const frame & other) const noexcept { return frame_number >= other.frame_number; }
- constexpr bool operator<=(const frame & other) const noexcept { return frame_number <= other.frame_number; }
- };
+ /**
+ * @brief Defaulted equals operator
+ */
+ constexpr auto operator==(const frame & other) const -> bool = default;
- struct frame_allocator
- {
- virtual auto allocate_frame() -> std::optional<frame> = 0;
- virtual auto deallocate_frame(frame frame) -> void = 0;
+ /**
+ * @brief Defaulted three-way comparsion operator
+ */
+ constexpr auto operator<=>(const frame & other) const -> std::partial_ordering = default;
};
- // TODO: FIX CONCEPT USAGE
- // template<typename T>
- // concept FrameAllocator = requires(T t) {
- // { t.allocate_frame() } -> std::optional<frame>;
- // { t.deallocate_frame() } -> void;
- // };
+ template<typename T>
+ concept FrameAllocator = requires(T t) {
+ { t.allocate_frame() } -> std::optional<frame>;
+ { t.deallocate_frame() } -> void;
+ };
- // template<FrameAllocator T>
- struct area_frame_allocator : frame_allocator
+ /**
+ * @brief Allocates memory using memory areas read from the multiboot2 information pointer
+ *
+ */
+ struct area_frame_allocator
{
- frame next_free_frame{0}; //!< The frame after the last allocated one
- std::optional<arch::memory::memory_area> current_area{std::nullopt}; //!< The current memory area
- arch::memory::memory_area * areas; //!< A list of all memory areas
- frame kernel_start; //!< The start address of the kernel code in memory
- frame kernel_end; //!< The end address of the kernel code in memory
- frame multiboot_start; //!< The start address of the multiboot code in memory
- frame multiboot_end; //!< The end address of the multiboot code in memory
+ frame next_free_frame{0}; //!< The frame after the last allocated one
+ std::optional<memory_area> current_area{std::nullopt}; //!< The current memory area
+ memory_area * areas; //!< Pointer to the first element of all memory areas
+ frame kernel_start; //!< The start address of the kernel code in memory
+ frame kernel_end; //!< The end address of the kernel code in memory
+ frame multiboot_start; //!< The start address of the multiboot code in memory
+ frame multiboot_end; //!< The end address of the multiboot code in memory
+ /**
+ * @brief Constructor
+ *
+ * @param kernel_start Start address of the kernel code in memory
+ * @param kernel_end End address of the kernel code in memory
+ * @param multiboot_start Start address of the multiboot code in memory
+ * @param multiboot_end End address of the multiboot code in memory
+ * @param memory_areas Pointer to the first element of all memory areas
+ */
area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start,
- std::size_t multiboot_end, arch::memory::memory_area * memory_areas)
+ std::size_t multiboot_end, memory_area * memory_areas)
: kernel_start(frame{kernel_start})
, kernel_end(frame{kernel_end})
, multiboot_start(frame{multiboot_start})
@@ -67,7 +91,7 @@ namespace teachos::arch::memory
}
/**
- * @brief Allocate memory be finding and returning a free frame
+ * @brief Allocate memory by finding and returning a free frame
*
* The frame allocation executes multiple checks before returning
* the frame that is available to allocate. It must at least
@@ -77,6 +101,12 @@ namespace teachos::arch::memory
* - update the next_free_frame after finding a free frame
*/
auto allocate_frame() -> std::optional<frame>;
+
+ /**
+ * @brief Deallocates a previously allocated frame
+ *
+ * @param frame Previously allocated frame that should be allocated
+ */
auto deallocate_frame(frame frame) -> void;
private:
diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp
index f6ff480..5990260 100644
--- a/arch/x86_64/include/arch/memory/multiboot.hpp
+++ b/arch/x86_64/include/arch/memory/multiboot.hpp
@@ -6,154 +6,264 @@
namespace teachos::arch::memory
{
- /*
- * Define all multiboot tag types to ther respective values
- * The gnu boot information format is defined here:
- * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format
+ /**
+ * @brief Defines all possible types a multiboot2 tag structure can have.
+ * See
+ * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format for more information.
*/
enum class multi_boot_tag_type : uint32_t
{
- END,
- CMDLINE,
- BOOT_LOADER_NAME,
- MODULE,
- BASIC_MEMORY_INFO,
- BOOTDEV,
- MEMORY_MAP,
- VBE,
- FRAMEBUFFER,
- ELF_SECTIONS,
- APM,
- EFI32,
- EFI64,
- SMBIOS,
- ACPI_OLD,
- ACPI_NEW,
- NETWORK,
- EFI_MEMORY_MAP,
- EFI_BS,
- EFI32_IH,
- EFI64_IH,
- LOAD_BASE_ADDRESS
+ END, ///< Signals final tag for the multiboot2 information structure
+ CMDLINE, ///< Contains the command line string
+ BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel
+ MODULE, ///< Indicates the boot module which was loaded along the kernel image
+ BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address)
+ BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from
+ MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags
+ VBE_INFO, ///< Includes information to access and utilize the device GPU
+ FRAMEBUFFER, ///< VBE framebuffer information
+ ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel
+ APM_INFO, ///< Advanced Power Management information
+ EFI32, ///< EFI 32 bit system table pointer
+ EFI64, ///< EFI 64 bit system table pointer
+ SMBIOS, ///< Contains copy of all Sytem Management BIOS tables
+ ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification
+ ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification
+ NETWORK, ///< Contains network information specified specified as DHCP
+ EFI_MEMORY_MAP, ///< Contains EFI memory map
+ EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called
+ EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer
+ EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer
+ LOAD_BASE_ADDRESS ///< Contains image load base physical address
};
+ /**
+ * @brief Basic structure that every entry in the multi_boot_tag array of the multi_boot_info struct has to begin
+ * with.
+ */
struct multi_boot_tag
{
- multi_boot_tag_type type;
- uint32_t size;
+ multi_boot_tag_type type; ///< Specific type of this multi_boot_tag entry, used to differentiate handling
+ uint32_t size; ///< Total size of this multi_boot_tag entry with all fields of the actual type
};
+ /**
+ * @brief Basic structure the multiboot_information_pointer points too and which contains all information of
+ * multiboot2 in the tags array of different types.
+ */
struct multi_boot_info
{
- uint32_t total_size;
- /*
- * field "tags" is an array of multi_boot_tag, however the array is never
- * being accessed by index we don't know the real size at compile-time,
- * and using an array definition with size 0 produces a compiler error.
- */
- alignas(8) struct multi_boot_tag tags;
+ uint32_t total_size; ///< Total size of all multi_boot_tags and their data
+ alignas(8) struct multi_boot_tag tags; ///< Specific tags
};
+ /**
+ * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type
+ * multi_boot_tag_type::BASIC_MEMORY_INFO.
+ */
struct memory_info
{
- multi_boot_tag tag;
- uint32_t mem_lower;
- uint32_t mem_upper;
+ multi_boot_tag tag; ///< Basic multi_boot_tag information
+ uint32_t mem_lower; ///< Amount of lower memory (0MB start address)
+ uint32_t mem_upper; ///< Amount of upper memory (1MB start address)
};
+ /**
+ * @brief Defines all memory area types possible that the memory region can be in.
+ */
enum class memory_area_type : uint32_t
{
- AVAILABLE = 1,
- RESERVED,
- ACPI_AVAILABLE,
- RESERVED_HIBERNATION,
- DEFECTIVE
+ AVAILABLE = 1, ///< Region is available for use by the OS
+ RESERVED, ///< Region is reserved by firmware or bootloader and should not be used by OS
+ ACPI_AVAILABLE, ///< Region is reclaimable by OS after ACPI event
+ RESERVED_HIBERNATION, ///< Region is used for Non-volatile Storage (NVS)
+ DEFECTIVE ///< Region is defective or unusable
};
+ /**
+ * @brief Defines an entry in the entries array of the memory_map struct.
+ */
struct memory_area
{
- uint64_t base_address;
- uint64_t area_length;
- alignas(8) memory_area_type type;
+ uint64_t base_address; ///< Base address the memory region starts at
+ uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address
+ alignas(8) memory_area_type type; ///< Specific type of memory the region can contain
};
+ /**
+ * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type
+ * multi_boot_tag_type::MEMORY_MAP.
+ */
struct memory_map
{
- multi_boot_tag tag;
- uint32_t entry_size;
- uint32_t entry_version;
- /*
- * field "entries" is an array of memory_area, however the array is never
- * being accessed by index, we don't know the real size at compile-time,
- * and using an array definition with size 0 produces a compiler error.
- */
- struct memory_area entries;
+ multi_boot_tag tag; ///< Basic multi_boot_tag information
+ uint32_t entry_size; ///< Size of each entry in the memory_area array. Guaranteed multiple of 8
+ uint32_t entry_version; ///< Version of the entries, currently 0
+ struct memory_area entries; ///< Specific memory regions
};
/**
- * https://refspecs.linuxfoundation.org/LSB_2.1.0/LSB-Core-generic/LSB-Core-generic/elftypes.html
+ * @brief Defines all elf section types an elf section header can have.
+ * The first section will always be INACTIVE, there can only ever be one DYNAMIC section and only either one
+ * DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html
+ * for more information.
*/
enum class elf_section_type : uint32_t
{
- INACTIVE,
- PROGRAMM,
- SYMBOL_TABLE,
- STRING_TABLE,
- RELOCATION_ENTRY_WITH_EXPLICIT_ADDENDS,
- SYMBOL_HASH_TABLE,
- DYNAMIC,
- NOTE,
- EMPTY,
- RELOCATION_ENTRY_WITHOUT_EXPLICIT_ADDENDS,
- UNSPECIFIED,
- DYNAMIC_SYMBOL,
- INITALIZATION_FUNCTION_ARRAY = 14,
- TERMINATION_FUNCTION_ARRAY,
- PRE_INITALIZATION_FUNCTION_ARRAY
+ INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out
+ PROGRAMM, ///< (SHT_PROGBITS) Program data
+ SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table
+ STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings
+ RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems
+ SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols
+ DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information
+ NOTE, ///< (SHT_NOTE) Stores information that marks files in some way
+ EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss)
+ RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems
+ UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics
+ DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking
+ INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void
+ TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void
+ PRE_INITALIZATION_FUNCTION_ARRAY ///< (SHT_PRE_INIT_ARRAY) Array of pointers to functions invoked before other
+ ///< initalization functions () -> void
};
/**
- * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html
+ * @brief Defines helper function for all states that the elf section flags of an elf section header can
+ * have. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html
+ * See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information.
*/
- class elf_section_flags
+ struct elf_section_flags
{
- public:
- elf_section_flags(uint64_t flags)
+ /**
+ * @brief Constructor.
+ *
+ * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to
+ * allow reading the state of single bits more easily.
+ */
+ explicit elf_section_flags(uint64_t flags)
: flags(flags)
{
// Nothing to do
}
- auto writeable() const -> bool { return is_bit_set(0); }
+ /**
+ * @brief (SHF_WRITE) Wether the current section is writable or not. Read from bit index 0.
+ *
+ * @return Current section is writable.
+ */
+ auto writeable() const -> bool;
- auto occupies_memory() const -> bool { return is_bit_set(1); }
+ /**
+ * @brief (SHF_ALLOC) Whether the current section occupies memory during execution or not. Read from bit index 1.
+ *
+ * @return Current section occupies memory during execution.
+ */
+ auto occupies_memory() const -> bool;
- auto is_executable() const -> bool { return is_bit_set(2); }
+ /**
+ * @brief (SHF_EXECINSTR) Whether the current section is executable or not. Read from bit index 2.
+ *
+ * @return Current section is executable.
+ */
+ auto is_executable() const -> bool;
- auto contains_duplicate_data() const -> bool { return is_bit_set(4); }
+ /**
+ * @brief (SHF_MERGE) Whether the current section might be merged with another section or not. Read from bit
+ * index 4.
+ *
+ * @return Current section might be merged with another section
+ */
+ auto contains_duplicate_data() const -> bool;
- auto contains_strings() const -> bool { return is_bit_set(5); }
+ /**
+ * @brief (SHF_STRINGS) Whether the current section contains null-terminated strings or not. Read from bit
+ * index 5.
+ *
+ * @return Current section contains null-terminated strings
+ */
+ auto contains_strings() const -> bool;
- auto section_header_info_is_section_header_table_index() const -> bool { return is_bit_set(6); }
+ /**
+ * @brief (SHF_INFO_LINK) Whether the current section contains the section header table index in the (sh_info)
+ * additional_information variable or not. Read from bit index 6.
+ *
+ * @return Current section contains the section header table index in the (sh_info)
+ * additional_information variable
+ */
+ auto section_header_info_is_section_header_table_index() const -> bool;
- auto preserve_ordering_after_combination() const -> bool { return is_bit_set(7); }
+ /**
+ * @brief (SHF_LINK_ORDER) Whether the current section preserves order after combining with another section or not.
+ * Read from bit index 7.
+ *
+ * @return Current section preserves order after combining with another section
+ */
+ auto preserve_ordering_after_combination() const -> bool;
- auto requires_special_os_processing() const -> bool { return is_bit_set(8); }
+ /**
+ * @brief (SHF_OS_NONCONFORMING) Whether the current section requires non-standard OS specific handling of its code
+ * or data, which does not confirm to standard ELF specifications. Read from bit index 8.
+ *
+ * @return Current section requires non-standard OS specific handling
+ */
+ auto requires_special_os_processing() const -> bool;
- auto is_section_group_member() const -> bool { return is_bit_set(9); }
+ /**
+ * @brief (SHF_GROUP) Whether the current section is a member of a section group or not. Read from bit index 9.
+ *
+ * @return Current section is a member of a section group
+ */
+ auto is_section_group_member() const -> bool;
- auto holds_thread_local_data() const -> bool { return is_bit_set(10); }
+ /**
+ * @brief (SHF_TLS) Whether the current section holds thread-local data or not. Read from bit
+ * index 10.
+ *
+ * @return Current section holds thread-local data
+ */
+ auto holds_thread_local_data() const -> bool;
- auto is_compressed() const -> bool { return is_bit_set(11); }
+ /**
+ * @brief (SHF_COMPRESSED) Whether the current section contains compressed data or not. Read from bit
+ * index 11.
+ *
+ * @return Current section contains compressed data
+ */
+ auto is_compressed() const -> bool;
- auto has_special_ordering_requirements() const -> bool { return is_bit_set(30); }
+ /**
+ * @brief (SHF_ORDERED) Whether the current section has special ordering requirements, meaning it should be ordered
+ * in relation to other sections of the same type. Read from bit index 30.
+ *
+ * @return current section has special ordering requirements
+ */
+ auto has_special_ordering_requirements() const -> bool;
- auto is_excluded_unless_referenced_or_allocated() const -> bool { return is_bit_set(31); }
+ /**
+ * @brief (SHF_EXCLUDE) Whether the current section is excluded unless refereenced or allocated, used for LTO
+ * (Link-Time Optimizations). Read from bit index 31.
+ *
+ * @return Current section is excluded unless refereenced or allocated
+ */
+ auto is_excluded_unless_referenced_or_allocated() const -> bool;
- auto operator==(elf_section_flags const & other) const -> bool { return flags == other.flags; }
+ /**
+ * @brief Allows to compare the underlying std::bitset of two instances
+ *
+ * @param other Other instance that we want to compare with
+ * @return Whether the underlying std::bitset of both types is the same
+ */
+ auto operator==(elf_section_flags const & other) const -> bool;
private:
- auto is_bit_set(uint8_t index) const -> bool { return flags[index] == 1; }
+ /**
+ * @brief Checks the underlying std::bitset if the bit at the specific index is set, meaning a value of 1
+ *
+ * @param index Specific index we want to check at
+ * @return Bit value 1 is set and will return true
+ */
+ auto is_bit_set(uint8_t index) const -> bool;
std::bitset<64U> flags;
};
@@ -164,41 +274,44 @@ namespace teachos::arch::memory
*/
struct elf_section_header
{
- uint32_t name_table_index;
- elf_section_type type;
- elf_section_flags flags;
- uint64_t virtual_address;
- uint64_t file_offset;
- uint64_t section_size;
- uint32_t other_section;
- uint32_t additional_information;
- uint64_t address_alignment;
- uint64_t fixed_table_entry_size;
-
- /**
- * @brief Detect whether e section header is inactive or not, should always be the case for the first entry in the
+ uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section
+ elf_section_type type; ///< Categorizes the sections content and semantics
+ elf_section_flags flags; ///< 1-bit flgas that describe section attributes
+ uint64_t virtual_address; ///< If section appears in memory image of a process, gives address at which the sections
+ ///< first byte should reside, otherwise 0
+ uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS
+ ///< contains the conceptual placement instead (because it occupies no space in the file)
+ uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always
+ ///< occupy no space in the file
+ uint32_t other_section; ///< Section header table index link, behaviour varies on type
+ ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link
+ uint32_t additional_information; ///< Extra information, behaviour varies on type
+ ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link
+ uint64_t address_alignment; ///< Possible address alignment constraints. Value of virutal_address must be 0 % value
+ ///< of address_alignment. Value 0 or 1 mean no alignment constraints
+ uint64_t fixed_table_entry_size; ///< If sections holds table with fixed-sized entries, this gives the size in
+ ///< bytes of each entry
+
+ /**
+ * @brief Detect whether a section header is inactive or not, should always be the case for the first entry in the
* sections table
* @return Whether the current section header is actually null or not, requires all fields besides section_size and
- * other_section to actually contain 0
+ * other_section to contain 0
*/
- auto is_null() const -> bool
- {
- return name_table_index == 0U && type == elf_section_type::UNSPECIFIED && flags == 0U && virtual_address == 0U &&
- file_offset == 0U && additional_information == 0U && address_alignment == 0U &&
- fixed_table_entry_size == 0U;
- }
+ auto is_null() const -> bool;
};
/**
- * https://gist.github.com/x0nu11byt3/bcb35c3de461e5fb66173071a2379779
+ * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type
+ * multi_boot_tag_type::ELF_SECTIONS.
*/
struct elf_symbols_section
{
- multi_boot_tag tag;
- uint32_t number_of_sections;
- uint32_t entry_size;
- uint32_t section_index;
- alignas(8) struct elf_section_header sections;
+ multi_boot_tag tag; ///< Basic multi_boot_tag information
+ uint32_t number_of_sections; ///< Number of sections in the sections array
+ uint32_t entry_size; ///< Size of each entry in the sections array
+ uint32_t section_index; ///< Index to the string table used for symbol names
+ alignas(8) struct elf_section_header sections; ///< Specific sectons
};
} // namespace teachos::arch::memory
diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp
index 2ba4fe2..6486b7c 100644
--- a/arch/x86_64/src/kernel/main.cpp
+++ b/arch/x86_64/src/kernel/main.cpp
@@ -63,6 +63,9 @@ namespace teachos::arch::kernel
// value should be zero :(
// assert(begin->is_null());
+ // TODO: Check if only contains one DYNSYM or SYMTAB but not both!
+ // TODO: Check if only contains one dynamic section
+
for (auto section = begin; section != end; ++section)
{
video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black);
diff --git a/arch/x86_64/src/memory/multiboot.cpp b/arch/x86_64/src/memory/multiboot.cpp
new file mode 100644
index 0000000..91e7550
--- /dev/null
+++ b/arch/x86_64/src/memory/multiboot.cpp
@@ -0,0 +1,41 @@
+#include "multiboot.hpp"
+
+namespace teachos::arch::memory
+{
+ auto elf_section_flags::writeable() const -> bool { return is_bit_set(0); }
+
+ auto elf_section_flags::occupies_memory() const -> bool { return is_bit_set(1); }
+
+ auto elf_section_flags::is_executable() const -> bool { return is_bit_set(2); }
+
+ auto elf_section_flags::contains_duplicate_data() const -> bool { return is_bit_set(4); }
+
+ auto elf_section_flags::contains_strings() const -> bool { return is_bit_set(5); }
+
+ auto elf_section_flags::section_header_info_is_section_header_table_index() const -> bool { return is_bit_set(6); }
+
+ auto elf_section_flags::preserve_ordering_after_combination() const -> bool { return is_bit_set(7); }
+
+ auto elf_section_flags::requires_special_os_processing() const -> bool { return is_bit_set(8); }
+
+ auto elf_section_flags::is_section_group_member() const -> bool { return is_bit_set(9); }
+
+ auto elf_section_flags::holds_thread_local_data() const -> bool { return is_bit_set(10); }
+
+ auto elf_section_flags::is_compressed() const -> bool { return is_bit_set(11); }
+
+ auto elf_section_flags::has_special_ordering_requirements() const -> bool { return is_bit_set(30); }
+
+ auto elf_section_flags::is_excluded_unless_referenced_or_allocated() const -> bool { return is_bit_set(31); }
+
+ auto elf_section_flags::operator==(elf_section_flags const & other) const -> bool { return flags == other.flags; }
+
+ auto elf_section_flags::is_bit_set(uint8_t index) const -> bool { return flags[index] == 1; }
+
+ auto elf_section_header::is_null() const -> bool
+ {
+ return name_table_index == 0U && type == elf_section_type::UNSPECIFIED &&
+ flags == teachos::arch::memory::elf_section_flags{0U} && virtual_address == 0U && file_offset == 0U &&
+ additional_information == 0U && address_alignment == 0U && fixed_table_entry_size == 0U;
+ }
+} // namespace teachos::arch::memory