From 84f64badaf1cf059004d2e942fd57d8798b76d60 Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Fri, 19 Jun 2020 12:08:17 -0500 Subject: [PATCH] Added the Global Descriptor Table. --- build_numbers.c | 2 +- includes/gdt.h | 22 +++++++++++++++++++++ includes/kernel.h | 3 +-- kernel/gdt.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ kernel/io.s | 21 +++++++++++++++++++- kernel/kmain.c | 9 ++++++++- 6 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 includes/gdt.h create mode 100644 kernel/gdt.c diff --git a/build_numbers.c b/build_numbers.c index 234dc3d..877ab0a 100644 --- a/build_numbers.c +++ b/build_numbers.c @@ -1,3 +1,3 @@ #ifndef KERNEL_VERSION_NUMBER -#define KERNEL_VERSION_NUMBER "0.0.1-333" +#define KERNEL_VERSION_NUMBER "0.0.1-348" #endif diff --git a/includes/gdt.h b/includes/gdt.h new file mode 100644 index 0000000..fcbcb98 --- /dev/null +++ b/includes/gdt.h @@ -0,0 +1,22 @@ +#ifndef GDT_H +#define GDT_H + +struct gdt { + unsigned short size; + unsigned int address; +} __attribute__((packed)); + +struct gdt_entry +{ + unsigned short limit_low; + unsigned short base_low; + unsigned char base_middle; + unsigned char access; + unsigned char granularity; + unsigned char base_high; +} __attribute__((packed)); + +void gdt_install(); +void load_gdt(struct gdt *); +void gdt_set_gate(unsigned long, unsigned long, unsigned char, unsigned char, struct gdt_entry*); +#endif diff --git a/includes/kernel.h b/includes/kernel.h index b9d8539..aa6a518 100644 --- a/includes/kernel.h +++ b/includes/kernel.h @@ -1,5 +1,4 @@ #ifndef KERNEL_H #define KERNEL_H - -int strlen(char*); +void kmain(); #endif diff --git a/kernel/gdt.c b/kernel/gdt.c new file mode 100644 index 0000000..e527bc3 --- /dev/null +++ b/kernel/gdt.c @@ -0,0 +1,50 @@ +#include "../includes/gdt.h" +/* Code taken from http://www.osdever.net/bkerndev/Docs/gdt.htm with some minor tweaks. */ + +/* Should be called by main. This will setup the special GDT +* pointer, set up the first 3 entries in our GDT, and then +* finally call load_gdt() in our assembler file in order +* to tell the processor where the new GDT is and update the +* new segment registers */ +void gdt_install() +{ + struct gdt_entry gdt_entries[3]; + struct gdt gdt_ptr; + /* Setup the GDT pointer and the size of the table */ + gdt_ptr.size = sizeof(struct gdt_entry) * 3 - 1; + gdt_ptr.address = (unsigned int) &gdt_entries; + + /* Our NULL descriptor */ + gdt_set_gate(0, 0, 0, 0, &gdt_entries[0]); + + /* The second entry is our Code Segment. The base address + * is 0, the limit is 4GBytes, it uses 4KByte granularity, + * uses 32-bit opcodes, and is a Code Segment descriptor. + * Please check the table above in the tutorial in order + * to see exactly what each value means */ + gdt_set_gate(0, 0xFFFFFFFF, 0x9A, 0xCF, &gdt_entries[1]); + + /* The third entry is our Data Segment. It's EXACTLY the + * same as our code segment, but the descriptor type in + * this entry's access byte says it's a Data Segment */ + gdt_set_gate(0, 0xFFFFFFFF, 0x92, 0xCF, &gdt_entries[2]); + + /* Flush out the old GDT and install the new changes! */ + load_gdt(&gdt_ptr); +} + +void gdt_set_gate(unsigned long base, unsigned long limit, unsigned char access, unsigned char gran, struct gdt_entry* gdt_entry) +{ + /* Setup the descriptor base address */ + gdt_entry->base_low = (base & 0xFFFF); + gdt_entry->base_middle = (base >> 16) & 0xFF; + gdt_entry->base_high = (base >> 24) & 0xFF; + + /* Setup the descriptor limits */ + gdt_entry->limit_low = (limit & 0xFFFF); + gdt_entry->granularity = ((limit >> 16) & 0x0F); + + /* Finally, set up the granularity and access flags */ + gdt_entry->granularity |= (gran & 0xF0); + gdt_entry->access = access; +} diff --git a/kernel/io.s b/kernel/io.s index 73f7f8d..a7416d0 100644 --- a/kernel/io.s +++ b/kernel/io.s @@ -16,6 +16,25 @@ global inb ; stack: [esp + 4] The address of the I/O port ; [esp ] The return address inb: - mov dx, [esp + 4] ; Move the address of the I/O port to the dx register. + mov dx, [esp + 4] ; Move the address of the I/O port to the dx register in al, dx ; Read a byte from the I/O port and store it in the al register ret + +global load_gdt + +; load_gdt - Installs a new GDT +; stack: [esp + 4] The address of the GDT +; [esp ] The return addess +load_gdt: + mov eax, [esp + 4] + lgdt [eax] + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + jmp 0x08:return ; Perform a "far jump" to load 0x08 in the CS register + +return: + ret ; Now we've changed CS to 0x08 diff --git a/kernel/kmain.c b/kernel/kmain.c index ea9cad9..375a61b 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -1,4 +1,5 @@ #include "../includes/io.h" +#include "../includes/gdt.h" #include "../includes/serial.h" #include "../includes/screen.h" @@ -26,7 +27,7 @@ void kmain() move_cursor(5, 20); draw_string("Cursor moved over 5 cells and down 4 cells.", 0xF, 0x0); draw_string("And the cursor moves to the end of the string", 0x1, 0xF); - draw_string("Now this string should have a newline now:\nAnd now a new line is here.", 0xF, 0x0); + draw_string("Now this string should have a newline now:\nAnd now a new line is here.\n", 0xF, 0x0); //draw_rect(20, 5, 50, 7, 0x4, 0xF); //draw_rect(20, 5, 50, 7, 0x4, 0xF); //draw_rect(20, 5, 50, 7, 0x4, 0xF); @@ -34,5 +35,11 @@ void kmain() //row = 2; ///column = 80; //draw_s("And 2nd Row. Now the 3rd row.", 2, 9); + move_cursor(0, 3); + draw_string("Installing GDT...\n", 0xF, 0x0); + gdt_install(); + move_cursor(0, 4); + draw_string("Installed GDT\n", 0xf, 0x0); + asm("hlt"); }