fixing the keyboard and bootloader so that its 2 stage again

This commit is contained in:
2025-08-02 20:06:15 -07:00
parent e1e30b511a
commit 267130281a
7 changed files with 411 additions and 53 deletions

View File

@@ -1,67 +1,230 @@
; ==============================================================================
; boot.asm - First Stage Bootloader (CHS Based)
; ==============================================================================
[BITS 16] [BITS 16]
[ORG 0x7C00] [ORG 0x7C00]
start: start:
cli cli ; Disable interrupts
mov [bootdev], dl ; Save boot device number (from BIOS in DL)
; Setup stack safely below EBDA area (choose 0x0000:0x7A00)
xor ax, ax ; AX = 0
mov ss, ax ; Stack segment = 0x0000
mov sp, 0x7A00 ; Stack offset = 0x7A00
; Initialize DS, ES for zero-based segments
xor ax, ax xor ax, ax
mov ds, ax mov ds, ax
mov es, ax mov es, ax
mov ss, ax
mov sp, 0x7C00
; Load second-stage bootloader (boot1.asm) to 0x7E00
mov si, 0x7E00 ; Destination offset (ES already zero, so physical 0x7E00)
mov al, 1 ; Number of sectors to read (adjust if needed)
mov cl, 1 ; Starting sector (CHS - sector number, 1-based)
call read_chs
jc disk_error ; Jump if carry set (read error)
; Load kernel to 0x100000 (1 MB)
mov si, 0x0000 ; Destination offset
mov ax, 0x1000 ; ES = 0x1000 (0x1000:0x0000 = 1 MB)
mov es, ax
xor bx, bx
mov al, 16 ; Number of sectors for kernel (example)
mov cl, 2 ; Starting sector (adjust as per your disk layout)
call read_chs
jc disk_error
; Memory Validation: Verify checksum of second stage bootloader
mov si, 0x7E00 ; Start of second stage
mov cx, 512 ; Size in bytes (adjust if more sectors loaded)
call verify_checksum
jc disk_error ; Jump if checksum fails
; Enable A20 line
call enable_a20 call enable_a20
jc a20_error ; Jump if A20 enable fails
; Setup Global Descriptor Table
call setup_gdt call setup_gdt
; Switch to protected mode and jump to second stage at 0x08:0x7E00
call switch_to_pm call switch_to_pm
; ---------------------- disk_error:
; A20 Gate Enable (Fast method) mov si, disk_error_msg
call print_string_16
jmp halt
a20_error:
mov si, a20_error_msg
call print_string_16
jmp halt
; ----------------------------------------------------------------
; Verify Checksum Routine
; Uses SI = start address, CX = byte count
; Simple XOR checksum over bytes, expects result 0
verify_checksum:
push ax
push bx
push di
mov di, si
xor al, al
xor bx, bx
.verify_loop:
lodsb
xor bl, al
loop .verify_loop
test bl, bl
jz .checksum_ok
stc ; Set carry on checksum error
jmp .done
.checksum_ok:
clc ; Clear carry on success
.done:
pop di
pop bx
pop ax
ret
; ----------------------------------------------------------------
; CHS Disk Read Routine
; AL = number of sectors
; CL = starting sector (1-based)
; SI = destination offset (Segment:ES already set)
read_chs:
pusha
push dx
mov cx, 5
.retry:
mov ah, 0x02 ; BIOS read sector
mov dl, [bootdev] ; Drive number
int 0x13
jc .error ; Carry flag set = error
pop dx
popa
ret
.error:
dec cx
jz disk_error
xor ah, ah
int 0x13
jmp .retry
; ----------------------------------------------------------------
enable_a20: enable_a20:
; Fast A20 gate method
in al, 0x92 in al, 0x92
or al, 0x02 or al, 0x02
out 0x92, al out 0x92, al
; Fallback method (keyboard controller)
jc .fallbackenable_a20:
; Fast A20 method
in al, 0x92
or al, 0x02
and al, 0xFE ; Clear bit 0 to avoid fast A20 issues on some systems
out 0x92, al
; Verify A20
call check_a20
jnc .done
; Fallback method
mov al, 0xAD
out 0x64, al
; ... (rest of keyboard controller code)
.done:
ret ret
; ---------------------- check_a20:
; Set up a minimal GDT in al, 0x64 ; Read keyboard controller status
test al, 0x02 ; Check if input buffer is full
jnz check_a20 ; Wait until empty
mov al, 0xD0 ; Command: read output port
out 0x64, al
.wait_output:
in al, 0x60 ; Read output port value
test al, 0x02 ; Check A20 gate bit (bit 1)
jnz .a20_enabled ; If set, A20 enabled
xor al, al ; Clear carry to indicate failure
stc ; Set carry for failure, jc will jump
ret
.a20_enabled:
clc ; Clear carry flag to indicate success
ret
.fallback:
mov al, 0xAD
out 0x64, al
mov al, 0xD0
out 0x64, al
in al, 0x60
or al, 0x02
mov al, 0xD1
out 0x64, al
mov al, 0xAE
out 0x64, al
ret
; ----------------------------------------------------------------
gdt_start: gdt_start:
dq 0x0000000000000000 ; null descriptor dq 0x0000000000000000 ; Null descriptor
dq 0x00CF9A000000FFFF ; code segment descriptor dq 0x00CF9A000000FFFF ; 32-bit code segment (selector 0x08)
dq 0x00CF92000000FFFF ; data segment descriptor dq 0x00CF92000000FFFF ; 32-bit data segment (selector 0x10)
dq 0x00009A000000FFFF ; 16-bit code segment for real mode (selector 0x18)
gdt_descriptor: gdt_descriptor:
dw gdt_end - gdt_start - 1 ; size of GDT dw gdt_end - gdt_start - 1
dd gdt_start ; address of GDT dd gdt_start
gdt_end: gdt_end:
setup_gdt: setup_gdt:
lgdt [gdt_descriptor] lgdt [gdt_descriptor]
ret ret
; ---------------------- ; ----------------------------------------------------------------
; Switch to Protected Mode
switch_to_pm: switch_to_pm:
cli cli
mov eax, cr0 mov eax, cr0
or eax, 1 or eax, 1
mov cr0, eax mov cr0, eax
jmp 0x08:protected_mode_entry jmp 0x08:0x7E00
; ----------------------
; 32-bit Protected Mode Entry Point
[BITS 32]
protected_mode_entry:
mov ax, 0x10 ; data segment selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x90000
; Kernel is assumed to be loaded at 0x100000 ; ----------------------------------------------------------------
jmp 0x08:0x100000 print_string_16:
.loop:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp .loop
.done:
ret
disk_error_msg db "Disk error!", 0
a20_error_msg db "A20 error!", 0
halt:
cli
hlt
bootdev db 0
sectors_per_track dw 63
heads_per_cylinder dw 255
; ----------------------
; Boot signature
times 510 - ($ - $$) db 0 times 510 - ($ - $$) db 0
dw 0xAA55 dw 0xAA55

