diff --git a/kernel/arch/x86_64/PageTable.cpp b/kernel/arch/x86_64/PageTable.cpp index fca738bc..24443797 100644 --- a/kernel/arch/x86_64/PageTable.cpp +++ b/kernel/arch/x86_64/PageTable.cpp @@ -4,6 +4,7 @@ #include #include #include +#include extern uint8_t g_kernel_start[]; extern uint8_t g_kernel_end[]; @@ -138,6 +139,16 @@ namespace Kernel // Map (0 -> phys_kernel_end) to (KERNEL_OFFSET -> virt_kernel_end) map_range_at(0, KERNEL_OFFSET, (uintptr_t)g_kernel_end - KERNEL_OFFSET, Flags::ReadWrite | Flags::Present); + // Map multiboot info + vaddr_t multiboot_data_start = (vaddr_t)g_multiboot2_info & PAGE_ADDR_MASK; + vaddr_t multiboot_data_end = (vaddr_t)g_multiboot2_info + g_multiboot2_info->total_size; + map_range_at( + V2P(multiboot_data_start), + multiboot_data_start, + multiboot_data_end - multiboot_data_start, + Flags::ReadWrite | Flags::Present + ); + // Map executable kernel memory as executable map_range_at( V2P(g_kernel_execute_start), diff --git a/kernel/arch/x86_64/boot.S b/kernel/arch/x86_64/boot.S index 98298b3a..b00995d9 100644 --- a/kernel/arch/x86_64/boot.S +++ b/kernel/arch/x86_64/boot.S @@ -1,11 +1,3 @@ -# Declare constants for the multiboot header -.set ALIGN, 1<<0 # align loaded modules on page boundaries -.set MEMINFO, 1<<1 # provide memory map -.set VIDEOINFO, 1<<2 # provide video info -.set MB_FLAGS, ALIGN | MEMINFO | VIDEOINFO # this is the Multiboot 'flag' field -.set MB_MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header -.set MB_CHECKSUM, -(MB_MAGIC + MB_FLAGS) #checksum of above, to prove we are multiboot - .set PG_PRESENT, 1<<0 .set PG_READ_WRITE, 1<<1 .set PG_PAGE_SIZE, 1<<7 @@ -15,19 +7,37 @@ .code32 -# Multiboot header +# multiboot2 header .section .multiboot, "aw" - .align 4 - .long MB_MAGIC - .long MB_FLAGS - .long MB_CHECKSUM - .skip 20 - +multiboot2_start: + .align 8 + .long 0xE85250D6 .long 0 - .long 800 - .long 600 + .long multiboot2_end - multiboot2_start + .long -(0xE85250D6 + (multiboot2_end - multiboot2_start)) + + # framebuffer tag + .align 8 + .short 5 + .short 0 + .long 20 + .long 1920 + .long 1080 .long 32 + # legacy start + .align 8 + .short 3 + .short 0 + .long 12 + .long V2P(_start) + + .align 8 + .short 0 + .short 0 + .long 8 +multiboot2_end: + .section .bss, "aw", @nobits # Create stack .global g_boot_stack_bottom @@ -40,11 +50,11 @@ g_kernel_cmdline: .skip 4096 - .global g_multiboot_info - g_multiboot_info: + .global g_multiboot2_info + g_multiboot2_info: .skip 8 - .global g_multiboot_magic - g_multiboot_magic: + .global g_multiboot2_magic + g_multiboot2_magic: .skip 8 .section .data @@ -119,19 +129,6 @@ check_requirements: .exit: jmp system_halt -copy_kernel_commandline: - pushl %esi - pushl %edi - movl V2P(g_multiboot_info), %esi - addl $16, %esi - movl (%esi), %esi - movl $1024, %ecx - movl $V2P(g_kernel_cmdline), %edi - rep movsl - popl %edi - popl %esi - ret - enable_sse: movl %cr0, %eax andw $0xFFFB, %ax @@ -170,10 +167,9 @@ initialize_paging: _start: # Initialize stack and multiboot info movl $V2P(g_boot_stack_top), %esp - movl %eax, V2P(g_multiboot_magic) - movl %ebx, V2P(g_multiboot_info) + movl %eax, V2P(g_multiboot2_magic) + movl %ebx, V2P(g_multiboot2_info) - call copy_kernel_commandline call check_requirements call enable_sse @@ -201,7 +197,7 @@ long_mode: jmp *%rcx higher_half: - addq $KERNEL_OFFSET, g_multiboot_info + addq $KERNEL_OFFSET, g_multiboot2_info # call global constuctors call _init diff --git a/kernel/include/kernel/multiboot.h b/kernel/include/kernel/multiboot.h deleted file mode 100644 index 2c42c876..00000000 --- a/kernel/include/kernel/multiboot.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include - -#define MULTIBOOT_FLAGS_FRAMEBUFFER (1 << 12) - -#define MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS 1 -#define MULTIBOOT_FRAMEBUFFER_TYPE_TEXT 2 - -struct framebuffer_info_t -{ - uint64_t addr; - uint32_t pitch; - uint32_t width; - uint32_t height; - uint8_t bpp; - uint8_t type; - uint8_t color_info[6]; -}; - -struct multiboot_memory_map_t -{ - uint32_t size; - uint64_t base_addr; - uint64_t length; - uint32_t type; -} __attribute__((packed)); - -// https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format -struct multiboot_info_t -{ - uint32_t flags; - uint32_t mem_lower; - uint32_t mem_upper; - uint32_t boot_device; - uint32_t cmdline; - uint32_t mods_count; - uint32_t mods_addr; - uint32_t syms[4]; - uint32_t mmap_length; - uint32_t mmap_addr; - uint32_t drives_length; - uint32_t drives_addr; - uint32_t config_table; - uint32_t boot_loader_name; - uint32_t apm_table; - uint32_t vbe_control_info; - uint32_t vbe_mode_info; - uint16_t vbe_mode; - uint16_t vbe_interface_seg; - uint16_t vbe_interface_off; - uint16_t vbe_interface_len; - framebuffer_info_t framebuffer; -}; - -extern "C" multiboot_info_t* g_multiboot_info; -extern "C" uint32_t g_multiboot_magic; diff --git a/kernel/include/kernel/multiboot2.h b/kernel/include/kernel/multiboot2.h new file mode 100644 index 00000000..fed08a8d --- /dev/null +++ b/kernel/include/kernel/multiboot2.h @@ -0,0 +1,75 @@ +#pragma once + +#include + +// https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information + +#define MULTIBOOT2_TAG_END 0 +#define MULTIBOOT2_TAG_CMDLINE 1 +#define MULTIBOOT2_TAG_MMAP 6 +#define MULTIBOOT2_TAG_FRAMEBUFFER 8 +#define MULTIBOOT2_TAG_OLD_RSDP 14 +#define MULTIBOOT2_TAG_NEW_RSDP 15 + +#define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1 + +struct multiboot2_tag_t +{ + uint32_t type; + uint32_t size; + multiboot2_tag_t* next() { return (multiboot2_tag_t*)((uintptr_t)this + ((size + 7) & ~7)); } +} __attribute__((packed)); + +struct multiboot2_cmdline_tag_t : public multiboot2_tag_t +{ + char cmdline[]; +} __attribute__((packed)); + +struct multiboot2_mmap_entry_t +{ + uint64_t base_addr; + uint64_t length; + uint32_t type; + uint32_t reserved; +} __attribute__((packed)); + +struct multiboot2_mmap_tag_t : public multiboot2_tag_t +{ + uint32_t entry_size; + uint32_t entry_version; + multiboot2_mmap_entry_t entries[]; +} __attribute__((packed)); + +struct multiboot2_framebuffer_tag_t : public multiboot2_tag_t +{ + uint64_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; + uint8_t reserved; +} __attribute__((packed)); + +struct multiboot2_rsdp_tag_t : public multiboot2_tag_t +{ + uint8_t data[]; +} __attribute__((packed)); + +struct multiboot2_info_t +{ + uint32_t total_size; + 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 ab995586..072f337a 100644 --- a/kernel/kernel/ACPI.cpp +++ b/kernel/kernel/ACPI.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -84,6 +85,12 @@ namespace Kernel static const RSDP* locate_rsdp() { + // 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; + // Look in main BIOS area below 1 MB for (uintptr_t addr = P2V(0x000E0000); addr < P2V(0x000FFFFF); addr += 16) if (is_rsdp(addr)) diff --git a/kernel/kernel/Memory/Heap.cpp b/kernel/kernel/Memory/Heap.cpp index 57ee9838..7be6a631 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,21 +26,23 @@ namespace Kernel void Heap::initialize_impl() { - if (!(g_multiboot_info->flags & (1 << 6))) + auto* mmap_tag = (multiboot2_mmap_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_MMAP); + if (mmap_tag == nullptr) Kernel::panic("Bootloader did not provide a memory map"); - - for (size_t i = 0; i < g_multiboot_info->mmap_length;) + + for (size_t offset = sizeof(*mmap_tag); offset < mmap_tag->size; offset += mmap_tag->entry_size) { - multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*)P2V(g_multiboot_info->mmap_addr + i); - if (mmmt->type == 1) + auto* mmap_entry = (multiboot2_mmap_entry_t*)((uintptr_t)mmap_tag + offset); + + if (mmap_entry->type == 1) { - paddr_t start = mmmt->base_addr; + 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; - paddr_t end = mmmt->base_addr + mmmt->length; + paddr_t end = mmap_entry->base_addr + mmap_entry->length; if (auto rem = end % PAGE_SIZE) end -= rem; @@ -48,7 +50,6 @@ namespace Kernel if (end > start + PAGE_SIZE) MUST(m_physical_ranges.emplace_back(start, end - start)); } - i += mmmt->size + sizeof(uint32_t); } size_t total = 0; diff --git a/kernel/kernel/Terminal/VesaTerminalDriver.cpp b/kernel/kernel/Terminal/VesaTerminalDriver.cpp index 2ac6445f..f53c678e 100644 --- a/kernel/kernel/Terminal/VesaTerminalDriver.cpp +++ b/kernel/kernel/Terminal/VesaTerminalDriver.cpp @@ -1,55 +1,54 @@ #include #include #include -#include +#include #include using namespace Kernel; VesaTerminalDriver* VesaTerminalDriver::create() { - if (!(g_multiboot_info->flags & MULTIBOOT_FLAGS_FRAMEBUFFER)) + auto* framebuffer_tag = (multiboot2_framebuffer_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_FRAMEBUFFER); + if (framebuffer_tag == nullptr) { dprintln("Bootloader did not provide framebuffer"); return nullptr; } - auto& framebuffer = g_multiboot_info->framebuffer; - - if (framebuffer.type == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS) + if (framebuffer_tag->framebuffer_type != MULTIBOOT2_FRAMEBUFFER_TYPE_RGB) { - if (framebuffer.bpp != 24 && framebuffer.bpp != 32) - { - dprintln("Unsupported bpp {}", framebuffer.bpp); - return nullptr; - } - dprintln("Graphics Mode {}x{} ({} bpp)", framebuffer.width, framebuffer.height, framebuffer.bpp); - } - else if (framebuffer.type == MULTIBOOT_FRAMEBUFFER_TYPE_TEXT) - { - dprintln("Text Mode is currently not supported"); - return nullptr; - } - else - { - dprintln("Unknown framebuffer type {}", framebuffer.type); + dprintln("unsupported framebuffer type {}", framebuffer_tag->framebuffer_type); return nullptr; } - uint64_t first_page = framebuffer.addr / PAGE_SIZE; - uint64_t last_page = BAN::Math::div_round_up(framebuffer.addr + framebuffer.pitch * framebuffer.height, PAGE_SIZE); - uint64_t needed_pages = last_page - first_page + 1; + if (framebuffer_tag->framebuffer_bpp != 24 && framebuffer_tag->framebuffer_bpp != 32) + { + dprintln("Unsupported bpp {}", framebuffer_tag->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 + ); + + paddr_t paddr = framebuffer_tag->framebuffer_addr & PAGE_ADDR_MASK; + size_t needed_pages = range_page_count( + framebuffer_tag->framebuffer_addr, + framebuffer_tag->framebuffer_pitch * framebuffer_tag->framebuffer_height + ); vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET); ASSERT(vaddr); - PageTable::kernel().map_range_at(framebuffer.addr, vaddr, needed_pages * PAGE_SIZE, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present); + 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.width, - framebuffer.height, - framebuffer.pitch, - framebuffer.bpp, + framebuffer_tag->framebuffer_width, + framebuffer_tag->framebuffer_height, + framebuffer_tag->framebuffer_pitch, + framebuffer_tag->framebuffer_bpp, vaddr ); driver->set_cursor_position(0, 0); diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 2a88287a..08ce725d 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -23,8 +23,6 @@ #include #include -extern "C" const char g_kernel_cmdline[]; - struct ParsedCommandLine { bool force_pic = false; @@ -35,11 +33,12 @@ struct ParsedCommandLine static bool should_disable_serial() { - if (!(g_multiboot_info->flags & 0x02)) + auto* cmdline_tag = (multiboot2_cmdline_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_CMDLINE); + if (cmdline_tag == nullptr) return false; - const char* start = g_kernel_cmdline; - const char* current = g_kernel_cmdline; + const char* start = cmdline_tag->cmdline; + const char* current = start; while (true) { if (!*current || *current == ' ' || *current == '\t') @@ -60,10 +59,11 @@ static ParsedCommandLine cmdline; static void parse_command_line() { - if (!(g_multiboot_info->flags & 0x02)) + auto* cmdline_tag = (multiboot2_cmdline_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_CMDLINE); + if (cmdline_tag == nullptr) return; - BAN::StringView full_command_line(g_kernel_cmdline); + BAN::StringView full_command_line(cmdline_tag->cmdline); auto arguments = MUST(full_command_line.split(' ')); for (auto argument : arguments) @@ -98,7 +98,7 @@ extern "C" void kernel_main() dprintln("Serial output initialized"); } - if (g_multiboot_magic != 0x2BADB002) + if (g_multiboot2_magic != 0x36d76289) { dprintln("Invalid multiboot magic number"); return; diff --git a/toolchain/local/grub-legacy-boot.cfg b/toolchain/local/grub-legacy-boot.cfg index 1798a1e5..4a40c130 100644 --- a/toolchain/local/grub-legacy-boot.cfg +++ b/toolchain/local/grub-legacy-boot.cfg @@ -1,23 +1,23 @@ menuentry "banan-os" { - multiboot /boot/banan-os.kernel root=/dev/sda2 + multiboot2 /boot/banan-os.kernel root=/dev/sda2 } menuentry "banan-os (no serial)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 noserial + multiboot2 /boot/banan-os.kernel root=/dev/sda2 noserial } menuentry "banan-os (only serial)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 console=ttyS0 + multiboot2 /boot/banan-os.kernel root=/dev/sda2 console=ttyS0 } menuentry "banan-os (no apic)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 noapic + multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic } menuentry "banan-os (no apic, no serial)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 noapic noserial + multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic noserial } menuentry "banan-os (no apic, only serial)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 noapic console=ttyS0 + multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic console=ttyS0 } diff --git a/toolchain/local/grub-uefi.cfg b/toolchain/local/grub-uefi.cfg index ca0ecb2c..69cb7ea4 100644 --- a/toolchain/local/grub-uefi.cfg +++ b/toolchain/local/grub-uefi.cfg @@ -2,25 +2,25 @@ insmod part_gpt set root=(hd0,gpt2) menuentry "banan-os" { - multiboot /boot/banan-os.kernel root=/dev/sda2 + multiboot2 /boot/banan-os.kernel root=/dev/sda2 } menuentry "banan-os (no serial)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 noserial + multiboot2 /boot/banan-os.kernel root=/dev/sda2 noserial } menuentry "banan-os (only serial)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 console=ttyS0 + multiboot2 /boot/banan-os.kernel root=/dev/sda2 console=ttyS0 } menuentry "banan-os (no apic)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 noapic + multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic } menuentry "banan-os (no apic, no serial)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 noapic noserial + multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic noserial } menuentry "banan-os (no apic, only serial)" { - multiboot /boot/banan-os.kernel root=/dev/sda2 noapic console=ttyS0 + multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic console=ttyS0 }