Kernel: Don't use multiboot2 explicitly. Parse it to common structure

This allows support of multiple different bootloaders
This commit is contained in:
2023-11-17 18:54:59 +02:00
parent 641a2dec00
commit 84040e64b8
10 changed files with 226 additions and 97 deletions

View File

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

View File

@@ -0,0 +1,94 @@
#include <kernel/BootInfo.h>
#include <kernel/multiboot2.h>
namespace Kernel
{
BootInfo g_boot_info;
void parse_boot_info_multiboot2(uint32_t info)
{
const auto& multiboot2_info = *reinterpret_cast<const multiboot2_info_t*>(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<const multiboot2_cmdline_tag_t*>(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<const multiboot2_framebuffer_tag_t*>(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<const multiboot2_mmap_tag_t*>(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<const multiboot2_mmap_entry_t*>(reinterpret_cast<uintptr_t>(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<const multiboot2_info_t*>(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<const multiboot2_cmdline_tag_t*>(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();
}
}

View File

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

View File

@@ -1,42 +1,41 @@
#include <BAN/Errors.h>
#include <kernel/BootInfo.h>
#include <kernel/Debug.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
#include <kernel/Terminal/VesaTerminalDriver.h>
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);

View File

@@ -1,5 +1,6 @@
#include <kernel/ACPI.h>
#include <kernel/Arch.h>
#include <kernel/BootInfo.h>
#include <kernel/Debug.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/ProcFS/FileSystem.h>
@@ -12,7 +13,6 @@
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
#include <kernel/PCI.h>
#include <kernel/PIC.h>
#include <kernel/Process.h>
@@ -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");