Binary file not shown.

182
bootloader/boot1.asm Normal file
View File

@@ -0,0 +1,182 @@
; ==============================================================================
; boot1.asm - Second Stage Bootloader (Fixed Real Mode Transition)
; ==============================================================================
[BITS 32]
global _start
extern kmain
_start:
; Set up segments
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Stack (must be identity-mapped)
mov esp, 0x90000
; CPU Feature Detection: check CPUID support
pushfd ; Save flags
pop eax
mov ecx, eax
xor eax, 1 << 21 ; Flip ID bit
push eax
popfd
pushfd
pop eax
xor eax, ecx
jz .no_cpuid ; CPUID unsupported if no change
; CPUID supported, verify features
mov eax, 1
cpuid
; Check for paging support (bit 31 of edx)
test edx, 1 << 31
jz .no_paging_support
; Additional CPU feature checks could be added here
jmp .cpuid_check_done
.no_cpuid:
mov si, no_cpuid_msg
call print_string_16
jmp halt
.no_paging_support:
mov si, no_paging_msg
call print_string_16
jmp halt
.cpuid_check_done:
; Temporarily switch back to real mode
cli
mov eax, cr0
and eax, 0x7FFFFFFE ; Clear PE & PG bits
mov cr0, eax
jmp 0x18:real_mode_entry
; ----------------------------------------------------------------
[BITS 16]
real_mode_entry:
; Real mode for BIOS access (E820, VESA)
xor ax, ax
mov es, ax
; VESA call
mov di, VbeControllerInfo
mov ax, 0x4F00
int 0x10
jc vesa_error
; E820 memory map
xor ebx, ebx
mov edx, 0x534D4150
mov di, MemoryMapBuffer
mov [MemoryMapEntries], dword 0
.e820_loop:
mov eax, 0xE820
mov ecx, 24
int 0x15
jc e820_error
add di, 24
inc dword [MemoryMapEntries]
test ebx, ebx
jnz .e820_loop
jmp .e820_done
e820_error:
mov si, e820_error_msg
call print_string_16
jmp halt
vesa_error:
mov si, vesa_error_msg
call print_string_16
; Fallback: set VGA text mode 3 and continue
mov ah, 0x00 ; BIOS Set Video Mode function
mov al, 0x03 ; VGA 80x25 text mode
int 0x10
; Clear screen
mov ah, 0x06 ; Scroll up function
mov al, 0 ; Clear entire screen
mov bh, 0x07 ; Text attribute (gray on black)
mov cx, 0 ; Upper-left corner
mov dx, 0x184F ; Lower-right corner
int 0x10
jmp .e820_done ; Continue booting without VESA graphics
.e820_done:
; Back to protected mode
cli
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:protected_entry
; ----------------------------------------------------------------
print_string_16:
.loop:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp .loop
.done:
ret
e820_error_msg db "E820 Failed!", 0
vesa_error_msg db "VESA Failed!", 0
no_cpuid_msg db "No CPUID support detected!", 0
no_paging_msg db "CPU lacks paging support!", 0
; ----------------------------------------------------------------
[BITS 32]
protected_entry:
; Paging setup
xor eax, eax
mov edi, page_directory
mov ecx, 1024
rep stosd
mov edi, page_table
rep stosd
mov dword [page_directory], page_table | 0x3
mov ecx, 1024
mov edi, page_table
mov eax, 0x00000003
.fill_pages:
mov [edi], eax
add eax, 0x1000
add edi, 4
loop .fill_pages
mov eax, page_directory
mov cr3, eax
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
jmp kmain
; ----------------------------------------------------------------
; Data buffers and variables must be appropriately defined in your data section
MemoryMapBuffer times 128 db 0 ; 128*24 bytes reserved for E820 memory map (adjust size as needed)
MemoryMapEntries dd 0
VbeControllerInfo times 512 db 0 ; Buffer for VESA controller info (adjust size as needed)
; Define page directory and page table aligned as needed (in your data section)
align 4096
page_directory times 1024 dd 0
align 4096
page_table times 1024 dd 0

