Fixes and improvements.
Including a new, rewritten and restructured boot.s file, plus automagical Protected Mode.
This commit is contained in:
parent
dbce420e56
commit
022884e20d
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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
|
|
@ -19,3 +19,5 @@ void int_to_ascii(int, char*);
|
|||
void int_to_hex(int, char*);
|
||||
|
||||
void empty_string(char*);
|
||||
|
||||
char* itoc(size_t);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user