From 1b429c0fc28e5cd8b474ad5a1de1fa6f3d7c2e2a Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Mon, 12 Jul 2021 18:14:44 +0200 Subject: Renamed files to match presentation --- example/segelboot.cfg | 3 + makefile | 2 +- run | 4 + src/loader/a20.c | 8 +- src/loader/acpi.c | 4 +- src/loader/cfg.c | 210 ----------------------------------------- src/loader/config.c | 210 +++++++++++++++++++++++++++++++++++++++++ src/loader/dev.c | 84 ----------------- src/loader/device.c | 84 +++++++++++++++++ src/loader/disk.c | 20 ++++ src/loader/dsk.c | 20 ---- src/loader/elf.c | 4 +- src/loader/format.c | 60 ++++++++++++ src/loader/fs/ext2.c | 6 +- src/loader/gui.c | 18 ++-- src/loader/ide.c | 12 +-- src/loader/impl/all.c | 36 ------- src/loader/impl/mb1.c | 147 ----------------------------- src/loader/impl/mb2.c | 105 --------------------- src/loader/inc/cfg.h | 39 -------- src/loader/inc/config.h | 39 ++++++++ src/loader/inc/dev.h | 41 -------- src/loader/inc/device.h | 41 ++++++++ src/loader/inc/disk.h | 21 +++++ src/loader/inc/dsk.h | 21 ----- src/loader/inc/elf.h | 2 +- src/loader/inc/fs/ext2.h | 2 +- src/loader/inc/impl.h | 20 ---- src/loader/inc/impl/all.h | 12 --- src/loader/inc/impl/mb1.h | 134 -------------------------- src/loader/inc/impl/mb2.h | 61 ------------ src/loader/inc/int.h | 49 ---------- src/loader/inc/interrupt.h | 49 ++++++++++ src/loader/inc/lib.h | 20 ---- src/loader/inc/library.h | 20 ++++ src/loader/inc/log.h | 5 +- src/loader/inc/mbr.h | 2 +- src/loader/inc/mem.h | 32 ------- src/loader/inc/memory.h | 32 +++++++ src/loader/inc/panic.h | 24 +++++ src/loader/inc/pic.h | 2 +- src/loader/inc/pnc.h | 24 ----- src/loader/inc/protocol.h | 20 ++++ src/loader/inc/protocols/all.h | 12 +++ src/loader/inc/protocols/mb1.h | 134 ++++++++++++++++++++++++++ src/loader/inc/protocols/mb2.h | 61 ++++++++++++ src/loader/inc/real.h | 29 ++++++ src/loader/inc/rem.h | 29 ------ src/loader/int.asm | 149 ----------------------------- src/loader/int.c | 132 -------------------------- src/loader/interrupt.asm | 149 +++++++++++++++++++++++++++++ src/loader/interrupt.c | 132 ++++++++++++++++++++++++++ src/loader/jmp.asm | 28 ------ src/loader/jumper.asm | 28 ++++++ src/loader/lib.c | 172 --------------------------------- src/loader/library.c | 172 +++++++++++++++++++++++++++++++++ src/loader/log.c | 189 ------------------------------------- src/loader/main.c | 14 +-- src/loader/mbr.c | 14 +-- src/loader/mem.c | 125 ------------------------ src/loader/memory.c | 125 ++++++++++++++++++++++++ src/loader/pic.c | 4 +- src/loader/protocols/all.c | 36 +++++++ src/loader/protocols/mb1.c | 147 +++++++++++++++++++++++++++++ src/loader/protocols/mb2.c | 105 +++++++++++++++++++++ src/loader/real.asm | 139 +++++++++++++++++++++++++++ src/loader/rem.asm | 139 --------------------------- src/loader/serial.c | 57 +++++++++++ src/loader/vga.c | 64 +++++++++++++ 69 files changed, 2067 insertions(+), 2067 deletions(-) delete mode 100644 src/loader/cfg.c create mode 100644 src/loader/config.c delete mode 100644 src/loader/dev.c create mode 100644 src/loader/device.c create mode 100644 src/loader/disk.c delete mode 100644 src/loader/dsk.c create mode 100644 src/loader/format.c delete mode 100644 src/loader/impl/all.c delete mode 100644 src/loader/impl/mb1.c delete mode 100644 src/loader/impl/mb2.c delete mode 100644 src/loader/inc/cfg.h create mode 100644 src/loader/inc/config.h delete mode 100644 src/loader/inc/dev.h create mode 100644 src/loader/inc/device.h create mode 100644 src/loader/inc/disk.h delete mode 100644 src/loader/inc/dsk.h delete mode 100644 src/loader/inc/impl.h delete mode 100644 src/loader/inc/impl/all.h delete mode 100644 src/loader/inc/impl/mb1.h delete mode 100644 src/loader/inc/impl/mb2.h delete mode 100644 src/loader/inc/int.h create mode 100644 src/loader/inc/interrupt.h delete mode 100644 src/loader/inc/lib.h create mode 100644 src/loader/inc/library.h delete mode 100644 src/loader/inc/mem.h create mode 100644 src/loader/inc/memory.h create mode 100644 src/loader/inc/panic.h delete mode 100644 src/loader/inc/pnc.h create mode 100644 src/loader/inc/protocol.h create mode 100644 src/loader/inc/protocols/all.h create mode 100644 src/loader/inc/protocols/mb1.h create mode 100644 src/loader/inc/protocols/mb2.h create mode 100644 src/loader/inc/real.h delete mode 100644 src/loader/inc/rem.h delete mode 100644 src/loader/int.asm delete mode 100644 src/loader/int.c create mode 100644 src/loader/interrupt.asm create mode 100644 src/loader/interrupt.c delete mode 100644 src/loader/jmp.asm create mode 100644 src/loader/jumper.asm delete mode 100644 src/loader/lib.c create mode 100644 src/loader/library.c delete mode 100644 src/loader/log.c delete mode 100644 src/loader/mem.c create mode 100644 src/loader/memory.c create mode 100644 src/loader/protocols/all.c create mode 100644 src/loader/protocols/mb1.c create mode 100644 src/loader/protocols/mb2.c create mode 100644 src/loader/real.asm delete mode 100644 src/loader/rem.asm create mode 100644 src/loader/serial.c create mode 100644 src/loader/vga.c diff --git a/example/segelboot.cfg b/example/segelboot.cfg index d30fc0d..640ebca 100644 --- a/example/segelboot.cfg +++ b/example/segelboot.cfg @@ -1,5 +1,8 @@ TIMEOUT=10 +# Melvix +PATH=hda0:/apps/kernel/exec + # Multiboot 1 PATH=hda0:/boot/mb1.elf diff --git a/makefile b/makefile index 6619bb8..47f8537 100644 --- a/makefile +++ b/makefile @@ -34,7 +34,7 @@ all: dir $(BLD)/boot.bin mb1 mb2 dir: @mkdir -p $(BLD)/entry/ @mkdir -p $(BLD)/loader/fs/ - @mkdir -p $(BLD)/loader/impl/ + @mkdir -p $(BLD)/loader/protocols/ mb1: @$(MAKE) --no-print-directory -C example/$@ diff --git a/run b/run index ee456ae..129b1d9 100755 --- a/run +++ b/run @@ -98,6 +98,10 @@ build() { $SUDO mkdir -p mnt/boot/ $SUDO cp example/segelboot.cfg mnt/boot/ $SUDO cp build/examples/* mnt/boot/ + + $SUDO cp -r "$HOME"/code/melvix/disk/* mnt/ || true + $SUDO cp -r "$HOME"/code/melvix/build/apps/ mnt/apps/ || true + $SUDO umount mnt/ || (sync && $SUDO umount mnt/) rm -rf mnt/ diff --git a/src/loader/a20.c b/src/loader/a20.c index b59500a..ecb4594 100644 --- a/src/loader/a20.c +++ b/src/loader/a20.c @@ -4,8 +4,8 @@ #include #include #include -#include -#include +#include +#include static u8 a20_check(void) { @@ -26,9 +26,9 @@ void a20_enable(void) return; // BIOS method - struct rem_regs r = { 0 }; + struct real_regs r = { 0 }; r.eax = 0x2401; - rem_int(0x15, &r, &r); + real_int(0x15, &r, &r); if (a20_check()) return; diff --git a/src/loader/acpi.c b/src/loader/acpi.c index f7e958c..b010a6a 100644 --- a/src/loader/acpi.c +++ b/src/loader/acpi.c @@ -1,8 +1,8 @@ // MIT License, Copyright (c) 2021 Marvin Borner #include -#include -#include +#include +#include /** * General SDP diff --git a/src/loader/cfg.c b/src/loader/cfg.c deleted file mode 100644 index bbe215a..0000000 --- a/src/loader/cfg.c +++ /dev/null @@ -1,210 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#include -#include -#include -#include -#include -#include - -// Keys -#define TIMEOUT "TIMEOUT" -#define PATH "PATH" - -// Config structure -static struct cfg cfg = { 0 }; - -// Config file contents (if found) -static char file[1024] = { 0 }; - -// Find config file -static u8 cfg_find(struct dev *dev) -{ - if (!dev->p.disk.fs.read) - return 0; // No fs found or not readable - continue! - - s32 res = dev->p.disk.fs.read("/boot/segelboot.cfg", file, 0, sizeof(file), dev); - if (res > 0) - return 1; // Break foreach - - // Continue foreach - return 0; -} - -// Checks if index is appropriate as some key/value need to be in entry -static void cfg_in_entry(u8 index) -{ - if (index == 0xff) - panic("No entry name given\n"); -} - -// Add/overwrite value by key and entry index -static void cfg_add(u8 index, enum cfg_key key, const char *value) -{ - struct cfg_entry *entry = &cfg.entry[index]; - entry->exists = 1; - - switch (key) { - case CFG_NAME: - cfg_in_entry(index); - strlcpy(entry->name, value, sizeof(entry->name)); - break; - case CFG_TIMEOUT: - cfg.timeout = atoi(value); - break; - case CFG_PATH: - cfg_in_entry(index); - strlcpy(entry->full_path, value, sizeof(entry->full_path)); - break; - case CFG_NONE: - default: - panic("Invalid config\n"); - } -} - -// TODO: This code is kind of messy -// Structure per line: KEY=VALUE -static void cfg_parse(void) -{ - // Entry index - u8 entry = 0xff; - - // Value per key - char value[64] = { 0 }; - u8 value_index = 0; - - // States - enum cfg_key current = CFG_NONE; // Value key type - u8 state = 0; // 0 is key, 1 is value, 2 is entry - - const char *start = file; // Start is at the beginning of the key - for (const char *p = start; *p; p++) { - if (state == 0) { - // We're at key parsing - if (*p == '\n') { // A key can't just end but ok - start = p + 1; - } else if (*p == '#') { - state = 2; // Let's parse the entry name - p++; - continue; - } else if (*p != '=') { - continue; - } - - // The key is now at start until p - u8 diff = p - start; - - // Timeout key - if (diff == sizeof(TIMEOUT) - 1 && memcmp(start, TIMEOUT, diff) == 0) { - current = CFG_TIMEOUT; - state = 1; - continue; - } - - // Path key - if (diff == sizeof(PATH) - 1 && memcmp(start, PATH, diff) == 0) { - current = CFG_PATH; - state = 1; - continue; - } - } else if (state == 1) { - // We're at value parsing - assert(value_index + 1 < (u8)sizeof(value)); - if (*p == '\n') { // Finished - value[value_index] = 0; - cfg_add(entry, current, value); - value_index = 0; - state = 0; - p--; // Repeat parse normally - } else { - value[value_index++] = *p; - } - } else if (state == 2) { - // We're at entry name parsing - assert(value_index + 1 < (u8)sizeof(value)); - if (*p == '\n') { // Finished - entry = entry == 0xff ? 0 : entry + 1; - value[value_index] = 0; - cfg_add(entry, CFG_NAME, value); - value_index = 0; - state = 0; - p--; // Repeat parse normally - } else { - value[value_index++] = *p; - } - } - } -} - -// 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) -{ - 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.entry) && cfg.entry[i].exists; i++) { - struct cfg_entry *entry = &cfg.entry[i]; - - u8 len = cfg_path_disk(entry->full_path); - struct dev *dev = dev_get_by_name(entry->full_path, len); - if (!dev || dev->type != DEV_DISK) - panic("Invalid device in config\n"); - entry->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 = &entry->full_path[len + 1]; - entry->path = path; - - 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(entry)) - panic("No boot implementation found\n"); - } -} - -// Call cb for each entry config -void cfg_foreach(u8 (*cb)(struct cfg_entry *)) -{ - for (u8 i = 0; i < COUNT(cfg.entry) && cfg.entry[i].exists; i++) { - if (cb(&cfg.entry[i])) // 1 means break - break; - } -} - -// Print all configs and entry values -static void cfg_print(void) -{ - log("[CFG] Global: %d\n", cfg.timeout); - - for (u8 i = 0; i < COUNT(cfg.entry) && cfg.entry[i].exists; i++) - log("[CFG] Entry: %s at %s\n", cfg.entry[i].name, cfg.entry[i].full_path); -} - -// Execute entry implementation -void cfg_exec(struct cfg_entry *entry) -{ - impl_exec(entry); -} - -void cfg_read(void) -{ - dev_foreach(DEV_DISK, &cfg_find); - if (!file[0]) - panic("No config found\n"); - cfg_parse(); - cfg_verify(); - cfg_print(); -} diff --git a/src/loader/config.c b/src/loader/config.c new file mode 100644 index 0000000..2471d87 --- /dev/null +++ b/src/loader/config.c @@ -0,0 +1,210 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include +#include +#include +#include +#include +#include + +// Keys +#define TIMEOUT "TIMEOUT" +#define PATH "PATH" + +// Config structure +static struct cfg cfg = { 0 }; + +// Config file contents (if found) +static char file[1024] = { 0 }; + +// Find config file +static u8 config_find(struct dev *dev) +{ + if (!dev->p.disk.fs.read) + return 0; // No fs found or not readable - continue! + + s32 res = dev->p.disk.fs.read("/boot/segelboot.cfg", file, 0, sizeof(file), dev); + if (res > 0) + return 1; // Break foreach + + // Continue foreach + return 0; +} + +// Checks if index is appropriate as some key/value need to be in entry +static void config_in_entry(u8 index) +{ + if (index == 0xff) + panic("No entry name given\n"); +} + +// Add/overwrite value by key and entry index +static void config_add(u8 index, enum config_key key, const char *value) +{ + struct config_entry *entry = &cfg.entry[index]; + entry->exists = 1; + + switch (key) { + case CONFIG_NAME: + config_in_entry(index); + strlcpy(entry->name, value, sizeof(entry->name)); + break; + case CONFIG_TIMEOUT: + cfg.timeout = atoi(value); + break; + case CONFIG_PATH: + config_in_entry(index); + strlcpy(entry->full_path, value, sizeof(entry->full_path)); + break; + case CONFIG_NONE: + default: + panic("Invalid config\n"); + } +} + +// TODO: This code is kind of messy +// Structure per line: KEY=VALUE +static void config_parse(void) +{ + // Entry index + u8 entry = 0xff; + + // Value per key + char value[64] = { 0 }; + u8 value_index = 0; + + // States + enum config_key current = CONFIG_NONE; // Value key type + u8 state = 0; // 0 is key, 1 is value, 2 is entry + + const char *start = file; // Start is at the beginning of the key + for (const char *p = start; *p; p++) { + if (state == 0) { + // We're at key parsing + if (*p == '\n') { // A key can't just end but ok + start = p + 1; + } else if (*p == '#') { + state = 2; // Let's parse the entry name + p++; + continue; + } else if (*p != '=') { + continue; + } + + // The key is now at start until p + u8 diff = p - start; + + // Timeout key + if (diff == sizeof(TIMEOUT) - 1 && memcmp(start, TIMEOUT, diff) == 0) { + current = CONFIG_TIMEOUT; + state = 1; + continue; + } + + // Path key + if (diff == sizeof(PATH) - 1 && memcmp(start, PATH, diff) == 0) { + current = CONFIG_PATH; + state = 1; + continue; + } + } else if (state == 1) { + // We're at value parsing + assert(value_index + 1 < (u8)sizeof(value)); + if (*p == '\n') { // Finished + value[value_index] = 0; + config_add(entry, current, value); + value_index = 0; + state = 0; + p--; // Repeat parse normally + } else { + value[value_index++] = *p; + } + } else if (state == 2) { + // We're at entry name parsing + assert(value_index + 1 < (u8)sizeof(value)); + if (*p == '\n') { // Finished + entry = entry == 0xff ? 0 : entry + 1; + value[value_index] = 0; + config_add(entry, CONFIG_NAME, value); + value_index = 0; + state = 0; + p--; // Repeat parse normally + } else { + value[value_index++] = *p; + } + } + } +} + +// Extract the disk from path by returning index of delimiter or 0xff +// Example: disk:/boot/config.cfg returns 4 (:) +static u8 config_path_disk(const char *path) +{ + 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 config_verify(void) +{ + for (u8 i = 0; i < COUNT(cfg.entry) && cfg.entry[i].exists; i++) { + struct config_entry *entry = &cfg.entry[i]; + + u8 len = config_path_disk(entry->full_path); + struct dev *dev = device_get_by_name(entry->full_path, len); + if (!dev || dev->type != DEVICE_DISK) + panic("Invalid device in config\n"); + entry->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 = &entry->full_path[len + 1]; + entry->path = path; + + 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(entry)) + panic("No boot implementation found\n"); + } +} + +// Call cb for each entry config +void config_foreach(u8 (*cb)(struct config_entry *)) +{ + for (u8 i = 0; i < COUNT(cfg.entry) && cfg.entry[i].exists; i++) { + if (cb(&cfg.entry[i])) // 1 means break + break; + } +} + +// Print all configs and entry values +static void config_print(void) +{ + log("[CFG] Global: %d\n", cfg.timeout); + + for (u8 i = 0; i < COUNT(cfg.entry) && cfg.entry[i].exists; i++) + log("[CFG] Entry: %s at %s\n", cfg.entry[i].name, cfg.entry[i].full_path); +} + +// Execute entry implementation +void config_exec(struct config_entry *entry) +{ + impl_exec(entry); +} + +void config_read(void) +{ + device_foreach(DEVICE_DISK, &config_find); + if (!file[0]) + panic("No config found\n"); + config_parse(); + config_verify(); + config_print(); +} diff --git a/src/loader/dev.c b/src/loader/dev.c deleted file mode 100644 index 2a57b02..0000000 --- a/src/loader/dev.c +++ /dev/null @@ -1,84 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner -// Device manager - -#include -#include -#include - -static struct dev devices[32] = { 0 }; - -static const char *dev_resolve_type(enum dev_type type) -{ - switch (type) { - case DEV_DISK: - return "Disk"; - case DEV_FB: - return "Framebuffer"; - case DEV_NONE: - default: - return "Unknown"; - } -} - -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++) { - struct dev *dev = &devices[i]; - if (dev->type == type) - if (cb(dev)) - break; - } -} - -u8 dev_register(enum dev_type type, char *name, u32 data, - s32 (*read)(void *, u32, u32, struct dev *), - s32 (*write)(const void *, u32, u32, struct dev *)) -{ - static u8 id = 0; - assert(++id < 0xff); - - struct dev *dev = &devices[id]; - dev->id = id; - dev->type = type; - dev->read = read; - dev->write = write; - dev->data = data; - - assert(strlen(name) < sizeof(dev->name)); - memcpy(dev->name, name, sizeof(dev->name)); - - if (type == DEV_DISK) - dsk_detect(dev); - - return id; -} - -void dev_print(void) -{ - for (u8 i = 0; i < COUNT(devices); i++) { - struct dev *dev = &devices[i]; - if (!dev->id) - continue; - log("[DEV] %d: %s device: %s\n", dev->id, dev_resolve_type(dev->type), dev->name); - } -} diff --git a/src/loader/device.c b/src/loader/device.c new file mode 100644 index 0000000..9c3e2ee --- /dev/null +++ b/src/loader/device.c @@ -0,0 +1,84 @@ +// MIT License, Copyright (c) 2021 Marvin Borner +// Device manager + +#include +#include +#include + +static struct dev devices[32] = { 0 }; + +static const char *device_resolve_type(enum device_type type) +{ + switch (type) { + case DEVICE_DISK: + return "Disk"; + case DEVICE_FB: + return "Framebuffer"; + case DEVICE_NONE: + default: + return "Unknown"; + } +} + +struct dev *device_get_by_id(u8 id) +{ + assert(id < COUNT(devices)); + return &devices[id]; +} + +struct dev *device_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 device_foreach(enum device_type type, u8 (*cb)(struct dev *)) +{ + for (u8 i = 0; i < COUNT(devices); i++) { + struct dev *dev = &devices[i]; + if (dev->type == type) + if (cb(dev)) + break; + } +} + +u8 device_register(enum device_type type, char *name, u32 data, + s32 (*read)(void *, u32, u32, struct dev *), + s32 (*write)(const void *, u32, u32, struct dev *)) +{ + static u8 id = 0; + assert(++id < 0xff); + + struct dev *dev = &devices[id]; + dev->id = id; + dev->type = type; + dev->read = read; + dev->write = write; + dev->data = data; + + assert(strlen(name) < sizeof(dev->name)); + memcpy(dev->name, name, sizeof(dev->name)); + + if (type == DEVICE_DISK) + disk_detect(dev); + + return id; +} + +void device_print(void) +{ + for (u8 i = 0; i < COUNT(devices); i++) { + struct dev *dev = &devices[i]; + if (!dev->id) + continue; + log("[DEV] %d: %s device: %s\n", dev->id, device_resolve_type(dev->type), dev->name); + } +} diff --git a/src/loader/disk.c b/src/loader/disk.c new file mode 100644 index 0000000..42ec772 --- /dev/null +++ b/src/loader/disk.c @@ -0,0 +1,20 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include +#include +#include +#include +#include + +void disk_detect(struct dev *dev) +{ + assert(dev->type == DEVICE_DISK); + + if (mbr_detect(dev)) + return; + + if (ext2_detect(dev)) + return; + + log("[DSK] Couldn't detect type of disk %s\n", dev->name); +} diff --git a/src/loader/dsk.c b/src/loader/dsk.c deleted file mode 100644 index 5e8fc3d..0000000 --- a/src/loader/dsk.c +++ /dev/null @@ -1,20 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#include -#include -#include -#include -#include - -void dsk_detect(struct dev *dev) -{ - assert(dev->type == DEV_DISK); - - if (mbr_detect(dev)) - return; - - if (ext2_detect(dev)) - return; - - log("[DSK] Couldn't detect type of disk %s\n", dev->name); -} diff --git a/src/loader/elf.c b/src/loader/elf.c index 3f5aea3..de596cf 100644 --- a/src/loader/elf.c +++ b/src/loader/elf.c @@ -1,11 +1,11 @@ // MIT License, Copyright (c) 2021 Marvin Borner #include -#include +#include u32 elf_load(struct dev *dev, const char *path) { - assert(dev->type == DEV_DISK); + assert(dev->type == DEVICE_DISK); struct elf_header header = { 0 }; s32 rd = dev->p.disk.fs.read(path, &header, 0, sizeof(header), dev); diff --git a/src/loader/format.c b/src/loader/format.c new file mode 100644 index 0000000..34327af --- /dev/null +++ b/src/loader/format.c @@ -0,0 +1,60 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include +#include + +/** + * Formatting + */ + +u32 vsnprintf(char *str, u32 size, const char *format, va_list ap) +{ + u32 length = 0; + + int temp_int; + char temp_ch; + char *temp_str; + + char buffer[64] = { 0 }; + + // TODO: Fix potential memory overflows because of str[length++]=xxx + char ch; + while ((ch = *format++)) { + if (ch == '%') { + switch (*format++) { + case '%': + str[length++] = '%'; + break; + case 'c': + temp_ch = va_arg(ap, int); + str[length++] = temp_ch; + break; + case 's': + temp_str = va_arg(ap, char *); + length += strlcpy(&str[length], temp_str, size - length); + break; + case 'b': + temp_int = va_arg(ap, int); + itoa(temp_int, buffer, 2); + length += strlcpy(&str[length], buffer, size - length); + break; + case 'd': + temp_int = va_arg(ap, int); + itoa(temp_int, buffer, 10); + length += strlcpy(&str[length], buffer, size - length); + break; + case 'x': + temp_int = va_arg(ap, int); + itoa(temp_int, buffer, 16); + length += strlcpy(&str[length], buffer, size - length); + break; + default: + serial_print("Unknown printf format\n"); + } + } else { + str[length++] = ch; + } + } + + return length; +} diff --git a/src/loader/fs/ext2.c b/src/loader/fs/ext2.c index 72fd3c0..3b2154b 100644 --- a/src/loader/fs/ext2.c +++ b/src/loader/fs/ext2.c @@ -1,9 +1,9 @@ // MIT License, Copyright (c) 2021 Marvin Borner -#include +#include #include -#include -#include +#include +#include static void ext2_buffer_read(u32 block, void *buf, struct dev *dev) { diff --git a/src/loader/gui.c b/src/loader/gui.c index 6ae35e6..2932dcc 100644 --- a/src/loader/gui.c +++ b/src/loader/gui.c @@ -1,19 +1,19 @@ // MIT License, Copyright (c) 2021 Marvin Borner // GUI - selection interface -#include +#include #include #include #include -#include +#include #include -#include +#include -struct { - struct cfg_entry *cfg; +static struct { + struct config_entry *cfg; } gui_entries[16] = { 0 }; -static u8 gui_entry_add(struct cfg_entry *entry) +static u8 gui_entry_add(struct config_entry *entry) { static u8 index = 0; assert(index + 1 < (u8)sizeof(gui_entries)); @@ -32,7 +32,7 @@ static u8 gui_entry_exists(u8 entry) static void gui_entry_select(u8 entry) { if (gui_entry_exists(entry)) - cfg_exec(gui_entries[entry].cfg); + config_exec(gui_entries[entry].cfg); else log("Invalid selection\n"); } @@ -71,8 +71,8 @@ void gui_draw(void) vga_clear(); vga_log("SegelBoot by Marvin Borner\n\n"); - cfg_foreach(&gui_entry_add); + config_foreach(&gui_entry_add); gui_entries_draw(); - int_event_handler_add(1, &gui_keyboard_handler); + interrupt_event_handler_add(1, &gui_keyboard_handler); } diff --git a/src/loader/ide.c b/src/loader/ide.c index c5461d0..7fb405a 100644 --- a/src/loader/ide.c +++ b/src/loader/ide.c @@ -2,13 +2,11 @@ #include #include -#include +#include #include -#include +#include #include -#include - -static u8 ide_buf[SECTOR_SIZE] = { 0 }; +#include static void ide_select_drive(u8 bus, u8 drive) { @@ -27,6 +25,8 @@ static void ide_select_drive(u8 bus, u8 drive) static u8 ide_find(u8 bus, u8 drive) { + static u8 ide_buf[SECTOR_SIZE] = { 0 }; + u16 io = bus == ATA_PRIMARY ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; ide_select_drive(bus, drive); @@ -113,7 +113,7 @@ static void ata_probe(void) name[2] = 'a' + i; // Register without write support - dev_register(DEV_DISK, name, data, ata_read, NULL); + device_register(DEVICE_DISK, name, data, ata_read, NULL); } } diff --git a/src/loader/impl/all.c b/src/loader/impl/all.c deleted file mode 100644 index 941986d..0000000 --- a/src/loader/impl/all.c +++ /dev/null @@ -1,36 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#include -#include -#include -#include - -u8 impl_detect(struct cfg_entry *cfg) -{ - if (mb1_detect(cfg)) - return 1; - - if (mb2_detect(cfg)) - return 1; - - return 0; -} - -void impl_exec(struct cfg_entry *cfg) -{ - assert(cfg->dev->type == DEV_DISK); - - switch (cfg->impl.type) { - case IMPL_MB1: - mb1_exec(cfg); - break; - case IMPL_MB2: - mb2_exec(cfg); - break; - case IMPL_NONE: - default: - panic("Invalid implementation\n"); - } - - panic("Couldn't execute implementation\n"); -} diff --git a/src/loader/impl/mb1.c b/src/loader/impl/mb1.c deleted file mode 100644 index c02aa50..0000000 --- a/src/loader/impl/mb1.c +++ /dev/null @@ -1,147 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner -// Everything according to spec - -#include -#include -#include -#include -#include - -// The address where data gets stored -#define MB1_LOAD_ADDRESS 0x10000 - -#define MB1_FLAG_PAGE_ALIGN (1 << 0) // Align modules with page boundaries (4K) -#define MB1_FLAG_MEMORY_INFO (1 << 1) // Load/store all mem_* fields and mmap_* structs -#define MB1_FLAG_VIDEO_MODE (1 << 2) // Load/store video mode table -#define MB1_FLAG_MANUAL_ADDRESSES (1 << 16) // Use specified load addresses - -struct mb1_entry { - u32 magic; - u32 flags; - u32 checksum; // Everything after that is optional - u32 header_addr; // Unsupported - u32 load_addr; // Unsupported - u32 load_end_addr; // Unsupported - u32 bss_end_addr; // Unsupported - u32 entry_addr; // Unsupported - u32 mode_type; - u32 width; - u32 height; - u32 depth; -}; - -// The (really simple) multiboot checksum algorithm -static u32 mb1_checksum(struct mb1_entry *entry) -{ - return -(entry->magic + entry->flags); -} - -// Load data into memory and return address (not overlapping -static u32 mb1_store(void *data, u32 size) -{ - static u32 offset = 0; - memcpy((void *)(MB1_LOAD_ADDRESS + offset), data, size); - offset += size; - return MB1_LOAD_ADDRESS + (offset - size); -} - -static void mb1_store_memory_info(struct mb1_info *info) -{ - // TODO: Store mem_lower and mem_upper - struct mem_map *mem_map = mem_map_get(); - info->flags |= MB1_INFO_MEM_MAP; - info->mmap_length = mem_map->count * sizeof(struct mb1_mmap_entry); - info->mmap_addr = mb1_store(NULL, 0); - for (u32 i = 0; i < mem_map->count; i++) { - struct mb1_mmap_entry mmap_entry; - mmap_entry.struct_size = sizeof(mmap_entry) - 4; - mmap_entry.addr_low = mem_map->entry[i].base; - mmap_entry.len_low = mem_map->entry[i].length; - mmap_entry.type = mem_map->entry[i].type; - mb1_store(&mmap_entry, sizeof(mmap_entry)); - } -} - -// Load the mb1 structs into memory -static void mb1_load(struct mb1_entry *entry) -{ - struct mb1_info info_struct = { 0 }; - struct mb1_info *info = (void *)mb1_store(&info_struct, sizeof(info_struct)); - - // Set boot device - info->flags |= MB1_INFO_BOOTDEV; - info->boot_device = boot_disk; - - // Set bootloader name - info->flags |= MB1_INFO_BOOT_LOADER_NAME; - char loader_name[] = "SegelBoot"; - info->boot_loader_name = mb1_store(loader_name, sizeof(loader_name)); - - // Store memory info - if (entry->flags & MB1_FLAG_MEMORY_INFO) - mb1_store_memory_info(info); -} - -// Jump to kernel with correct info pointer in eax -static void mb1_jump(u32 entry, u32 info) -{ - log("Jumping. So long and thanks for all the fish!\n"); - - // Move and jump! - __asm__ volatile("movl $" STRINGIFY(MB1_LOAD_MAGIC) ", %%eax\n\t" - "jmpl *%%edi\n\t" - : - : "D"(entry), "b"(info) - : "memory"); - - panic("Jumper returned\n"); -} - -// Detect and verify mb1 -u8 mb1_detect(struct cfg_entry *cfg) -{ - u8 header[8192] = { 0 }; - - s32 ret = cfg->dev->p.disk.fs.read(cfg->path, header, 0, sizeof(header), cfg->dev); - if (ret < 12) - return 0; - - // Find start of multiboot entry by searching for magic - struct mb1_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; - - cfg->impl.type = IMPL_MB1; - cfg->impl.offset = (u32)entry - (u32)header; - - return 1; -} - -// Execute mb1 type kernel -void mb1_exec(struct cfg_entry *cfg) -{ - struct mb1_entry mb1_entry = { 0 }; - s32 ret = cfg->dev->p.disk.fs.read(cfg->path, &mb1_entry, cfg->impl.offset, - sizeof(mb1_entry), cfg->dev); - assert(ret == sizeof(mb1_entry)); - mb1_load(&mb1_entry); - - u32 entry = elf_load(cfg->dev, cfg->path); - - // This is a kind of hacky parameter stack pushing thing, just disable warning :) -#pragma GCC diagnostic ignored "-Wpedantic" - jmp_kernel((void *)mb1_jump, 2, entry, MB1_LOAD_ADDRESS); -#pragma GCC diagnostic pop -} diff --git a/src/loader/impl/mb2.c b/src/loader/impl/mb2.c deleted file mode 100644 index 09f69ea..0000000 --- a/src/loader/impl/mb2.c +++ /dev/null @@ -1,105 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner -// Everything according to spec - -#include -#include -#include -#include - -// The address where data gets stored -#define MB2_LOAD_ADDRESS 0x10000 - -struct mb2_entry { - u32 magic; - u32 flags; - u32 header_length; - u32 checksum; // Everything after that is optional - u8 *tags; -}; - -// The (really simple) multiboot checksum algorithm -/* static u32 mb2_checksum(struct mb2_entry *entry) */ -/* { */ -/* return -(entry->magic + entry->flags); */ -/* } */ - -// Load data into memory and return address (not overlapping -static u32 mb2_store(void *data, u32 size) -{ - static u32 offset = 0; - memcpy((void *)MB2_LOAD_ADDRESS, data, size); - offset += size; - return MB2_LOAD_ADDRESS + (size - offset); -} - -// Load the mb2 structs into memory -static void mb2_load(struct mb2_entry *entry) -{ - (void)mb2_store; - (void)entry; -} - -// Jump to kernel with correct info pointer in eax -static void mb2_jump(u32 entry, u32 info) -{ - log("Jumping. So long and thanks for all the fish!\n"); - - // Move and jump! - __asm__ volatile("movl $" STRINGIFY(MB2_LOAD_MAGIC) ", %%eax\n\t" - "jmpl *%%edi\n\t" - : - : "D"(entry), "b"(info) - : "memory"); - - panic("Jumper returned\n"); -} - -// Detect and verify mb2 -u8 mb2_detect(struct cfg_entry *cfg) -{ - u8 header[8192] = { 0 }; - - s32 ret = cfg->dev->p.disk.fs.read(cfg->path, header, 0, sizeof(header), cfg->dev); - if (ret < 12) - return 0; - - // Find start of multiboot entry by searching for magic - struct mb2_entry *entry = 0; - for (u32 i = 0; i < sizeof(header); i++) { - u32 *p = (u32 *)&header[i]; - if (*p == MB2_MAGIC) { - entry = (void *)p; - break; - } - } - - if (!entry) - return 0; - - // TODO: mb2 checksum - /* u32 checksum = mb2_checksum(entry); */ - /* if (checksum != entry->checksum) */ - /* return 0; */ - - cfg->impl.type = IMPL_MB2; - cfg->impl.offset = (u32)entry - (u32)header; - - return 1; -} - -// Execute mb2 type kernel -void mb2_exec(struct cfg_entry *cfg) -{ - struct mb2_entry mb2_entry = { 0 }; - s32 ret = cfg->dev->p.disk.fs.read(cfg->path, &mb2_entry, cfg->impl.offset, - sizeof(mb2_entry), cfg->dev); - assert(ret == sizeof(mb2_entry)); - mb2_load(&mb2_entry); - - u32 entry = elf_load(cfg->dev, cfg->path); - - // This is a kind of hacky parameter stack pushing thing, just disable warning :) -#pragma GCC diagnostic ignored "-Wpedantic" - jmp_kernel((void *)mb2_jump, 2, entry, MB2_LOAD_ADDRESS); -#pragma GCC diagnostic pop -} diff --git a/src/loader/inc/cfg.h b/src/loader/inc/cfg.h deleted file mode 100644 index cb91ab2..0000000 --- a/src/loader/inc/cfg.h +++ /dev/null @@ -1,39 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef CFG_H -#define CFG_H - -#include -#include - -extern u8 boot_disk; - -// Global config element index (can actually be anything but wth) -#define CFG_GLOBAL 0 - -enum cfg_key { - CFG_NONE, - CFG_NAME, - CFG_TIMEOUT, - CFG_PATH, -}; - -struct cfg_entry { - u8 exists : 1; - char name[64]; - char full_path[64]; // With disk name - const char *path; // Without disk name - struct dev *dev; - struct impl impl; -}; - -struct cfg { - u32 timeout; - struct cfg_entry entry[16]; // Up to 16 different entries -}; - -void cfg_foreach(u8 (*cb)(struct cfg_entry *)); -void cfg_exec(struct cfg_entry *entry); -void cfg_read(void); - -#endif diff --git a/src/loader/inc/config.h b/src/loader/inc/config.h new file mode 100644 index 0000000..4f2d7dc --- /dev/null +++ b/src/loader/inc/config.h @@ -0,0 +1,39 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include + +extern u8 boot_disk; + +// Global config element index (can actually be anything but wth) +#define CONFIG_GLOBAL 0 + +enum config_key { + CONFIG_NONE, + CONFIG_NAME, + CONFIG_TIMEOUT, + CONFIG_PATH, +}; + +struct config_entry { + u8 exists : 1; + char name[64]; + char full_path[64]; // With disk name + const char *path; // Without disk name + struct dev *dev; + struct impl impl; +}; + +struct cfg { + u32 timeout; + struct config_entry entry[16]; // Up to 16 different entries +}; + +void config_foreach(u8 (*cb)(struct config_entry *)); +void config_exec(struct config_entry *entry); +void config_read(void); + +#endif diff --git a/src/loader/inc/dev.h b/src/loader/inc/dev.h deleted file mode 100644 index cbefe99..0000000 --- a/src/loader/inc/dev.h +++ /dev/null @@ -1,41 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef DEV_H -#define DEV_H - -#include -#include - -enum dev_type { - DEV_NONE, - DEV_DISK, - DEV_FB, -}; - -struct dev { - u8 id; - enum dev_type type; - char name[16]; - - s32 (*read)(void *, u32, u32, struct dev *); - s32 (*write)(const void *, u32, u32, struct dev *); - - union { - struct { - struct fs fs; - } disk; - // TODO: Other (framebuffer?) - } p; // Prototype union - - u32 data; // Optional (device-specific) data/information -}; - -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 *), - s32 (*write)(const void *, u32, u32, struct dev *)); -void dev_print(void); - -#endif diff --git a/src/loader/inc/device.h b/src/loader/inc/device.h new file mode 100644 index 0000000..5081cb7 --- /dev/null +++ b/src/loader/inc/device.h @@ -0,0 +1,41 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef DEVICE_H +#define DEVICE_H + +#include +#include + +enum device_type { + DEVICE_NONE, + DEVICE_DISK, + DEVICE_FB, +}; + +struct dev { + u8 id; + enum device_type type; + char name[16]; + + s32 (*read)(void *, u32, u32, struct dev *); + s32 (*write)(const void *, u32, u32, struct dev *); + + union { + struct { + struct fs fs; + } disk; + // TODO: Other (framebuffer?) + } p; // Prototype union + + u32 data; // Optional (device-specific) data/information +}; + +struct dev *device_get_by_id(u8 id); +struct dev *device_get_by_name(const char *name, u32 len); +void device_foreach(enum device_type type, u8 (*cb)(struct dev *)); // cb=1 => break +u8 device_register(enum device_type type, char *name, u32 data, + s32 (*read)(void *, u32, u32, struct dev *), + s32 (*write)(const void *, u32, u32, struct dev *)); +void device_print(void); + +#endif diff --git a/src/loader/inc/disk.h b/src/loader/inc/disk.h new file mode 100644 index 0000000..e4fb285 --- /dev/null +++ b/src/loader/inc/disk.h @@ -0,0 +1,21 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef DISK_H +#define DISK_H + +#include + +// General disk assumptions +#define BLOCK_SIZE 1024 +#define BLOCK_COUNT 256 // BLOCK_SIZE / sizeof(u32) +#define SECTOR_SIZE 512 +#define SECTOR_COUNT (BLOCK_SIZE / SECTOR_SIZE) // 2 + +struct dev; +struct fs { + s32 (*read)(const char *, void *, u32, u32, struct dev *); +}; + +void disk_detect(struct dev *dev); + +#endif diff --git a/src/loader/inc/dsk.h b/src/loader/inc/dsk.h deleted file mode 100644 index 5b2dec9..0000000 --- a/src/loader/inc/dsk.h +++ /dev/null @@ -1,21 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef DSK_H -#define DSK_H - -#include - -// General disk assumptions -#define BLOCK_SIZE 1024 -#define BLOCK_COUNT 256 // BLOCK_SIZE / sizeof(u32) -#define SECTOR_SIZE 512 -#define SECTOR_COUNT (BLOCK_SIZE / SECTOR_SIZE) // 2 - -struct dev; -struct fs { - s32 (*read)(const char *, void *, u32, u32, struct dev *); -}; - -void dsk_detect(struct dev *dev); - -#endif diff --git a/src/loader/inc/elf.h b/src/loader/inc/elf.h index 4b19f2f..9cf5c2b 100644 --- a/src/loader/inc/elf.h +++ b/src/loader/inc/elf.h @@ -5,7 +5,7 @@ #define ELF_H #include -#include +#include #define ELF_MAG0 0x7F #define ELF_MAG1 'E' diff --git a/src/loader/inc/fs/ext2.h b/src/loader/inc/fs/ext2.h index 0c2052a..ce19ddb 100644 --- a/src/loader/inc/fs/ext2.h +++ b/src/loader/inc/fs/ext2.h @@ -4,7 +4,7 @@ #define FS_EXT2_H #include -#include +#include #define EXT2_BOOT 0 #define EXT2_SUPER 1 diff --git a/src/loader/inc/impl.h b/src/loader/inc/impl.h deleted file mode 100644 index 58ae706..0000000 --- a/src/loader/inc/impl.h +++ /dev/null @@ -1,20 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef IMPL_H -#define IMPL_H - -#include - -enum impl_type { - IMPL_NONE, - IMPL_MB1, - IMPL_MB2, -}; - -struct impl { - enum impl_type type; - u32 offset; // Of header/entry - void (*load)(struct dev *, const char *); -}; - -#endif diff --git a/src/loader/inc/impl/all.h b/src/loader/inc/impl/all.h deleted file mode 100644 index 01565a6..0000000 --- a/src/loader/inc/impl/all.h +++ /dev/null @@ -1,12 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef IMPL_ALL_H -#define IMPL_ALL_H - -#include -#include - -u8 impl_detect(struct cfg_entry *cfg); -void impl_exec(struct cfg_entry *cfg); - -#endif diff --git a/src/loader/inc/impl/mb1.h b/src/loader/inc/impl/mb1.h deleted file mode 100644 index 5e68ece..0000000 --- a/src/loader/inc/impl/mb1.h +++ /dev/null @@ -1,134 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef IMPL_MB1_H -#define IMPL_MB1_H - -#include -#include -#include - -#define MB1_MAGIC 0x1badb002 // Identifies kernel -#define MB1_LOAD_MAGIC 0x2badb002 // Passed to kernel - -#define MB1_INFO_MEMORY 0x00000001 -#define MB1_INFO_BOOTDEV 0x00000002 -#define MB1_INFO_CMDLINE 0x00000004 -#define MB1_INFO_MODS 0x00000008 -#define MB1_INFO_AOUT_SYMS 0x00000010 -#define MB1_INFO_ELF_SHDR 0x00000020 -#define MB1_INFO_MEM_MAP 0x00000040 -#define MB1_INFO_DRIVE_INFO 0x00000080 -#define MB1_INFO_CONFIG_TABLE 0x00000100 -#define MB1_INFO_BOOT_LOADER_NAME 0x00000200 -#define MB1_INFO_APM_TABLE 0x00000400 -#define MB1_INFO_VBE_INFO 0x00000800 -#define MB1_INFO_FRAMEBUFFER_INFO 0x00001000 - -#define MB1_FRAMEBUFFER_TYPE_INDEXED 0 -#define MB1_FRAMEBUFFER_TYPE_RGB 1 -#define MB1_FRAMEBUFFER_TYPE_EGA_TEXT 2 - -#define MB1_MEMORY_AVAILABLE 1 -#define MB1_MEMORY_RESERVED 2 -#define MB1_MEMORY_ACPI_RECLAIMABLE 3 -#define MB1_MEMORY_NVS 4 -#define MB1_MEMORY_BADRAM 5 - -#include - -struct mb1_aout_symbol_table { - u32 tabsize; - u32 strsize; - u32 addr; - u32 reserved; -}; - -struct mb1_elf_section_header_table { - u32 num; - u32 size; - u32 addr; - u32 shndx; -}; - -struct mb1_info { - u32 flags; - - u32 mem_lower; - u32 mem_upper; - - u32 boot_device; - - u32 cmdline; - - u32 mods_count; - u32 mods_addr; - - union { - struct mb1_aout_symbol_table aout_sym; - struct mb1_elf_section_header_table elf_sec; - } u; - - u32 mmap_length; - u32 mmap_addr; - - u32 drives_length; - u32 drives_addr; - - u32 config_table; - - u32 boot_loader_name; - - u32 apm_table; - - u32 vbe_control_info; - u32 vbe_mode_info; - u16 vbe_mode; - u16 vbe_interface_seg; - u16 vbe_interface_off; - u16 vbe_interface_len; - - u32 framebuffer_addr_high; - u32 framebuffer_addr_low; - u32 framebuffer_pitch; - u32 framebuffer_width; - u32 framebuffer_height; - u8 framebuffer_bpp; - u8 framebuffer_type; - union { - struct { - u32 framebuffer_palette_addr; - u16 framebuffer_palette_num_colors; - } palette; - struct { - u8 framebuffer_red_field_position; - u8 framebuffer_red_mask_size; - u8 framebuffer_green_field_position; - u8 framebuffer_green_mask_size; - u8 framebuffer_blue_field_position; - u8 framebuffer_blue_mask_size; - } colors; - } framebuffer_colors; -} PACKED; - -struct mb1_mmap_entry { - u32 struct_size; - u32 addr_low; - u32 addr_high; - u32 len_low; - u32 len_high; - u32 type; -} PACKED; - -struct mb1_mod_list { - u32 mod_start; - u32 mod_end; - - u32 cmdline; - - u32 pad; -}; - -u8 mb1_detect(struct cfg_entry *cfg); -void mb1_exec(struct cfg_entry *cfg); - -#endif diff --git a/src/loader/inc/impl/mb2.h b/src/loader/inc/impl/mb2.h deleted file mode 100644 index 3f64dbd..0000000 --- a/src/loader/inc/impl/mb2.h +++ /dev/null @@ -1,61 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef IMPL_MB2_H -#define IMPL_MB2_H - -#include -#include -#include - -#define MB2_MAGIC 0xe85250d6 // Identifies kernel -#define MB2_LOAD_MAGIC 0x36d76289 // Passed to kernel - -struct mb2_header { - u32 total_size; - u32 unknown; -} PACKED; - -struct mb2_tag { - u32 type; - u32 size; -} PACKED; - -struct mb2_memory { - u32 addr_low; - u32 addr_high; - u32 size_low; - u32 size_high; - u32 type; - u32 reserved; -} PACKED; - -struct mb2_module { - u32 start; - u32 end; - char string[1]; -} PACKED; - -struct mb2_fb { - u32 addr_low; - u32 addr_high; - u32 pitch; - u32 width; - u32 height; - u8 bpp; - u8 type; -} PACKED; - -enum mb2_tags { - MB2_TAG_END = 0, - MB2_TAG_CMDLINE = 1, - MB2_TAG_MODULE = 3, - MB2_TAG_MEMORY = 6, - MB2_TAG_FB = 8, - MB2_TAG_ACPI_1 = 14, - MB2_TAG_ACPI_2 = 15, -}; - -u8 mb2_detect(struct cfg_entry *cfg); -void mb2_exec(struct cfg_entry *cfg); - -#endif diff --git a/src/loader/inc/int.h b/src/loader/inc/int.h deleted file mode 100644 index ccd9ea8..0000000 --- a/src/loader/inc/int.h +++ /dev/null @@ -1,49 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef INT_H -#define INT_H - -#include - -#define INT_GATE 0x8e -#define INT_TRAP 0xef -#define INT_USER 0x60 -#define IDT_ENTRY(offset, selector, type) \ - (struct idt_entry) \ - { \ - .base_low = (u16)((offset)&0xffff), .sel = (selector), .zero = 0, .flags = (type), \ - .base_high = (u16)(((offset) >> 16) & 0xffff), \ - } - -struct int_frame { - u32 gs, fs, es, ds; - u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; - u32 int_no, err_code; - u32 eip, cs, eflags; -} PACKED; - -struct int_frame_user { - u32 gs, fs, es, ds; - u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; - u32 int_no, err_code; - u32 eip, cs, eflags; - u32 useresp, ss; -} PACKED; - -struct idt_entry { - u16 base_low; - u16 sel; // Kernel segment - u8 zero; // Always 0 - u8 flags; - u16 base_high; -} PACKED; - -struct idt_ptr { - u16 size; - void *base; -} PACKED; - -void idt_install(void); -void int_event_handler_add(u32 int_no, void (*handler)(void)); - -#endif diff --git a/src/loader/inc/interrupt.h b/src/loader/inc/interrupt.h new file mode 100644 index 0000000..4706dbe --- /dev/null +++ b/src/loader/inc/interrupt.h @@ -0,0 +1,49 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef INTERRUPT_H +#define INTERRUPT_H + +#include + +#define INTERRUPT_GATE 0x8e +#define INTERRUPT_TRAP 0xef +#define INTERRUPT_USER 0x60 +#define IDT_ENTRY(offset, selector, type) \ + (struct idt_entry) \ + { \ + .base_low = (u16)((offset)&0xffff), .sel = (selector), .zero = 0, .flags = (type), \ + .base_high = (u16)(((offset) >> 16) & 0xffff), \ + } + +struct interrupt_frame { + u32 gs, fs, es, ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 interrupt_no, err_code; + u32 eip, cs, eflags; +} PACKED; + +struct interrupt_frame_user { + u32 gs, fs, es, ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 interrupt_no, err_code; + u32 eip, cs, eflags; + u32 useresp, ss; +} PACKED; + +struct idt_entry { + u16 base_low; + u16 sel; // Kernel segment + u8 zero; // Always 0 + u8 flags; + u16 base_high; +} PACKED; + +struct idt_ptr { + u16 size; + void *base; +} PACKED; + +void idt_install(void); +void interrupt_event_handler_add(u32 interrupt_no, void (*handler)(void)); + +#endif diff --git a/src/loader/inc/lib.h b/src/loader/inc/lib.h deleted file mode 100644 index 2f49007..0000000 --- a/src/loader/inc/lib.h +++ /dev/null @@ -1,20 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef LIB_H -#define LIB_H - -#include - -u32 strlen(const char *str); -u32 strnlen(const char *s, u32 max); -u32 strlcpy(char *dst, const char *src, u32 size); -s32 strncmp(const char *s1, const char *s2, u32 n); - -void *memcpy(void *dest, const void *src, u32 n); -void *memset(void *dest, u32 val, u32 n); -s32 memcmp(const void *s1, const void *s2, u32 n); - -s32 itoa(s32 value, char *buffer, u32 base); -s32 atoi(const char *inp); - -#endif diff --git a/src/loader/inc/library.h b/src/loader/inc/library.h new file mode 100644 index 0000000..2f49007 --- /dev/null +++ b/src/loader/inc/library.h @@ -0,0 +1,20 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef LIB_H +#define LIB_H + +#include + +u32 strlen(const char *str); +u32 strnlen(const char *s, u32 max); +u32 strlcpy(char *dst, const char *src, u32 size); +s32 strncmp(const char *s1, const char *s2, u32 n); + +void *memcpy(void *dest, const void *src, u32 n); +void *memset(void *dest, u32 val, u32 n); +s32 memcmp(const void *s1, const void *s2, u32 n); + +s32 itoa(s32 value, char *buffer, u32 base); +s32 atoi(const char *inp); + +#endif diff --git a/src/loader/inc/log.h b/src/loader/inc/log.h index cb1acd8..f6a28e1 100644 --- a/src/loader/inc/log.h +++ b/src/loader/inc/log.h @@ -5,13 +5,14 @@ #include +u32 vsnprintf(char *str, u32 size, const char *format, va_list ap); + void serial_install(void); void serial_print(const char *data); +void log(const char *format, ...); void vga_put_at(char ch, u8 x, u8 y, u8 color); void vga_clear(void); - -void log(const char *format, ...); void vga_log(const char *format, ...); #endif diff --git a/src/loader/inc/mbr.h b/src/loader/inc/mbr.h index a9befe5..ec51944 100644 --- a/src/loader/inc/mbr.h +++ b/src/loader/inc/mbr.h @@ -4,7 +4,7 @@ #define MBR_H #include -#include +#include struct mbr_entry { u8 attributes; diff --git a/src/loader/inc/mem.h b/src/loader/inc/mem.h deleted file mode 100644 index 7153465..0000000 --- a/src/loader/inc/mem.h +++ /dev/null @@ -1,32 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef MEM_H -#define MEM_H - -#include - -enum mem_entry_type { - MEM_NONE, - MEM_USABLE, - MEM_RESERVED, - MEM_RECLAIMABLE, - MEM_ACPI_NVS, - MEM_UNUSABLE, -}; - -// Generalised memory map entry struct -struct mem_entry { - u32 base; - u32 length; - u32 type; -}; - -struct mem_map { - struct mem_entry *entry; - u32 count; -}; - -void mem_map(void); -struct mem_map *mem_map_get(void); - -#endif diff --git a/src/loader/inc/memory.h b/src/loader/inc/memory.h new file mode 100644 index 0000000..1a74884 --- /dev/null +++ b/src/loader/inc/memory.h @@ -0,0 +1,32 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef MEMORY_H +#define MEMORY_H + +#include + +enum memory_entry_type { + MEMORY_NONE, + MEMORY_USABLE, + MEMORY_RESERVED, + MEMORY_RECLAIMABLE, + MEMORY_ACPI_NVS, + MEMORY_UNUSABLE, +}; + +// Generalised memory map entry struct +struct memory_entry { + u32 base; + u32 length; + u32 type; +}; + +struct memory_map { + struct memory_entry *entry; + u32 count; +}; + +void memory_map(void); +struct memory_map *memory_map_get(void); + +#endif diff --git a/src/loader/inc/panic.h b/src/loader/inc/panic.h new file mode 100644 index 0000000..73819c9 --- /dev/null +++ b/src/loader/inc/panic.h @@ -0,0 +1,24 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef PNC_H +#define PNC_H + +#include + +#define panic(reason) \ + { \ + log("%s:%d: %s: Panic: %s", __FILE__, __LINE__, __func__, (reason)); \ + while (1) \ + __asm__ volatile("cli\nhlt"); \ + } + +#define assert(exp) \ + { \ + if (!(exp)) \ + panic("Assertion '" #exp "' failed\n"); \ + } + +// This shouldn't return, therefore this declaration belongs here (kinda) +void jmp_kernel(void *kernel, int args, ...); + +#endif diff --git a/src/loader/inc/pic.h b/src/loader/inc/pic.h index c2a7d87..d662454 100644 --- a/src/loader/inc/pic.h +++ b/src/loader/inc/pic.h @@ -6,6 +6,6 @@ #include void pic_install(void); -void pic_ack(u32 int_no); +void pic_ack(u32 interrupt_no); #endif diff --git a/src/loader/inc/pnc.h b/src/loader/inc/pnc.h deleted file mode 100644 index 73819c9..0000000 --- a/src/loader/inc/pnc.h +++ /dev/null @@ -1,24 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef PNC_H -#define PNC_H - -#include - -#define panic(reason) \ - { \ - log("%s:%d: %s: Panic: %s", __FILE__, __LINE__, __func__, (reason)); \ - while (1) \ - __asm__ volatile("cli\nhlt"); \ - } - -#define assert(exp) \ - { \ - if (!(exp)) \ - panic("Assertion '" #exp "' failed\n"); \ - } - -// This shouldn't return, therefore this declaration belongs here (kinda) -void jmp_kernel(void *kernel, int args, ...); - -#endif diff --git a/src/loader/inc/protocol.h b/src/loader/inc/protocol.h new file mode 100644 index 0000000..a667467 --- /dev/null +++ b/src/loader/inc/protocol.h @@ -0,0 +1,20 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef IMPL_H +#define IMPL_H + +#include + +enum impl_type { + IMPL_NONE, + IMPL_MB1, + IMPL_MB2, +}; + +struct impl { + enum impl_type type; + u32 offset; // Of header/entry + void (*load)(struct dev *, const char *); +}; + +#endif diff --git a/src/loader/inc/protocols/all.h b/src/loader/inc/protocols/all.h new file mode 100644 index 0000000..9b6e750 --- /dev/null +++ b/src/loader/inc/protocols/all.h @@ -0,0 +1,12 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef IMPL_ALL_H +#define IMPL_ALL_H + +#include +#include + +u8 impl_detect(struct config_entry *cfg); +void impl_exec(struct config_entry *cfg); + +#endif diff --git a/src/loader/inc/protocols/mb1.h b/src/loader/inc/protocols/mb1.h new file mode 100644 index 0000000..2a85bc0 --- /dev/null +++ b/src/loader/inc/protocols/mb1.h @@ -0,0 +1,134 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef IMPL_MB1_H +#define IMPL_MB1_H + +#include +#include +#include + +#define MB1_MAGIC 0x1badb002 // Identifies kernel +#define MB1_LOAD_MAGIC 0x2badb002 // Passed to kernel + +#define MB1_INFO_MEMORY 0x00000001 +#define MB1_INFO_BOOTDEV 0x00000002 +#define MB1_INFO_CMDLINE 0x00000004 +#define MB1_INFO_MODS 0x00000008 +#define MB1_INFO_AOUT_SYMS 0x00000010 +#define MB1_INFO_ELF_SHDR 0x00000020 +#define MB1_INFO_MEMORY_MAP 0x00000040 +#define MB1_INFO_DRIVE_INFO 0x00000080 +#define MB1_INFO_CONFIG_TABLE 0x00000100 +#define MB1_INFO_BOOT_LOADER_NAME 0x00000200 +#define MB1_INFO_APM_TABLE 0x00000400 +#define MB1_INFO_VBE_INFO 0x00000800 +#define MB1_INFO_FRAMEBUFFER_INFO 0x00001000 + +#define MB1_FRAMEBUFFER_TYPE_INDEXED 0 +#define MB1_FRAMEBUFFER_TYPE_RGB 1 +#define MB1_FRAMEBUFFER_TYPE_EGA_TEXT 2 + +#define MB1_MEMORY_AVAILABLE 1 +#define MB1_MEMORY_RESERVED 2 +#define MB1_MEMORY_ACPI_RECLAIMABLE 3 +#define MB1_MEMORY_NVS 4 +#define MB1_MEMORY_BADRAM 5 + +#include + +struct mb1_aout_symbol_table { + u32 tabsize; + u32 strsize; + u32 addr; + u32 reserved; +}; + +struct mb1_elf_section_header_table { + u32 num; + u32 size; + u32 addr; + u32 shndx; +}; + +struct mb1_info { + u32 flags; + + u32 memory_lower; + u32 memory_upper; + + u32 boot_device; + + u32 cmdline; + + u32 mods_count; + u32 mods_addr; + + union { + struct mb1_aout_symbol_table aout_sym; + struct mb1_elf_section_header_table elf_sec; + } u; + + u32 mmap_length; + u32 mmap_addr; + + u32 drives_length; + u32 drives_addr; + + u32 config_table; + + u32 boot_loader_name; + + u32 apm_table; + + u32 vbe_control_info; + u32 vbe_mode_info; + u16 vbe_mode; + u16 vbe_interface_seg; + u16 vbe_interface_off; + u16 vbe_interface_len; + + u32 framebuffer_addr_high; + u32 framebuffer_addr_low; + u32 framebuffer_pitch; + u32 framebuffer_width; + u32 framebuffer_height; + u8 framebuffer_bpp; + u8 framebuffer_type; + union { + struct { + u32 framebuffer_palette_addr; + u16 framebuffer_palette_num_colors; + } palette; + struct { + u8 framebuffer_red_field_position; + u8 framebuffer_red_mask_size; + u8 framebuffer_green_field_position; + u8 framebuffer_green_mask_size; + u8 framebuffer_blue_field_position; + u8 framebuffer_blue_mask_size; + } colors; + } framebuffer_colors; +} PACKED; + +struct mb1_mmap_entry { + u32 struct_size; + u32 addr_low; + u32 addr_high; + u32 len_low; + u32 len_high; + u32 type; +} PACKED; + +struct mb1_mod_list { + u32 mod_start; + u32 mod_end; + + u32 cmdline; + + u32 pad; +}; + +u8 mb1_detect(struct config_entry *cfg); +void mb1_exec(struct config_entry *cfg); + +#endif diff --git a/src/loader/inc/protocols/mb2.h b/src/loader/inc/protocols/mb2.h new file mode 100644 index 0000000..b471b0f --- /dev/null +++ b/src/loader/inc/protocols/mb2.h @@ -0,0 +1,61 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef IMPL_MB2_H +#define IMPL_MB2_H + +#include +#include +#include + +#define MB2_MAGIC 0xe85250d6 // Identifies kernel +#define MB2_LOAD_MAGIC 0x36d76289 // Passed to kernel + +struct mb2_header { + u32 total_size; + u32 unknown; +} PACKED; + +struct mb2_tag { + u32 type; + u32 size; +} PACKED; + +struct mb2_memory { + u32 addr_low; + u32 addr_high; + u32 size_low; + u32 size_high; + u32 type; + u32 reserved; +} PACKED; + +struct mb2_module { + u32 start; + u32 end; + char string[1]; +} PACKED; + +struct mb2_fb { + u32 addr_low; + u32 addr_high; + u32 pitch; + u32 width; + u32 height; + u8 bpp; + u8 type; +} PACKED; + +enum mb2_tags { + MB2_TAG_END = 0, + MB2_TAG_CMDLINE = 1, + MB2_TAG_MODULE = 3, + MB2_TAG_MEMORY = 6, + MB2_TAG_FB = 8, + MB2_TAG_ACPI_1 = 14, + MB2_TAG_ACPI_2 = 15, +}; + +u8 mb2_detect(struct config_entry *cfg); +void mb2_exec(struct config_entry *cfg); + +#endif diff --git a/src/loader/inc/real.h b/src/loader/inc/real.h new file mode 100644 index 0000000..a9d36dc --- /dev/null +++ b/src/loader/inc/real.h @@ -0,0 +1,29 @@ +// MIT License, Copyright (c) 2021 Marvin Borner +// Real mode emulation - Implementation by Napalm (see rem.asm) + +#ifndef REAL_H +#define REAL_H + +#include + +#define EFLAGS_CF (1 << 0) // Carry flag +#define EFLAGS_ZF (1 << 6) // Zero flag + +struct real_regs { + u16 gs; + u16 fs; + u16 es; + u16 ds; + u32 eflags; + u32 ebp; + u32 edi; + u32 esi; + u32 edx; + u32 ecx; + u32 ebx; + u32 eax; +} PACKED; + +void real_int(u8 interrupt_num, struct real_regs *out_regs, struct real_regs *in_regs); + +#endif diff --git a/src/loader/inc/rem.h b/src/loader/inc/rem.h deleted file mode 100644 index 61eb30a..0000000 --- a/src/loader/inc/rem.h +++ /dev/null @@ -1,29 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner -// Real mode emulation - Implementation by Napalm (see rem.asm) - -#ifndef REM_H -#define REM_H - -#include - -#define EFLAGS_CF (1 << 0) // Carry flag -#define EFLAGS_ZF (1 << 6) // Zero flag - -struct rem_regs { - u16 gs; - u16 fs; - u16 es; - u16 ds; - u32 eflags; - u32 ebp; - u32 edi; - u32 esi; - u32 edx; - u32 ecx; - u32 ebx; - u32 eax; -} PACKED; - -void rem_int(u8 int_num, struct rem_regs *out_regs, struct rem_regs *in_regs); - -#endif diff --git a/src/loader/int.asm b/src/loader/int.asm deleted file mode 100644 index 4805448..0000000 --- a/src/loader/int.asm +++ /dev/null @@ -1,149 +0,0 @@ -; MIT License, Copyright (c) 2021 Marvin Borner - -%macro INT_REGISTER 1 -dd int%1 -%endmacro - -%macro INT_ERR 1 -int%1: - push %1 - jmp int_common -%endmacro - -%macro INT_NOERR 1 -int%1: - push 0 - push %1 - jmp int_common -%endmacro - -extern int_handler -int_common: - cld - - pushad - push ds - push es - push fs - push gs - - mov ax, 0x20 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - push esp - call int_handler - mov esp, eax - - pop gs - pop fs - pop es - pop ds - popad - - add esp, 8 - iret - -INT_NOERR 0 -INT_NOERR 1 -INT_NOERR 2 -INT_NOERR 3 -INT_NOERR 4 -INT_NOERR 5 -INT_NOERR 6 -INT_NOERR 7 -INT_ERR 8 -INT_NOERR 9 -INT_ERR 10 -INT_ERR 11 -INT_ERR 12 -INT_ERR 13 -INT_ERR 14 -INT_NOERR 15 -INT_NOERR 16 -INT_ERR 17 -INT_NOERR 18 -INT_NOERR 19 -INT_NOERR 20 -INT_NOERR 21 -INT_NOERR 22 -INT_NOERR 23 -INT_NOERR 24 -INT_NOERR 25 -INT_NOERR 26 -INT_NOERR 27 -INT_NOERR 28 -INT_NOERR 29 -INT_ERR 30 -INT_NOERR 31 - -INT_NOERR 32 -INT_NOERR 33 -INT_NOERR 34 -INT_NOERR 35 -INT_NOERR 36 -INT_NOERR 37 -INT_NOERR 38 -INT_NOERR 39 -INT_NOERR 40 -INT_NOERR 41 -INT_NOERR 42 -INT_NOERR 43 -INT_NOERR 44 -INT_NOERR 45 -INT_NOERR 46 -INT_NOERR 47 - -global int_table -int_table: - INT_REGISTER 0 - INT_REGISTER 1 - INT_REGISTER 2 - INT_REGISTER 3 - INT_REGISTER 4 - INT_REGISTER 5 - INT_REGISTER 6 - INT_REGISTER 7 - INT_REGISTER 8 - INT_REGISTER 9 - INT_REGISTER 10 - INT_REGISTER 11 - INT_REGISTER 12 - INT_REGISTER 13 - INT_REGISTER 14 - INT_REGISTER 15 - INT_REGISTER 16 - INT_REGISTER 17 - INT_REGISTER 18 - INT_REGISTER 19 - INT_REGISTER 20 - INT_REGISTER 21 - INT_REGISTER 22 - INT_REGISTER 23 - INT_REGISTER 24 - INT_REGISTER 25 - INT_REGISTER 26 - INT_REGISTER 27 - INT_REGISTER 28 - INT_REGISTER 29 - INT_REGISTER 30 - INT_REGISTER 31 - - INT_REGISTER 32 - INT_REGISTER 33 - INT_REGISTER 34 - INT_REGISTER 35 - INT_REGISTER 36 - INT_REGISTER 37 - INT_REGISTER 38 - INT_REGISTER 39 - INT_REGISTER 40 - INT_REGISTER 41 - INT_REGISTER 42 - INT_REGISTER 43 - INT_REGISTER 44 - INT_REGISTER 45 - INT_REGISTER 46 - INT_REGISTER 47 diff --git a/src/loader/int.c b/src/loader/int.c deleted file mode 100644 index d4e4841..0000000 --- a/src/loader/int.c +++ /dev/null @@ -1,132 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#include -#include -#include -#include - -/** - * IDT - */ - -extern u32 int_table[]; -static struct idt_entry idt_entries[256] = { 0 }; -REAL static struct idt_ptr idt = { .size = sizeof(idt_entries) - 1, .base = idt_entries }; - -void idt_install(void) -{ - for (u8 i = 0; i < 3; i++) - idt_entries[i] = IDT_ENTRY(int_table[i], 0x18, INT_GATE); - - idt_entries[3] = IDT_ENTRY(int_table[3], 0x18, INT_TRAP); - idt_entries[4] = IDT_ENTRY(int_table[4], 0x18, INT_TRAP); - - for (u8 i = 5; i < 48; i++) - idt_entries[i] = IDT_ENTRY(int_table[i], 0x18, INT_GATE); - - // Load table - __asm__ volatile("lidt %0" : : "m"(idt) : "memory"); -} - -/** - * Exception (trap) handling - */ - -const char *int_trap_names[32] = { - "Division By Zero", - "Debug", - "Non Maskable Interrupt", - "Breakpoint", - "Into Detected Overflow", - "Out of Bounds", - "Invalid Opcode", - "No Coprocessor", - - "Double Fault", - "Coprocessor Segment Overrun", - "Bad TSS", - "Segment Not Present", - "Stack Fault", - "General Protection Fault", - "Page Fault", - "Unknown Interrupt", - - "Coprocessor Fault", - "Alignment Check", - "Machine Check", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", -}; - -static void int_trap_handler(struct int_frame *frame) -{ - static u8 faulting = 0; - faulting++; - - if (faulting == 2) { - // Fall back to serial driver - serial_print("Double fault, halting immediatly\n"); - while (1) - __asm__ volatile("cli\nhlt"); - } - - log("%s Exception (code %x) at 0x%x!\n", int_trap_names[frame->int_no], frame->err_code, - frame->eip); - - while (1) - __asm__ volatile("cli\nhlt"); -} - -/** - * Event handling - */ - -static void (*int_event_handlers[16])(void) = { 0 }; - -void int_event_handler_add(u32 int_no, void (*handler)(void)) -{ - assert(int_no < COUNT(int_event_handlers)); - int_event_handlers[int_no] = handler; -} - -static u32 int_event_handler(struct int_frame *frame) -{ - u32 int_no = frame->int_no - 32; - assert(int_no < COUNT(int_event_handlers)); - void (*handler)(void) = int_event_handlers[int_no]; - if (handler) - handler(); - - return (u32)frame; -} - -/** - * Universal handler - */ - -u32 int_handler(u32 esp); -u32 int_handler(u32 esp) -{ - struct int_frame *frame = (struct int_frame *)esp; - if (frame->int_no < 32) - int_trap_handler(frame); - else if (frame->int_no < 48) - esp = int_event_handler(frame); - else - panic("Unknown interrupt\n"); - - pic_ack(frame->int_no); - return esp; -} diff --git a/src/loader/interrupt.asm b/src/loader/interrupt.asm new file mode 100644 index 0000000..7ac805b --- /dev/null +++ b/src/loader/interrupt.asm @@ -0,0 +1,149 @@ +; MIT License, Copyright (c) 2021 Marvin Borner + +%macro INTERRUPT_REGISTER 1 +dd int%1 +%endmacro + +%macro INTERRUPT_ERR 1 +int%1: + push %1 + jmp interrupt_common +%endmacro + +%macro INTERRUPT_NOERR 1 +int%1: + push 0 + push %1 + jmp interrupt_common +%endmacro + +extern interrupt_handler +interrupt_common: + cld + + pushad + push ds + push es + push fs + push gs + + mov ax, 0x20 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + push esp + call interrupt_handler + mov esp, eax + + pop gs + pop fs + pop es + pop ds + popad + + add esp, 8 + iret + +INTERRUPT_NOERR 0 +INTERRUPT_NOERR 1 +INTERRUPT_NOERR 2 +INTERRUPT_NOERR 3 +INTERRUPT_NOERR 4 +INTERRUPT_NOERR 5 +INTERRUPT_NOERR 6 +INTERRUPT_NOERR 7 +INTERRUPT_ERR 8 +INTERRUPT_NOERR 9 +INTERRUPT_ERR 10 +INTERRUPT_ERR 11 +INTERRUPT_ERR 12 +INTERRUPT_ERR 13 +INTERRUPT_ERR 14 +INTERRUPT_NOERR 15 +INTERRUPT_NOERR 16 +INTERRUPT_ERR 17 +INTERRUPT_NOERR 18 +INTERRUPT_NOERR 19 +INTERRUPT_NOERR 20 +INTERRUPT_NOERR 21 +INTERRUPT_NOERR 22 +INTERRUPT_NOERR 23 +INTERRUPT_NOERR 24 +INTERRUPT_NOERR 25 +INTERRUPT_NOERR 26 +INTERRUPT_NOERR 27 +INTERRUPT_NOERR 28 +INTERRUPT_NOERR 29 +INTERRUPT_ERR 30 +INTERRUPT_NOERR 31 + +INTERRUPT_NOERR 32 +INTERRUPT_NOERR 33 +INTERRUPT_NOERR 34 +INTERRUPT_NOERR 35 +INTERRUPT_NOERR 36 +INTERRUPT_NOERR 37 +INTERRUPT_NOERR 38 +INTERRUPT_NOERR 39 +INTERRUPT_NOERR 40 +INTERRUPT_NOERR 41 +INTERRUPT_NOERR 42 +INTERRUPT_NOERR 43 +INTERRUPT_NOERR 44 +INTERRUPT_NOERR 45 +INTERRUPT_NOERR 46 +INTERRUPT_NOERR 47 + +global interrupt_table +interrupt_table: + INTERRUPT_REGISTER 0 + INTERRUPT_REGISTER 1 + INTERRUPT_REGISTER 2 + INTERRUPT_REGISTER 3 + INTERRUPT_REGISTER 4 + INTERRUPT_REGISTER 5 + INTERRUPT_REGISTER 6 + INTERRUPT_REGISTER 7 + INTERRUPT_REGISTER 8 + INTERRUPT_REGISTER 9 + INTERRUPT_REGISTER 10 + INTERRUPT_REGISTER 11 + INTERRUPT_REGISTER 12 + INTERRUPT_REGISTER 13 + INTERRUPT_REGISTER 14 + INTERRUPT_REGISTER 15 + INTERRUPT_REGISTER 16 + INTERRUPT_REGISTER 17 + INTERRUPT_REGISTER 18 + INTERRUPT_REGISTER 19 + INTERRUPT_REGISTER 20 + INTERRUPT_REGISTER 21 + INTERRUPT_REGISTER 22 + INTERRUPT_REGISTER 23 + INTERRUPT_REGISTER 24 + INTERRUPT_REGISTER 25 + INTERRUPT_REGISTER 26 + INTERRUPT_REGISTER 27 + INTERRUPT_REGISTER 28 + INTERRUPT_REGISTER 29 + INTERRUPT_REGISTER 30 + INTERRUPT_REGISTER 31 + + INTERRUPT_REGISTER 32 + INTERRUPT_REGISTER 33 + INTERRUPT_REGISTER 34 + INTERRUPT_REGISTER 35 + INTERRUPT_REGISTER 36 + INTERRUPT_REGISTER 37 + INTERRUPT_REGISTER 38 + INTERRUPT_REGISTER 39 + INTERRUPT_REGISTER 40 + INTERRUPT_REGISTER 41 + INTERRUPT_REGISTER 42 + INTERRUPT_REGISTER 43 + INTERRUPT_REGISTER 44 + INTERRUPT_REGISTER 45 + INTERRUPT_REGISTER 46 + INTERRUPT_REGISTER 47 diff --git a/src/loader/interrupt.c b/src/loader/interrupt.c new file mode 100644 index 0000000..e05b4e0 --- /dev/null +++ b/src/loader/interrupt.c @@ -0,0 +1,132 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include +#include +#include +#include + +/** + * IDT + */ + +extern u32 interrupt_table[]; +static struct idt_entry idt_entries[256] = { 0 }; +REAL static struct idt_ptr idt = { .size = sizeof(idt_entries) - 1, .base = idt_entries }; + +void idt_install(void) +{ + for (u8 i = 0; i < 3; i++) + idt_entries[i] = IDT_ENTRY(interrupt_table[i], 0x18, INTERRUPT_GATE); + + idt_entries[3] = IDT_ENTRY(interrupt_table[3], 0x18, INTERRUPT_TRAP); + idt_entries[4] = IDT_ENTRY(interrupt_table[4], 0x18, INTERRUPT_TRAP); + + for (u8 i = 5; i < 48; i++) + idt_entries[i] = IDT_ENTRY(interrupt_table[i], 0x18, INTERRUPT_GATE); + + // Load table + __asm__ volatile("lidt %0" : : "m"(idt) : "memory"); +} + +/** + * Exception (trap) handling + */ + +static const char *interrupt_trap_names[32] = { + "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Into Detected Overflow", + "Out of Bounds", + "Invalid Opcode", + "No Coprocessor", + + "Double Fault", + "Coprocessor Segment Overrun", + "Bad TSS", + "Segment Not Present", + "Stack Fault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", +}; + +static void interrupt_trap_handler(struct interrupt_frame *frame) +{ + static u8 faulting = 0; + faulting++; + + if (faulting == 2) { + // Fall back to serial driver + serial_print("Double fault, halting immediatly\n"); + while (1) + __asm__ volatile("cli\nhlt"); + } + + log("%s Exception (code %x) at 0x%x!\n", interrupt_trap_names[frame->interrupt_no], frame->err_code, + frame->eip); + + while (1) + __asm__ volatile("cli\nhlt"); +} + +/** + * Event handling + */ + +static void (*interrupt_event_handlers[16])(void) = { 0 }; + +void interrupt_event_handler_add(u32 interrupt_no, void (*handler)(void)) +{ + assert(interrupt_no < COUNT(interrupt_event_handlers)); + interrupt_event_handlers[interrupt_no] = handler; +} + +static u32 interrupt_event_handler(struct interrupt_frame *frame) +{ + u32 interrupt_no = frame->interrupt_no - 32; + assert(interrupt_no < COUNT(interrupt_event_handlers)); + void (*handler)(void) = interrupt_event_handlers[interrupt_no]; + if (handler) + handler(); + + return (u32)frame; +} + +/** + * Universal handler + */ + +u32 interrupt_handler(u32 esp); +u32 interrupt_handler(u32 esp) +{ + struct interrupt_frame *frame = (struct interrupt_frame *)esp; + if (frame->interrupt_no < 32) + interrupt_trap_handler(frame); + else if (frame->interrupt_no < 48) + esp = interrupt_event_handler(frame); + else + panic("Unknown interrupt\n"); + + pic_ack(frame->interrupt_no); + return esp; +} diff --git a/src/loader/jmp.asm b/src/loader/jmp.asm deleted file mode 100644 index f591dda..0000000 --- a/src/loader/jmp.asm +++ /dev/null @@ -1,28 +0,0 @@ -; MIT License, Copyright (c) 2021 Marvin Borner -; Exit the bootloader and clear registers - -bits 32 - -; Empty (invalid) idt -idt: - dd 0, 0 - -global jmp_kernel -jmp_kernel: - cli ; Disable interrupts because of invalid idt - lidt [idt] ; Load empty (invalid) idt - - xor eax, eax - lldt ax ; Clear LDT by pointing to nothing - - add esp, 4 - pop edi - add esp, 4 - - mov eax, 0x00000001 - mov cr0, eax ; Clear cr0 except protected mode - - xor eax, eax - mov cr4, eax ; Clear cr4 completely - - call edi ; Call custom (specified) jumper diff --git a/src/loader/jumper.asm b/src/loader/jumper.asm new file mode 100644 index 0000000..f591dda --- /dev/null +++ b/src/loader/jumper.asm @@ -0,0 +1,28 @@ +; MIT License, Copyright (c) 2021 Marvin Borner +; Exit the bootloader and clear registers + +bits 32 + +; Empty (invalid) idt +idt: + dd 0, 0 + +global jmp_kernel +jmp_kernel: + cli ; Disable interrupts because of invalid idt + lidt [idt] ; Load empty (invalid) idt + + xor eax, eax + lldt ax ; Clear LDT by pointing to nothing + + add esp, 4 + pop edi + add esp, 4 + + mov eax, 0x00000001 + mov cr0, eax ; Clear cr0 except protected mode + + xor eax, eax + mov cr4, eax ; Clear cr4 completely + + call edi ; Call custom (specified) jumper diff --git a/src/loader/lib.c b/src/loader/lib.c deleted file mode 100644 index a5a1aee..0000000 --- a/src/loader/lib.c +++ /dev/null @@ -1,172 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#include - -/** - * Common string functions - */ - -u32 strlen(const char *str) -{ - const char *s = str; - while (*s) - s++; - return s - str; -} - -u32 strnlen(const char *str, u32 max) -{ - const char *s = str; - while (max && *s) { - s++; - max--; - } - return s - str; -} - -u32 strlcpy(char *dst, const char *src, u32 size) -{ - const char *orig = src; - u32 left = size; - - if (left) - while (--left) - if (!(*dst++ = *src++)) - break; - - if (!left) { - if (size) - *dst = 0; - while (*src++) - ; - } - - return src - orig - 1; -} - -s32 strncmp(const char *s1, const char *s2, u32 n) -{ - const u8 *c1 = (const u8 *)s1; - const u8 *c2 = (const u8 *)s2; - u8 ch; - s32 d = 0; - - while (n--) { - d = (s32)(ch = *c1++) - (s32)*c2++; - if (d || !ch) - break; - } - - return d; -} - -/** - * Common memory functions - */ - -void *memcpy(void *dest, const void *src, u32 n) -{ - // Inspired by jgraef at osdev - u32 num_dwords = n / 4; - u32 num_bytes = n % 4; - u32 *dest32 = (u32 *)dest; - const u32 *src32 = (const u32 *)src; - u8 *dest8 = ((u8 *)dest) + num_dwords * 4; - const u8 *src8 = ((const u8 *)src) + num_dwords * 4; - - __asm__ volatile("rep movsl\n" - : "=S"(src32), "=D"(dest32), "=c"(num_dwords) - : "S"(src32), "D"(dest32), "c"(num_dwords) - : "memory"); - - for (u32 i = 0; i < num_bytes; i++) - dest8[i] = src8[i]; - - return dest; -} - -void *memset(void *dest, u32 val, u32 n) -{ - // Inspired by jgraef at osdev - u32 uval = val; - u32 num_dwords = n / 4; - u32 num_bytes = n % 4; - u32 *dest32 = (u32 *)dest; - u8 *dest8 = ((u8 *)dest) + num_dwords * 4; - u8 val8 = (u8)val; - u32 val32 = uval | (uval << 8) | (uval << 16) | (uval << 24); - - __asm__ volatile("rep stosl\n" - : "=D"(dest32), "=c"(num_dwords) - : "D"(dest32), "c"(num_dwords), "a"(val32) - : "memory"); - - for (u32 i = 0; i < num_bytes; i++) - dest8[i] = val8; - - return dest; -} - -s32 memcmp(const void *s1, const void *s2, u32 n) -{ - const u8 *a = (const u8 *)s1; - const u8 *b = (const u8 *)s2; - for (u32 i = 0; i < n; i++) { - if (a[i] < b[i]) - return -1; - else if (b[i] < a[i]) - return 1; - } - return 0; -} - -/** - * Conversion - */ - -s32 itoa(s32 value, char *buffer, u32 base) -{ - char tmp[16]; - char *tp = tmp; - s32 i; - unsigned v; - - s32 sign = (base == 10 && value < 0); - if (sign) - v = -value; - else - v = (unsigned)value; - - while (v || tp == tmp) { - i = v % base; - v /= base; - if (i < 10) - *tp++ = i + '0'; - else - *tp++ = i + 'a' - 10; - } - - s32 len = tp - tmp; - - if (sign) { - *buffer++ = '-'; - len++; - } - - while (tp > tmp) - *buffer++ = *--tp; - *buffer = '\0'; - - return len; -} - -// From stackoverflow -s32 atoi(const char *inp) -{ - s32 ret = 0; - while (*inp) { - ret = (ret << 3) + (ret << 1) + (*inp) - '0'; - inp++; - } - return ret; -} diff --git a/src/loader/library.c b/src/loader/library.c new file mode 100644 index 0000000..4317a8e --- /dev/null +++ b/src/loader/library.c @@ -0,0 +1,172 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include + +/** + * Common string functions + */ + +u32 strlen(const char *str) +{ + const char *s = str; + while (*s) + s++; + return s - str; +} + +u32 strnlen(const char *str, u32 max) +{ + const char *s = str; + while (max && *s) { + s++; + max--; + } + return s - str; +} + +u32 strlcpy(char *dst, const char *src, u32 size) +{ + const char *orig = src; + u32 left = size; + + if (left) + while (--left) + if (!(*dst++ = *src++)) + break; + + if (!left) { + if (size) + *dst = 0; + while (*src++) + ; + } + + return src - orig - 1; +} + +s32 strncmp(const char *s1, const char *s2, u32 n) +{ + const u8 *c1 = (const u8 *)s1; + const u8 *c2 = (const u8 *)s2; + u8 ch; + s32 d = 0; + + while (n--) { + d = (s32)(ch = *c1++) - (s32)*c2++; + if (d || !ch) + break; + } + + return d; +} + +/** + * Common memory functions + */ + +void *memcpy(void *dest, const void *src, u32 n) +{ + // Inspired by jgraef at osdev + u32 num_dwords = n / 4; + u32 num_bytes = n % 4; + u32 *dest32 = (u32 *)dest; + const u32 *src32 = (const u32 *)src; + u8 *dest8 = ((u8 *)dest) + num_dwords * 4; + const u8 *src8 = ((const u8 *)src) + num_dwords * 4; + + __asm__ volatile("rep movsl\n" + : "=S"(src32), "=D"(dest32), "=c"(num_dwords) + : "S"(src32), "D"(dest32), "c"(num_dwords) + : "memory"); + + for (u32 i = 0; i < num_bytes; i++) + dest8[i] = src8[i]; + + return dest; +} + +void *memset(void *dest, u32 val, u32 n) +{ + // Inspired by jgraef at osdev + u32 uval = val; + u32 num_dwords = n / 4; + u32 num_bytes = n % 4; + u32 *dest32 = (u32 *)dest; + u8 *dest8 = ((u8 *)dest) + num_dwords * 4; + u8 val8 = (u8)val; + u32 val32 = uval | (uval << 8) | (uval << 16) | (uval << 24); + + __asm__ volatile("rep stosl\n" + : "=D"(dest32), "=c"(num_dwords) + : "D"(dest32), "c"(num_dwords), "a"(val32) + : "memory"); + + for (u32 i = 0; i < num_bytes; i++) + dest8[i] = val8; + + return dest; +} + +s32 memcmp(const void *s1, const void *s2, u32 n) +{ + const u8 *a = (const u8 *)s1; + const u8 *b = (const u8 *)s2; + for (u32 i = 0; i < n; i++) { + if (a[i] < b[i]) + return -1; + else if (b[i] < a[i]) + return 1; + } + return 0; +} + +/** + * Conversion + */ + +s32 itoa(s32 value, char *buffer, u32 base) +{ + char tmp[16]; + char *tp = tmp; + s32 i; + unsigned v; + + s32 sign = (base == 10 && value < 0); + if (sign) + v = -value; + else + v = (unsigned)value; + + while (v || tp == tmp) { + i = v % base; + v /= base; + if (i < 10) + *tp++ = i + '0'; + else + *tp++ = i + 'a' - 10; + } + + s32 len = tp - tmp; + + if (sign) { + *buffer++ = '-'; + len++; + } + + while (tp > tmp) + *buffer++ = *--tp; + *buffer = '\0'; + + return len; +} + +// From stackoverflow +s32 atoi(const char *inp) +{ + s32 ret = 0; + while (*inp) { + ret = (ret << 3) + (ret << 1) + (*inp) - '0'; + inp++; + } + return ret; +} diff --git a/src/loader/log.c b/src/loader/log.c deleted file mode 100644 index 3a4167f..0000000 --- a/src/loader/log.c +++ /dev/null @@ -1,189 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#include -#include -#include -#include - -/** - * Formatting - */ - -static u32 vsnprintf(char *str, u32 size, const char *format, va_list ap) -{ - u32 length = 0; - - int temp_int; - char temp_ch; - char *temp_str; - - char buffer[64] = { 0 }; - - // TODO: Fix potential memory overflows because of str[length++]=xxx - char ch; - while ((ch = *format++)) { - if (ch == '%') { - switch (*format++) { - case '%': - str[length++] = '%'; - break; - case 'c': - temp_ch = va_arg(ap, int); - str[length++] = temp_ch; - break; - case 's': - temp_str = va_arg(ap, char *); - length += strlcpy(&str[length], temp_str, size - length); - break; - case 'b': - temp_int = va_arg(ap, int); - itoa(temp_int, buffer, 2); - length += strlcpy(&str[length], buffer, size - length); - break; - case 'd': - temp_int = va_arg(ap, int); - itoa(temp_int, buffer, 10); - length += strlcpy(&str[length], buffer, size - length); - break; - case 'x': - temp_int = va_arg(ap, int); - itoa(temp_int, buffer, 16); - length += strlcpy(&str[length], buffer, size - length); - break; - default: - serial_print("Unknown printf format\n"); - } - } else { - str[length++] = ch; - } - } - - return length; -} - -/** - * Serial - */ - -#define PORT 0x3f8 - -void serial_install(void) -{ - outb(PORT + 1, 0x00); - outb(PORT + 3, 0x80); - outb(PORT + 0, 0x03); - outb(PORT + 1, 0x00); - outb(PORT + 3, 0x03); - outb(PORT + 2, 0xc7); - - // Test serial chip - outb(PORT + 4, 0x1e); // Enable loopback - outb(PORT + 0, 0xae); // Write - assert(inb(PORT + 0) == 0xae); // Verify receive - - // Activate - outb(PORT + 4, 0x0f); - - log("[LOG] Initiated\n"); -} - -static int serial_empty(void) -{ - return inb(PORT + 5) & 0x20; -} - -static void serial_put(char ch) -{ - while (serial_empty() == 0) - ; - outb(PORT, (u8)ch); -} - -void serial_print(const char *data) -{ - for (const char *p = data; *p; p++) - serial_put(*p); -} - -/** - * VGA - */ - -#define VGA_WIDTH 80 -#define VGA_HEIGHT 25 -#define VGA_ADDRESS 0xb8000 - -void vga_clear(void) -{ - u16 *out = (u16 *)VGA_ADDRESS; - for (u16 i = 0; i < 80 * 25; i++) - out[i] = 0; -} - -void vga_put_at(char ch, u8 x, u8 y, u8 color) -{ - u8 *out = (u8 *)(VGA_ADDRESS + 2 * (x + y * VGA_WIDTH)); - *out++ = ch; - *out++ = color; -} - -static void vga_put(char ch) -{ - static u8 x = 0; - static u8 y = 0; - - if (ch == '\n') { - x = 0; - y++; - return; - } else if (x + 1 == VGA_WIDTH) { - x = 0; - y++; - } else if (y + 1 == VGA_HEIGHT) { - x = 0; - y = 0; - vga_clear(); - } - - u8 *out = (u8 *)(VGA_ADDRESS + 2 * (x + y * VGA_WIDTH)); - *out++ = ch; - *out++ = 0x07; - - x++; -} - -static void vga_print(const char *data) -{ - for (const char *p = data; *p; p++) - vga_put(*p); -} - -/** - * Formatted print functions - */ - -// Serial -void log(const char *format, ...) -{ - char buf[1024] = { 0 }; - - va_list ap; - va_start(ap, format); - vsnprintf(buf, sizeof(buf), format, ap); - va_end(ap); - - serial_print(buf); -} - -// VGA log -void vga_log(const char *format, ...) -{ - char buf[1024] = { 0 }; - - va_list ap; - va_start(ap, format); - vsnprintf(buf, sizeof(buf), format, ap); - va_end(ap); - - vga_print(buf); -} diff --git a/src/loader/main.c b/src/loader/main.c index a16149e..1884b2f 100644 --- a/src/loader/main.c +++ b/src/loader/main.c @@ -2,14 +2,14 @@ #include #include -#include +#include #include -#include +#include #include #include -#include +#include #include -#include +#include #include #include @@ -23,7 +23,7 @@ int start(u8 disk); int start(u8 disk) { boot_disk = disk; - mem_map(); + memory_map(); a20_enable(); vga_clear(); @@ -34,9 +34,9 @@ int start(u8 disk) // acpi_probe(); // TODO: Fix slow ACPI probing pci_probe(); - dev_print(); + device_print(); - cfg_read(); + config_read(); gui_draw(); // Sleep and wait for interrupts diff --git a/src/loader/mbr.c b/src/loader/mbr.c index df0c1db..f0f473a 100644 --- a/src/loader/mbr.c +++ b/src/loader/mbr.c @@ -1,17 +1,17 @@ // MIT License, Copyright (c) 2021 Marvin Borner -#include +#include #include #include -#include +#include 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_by_id(dev_id); - assert(dev && dev->type == DEV_DISK && dev->read); + u8 device_id = (part->data & 0xff00) >> 8; + struct dev *dev = device_get_by_id(device_id); + assert(dev && dev->type == DEVICE_DISK && dev->read); u8 mbr_id = part->data & 0xff; assert(mbr_id < COUNT(entries)); @@ -30,7 +30,7 @@ static u8 mbr_add_entry(struct mbr_entry *entry) u8 mbr_detect(struct dev *dev) { - assert(dev->type == DEV_DISK); + assert(dev->type == DEVICE_DISK); struct mbr mbr = { 0 }; dev->read(&mbr, 0, 1, dev); // Read first sector (MBR) @@ -52,7 +52,7 @@ u8 mbr_detect(struct dev *dev) // Saving space and everything u16 data = mbr_add_entry(entry) | (dev->id << 8); - dev_register(DEV_DISK, name, data, mbr_read, NULL); + device_register(DEVICE_DISK, name, data, mbr_read, NULL); } return 1; diff --git a/src/loader/mem.c b/src/loader/mem.c deleted file mode 100644 index 698c85d..0000000 --- a/src/loader/mem.c +++ /dev/null @@ -1,125 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner -// Memory map generator - -#include -#include -#include -#include - -/** - * Memory map using e820 BIOS call - */ - -#define E820_MAX_ENTRIES 256 // Spec - -enum e820_entry_type { - E820_MEM_NONE, - E820_MEM_USABLE, - E820_MEM_RESERVED, - E820_MEM_RECLAIMABLE, - E820_MEM_ACPI_NVS, - E820_MEM_UNUSABLE, -}; - -struct e820_entry { - u32 base_low; - u32 base_high; - u32 length_low; - u32 length_high; - enum e820_entry_type type; - u32 unused; -} PACKED; - -u16 e820_count = 0; -struct e820_entry e820_map[E820_MAX_ENTRIES] = { 0 }; - -static u8 mem_e820(void) -{ - struct rem_regs r = { 0 }; - - for (u32 i = 0; i < E820_MAX_ENTRIES; i++) { - struct e820_entry entry = { 0 }; - - r.eax = 0xe820; - r.ecx = 24; - r.edx = 0x534d4150; - r.edi = (u32)&entry; - rem_int(0x15, &r, &r); - - if (r.eflags & EFLAGS_CF) { - e820_count = i; - return 1; - } - - e820_map[i] = entry; - - if (!r.ebx) { - e820_count = i++; - return 1; - } - } - - return 0; -} - -/** - * Configure memory map - */ - -#define MAP_MAX_ENTRIES 256 - -static struct mem_entry mem[MAP_MAX_ENTRIES] = { 0 }; -static struct mem_map map = { .entry = mem, .count = 0 }; - -static void mem_map_e820(void) -{ - u32 i; - for (i = 0; i < COUNT(e820_map); i++) { - struct e820_entry *e820_entry = &e820_map[i]; - struct mem_entry *map_entry = &mem[i]; - - map_entry->base = e820_entry->base_low; - map_entry->length = e820_entry->length_low; - - // Set type accordingly - switch (e820_entry->type) { - case E820_MEM_NONE: - map_entry->type = MEM_USABLE; - continue; - case E820_MEM_USABLE: - map_entry->type = MEM_USABLE; - break; - case E820_MEM_RESERVED: - map_entry->type = MEM_RESERVED; - break; - case E820_MEM_RECLAIMABLE: - map_entry->type = MEM_RECLAIMABLE; - break; - case E820_MEM_ACPI_NVS: - map_entry->type = MEM_ACPI_NVS; - break; - case E820_MEM_UNUSABLE: - map_entry->type = MEM_UNUSABLE; - break; - default: - panic("Unknown e820 type\n"); - } - } - - map.count = i; -} - -struct mem_map *mem_map_get(void) -{ - return ↦ -} - -void mem_map(void) -{ - if (mem_e820()) { - mem_map_e820(); - return; - } - - panic("Couldn't find memory map\n"); -} diff --git a/src/loader/memory.c b/src/loader/memory.c new file mode 100644 index 0000000..a38e48b --- /dev/null +++ b/src/loader/memory.c @@ -0,0 +1,125 @@ +// MIT License, Copyright (c) 2021 Marvin Borner +// Memory map generator + +#include +#include +#include +#include + +/** + * Memory map using e820 BIOS call + */ + +#define E820_MAX_ENTRIES 256 // Spec + +enum e820_entry_type { + E820_MEMORY_NONE, + E820_MEMORY_USABLE, + E820_MEMORY_RESERVED, + E820_MEMORY_RECLAIMABLE, + E820_MEMORY_ACPI_NVS, + E820_MEMORY_UNUSABLE, +}; + +struct e820_entry { + u32 base_low; + u32 base_high; + u32 length_low; + u32 length_high; + enum e820_entry_type type; + u32 unused; +} PACKED; + +u16 e820_count = 0; +struct e820_entry e820_map[E820_MAX_ENTRIES] = { 0 }; + +static u8 memory_e820(void) +{ + struct real_regs r = { 0 }; + + for (u32 i = 0; i < E820_MAX_ENTRIES; i++) { + struct e820_entry entry = { 0 }; + + r.eax = 0xe820; + r.ecx = 24; + r.edx = 0x534d4150; + r.edi = (u32)&entry; + real_int(0x15, &r, &r); + + if (r.eflags & EFLAGS_CF) { + e820_count = i; + return 1; + } + + e820_map[i] = entry; + + if (!r.ebx) { + e820_count = i++; + return 1; + } + } + + return 0; +} + +/** + * Configure memory map + */ + +#define MAP_MAX_ENTRIES 256 + +static struct memory_entry mem[MAP_MAX_ENTRIES] = { 0 }; +static struct memory_map map = { .entry = mem, .count = 0 }; + +static void memory_map_e820(void) +{ + u32 i; + for (i = 0; i < COUNT(e820_map); i++) { + struct e820_entry *e820_entry = &e820_map[i]; + struct memory_entry *map_entry = &mem[i]; + + map_entry->base = e820_entry->base_low; + map_entry->length = e820_entry->length_low; + + // Set type accordingly + switch (e820_entry->type) { + case E820_MEMORY_NONE: + map_entry->type = MEMORY_USABLE; + continue; + case E820_MEMORY_USABLE: + map_entry->type = MEMORY_USABLE; + break; + case E820_MEMORY_RESERVED: + map_entry->type = MEMORY_RESERVED; + break; + case E820_MEMORY_RECLAIMABLE: + map_entry->type = MEMORY_RECLAIMABLE; + break; + case E820_MEMORY_ACPI_NVS: + map_entry->type = MEMORY_ACPI_NVS; + break; + case E820_MEMORY_UNUSABLE: + map_entry->type = MEMORY_UNUSABLE; + break; + default: + panic("Unknown e820 type\n"); + } + } + + map.count = i; +} + +struct memory_map *memory_map_get(void) +{ + return ↦ +} + +void memory_map(void) +{ + if (memory_e820()) { + memory_map_e820(); + return; + } + + panic("Couldn't find memory map\n"); +} diff --git a/src/loader/pic.c b/src/loader/pic.c index 18b248c..fa728b6 100644 --- a/src/loader/pic.c +++ b/src/loader/pic.c @@ -55,9 +55,9 @@ void pic_install(void) pic_wait(); } -void pic_ack(u32 int_no) +void pic_ack(u32 interrupt_no) { - if (int_no >= 40) + if (interrupt_no >= 40) outb(PIC2, 0x20); outb(PIC1, 0x20); diff --git a/src/loader/protocols/all.c b/src/loader/protocols/all.c new file mode 100644 index 0000000..8ea16dd --- /dev/null +++ b/src/loader/protocols/all.c @@ -0,0 +1,36 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include +#include +#include +#include + +u8 impl_detect(struct config_entry *cfg) +{ + if (mb1_detect(cfg)) + return 1; + + if (mb2_detect(cfg)) + return 1; + + return 0; +} + +void impl_exec(struct config_entry *cfg) +{ + assert(cfg->dev->type == DEVICE_DISK); + + switch (cfg->impl.type) { + case IMPL_MB1: + mb1_exec(cfg); + break; + case IMPL_MB2: + mb2_exec(cfg); + break; + case IMPL_NONE: + default: + panic("Invalid implementation\n"); + } + + panic("Couldn't execute implementation\n"); +} diff --git a/src/loader/protocols/mb1.c b/src/loader/protocols/mb1.c new file mode 100644 index 0000000..cd57fad --- /dev/null +++ b/src/loader/protocols/mb1.c @@ -0,0 +1,147 @@ +// MIT License, Copyright (c) 2021 Marvin Borner +// Everything according to spec + +#include +#include +#include +#include +#include + +// The address where data gets stored +#define MB1_LOAD_ADDRESS 0x20000 + +#define MB1_FLAG_PAGE_ALIGN (1 << 0) // Align modules with page boundaries (4K) +#define MB1_FLAG_MEMORY_INFO (1 << 1) // Load/store all memory_* fields and mmap_* structs +#define MB1_FLAG_VIDEO_MODE (1 << 2) // Load/store video mode table +#define MB1_FLAG_MANUAL_ADDRESSES (1 << 16) // Use specified load addresses + +struct mb1_entry { + u32 magic; + u32 flags; + u32 checksum; // Everything after that is optional + u32 header_addr; // Unsupported + u32 load_addr; // Unsupported + u32 load_end_addr; // Unsupported + u32 bss_end_addr; // Unsupported + u32 entry_addr; // Unsupported + u32 mode_type; + u32 width; + u32 height; + u32 depth; +}; + +// The (really simple) multiboot checksum algorithm +static u32 mb1_checksum(struct mb1_entry *entry) +{ + return -(entry->magic + entry->flags); +} + +// Load data into memory and return address (not overlapping) +static u32 mb1_store(void *data, u32 size) +{ + static u32 offset = 0; + memcpy((void *)(MB1_LOAD_ADDRESS + offset), data, size); + offset += size; + return MB1_LOAD_ADDRESS + (offset - size); +} + +static void mb1_store_memory_info(struct mb1_info *info) +{ + // TODO: Store memory_lower and memory_upper + struct memory_map *memory_map = memory_map_get(); + info->flags |= MB1_INFO_MEMORY_MAP; + info->mmap_length = memory_map->count * sizeof(struct mb1_mmap_entry); + info->mmap_addr = mb1_store(NULL, 0); + for (u32 i = 0; i < memory_map->count; i++) { + struct mb1_mmap_entry mmap_entry = { 0 }; + mmap_entry.struct_size = sizeof(mmap_entry) - 4; + mmap_entry.addr_low = memory_map->entry[i].base; + mmap_entry.len_low = memory_map->entry[i].length; + mmap_entry.type = memory_map->entry[i].type; + mb1_store(&mmap_entry, sizeof(mmap_entry)); + } +} + +// Load the mb1 structs into memory +static void mb1_load(struct mb1_entry *entry) +{ + struct mb1_info info_struct = { 0 }; + struct mb1_info *info = (void *)mb1_store(&info_struct, sizeof(info_struct)); + + // Set boot device + info->flags |= MB1_INFO_BOOTDEV; + info->boot_device = boot_disk; + + // Set bootloader name + info->flags |= MB1_INFO_BOOT_LOADER_NAME; + char loader_name[] = "SegelBoot"; + info->boot_loader_name = mb1_store(loader_name, sizeof(loader_name)); + + // Store memory info + if (entry->flags & MB1_FLAG_MEMORY_INFO) + mb1_store_memory_info(info); +} + +// Jump to kernel with correct info pointer in eax +static void mb1_jump(u32 entry, u32 info) +{ + log("Jumping. So long and thanks for all the fish!\n"); + + // Move and jump! + __asm__ volatile("movl $" STRINGIFY(MB1_LOAD_MAGIC) ", %%eax\n\t" + "jmpl *%%edi\n\t" + : + : "D"(entry), "b"(info) + : "memory"); + + panic("Jumper returned\n"); +} + +// Detect and verify mb1 +u8 mb1_detect(struct config_entry *cfg) +{ + u8 header[8192] = { 0 }; + + s32 ret = cfg->dev->p.disk.fs.read(cfg->path, header, 0, sizeof(header), cfg->dev); + if (ret < 12) + return 0; + + // Find start of multiboot entry by searching for magic + struct mb1_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; + + cfg->impl.type = IMPL_MB1; + cfg->impl.offset = (u32)entry - (u32)header; + + return 1; +} + +// Execute mb1 type kernel +void mb1_exec(struct config_entry *cfg) +{ + struct mb1_entry mb1_entry = { 0 }; + s32 ret = cfg->dev->p.disk.fs.read(cfg->path, &mb1_entry, cfg->impl.offset, + sizeof(mb1_entry), cfg->dev); + assert(ret == sizeof(mb1_entry)); + mb1_load(&mb1_entry); + + u32 entry = elf_load(cfg->dev, cfg->path); + + // This is a kind of hacky parameter stack pushing thing, just disable warning :) +#pragma GCC diagnostic ignored "-Wpedantic" + jmp_kernel((void *)mb1_jump, 2, entry, MB1_LOAD_ADDRESS); +#pragma GCC diagnostic pop +} diff --git a/src/loader/protocols/mb2.c b/src/loader/protocols/mb2.c new file mode 100644 index 0000000..8f0a660 --- /dev/null +++ b/src/loader/protocols/mb2.c @@ -0,0 +1,105 @@ +// MIT License, Copyright (c) 2021 Marvin Borner +// Everything according to spec + +#include +#include +#include +#include + +// The address where data gets stored +#define MB2_LOAD_ADDRESS 0x10000 + +struct mb2_entry { + u32 magic; + u32 flags; + u32 header_length; + u32 checksum; // Everything after that is optional + u8 *tags; +}; + +// The (really simple) multiboot checksum algorithm +/* static u32 mb2_checksum(struct mb2_entry *entry) */ +/* { */ +/* return -(entry->magic + entry->flags); */ +/* } */ + +// Load data into memory and return address (not overlapping +static u32 mb2_store(void *data, u32 size) +{ + static u32 offset = 0; + memcpy((void *)MB2_LOAD_ADDRESS, data, size); + offset += size; + return MB2_LOAD_ADDRESS + (size - offset); +} + +// Load the mb2 structs into memory +static void mb2_load(struct mb2_entry *entry) +{ + (void)mb2_store; + (void)entry; +} + +// Jump to kernel with correct info pointer in eax +static void mb2_jump(u32 entry, u32 info) +{ + log("Jumping. So long and thanks for all the fish!\n"); + + // Move and jump! + __asm__ volatile("movl $" STRINGIFY(MB2_LOAD_MAGIC) ", %%eax\n\t" + "jmpl *%%edi\n\t" + : + : "D"(entry), "b"(info) + : "memory"); + + panic("Jumper returned\n"); +} + +// Detect and verify mb2 +u8 mb2_detect(struct config_entry *cfg) +{ + u8 header[8192] = { 0 }; + + s32 ret = cfg->dev->p.disk.fs.read(cfg->path, header, 0, sizeof(header), cfg->dev); + if (ret < 12) + return 0; + + // Find start of multiboot entry by searching for magic + struct mb2_entry *entry = 0; + for (u32 i = 0; i < sizeof(header); i++) { + u32 *p = (u32 *)&header[i]; + if (*p == MB2_MAGIC) { + entry = (void *)p; + break; + } + } + + if (!entry) + return 0; + + // TODO: mb2 checksum + /* u32 checksum = mb2_checksum(entry); */ + /* if (checksum != entry->checksum) */ + /* return 0; */ + + cfg->impl.type = IMPL_MB2; + cfg->impl.offset = (u32)entry - (u32)header; + + return 1; +} + +// Execute mb2 type kernel +void mb2_exec(struct config_entry *cfg) +{ + struct mb2_entry mb2_entry = { 0 }; + s32 ret = cfg->dev->p.disk.fs.read(cfg->path, &mb2_entry, cfg->impl.offset, + sizeof(mb2_entry), cfg->dev); + assert(ret == sizeof(mb2_entry)); + mb2_load(&mb2_entry); + + u32 entry = elf_load(cfg->dev, cfg->path); + + // This is a kind of hacky parameter stack pushing thing, just disable warning :) +#pragma GCC diagnostic ignored "-Wpedantic" + jmp_kernel((void *)mb2_jump, 2, entry, MB2_LOAD_ADDRESS); +#pragma GCC diagnostic pop +} diff --git a/src/loader/real.asm b/src/loader/real.asm new file mode 100644 index 0000000..a7c6fc0 --- /dev/null +++ b/src/loader/real.asm @@ -0,0 +1,139 @@ +; Real mode interrupt from protected mode +; Written by mintsuki, licensed under BSD 2-Clause "Simplified" License + +section .realmode + +global real_int +real_int: + ; Self-modifying code: int $interrupt_no + mov al, byte [esp+4] + mov byte [.interrupt_no], al + + ; Save out_regs + mov eax, dword [esp+8] + mov dword [.out_regs], eax + + ; Save in_regs + mov eax, dword [esp+12] + mov dword [.in_regs], eax + + ; Save GDT in case BIOS overwrites it + sgdt [.gdt] + + ; Save IDT + sidt [.idt] + + ; Load BIOS IVT + lidt [.real_idt] + + ; Save non-scratch GPRs + push ebx + push esi + push edi + push ebp + + ; Jump to real mode + jmp 0x08:.bits16 + .bits16: + bits 16 + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov eax, cr0 + and al, 0xfe + mov cr0, eax + jmp 0x00:.cszero + .cszero: + xor ax, ax + mov ss, ax + + ; Load in_regs + mov dword [ss:.esp], esp + mov esp, dword [ss:.in_regs] + pop gs + pop fs + pop es + pop ds + popfd + pop ebp + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + mov esp, dword [ss:.esp] + + sti + + ; Indirect interrupt call + db 0xcd + .interrupt_no: + db 0 + + cli + + ; Load out_regs + mov dword [ss:.esp], esp + mov esp, dword [ss:.out_regs] + lea esp, [esp + 10*4] + push eax + push ebx + push ecx + push edx + push esi + push edi + push ebp + pushfd + push ds + push es + push fs + push gs + mov esp, dword [ss:.esp] + + ; Restore GDT + o32 lgdt [ss:.gdt] + + ; Restore IDT + o32 lidt [ss:.idt] + + ; Jump back to pmode + mov eax, cr0 + or al, 1 + mov cr0, eax + jmp 0x18:.bits32 + .bits32: + bits 32 + mov ax, 0x20 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + ; Restore non-scratch GPRs + pop ebp + pop edi + pop esi + pop ebx + + ; Exit + ret + +align 16 +.esp: + dd 0 +.out_regs: + dd 0 +.in_regs: + dd 0 +.gdt: + dq 0 +.idt: + dq 0 +.real_idt: + dw 0x3ff + dd 0 diff --git a/src/loader/rem.asm b/src/loader/rem.asm deleted file mode 100644 index 7a33048..0000000 --- a/src/loader/rem.asm +++ /dev/null @@ -1,139 +0,0 @@ -; Real mode interrupt from protected mode -; Written by mintsuki, licensed under BSD 2-Clause "Simplified" License - -section .realmode - -global rem_int -rem_int: - ; Self-modifying code: int $int_no - mov al, byte [esp+4] - mov byte [.int_no], al - - ; Save out_regs - mov eax, dword [esp+8] - mov dword [.out_regs], eax - - ; Save in_regs - mov eax, dword [esp+12] - mov dword [.in_regs], eax - - ; Save GDT in case BIOS overwrites it - sgdt [.gdt] - - ; Save IDT - sidt [.idt] - - ; Load BIOS IVT - lidt [.rem_idt] - - ; Save non-scratch GPRs - push ebx - push esi - push edi - push ebp - - ; Jump to real mode - jmp 0x08:.bits16 - .bits16: - bits 16 - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - mov eax, cr0 - and al, 0xfe - mov cr0, eax - jmp 0x00:.cszero - .cszero: - xor ax, ax - mov ss, ax - - ; Load in_regs - mov dword [ss:.esp], esp - mov esp, dword [ss:.in_regs] - pop gs - pop fs - pop es - pop ds - popfd - pop ebp - pop edi - pop esi - pop edx - pop ecx - pop ebx - pop eax - mov esp, dword [ss:.esp] - - sti - - ; Indirect interrupt call - db 0xcd - .int_no: - db 0 - - cli - - ; Load out_regs - mov dword [ss:.esp], esp - mov esp, dword [ss:.out_regs] - lea esp, [esp + 10*4] - push eax - push ebx - push ecx - push edx - push esi - push edi - push ebp - pushfd - push ds - push es - push fs - push gs - mov esp, dword [ss:.esp] - - ; Restore GDT - o32 lgdt [ss:.gdt] - - ; Restore IDT - o32 lidt [ss:.idt] - - ; Jump back to pmode - mov eax, cr0 - or al, 1 - mov cr0, eax - jmp 0x18:.bits32 - .bits32: - bits 32 - mov ax, 0x20 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - ; Restore non-scratch GPRs - pop ebp - pop edi - pop esi - pop ebx - - ; Exit - ret - -align 16 -.esp: - dd 0 -.out_regs: - dd 0 -.in_regs: - dd 0 -.gdt: - dq 0 -.idt: - dq 0 -.rem_idt: - dw 0x3ff - dd 0 diff --git a/src/loader/serial.c b/src/loader/serial.c new file mode 100644 index 0000000..20299c4 --- /dev/null +++ b/src/loader/serial.c @@ -0,0 +1,57 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include +#include +#include + +#define PORT 0x3f8 + +void serial_install(void) +{ + outb(PORT + 1, 0x00); + outb(PORT + 3, 0x80); + outb(PORT + 0, 0x03); + outb(PORT + 1, 0x00); + outb(PORT + 3, 0x03); + outb(PORT + 2, 0xc7); + + // Test serial chip + outb(PORT + 4, 0x1e); // Enable loopback + outb(PORT + 0, 0xae); // Write + assert(inb(PORT + 0) == 0xae); // Verify receive + + // Activate + outb(PORT + 4, 0x0f); + + log("[LOG] Initiated\n"); +} + +static int serial_empty(void) +{ + return inb(PORT + 5) & 0x20; +} + +static void serial_put(char ch) +{ + while (serial_empty() == 0) + ; + outb(PORT, (u8)ch); +} + +void serial_print(const char *data) +{ + for (const char *p = data; *p; p++) + serial_put(*p); +} + +void log(const char *format, ...) +{ + char buf[1024] = { 0 }; + + va_list ap; + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + serial_print(buf); +} diff --git a/src/loader/vga.c b/src/loader/vga.c new file mode 100644 index 0000000..6cc9bfa --- /dev/null +++ b/src/loader/vga.c @@ -0,0 +1,64 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include + +#define VGA_WIDTH 80 +#define VGA_HEIGHT 25 +#define VGA_ADDRESS 0xb8000 + +void vga_clear(void) +{ + u16 *out = (u16 *)VGA_ADDRESS; + for (u16 i = 0; i < 80 * 25; i++) + out[i] = 0; +} + +void vga_put_at(char ch, u8 x, u8 y, u8 color) +{ + u8 *out = (u8 *)(VGA_ADDRESS + 2 * (x + y * VGA_WIDTH)); + *out++ = ch; + *out++ = color; +} + +static void vga_put(char ch) +{ + static u8 x = 0; + static u8 y = 0; + + if (ch == '\n') { + x = 0; + y++; + return; + } else if (x + 1 == VGA_WIDTH) { + x = 0; + y++; + } else if (y + 1 == VGA_HEIGHT) { + x = 0; + y = 0; + vga_clear(); + } + + u8 *out = (u8 *)(VGA_ADDRESS + 2 * (x + y * VGA_WIDTH)); + *out++ = ch; + *out++ = 0x07; + + x++; +} + +static void vga_print(const char *data) +{ + for (const char *p = data; *p; p++) + vga_put(*p); +} + +void vga_log(const char *format, ...) +{ + char buf[1024] = { 0 }; + + va_list ap; + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + vga_print(buf); +} -- cgit v1.2.3