summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Mikkelsen <petermikkelsen10@gmail.com>2025-07-27 15:33:22 +0200
committerPeter Mikkelsen <petermikkelsen10@gmail.com>2025-07-27 15:33:22 +0200
commitefb1cf0895d6c5019f5a88fa14b59afd030fefca (patch)
tree24fe5d99faad9eeed625d0ef1a6edea65482e246
parentb5a24778844f41e38168d97761d72cf0d5b400b3 (diff)
Setup descriptor tables, and enable interrupts
-rw-r--r--Makefile3
-rw-r--r--src/aplos.h16
-rw-r--r--src/boot.c1
-rw-r--r--src/descriptors.c148
-rw-r--r--src/interrupt.c41
-rw-r--r--src/main.c5
-rw-r--r--src/nasty.S85
-rw-r--r--src/panic.c8
-rw-r--r--src/screen.c13
-rw-r--r--src/util.c34
10 files changed, 352 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 7f7c970..c90629e 100644
--- a/Makefile
+++ b/Makefile
@@ -21,10 +21,13 @@ LDFLAGS = \
OFILES = \
src/boot.o \
+ src/descriptors.o \
src/error.o \
src/font.o \
+ src/interrupt.o \
src/main.o \
src/nasty.o \
+ src/panic.o \
src/screen.o \
src/utf8.o \
src/util.o
diff --git a/src/aplos.h b/src/aplos.h
index a64e7cc..e364eea 100644
--- a/src/aplos.h
+++ b/src/aplos.h
@@ -29,6 +29,9 @@ struct boot_info
/* boot.c */
uint64_t cpu_count(void);
+/* descriptors */
+void setup_descriptors(void);
+
/* error.c */
void assert(bool);
@@ -40,7 +43,16 @@ void font_draw(char8_t *, uint32_t, uint32_t, uint32_t, uint32_t);
void main(struct boot_info *);
/* nasty.S */
+struct table_reg;
void halt(void);
+void disable_interrupts(void);
+void enable_interrupts(void);
+void set_gdt(struct table_reg *, uint64_t, uint64_t, uint64_t);
+void set_idt(struct table_reg *);
+extern void (*isr_stubs[32])(void);
+
+/* panic.c */
+void panic(void);
/* screen.c */
void screen_init(struct framebuffer *);
@@ -56,4 +68,8 @@ uint32_t utf8_value(const char8_t *);
uint16_t read_uint16_le(const uint8_t *);
uint16_t read_uint16_be(const uint8_t *);
uint32_t read_uint32_le(const uint8_t *);
+void write_uint16_le(uint8_t *, uint16_t);
+void write_uint32_le(uint8_t *, uint32_t);
+void write_uint64_le(uint8_t *, uint64_t);
int memcmp(const void *, const void *, size_t);
+void memset(void *, uint8_t, size_t);
diff --git a/src/boot.c b/src/boot.c
index f3afb5e..c2d4a22 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -86,4 +86,5 @@ bootmain(void)
info.memmaps = memmaps;
main(&info);
+ halt();
}
diff --git a/src/descriptors.c b/src/descriptors.c
new file mode 100644
index 0000000..82b8709
--- /dev/null
+++ b/src/descriptors.c
@@ -0,0 +1,148 @@
+#include "aplos.h"
+
+#define DESCRIPTOR_SIZE 8
+#define IDT_ENTRIES 256
+
+enum {
+ GDT_START,
+ NULL_SEGMENT = GDT_START,
+ KERNEL_CODE_SEGMENT,
+ KERNEL_DATA_SEGMENT,
+ TASK_STATE_SEGMENT,
+ TASK_STATE_SEGMENT_CONT,
+ GDT_END = TASK_STATE_SEGMENT_CONT,
+
+ IDT_START,
+ IDT_END = IDT_START + (2*IDT_ENTRIES) - 1,
+
+ TOTAL_ENTRY_COUNT
+};
+
+enum {
+ TYPE_NULL_SEGMENT = 0x10,
+ TYPE_DATA_SEGMENT = 0x12,
+ TYPE_CODE_SEGMENT = 0x18,
+ TYPE_TSS_SEGMENT = 0x09,
+ TYPE_IDT = 0x0E,
+
+ USER_TYPE_MASK = 0x10
+};
+
+struct descriptor
+{
+ int type;
+
+ /* TASK_STATE_SEGMENT */
+ struct encoded_tss_entry *tss;
+
+ /* IDT */
+ void (*isr)(void);
+};
+
+struct encoded_descriptor
+{
+ alignas(DESCRIPTOR_SIZE) uint8_t data[DESCRIPTOR_SIZE];
+};
+static_assert(sizeof(struct encoded_descriptor) == DESCRIPTOR_SIZE);
+
+struct encoded_tss_entry
+{
+ uint8_t data[104]; /* Not part of this is used yet... */
+};
+
+struct table_reg
+{
+ uint8_t data[10];
+};
+static_assert(sizeof(struct table_reg) == 10);
+
+static struct encoded_tss_entry tss;
+
+static struct descriptor entries[TOTAL_ENTRY_COUNT] = {
+ [NULL_SEGMENT] = {
+ .type = TYPE_NULL_SEGMENT
+ },
+ [KERNEL_CODE_SEGMENT] = {
+ .type = TYPE_CODE_SEGMENT
+ },
+ [KERNEL_DATA_SEGMENT] = {
+ .type = TYPE_DATA_SEGMENT
+ },
+ [TASK_STATE_SEGMENT] = {
+ .type = TYPE_TSS_SEGMENT,
+ .tss = &tss,
+ },
+};
+
+static struct encoded_descriptor encoded[nelem(entries)];
+
+static void encode_descriptors(struct table_reg *, uint64_t, uint64_t);
+static void encode_descriptor(struct descriptor *, struct encoded_descriptor *);
+
+void
+setup_descriptors(void)
+{
+ struct table_reg reg;
+
+ disable_interrupts();
+ encode_descriptors(&reg, GDT_START, GDT_END);
+ set_gdt(&reg, DESCRIPTOR_SIZE*KERNEL_CODE_SEGMENT, DESCRIPTOR_SIZE*KERNEL_DATA_SEGMENT, DESCRIPTOR_SIZE*TASK_STATE_SEGMENT);
+
+ for(uint64_t i = IDT_START; i < IDT_END; i += 2)
+ entries[i].type = TYPE_IDT;
+ for(uint64_t i = 0; i < nelem(isr_stubs); i++)
+ entries[IDT_START+i*2].isr = isr_stubs[i];
+
+ encode_descriptors(&reg, IDT_START, IDT_END);
+ set_idt(&reg);
+
+ enable_interrupts();
+}
+
+static void
+encode_descriptors(struct table_reg *reg, uint64_t start, uint64_t end)
+{
+ uint64_t count = 1 + end - start;
+ struct descriptor *d = entries + start;
+ struct encoded_descriptor *e = encoded + start;
+
+
+ memset(e, 0, sizeof(*e) * count);
+ for(uint64_t i = 0; i < count; i++){
+ encode_descriptor(d+i, e+i);
+ if(!(d[i].type & USER_TYPE_MASK))
+ i++; /* System types are twice as big */
+ }
+
+ write_uint16_le(reg->data, count*DESCRIPTOR_SIZE - 1);
+ write_uint64_le(reg->data+2, (uint64_t)e);
+}
+
+static void
+encode_descriptor(struct descriptor *d, struct encoded_descriptor *e)
+{
+ e->data[5] |= d->type&0x1F; /* Type */
+ e->data[5] |= 1<<7; /* Present */
+ e->data[6] |= 1<<5; /* Long mode */
+
+ uint64_t v;
+
+ switch(d->type){
+ case TYPE_TSS_SEGMENT:
+ write_uint16_le(e->data, sizeof(*d->tss));
+
+ v = (uint64_t)d->tss;
+ write_uint16_le(e->data+2, v & 0xFFFF);
+ e->data[4] = (v >> 16) & 0xFF;
+ e->data[7] = (v >> 24) & 0xFF;
+ write_uint32_le((uint8_t *)(e+1), (v >> 32) & 0xFFFFFFFF);
+ break;
+ case TYPE_IDT:
+ v = (uint64_t)d->isr;
+ write_uint16_le(e->data, v & 0xFFFF);
+ write_uint16_le(e->data+6, (v >> 16) & 0xFFFF);
+ write_uint32_le(e->data+8, (v >> 32) & 0xFFFFFFFF);
+
+ write_uint16_le(e->data+2, DESCRIPTOR_SIZE*KERNEL_CODE_SEGMENT);
+ }
+}
diff --git a/src/interrupt.c b/src/interrupt.c
new file mode 100644
index 0000000..97bc921
--- /dev/null
+++ b/src/interrupt.c
@@ -0,0 +1,41 @@
+#include "aplos.h"
+
+static char8_t *descriptions[256] = {
+ [0] = u8"divide-by-zero-error",
+ [1] = u8"debug",
+ [2] = u8"non-maskable-interrupt",
+ [3] = u8"breakpoint",
+ [4] = u8"overflow",
+ [5] = u8"bound-range",
+ [6] = u8"invalid-opcode",
+ [7] = u8"device-not-available",
+ [8] = u8"double-fault",
+ [9] = u8"coprocessor-segment-overrun",
+ [10] = u8"invalid-tss",
+ [11] = u8"segment-not-present",
+ [12] = u8"stack",
+ [13] = u8"general-protection",
+ [14] = u8"page-fault",
+ [16] = u8"x87 floating-point exception-pending",
+ [17] = u8"alignment-check",
+ [18] = u8"machine-check",
+ [19] = u8"simd floating-point",
+ [21] = u8"control protection",
+ [28] = u8"hypervisor injection exception",
+ [29] = u8"vmm communication exception",
+ [30] = u8"security exception",
+};
+
+void
+interrupt_handler(uint8_t n)
+{
+ char8_t *desc = descriptions[n];
+
+ print(u8"Got interrupt: %u8", n);
+ if(desc)
+ print(u8" (%s)", desc);
+ print(u8"\n");
+ panic();
+}
+
+
diff --git a/src/main.c b/src/main.c
index 4721735..a0c0ebc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -7,12 +7,15 @@ static void print_size(uint64_t);
void
main(struct boot_info *info)
{
+ setup_descriptors();
screen_init(&info->framebuffer);
welcome();
print(u8"CPU count: %u64\n", cpu_count());
print_memmap(info);
- halt();
+ /* Uncomment lines below to trigger a page fault (to see if the interrupts are setup correctly) */
+// uint64_t *silly = (uint64_t *)0x1234;
+// print(u8"Fun: %u64\n", *silly);
}
static void
diff --git a/src/nasty.S b/src/nasty.S
index 26732a3..3f1c569 100644
--- a/src/nasty.S
+++ b/src/nasty.S
@@ -1,7 +1,90 @@
.intel_syntax noprefix
-
.section .text
+
.global halt
halt:
1: hlt
jmp 1b
+
+
+.global set_gdt
+set_gdt:
+ lgdt [rdi]
+ push rsi
+ lea rax, 1f
+ push rax
+ retfq
+1: mov ds, rdx
+ mov es, rdx
+ mov fs, rdx
+ mov gs, rdx
+ mov ss, rdx
+ ltr rcx
+ ret
+
+.global set_idt
+set_idt:
+ lidt [rdi]
+ ret
+
+.global disable_interrupts
+disable_interrupts:
+ cli
+ ret
+
+.global enable_interrupts
+enable_interrupts:
+ sti
+ ret
+
+#define DEFINE_ISRS \
+ ISR(0) \
+ ISR(1) \
+ ISR(2) \
+ ISR(3) \
+ ISR(4) \
+ ISR(5) \
+ ISR(6) \
+ ISR(7) \
+ ISR(8) \
+ ISR(9) \
+ ISR(10) \
+ ISR(11) \
+ ISR(12) \
+ ISR(13) \
+ ISR(14) \
+ ISR(15) \
+ ISR(16) \
+ ISR(17) \
+ ISR(18) \
+ ISR(19) \
+ ISR(20) \
+ ISR(21) \
+ ISR(22) \
+ ISR(23) \
+ ISR(24) \
+ ISR(25) \
+ ISR(26) \
+ ISR(27) \
+ ISR(28) \
+ ISR(29) \
+ ISR(30) \
+ ISR(31)
+
+.extern interrupt_handler
+#define ISR(n) \
+isr_stub_##n: \
+ mov rdi, n; \
+ call interrupt_handler; \
+ iretq;
+DEFINE_ISRS
+#undef ISR
+
+#define ISR(n) \
+ .quad isr_stub_##n;
+
+.section .data
+.global isr_stubs
+isr_stubs:
+DEFINE_ISRS
+#undef ISR
diff --git a/src/panic.c b/src/panic.c
new file mode 100644
index 0000000..5b17b04
--- /dev/null
+++ b/src/panic.c
@@ -0,0 +1,8 @@
+#include "aplos.h"
+
+void
+panic(void)
+{
+ print(u8"--- PANIC ---\n");
+ halt();
+}
diff --git a/src/screen.c b/src/screen.c
index 1ce4192..903ce9c 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -28,6 +28,8 @@ screen_draw_pixel(uint32_t x, uint32_t y, uint32_t c)
fb_mem[x + y * (fb->pitch/4)] = c;
}
+static int nested;
+
void
print(char8_t *fmt, ...)
{
@@ -71,6 +73,9 @@ screen_clear(void)
static int
print_fmt(char8_t *fmt, va_list args)
{
+ if(nested)
+ return 0;
+
char8_t digits[] = u8"0123456789ABCDEF";
char8_t *prefixes[17] = {0};
char8_t buf[65];
@@ -112,5 +117,13 @@ print_fmt(char8_t *fmt, va_list args)
UINT(u8"%p", 0, 16, 16, uintptr_t);
+ if(utf8_cmp_n(fmt, u8"%s", 2) == 0){
+ char8_t *str = va_arg(args, char8_t *);
+ nested++;
+ print(str);
+ nested--;
+ return 2;
+ }
+
return 0;
}
diff --git a/src/util.c b/src/util.c
index e77f65b..96cbe11 100644
--- a/src/util.c
+++ b/src/util.c
@@ -18,6 +18,32 @@ read_uint32_le(const uint8_t *p)
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
+void write_uint16_le(uint8_t *p, uint16_t v)
+{
+ p[0] = v & 0xFF;
+ p[1] = (v >> 8) & 0xFF;
+}
+
+void write_uint32_le(uint8_t *p, uint32_t v)
+{
+ p[0] = v & 0xFF;
+ p[1] = (v >> 8) & 0xFF;
+ p[2] = (v >> 16) & 0xFF;
+ p[3] = (v >> 24) & 0xFF;
+}
+
+void write_uint64_le(uint8_t *p, uint64_t v)
+{
+ p[0] = v & 0xFF;
+ p[1] = (v >> 8) & 0xFF;
+ p[2] = (v >> 16) & 0xFF;
+ p[3] = (v >> 24) & 0xFF;
+ p[4] = (v >> 32) & 0xFF;
+ p[5] = (v >> 40) & 0xFF;
+ p[6] = (v >> 48) & 0xFF;
+ p[7] = (v >> 56) & 0xFF;
+}
+
int
memcmp(const void *p1, const void *p2, size_t n)
{
@@ -31,3 +57,11 @@ memcmp(const void *p1, const void *p2, size_t n)
}
return 0;
}
+
+void
+memset(void *v, uint8_t b, size_t n)
+{
+ uint8_t *p = v;
+ for(size_t i = 0; i < n; i++)
+ p[i] = b;
+}