summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarvin Borner2021-07-06 22:07:04 +0200
committerMarvin Borner2021-07-06 22:07:04 +0200
commitb2880945ae17ad857bd425540acd3dc75b2cff6b (patch)
treef5dea0028fb5e2b9072aa15f60c497bc7e20d13b
parent23aa6f84539ba320a91235fb81681d0754178f62 (diff)
Basic multiboot 1 detection and verification
-rw-r--r--example/mb1/entry.asm48
-rw-r--r--example/mb1/link.ld33
-rw-r--r--example/mb1/main.c16
-rw-r--r--example/mb1/makefile16
-rw-r--r--example/segelboot.cfg4
-rw-r--r--makefile7
-rwxr-xr-xrun1
-rw-r--r--src/loader/cfg.c68
-rw-r--r--src/loader/dev.c16
-rw-r--r--src/loader/dsk.c3
-rw-r--r--src/loader/fs/ext2.c2
-rw-r--r--src/loader/impl/all.c12
-rw-r--r--src/loader/impl/mb1.c55
-rw-r--r--src/loader/inc/cfg.h1
-rw-r--r--src/loader/inc/dev.h12
-rw-r--r--src/loader/inc/fs/ext2.h4
-rw-r--r--src/loader/inc/impl/all.h23
-rw-r--r--src/loader/inc/impl/mb1.h8
-rw-r--r--src/loader/inc/pnc.h4
-rw-r--r--src/loader/main.c1
-rw-r--r--src/loader/mbr.c2
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
diff --git a/makefile b/makefile
index 3c52077..3d310d0 100644
--- a/makefile
+++ b/makefile
@@ -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 $@
diff --git a/run b/run
index 31287fc..72ae723 100755
--- a/run
+++ b/run
@@ -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;