From 174cf436480efe690f72d64c9ecd16b7af4d1f0e Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 25 Jun 2021 12:30:07 +0200 Subject: setting up the GDT --- .gdbinit | 2 + Makefile | 10 ++++- kernel/gdt.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/gdt.h | 3 ++ kernel/main.c | 5 ++- kernel/tty.c | 6 +++ kernel/tty.h | 1 + platform/boot.s | 2 + 8 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 .gdbinit create mode 100644 kernel/gdt.c create mode 100644 kernel/gdt.h diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..4455986 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,2 @@ +file kernel.bin +target remote localhost:1234 diff --git a/Makefile b/Makefile index 593ead0..a1f9899 100644 --- a/Makefile +++ b/Makefile @@ -3,14 +3,20 @@ CC = i686-elf-gcc CFLAGS = -std=gnu99 -ffreestanding -O2 -Wall -Wextra CFLAGS += -I. LFLAGS = -ffreestanding -O2 -nostdlib -lgcc +QFLAGS = -no-reboot -d guest_errors OBJ = platform/boot.o OBJ += $(patsubst %.c,%.o,$(wildcard kernel/*.c)) -.PHONY: boot clean +.PHONY: boot debug clean boot: kernel.bin - qemu-system-i386 -kernel kernel.bin + qemu-system-i386 -kernel kernel.bin $(QFLAGS) -no-shutdown + +debug: kernel.bin + qemu-system-i386 -kernel kernel.bin $(QFLAGS) -s -S & + sleep 1 + gdb clean: rm -vf kernel.bin diff --git a/kernel/gdt.c b/kernel/gdt.c new file mode 100644 index 0000000..1ee2042 --- /dev/null +++ b/kernel/gdt.c @@ -0,0 +1,127 @@ +#include +#include + +extern void stack_top; // platform/boot.s + +struct gdt_entry { + uint64_t limit_low : 16; + uint64_t base_low : 24; + uint64_t accessed : 1; // set by the processor + // CODE | DATA + uint64_t rw : 1; // readable? | writeable? + uint64_t conforming : 1; // conforming? | expands down? + uint64_t code : 1; // 1 | 0 + + uint64_t codeordata : 1; // 1 for everything other than TSS and LDT + uint64_t ring : 2; + uint64_t present : 1; // always 1 + uint64_t limit_high : 4; + uint64_t available : 1; // ??? + uint64_t long_mode : 1; + uint64_t x32 : 1; + uint64_t gran : 1; // 1 - 4kb, 0 - 1b + uint64_t base_high : 8; +} __attribute__((packed)); + +struct tss_entry { + uint32_t prev_tss; // unused + uint32_t esp0; // kernel mode stack pointer + uint32_t ss0; // kernel mode stack segment + // total size = 0x68 (?) - 3 * sizeof(uint32_t) = 5c + uint8_t _unused[0x5c]; +} __attribute__((packed)); + +struct lgdt_arg { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +enum { + SEG_null, + SEG_r0data, + SEG_r0code, + SEG_r3data, + SEG_r3code, + SEG_TSS, + + SEG_end +}; +static struct gdt_entry GDT[6]; +static struct tss_entry TSS; +static struct lgdt_arg lgdt_arg; // probably doesn't need to be global + +static void gdt_prepare(); +static void gdt_load(); + + +static void gdt_prepare() { + // null segment + GDT[0].present = 0; + + // ring0 data + GDT[1].limit_low = 0xFFFF; + GDT[1].limit_high = 0xF; + GDT[1].gran = 1; // 4KB * 0xFFFFF = (almost) 4GB + + GDT[1].base_low = 0; + GDT[1].base_high = 0; + GDT[1].accessed = 0; + GDT[1].rw = 1; + GDT[1].conforming = 0; + GDT[1].code = 0; + GDT[1].codeordata = 1; + GDT[1].ring = 0; + GDT[1].present = 1; + GDT[1].long_mode = 0; // ??? + GDT[1].available = 1; // ??? + GDT[1].x32 = 1; + + // copy to r0 code + GDT[2] = GDT[1]; + GDT[2].code = 1; + + // r3 data & code + GDT[3] = GDT[1]; + GDT[3].ring = 3; + GDT[4] = GDT[2]; + GDT[3].ring = 3; + + { // tss + // TODO memset(&TSS, 0, sizeof(TSS)); + TSS.ss0 = 1 << 3; // kernel data segment + TSS.esp0 = (uint32_t) &stack_top; + + GDT[5].limit_low = sizeof(TSS); + GDT[5].base_low = (uint32_t) &TSS; + GDT[5].accessed = 1; // 0 for TSS + GDT[5].rw = 0; // 1 busy / 0 not busy + GDT[5].conforming = 0; // 0 for TSS + GDT[5].code = 1; // 32bit + GDT[5].codeordata = 0; // is a system entry + GDT[5].ring = 3; + GDT[5].present = 1; + GDT[5].limit_high = (sizeof(TSS) >> 16) & 0xf; + GDT[5].available = 0; // 0 for TSS + GDT[5].long_mode = 0; + GDT[5].x32 = 0; // idk + GDT[5].gran = 0; + GDT[5].base_high = (((uint32_t) &TSS) >> 24) & 0xff; + } +} + +static void gdt_load() { + lgdt_arg.limit = sizeof(GDT) - 1; + lgdt_arg.base = (uint32_t) &GDT; + asm("lgdt (%0)" : : "b" (&lgdt_arg)); +} + +void gdt_init() { + gdt_prepare(); + gdt_load(); + // check if the GDT was set up correctly + tty_write("checking gdt...", 15); + asm("mov $8, %%eax;" + "mov %%eax, %%ds;" + : : : "%eax"); + tty_write("ok", 2); +} diff --git a/kernel/gdt.h b/kernel/gdt.h new file mode 100644 index 0000000..9ae366c --- /dev/null +++ b/kernel/gdt.h @@ -0,0 +1,3 @@ +#pragma once + +void gdt_init(); diff --git a/kernel/main.c b/kernel/main.c index 73c66e2..d2f0693 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,7 +1,8 @@ +#include #include void kmain() { - for (int i = 0; i < 400; i++) - tty_write("words ", 6); + tty_clear(); + gdt_init(); } diff --git a/kernel/tty.c b/kernel/tty.c index 45de728..5c4c47d 100644 --- a/kernel/tty.c +++ b/kernel/tty.c @@ -30,3 +30,9 @@ void tty_write(const char *buf, size_t len) tty_putchar(buf[i]); } } + +void tty_clear() { + for (size_t i = 0; i < vga_len; i++) + vga[i].c = ' '; + vga_pos = 0; +} diff --git a/kernel/tty.h b/kernel/tty.h index 87a4744..435c87f 100644 --- a/kernel/tty.h +++ b/kernel/tty.h @@ -4,3 +4,4 @@ void tty_putchar(char c); void tty_write(const char *buf, size_t len); +void tty_clear(); diff --git a/platform/boot.s b/platform/boot.s index 77af2bc..6052347 100644 --- a/platform/boot.s +++ b/platform/boot.s @@ -12,6 +12,8 @@ /* a lil stack */ .section .bss +.global stack_top +.type stack_top, @object .align 16 stack_bottom: .skip 16384 -- cgit v1.2.3