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]
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:

View File

@ -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) {

View File

@ -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

View File

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

View File

@ -1,3 +1,9 @@
/////////////////////////////
/// ///
/// Team Kitty, 2019 ///
/// ProjectRED ///
/// ///
/////////////////////////////
//#include <stdio.h>
@ -5,32 +11,58 @@
#include <kernel/descriptor_tables.h>
#include <kernel/serial.h>
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");
/* 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)");
/* Everything is ready; print a pretty message. */
term_writes("\n(c)");
term_setcolor(GREEN);
term_writes(" Project");
term_setcolor(RED);
@ -40,12 +72,16 @@ int kernel_main(void) {
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;
}

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) {
empty_string(string);