Kernel: Start using multiboot2 instead of multiboot

This allows better compatibility with (U)EFI and gives RSDP location
instead of me having to scan ram to find it.
This commit is contained in:
Bananymous 2023-10-17 01:06:24 +03:00
parent 19696bdad3
commit 69a39b7077
10 changed files with 185 additions and 153 deletions

View File

@ -4,6 +4,7 @@
#include <kernel/LockGuard.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
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),

View File

@ -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

View File

@ -1,57 +0,0 @@
#pragma once
#include <stdint.h>
#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;

View File

@ -0,0 +1,75 @@
#pragma once
#include <stdint.h>
// 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;
}

View File

@ -2,6 +2,7 @@
#include <BAN/StringView.h>
#include <kernel/ACPI.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
#include <lai/core.h>
@ -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))

View File

@ -1,7 +1,7 @@
#include <kernel/LockGuard.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot.h>
#include <kernel/multiboot2.h>
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;

View File

@ -1,55 +1,54 @@
#include <BAN/Errors.h>
#include <kernel/Debug.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot.h>
#include <kernel/multiboot2.h>
#include <kernel/Terminal/VesaTerminalDriver.h>
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<uint64_t>(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);

View File

@ -12,7 +12,7 @@
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot.h>
#include <kernel/multiboot2.h>
#include <kernel/PCI.h>
#include <kernel/PIC.h>
#include <kernel/Process.h>
@ -23,8 +23,6 @@
#include <kernel/Terminal/VesaTerminalDriver.h>
#include <kernel/Timer/Timer.h>
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;

View File

@ -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
}

View File

@ -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
}