Skip to content

Commit

Permalink
kernel: x86_64: rewrite multiboot logic, clarify header license
Browse files Browse the repository at this point in the history
  • Loading branch information
willdurand committed Jan 29, 2024
1 parent 88716b7 commit ea6c6d5
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 170 deletions.
201 changes: 61 additions & 140 deletions src/kernel/arch/x86_64/core/multiboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <stdio.h>

reserved_areas_t build_reserved_areas();
void* _multiboot_find(multiboot_tag_t* tag, uint16_t type);

static multiboot_info_t* saved_mbi = NULL;
static reserved_areas_t reserved_areas = { .kernel_start = 0,
Expand All @@ -19,6 +20,13 @@ void multiboot_init(multiboot_info_t* mbi)
{
saved_mbi = mbi;
reserved_areas = build_reserved_areas();
framebuffer = multiboot_find(MULTIBOOT_TAG_TYPE_FRAMEBUFFER);
mmap = multiboot_find(MULTIBOOT_TAG_TYPE_MMAP);

multiboot_tag_string_t* string = multiboot_find(MULTIBOOT_TAG_TYPE_CMDLINE);
if (string != NULL) {
cmdline = string->string;
}
}

multiboot_tag_framebuffer_t* multiboot_get_framebuffer()
Expand Down Expand Up @@ -48,171 +56,66 @@ multiboot_tag_mmap_t* multiboot_get_mmap()

void* multiboot_find(uint16_t type)
{
multiboot_tag_t* tag = NULL;
// `*tag` points to the first tag of the multiboot_info_t struct
for (tag = (multiboot_tag_t*)saved_mbi->tags;
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (multiboot_tag_t*)((uint8_t*)tag + ((tag->size + 7) & ~7))) {
CORE_DEBUG("found tag with type=%d", tag->type);
if (tag->type == type) {
CORE_DEBUG("found tag for type=%d", type);
return tag;
}
}

CORE_DEBUG("could not find tag for type=%d", type);
return NULL;
return _multiboot_find(saved_mbi->tags, type);
}

reserved_areas_t build_reserved_areas()
{
multiboot_tag_t* tag = NULL;
reserved_areas_t reserved = { .kernel_start = 0,
.kernel_end = 0,
.multiboot_start = (uint64_t)saved_mbi,
.multiboot_end = 0,
.multiboot_end =
(uint64_t)saved_mbi + saved_mbi->size,
.start = 0,
.end = 0 };

CORE_DEBUG("announced MBI size %#x", saved_mbi->size);

for (tag = (multiboot_tag_t*)saved_mbi->tags;
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (multiboot_tag_t*)((uint8_t*)tag + ((tag->size + 7) & ~7))) {
CORE_DEBUG("found tag with type=%d", tag->type);

switch (tag->type) {
case MULTIBOOT_TAG_TYPE_CMDLINE: {
cmdline = ((multiboot_tag_string_t*)tag)->string;
CORE_DEBUG("command line=%s", cmdline);
break;
}

case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
CORE_DEBUG("boot loader name=%s",
((multiboot_tag_string_t*)tag)->string);
break;

case MULTIBOOT_TAG_TYPE_MODULE: {
reserved.end = ((multiboot_tag_module_t*)tag)->mod_end;
CORE_DEBUG("module at %p-%p with command line=%s",
((multiboot_tag_module_t*)tag)->mod_start,
((multiboot_tag_module_t*)tag)->mod_end,
((multiboot_tag_module_t*)tag)->cmdline);
break;
}

case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
CORE_DEBUG("mem_lower = %dKB, mem_upper = %dKB",
((multiboot_tag_basic_meminfo_t*)tag)->mem_lower,
((multiboot_tag_basic_meminfo_t*)tag)->mem_upper);
break;

case MULTIBOOT_TAG_TYPE_BOOTDEV:
CORE_DEBUG("boot device %#x, %u, %u",
((multiboot_tag_bootdev_t*)tag)->biosdev,
((multiboot_tag_bootdev_t*)tag)->slice,
((multiboot_tag_bootdev_t*)tag)->part);
break;

case MULTIBOOT_TAG_TYPE_MMAP: {
mmap = (multiboot_tag_mmap_t*)tag;
for (multiboot_mmap_entry_t* entry = mmap->entries;
(uint8_t*)entry < (uint8_t*)tag + tag->size;
entry = (multiboot_mmap_entry_t*)((uint64_t)entry +
((multiboot_tag_mmap_t*)tag)
->entry_size)) {
CORE_DEBUG("mmap entry: base_addr = %p, length = %#x, type = %#x",
entry->addr,
entry->len,
entry->type);
}
break;
multiboot_tag_elf_sections_t* sections =
multiboot_find(MULTIBOOT_TAG_TYPE_ELF_SECTIONS);
if (sections != NULL) {
uint32_t i = 0;
multiboot_elf_sections_entry_t* elf = sections->sections;
for (; i < sections->num;
elf = (multiboot_elf_sections_entry_t*)((uint64_t)elf +
sections->section_size),
i++) {
CORE_DEBUG("elf section #%02d: addr=%p, type=%#x, size=%#x, flags=%#x",
i,
elf->addr,
elf->type,
elf->size,
elf->flags);

if (elf->type == MULTIBOOT_ELF_SECTION_TYPE_NULL) {
continue;
}

case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: {
framebuffer = (multiboot_tag_framebuffer_t*)tag;
CORE_DEBUG("framebuffer framebuffer_addr=%p common_addr=%p",
framebuffer->common.framebuffer_addr,
(void*)&framebuffer->common);
break;
if (elf->addr < reserved.kernel_start || reserved.kernel_start == 0) {
reserved.kernel_start = elf->addr;
}

case MULTIBOOT_TAG_TYPE_APM:
CORE_DEBUG("%s", "apm");
break;

case MULTIBOOT_TAG_TYPE_ACPI_OLD:
CORE_DEBUG("%s", "acpi old");
break;

case MULTIBOOT_TAG_TYPE_ACPI_NEW:
CORE_DEBUG("%s", "acpi new");
break;

case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: {
multiboot_elf_sections_entry_t* elf = NULL;

uint32_t i = 0;

for (
i = 0, elf = ((multiboot_tag_elf_sections_t*)tag)->sections;
i < ((multiboot_tag_elf_sections_t*)tag)->num;
elf =
(multiboot_elf_sections_entry_t*)((uint64_t)elf +
((multiboot_tag_elf_sections_t*)
tag)
->section_size),
i++) {
CORE_DEBUG("elf section #%02d addr = %p, type = %#x, size = %#x, "
"flags = %#x",
i,
elf->addr,
elf->type,
elf->size,
elf->flags);

if (elf->type == MULTIBOOT_ELF_SECTION_TYPE_NULL) {
continue;
}

if (elf->addr < reserved.kernel_start || reserved.kernel_start == 0) {
reserved.kernel_start = elf->addr;
}

if ((elf->addr + elf->size) > reserved.kernel_end) {
reserved.kernel_end = elf->addr + elf->size;
}
}
break;
if ((elf->addr + elf->size) > reserved.kernel_end) {
reserved.kernel_end = elf->addr + elf->size;
}

case MULTIBOOT_TAG_TYPE_NETWORK:
CORE_DEBUG("%s", "network");
break;

case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
CORE_DEBUG("%s", "load base addr");
break;

default:
CORE_DEBUG("tag %#x, size %#x", tag->type, tag->size);
}
}

tag = (multiboot_tag_t*)((uint8_t*)tag + ((tag->size + 7) & ~7));
reserved.multiboot_end = (uint64_t)tag;

CORE_DEBUG("total MBI size %#x", (uint64_t)tag - (uint64_t)saved_mbi);

reserved.start = reserved.kernel_start;

// TODO: Add support for more modules. While most tags are unique in
// Multiboot2, this isn't the case for modules.
multiboot_tag_module_t* module = multiboot_find(MULTIBOOT_TAG_TYPE_MODULE);
if (module != NULL) {
CORE_DEBUG("module: cmdline=%s", module->cmdline);
reserved.end = module->mod_end;
}

// Adjust end in case we don't have any modules.
if (reserved.end < reserved.multiboot_end) {
reserved.end = reserved.multiboot_end;
}

CORE_DEBUG("kernel_start=%#x kernel_end=%#x multiboot_start=%#x "
"multiboot_end=%#x reserved start=%#x end=%#x",
"multiboot_end=%#x reserved_start=%#x reserved_end=%#x",
reserved.kernel_start,
reserved.kernel_end,
reserved.multiboot_start,
Expand All @@ -222,3 +125,21 @@ reserved_areas_t build_reserved_areas()

return reserved;
}

void* _multiboot_find(multiboot_tag_t* first_tag, uint16_t type)
{
multiboot_tag_t* tag = NULL;
for (tag = first_tag; tag->type != MULTIBOOT_TAG_TYPE_END;
// Round up to 8-byte boundary as per section "3.1.3 General tag
// structure" of the Multiboot2 spec.
tag = (multiboot_tag_t*)((
uint8_t*)(((uintptr_t)tag + tag->size + (8 - 1)) & -8))) {
if (tag->type == type) {
CORE_DEBUG("found tag for type=%d", type);
return tag;
}
}

CORE_DEBUG("could not find tag for type=%d", type);
return NULL;
}
22 changes: 5 additions & 17 deletions src/kernel/arch/x86_64/core/multiboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
#include <stdbool.h>
#include <stdint.h>

// The constants and structures in this file come from the Multiboot 2 header
// file released under the MIT license.
//
// Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.

// Flags set in the 'flags' member of the multiboot header.
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
Expand Down Expand Up @@ -62,23 +67,6 @@ typedef struct multiboot_tag_string
char string[];
} __attribute__((packed)) multiboot_tag_string_t;

typedef struct multiboot_tag_basic_meminfo
{
uint32_t type;
uint32_t size;
uint32_t mem_lower;
uint32_t mem_upper;
} __attribute__((packed)) multiboot_tag_basic_meminfo_t;

typedef struct multiboot_tag_bootdev
{
uint32_t type;
uint32_t size;
uint32_t biosdev;
uint32_t slice;
uint32_t part;
} __attribute__((packed)) multiboot_tag_bootdev_t;

typedef struct multiboot_tag_module
{
uint32_t type;
Expand Down
22 changes: 9 additions & 13 deletions src/kernel/arch/x86_64/kmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,20 @@
#include <stdlib.h>
#include <string.h>

void load_modules(multiboot_info_t* mbi);
void load_modules();
void load_network_config(inish_config_t* kernel_cfg, net_driver_t* driver);
void load_system_config(inish_config_t* kernel_cfg);

static uintptr_t initrd_addr = 0;

void load_modules(multiboot_info_t* mbi)
void load_modules()
{
for (multiboot_tag_t* tag = (multiboot_tag_t*)mbi->tags;
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (multiboot_tag_t*)((uint8_t*)tag + ((tag->size + 7) & ~7))) {
if (tag->type == MULTIBOOT_TAG_TYPE_MODULE) {
multiboot_tag_module_t* module = (multiboot_tag_module_t*)tag;

if (strcmp(module->cmdline, "initrd") == 0) {
initrd_addr = (uintptr_t)module->mod_start;
}
}
// TODO: See also comment in `src/kernel/arch/x86_64/core/multiboot.c` about
// the lack of support for more than one module.
multiboot_tag_module_t* module = multiboot_find(MULTIBOOT_TAG_TYPE_MODULE);

if (module != NULL && strcmp(module->cmdline, "initrd") == 0) {
initrd_addr = (uintptr_t)module->mod_start;
}
}

Expand Down Expand Up @@ -123,7 +119,7 @@ void kmain(uintptr_t addr)
alloc_init();
keyboard_init();

load_modules(mbi);
load_modules();

if (console_mode_is_vbe()) {
INFO("%s", "console: switching to fullscreen mode");
Expand Down

0 comments on commit ea6c6d5

Please sign in to comment.