From 5e668f5e67579ba16974031955b9818f2272c055 Mon Sep 17 00:00:00 2001 From: Nigel Barink Date: Wed, 12 May 2021 23:03:00 +0100 Subject: [PATCH] Basics for an proper GDT and IDT --- Makefile | 6 +- src/kernel/arch/i386/boot.s | 381 +++++++++++++++++++++++++++++-- src/kernel/arch/i386/tty/kterm.c | 1 - src/kernel/arch/i386/tty/kterm.h | 1 + src/kernel/gdtc.cpp | 29 +++ src/kernel/gdtc.h | 20 ++ src/kernel/idt.cpp | 64 ++++++ src/kernel/idt.h | 70 ++++++ src/kernel/kernel.cpp | 39 +++- src/kernel/kernel.h | 5 +- 10 files changed, 590 insertions(+), 26 deletions(-) create mode 100644 src/kernel/gdtc.cpp create mode 100644 src/kernel/gdtc.h create mode 100644 src/kernel/idt.cpp create mode 100644 src/kernel/idt.h diff --git a/Makefile b/Makefile index 4611669..f329535 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CC = ${HOME}/opt/cross/bin/i686-elf-gcc CPP = ${HOME}/opt/cross/bin/i686-elf-g++ CFLAGS = -ffreestanding -O2 -Wall -Wextra -OFILES = $(BUILD_DIR)/boot.o $(BUILD_DIR)/kterm.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/io.o $(BUILD_DIR)/MMU.o +OFILES = $(BUILD_DIR)/boot.o $(BUILD_DIR)/kterm.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/io.o $(BUILD_DIR)/MMU.o $(BUILD_DIR)/idt.o SRC_DIR = src BUILD_DIR = build @@ -56,4 +56,6 @@ $(BUILD_DIR)/crtn.o: $(BUILD_DIR)/io.o: $(CPP) -c $(SRC_DIR)/kernel/io.cpp -o $(BUILD_DIR)/io.o $(CFLAGS) -fno-exceptions -fno-rtti $(BUILD_DIR)/MMU.o: - $(CPP) -c $(SRC_DIR)/kernel/MMU.cpp -o $(BUILD_DIR)/MMU.o $(CFLAGS) -fno-exceptions -fno-rtti \ No newline at end of file + $(CPP) -c $(SRC_DIR)/kernel/MMU.cpp -o $(BUILD_DIR)/MMU.o $(CFLAGS) -fno-exceptions -fno-rtti +$(BUILD_DIR)/idt.o: + $(CPP) -c $(SRC_DIR)/kernel/idt.cpp -o $(BUILD_DIR)/idt.o $(CFLAGS) -fno-exceptions -fno-rtti \ No newline at end of file diff --git a/src/kernel/arch/i386/boot.s b/src/kernel/arch/i386/boot.s index 99fa270..91c47df 100644 --- a/src/kernel/arch/i386/boot.s +++ b/src/kernel/arch/i386/boot.s @@ -20,8 +20,12 @@ stack_bottom: .skip 16384 # 16 KiB stack_top: - - +.text +.globl idt_flush +idt_flush: + mov 4(%esp), %eax + lidt (%eax) + ret .text .globl enablePaging @@ -51,20 +55,369 @@ loadPageDirectory: .global _start .type _start, @function _start: - - - + /*Setup the stack pointer to point to the beginning of our stack */ + /* I believe its a hight address growing down to lower adress for the stack on x86*/ mov $stack_top, %esp - + call early_main + + load_gdt: + lgdt gdt + + # set the segment selecters + + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + ljmp $0x08, $flush + + flush: + #load idt + call init_idt + + # Try enable A20 + # mov $0x2401, %ax + # int $0x15 - call _init - call kernel_main - + # enable protected mode + mov %cr0, %eax + or $1, %eax + mov %eax, %cr0 - cli -1: hlt - jmp 1b - + + call kernel_main -.size _start, . - _start \ No newline at end of file + + cli + 1: hlt + jmp 1b + + + + + /* Tell processor to use our gdt*/ + gdt: + .word (gdt_end - gdt_start -1) # Size of the GDT in bytes minus 1 for math reasons + .int gdt_start # linear address of our GDT + + + + +.att_syntax + + +.size _start, . - _start + + +/* +* Interupt handlers +*/ + +.text +.macro irq_NoErrCode code:req + .globl irq\code + irq\code: + cli + pushb $0 + pushb \code + jmp irq_common +.endm + +.text +.macro irq_ErrCode code + .globl irq\code + irq\code: + cli + pushb \code + jmp irq_common +.endm + + + +.globl irq0 +irq0: + cli + push $0 + push $0 + jmp irq_common + +.globl irq1 +irq1: + cli + push $0 + push $1 + jmp irq_common + +.globl irq2 +irq2: + cli + push $0 + push $2 + jmp irq_common + +.globl irq3 +irq3: + cli + push $0 + push $3 + jmp irq_common + +.globl irq4 +irq4: + cli + push $0 + push $4 + jmp irq_common + +.globl irq5 +irq5: + cli + push $0 + push $5 + jmp irq_common + +.globl irq6 +irq6: + cli + push $0 + push $6 + jmp irq_common + +.globl irq7 +irq7: + cli + push $0 + push $7 + jmp irq_common + +.globl irq8 +irq8: + cli + push $0 + push $8 + jmp irq_common + +.globl irq9 +irq9: + cli + push $0 + push $9 + jmp irq_common + +.globl irq10 +irq10: + cli + push $0 + push $10 + jmp irq_common + +.globl irq11 +irq11: + cli + push $0 + push $11 + jmp irq_common + +.globl irq12 +irq12: + cli + push $0 + push $12 + jmp irq_common + +.globl irq13 +irq13: + cli + push $0 + push $13 + jmp irq_common + +.globl irq14 +irq14: + cli + push $0 + push $14 + jmp irq_common + +.globl irq15 +irq15: + cli + push $0 + push $15 + jmp irq_common + +.globl irq16 +irq16: + cli + push $0 + push $16 + jmp irq_common + +.globl irq17 +irq17: + cli + push $0 + push $17 + jmp irq_common + +.globl irq18 +irq18: + cli + push $0 + push $18 + jmp irq_common + +.globl irq19 +irq19: + cli + push $0 + push $19 + jmp irq_common + +.globl irq20 +irq20: + cli + push $0 + push $20 + jmp irq_common + +.globl irq21 +irq21: + cli + push $0 + push $21 + jmp irq_common + +.globl irq22 +irq22: + cli + push $0 + push $22 + jmp irq_common + +.globl irq23 +irq23: + cli + push $0 + push $23 + jmp irq_common + +.globl irq24 +irq24: + cli + push $0 + push $24 + jmp irq_common + +.globl irq25 +irq25: + cli + push $0 + push $25 + jmp irq_common + +.globl irq26 +irq26: + cli + push $0 + push $26 + jmp irq_common + +.globl irq27 +irq27: + cli + push $0 + push $27 + jmp irq_common + +.globl irq28 +irq28: + cli + push $0 + push $28 + jmp irq_common + +.globl irq29 +irq29: + cli + push $0 + push $29 + jmp irq_common + +.globl irq30 +irq30: + cli + push $0 + push $30 + jmp irq_common + +.globl irq31 +irq31: + cli + push $0 + push $31 + jmp irq_common + + + + + + +.text +irq_common: + pusha # Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax + + + mov %ds, %ax + push %eax + + /* load the kernel data segment descriptor*/ + + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + call irq_handler + + pop %eax + + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + popa + add $8, %esp # cleans push error and irq code + sti + iret # pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP + +/* +* Create the GDT +*/ +.section .data +gdt_start: +gdt_null: +.long 0x0 +.long 0x0 + +gdt_kcode: +.word 0xFFFF # limit +.word 0x0 # base +.byte 0x0 # base +.byte 0b10011010 # 1st flags | type flags +.byte 0b11001111 # 2nd flags | limit +.byte 0x0 # base + +gdt_kdata: +.word 0xFFFF # limit +.word 0x0 # base +.byte 0x0 # base +.byte 0b10010010 # 1st flags | type flags +.byte 0b11001111 # 2nd flags | limit +.byte 0x0 # base +gdt_end: \ No newline at end of file diff --git a/src/kernel/arch/i386/tty/kterm.c b/src/kernel/arch/i386/tty/kterm.c index 2021e22..6dab47f 100644 --- a/src/kernel/arch/i386/tty/kterm.c +++ b/src/kernel/arch/i386/tty/kterm.c @@ -89,4 +89,3 @@ void kterm_writestring(const char* data ){ AS_KERNEL(); kterm_write(data, strlen(data)); } - diff --git a/src/kernel/arch/i386/tty/kterm.h b/src/kernel/arch/i386/tty/kterm.h index 6cf784e..f1570c6 100644 --- a/src/kernel/arch/i386/tty/kterm.h +++ b/src/kernel/arch/i386/tty/kterm.h @@ -15,6 +15,7 @@ void kterm_putat(char, uint8_t, size_t, size_t); void kterm_put(char); void kterm_write(const char*, size_t); void kterm_writestring(const char*); + void kterm_scrollup(); #define KernelTag "[Kernel]: " diff --git a/src/kernel/gdtc.cpp b/src/kernel/gdtc.cpp new file mode 100644 index 0000000..f21e80f --- /dev/null +++ b/src/kernel/gdtc.cpp @@ -0,0 +1,29 @@ +#include "gdtc.h" + + +gdtEntry_t gdt[3]; + + +void gdtSetGate(int num, uint64_t base, uint64_t limit, uint8_t access, + uint8_t gran){ + gdt[num].lBase = (base & 0xFFFF); + gdt[num].mBase = (base >> 16) & 0xFF; + gdt[num].hBase = (base >> 24) & 0xFF; + + gdt[num].lLimit = (limit & 0xFFFF); + gdt[num].granularity = ((limit >> 16) & 0x0F); + + gdt[num].granularity |= (gran & 0xF0); + gdt[num].access = access; +} + +void setupGdt(){ + gdtPointer.limit = (sizeof(gdtEntry_t) * 3) - 1; + gdtPointer.base = &gdt; + + gdtSetGate(0, 0, 0, 0, 0); + gdtSetGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); + gdtSetGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); + + loadGdt(); +} diff --git a/src/kernel/gdtc.h b/src/kernel/gdtc.h new file mode 100644 index 0000000..2b34997 --- /dev/null +++ b/src/kernel/gdtc.h @@ -0,0 +1,20 @@ +#include +extern "c"{ + +typedef struct { + uint16_t lLimit; + uint16_t lBase; + uint8_t mBase; + uint8_t access; + uint8_t granularity; + uint8_t hBase; +} gdtEntry_t; + +struct { + uint16_t limit; + uint32_t base; +} gdtPointer; + +extern void loadGdt(); +void setupGdt(); +} \ No newline at end of file diff --git a/src/kernel/idt.cpp b/src/kernel/idt.cpp new file mode 100644 index 0000000..2ba7165 --- /dev/null +++ b/src/kernel/idt.cpp @@ -0,0 +1,64 @@ +#include "idt.h" + +IDT_entry idt_table[256]; +IDT_ptr idt_ptr; + +void set_id_entry (uint8_t num , uint32_t base, uint16_t sel, uint8_t flags){ + idt_table[num].offset_1 = base & 0xFFFF; + idt_table[num].selector = sel; + idt_table[num].zero = 0; + idt_table[num].type_attr = flags; + idt_table[num].offset_2 = (base >> 16) & 0xFFFF; + +}; + + +void irq_handler (registers regs) { + kterm_writestring("received interrupt!"); +} + + +void init_idt(){ + // Initialise the IDT pointer + idt_ptr.length = sizeof(IDT_entry) * 255; + idt_ptr.base = (uint32_t)&idt_table; + + + // TODO: Set everything to zero first + + set_id_entry(0, (uint32_t) irq0 , 0x08, 0x8E); + set_id_entry(1, (uint32_t) irq1 , 0x08, 0x8E); + set_id_entry(2, (uint32_t) irq2 , 0x08, 0x8E); + set_id_entry(3, (uint32_t) irq3 , 0x08, 0x8E); + set_id_entry(4, (uint32_t) irq4 , 0x08, 0x8E); + set_id_entry(5, (uint32_t) irq5 , 0x08, 0x8E); + set_id_entry(6, (uint32_t) irq6 , 0x08, 0x8E); + set_id_entry(7, (uint32_t) irq7 , 0x08, 0x8E); + set_id_entry(8, (uint32_t) irq8 , 0x08, 0x8E); + set_id_entry(9, (uint32_t) irq9 , 0x08, 0x8E); + set_id_entry(10, (uint32_t) irq10 , 0x08, 0x8E); + set_id_entry(11, (uint32_t) irq11 , 0x08, 0x8E); + set_id_entry(12, (uint32_t) irq12 , 0x08, 0x8E); + set_id_entry(13, (uint32_t) irq13 , 0x08, 0x8E); + set_id_entry(14, (uint32_t) irq14 , 0x08, 0x8E); + set_id_entry(15, (uint32_t) irq15 , 0x08, 0x8E); + set_id_entry(16, (uint32_t) irq16 , 0x08, 0x8E); + set_id_entry(17, (uint32_t) irq17 , 0x08, 0x8E); + set_id_entry(18, (uint32_t) irq18 , 0x08, 0x8E); + set_id_entry(19, (uint32_t) irq19 , 0x08, 0x8E); + set_id_entry(20, (uint32_t) irq20 , 0x08, 0x8E); + set_id_entry(21, (uint32_t) irq21 , 0x08, 0x8E); + set_id_entry(22, (uint32_t) irq22 , 0x08, 0x8E); + set_id_entry(23, (uint32_t) irq23 , 0x08, 0x8E); + set_id_entry(24, (uint32_t) irq24 , 0x08, 0x8E); + set_id_entry(25, (uint32_t) irq25 , 0x08, 0x8E); + set_id_entry(26, (uint32_t) irq26 , 0x08, 0x8E); + set_id_entry(27, (uint32_t) irq27 , 0x08, 0x8E); + set_id_entry(28, (uint32_t) irq28 , 0x08, 0x8E); + set_id_entry(29, (uint32_t) irq29 , 0x08, 0x8E); + set_id_entry(30, (uint32_t) irq30 , 0x08, 0x8E); + set_id_entry(31, (uint32_t) irq31 , 0x08, 0x8E); + + + idt_flush((uint32_t)&idt_ptr); +} diff --git a/src/kernel/idt.h b/src/kernel/idt.h new file mode 100644 index 0000000..78b9a3d --- /dev/null +++ b/src/kernel/idt.h @@ -0,0 +1,70 @@ +#pragma once +#include "stdint.h" + +extern "C" void kterm_writestring(const char* data ); + +extern "C" { + struct __attribute__((__packed__)) IDT_entry { + uint16_t offset_1; + uint16_t selector; + uint8_t zero; + uint8_t type_attr; + uint16_t offset_2; + }; + + struct __attribute__((__packed__)) IDT_ptr { + unsigned short length; + unsigned long base; + }; + + struct registers { + uint32_t ds; // Data segment selector + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha. + uint32_t int_no, err_code; // Interrupt number and error code (if applicable) + uint32_t eip, cs, eflags, useresp, ss; + }; + + + extern void idt_flush(uint32_t); + void set_id_entry (uint8_t num , uint32_t base, uint16_t sel, uint8_t flags); + void init_idt(); + + void irq_handler (registers regs); + + extern void irq0 (); + extern void irq1 (); + extern void irq2 (); + extern void irq3 (); + extern void irq4 (); + extern void irq5 (); + extern void irq6 (); + extern void irq7 (); + extern void irq8 (); + extern void irq9 (); + extern void irq10 (); + extern void irq11 (); + extern void irq12 (); + extern void irq13 (); + extern void irq14 (); + extern void irq15 (); + extern void irq16 (); + extern void irq17 (); + extern void irq18 (); + extern void irq19 (); + extern void irq20 (); + extern void irq21 (); + extern void irq22 (); + extern void irq23 (); + extern void irq24 (); + extern void irq25 (); + extern void irq26 (); + extern void irq27 (); + extern void irq28 (); + extern void irq29 (); + extern void irq30 (); + extern void irq31 (); + + + + +} diff --git a/src/kernel/kernel.cpp b/src/kernel/kernel.cpp index 14f0321..ddb9402 100644 --- a/src/kernel/kernel.cpp +++ b/src/kernel/kernel.cpp @@ -74,6 +74,12 @@ char read_serial() { } +void print_serial(const char* string ){ + for(size_t i = 0; i < strlen(string); i ++){ + write_serial(string[i]); + } +} + void test_serial(){ /** Serial test **/ kterm_writestring("Writing to COM1 serial port:"); @@ -93,11 +99,34 @@ void test_serial(){ } + extern "C" { + + void early_main(){ + + init_serial(); + print_serial("\033[31;42mEarly main called!\n"); + + + } + void kernel_main (void) { + + print_serial("\033[31;42mKernel main called!\n"); + + /** initialize terminal interface */ kterm_init(); + /** Setup the MMU **/ + kterm_writestring("Starting MMU...\n"); + auto mmu = MMU(); + mmu.enable(); + kterm_writestring("MMU enabled!\n"); + + + + /** Wrtite stuff to the screen to test the terminal**/ kterm_writestring("Hello world!\n"); kterm_writestring("We got newline support!\n"); @@ -114,14 +143,11 @@ extern "C" { auto testObject = Test(); testObject.printMe(); - /** Setup the MMU **/ - kterm_writestring("Starting MMU...\n"); - auto mmu = MMU(); - mmu.enable(); - kterm_writestring("MMU enabled!\n"); - + /** test interrupt handlers **/ + //asm volatile ("int $0x3"); + //asm volatile ("int $0x4"); /** Lets start using the serial port for debugging .. **/ // Hopefully once we go into realmode or do something that @@ -129,7 +155,6 @@ extern "C" { // some situational awareness //Serial serialbus = Serial::init(); - test_serial(); } diff --git a/src/kernel/kernel.h b/src/kernel/kernel.h index 080869a..4b2b306 100644 --- a/src/kernel/kernel.h +++ b/src/kernel/kernel.h @@ -1,7 +1,8 @@ #pragma once extern "C" { -#include "../libc/include/string.h" -#include "arch/i386/tty/kterm.h" + #include "../libc/include/string.h" + #include "arch/i386/tty/kterm.h" } #include "MMU.h" #include "io.h" +#include "idt.h" \ No newline at end of file