View File

@@ -1,10 +1,9 @@
ENTRY(start) ENTRY(kmain)
SECTIONS { SECTIONS {
. = 1M; . = 1M;
.text : { .text : {
*(.multiboot)
*(.text*) *(.text*)
} }

View File

@@ -20,34 +20,40 @@ static const char scancode_map[128] = {
}; };
// Interrupt handler for IRQ1 // Interrupt handler for IRQ1
void keyboard_callback() { void keyboard_callback(void) {
uint8_t scancode = inb(KEYBOARD_DATA_PORT); uint8_t scancode = inb(0x60);
// Ignore key releases (scancodes with high bit set)
if (scancode & 0x80)
return;
// Only handle key press (ignore key release)
if (!(scancode & 0x80)) {
char c = scancode_map[scancode]; char c = scancode_map[scancode];
if (c && buffer_index < sizeof(key_buffer) - 1) { if (c && buffer_index < sizeof(key_buffer) - 1) {
key_buffer[buffer_index++] = c; key_buffer[buffer_index++] = c;
terminal_putchar(c); // Echo to terminal (optional) terminal_putchar(c);
} }
} }
// Send End of Interrupt (EOI) to the PIC
outb(0x20, 0x20);
}
void keyboard_init() { void keyboard_init() {
register_interrupt_handler(33, keyboard_callback); // IRQ1 = int 33 (0x21) register_interrupt_handler(33, keyboard_callback); // IRQ1 = int 33 (0x21)
} }
// Blocking read (returns one char) // Blocking read (returns one char)
char keyboard_get_char() { char keyboard_get_char() {
while (buffer_index == 0); while (buffer_index == 0); // Busy wait
char c = key_buffer[0];
// Shift buffer left char c;
__asm__ __volatile__("cli");
c = key_buffer[0];
for (uint8_t i = 1; i < buffer_index; i++) { for (uint8_t i = 1; i < buffer_index; i++) {
key_buffer[i - 1] = key_buffer[i]; key_buffer[i - 1] = key_buffer[i];
} }
buffer_index--; buffer_index--;
__asm__ __volatile__("sti");
return c; return c;
} }

View File

@@ -11,6 +11,7 @@
#include "kmalloc.h" #include "kmalloc.h"
#include "timer.h" #include "timer.h"
#include "utils.h" #include "utils.h"
#include "keyboard.h"
#define LPT1 0x378 #define LPT1 0x378
@@ -54,6 +55,10 @@ void kmain(void) {
timer_init(100); // 100 Hz (10 ms interval) timer_init(100); // 100 Hz (10 ms interval)
serial_write("Timer initialized.\n"); serial_write("Timer initialized.\n");
terminal_write("Initializing keyboard...\n");
keyboard_init();
serial_write("Keyboard initialized.\n");
terminal_write("Getting memory map...\n"); terminal_write("Getting memory map...\n");
memory_map_entry_t mmap[32]; memory_map_entry_t mmap[32];
uint32_t mmap_size = get_memory_map(mmap, 32); uint32_t mmap_size = get_memory_map(mmap, 32);

View File

@@ -4,17 +4,20 @@
#include "terminal.h" #include "terminal.h"
#include "stdio.h" #include "stdio.h"
static uint32_t tick = 0; static volatile uint32_t tick = 0;
void timer_callback(void) { void timer_callback(void) {
tick++; tick++;
// Print every 100 ticks for debugging purposes
if (tick % 100 == 0) { if (tick % 100 == 0) {
char tick_msg[50]; char buf[16];
snprintf(tick_msg, sizeof(tick_msg), "Tick count: %u\n", tick); itoa(tick, buf, 10);
terminal_write(tick_msg); terminal_write("Tick count: ");
terminal_write(buf);
terminal_write("\n");
} }
outb(0x20, 0x20); // EOI to PIC
} }
void timer_init(uint32_t frequency) { void timer_init(uint32_t frequency) {