#include "arch/kernel/main.hpp" #include "arch/boot/pointers.hpp" #include "arch/memory/frame_allocator.hpp" #include "arch/memory/multiboot.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::kernel { auto assert(bool condition) -> void { if (condition) { return; } video::vga::text::write("Assert failed", video::vga::text::common_attributes::green_on_black); for (;;) { // Trick the compiler into thinking the variable is changes at run time, // to prevent the while loop being optimized away // See // https://stackoverflow.com/questions/9495856/how-to-prevent-g-from-optimizing-out-a-loop-controlled-by-a-variable-that-can // for more information. asm volatile("" : "+g"(condition)); } } 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); assert(expected_entry_size == actual_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); assert(expected_entry_size == actual_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; assert(expected_total_size == actual_total_size); auto begin = reinterpret_cast(&symbol->end); auto end = begin + symbol->number_of_sections; assert(begin->is_null()); 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 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; } } assert(symbol_table_section_count == 1U); assert(dynamic_section_count <= 1U); } auto main() -> void { using namespace video::vga; text::clear(); 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 = reinterpret_cast((reinterpret_cast(tag)) + ((tag->size + 7) & ~7))) { 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; } } // Kernel start 0x100000 // Kernel end 0x23E943 // Kernel Size 0x13E943 -> 1'304'899 // Multiboot start 0x241AA0 // Multiboot end 0x242280 // Multiboot Size 0x7E0 -> 2'016 // Memory area start 0x241b10 // // Address of Frame: 0x203F00 auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end, memory_areas, area_count); auto allocated = allocator.allocate_frame(); // WATCH OUT: using optional::value() crashes the build... I think its because of missing exception handling if (allocated.has_value()) { video::vga::text::write("Allocated Frame address: ", video::vga::text::common_attributes::green_on_black); video::vga::text::write_number(reinterpret_cast(&allocated->frame_number), video::vga::text::common_attributes::green_on_black); video::vga::text::write("Allocated Frame number: ", video::vga::text::common_attributes::green_on_black); video::vga::text::write_number(allocated->frame_number, video::vga::text::common_attributes::green_on_black); } else { video::vga::text::write("NO VALUE", video::vga::text::common_attributes::green_on_black); } } } // namespace teachos::arch::kernel