aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraqua <aqua@iserlohn-fortress.net>2022-04-01 11:38:00 +0300
committeraqua <aqua@iserlohn-fortress.net>2022-08-12 10:13:59 +0300
commita6c1174b3fb598cd59c1668cfc4d4746ab688079 (patch)
tree85e2c3e37ef0c9602c56873332b98311e655e6e5
parentInitial commit (diff)
downloadkernel-a6c1174b3fb598cd59c1668cfc4d4746ab688079.tar.xz
lidt
-rw-r--r--arch/i686/include/gdt.h5
-rw-r--r--arch/i686/include/idt.h18
-rw-r--r--arch/i686/include/sys/control.h9
-rw-r--r--arch/i686/lgdt.c8
-rw-r--r--arch/i686/lidt.c46
-rw-r--r--arch/i686/meson.build7
-rw-r--r--devices/meson.build2
-rw-r--r--devices/pic.h4
-rw-r--r--devices/pic_8259.c39
-rw-r--r--meson.build2
-rw-r--r--src/isr.c35
-rw-r--r--src/kernel.c7
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)
;
}