diff options
author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-27 15:33:22 +0200 |
---|---|---|
committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-27 15:33:22 +0200 |
commit | efb1cf0895d6c5019f5a88fa14b59afd030fefca (patch) | |
tree | 24fe5d99faad9eeed625d0ef1a6edea65482e246 | |
parent | b5a24778844f41e38168d97761d72cf0d5b400b3 (diff) |
Setup descriptor tables, and enable interrupts
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | src/aplos.h | 16 | ||||
-rw-r--r-- | src/boot.c | 1 | ||||
-rw-r--r-- | src/descriptors.c | 148 | ||||
-rw-r--r-- | src/interrupt.c | 41 | ||||
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/nasty.S | 85 | ||||
-rw-r--r-- | src/panic.c | 8 | ||||
-rw-r--r-- | src/screen.c | 13 | ||||
-rw-r--r-- | src/util.c | 34 |
10 files changed, 352 insertions, 2 deletions
@@ -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); @@ -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(®, GDT_START, GDT_END); + set_gdt(®, 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(®, IDT_START, IDT_END); + set_idt(®); + + 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(); +} + + @@ -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; } @@ -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; +} |