diff options
author | Marvin Borner | 2021-07-06 22:07:04 +0200 |
---|---|---|
committer | Marvin Borner | 2021-07-06 22:07:04 +0200 |
commit | b2880945ae17ad857bd425540acd3dc75b2cff6b (patch) | |
tree | f5dea0028fb5e2b9072aa15f60c497bc7e20d13b | |
parent | 23aa6f84539ba320a91235fb81681d0754178f62 (diff) |
Basic multiboot 1 detection and verification
-rw-r--r-- | example/mb1/entry.asm | 48 | ||||
-rw-r--r-- | example/mb1/link.ld | 33 | ||||
-rw-r--r-- | example/mb1/main.c | 16 | ||||
-rw-r--r-- | example/mb1/makefile | 16 | ||||
-rw-r--r-- | example/segelboot.cfg | 4 | ||||
-rw-r--r-- | makefile | 7 | ||||
-rwxr-xr-x | run | 1 | ||||
-rw-r--r-- | src/loader/cfg.c | 68 | ||||
-rw-r--r-- | src/loader/dev.c | 16 | ||||
-rw-r--r-- | src/loader/dsk.c | 3 | ||||
-rw-r--r-- | src/loader/fs/ext2.c | 2 | ||||
-rw-r--r-- | src/loader/impl/all.c | 12 | ||||
-rw-r--r-- | src/loader/impl/mb1.c | 55 | ||||
-rw-r--r-- | src/loader/inc/cfg.h | 1 | ||||
-rw-r--r-- | src/loader/inc/dev.h | 12 | ||||
-rw-r--r-- | src/loader/inc/fs/ext2.h | 4 | ||||
-rw-r--r-- | src/loader/inc/impl/all.h | 23 | ||||
-rw-r--r-- | src/loader/inc/impl/mb1.h | 8 | ||||
-rw-r--r-- | src/loader/inc/pnc.h | 4 | ||||
-rw-r--r-- | src/loader/main.c | 1 | ||||
-rw-r--r-- | src/loader/mbr.c | 2 |
21 files changed, 301 insertions, 35 deletions
diff --git a/example/mb1/entry.asm b/example/mb1/entry.asm new file mode 100644 index 0000000..8b8f47e --- /dev/null +++ b/example/mb1/entry.asm @@ -0,0 +1,48 @@ +; MIT License, Copyright (c) 2021 Marvin Borner + +bits 32 + +%define MULTIBOOT_MAGIC 0x1badb002 +%define MULTIBOOT_PAGE_ALIGN 0x1 +%define MULTIBOOT_MEMORY_INFO 0x2 +%define MULTIBOOT_VIDEO_MODE 0x4 +%define MULTIBOOT_FLAGS (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE) +%define MULTIBOOT_CHECKSUM -(MULTIBOOT_MAGIC + MULTIBOOT_FLAGS) + +section .text +align 4 + +dd MULTIBOOT_MAGIC +dd MULTIBOOT_FLAGS +dd MULTIBOOT_CHECKSUM + +; MULTIBOOT_MEMORY_INFO +dd 0x00000000 +dd 0x00000000 +dd 0x00000000 +dd 0x00000000 +dd 0x00000000 + +; MULTIBOOT_VIDEO_MODE +dd 0x00000000 +dd 1920 +dd 1200 +dd 32 + +global boot_entry +extern kernel_main +boot_entry: + mov esp, stack_top + push esp + push ebx + push eax + cli + call kernel_main + hlt + jmp $ + +section .bss +align 32 +stack_bottom: + resb 0x4000 +stack_top: diff --git a/example/mb1/link.ld b/example/mb1/link.ld new file mode 100644 index 0000000..0d79ef4 --- /dev/null +++ b/example/mb1/link.ld @@ -0,0 +1,33 @@ +/* MIT License, Copyright (c) 2021 Marvin Borner */ + +OUTPUT_ARCH(i386) +ENTRY(boot_entry) +phys = 0x00100000; + +SECTIONS +{ + . = phys; + + .text BLOCK(4K) : ALIGN(4K) + { + *(.text*) + } + + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata*) + } + + .data BLOCK(4K) : ALIGN(4K) + { + *(.data*) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } + + end = .; +} diff --git a/example/mb1/main.c b/example/mb1/main.c new file mode 100644 index 0000000..0174803 --- /dev/null +++ b/example/mb1/main.c @@ -0,0 +1,16 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +typedef unsigned int u32; + +int kernel_main(u32 magic, u32 addr, u32 esp); // Decl +int kernel_main(u32 magic, u32 addr, u32 esp) +{ + (void)magic; + (void)addr; + (void)esp; + + while (1) + ; + + return 1; +} diff --git a/example/mb1/makefile b/example/mb1/makefile new file mode 100644 index 0000000..1a4e79b --- /dev/null +++ b/example/mb1/makefile @@ -0,0 +1,16 @@ +# MIT License, Copyright (c) 2021 Marvin Borner +# Gets called by main makefile (their variables are exported) + +OBJS = entry_asm.o main.o + +all: compile + +%.o: %.c + @$(CC) -c $(CFLAGS) $< -o $@ + +%_asm.o: %.asm + @$(AS) $(ASFLAGS) $< -o $@ + +compile: $(OBJS) + @mkdir -p $(BLD)/examples/ + @$(LD) -N -z max-page-size=0x1000 -eboot_entry -Tlink.ld -o $(BLD)/examples/mb1.elf $+ diff --git a/example/segelboot.cfg b/example/segelboot.cfg index 17a7d14..65938eb 100644 --- a/example/segelboot.cfg +++ b/example/segelboot.cfg @@ -3,5 +3,5 @@ TIMEOUT=10 # Multiboot 1 PATH=hda0:/boot/mb1.elf -# Multiboot 2 -PATH=hda0:/boot/mb2.elf +# Multiboot 2 (TODO) +PATH=hda0:/boot/mb1.elf @@ -27,13 +27,18 @@ CFLAGS = $(WARNINGS) -std=c99 -m32 -nostdlib -nostdinc -ffunction-sections -fno- ASFLAGS = -f elf32 -all: dir $(BLD)/boot.bin +export + +all: dir $(BLD)/boot.bin mb1 dir: @mkdir -p $(BLD)/entry/ @mkdir -p $(BLD)/loader/fs/ @mkdir -p $(BLD)/loader/impl/ +mb1: + @$(MAKE) --no-print-directory -C example/$@ + $(BLD)/boot.bin: $(BLD)/loader.bin @$(AS) $(ASFLAGS) -f bin $(SRC)/entry/bootsector.asm -o $@ @@ -97,6 +97,7 @@ build() { $SUDO mount "$DEV$PART" mnt/ $SUDO mkdir -p mnt/boot/ $SUDO cp example/segelboot.cfg mnt/boot/ + $SUDO cp build/examples/* mnt/boot/ $SUDO umount mnt/ || (sync && $SUDO umount mnt/) rm -rf mnt/ diff --git a/src/loader/cfg.c b/src/loader/cfg.c index 37794e6..a55533e 100644 --- a/src/loader/cfg.c +++ b/src/loader/cfg.c @@ -17,6 +17,7 @@ struct { u8 exists : 1; char name[64]; char path[64]; + struct dev *dev; } elem[16]; // Up to 16 different selections } cfg = { 0 }; @@ -26,10 +27,10 @@ static char file[1024] = { 0 }; // Find config file static u8 cfg_find(struct dev *dev) { - if (!dev->fs.read) + if (!dev->p.disk.fs.read) return 0; // No fs found or not readable - continue! - s32 res = dev->fs.read("/boot/segelboot.cfg", file, 0, sizeof(file), dev); + s32 res = dev->p.disk.fs.read("/boot/segelboot.cfg", file, 0, sizeof(file), dev); if (res > 0) return 1; // Break foreach @@ -67,6 +68,21 @@ static void cfg_add(u8 index, enum cfg_key key, const char *value) } } +const void *cfg_get(u8 index, enum cfg_key key) +{ + switch (key) { + case CFG_NAME: + return &cfg.elem[index].path; + case CFG_TIMEOUT: + return &cfg.timeout; + case CFG_PATH: + return &cfg.elem[index].path; + case CFG_NONE: + default: + return NULL; + } +} + // TODO: This code is kind of messy // Structure per line: KEY=VALUE static void cfg_parse(void) @@ -141,22 +157,44 @@ static void cfg_parse(void) } } -const void *cfg_get(u8 index, enum cfg_key key) +// Extract the disk from path by returning index of delimiter or 0xff +// Example: disk:/boot/config.cfg returns 4 (:) +static u8 cfg_path_disk(const char *path) { - switch (key) { - case CFG_NAME: - return &cfg.elem[index].path; - case CFG_TIMEOUT: - return &cfg.timeout; - case CFG_PATH: - return &cfg.elem[index].path; - case CFG_NONE: - default: - return NULL; + for (const char *p = path; *p; p++) + if (*p == ':') + return p - path; + return 0xff; +} + +// Find matching disk dev for every entry and verify path existence and readability +static void cfg_verify(void) +{ + for (u8 i = 0; i < COUNT(cfg.elem) && cfg.elem[i].exists; i++) { + u8 len = cfg_path_disk(cfg.elem[i].path); + struct dev *dev = dev_get_by_name(cfg.elem[i].path, len); + if (!dev || dev->type != DEV_DISK) + panic("Invalid device in config\n"); + cfg.elem[i].dev = dev; + + if (!dev->p.disk.fs.read) + panic("Device fs not readable\n"); + + // This is now the correct path (due to "disk:PATH") + const char *path = &cfg.elem[i].path[len + 1]; + + u8 buf[1] = { 0 }; // Just for existence-check + s32 ret = dev->p.disk.fs.read(path, buf, 0, sizeof(buf), dev); + if (ret != 1 || !buf[0]) + panic("Path is invalid\n"); + + if (!impl_detect(dev, path)) + panic("No boot implementation found\n"); } } -void cfg_print(void) +// Print all configs and entry values +static void cfg_print(void) { log("[CFG] Global: %d\n", cfg.timeout); @@ -170,4 +208,6 @@ void cfg_exec(void) if (!file[0]) panic("No config found\n"); cfg_parse(); + cfg_print(); + cfg_verify(); } diff --git a/src/loader/dev.c b/src/loader/dev.c index 591d5a2..3cdef10 100644 --- a/src/loader/dev.c +++ b/src/loader/dev.c @@ -19,12 +19,26 @@ static const char *dev_resolve_type(enum dev_type type) } } -struct dev *dev_get(u8 id) +struct dev *dev_get_by_id(u8 id) { assert(id < COUNT(devices)); return &devices[id]; } +struct dev *dev_get_by_name(const char *name, u32 len) +{ + if (!name || !name[0]) + return NULL; + + for (u8 i = 0; i < COUNT(devices); i++) { + struct dev *dev = &devices[i]; + if (strncmp(dev->name, name, MIN(sizeof(dev->name), len)) == 0) + return dev; + } + + return NULL; +} + void dev_foreach(enum dev_type type, u8 (*cb)(struct dev *)) { for (u8 i = 0; i < COUNT(devices); i++) { diff --git a/src/loader/dsk.c b/src/loader/dsk.c index 338c985..5e8fc3d 100644 --- a/src/loader/dsk.c +++ b/src/loader/dsk.c @@ -4,9 +4,12 @@ #include <fs/ext2.h> #include <log.h> #include <mbr.h> +#include <pnc.h> void dsk_detect(struct dev *dev) { + assert(dev->type == DEV_DISK); + if (mbr_detect(dev)) return; diff --git a/src/loader/fs/ext2.c b/src/loader/fs/ext2.c index a7d4662..72fd3c0 100644 --- a/src/loader/fs/ext2.c +++ b/src/loader/fs/ext2.c @@ -195,7 +195,7 @@ u8 ext2_detect(struct dev *dev) if (sb.magic != EXT2_MAGIC) return 0; - dev->fs.read = ext2_read; + dev->p.disk.fs.read = ext2_read; return 1; } diff --git a/src/loader/impl/all.c b/src/loader/impl/all.c new file mode 100644 index 0000000..1f19b1e --- /dev/null +++ b/src/loader/impl/all.c @@ -0,0 +1,12 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <impl/all.h> +#include <impl/mb1.h> + +u8 impl_detect(struct dev *dev, const char *path) +{ + if (mb1_detect(dev, path)) + return 1; + + return 0; +} diff --git a/src/loader/impl/mb1.c b/src/loader/impl/mb1.c index 5265082..cb75976 100644 --- a/src/loader/impl/mb1.c +++ b/src/loader/impl/mb1.c @@ -1,9 +1,60 @@ // MIT License, Copyright (c) 2021 Marvin Borner +// Everything according to spec #include <impl/mb1.h> +#include <pnc.h> -u8 mb1_probe(struct dev *dev) +#define MB1_MAGIC 0x1badb002 + +struct multiboot_entry { + u32 magic; + u32 flags; + u32 checksum; // Everything after that is optional + u32 header_addr; + u32 load_addr; + u32 load_end_addr; + u32 bss_end_addr; + u32 entry_addr; + u32 mode_type; + u32 width; + u32 height; + u32 depth; +}; + +// The (really simple) multiboot checksum algorithm +static u32 mb1_checksum(struct multiboot_entry *entry) +{ + return -(entry->magic + entry->flags); +} + +// Detect and verify mb1 +u8 mb1_detect(struct dev *dev, const char *path) { - (void)dev; + u8 header[8192] = { 0 }; + + s32 ret = dev->p.disk.fs.read(path, header, 0, sizeof(header), dev); + if (ret < 12) + return 0; + + // Find start of multiboot entry by searching for magic + struct multiboot_entry *entry = 0; + for (u32 i = 0; i < sizeof(header); i++) { + u32 *p = (u32 *)&header[i]; + if (*p == MB1_MAGIC) { + entry = (void *)p; + break; + } + } + + if (!entry) + return 0; + + u32 checksum = mb1_checksum(entry); + if (checksum != entry->checksum) + return 0; + + dev->p.disk.impl.type = IMPL_MB1; + dev->p.disk.impl.start = entry; + return 1; } diff --git a/src/loader/inc/cfg.h b/src/loader/inc/cfg.h index a214db2..1332fe1 100644 --- a/src/loader/inc/cfg.h +++ b/src/loader/inc/cfg.h @@ -17,6 +17,5 @@ enum cfg_key { const void *cfg_get(u8 index, enum cfg_key key); void cfg_exec(void); -void cfg_print(void); #endif diff --git a/src/loader/inc/dev.h b/src/loader/inc/dev.h index 9d9913e..9e64bdb 100644 --- a/src/loader/inc/dev.h +++ b/src/loader/inc/dev.h @@ -5,6 +5,7 @@ #include <def.h> #include <dsk.h> +#include <impl/all.h> enum dev_type { DEV_DISK, @@ -19,12 +20,19 @@ struct dev { s32 (*read)(void *, u32, u32, struct dev *); s32 (*write)(const void *, u32, u32, struct dev *); - struct fs fs; + union { + struct { + struct fs fs; + struct impl impl; + } disk; + // TODO: Other (framebuffer?) + } p; // Prototype union u32 data; // Optional (device-specific) data/information }; -struct dev *dev_get(u8 id); +struct dev *dev_get_by_id(u8 id); +struct dev *dev_get_by_name(const char *name, u32 len); void dev_foreach(enum dev_type type, u8 (*cb)(struct dev *)); // cb=1 => break u8 dev_register(enum dev_type type, char *name, u32 data, s32 (*read)(void *, u32, u32, struct dev *), diff --git a/src/loader/inc/fs/ext2.h b/src/loader/inc/fs/ext2.h index 10650cd..0c2052a 100644 --- a/src/loader/inc/fs/ext2.h +++ b/src/loader/inc/fs/ext2.h @@ -1,7 +1,7 @@ // MIT License, Copyright (c) 2021 Marvin Borner -#ifndef EXT2_H -#define EXT2_H +#ifndef FS_EXT2_H +#define FS_EXT2_H #include <def.h> #include <dev.h> diff --git a/src/loader/inc/impl/all.h b/src/loader/inc/impl/all.h new file mode 100644 index 0000000..366b1b3 --- /dev/null +++ b/src/loader/inc/impl/all.h @@ -0,0 +1,23 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef IMPL_ALL_H +#define IMPL_ALL_H + +#include <def.h> + +enum impl_type { + IMPL_NONE, + IMPL_MB1, + IMPL_MB2, +}; + +struct impl { + enum impl_type type; + void *start; // Of header/entry +}; + +#include <dev.h> + +u8 impl_detect(struct dev *dev, const char *path); + +#endif diff --git a/src/loader/inc/impl/mb1.h b/src/loader/inc/impl/mb1.h index fa0efc1..fcaf048 100644 --- a/src/loader/inc/impl/mb1.h +++ b/src/loader/inc/impl/mb1.h @@ -1,13 +1,11 @@ // MIT License, Copyright (c) 2021 Marvin Borner -#ifndef MB1_H -#define MB1_H +#ifndef IMPL_MB1_H +#define IMPL_MB1_H #include <def.h> #include <dev.h> -#define MB1_MAGIC 0x1badb002 - -u8 mb1_probe(struct dev *dev); +u8 mb1_detect(struct dev *dev, const char *path); #endif diff --git a/src/loader/inc/pnc.h b/src/loader/inc/pnc.h index 3de3364..1630bd9 100644 --- a/src/loader/inc/pnc.h +++ b/src/loader/inc/pnc.h @@ -7,7 +7,7 @@ #define panic(reason) \ { \ - log("%s:%d: %s: Panic: %s\n", __FILE__, __LINE__, __func__, (reason)); \ + log("%s:%d: %s: Panic: %s", __FILE__, __LINE__, __func__, (reason)); \ while (1) \ __asm__ volatile("cli\nhlt"); \ } @@ -15,7 +15,7 @@ #define assert(exp) \ { \ if (!(exp)) \ - panic("Assertion '" #exp "' failed"); \ + panic("Assertion '" #exp "' failed\n"); \ } #endif diff --git a/src/loader/main.c b/src/loader/main.c index f01a93b..bb12c80 100644 --- a/src/loader/main.c +++ b/src/loader/main.c @@ -28,7 +28,6 @@ int start(void) dev_print(); cfg_exec(); - cfg_print(); // Sleep and wait for interrupts while (1) diff --git a/src/loader/mbr.c b/src/loader/mbr.c index 599952c..df0c1db 100644 --- a/src/loader/mbr.c +++ b/src/loader/mbr.c @@ -10,7 +10,7 @@ static struct mbr_entry entries[16] = { 0 }; static s32 mbr_read(void *buf, u32 lba, u32 sector_count, struct dev *part) { u8 dev_id = (part->data & 0xff00) >> 8; - struct dev *dev = dev_get(dev_id); + struct dev *dev = dev_get_by_id(dev_id); assert(dev && dev->type == DEV_DISK && dev->read); u8 mbr_id = part->data & 0xff; |