diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 0dce633f5..450bdddfc 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -12,6 +12,7 @@ set(KERNEL_SOURCES font/prefs.psf.o kernel/ACPI.cpp kernel/APIC.cpp + kernel/BootInfo.cpp kernel/CPUID.cpp kernel/Debug.cpp kernel/Device/Device.cpp diff --git a/kernel/arch/x86_64/PageTable.cpp b/kernel/arch/x86_64/PageTable.cpp index 2abd768a2..4913f212f 100644 --- a/kernel/arch/x86_64/PageTable.cpp +++ b/kernel/arch/x86_64/PageTable.cpp @@ -4,7 +4,6 @@ #include #include #include -#include extern uint8_t g_kernel_start[]; extern uint8_t g_kernel_end[]; @@ -145,6 +144,14 @@ namespace Kernel prepare_fast_page(); + // Map main bios area below 1 MiB + map_range_at( + 0x000E0000, + P2V(0x000E0000), + 0x00100000 - 0x000E0000, + PageTable::Flags::Present + ); + // Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end) ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0); map_range_at( @@ -169,22 +176,6 @@ namespace Kernel g_userspace_end - g_userspace_start, Flags::Execute | Flags::UserSupervisor | Flags::Present ); - - // Map multiboot memory - paddr_t multiboot2_data_start = (vaddr_t)g_multiboot2_info & PAGE_ADDR_MASK; - paddr_t multiboot2_data_end = (vaddr_t)g_multiboot2_info + g_multiboot2_info->total_size; - - size_t multiboot2_needed_pages = BAN::Math::div_round_up(multiboot2_data_end - multiboot2_data_start, PAGE_SIZE); - vaddr_t multiboot2_vaddr = reserve_free_contiguous_pages(multiboot2_needed_pages, KERNEL_OFFSET); - - map_range_at( - multiboot2_data_start, - multiboot2_vaddr, - multiboot2_needed_pages * PAGE_SIZE, - Flags::ReadWrite | Flags::Present - ); - - g_multiboot2_info = (multiboot2_info_t*)(multiboot2_vaddr + ((vaddr_t)g_multiboot2_info % PAGE_SIZE)); } void PageTable::prepare_fast_page() @@ -371,7 +362,7 @@ namespace Kernel { ASSERT(vaddr); ASSERT(vaddr != fast_page()); - if (vaddr >= KERNEL_OFFSET) + if (vaddr >= KERNEL_OFFSET && s_current) ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start); if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel)) Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel); diff --git a/kernel/arch/x86_64/boot.S b/kernel/arch/x86_64/boot.S index ab4d54bf8..f2dd6ad46 100644 --- a/kernel/arch/x86_64/boot.S +++ b/kernel/arch/x86_64/boot.S @@ -21,8 +21,8 @@ multiboot2_start: .short 5 .short 0 .long 20 - .long 1920 - .long 1080 + .long 800 + .long 600 .long 32 # legacy start @@ -50,11 +50,9 @@ multiboot2_end: g_kernel_cmdline: .skip 4096 - .global g_multiboot2_info - g_multiboot2_info: + bootloader_magic: .skip 8 - .global g_multiboot2_magic - g_multiboot2_magic: + bootloader_info: .skip 8 .section .data @@ -167,8 +165,8 @@ initialize_paging: _start: # Initialize stack and multiboot info movl $V2P(g_boot_stack_top), %esp - movl %eax, V2P(g_multiboot2_magic) - movl %ebx, V2P(g_multiboot2_info) + movl %eax, V2P(bootloader_magic) + movl %ebx, V2P(bootloader_info) call check_requirements call enable_sse @@ -200,8 +198,11 @@ higher_half: # call global constuctors call _init - # call to the kernel itself (clear ebp for stacktrace) + # call to the kernel itself (clear rbp for stacktrace) xorq %rbp, %rbp + + movl V2P(bootloader_magic), %edi + movl V2P(bootloader_info), %esi call kernel_main # call global destructors diff --git a/kernel/include/kernel/BootInfo.h b/kernel/include/kernel/BootInfo.h new file mode 100644 index 000000000..1f52b5a14 --- /dev/null +++ b/kernel/include/kernel/BootInfo.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +namespace Kernel +{ + + enum class FramebufferType + { + NONE, + UNKNOWN, + RGB + }; + + struct FramebufferInfo + { + paddr_t address; + uint32_t pitch; + uint32_t width; + uint32_t height; + uint8_t bpp; + FramebufferType type = FramebufferType::NONE; + }; + + struct MemoryMapEntry + { + uint32_t type; + paddr_t address; + uint64_t length; + }; + + struct BootInfo + { + BAN::String command_line; + FramebufferInfo framebuffer; + BAN::Vector memory_map_entries; + }; + + bool validate_boot_magic(uint32_t magic); + void parse_boot_info(uint32_t magic, uint32_t info); + BAN::StringView get_early_boot_command_line(uint32_t magic, uint32_t info); + + extern BootInfo g_boot_info; + +} diff --git a/kernel/include/kernel/multiboot2.h b/kernel/include/kernel/multiboot2.h index fed08a8d2..6723a8de3 100644 --- a/kernel/include/kernel/multiboot2.h +++ b/kernel/include/kernel/multiboot2.h @@ -13,11 +13,18 @@ #define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT2_MAGIC 0x36d76289 + struct multiboot2_tag_t { uint32_t type; uint32_t size; - multiboot2_tag_t* next() { return (multiboot2_tag_t*)((uintptr_t)this + ((size + 7) & ~7)); } + const multiboot2_tag_t* next() const + { + return reinterpret_cast( + reinterpret_cast(this) + ((size + 7) & ~7) + ); + } } __attribute__((packed)); struct multiboot2_cmdline_tag_t : public multiboot2_tag_t @@ -62,14 +69,3 @@ struct multiboot2_info_t uint32_t reserved; multiboot2_tag_t tags[]; } __attribute__((packed)); - -extern "C" multiboot2_info_t* g_multiboot2_info; -extern "C" uint32_t g_multiboot2_magic; - -inline multiboot2_tag_t* multiboot2_find_tag(uint32_t type) -{ - for (auto* tag = g_multiboot2_info->tags; tag->type != MULTIBOOT2_TAG_END; tag = tag->next()) - if (tag->type == type) - return tag; - return nullptr; -} diff --git a/kernel/kernel/ACPI.cpp b/kernel/kernel/ACPI.cpp index d5de89cb9..3983eb8b6 100644 --- a/kernel/kernel/ACPI.cpp +++ b/kernel/kernel/ACPI.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include @@ -85,11 +84,14 @@ namespace Kernel static const RSDP* locate_rsdp() { + // FIXME: add this back +#if 0 // Check the multiboot headers if (auto* rsdp_new = (multiboot2_rsdp_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_NEW_RSDP)) return (const RSDP*)rsdp_new->data; if (auto* rsdp_old = (multiboot2_rsdp_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_OLD_RSDP)) return (const RSDP*)rsdp_old->data; +#endif // Look in main BIOS area below 1 MB for (uintptr_t addr = P2V(0x000E0000); addr < P2V(0x000FFFFF); addr += 16) diff --git a/kernel/kernel/BootInfo.cpp b/kernel/kernel/BootInfo.cpp new file mode 100644 index 000000000..cf6420df8 --- /dev/null +++ b/kernel/kernel/BootInfo.cpp @@ -0,0 +1,94 @@ +#include + +#include + +namespace Kernel +{ + + BootInfo g_boot_info; + + void parse_boot_info_multiboot2(uint32_t info) + { + const auto& multiboot2_info = *reinterpret_cast(info); + + for (const auto* tag = multiboot2_info.tags; tag->type != MULTIBOOT2_TAG_END; tag = tag->next()) + { + if (tag->type == MULTIBOOT2_TAG_CMDLINE) + { + const auto& command_line_tag = *reinterpret_cast(tag); + MUST(g_boot_info.command_line.append(command_line_tag.cmdline)); + } + else if (tag->type == MULTIBOOT2_TAG_FRAMEBUFFER) + { + const auto& framebuffer_tag = *reinterpret_cast(tag); + g_boot_info.framebuffer.address = framebuffer_tag.framebuffer_addr; + g_boot_info.framebuffer.pitch = framebuffer_tag.framebuffer_pitch; + g_boot_info.framebuffer.width = framebuffer_tag.framebuffer_width; + g_boot_info.framebuffer.height = framebuffer_tag.framebuffer_height; + g_boot_info.framebuffer.bpp = framebuffer_tag.framebuffer_bpp; + if (framebuffer_tag.framebuffer_type == MULTIBOOT2_FRAMEBUFFER_TYPE_RGB) + g_boot_info.framebuffer.type = FramebufferType::RGB; + else + g_boot_info.framebuffer.type = FramebufferType::UNKNOWN; + } + else if (tag->type == MULTIBOOT2_TAG_MMAP) + { + const auto& mmap_tag = *reinterpret_cast(tag); + + const size_t entry_count = (mmap_tag.size - sizeof(multiboot2_mmap_tag_t)) / mmap_tag.entry_size; + + MUST(g_boot_info.memory_map_entries.resize(entry_count)); + + for (size_t i = 0; i < entry_count; i++) + { + const auto& mmap_entry = *reinterpret_cast(reinterpret_cast(tag) + sizeof(multiboot2_mmap_tag_t) + i * mmap_tag.entry_size); + dprintln("entry {16H} {16H} {8H}", + (uint64_t)mmap_entry.base_addr, + (uint64_t)mmap_entry.length, + (uint64_t)mmap_entry.type + ); + g_boot_info.memory_map_entries[i].address = mmap_entry.base_addr; + g_boot_info.memory_map_entries[i].length = mmap_entry.length; + g_boot_info.memory_map_entries[i].type = mmap_entry.type; + } + } + } + } + + BAN::StringView get_early_boot_command_line_multiboot2(uint32_t info) + { + const auto& multiboot2_info = *reinterpret_cast(info); + for (const auto* tag = multiboot2_info.tags; tag->type != MULTIBOOT2_TAG_END; tag = tag->next()) + if (tag->type == MULTIBOOT2_TAG_CMDLINE) + return reinterpret_cast(tag)->cmdline; + return {}; + } + + bool validate_boot_magic(uint32_t magic) + { + if (magic == MULTIBOOT2_MAGIC) + return true; + return false; + } + + void parse_boot_info(uint32_t magic, uint32_t info) + { + switch (magic) + { + case MULTIBOOT2_MAGIC: + return parse_boot_info_multiboot2(info); + } + ASSERT_NOT_REACHED(); + } + + BAN::StringView get_early_boot_command_line(uint32_t magic, uint32_t info) + { + switch (magic) + { + case MULTIBOOT2_MAGIC: + return get_early_boot_command_line_multiboot2(info); + } + ASSERT_NOT_REACHED(); + } + +} diff --git a/kernel/kernel/Memory/Heap.cpp b/kernel/kernel/Memory/Heap.cpp index 7be6a631d..4f6072041 100644 --- a/kernel/kernel/Memory/Heap.cpp +++ b/kernel/kernel/Memory/Heap.cpp @@ -1,7 +1,7 @@ +#include #include #include #include -#include extern uint8_t g_kernel_end[]; @@ -26,30 +26,33 @@ namespace Kernel void Heap::initialize_impl() { - auto* mmap_tag = (multiboot2_mmap_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_MMAP); - if (mmap_tag == nullptr) + if (g_boot_info.memory_map_entries.empty()) Kernel::panic("Bootloader did not provide a memory map"); - for (size_t offset = sizeof(*mmap_tag); offset < mmap_tag->size; offset += mmap_tag->entry_size) + for (const auto& entry : g_boot_info.memory_map_entries) { - auto* mmap_entry = (multiboot2_mmap_entry_t*)((uintptr_t)mmap_tag + offset); + dprintln("{16H}, {16H}, {8H}", + entry.address, + entry.length, + entry.type + ); - if (mmap_entry->type == 1) - { - paddr_t start = mmap_entry->base_addr; - if (start < V2P(g_kernel_end)) - start = V2P(g_kernel_end); - if (auto rem = start % PAGE_SIZE) - start += PAGE_SIZE - rem; + if (entry.type != 1) + continue; + + paddr_t start = entry.address; + if (start < V2P(g_kernel_end)) + start = V2P(g_kernel_end); + if (auto rem = start % PAGE_SIZE) + start += PAGE_SIZE - rem; - paddr_t end = mmap_entry->base_addr + mmap_entry->length; - if (auto rem = end % PAGE_SIZE) - end -= rem; + paddr_t end = entry.address + entry.length; + if (auto rem = end % PAGE_SIZE) + end -= rem; - // Physical pages needs atleast 2 pages - if (end > start + PAGE_SIZE) - MUST(m_physical_ranges.emplace_back(start, end - start)); - } + // Physical pages needs atleast 2 pages + if (end > start + PAGE_SIZE) + MUST(m_physical_ranges.emplace_back(start, end - start)); } size_t total = 0; diff --git a/kernel/kernel/Terminal/VesaTerminalDriver.cpp b/kernel/kernel/Terminal/VesaTerminalDriver.cpp index f53c678e6..f0197d15e 100644 --- a/kernel/kernel/Terminal/VesaTerminalDriver.cpp +++ b/kernel/kernel/Terminal/VesaTerminalDriver.cpp @@ -1,42 +1,41 @@ #include +#include #include #include -#include #include using namespace Kernel; VesaTerminalDriver* VesaTerminalDriver::create() { - auto* framebuffer_tag = (multiboot2_framebuffer_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_FRAMEBUFFER); - if (framebuffer_tag == nullptr) + if (g_boot_info.framebuffer.type == FramebufferType::NONE) { dprintln("Bootloader did not provide framebuffer"); return nullptr; } - if (framebuffer_tag->framebuffer_type != MULTIBOOT2_FRAMEBUFFER_TYPE_RGB) + if (g_boot_info.framebuffer.type != FramebufferType::RGB) { - dprintln("unsupported framebuffer type {}", framebuffer_tag->framebuffer_type); + dprintln("unsupported framebuffer type"); return nullptr; } - if (framebuffer_tag->framebuffer_bpp != 24 && framebuffer_tag->framebuffer_bpp != 32) + if (g_boot_info.framebuffer.bpp != 24 && g_boot_info.framebuffer.bpp != 32) { - dprintln("Unsupported bpp {}", framebuffer_tag->framebuffer_bpp); + dprintln("Unsupported bpp {}", g_boot_info.framebuffer.bpp); return nullptr; } dprintln("Graphics Mode {}x{} ({} bpp)", - (uint32_t)framebuffer_tag->framebuffer_width, - (uint32_t)framebuffer_tag->framebuffer_height, - (uint8_t)framebuffer_tag->framebuffer_bpp + g_boot_info.framebuffer.width, + g_boot_info.framebuffer.height, + g_boot_info.framebuffer.bpp ); - paddr_t paddr = framebuffer_tag->framebuffer_addr & PAGE_ADDR_MASK; + paddr_t paddr = g_boot_info.framebuffer.address & PAGE_ADDR_MASK; size_t needed_pages = range_page_count( - framebuffer_tag->framebuffer_addr, - framebuffer_tag->framebuffer_pitch * framebuffer_tag->framebuffer_height + g_boot_info.framebuffer.address, + g_boot_info.framebuffer.pitch * g_boot_info.framebuffer.height ); vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET); @@ -45,10 +44,10 @@ VesaTerminalDriver* VesaTerminalDriver::create() PageTable::kernel().map_range_at(paddr, vaddr, needed_pages * PAGE_SIZE, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present); auto* driver = new VesaTerminalDriver( - framebuffer_tag->framebuffer_width, - framebuffer_tag->framebuffer_height, - framebuffer_tag->framebuffer_pitch, - framebuffer_tag->framebuffer_bpp, + g_boot_info.framebuffer.width, + g_boot_info.framebuffer.height, + g_boot_info.framebuffer.pitch, + g_boot_info.framebuffer.bpp, vaddr ); driver->set_cursor_position(0, 0); diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 5c5e1382b..047712de1 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -12,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -31,13 +31,9 @@ struct ParsedCommandLine BAN::StringView root; }; -static bool should_disable_serial() +static bool should_disable_serial(BAN::StringView full_command_line) { - auto* cmdline_tag = (multiboot2_cmdline_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_CMDLINE); - if (cmdline_tag == nullptr) - return false; - - const char* start = cmdline_tag->cmdline; + const char* start = full_command_line.data(); const char* current = start; while (true) { @@ -59,13 +55,8 @@ static ParsedCommandLine cmdline; static void parse_command_line() { - auto* cmdline_tag = (multiboot2_cmdline_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_CMDLINE); - if (cmdline_tag == nullptr) - return; - - BAN::StringView full_command_line(cmdline_tag->cmdline); + auto full_command_line = Kernel::g_boot_info.command_line.sv(); auto arguments = MUST(full_command_line.split(' ')); - for (auto argument : arguments) { if (argument == "noapic") @@ -83,27 +74,31 @@ TerminalDriver* g_terminal_driver = nullptr; static void init2(void*); -extern "C" void kernel_main() +extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info) { using namespace Kernel; DISABLE_INTERRUPTS(); - if (!should_disable_serial()) + if (!validate_boot_magic(boot_magic)) + { + Serial::initialize(); + dprintln("Unrecognized boot magic {8H}", boot_magic); + return; + } + + if (!should_disable_serial(get_early_boot_command_line(boot_magic, boot_info))) { Serial::initialize(); dprintln("Serial output initialized"); } - if (g_multiboot2_magic != 0x36d76289) - { - dprintln("Invalid multiboot magic number"); - return; - } - kmalloc_initialize(); dprintln("kmalloc initialized"); + parse_boot_info(boot_magic, boot_info); + dprintln("boot info parsed"); + GDT::initialize(); dprintln("GDT initialized");