From 022884e20d65e567eea5b6388068c13cd029b8b1 Mon Sep 17 00:00:00 2001 From: Curle Date: Tue, 25 Jun 2019 22:31:26 +0100 Subject: [PATCH] Fixes and improvements. Including a new, rewritten and restructured boot.s file, plus automagical Protected Mode. --- arch/i386/boot.s | 66 ++++++++++++++++++++++------- arch/i386/tty.c | 2 +- include/arch/i386/vga.h | 6 +-- include/kernel/utils.h | 20 +++++---- kernel/idt.c | 64 ++++++++++++++-------------- kernel/kernel.c | 92 ++++++++++++++++++++++++++++------------- kernel/utils.c | 16 ++++++- 7 files changed, 177 insertions(+), 89 deletions(-) diff --git a/arch/i386/boot.s b/arch/i386/boot.s index 2104a19..17ce395 100755 --- a/arch/i386/boot.s +++ b/arch/i386/boot.s @@ -1,12 +1,12 @@ -[BITS 32] +[BITS 32] ;... somehow. [GLOBAL start] start: - mov esp, _sys_stack - jmp stublet + mov esp, _sys_stack ; Stack pointer! + jmp stublet ; This has a purpse. I don't know what it is, but there is one. -ALIGN 4 -mboot: +ALIGN 4 ; 4KB alignment, required by GRUB. +mboot: ; This is all magic, and all of it required for GRUB to see our stuff. MULTIBOOT_ALIGN equ 1<<0 MULTIBOOT_MEM equ 1<<1 MULTIBOOT_AOUT equ 1<<16 @@ -25,23 +25,60 @@ mboot: dd end dd start -stublet: +stublet: ; Where the kernel stuff goes. + + ;===================================== + ;===Priority: 32 bit Protected Mode=== + ;===================================== + + cli ; Interrupts be gone! + + xor cx, cx ; CX - GP, useful here. +kbempty: + in al, 64h ; Read keyboard status + test al, 02h ; Check if the buffer is full + loopnz kbempty ; Wait until it is + mov al, 0d1h ; Prepare a message + out 64h, al ; And then send it to the keyboard (controller) +kbempty2: + in al, 64h ; Read the status again + test al, 02h ; Check if it's processed our message + loopnz kbempty2 ; And wait until it has + mov al, 0dfh ; Prepare a different message, telling it to enable A20 + out 60h, al ; Send the message + mov cx, 14h ; Restore the value of CX +wait_kb: ; Insinuate a 25uS delay to allow the processor to catch up + out 0edh, ax + loop wait_kb + + mov eax, cr0 ; Read the control register + or al, 1 ; Set bit 1: protected mode + mov cr0, eax ; Set the control register back + jmp $+2 ; Clear the queue + nop ; (jump straight to kernel) + nop + +;================================== +;===32-bit Protected Mode active=== +;================================== + ; Call the kernel + EXTERN kernel_main call kernel_main jmp $ -[GLOBAL load_gdt] ; Allows the C code to call gdt_flush(). +[GLOBAL load_gdt] [EXTERN gp] load_gdt: lgdt [gp] ; Load the new GDT pointer - mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment - mov ds, ax ; Load all data segment selectors + mov ax, 0x10 + mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax - jmp 0x08:flush ; 0x08 is the offset to our code segment: Far jump! + jmp 0x08:flush flush: ret @@ -121,7 +158,7 @@ IRQ 13, 45 IRQ 14, 46 IRQ 15, 47 -extern fault_handler +[EXTERN fault_handler] isr_common: pusha @@ -149,7 +186,7 @@ isr_common: add esp, 8 iret -extern irq_handler +[EXTERN irq_handler] irq_common: pusha @@ -176,11 +213,12 @@ irq_common: iret [GLOBAL idt_load] +[EXTERN idtp] idt_load: - mov eax, [esp+4] lidt [eax] ret - + + SECTION .bss resb 8192 _sys_stack: diff --git a/arch/i386/tty.c b/arch/i386/tty.c index a9cc9af..e8615e0 100644 --- a/arch/i386/tty.c +++ b/arch/i386/tty.c @@ -14,7 +14,7 @@ static size_t terminal_column; static uint8_t current_color; static uint16_t* term_buffer; -static uint16_t* const vga_buffer = (uint16_t*)0xB8000; +volatile uint16_t* vga_buffer = (uint16_t*)0xB8000; void screen_initialize(void) { diff --git a/include/arch/i386/vga.h b/include/arch/i386/vga.h index e8f3fb7..52c20c7 100644 --- a/include/arch/i386/vga.h +++ b/include/arch/i386/vga.h @@ -22,8 +22,8 @@ enum vga_colors { WHITE = 15 }; -static inline uint8_t vga_color_set(enum vga_colors fg, enum vga_colors bg) { return fg | bg << 4; } +static inline uint8_t vga_color_set(enum vga_colors fg, enum vga_colors bg) { return bg << 4 | fg; } -static inline uint16_t vga_entry(unsigned char uc, uint8_t color) { return (uint16_t)uc | (uint16_t)color << 8; } +static inline uint16_t vga_entry(uint8_t uc, uint8_t color) { return color << 8 | uc; } -#endif \ No newline at end of file +#endif diff --git a/include/kernel/utils.h b/include/kernel/utils.h index 91bc58c..cac52c3 100755 --- a/include/kernel/utils.h +++ b/include/kernel/utils.h @@ -1,13 +1,13 @@ -#pragma once -#include - -/* A temporary file, to get the system compiling. */ - -size_t strlen(const char*); - -unsigned char inb(unsigned short); - +#pragma once +#include + +/* A temporary file, to get the system compiling. */ + +size_t strlen(const char*); + +unsigned char inb(unsigned short); + void outb(unsigned short, unsigned char); void memcpy(void*, void*, size_t); @@ -19,3 +19,5 @@ void int_to_ascii(int, char*); void int_to_hex(int, char*); void empty_string(char*); + +char* itoc(size_t); diff --git a/kernel/idt.c b/kernel/idt.c index 90c2b80..ba49a88 100755 --- a/kernel/idt.c +++ b/kernel/idt.c @@ -38,40 +38,40 @@ void idt_install() { memset(&idt, 0, sizeof(struct idt_entry) * 256); idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E); - idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E); - idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E); - idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E); - idt_set_gate(4, (unsigned)isr4, 0x08, 0x8E); - idt_set_gate(5, (unsigned)isr5, 0x08, 0x8E); - idt_set_gate(6, (unsigned)isr6, 0x08, 0x8E); - idt_set_gate(7, (unsigned)isr7, 0x08, 0x8E); + idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E); + idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E); + idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E); + idt_set_gate(4, (unsigned)isr4, 0x08, 0x8E); + idt_set_gate(5, (unsigned)isr5, 0x08, 0x8E); + idt_set_gate(6, (unsigned)isr6, 0x08, 0x8E); + idt_set_gate(7, (unsigned)isr7, 0x08, 0x8E); - idt_set_gate(8, (unsigned)isr8, 0x08, 0x8E); - idt_set_gate(9, (unsigned)isr9, 0x08, 0x8E); - idt_set_gate(10, (unsigned)isr10, 0x08, 0x8E); - idt_set_gate(11, (unsigned)isr11, 0x08, 0x8E); - idt_set_gate(12, (unsigned)isr12, 0x08, 0x8E); - idt_set_gate(13, (unsigned)isr13, 0x08, 0x8E); - idt_set_gate(14, (unsigned)isr14, 0x08, 0x8E); - idt_set_gate(15, (unsigned)isr15, 0x08, 0x8E); + idt_set_gate(8, (unsigned)isr8, 0x08, 0x8E); + idt_set_gate(9, (unsigned)isr9, 0x08, 0x8E); + idt_set_gate(10, (unsigned)isr10, 0x08, 0x8E); + idt_set_gate(11, (unsigned)isr11, 0x08, 0x8E); + idt_set_gate(12, (unsigned)isr12, 0x08, 0x8E); + idt_set_gate(13, (unsigned)isr13, 0x08, 0x8E); + idt_set_gate(14, (unsigned)isr14, 0x08, 0x8E); + idt_set_gate(15, (unsigned)isr15, 0x08, 0x8E); - idt_set_gate(16, (unsigned)isr16, 0x08, 0x8E); - idt_set_gate(17, (unsigned)isr17, 0x08, 0x8E); - idt_set_gate(18, (unsigned)isr18, 0x08, 0x8E); - idt_set_gate(19, (unsigned)isr19, 0x08, 0x8E); - idt_set_gate(20, (unsigned)isr20, 0x08, 0x8E); - idt_set_gate(21, (unsigned)isr21, 0x08, 0x8E); - idt_set_gate(22, (unsigned)isr22, 0x08, 0x8E); - idt_set_gate(23, (unsigned)isr23, 0x08, 0x8E); + idt_set_gate(16, (unsigned)isr16, 0x08, 0x8E); + idt_set_gate(17, (unsigned)isr17, 0x08, 0x8E); + idt_set_gate(18, (unsigned)isr18, 0x08, 0x8E); + idt_set_gate(19, (unsigned)isr19, 0x08, 0x8E); + idt_set_gate(20, (unsigned)isr20, 0x08, 0x8E); + idt_set_gate(21, (unsigned)isr21, 0x08, 0x8E); + idt_set_gate(22, (unsigned)isr22, 0x08, 0x8E); + idt_set_gate(23, (unsigned)isr23, 0x08, 0x8E); - idt_set_gate(24, (unsigned)isr24, 0x08, 0x8E); - idt_set_gate(25, (unsigned)isr25, 0x08, 0x8E); - idt_set_gate(26, (unsigned)isr26, 0x08, 0x8E); - idt_set_gate(27, (unsigned)isr27, 0x08, 0x8E); - idt_set_gate(28, (unsigned)isr28, 0x08, 0x8E); - idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E); - idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E); - idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E); + idt_set_gate(24, (unsigned)isr24, 0x08, 0x8E); + idt_set_gate(25, (unsigned)isr25, 0x08, 0x8E); + idt_set_gate(26, (unsigned)isr26, 0x08, 0x8E); + idt_set_gate(27, (unsigned)isr27, 0x08, 0x8E); + idt_set_gate(28, (unsigned)isr28, 0x08, 0x8E); + idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E); + idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E); + idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E); idt_load(); irq_install(); @@ -139,4 +139,4 @@ void irq_handler(registers_t *r) { outb(0xA0, 0x20); outb(0x20, 0x20); -} \ No newline at end of file +} diff --git a/kernel/kernel.c b/kernel/kernel.c index 291d882..a0b3cd1 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,51 +1,87 @@ +///////////////////////////// +/// /// +/// Team Kitty, 2019 /// +/// ProjectRED /// +/// /// +///////////////////////////// -//#include - -#include +//#include + +#include #include -#include - +#include + +void gdb_end() {} /* GDB Debugging stump */ + int kernel_main(void) { - // Prepare the screen, and blank it out. + /* The kernel is started in 32-bit protected mode by the ASM. */ + /* Here, we start by enabling the screen, then loading a GDT and IDT into the actual places they need to be. */ + + /* Black the screen out. */ screen_initialize(); - // Prepare the serial console. + /* Prepare the serial line for our debug output. */ init_serial(); serial_print(0x3F8, "[INFO] Serial ready.\r\n"); - - // Prepare the GDT - serial_print(0x3F8, "[INFO] Beginning GDT subroutine.\r\n"); + + + serial_print(0x3F8, "[INFO] Beginning GDT subroutine.\r\n"); + + /* term_writes: writes a string to the terminal. */ + term_writes("GDT..."); + + /* Prepares the Global Descriptor Table, called from gdt.c */ gdt_install(); + + /* puts: writes a line to the terminal. */ + puts("GDT Ready."); serial_print(0x3F8, "[INFO] GDT subroutine complete.\r\n"); - // Prepare interrupts + /* Prepare the Interrupt Descriptor Table. */ serial_print(0x3F8, "[INFO] Beginning IDT subroutine.\r\n"); + term_writes("IDT..."); idt_install(); + puts("IDT Ready."); serial_print(0x3F8, "[INFO] IDT subroutine complete.\r\n[INFO] Enabling interrupts.\r\n"); - asm volatile("sti"); + gdb_end(); /* The first important step. Waypoint it for gdb debugging. */ + + term_writes("Memory available:"); + /* TODO: implement check_a20, which double-triple checks the state of the A20 line. */ + + //if(check_a20()) + puts(" 4GB"); + serial_print(0x3F8, "[INFO] A20 enabled. 4GB memory available."); + + /* The first important thing: start the system clock immediately. */ serial_print(0x3F8, "[INFO] Starting System Clock.\r\n"); + term_writes("Timer..."); timer_install(); + puts("Timer Ready."); - serial_print(0x3F8, "[INFO] All subsystems ready. Printing message.\r\n"); - - //Print a copyright message. - term_writes("(c)"); - term_setcolor(GREEN); - term_writes(" Project"); - term_setcolor(RED); - term_writes("RED"); - term_setcolor(WHITE); + serial_print(0x3F8, "[INFO] All subsystems ready. Printing message.\r\n"); + + /* Everything is ready; print a pretty message. */ + term_writes("\n(c)"); + term_setcolor(GREEN); + term_writes(" Project"); + term_setcolor(RED); + term_writes("RED"); + term_setcolor(WHITE); term_writes(", 2019\n"); serial_print(0x3F8, "[INFO] All operations complete. Checking for other tasks...\r\n"); - for(size_t i = 0; i < 3000; i++) {} + /* Here are a series of tests for the ANSI escape code and CSI implementations. */ + term_writes("\x1b[BA"); /* Down a line, then A. */ - serial_print(0x3F8, "[DEBUG] Attempting a Divide by Zero error.\r\n"); - //term_putchar(5/0); - serial_print(0x3F8, "[DEBUG] Survived the error!\r\n"); - - for(;;) {} - return 0; + + /* A stub causing a Divide by Zero error. */ + //serial_print(0x3F8, "[DEBUG] Attempting a Divide by Zero error.\r\n"); + //char div = (5 / 0); + //serial_print(0x3F8, "[DEBUG] Survived the error!\r\n"); + + gdb_end(); /* Everything is done. The last debug routine. */ + return 0; } + diff --git a/kernel/utils.c b/kernel/utils.c index cb70f3d..31bf598 100644 --- a/kernel/utils.c +++ b/kernel/utils.c @@ -23,7 +23,7 @@ void outb(unsigned short port, unsigned char data) { void memcpy(void* dest, void* src, size_t n) { char* src_c = (char*)src; - char* dest_c = (char*)dest; + char* dest_c = (char*)dest; for(size_t i = 0; i < n; i++) { dest_c[i] = src_c[i]; @@ -75,6 +75,18 @@ void int_to_ascii(int num, char* string) { } } +char* itoc(size_t num) { + char* result; + size_t tmp_value; + do { + tmp_value = num; + num /= 10; + *result++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - num * 10)]; + }while (num); + + return result; +} + void int_to_hex(int num, char* string) { empty_string(string); @@ -101,4 +113,4 @@ void empty_string(char* string) { for(size_t i = 0; i < len + 1; i++) { string[i] = '\0'; } -} \ No newline at end of file +}