From b987beca85966123a62ef21d5e05e298c5313791 Mon Sep 17 00:00:00 2001 From: Furkan Mudanyali Date: Mon, 18 Jul 2022 22:37:43 +0300 Subject: [PATCH] Paging, interrupts --- kernel/Makefile | 2 +- kernel/arch/i386/boot/boot.S | 5 +-- kernel/arch/i386/boot/gdt.c | 2 +- kernel/arch/i386/boot/idt.c | 49 +++++++++++++++++++++++++++++ kernel/arch/i386/boot/idt_load.S | 6 ++++ kernel/arch/i386/make.config | 5 ++- kernel/arch/i386/paging/paging.S | 22 +++++++++++++ kernel/arch/i386/vga/tty.c | 12 ++++++-- kernel/include/kernel/gdt.h | 8 ++--- kernel/include/kernel/idt.h | 53 ++++++++++++++++++++++++++++++++ kernel/include/kernel/paging.h | 7 +++++ kernel/kernel/exception.c | 8 +++++ kernel/kernel/kernel.c | 39 ++++++++++++++++++++--- 13 files changed, 201 insertions(+), 17 deletions(-) create mode 100644 kernel/arch/i386/boot/idt.c create mode 100644 kernel/arch/i386/boot/idt_load.S create mode 100644 kernel/arch/i386/paging/paging.S create mode 100644 kernel/include/kernel/idt.h create mode 100644 kernel/include/kernel/paging.h create mode 100644 kernel/kernel/exception.c diff --git a/kernel/Makefile b/kernel/Makefile index ada5e86..b12deb8 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -13,7 +13,7 @@ EXEC_PREFIX?=$(PREFIX) BOOTDIR?=$(EXEC_PREFIX)/boot INCLUDEDIR?=$(PREFIX)/include -CFLAGS:=$(CFLAGS) -ffreestanding -Wall -Wextra -fstack-protector +CFLAGS:=$(CFLAGS) -ffreestanding -Wall -Wextra -fstack-protector-strong -mgeneral-regs-only -mno-red-zone CPPFLAGS:=$(CPPFLAGS) -D__is_kernel -Iinclude LDFLAGS:=$(LDFLAGS) LIBS:=$(LIBS) -nostdlib -lk -lgcc diff --git a/kernel/arch/i386/boot/boot.S b/kernel/arch/i386/boot/boot.S index 65e3e0e..08389cc 100644 --- a/kernel/arch/i386/boot/boot.S +++ b/kernel/arch/i386/boot/boot.S @@ -26,8 +26,9 @@ stack_top: _start: movl $stack_top, %esp cli - call gdt_init # call global constructors - call kernel_main # transfer control to main kernel + call gdt_init # initialize the GDT + call idt_init # initialize the IDT + call kernel_main # transfer control to main kernel # Hang if kernel_main unexpectedly returns 1: hlt jmp 1b diff --git a/kernel/arch/i386/boot/gdt.c b/kernel/arch/i386/boot/gdt.c index e274ca9..01588f7 100644 --- a/kernel/arch/i386/boot/gdt.c +++ b/kernel/arch/i386/boot/gdt.c @@ -41,7 +41,7 @@ void gdt_init(void) { gdt_fill(GDT+i, rows+i); } - gp.base = (void*) GDT; + gp.base = &GDT; gp.limit = (GDT_ENTRIES * sizeof(gdt_entry)) - 1; gdt_load(); diff --git a/kernel/arch/i386/boot/idt.c b/kernel/arch/i386/boot/idt.c new file mode 100644 index 0000000..3f2d98f --- /dev/null +++ b/kernel/arch/i386/boot/idt.c @@ -0,0 +1,49 @@ +#include +#include + +__attribute__((interrupt)) void hello_interrupt(idt_frame* frame) { + printf("Hello from interrupt!\n"); + printf("ip=0x%x, cs=0x%x, flags=0b%b\n", frame->ip, frame->cs, frame->flags); +} + +__attribute__((interrupt)) void hello_interrupt_err(idt_frame_err* frame) { + printf("Hello from error interrupt!\n"); + printf("ip=0x%x, cs=0x%x, flags=0b%b, err=0x%x\n", frame->ip, frame->cs, frame->flags, frame->err); + asm volatile("cli; hlt"); +} + +void idt_fill_row(idt_entry_t* target, idt* source) { + target->isr_low = source->offset & 0xFFFF; + target->isr_high = (source->offset >> 16) & 0xFFFF; + target->kernel_cs = source->segment; + target->flags = 0x80; + target->flags |= (source->ring & 0x3) << 5; + target->flags |= (source->gate & 0xF); + target->reserved = 0; +} + +__attribute__((aligned(0x10))) idt_entry_t IDT[IDT_ROWS]; +idtr_t idtptr; + +void idt_init(void) { + idt rows[] = { + {(uint32_t)hello_interrupt, 0x08, INT_GATE32, 0}, + {(uint32_t)hello_interrupt_err, 0x08, INT_GATE32, 0}, + }; + + int valid_rows = sizeof(rows) / sizeof(idt_entry_t); + + for(int i = 0; i < valid_rows; ++i) { + idt_fill_row(IDT+i, rows+i); + } + + idt blank_row = {0, 0, 0, 0}; + for(int i = valid_rows; i < IDT_ROWS; ++i) { + idt_fill_row(IDT+i, &blank_row); + } + + idtptr.base = &IDT; + idtptr.limit = (IDT_ROWS * sizeof(idt_entry_t)) - 1; + + idt_load(); +} \ No newline at end of file diff --git a/kernel/arch/i386/boot/idt_load.S b/kernel/arch/i386/boot/idt_load.S new file mode 100644 index 0000000..dd62b89 --- /dev/null +++ b/kernel/arch/i386/boot/idt_load.S @@ -0,0 +1,6 @@ +.global idt_load +.type idt_load, @function +idt_load: + lidt (idtptr) + sti + ret \ No newline at end of file diff --git a/kernel/arch/i386/make.config b/kernel/arch/i386/make.config index 8441da1..f97727a 100644 --- a/kernel/arch/i386/make.config +++ b/kernel/arch/i386/make.config @@ -7,4 +7,7 @@ KERNEL_ARCH_OBJS=\ $(ARCHDIR)/boot/boot.o \ $(ARCHDIR)/vga/tty.o \ $(ARCHDIR)/boot/gdt.o \ -$(ARCHDIR)/boot/gdt_load.o +$(ARCHDIR)/boot/gdt_load.o \ +$(ARCHDIR)/paging/paging.o \ +$(ARCHDIR)/boot/idt.o \ +$(ARCHDIR)/boot/idt_load.o \ No newline at end of file diff --git a/kernel/arch/i386/paging/paging.S b/kernel/arch/i386/paging/paging.S new file mode 100644 index 0000000..3dbdd98 --- /dev/null +++ b/kernel/arch/i386/paging/paging.S @@ -0,0 +1,22 @@ +.text +.globl load_page_dir +load_page_dir: + push %ebp + mov %esp, %ebp + mov 8(%esp), %eax + mov %eax, %cr3 + mov %ebp, %esp + pop %ebp + ret + +.text +.globl enable_paging +enable_paging: + push %ebp + mov %esp, %ebp + mov %cr0, %eax + or $0x80000000, %eax + mov %eax, %cr0 + mov %ebp, %esp + pop %ebp + ret \ No newline at end of file diff --git a/kernel/arch/i386/vga/tty.c b/kernel/arch/i386/vga/tty.c index 61d9d68..3188a60 100644 --- a/kernel/arch/i386/vga/tty.c +++ b/kernel/arch/i386/vga/tty.c @@ -41,13 +41,19 @@ void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y) { void terminal_putchar(char c) { unsigned char uc = c; - terminal_putentryat(uc, terminal_color, terminal_column, terminal_row); - - if (++terminal_column == VGA_WIDTH) { + if (uc == '\n') { terminal_column = 0; if (++terminal_row == VGA_HEIGHT) { terminal_row = 0; } + } else { + terminal_putentryat(uc, terminal_color, terminal_column, terminal_row); + if (++terminal_column == VGA_WIDTH) { + terminal_column = 0; + if (++terminal_row == VGA_HEIGHT) { + terminal_row = 0; + } + } } } diff --git a/kernel/include/kernel/gdt.h b/kernel/include/kernel/gdt.h index 612684f..a2e59d2 100644 --- a/kernel/include/kernel/gdt.h +++ b/kernel/include/kernel/gdt.h @@ -1,5 +1,5 @@ /** - * Referenced from https://tendstofortytwo/clay + * Referenced from https://github.com/tendstofortytwo/clay * kernel/kernel.c */ @@ -13,7 +13,7 @@ typedef struct { uint16_t limit; uint32_t base; -}__attribute__((packed)) gdt_ptr; +} __attribute__((packed)) gdt_ptr; typedef struct { uint16_t limit_lo; @@ -22,14 +22,14 @@ typedef struct { uint8_t access; uint8_t limit_hi_flags; uint8_t base_hi; -}__attribute__((packed)) gdt_entry; +} __attribute__((packed)) gdt_entry; typedef struct { uint32_t base; uint32_t limit; uint8_t access; uint8_t flags; -}__attribute__((packed)) gdt; +} __attribute__((packed)) gdt; void gdt_fill(gdt_entry*, gdt*); void gdt_init(void); diff --git a/kernel/include/kernel/idt.h b/kernel/include/kernel/idt.h new file mode 100644 index 0000000..c39a840 --- /dev/null +++ b/kernel/include/kernel/idt.h @@ -0,0 +1,53 @@ +#ifndef _KERNEL_IDT_H +#define _KERNEL_IDT_H + +#include + +#define IDT_ROWS 256 +#define TASK_GATE 0x5 +#define INT_GATE16 0x6 +#define TRAP_GATE16 0x7 +#define INT_GATE32 0xE +#define TRAP_GATE32 0xF + +typedef struct { + uint16_t limit; + uint32_t base; +} __attribute__((packed)) idtr_t; + +typedef struct { + uint16_t isr_low; // lower 16-bits of ISR address + uint16_t kernel_cs; // The GDT selector that the CPU will load into CS before calling ISR + uint8_t reserved; // set to zero + uint8_t flags; // Type and attributes + uint16_t isr_high; // Higher 16-bits of ISR address +} __attribute__((packed)) idt_entry_t; + +typedef struct { + uint32_t offset; + uint16_t segment; + uint8_t gate; + uint8_t ring; +} idt; + +typedef struct { + uint32_t ip; + uint32_t cs; + uint32_t flags; + uint32_t sp; + uint32_t ss; +} __attribute__((packed)) idt_frame; + +typedef struct { + uint32_t err; + uint32_t ip; + uint32_t cs; + uint32_t flags; + uint32_t sp; + uint32_t ss; +} __attribute__((packed)) idt_frame_err; + +extern void idt_load(); +extern idtr_t idtptr; + +#endif \ No newline at end of file diff --git a/kernel/include/kernel/paging.h b/kernel/include/kernel/paging.h new file mode 100644 index 0000000..39df8e6 --- /dev/null +++ b/kernel/include/kernel/paging.h @@ -0,0 +1,7 @@ +#ifndef _KERNEL_PAGING_H +#define _KERNEL_PAGING_H + +extern void load_page_dir(unsigned int*); +extern void enable_paging(); + +#endif \ No newline at end of file diff --git a/kernel/kernel/exception.c b/kernel/kernel/exception.c new file mode 100644 index 0000000..e46be97 --- /dev/null +++ b/kernel/kernel/exception.c @@ -0,0 +1,8 @@ +#include + +__attribute__((noreturn)) +void exception_handler(void); +void exception_handler() { + printf("Kernel exception!\n"); + __asm__ volatile ("cli; hlt"); +} \ No newline at end of file diff --git a/kernel/kernel/kernel.c b/kernel/kernel/kernel.c index 83e08cb..3952e39 100644 --- a/kernel/kernel/kernel.c +++ b/kernel/kernel/kernel.c @@ -2,13 +2,42 @@ #include #include +#include + +#define PAGE_ENTRIES 1024 +#define PAGE_SIZE 4 * PAGE_ENTRIES + +void paging_init() { + uint32_t page_dir[PAGE_ENTRIES] __attribute__((aligned(PAGE_SIZE))); + for(int i = 0; i < PAGE_ENTRIES; i++) { + // Supervisor: only kernel-mode can access + // Write Enabled: Can be both read and written to + // Not Present: Page table not present + page_dir[i] = 0x00000002; + } + + uint32_t first_page_table[PAGE_ENTRIES] __attribute__((aligned(PAGE_SIZE))); + for(unsigned int i = 0; i < PAGE_ENTRIES; i++) { + // As the address is page aligned, it will leave 12 bits zeroed, + // which are used by the attributes. + first_page_table[i] = (i * 0x1000) | 3; // attr: supervisor, r/w, present + } + + page_dir[0] = ((unsigned int)first_page_table) | 3; //attr: supervisor, r/w, present + + load_page_dir(page_dir); + enable_paging(); +} void kernel_main(void) { + paging_init(); terminal_initialize(); - printf("Hello, kernel World!\n "); - printf("String test: %s\n ", "HELLOOOOO"); - printf("Float test: %.10f\n ", 0.123456789); - printf("Int test: %d\n ", 747474); - printf("Hex test: 0x%x\n ", 0xDEADBEEF); + printf("Hello, kernel World!\n"); + printf("String test: %s\n", "HELLOOOOO"); + printf("Float test: %.10f\n", 0.123456789); + printf("Int test: %d\n", 747474); + printf("Hex test: 0x%x\n", 0xDEADBEEF); printf("And now for 0.1 + 0.2...... which is: %.17f\n", 0.1 + 0.2); + asm("int $0"); + asm("cli"); }