From a2fdcea0d7615f8933401e45e0c64a2f618bb730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 19 Oct 2024 13:15:45 +0000 Subject: Move compelte multiboot2 code into seperate files and behaviour into seperate static class --- arch/x86_64/CMakeLists.txt | 4 +- .../x86_64/include/arch/memory/frame_allocator.hpp | 84 ++----- arch/x86_64/include/arch/memory/multiboot.hpp | 262 --------------------- .../arch/memory/multiboot/elf_sybols_section.hpp | 157 ++++++++++++ arch/x86_64/include/arch/memory/multiboot/info.hpp | 62 +++++ .../include/arch/memory/multiboot/memory_map.hpp | 93 ++++++++ .../include/arch/memory/multiboot/reader.hpp | 50 ++++ arch/x86_64/include/arch/memory/paging.hpp | 5 + arch/x86_64/src/kernel/main.cpp | 151 +----------- arch/x86_64/src/memory/frame_allocator.cpp | 44 +--- arch/x86_64/src/memory/multiboot.cpp | 13 - .../src/memory/multiboot/elf_symbols_section.cpp | 13 + arch/x86_64/src/memory/multiboot/memory_map.cpp | 24 ++ arch/x86_64/src/memory/multiboot/reader.cpp | 117 +++++++++ 14 files changed, 555 insertions(+), 524 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/multiboot.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/info.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/memory_map.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/reader.hpp delete mode 100644 arch/x86_64/src/memory/multiboot.cpp create mode 100644 arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp create mode 100644 arch/x86_64/src/memory/multiboot/memory_map.cpp create mode 100644 arch/x86_64/src/memory/multiboot/reader.cpp (limited to 'arch/x86_64') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 3f67d71..7ddf303 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -41,7 +41,9 @@ target_sources("_video" PRIVATE #]============================================================================] target_sources("_memory" PRIVATE - "src/memory/multiboot.cpp" + "src/memory/multiboot/elf_symbols_section.cpp" + "src/memory/multiboot/memory_map.cpp" + "src/memory/multiboot/reader.cpp" "src/memory/frame_allocator.cpp" "src/memory/paging.cpp" ) diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index 89f2570..f1096d1 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -1,7 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP #define TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP -#include "multiboot.hpp" +#include "multiboot/reader.hpp" + #include #include #include @@ -17,7 +18,7 @@ namespace teachos::arch::memory struct physical_frame { /** - * @brief Constructor + * @brief Constructor. * * @param frame_number Index number that should be assigned to this physical_frame. */ @@ -32,9 +33,9 @@ namespace teachos::arch::memory static auto containing_address(std::size_t address) -> physical_frame; /** - * @brief Evaluates the start address of the physical frame + * @brief Evaluates the start address of the physical frame. * - * @return start address of the physical frame + * @return start address of the physical frame. */ auto start_address() const -> uint64_t; @@ -58,51 +59,6 @@ namespace teachos::arch::memory { t.deallocate_frame() } -> std::same_as; }; - /** - * @brief Iterator for memory areas. - */ - struct memory_area_iterator - { - /** - * @brief Constructor. - * - * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer. - */ - explicit memory_area_iterator(memory_area * p); - - /** - * @brief Dereferences the initally given pointer to its value. - * - * @return Reference to the value. - */ - memory_area & operator*() const; - - /** - * @brief Post increment operator. Returns a copy of the value - * - * @return Copy of the incremented underlying address. - */ - memory_area_iterator operator++(int); - - /** - * @brief Pre increment operator. Returns a reference to the changed value. - * - * @return Reference to the incremented underlying address. - */ - memory_area_iterator & operator++(); - - /** - * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. - * - * @param other Other iterator to compare to. - * @return Whether poith iterators point to the same underlying address in memory. - */ - bool operator==(memory_area_iterator const & other) const = default; - - private: - memory_area * ptr; ///< Underlying address the iterator is currently pointing too. - }; - /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ @@ -111,15 +67,9 @@ namespace teachos::arch::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. - * @param area_count Amount of total entries in the memory_areas array. + * @param mem_info Structure containg all relevant information to map and allocate memory */ - area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, - std::size_t multiboot_end, memory_area * memory_areas, uint8_t area_count); + area_frame_allocator(multiboot::memory_information mem_info); /** * @brief Allocate memory by finding and returning a free physical_frame. @@ -146,7 +96,7 @@ namespace teachos::arch::memory * * @return Iterator pointing to first element of the memory area. */ - auto begin() -> memory_area_iterator; + auto begin() -> multiboot::memory_area_iterator; /** * @brief Returns the iterator pointing to one past the last element of the memory area. @@ -154,7 +104,7 @@ namespace teachos::arch::memory * * @return Iterator pointing to one past the last element of the memory area. */ - auto end() -> memory_area_iterator; + auto end() -> multiboot::memory_area_iterator; private: /** @@ -162,14 +112,14 @@ namespace teachos::arch::memory */ auto choose_next_area() -> void; - physical_frame next_free_frame; ///< The physical_frame after the last allocated one. - std::optional current_area; ///< The current memory area. - memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. - memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. - physical_frame const kernel_start; ///< The start address of the kernel code in memory. - physical_frame const kernel_end; ///< The end address of the kernel code in memory. - physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. - physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. + physical_frame next_free_frame; ///< The physical_frame after the last allocated one. + std::optional current_area; ///< The current memory area. + multiboot::memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. + multiboot::memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. + physical_frame const kernel_start; ///< The start address of the kernel code in memory. + physical_frame const kernel_end; ///< The end address of the kernel code in memory. + physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. + physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp deleted file mode 100644 index 8ecb1b5..0000000 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ /dev/null @@ -1,262 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP - -#include -#include - -namespace teachos::arch::memory -{ - /** - * @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, ///< 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; ///< 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. The start as well as the content has to be 8 byte aligned. - */ - struct multi_boot_info - { - 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; ///< 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, ///< 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. Has to have all padding stripped between the - * individual values, because the size of the entry needs to be exactly 24 bytes and not one byte more. See - * https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Packed-Structures.html for more information on the - * used attribute. - */ - struct __attribute__((packed)) memory_area - { - uint32_t size; ///< TODO: Not clear what exactly the size signifies - 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 - memory_area_type type; ///< Specific type of memory the region can contain - }; - /*struct memory_area - { - 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 - 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; ///< 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 - }; - - /** - * @brief Defines all elf section types an elf section header can have. 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, ///< (SHT_NULL) Unused, meaning all values are zeroed out - PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) - 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 - }; - - /** - * @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. - */ - struct elf_section_flags - { - /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. - */ - enum bitset : uint32_t - { - WRITABLE = 1U << 0U, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section - ///< is assumed to be READONLY and only that flag is shown in the objdump. - OCCUPIES_MEMORY = 1U << 1U, ///< (SHF_ALLOC) Section occupies memory during execution. - ///< ALLOC flag is shown in the objdump. - EXECUTABLE_CODE = 1U << 2U, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. - DUPLICATE_DATA = 1U << 4U, ///< (SHF_MERGE) Section might be merged with another section. - CONTAINS_STRING = 1U << 5U, ///< (SHF_STRINGS) Section contains null-terminated strings. - SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX = - 1U << 6U, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) - ///< additional_information variable. - PRESERVE_ORDERING_AFTER_COMBINATION = - 1U << 7U, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. - REQUIRES_SPECIAL_OS_PROCESSING = - 1U << 8U, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or - ///< data, which does not confirm to standard ELF specifications. - SECTION_GROUP_MEMBER = 1U << 9U, ///< (SHF_GROUP) Section is a member of a section group. - HOLDS_THREAD_LOCAL_DATA = 1U << 10U, ///< (SHF_TLS) Section holds thread-local data. - COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data. - SPECIAL_ORDERING_REQUIREMENTS = - 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it - ///< should be ordered in relation to other sections of the same type - EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or - ///< allocated, used for LTO (Link-Time Optimizations) - }; - - /** - * @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 - } - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all - * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits - * that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying std::bitset - */ - auto contains_flags(std::bitset<64U> other) const -> bool; - - /** - * @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 = default; - - private: - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 21 - 28 are reserved for operating - ///< system specific semantics and bits 29 - 32 are reserved for processor specific - ///< semantics. Bits 33 - 64 are unused for compatability with ELF32. - }; - - /** - * @brief Defines the data included in a section header, where each section has exactly one section header. - * See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information - */ - struct elf_section_header - { - 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 contain 0 - */ - auto is_null() const -> bool; - }; - - /** - * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type - * multi_boot_tag_type::ELF_SECTIONS. - * The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section and - * only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. - */ - struct elf_symbols_section - { - 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 - std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data - ///< contained in the section, to ensure byte alignment is actually 4 byte - }; -} // namespace teachos::arch::memory - -#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp new file mode 100644 index 0000000..88d211e --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp @@ -0,0 +1,157 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP + +#include "info.hpp" +#include +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Defines all elf section types an elf section header can have. 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, ///< (SHT_NULL) Unused, meaning all values are zeroed out + PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) + 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 + }; + + /** + * @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. + */ + struct elf_section_flags + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint32_t + { + WRITABLE = 1U << 0U, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section + ///< is assumed to be READONLY and only that flag is shown in the objdump. + OCCUPIES_MEMORY = 1U << 1U, ///< (SHF_ALLOC) Section occupies memory during execution. + ///< ALLOC flag is shown in the objdump. + EXECUTABLE_CODE = 1U << 2U, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. + DUPLICATE_DATA = 1U << 4U, ///< (SHF_MERGE) Section might be merged with another section. + CONTAINS_STRING = 1U << 5U, ///< (SHF_STRINGS) Section contains null-terminated strings. + SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX = + 1U << 6U, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) + ///< additional_information variable. + PRESERVE_ORDERING_AFTER_COMBINATION = + 1U << 7U, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. + REQUIRES_SPECIAL_OS_PROCESSING = + 1U << 8U, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or + ///< data, which does not confirm to standard ELF specifications. + SECTION_GROUP_MEMBER = 1U << 9U, ///< (SHF_GROUP) Section is a member of a section group. + HOLDS_THREAD_LOCAL_DATA = 1U << 10U, ///< (SHF_TLS) Section holds thread-local data. + COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data. + SPECIAL_ORDERING_REQUIREMENTS = + 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it + ///< should be ordered in relation to other sections of the same type + EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or + ///< allocated, used for LTO (Link-Time Optimizations) + }; + + /** + * @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 + } + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all + * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits + * that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset + */ + auto contains_flags(std::bitset<64U> other) const -> bool; + + /** + * @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 = default; + + private: + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 21 - 28 are reserved for operating + ///< system specific semantics and bits 29 - 32 are reserved for processor specific + ///< semantics. Bits 33 - 64 are unused for compatability with ELF32. + }; + + /** + * @brief Defines the data included in a section header, where each section has exactly one section header. + * See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information + */ + struct elf_section_header + { + 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 contain 0 + */ + auto is_null() const -> bool; + }; + + /** + * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type + * multi_boot_tag_type::ELF_SECTIONS. + * The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section and + * only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. + */ + struct elf_symbols_section_header + { + tag info; ///< 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 + std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data + ///< contained in the section, to ensure byte alignment is actually 4 byte + }; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/info.hpp b/arch/x86_64/include/arch/memory/multiboot/info.hpp new file mode 100644 index 0000000..ca87834 --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/info.hpp @@ -0,0 +1,62 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP + +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Defines all possible types a multiboot2 tag structure can have. + * See + * https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot2.h for more information on the structure of the + * tag headers and see https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot.h for more information on the + * actual header contents and their following data. + */ + enum class tag_type : 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 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 tag + { + 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. The start as well as the content has to be 8 byte aligned. + */ + struct info_header + { + uint32_t total_size; ///< Total size of all multiboot::tags and their data + alignas(8) struct tag tags; ///< Specific tags + }; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp new file mode 100644 index 0000000..4dc11cf --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -0,0 +1,93 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP + +#include "info.hpp" +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Defines all memory area types possible that the memory region can be in. + */ + enum class memory_area_type : uint32_t + { + 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. Has to have all padding stripped between the + * individual values, because the size of the entry needs to be exactly 24 bytes and not one byte more. See + * https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Packed-Structures.html for more information on the + * used attribute. + */ + struct __attribute__((packed)) memory_area + { + uint32_t size; ///< Size of this structure in bytes + 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 + 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_header + { + tag info; ///< 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 + }; + + /** + * @brief Iterator for memory areas. + */ + struct memory_area_iterator + { + /** + * @brief Constructor. + * + * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer. + */ + explicit memory_area_iterator(memory_area * p); + + /** + * @brief Dereferences the initally given pointer to its value. + * + * @return Reference to the value. + */ + memory_area & operator*() const; + + /** + * @brief Post increment operator. Returns a copy of the value + * + * @return Copy of the incremented underlying address. + */ + memory_area_iterator operator++(int); + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying address. + */ + memory_area_iterator & operator++(); + + /** + * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether poith iterators point to the same underlying address in memory. + */ + bool operator==(memory_area_iterator const & other) const = default; + + private: + memory_area * ptr; ///< Underlying address the iterator is currently pointing too. + }; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp new file mode 100644 index 0000000..14086a7 --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -0,0 +1,50 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP + +#include "elf_sybols_section.hpp" +#include "memory_map.hpp" +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Contains all relevant information to map and allocate memory that is read from the multiboot2 information + * structure. + */ + struct memory_information + { + std::size_t kernel_start; ///< Start address of the kernel code in memory. + std::size_t kernel_end; ///< End address of the kernel code in memory. + std::size_t multiboot_start; ///< Start address of the multiboot code in memory. + std::size_t multiboot_end; ///< End address of the multiboot code in memory. + memory_area * memory_areas; ///< Non-owning pointer to the first element of all memory areas. + uint8_t area_count; ///< Amount of total entries in the memory_areas array. + }; + + /** + * @brief Reads the relevant multiboot2 information data from memory. This is done using the + * multiboot_information_pointer, which marks the start of the multiboot2 data. The indivdual headers we have to read + * are 8 byte aligned, whereas the data contained in those headers does not have to be. All sections that are read + * additionaly receive some sanity to ensure the read address is actually pointing to the expected structure, if they + * are not this method will assert. + * + * The memory_information variables are calcualted like this: + * - kernel_start: Calculated by getting the lowest address specified in the elf symbols headers. + * - kernel_end: Calculated by getting the highest address specified in the elf symbols headers and adding the length + * of that section. + * - multiboot_start: Calcualted by simply getting the value of the multiboot information pointer, because it already + * contains the address pointint to the start of the multiboot2 data. + * - multiboot_end: Calcualted by getting the value of the multiboot information pointer and adding the total size of + * the complete multiboot2 data + * - memory_areas: Calculated by simply accessing the address of the entries variable in the memory map header + * structure. + * - area_count: Calculated by subtracing the memory map header size from the total tag size, which results in the + * remaining size (size of the entries array), this size is then divided by the size of one entry in that array, which + * should be 24 bytes. + * + * @return Relevant data read from multiboot2. + */ + auto read_multiboot2() -> memory_information; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 4bbb0e0..04c2065 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -4,6 +4,7 @@ #include "arch/exception_handling/assert.hpp" #include "frame_allocator.hpp" +#include namespace teachos::arch::memory { @@ -113,6 +114,10 @@ namespace teachos::arch::memory template struct page_table { + /** + * @brief Level of the page table, level 1 should not be able to call next_table anymore, because it would result in + * attempting to access memory that it should not. + */ enum level : uint8_t { LEVEL1, diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index babe251..c0d4aed 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,120 +1,14 @@ #include "arch/kernel/main.hpp" -#include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/memory/frame_allocator.hpp" -#include "arch/memory/multiboot.hpp" +#include "arch/memory/multiboot/reader.hpp" #include "arch/video/vga/text.hpp" #include namespace teachos::arch::kernel { - auto process_memory_map(arch::memory::memory_map * mminfo, arch::memory::memory_area *& memory_areas, - uint8_t & area_count) -> void - { - auto expected_entry_size = mminfo->entry_size; - constexpr auto actual_entry_size = sizeof(arch::memory::memory_area); - arch::exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected memoryarea entry size"); - - auto total_size = mminfo->tag.size; - auto total_entries_size = total_size - sizeof(arch::memory::memory_map) + actual_entry_size; - auto number_of_entries = total_entries_size / actual_entry_size; - - memory_areas = &mminfo->entries; - area_count = number_of_entries; - } - - auto process_elf_sections(arch::memory::elf_symbols_section * symbol, uint64_t & kernel_start, - uint64_t & kernel_end) -> void - { - auto expected_entry_size = symbol->entry_size; - constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); - arch::exception_handling::assert(expected_entry_size == actual_entry_size, - "Unexpected elf_section_header entry size"); - - auto expected_total_size = symbol->tag.size; - auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; - constexpr auto actual_total_section_size = sizeof(arch::memory::elf_symbols_section) - sizeof(uint32_t); - auto actual_total_size = actual_total_entry_size + actual_total_section_size; - arch::exception_handling::assert(expected_total_size == actual_total_size, "Unexpected elf_symbols total size"); - - auto begin = reinterpret_cast(&symbol->end); - auto end = begin + symbol->number_of_sections; - arch::exception_handling::assert(begin->is_null(), "Missing elf_section_header begin"); - - std::size_t symbol_table_section_count = 0U; - std::size_t dynamic_section_count = 0U; - - for (auto section = begin; section != end; ++section) - { - bool const writable = section->flags.contains_flags(arch::memory::elf_section_flags::WRITABLE); - bool const occupies_memory = section->flags.contains_flags(arch::memory::elf_section_flags::OCCUPIES_MEMORY); - bool const is_executable = section->flags.contains_flags(arch::memory::elf_section_flags::EXECUTABLE_CODE); - bool const contains_duplicate_data = - section->flags.contains_flags(arch::memory::elf_section_flags::DUPLICATE_DATA); - bool const contains_strings = section->flags.contains_flags(arch::memory::elf_section_flags::CONTAINS_STRING); - bool const section_header_info_is_section_header_table_index = section->flags.contains_flags( - arch::memory::elf_section_flags::SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX); - bool const preserve_ordering_after_combination = - section->flags.contains_flags(arch::memory::elf_section_flags::PRESERVE_ORDERING_AFTER_COMBINATION); - bool const requires_special_os_processing = - section->flags.contains_flags(arch::memory::elf_section_flags::REQUIRES_SPECIAL_OS_PROCESSING); - bool const is_section_group_member = - section->flags.contains_flags(arch::memory::elf_section_flags::SECTION_GROUP_MEMBER); - bool const holds_thread_local_data = - section->flags.contains_flags(arch::memory::elf_section_flags::HOLDS_THREAD_LOCAL_DATA); - bool const is_compressed = section->flags.contains_flags(arch::memory::elf_section_flags::COMPRESSED); - bool const has_special_ordering_requirements = - section->flags.contains_flags(arch::memory::elf_section_flags::SPECIAL_ORDERING_REQUIREMENTS); - bool const is_excluded_unless_referenced_or_allocated = - section->flags.contains_flags(arch::memory::elf_section_flags::EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED); - - if (writable && occupies_memory && is_executable && contains_duplicate_data && contains_strings && - section_header_info_is_section_header_table_index && preserve_ordering_after_combination && - requires_special_os_processing && is_section_group_member && holds_thread_local_data && is_compressed && - has_special_ordering_requirements && is_excluded_unless_referenced_or_allocated) - { - } - - switch (section->type) - { - case arch::memory::elf_section_type::PROGRAMM: { - if (section->virtual_address < kernel_start) - { - kernel_start = section->virtual_address; - } - auto virtual_address_end = section->virtual_address + section->section_size; - if (virtual_address_end > kernel_end) - { - kernel_end = virtual_address_end; - } - break; - } - case arch::memory::elf_section_type::DYNAMIC_SYMBOL_TABLE: - case arch::memory::elf_section_type::SYMBOL_TABLE: - symbol_table_section_count++; - break; - case arch::memory::elf_section_type::DYNAMIC: - dynamic_section_count++; - break; - default: - // All other cases are not important and can be ignored - break; - } - } - - arch::exception_handling::assert(symbol_table_section_count == 1U, "Unexpected symbol_table_count value"); - arch::exception_handling::assert(dynamic_section_count <= 1U, "Unexpected dynamic_section_count value"); - } - - template - requires std::is_pointer::value - auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T - { - return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); - } - auto main() -> void { using namespace video::vga; @@ -123,47 +17,8 @@ namespace teachos::arch::kernel text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); - auto * multiboot_information_pointer = - reinterpret_cast(arch::boot::multiboot_information_pointer); - auto multiboot_tag = &(multiboot_information_pointer->tags); - - uint64_t kernel_start = UINT64_MAX; - uint64_t kernel_end = 0; - uint64_t multiboot_start = arch::boot::multiboot_information_pointer; - uint64_t multiboot_end = multiboot_start + multiboot_information_pointer->total_size; - arch::memory::memory_area * memory_areas = nullptr; - uint8_t area_count = 0; - - /* - * Loop over the multiboot2 tags to access the information needed. - * Tags are defined in the header file and are padded so that each - * Tag starts at an 8-bytes aligned adress. - * - * The increment part aligns the size to an 8-byte address. - */ - for (auto tag = multiboot_tag; tag->type != arch::memory::multi_boot_tag_type::END; - tag = align_to_8_byte_boundary(tag, tag->size)) - { - switch (tag->type) - { - case arch::memory::multi_boot_tag_type::ELF_SECTIONS: { - auto symbol = reinterpret_cast(tag); - process_elf_sections(symbol, kernel_start, kernel_end); - break; - } - case arch::memory::multi_boot_tag_type::MEMORY_MAP: { - auto mminfo = reinterpret_cast(tag); - process_memory_map(mminfo, memory_areas, area_count); - break; - } - default: - // All other cases are not important and can be ignored - break; - } - } - - auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end, - memory_areas, area_count); + auto memory_information = memory::multiboot::read_multiboot2(); + auto allocator = memory::area_frame_allocator(memory_information); auto last_allocated = allocator.allocate_frame(); auto allocated = last_allocated; diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index 70276ae..7776082 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -17,37 +17,15 @@ namespace teachos::arch::memory auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_FRAME_SIZE; } - memory_area_iterator::memory_area_iterator(memory_area * p) - : ptr(p) - { - // Nothing to do - } - - memory_area & memory_area_iterator::operator*() const { return *ptr; } - - auto memory_area_iterator::operator++(int) -> memory_area_iterator - { - ++(*this); - return *this; - } - - auto memory_area_iterator::operator++() -> memory_area_iterator & - { - ++ptr; - return *this; - } - - area_frame_allocator::area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, - std::size_t multiboot_start, std::size_t multiboot_end, - memory_area * memory_areas, uint8_t area_count) + area_frame_allocator::area_frame_allocator(multiboot::memory_information mem_info) : next_free_frame(0) , current_area(std::nullopt) - , area_begin(memory_areas) - , area_end(memory_areas + area_count) - , kernel_start(physical_frame::containing_address(kernel_start)) - , kernel_end(physical_frame::containing_address(kernel_end)) - , multiboot_start(physical_frame::containing_address(multiboot_start)) - , multiboot_end(physical_frame::containing_address(multiboot_end)) + , area_begin(mem_info.memory_areas) + , area_end(mem_info.memory_areas + mem_info.area_count) + , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) + , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) + , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) + , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) { choose_next_area(); } @@ -56,9 +34,9 @@ namespace teachos::arch::memory { current_area = std::nullopt; - for (memory_area_iterator it = begin(); it != end(); ++it) + for (multiboot::memory_area_iterator it = begin(); it != end(); ++it) { - memory_area & area = *it; + multiboot::memory_area & area = *it; std::size_t address = area.base_address + area.area_length - 1; if (physical_frame::containing_address(address) >= next_free_frame) @@ -126,7 +104,7 @@ namespace teachos::arch::memory "[deallocate_frame] Not implemented Exception"); } - auto area_frame_allocator::begin() -> memory_area_iterator { return area_begin; } + auto area_frame_allocator::begin() -> multiboot::memory_area_iterator { return area_begin; } - auto area_frame_allocator::end() -> memory_area_iterator { return area_end; } + auto area_frame_allocator::end() -> multiboot::memory_area_iterator { return area_end; } } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/multiboot.cpp b/arch/x86_64/src/memory/multiboot.cpp deleted file mode 100644 index 8c6793e..0000000 --- a/arch/x86_64/src/memory/multiboot.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/memory/multiboot.hpp" - -namespace teachos::arch::memory -{ - auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } - - auto elf_section_header::is_null() const -> bool - { - return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == 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 diff --git a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp new file mode 100644 index 0000000..78ab952 --- /dev/null +++ b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp @@ -0,0 +1,13 @@ +#include "arch/memory/multiboot/elf_sybols_section.hpp" + +namespace teachos::arch::memory::multiboot +{ + auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } + + auto elf_section_header::is_null() const -> bool + { + return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == 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::multiboot diff --git a/arch/x86_64/src/memory/multiboot/memory_map.cpp b/arch/x86_64/src/memory/multiboot/memory_map.cpp new file mode 100644 index 0000000..6b1d1d4 --- /dev/null +++ b/arch/x86_64/src/memory/multiboot/memory_map.cpp @@ -0,0 +1,24 @@ +#include "arch/memory/multiboot/memory_map.hpp" + +namespace teachos::arch::memory::multiboot +{ + memory_area_iterator::memory_area_iterator(multiboot::memory_area * p) + : ptr(p) + { + // Nothing to do + } + + multiboot::memory_area & memory_area_iterator::operator*() const { return *ptr; } + + auto memory_area_iterator::operator++(int) -> memory_area_iterator + { + ++(*this); + return *this; + } + + auto memory_area_iterator::operator++() -> memory_area_iterator & + { + ++ptr; + return *this; + } +} // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp new file mode 100644 index 0000000..8741b44 --- /dev/null +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -0,0 +1,117 @@ +#include "arch/memory/multiboot/reader.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/multiboot/info.hpp" + +namespace teachos::arch::memory::multiboot +{ + namespace + { + template + requires std::is_pointer::value + auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T + { + return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); + } + + auto process_memory_map(memory_map_header * mminfo, memory_area *& memory_areas, uint8_t & area_count) -> void + { + auto expected_entry_size = mminfo->entry_size; + constexpr auto actual_entry_size = sizeof(memory_area); + arch::exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected memory_area entry size"); + + auto total_size = mminfo->info.size; + auto total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; + auto number_of_entries = total_entries_size / actual_entry_size; + + memory_areas = &mminfo->entries; + area_count = number_of_entries; + } + + auto process_elf_sections(elf_symbols_section_header * symbol, uint64_t & kernel_start, + uint64_t & kernel_end) -> void + { + auto expected_entry_size = symbol->entry_size; + constexpr auto actual_entry_size = sizeof(elf_section_header); + arch::exception_handling::assert(expected_entry_size == actual_entry_size, + "Unexpected elf_section_header entry size"); + + auto expected_total_size = symbol->info.size; + auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; + constexpr auto actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); + auto actual_total_size = actual_total_entry_size + actual_total_section_size; + arch::exception_handling::assert(expected_total_size == actual_total_size, + "Unexpected elf_symbols_section_header total size"); + + auto begin = reinterpret_cast(&symbol->end); + auto end = begin + symbol->number_of_sections; + arch::exception_handling::assert(begin->is_null(), "Missing elf_section_header begin"); + + std::size_t symbol_table_section_count = 0U; + std::size_t dynamic_section_count = 0U; + + for (auto section = begin; section != end; ++section) + { + switch (section->type) + { + case elf_section_type::PROGRAMM: { + if (section->virtual_address < kernel_start) + { + kernel_start = section->virtual_address; + } + auto virtual_address_end = section->virtual_address + section->section_size; + if (virtual_address_end > kernel_end) + { + kernel_end = virtual_address_end; + } + break; + } + case elf_section_type::DYNAMIC_SYMBOL_TABLE: + case elf_section_type::SYMBOL_TABLE: + symbol_table_section_count++; + break; + case elf_section_type::DYNAMIC: + dynamic_section_count++; + break; + default: + // All other cases are not important and can be ignored + break; + } + } + + arch::exception_handling::assert(symbol_table_section_count == 1U, "Unexpected symbol_table_count value"); + arch::exception_handling::assert(dynamic_section_count <= 1U, "Unexpected dynamic_section_count value"); + } + } // namespace + + auto read_multiboot2() -> memory_information + { + memory_information mem_info{UINT64_MAX, 0U, boot::multiboot_information_pointer, 0U, nullptr, 0U}; + + auto * multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); + auto multiboot_tag = &(multiboot_information_pointer->tags); + mem_info.multiboot_end = mem_info.multiboot_start + multiboot_information_pointer->total_size; + + for (auto tag = multiboot_tag; tag->type != tag_type::END; tag = align_to_8_byte_boundary(tag, tag->size)) + { + switch (tag->type) + { + case tag_type::ELF_SECTIONS: { + auto symbol = reinterpret_cast(tag); + process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); + break; + } + case tag_type::MEMORY_MAP: { + auto mminfo = reinterpret_cast(tag); + process_memory_map(mminfo, mem_info.memory_areas, mem_info.area_count); + break; + } + default: + // All other cases are not important and can be ignored + break; + } + } + return mem_info; + } +} // namespace teachos::arch::memory::multiboot -- cgit v1.2.3