From 065dbf51777be2d069f01a1bbbcff2759808fced Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Thu, 24 Feb 2022 18:11:09 +0200 Subject: [PATCH] better exception handling + bad kprintf --- Makefile | 4 +- cpu/exception.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ cpu/exception.h | 6 +++ cpu/idt.h | 4 +- kernel.c | 32 +++++------- std/kstd.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++ std/kstd.h | 11 ++++ std/std.c | 1 - vga.c | 20 ++++++-- 9 files changed, 305 insertions(+), 30 deletions(-) create mode 100644 cpu/exception.c create mode 100644 cpu/exception.h create mode 100644 std/kstd.c create mode 100644 std/kstd.h diff --git a/Makefile b/Makefile index 280b57a..f2cb23b 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CC=i686-elf-gcc bootstrap.o: bootstrap.s i686-elf-as bootstrap.s -o bootstrap.o -kernel.bin: bootstrap.o vga.o std/std.o cpu/idt.o cpu/pic.o kernel.o +kernel.bin: bootstrap.o vga.o std/std.o std/kstd.o cpu/idt.o cpu/pic.o cpu/exception.o kernel.o $(CC) -T linker.ld -o $@ -ffreestanding -O2 -nostdlib -lgcc $^ iso: kernel.bin @@ -18,7 +18,7 @@ iso: kernel.bin grub-mkrescue -o generated-iso.iso isodir run: iso - qemu-system-i386 -cdrom generated-iso.iso + qemu-system-i386 -d int -M smm=off -cdrom generated-iso.iso clean: rm -rf *.o kernel.bin *.iso isodir/ diff --git a/cpu/exception.c b/cpu/exception.c new file mode 100644 index 0000000..5e72520 --- /dev/null +++ b/cpu/exception.c @@ -0,0 +1,130 @@ +#include "cpu/idt.h" +#include "std/std.h" +#include "std/kstd.h" + +void generic_exception_handler(struct interrupt_descriptor_32 *frame, uint8_t irq) { + kprintf("\n\n"); + kprintf("---- PANIC -------------\n"); + kprintf("Kernel panic due to exception\n"); + kprintf("IRQ %d\n", (int)irq); + kprintf("------------------------\n"); + kabort(); +} + +__attribute__((interrupt)) +static void isr0(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 0); +} + +__attribute__((interrupt)) +static void isr1(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 1); +} + +__attribute__((interrupt)) +static void isr2(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 2); +} + +__attribute__((interrupt)) +static void isr3(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 3); +} + +__attribute__((interrupt)) +static void isr4(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 4); +} + +__attribute__((interrupt)) +static void isr5(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 5); +} + +__attribute__((interrupt)) +static void isr6(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 6); +} + +__attribute__((interrupt)) +static void isr7(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 7); +} + +__attribute__((interrupt)) +static void isr8(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 8); +} + +__attribute__((interrupt)) +static void isr9(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 9); +} + +__attribute__((interrupt)) +static void isr10(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 10); +} + +__attribute__((interrupt)) +static void isr11(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 11); +} + +__attribute__((interrupt)) +static void isr12(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 12); +} + +__attribute__((interrupt)) +static void isr13(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 13); +} + +__attribute__((interrupt)) +static void isr14(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 14); +} + +__attribute__((interrupt)) +static void isr15(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 15); +} + +__attribute__((interrupt)) +static void isr16(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 16); +} + +__attribute__((interrupt)) +static void isr17(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 17); +} + +__attribute__((interrupt)) +static void isr18(struct interrupt_descriptor_32 *frame) { + generic_exception_handler(frame, 17); +} + + +void exception_handlers_init() { + idt_register_handler(0, (size_t)isr0); + idt_register_handler(1, (size_t)isr1); + idt_register_handler(2, (size_t)isr2); + idt_register_handler(3, (size_t)isr3); + idt_register_handler(4, (size_t)isr4); + idt_register_handler(5, (size_t)isr5); + idt_register_handler(6, (size_t)isr6); + idt_register_handler(7, (size_t)isr7); + idt_register_handler(8, (size_t)isr8); + idt_register_handler(9, (size_t)isr9); + idt_register_handler(10, (size_t)isr10); + idt_register_handler(11, (size_t)isr11); + idt_register_handler(12, (size_t)isr12); + idt_register_handler(13, (size_t)isr13); + idt_register_handler(14, (size_t)isr14); + idt_register_handler(15, (size_t)isr15); + idt_register_handler(16, (size_t)isr16); + idt_register_handler(17, (size_t)isr17); + idt_register_handler(18, (size_t)isr18); +} diff --git a/cpu/exception.h b/cpu/exception.h new file mode 100644 index 0000000..12a35ff --- /dev/null +++ b/cpu/exception.h @@ -0,0 +1,6 @@ +#ifndef _EXCEPTION_H +#define _EXCEPTION_H + +void exception_handlers_init(); + +#endif \ No newline at end of file diff --git a/cpu/idt.h b/cpu/idt.h index 1aa60b4..b120d71 100644 --- a/cpu/idt.h +++ b/cpu/idt.h @@ -8,13 +8,13 @@ #define INTERRUPT_GATE 0x8e // https://wiki.osdev.org/Interrupt_Descriptor_Table -struct __attribute__((__packed__)) interrupt_descriptor_32 { +struct interrupt_descriptor_32 { uint16_t offset_1; // offset bits 0..15 uint16_t selector; // a code segment selector in GDT or LDT uint8_t zero; // unused, set to 0 uint8_t type_attributes; // gate type, dpl, and p fields uint16_t offset_2; // offset bits 16..31 -}; +} __attribute__((__packed__)); void idt_init(); void idt_register_handler(uint8_t interrupt, size_t address); diff --git a/kernel.c b/kernel.c index 8766ebb..aaebfa3 100644 --- a/kernel.c +++ b/kernel.c @@ -4,6 +4,7 @@ #include "vga.h" #include "cpu/pic.h" #include "cpu/idt.h" +#include "std/kstd.h" #if defined(__linux__) #error "You are not using a cross-compiler, you will most certainly run into trouble" @@ -13,32 +14,23 @@ #error "This OS needs to be compiled with a ix86-elf compiler" #endif -struct interrupt_frame -{ - size_t ip; - size_t cs; - size_t flags; - size_t sp; - size_t ss; -} __attribute__((packed)); - -__attribute__((interrupt)) -static void isr0(struct interrupt_frame *frame) { - terminal_writestring("division by zero"); - pic_send_eoi(0); -} - void kmain(void) { terminal_initialize(); - terminal_writestring("start"); + kprintf("kmain(): info: kernel init started\n"); + kprintf("[ ] Remapping PIC"); pic_remap(0x20, 0x28); - idt_register_handler(0, (size_t)isr0); + kprintf("\r[ OK ]\n"); + + kprintf("[ ] Installing exception handlers"); + exception_handlers_init(); + kprintf("\r[ OK ]\n"); + + kprintf("[ ] Initializing IDT"); idt_init(); + kprintf("\r[ OK ]\n"); - volatile int a = 0/0; - - terminal_writestring("Hello, kernel World!\n"); + terminal_writestring("Initialization finished.\n"); } diff --git a/std/kstd.c b/std/kstd.c new file mode 100644 index 0000000..12b5083 --- /dev/null +++ b/std/kstd.c @@ -0,0 +1,127 @@ +#include +#include +#include "std/kstd.h" +#include "std/std.h" +#include "vga.h" + +int putchar(int ic) { + char c = (char) ic; + terminal_write(&c, sizeof(c)); + return ic; +} + +static bool print(const char* data, size_t length) { + const unsigned char* bytes = (const unsigned char*) data; + for (size_t i = 0; i < length; i++) { + if (putchar(bytes[i]) == (-1)) { // EOF?? + return false; + } + } + return true; +} + +// https://wiki.osdev.org/Meaty_Skeleton +int kprintf(const char* restrict format, ...) { + va_list parameters; + va_start(parameters, format); + + int written = 0; + + while (*format != '\0') { + size_t maxrem = INT_MAX - written; + + if (format[0] != '%' || format[1] == '%') { + if (format[0] == '%') + format++; + size_t amount = 1; + while (format[amount] && format[amount] != '%') + amount++; + if (maxrem < amount) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + if (!print(format, amount)) + return -1; + format += amount; + written += amount; + continue; + } + + const char* format_begun_at = format++; + + if (*format == 'c') { + format++; + char c = (char) va_arg(parameters, int /* char promotes to int */); + if (!maxrem) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + if (!print(&c, sizeof(c))) + return -1; + written++; + } else if (*format == 's') { + format++; + const char* str = va_arg(parameters, const char*); + size_t len = strlen(str); + if (maxrem < len) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + if (!print(str, len)) + return -1; + written += len; + } else if (*format == 'd') { + format++; + int val = va_arg(parameters, int); + int base = 10; + char *str; + + // note: flawed implementation + // based on: https://www.strudel.org.uk/itoa/ + if (val == 0) { + str = "0\0"; + } else { + static char buf[32] = {0}; + int i = 30; + for(; val && i ; --i, val /= base) { + buf[i] = "0123456789abcdef"[val % base]; + } + str = &buf[i+1]; + } + + size_t len = strlen(str); + if (maxrem < len) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + print(str, len); + written += len; + } else { + format = format_begun_at; + size_t len = strlen(format); + if (maxrem < len) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + if (!print(format, len)) + return -1; + written += len; + format += len; + } + } + + va_end(parameters); + return written; +} + +void kputs(const char* data) { + kprintf("%s\n", data); +} + +void kabort() { + kprintf("kabort(): halting kernel...\n"); + asm volatile("cli"); + asm volatile("hlt"); + while (1) {} + __builtin_unreachable(); +} diff --git a/std/kstd.h b/std/kstd.h new file mode 100644 index 0000000..a5d9911 --- /dev/null +++ b/std/kstd.h @@ -0,0 +1,11 @@ +#ifndef _KSTD_H +#define _KSTD_H + +#include + +int putchar(int ic); +int kprintf(const char* restrict format, ...); +void kputs(const char* data); +void kabort(); + +#endif \ No newline at end of file diff --git a/std/std.c b/std/std.c index 6600c13..9b54fb7 100644 --- a/std/std.c +++ b/std/std.c @@ -40,4 +40,3 @@ void* memcpy(void *destv, void *srcv, size_t size) { return destv; } - diff --git a/vga.c b/vga.c index 335be5b..05148bd 100644 --- a/vga.c +++ b/vga.c @@ -29,11 +29,21 @@ void terminal_putentryat(char c, uint8_t color, size_t x, size_t y) { } void terminal_putchar(char c) { - terminal_putentryat(c, terminal_color, terminal_column, terminal_row); - if (++terminal_column == VGA_WIDTH) { - terminal_column = 0; - if (++terminal_row == VGA_HEIGHT) - terminal_row = 0; + switch (c) { + case '\r': + terminal_column = 0; + break; + case '\n': + terminal_column = 0; + terminal_row++; + break; + default: + terminal_putentryat(c, terminal_color, terminal_column, terminal_row); + if (++terminal_column == VGA_WIDTH) { + terminal_column = 0; + if (++terminal_row == VGA_HEIGHT) + terminal_row = 0; + } } }