better exception handling + bad kprintf

This commit is contained in:
hippoz 2022-02-24 18:11:09 +02:00
parent b654976ebb
commit 065dbf5177
Signed by: hippoz
GPG key ID: 7C52899193467641
9 changed files with 305 additions and 30 deletions

View file

@ -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/

130
cpu/exception.c Normal file
View file

@ -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);
}

6
cpu/exception.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef _EXCEPTION_H
#define _EXCEPTION_H
void exception_handlers_init();
#endif

View file

@ -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);

View file

@ -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");
}

127
std/kstd.c Normal file
View file

@ -0,0 +1,127 @@
#include <stdarg.h>
#include <limits.h>
#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();
}

11
std/kstd.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef _KSTD_H
#define _KSTD_H
#include <stdbool.h>
int putchar(int ic);
int kprintf(const char* restrict format, ...);
void kputs(const char* data);
void kabort();
#endif

View file

@ -40,4 +40,3 @@ void* memcpy(void *destv, void *srcv, size_t size) {
return destv;
}

20
vga.c
View file

@ -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;
}
}
}