Fixes and improvements.

Including a new, rewritten and restructured boot.s file, plus automagical Protected Mode.
This commit is contained in:
Curle 2019-06-25 22:31:26 +01:00
parent dbce420e56
commit 022884e20d
7 changed files with 177 additions and 89 deletions

View File

@ -1,12 +1,12 @@
[BITS 32] [BITS 32] ;... somehow.
[GLOBAL start] [GLOBAL start]
start: start:
mov esp, _sys_stack mov esp, _sys_stack ; Stack pointer!
jmp stublet jmp stublet ; This has a purpse. I don't know what it is, but there is one.
ALIGN 4 ALIGN 4 ; 4KB alignment, required by GRUB.
mboot: mboot: ; This is all magic, and all of it required for GRUB to see our stuff.
MULTIBOOT_ALIGN equ 1<<0 MULTIBOOT_ALIGN equ 1<<0
MULTIBOOT_MEM equ 1<<1 MULTIBOOT_MEM equ 1<<1
MULTIBOOT_AOUT equ 1<<16 MULTIBOOT_AOUT equ 1<<16
@ -25,23 +25,60 @@ mboot:
dd end dd end
dd start 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 EXTERN kernel_main
call kernel_main call kernel_main
jmp $ jmp $
[GLOBAL load_gdt] ; Allows the C code to call gdt_flush(). [GLOBAL load_gdt]
[EXTERN gp] [EXTERN gp]
load_gdt: load_gdt:
lgdt [gp] ; Load the new GDT pointer lgdt [gp] ; Load the new GDT pointer
mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment mov ax, 0x10
mov ds, ax ; Load all data segment selectors mov ds, ax
mov es, ax mov es, ax
mov fs, ax mov fs, ax
mov gs, ax mov gs, ax
mov ss, ax mov ss, ax
jmp 0x08:flush ; 0x08 is the offset to our code segment: Far jump! jmp 0x08:flush
flush: flush:
ret ret
@ -121,7 +158,7 @@ IRQ 13, 45
IRQ 14, 46 IRQ 14, 46
IRQ 15, 47 IRQ 15, 47
extern fault_handler [EXTERN fault_handler]
isr_common: isr_common:
pusha pusha
@ -149,7 +186,7 @@ isr_common:
add esp, 8 add esp, 8
iret iret
extern irq_handler [EXTERN irq_handler]
irq_common: irq_common:
pusha pusha
@ -176,11 +213,12 @@ irq_common:
iret iret
[GLOBAL idt_load] [GLOBAL idt_load]
[EXTERN idtp]
idt_load: idt_load:
mov eax, [esp+4]
lidt [eax] lidt [eax]
ret ret
SECTION .bss SECTION .bss
resb 8192 resb 8192
_sys_stack: _sys_stack:

View File

