better exception handling + bad kprintf
This commit is contained in:
parent
b654976ebb
commit
065dbf5177
9 changed files with 305 additions and 30 deletions
4
Makefile
4
Makefile
|
@ -8,7 +8,7 @@ CC=i686-elf-gcc
|
||||||
bootstrap.o: bootstrap.s
|
bootstrap.o: bootstrap.s
|
||||||
i686-elf-as bootstrap.s -o bootstrap.o
|
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 $^
|
$(CC) -T linker.ld -o $@ -ffreestanding -O2 -nostdlib -lgcc $^
|
||||||
|
|
||||||
iso: kernel.bin
|
iso: kernel.bin
|
||||||
|
@ -18,7 +18,7 @@ iso: kernel.bin
|
||||||
grub-mkrescue -o generated-iso.iso isodir
|
grub-mkrescue -o generated-iso.iso isodir
|
||||||
|
|
||||||
run: iso
|
run: iso
|
||||||
qemu-system-i386 -cdrom generated-iso.iso
|
qemu-system-i386 -d int -M smm=off -cdrom generated-iso.iso
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf *.o kernel.bin *.iso isodir/
|
rm -rf *.o kernel.bin *.iso isodir/
|
||||||
|
|
130
cpu/exception.c
Normal file
130
cpu/exception.c
Normal 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
6
cpu/exception.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef _EXCEPTION_H
|
||||||
|
#define _EXCEPTION_H
|
||||||
|
|
||||||
|
void exception_handlers_init();
|
||||||
|
|
||||||
|
#endif
|
|
@ -8,13 +8,13 @@
|
||||||
#define INTERRUPT_GATE 0x8e
|
#define INTERRUPT_GATE 0x8e
|
||||||
|
|
||||||
// https://wiki.osdev.org/Interrupt_Descriptor_Table
|
// 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 offset_1; // offset bits 0..15
|
||||||
uint16_t selector; // a code segment selector in GDT or LDT
|
uint16_t selector; // a code segment selector in GDT or LDT
|
||||||
uint8_t zero; // unused, set to 0
|
uint8_t zero; // unused, set to 0
|
||||||
uint8_t type_attributes; // gate type, dpl, and p fields
|
uint8_t type_attributes; // gate type, dpl, and p fields
|
||||||
uint16_t offset_2; // offset bits 16..31
|
uint16_t offset_2; // offset bits 16..31
|
||||||
};
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
void idt_init();
|
void idt_init();
|
||||||
void idt_register_handler(uint8_t interrupt, size_t address);
|
void idt_register_handler(uint8_t interrupt, size_t address);
|
||||||
|
|
32
kernel.c
32
kernel.c
|
@ -4,6 +4,7 @@
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
#include "cpu/pic.h"
|
#include "cpu/pic.h"
|
||||||
#include "cpu/idt.h"
|
#include "cpu/idt.h"
|
||||||
|
#include "std/kstd.h"
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#error "You are not using a cross-compiler, you will most certainly run into trouble"
|
#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"
|
#error "This OS needs to be compiled with a ix86-elf compiler"
|
||||||
#endif
|
#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) {
|
void kmain(void) {
|
||||||
terminal_initialize();
|
terminal_initialize();
|
||||||
|
|
||||||
terminal_writestring("start");
|
kprintf("kmain(): info: kernel init started\n");
|
||||||
|
|
||||||
|
kprintf("[ ] Remapping PIC");
|
||||||
pic_remap(0x20, 0x28);
|
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();
|
idt_init();
|
||||||
|
kprintf("\r[ OK ]\n");
|
||||||
|
|
||||||
volatile int a = 0/0;
|
terminal_writestring("Initialization finished.\n");
|
||||||
|
|
||||||
terminal_writestring("Hello, kernel World!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
127
std/kstd.c
Normal file
127
std/kstd.c
Normal 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
11
std/kstd.h
Normal 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
|
|
@ -40,4 +40,3 @@ void* memcpy(void *destv, void *srcv, size_t size) {
|
||||||
|
|
||||||
return destv;
|
return destv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
vga.c
20
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) {
|
void terminal_putchar(char c) {
|
||||||
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
|
switch (c) {
|
||||||
if (++terminal_column == VGA_WIDTH) {
|
case '\r':
|
||||||
terminal_column = 0;
|
terminal_column = 0;
|
||||||
if (++terminal_row == VGA_HEIGHT)
|
break;
|
||||||
terminal_row = 0;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue