diff options
-rw-r--r-- | arch/i686/include/gdt.h | 5 | ||||
-rw-r--r-- | arch/i686/include/idt.h | 18 | ||||
-rw-r--r-- | arch/i686/include/sys/control.h | 9 | ||||
-rw-r--r-- | arch/i686/lgdt.c | 8 | ||||
-rw-r--r-- | arch/i686/lidt.c | 46 | ||||
-rw-r--r-- | arch/i686/meson.build | 7 | ||||
-rw-r--r-- | devices/meson.build | 2 | ||||
-rw-r--r-- | devices/pic.h | 4 | ||||
-rw-r--r-- | devices/pic_8259.c | 39 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | src/isr.c | 35 | ||||
-rw-r--r-- | src/kernel.c | 7 |
12 files changed, 171 insertions, 11 deletions
diff --git a/arch/i686/include/gdt.h b/arch/i686/include/gdt.h index 6badf84..9148c3d 100644 --- a/arch/i686/include/gdt.h +++ b/arch/i686/include/gdt.h @@ -47,11 +47,6 @@ _Static_assert(sizeof(struct SegmentDescriptor_t) == 8); void SegmentDescriptor(struct SegmentDescriptor_t *self, unsigned base, unsigned limit, uint8_t access); -struct __attribute__((packed)) Pointer { - uint16_t limit; - uint32_t base; -}; - void gdt_install(); enum SegmentIndex { diff --git a/arch/i686/include/idt.h b/arch/i686/include/idt.h new file mode 100644 index 0000000..22dc6de --- /dev/null +++ b/arch/i686/include/idt.h @@ -0,0 +1,18 @@ +#pragma once + +#include <stdint.h> + +struct interrupt_frame { + uint32_t ip; + uint32_t cs; + uint32_t flags; + uint32_t sp; + uint32_t ss; +}; + +void abort_handler(struct interrupt_frame *frame); +void interrupt_handler(struct interrupt_frame *frame); +void interrupt_handler_e(struct interrupt_frame *frame, uint32_t error); +void syscall_handler(struct interrupt_frame *frame); + +void idt_install(); diff --git a/arch/i686/include/sys/control.h b/arch/i686/include/sys/control.h new file mode 100644 index 0000000..a40a67f --- /dev/null +++ b/arch/i686/include/sys/control.h @@ -0,0 +1,9 @@ +#pragma once + +static void +abort() +{ + asm volatile(R"(cli +h: hlt +jmp h)"); +} diff --git a/arch/i686/lgdt.c b/arch/i686/lgdt.c index 2d35e8d..2be5d30 100644 --- a/arch/i686/lgdt.c +++ b/arch/i686/lgdt.c @@ -1,5 +1,10 @@ #include <gdt.h> +struct __attribute__((packed)) Pointer { + uint16_t limit; + uint32_t base; +}; + static struct SegmentDescriptor_t segments[8] __attribute__((aligned(32))); void @@ -9,8 +14,7 @@ gdt_install() SegmentDescriptor(&segments[2], 0, 0xffffffff, 0x9a); // ktext SegmentDescriptor(&segments[3], 0, 0xffffffff, 0x92); // kdata - struct Pointer ptr = {.limit = sizeof(segments) - 1, .base = (unsigned)&segments}; - + const struct Pointer ptr = {.limit = sizeof(segments) - 1, .base = (unsigned)&segments}; asm volatile("lgdt (%0)" : : "a"(&ptr)); // load the kernel data segment diff --git a/arch/i686/lidt.c b/arch/i686/lidt.c new file mode 100644 index 0000000..efbade3 --- /dev/null +++ b/arch/i686/lidt.c @@ -0,0 +1,46 @@ +#include <idt.h> +#include <stdint.h> + +struct __attribute__((packed)) Pointer { + uint16_t limit; + uint32_t base; +}; + +enum Type { + Null = 0, + Intr = 0b10001110, // 32-bit interrupt +}; + +struct __attribute__((packed)) Gate_t { + uint16_t offset_15_0; // segment offset low + uint16_t selector; // code segment selector + uint8_t __unused; // unused in protected mode + uint8_t type; // interrupt type + uint16_t offset_31_16; // segment offset high +}; +_Static_assert(sizeof(struct Gate_t) == 8); + +void +Gate(struct Gate_t *entry, void *f, uint16_t selector) +{ + uint32_t f_addr = (uint32_t)f; + entry->offset_15_0 = f_addr & 0xffff; + entry->offset_31_16 = (f_addr >> 16) & 0xffff; + entry->selector = selector; + entry->__unused = 0; + entry->type = Intr; +} + +static struct Gate_t interrupt_table[256] __attribute((aligned(4096))); + +void +idt_install() +{ + for (int i = 0; i <= 0x2f; ++i) Gate(&interrupt_table[i], &interrupt_handler, 0x10); + Gate(&interrupt_table[0x80], &abort_handler, 0x10); + + const struct Pointer ptr = {.limit = sizeof(interrupt_table) - 1, .base = (unsigned)&interrupt_table}; + asm volatile("lidt (%0)" : : "a"(&ptr)); + + asm volatile("sti"); +} diff --git a/arch/i686/meson.build b/arch/i686/meson.build index 25eebee..f6bed8e 100644 --- a/arch/i686/meson.build +++ b/arch/i686/meson.build @@ -1,6 +1,9 @@ arch = declare_dependency( - sources: ['boot.S', 'init.s', 'gdt.c', 'lgdt.c'], - include_directories: 'include' + sources: ['boot.S', 'init.s', + 'gdt.c', 'lgdt.c', 'lidt.c' + ], + include_directories: 'include', + compile_args: '-mgeneral-regs-only' ) test('GDT', executable('gdt', ['test/gdt.c', 'gdt.c'], include_directories: 'include', native: true)) diff --git a/devices/meson.build b/devices/meson.build index c52c389..de0230d 100644 --- a/devices/meson.build +++ b/devices/meson.build @@ -1,5 +1,5 @@ devices = declare_dependency( - sources: ['vga.c', 'uart_16550.c'], + sources: ['vga.c', 'uart_16550.c', 'pic_8259.c'], include_directories: '.' ) diff --git a/devices/pic.h b/devices/pic.h new file mode 100644 index 0000000..685a85b --- /dev/null +++ b/devices/pic.h @@ -0,0 +1,4 @@ +#pragma once + +void pic_init(); +void pic_clear(unsigned char irq); diff --git a/devices/pic_8259.c b/devices/pic_8259.c new file mode 100644 index 0000000..43b090f --- /dev/null +++ b/devices/pic_8259.c @@ -0,0 +1,39 @@ +#include "pic.h" +#include <sys/io.h> + +#define PIC1 0x20 +#define PIC2 0xa0 +#define DATA 1 + +// initialization +#define ICW1_INIT 0x10 +// TODO +#define ICW1_ICW4 0x01 +// 8086/88 mode +#define ICW4_8086 0x01 + +void +pic_init() +{ + outb(ICW1_INIT | ICW1_ICW4, PIC1); + outb(ICW1_INIT | ICW1_ICW4, PIC2); + + outb(0x20, PIC1 + DATA); // offset 0x20 + outb(0x28, PIC2 + DATA); // offset 0x28 + + outb(0x04, PIC1 + DATA); // tell master pic there is a slave pic + outb(0x02, PIC2 + DATA); // tell slave pic its cascade identity + + outb(ICW4_8086, PIC1 + DATA); + outb(ICW4_8086, PIC2 + DATA); + + // PIC masks + outb(0xff, PIC1 + DATA); + outb(0xff, PIC2 + DATA); +} + +void +pic_clear(unsigned char irq) +{ + outb(0x20, PIC1); +} diff --git a/meson.build b/meson.build index e5c8410..d0f6819 100644 --- a/meson.build +++ b/meson.build @@ -6,7 +6,7 @@ subdir('devices') kernel = executable('glitch.elf', ['src/multiboot2.c', 'src/mmap.c', 'src/kernel.c', - 'src/mem/vmm.c', + 'src/isr.c', 'src/mem/vmm.c', 'lib/string/itoa.c', 'lib/stdio/printf.c'], link_language: 'c', link_args: ['-ffreestanding', '-nostdlib', '-static', '-T', meson.current_source_dir()/'arch/i686/linker.ld'], diff --git a/src/isr.c b/src/isr.c new file mode 100644 index 0000000..c94d37e --- /dev/null +++ b/src/isr.c @@ -0,0 +1,35 @@ +/* + * Interrupt Service Routines + */ + +#include <idt.h> +#include <stdio.h> +#include <sys/control.h> + +__attribute__((interrupt)) void +abort_handler(struct interrupt_frame *frame) +{ + printf("abort\n"); + abort(); +} + +__attribute__((interrupt)) void +interrupt_handler(struct interrupt_frame *frame) +{ + printf("interrupt\n"); + abort(); +} + +__attribute__((interrupt)) void +interrupt_handler_e(struct interrupt_frame *frame, uint32_t error) +{ + printf("interrupt\n"); + abort(); +} + +__attribute__((interrupt)) void +syscall_handler(struct interrupt_frame *frame) +{ + printf("interrupt\n"); + abort(); +} diff --git a/src/kernel.c b/src/kernel.c index b84d7ee..f7f9d6d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,13 +1,18 @@ #include "mem.h" #include <gdt.h> +#include <idt.h> #include <stdio.h> +#include "devices/pic.h" #include "devices/uart_16550.h" #include "devices/vga.h" void kmain() { + pic_init(); + gdt_install(); + idt_install(); if (uart_init(COM1) != 0) printf("UART self-test failed.\r\n"); @@ -19,6 +24,8 @@ void kmain() { char *c = (char *)0xc0700000; if (*c == 0) printf("c is 0\r\n"); + asm volatile("int $0x80"); + while (1) ; } |