@ -14,7 +14,7 @@ static size_t terminal_column;
static uint8_t current_color; static uint8_t current_color;
static uint16_t* term_buffer; 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) { void screen_initialize(void) {

View File

@ -22,8 +22,8 @@ enum vga_colors {
WHITE = 15 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 #endif

View File

@ -19,3 +19,5 @@ void int_to_ascii(int, char*);
void int_to_hex(int, char*); void int_to_hex(int, char*);
void empty_string(char*); void empty_string(char*);
char* itoc(size_t);

View File

@ -38,40 +38,40 @@ void idt_install() {
memset(&idt, 0, sizeof(struct idt_entry) * 256); memset(&idt, 0, sizeof(struct idt_entry) * 256);
idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E); idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E);
idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E); idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E);
idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E); idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E);
idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E); idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E);
idt_set_gate(4, (unsigned)isr4, 0x08, 0x8E); idt_set_gate(4, (unsigned)isr4, 0x08, 0x8E);
idt_set_gate(5, (unsigned)isr5, 0x08, 0x8E); idt_set_gate(5, (unsigned)isr5, 0x08, 0x8E);
idt_set_gate(6, (unsigned)isr6, 0x08, 0x8E); idt_set_gate(6, (unsigned)isr6, 0x08, 0x8E);
idt_set_gate(7, (unsigned)isr7, 0x08, 0x8E); idt_set_gate(7, (unsigned)isr7, 0x08, 0x8E);
idt_set_gate(8, (unsigned)isr8, 0x08, 0x8E); idt_set_gate(8, (unsigned)isr8, 0x08, 0x8E);
idt_set_gate(9, (unsigned)isr9, 0x08, 0x8E); idt_set_gate(9, (unsigned)isr9, 0x08, 0x8E);
idt_set_gate(10, (unsigned)isr10, 0x08, 0x8E); idt_set_gate(10, (unsigned)isr10, 0x08, 0x8E);
idt_set_gate(11, (unsigned)isr11, 0x08, 0x8E); idt_set_gate(11, (unsigned)isr11, 0x08, 0x8E);
idt_set_gate(12, (unsigned)isr12, 0x08, 0x8E); idt_set_gate(12, (unsigned)isr12, 0x08, 0x8E);
idt_set_gate(13, (unsigned)isr13, 0x08, 0x8E); idt_set_gate(13, (unsigned)isr13, 0x08, 0x8E);
idt_set_gate(14, (unsigned)isr14, 0x08, 0x8E); idt_set_gate(14, (unsigned)isr14, 0x08, 0x8E);
idt_set_gate(15, (unsigned)isr15, 0x08, 0x8E); idt_set_gate(15, (unsigned)isr15, 0x08, 0x8E);
idt_set_gate(16, (unsigned)isr16, 0x08, 0x8E); idt_set_gate(16, (unsigned)isr16, 0x08, 0x8E);
idt_set_gate(17, (unsigned)isr17, 0x08, 0x8E); idt_set_gate(17, (unsigned)isr17, 0x08, 0x8E);
idt_set_gate(18, (unsigned)isr18, 0x08, 0x8E); idt_set_gate(18, (unsigned)isr18, 0x08, 0x8E);
idt_set_gate(19, (unsigned)isr19, 0x08, 0x8E); idt_set_gate(19, (unsigned)isr19, 0x08, 0x8E);
idt_set_gate(20, (unsigned)isr20, 0x08, 0x8E); idt_set_gate(20, (unsigned)isr20, 0x08, 0x8E);
idt_set_gate(21, (unsigned)isr21, 0x08, 0x8E); idt_set_gate(21, (unsigned)isr21, 0x08, 0x8E);
idt_set_gate(22, (unsigned)isr22, 0x08, 0x8E); idt_set_gate(22, (unsigned)isr22, 0x08, 0x8E);
idt_set_gate(23, (unsigned)isr23, 0x08, 0x8E); idt_set_gate(23, (unsigned)isr23, 0x08, 0x8E);
idt_set_gate(24, (unsigned)isr24, 0x08, 0x8E); idt_set_gate(24, (unsigned)isr24, 0x08, 0x8E);
idt_set_gate(25, (unsigned)isr25, 0x08, 0x8E); idt_set_gate(25, (unsigned)isr25, 0x08, 0x8E);
idt_set_gate(26, (unsigned)isr26, 0x08, 0x8E); idt_set_gate(26, (unsigned)isr26, 0x08, 0x8E);
idt_set_gate(27, (unsigned)isr27, 0x08, 0x8E); idt_set_gate(27, (unsigned)isr27, 0x08, 0x8E);
idt_set_gate(28, (unsigned)isr28, 0x08, 0x8E); idt_set_gate(28, (unsigned)isr28, 0x08, 0x8E);
idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E); idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E);
idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E); idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E); idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
idt_load(); idt_load();
irq_install(); irq_install();

View File

@ -1,3 +1,9 @@
/////////////////////////////
/// ///
/// Team Kitty, 2019 ///
/// ProjectRED ///
/// ///
/////////////////////////////
//#include <stdio.h> //#include <stdio.h>
@ -5,32 +11,58 @@
#include <kernel/descriptor_tables.h> #include <kernel/descriptor_tables.h>
#include <kernel/serial.h> #include <kernel/serial.h>
void gdb_end() {} /* GDB Debugging stump */
int kernel_main(void) { 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(); screen_initialize();
// Prepare the serial console. /* Prepare the serial line for our debug output. */
init_serial(); init_serial();
serial_print(0x3F8, "[INFO] Serial ready.\r\n"); 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(); gdt_install();
/* puts: writes a line to the terminal. */
puts("GDT Ready.");
serial_print(0x3F8, "[INFO] GDT subroutine complete.\r\n"); 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"); serial_print(0x3F8, "[INFO] Beginning IDT subroutine.\r\n");
term_writes("IDT...");
idt_install(); idt_install();
puts("IDT Ready.");
serial_print(0x3F8, "[INFO] IDT subroutine complete.\r\n[INFO] Enabling interrupts.\r\n"); 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"); serial_print(0x3F8, "[INFO] Starting System Clock.\r\n");
term_writes("Timer...");
timer_install(); timer_install();
puts("Timer Ready.");
serial_print(0x3F8, "[INFO] All subsystems ready. Printing message.\r\n"); serial_print(0x3F8, "[INFO] All subsystems ready. Printing message.\r\n");
//Print a copyright message. /* Everything is ready; print a pretty message. */
term_writes("(c)"); term_writes("\n(c)");
term_setcolor(GREEN); term_setcolor(GREEN);
term_writes(" Project"); term_writes(" Project");
term_setcolor(RED); term_setcolor(RED);
@ -40,12 +72,16 @@ int kernel_main(void) {
serial_print(0x3F8, "[INFO] All operations complete. Checking for other tasks...\r\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(;;) {} /* 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; return 0;
} }

View File

@ -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) { void int_to_hex(int num, char* string) {
empty_string(string); empty_string(string);