From 49f7738be2172696cfbc404ec90c5dd9443b0830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Mon, 4 Dec 2017 22:09:14 +0100 Subject: [PATCH] Parse multiboot information --- src/kernel/boot/boot.S | 3 + src/kernel/boot/kmain.c | 16 ++-- src/kernel/boot/multiboot.c | 42 ++++++++++ src/kernel/boot/multiboot.tt | 144 +++++++++++++++++++++++++++++++++ src/kernel/include/memory.h | 1 + src/kernel/include/multiboot.h | 25 ++++++ 6 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 src/kernel/boot/multiboot.c create mode 100644 src/kernel/boot/multiboot.tt create mode 100644 src/kernel/include/multiboot.h diff --git a/src/kernel/boot/boot.S b/src/kernel/boot/boot.S index cddc020..312a8a7 100644 --- a/src/kernel/boot/boot.S +++ b/src/kernel/boot/boot.S @@ -13,6 +13,9 @@ BootStack: _start: cli + mov edi, eax + mov esi, ebx + //; Set up a known stack mov esp, offset V2P(BootStack) diff --git a/src/kernel/boot/kmain.c b/src/kernel/boot/kmain.c index aaec318..3c322d2 100644 --- a/src/kernel/boot/kmain.c +++ b/src/kernel/boot/kmain.c @@ -2,18 +2,20 @@ #include #include #include +#include -void kmain() +void kmain(uint64_t multiboot_magic, void *multiboot_data) { serial_init(PORT_COM1); vga_init(); + debug_printf("kernel loaded\n"); - debug("Hello from debug printing function!\n"); - debug("A number:%d\n", 12345); - debug_info("Here's some info\n"); - debug_ok("This thing worked well!\n"); - debug_warning("Careful!\n"); - debug_error("Something went wrong!\n"); + + parse_multiboot(multiboot_magic, P2V(multiboot_data)); + + debug_printf("Hello from debug printing function!\n"); + debug_printf("A number:%d\n", 12345); + debug_printf("Multiboot data: %x, magic: %x\n", multiboot_data, multiboot_magic); PANIC("Reached end of kernel main function\n"); for(;;); diff --git a/src/kernel/boot/multiboot.c b/src/kernel/boot/multiboot.c new file mode 100644 index 0000000..3196070 --- /dev/null +++ b/src/kernel/boot/multiboot.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#define MBOOT_REPLY 0x36D76289 + +struct kernel_boot_data_st kernel_boot_data; + +int parse_multiboot2(struct mboot2_taglist *tags) +{ + struct mboot2_tag *tag = incptr(tags, sizeof(struct mboot2_taglist)); + while(tag->type) + { + switch(tag->type) + { + case MBOOT2_BOOTLOADER: + kernel_boot_data.bootloader = (char *)tag->data; + break; + case MBOOT2_COMMANDLINE: + kernel_boot_data.commandline = (char *)tag->data; + break; + default: + debug("[info] Unknown multiboot tag type:%d \n", tag->type); + } + int padded_size = tag->size + ((tag->size % 8)?(8-(tag->size%8)):0); + tag = incptr(tag, padded_size); + } + return 0; +} + +int parse_multiboot(uint64_t magic, void *mboot_info) +{ + if(magic == MBOOT_REPLY) + { + kernel_boot_data.multiboot_version = 2; + parse_multiboot2(mboot_info); + } + else + return 1; + + return 0; +} diff --git a/src/kernel/boot/multiboot.tt b/src/kernel/boot/multiboot.tt new file mode 100644 index 0000000..6f3acf9 --- /dev/null +++ b/src/kernel/boot/multiboot.tt @@ -0,0 +1,144 @@ +// vim: ft=c +#include + +#include +#include +#undef debug +#define debug(...) +#undef P2V +#define P2V(addr) (void *)((uintptr_t)(addr)) +#include "multiboot.c" + +#include +#include + +#define MAGIC 0x36D76289 + +struct mboot2_tag *generate_tag(uint32_t type, void *data, uint32_t data_size) +{ + struct mboot2_tag *tag = calloc(1, sizeof(struct mboot2_tag) + data_size); + tag->type = type; + tag->size = sizeof(struct mboot2_tag) + data_size; + if(data_size) + memcpy(tag->data, data, data_size); + return tag; +} + +#define padded_size(tag) (tag->size + ((tag->size%8)?(8-(tag->size%8)):0)) + +struct mboot2_taglist *generate_taglist(int num, ...) +{ + va_list args; + va_start(args, num); + uint32_t total_size = sizeof(struct mboot2_taglist); + struct mboot2_tag **tags = calloc(num, sizeof(struct mboot2_tag *)); + for(int i = 0; i < num; i++) + { + tags[i] = va_arg(args, struct mboot2_tag *); + total_size += padded_size(tags[i]); + } + + struct mboot2_taglist *taglist = calloc(1, total_size); + taglist->total_size = total_size; + + int pos = 8; + uint8_t *p = (uint8_t *)taglist; + for(int i = 0; i < num; i++) + { + memcpy(&p[pos], tags[i], tags[i]->size); + pos += padded_size(tags[i]); + free(tags[i]); + } + va_end(args); + + return taglist; +} + +TEST(correctly_identifies_multiboot2_magic) +{ + uint32_t tags[] = {16, 0, 0, 8}; + parse_multiboot(MAGIC, tags); + ASSERT_EQ_INT(kernel_boot_data.multiboot_version, 2); +} + +TEST(reads_boot_loader_name) +{ + char *name = "ttest"; + struct mboot2_taglist *tags = generate_taglist(2, + generate_tag(2, name, strlen(name) + 1), + generate_tag(0,0,0)); + + parse_multiboot(MAGIC, tags); + ASSERT_EQ_STR(kernel_boot_data.bootloader, name, strlen(name)); + free(tags); +} +TEST(reads_kernel_commandline) +{ + char *cmd = "mittos64-kern boot"; + struct mboot2_taglist *tags = generate_taglist(2, + generate_tag(1, cmd, strlen(cmd) + 1), + generate_tag(0,0,0)); + + parse_multiboot(MAGIC, tags); + ASSERT_EQ_STR(kernel_boot_data.commandline, cmd, strlen(cmd)); + free(tags); +} +// Here are four very simmilar tests +// The difference is what values are checked and the order of the tags +// Their existence is based on experience - helped me actually find a bug +TEST(reads_multiple_tags_1) +{ + char *cmd = "mittos64-kern boot"; + char *name = "ttest"; + struct mboot2_taglist *tags = generate_taglist(3, + generate_tag(1, cmd, strlen(cmd) + 1), + generate_tag(2, name, strlen(name) + 1), + generate_tag(0,0,0) + ); + + parse_multiboot(MAGIC, tags); + ASSERT_EQ_STR(kernel_boot_data.commandline, cmd, strlen(cmd)); + free(tags); +} +TEST(reads_multiple_tags_2) +{ + char *cmd = "mittos64-kern boot"; + char *name = "ttest"; + struct mboot2_taglist *tags = generate_taglist(3, + generate_tag(1, cmd, strlen(cmd) + 1), + generate_tag(2, name, strlen(name) + 1), + generate_tag(0,0,0) + ); + + parse_multiboot(MAGIC, tags); + ASSERT_EQ_STR(kernel_boot_data.bootloader, name, strlen(name)); + free(tags); +} +TEST(reads_multiple_tags_3) +{ + char *cmd = "mittos64-kern boot"; + char *name = "ttest"; + struct mboot2_taglist *tags = generate_taglist(3, + generate_tag(2, name, strlen(name) + 1), + generate_tag(1, cmd, strlen(cmd) + 1), + generate_tag(0,0,0) + ); + + parse_multiboot(MAGIC, tags); + ASSERT_EQ_STR(kernel_boot_data.commandline, cmd, strlen(cmd)); + free(tags); +} +TEST(reads_multiple_tags_4) +{ + char *cmd = "mittos64-kern boot"; + char *name = "ttest"; + struct mboot2_taglist *tags = generate_taglist(3, + generate_tag(2, name, strlen(name) + 1), + generate_tag(1, cmd, strlen(cmd) + 1), + generate_tag(0,0,0) + ); + + parse_multiboot(MAGIC, tags); + ASSERT_EQ_STR(kernel_boot_data.bootloader, name, strlen(name)); + free(tags); +} diff --git a/src/kernel/include/memory.h b/src/kernel/include/memory.h index 17cb7a4..f5300f3 100644 --- a/src/kernel/include/memory.h +++ b/src/kernel/include/memory.h @@ -8,6 +8,7 @@ #include #define V2P(a) ((uintptr_t)(a) & ~KERNEL_OFFSET) #define P2V(a) ((void *)((uintptr_t)(a) | KERNEL_OFFSET)) +#define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n))) #endif #define P1_OFFSET(a) (((a)>>12) & 0x1FF) diff --git a/src/kernel/include/multiboot.h b/src/kernel/include/multiboot.h new file mode 100644 index 0000000..0b5a353 --- /dev/null +++ b/src/kernel/include/multiboot.h @@ -0,0 +1,25 @@ +#pragma once +#include +struct kernel_boot_data_st +{ + int multiboot_version; + char *bootloader; + char *commandline; +}; + +struct kernel_boot_data_st kernel_boot_data; + +struct mboot2_taglist{ + uint32_t total_size; + uint32_t reserved; +}__attribute__((packed)); +struct mboot2_tag { + uint32_t type; + uint32_t size; + uint8_t data[]; +}__attribute__((packed)); + +#define MBOOT2_COMMANDLINE 1 +#define MBOOT2_BOOTLOADER 2 + +int parse_multiboot(uint64_t magic, void *mboot_info);