summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordzwdz2021-06-25 12:30:07 +0200
committerdzwdz2021-06-25 12:30:07 +0200
commit174cf436480efe690f72d64c9ecd16b7af4d1f0e (patch)
treee8a6634a566492f3e511a2dd8c68870a665ba7a1
parentfde20f86f5be5a39fd3eadf95ba71761d173e0ce (diff)
setting up the GDT
-rw-r--r--.gdbinit2
-rw-r--r--Makefile10
-rw-r--r--kernel/gdt.c127
-rw-r--r--kernel/gdt.h3
-rw-r--r--kernel/main.c5
-rw-r--r--kernel/tty.c6
-rw-r--r--kernel/tty.h1
-rw-r--r--platform/boot.s2
8 files changed, 152 insertions, 4 deletions
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 <kernel/tty.h>
+#include <stdint.h>
+
+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 <kernel/gdt.h>
#include <kernel/tty.h>
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