From 3bd026ca7a35ef4ea60061080be3f8aafc64db83 Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Wed, 19 Nov 2025 20:11:50 +0000 Subject: [PATCH] Feat: Kernel up and running. --- build.sh | 33 ++++++---- elevator.asm | 179 +++++++++++++++++++++++++++++++++++++++++++++++---- kernel.c | 2 +- 3 files changed, 189 insertions(+), 25 deletions(-) diff --git a/build.sh b/build.sh index 7281593..e8593ba 100755 --- a/build.sh +++ b/build.sh @@ -13,32 +13,40 @@ BLUE='\033[0;34m' YELLOW='\033[1;33m' NC='\033[0m' +# Prepare build environment +echo -e "Preparing build environment...${NC}" +echo -e "Creating Folders${NC}" +mkdir -p bin obj boot include +echo -e "${GREEN}✓ ${NC}Folders created.${NC}" + # Step 1: Assemble Stage 1 bootloader (MBR - 512 bytes) echo -e "${BLUE}[1/6]${NC} Assembling Stage 1 bootloader (MBR)..." -nasm -f bin boot.asm -o boot.bin +nasm -f bin ./boot/boot.asm -o ./bin/boot.bin # Step 2: Assemble Stage 2 bootloader (extended loader) echo -e "${BLUE}[2/6]${NC} Assembling Stage 2 bootloader..." -nasm -f bin elevator.asm -o elevator.bin +nasm -f bin ./boot/elevator.asm -o ./bin/elevator.bin # Step 3: Assemble kernel entry point echo -e "${BLUE}[3/6]${NC} Assembling kernel entry..." -nasm -f elf64 kernel.asm -o kernel.asm.o +nasm -f elf64 kernel.asm -o ./obj/kernel.asm.o # Step 4: Compile kernel C code echo -e "${BLUE}[4/6]${NC} Compiling kernel..." -gcc -ffreestanding -c kernel.c -o kernel.c.o -mcmodel=large -mno-red-zone -fno-pic -fno-pie -static -fno-stack-protector -nostdlib -mno-mmx -mno-sse -mno-sse2 -m64 +gcc -ffreestanding -c kernel.c -o ./obj/kernel.c.o -mcmodel=large -mno-red-zone -fno-pic -fno-pie -static -fno-stack-protector -nostdlib -mno-mmx -mno-sse -mno-sse2 -m64 # Step 5: Link kernel echo -e "${BLUE}[5/6]${NC} Linking kernel..." -ld -T linker.ld -o kernel.bin kernel.asm.o kernel.c.o --oformat binary +ld -T linker.ld -o ./bin/kernel.bin ./obj/kernel.asm.o ./obj/kernel.c.o --oformat binary --nostdlib # Step 6: Create OS image echo -e "${BLUE}[6/6]${NC} Creating OS image..." -cat boot.bin elevator.bin kernel.bin > os-image.bin +cat ./bin/boot.bin ./bin/elevator.bin ./bin/kernel.bin > os.bin # Pad to floppy size (1.44MB) -truncate -s 1440K os-image.bin +# FIX: Uncomment the line below if you want to ensure the image is exactly 1.44MB +# +# truncate -s 1440K os-image.bin echo "" echo -e "${GREEN}✓ Build complete!${NC}" @@ -55,17 +63,18 @@ echo "" echo "File Sizes:" printf "%-15s %10s\n" "File" "Size" printf "%-15s %10s\n" "----" "----" -printf "%-15s %10d bytes\n" "boot.bin" $(stat -f%z boot.bin 2>/dev/null || stat -c%s stage1.bin 2>/dev/null) -printf "%-15s %10d bytes\n" "elevator.bin" $(stat -f%z elevator.bin 2>/dev/null || stat -c%s stage2.bin 2>/dev/null) -printf "%-15s %10d bytes\n" "kernel.bin" $(stat -f%z kernel.bin 2>/dev/null || stat -c%s kernel.bin 2>/dev/null) -printf "%-15s %10d bytes\n" "os-image.bin" $(stat -f%z os-image.bin 2>/dev/null || stat -c%s os-image.bin 2>/dev/null) +printf "%-15s %10d bytes\n" "boot.bin" $(stat -f%z ./bin/boot.bin 2>/dev/null || stat -c%s ./bin/boot.bin 2>/dev/null) +printf "%-15s %10d bytes\n" "elevator.bin" $(stat -f%z ./bin/elevator.bin 2>/dev/null || stat -c%s ./bin/elevator.bin 2>/dev/null) +printf "%-15s %10d bytes\n" "kernel.bin" $(stat -f%z ./bin/kernel.bin 2>/dev/null || stat -c%s ./bin/kernel.bin 2>/dev/null) +printf "%-15s %10d bytes\n" "os.bin" $(stat -f%z os.bin 2>/dev/null || stat -c%s os.bin 2>/dev/null) echo "" echo -e "${YELLOW}Running QEMU...${NC}" echo "===================================" echo "Press Ctrl+C to exit QEMU" echo "" -qemu-system-x86_64 -drive format=raw,file=os-image.bin -no-reboot -d cpu_reset + +qemu-system-x86_64 -drive format=raw,file=os.bin -no-reboot echo -e "${GREEN}Done!${NC}" diff --git a/elevator.asm b/elevator.asm index faada1a..304f0ee 100644 --- a/elevator.asm +++ b/elevator.asm @@ -2,12 +2,12 @@ ; Stage 2 Bootloader - No size limit! ; Job: Load kernel, set up GDT, switch to 64-bit mode, jump to kernel + [org 0x7e00] [bits 16] KERNEL_OFFSET equ 0x10000 ; Load kernel at 64KB (safer than 0x1000) BOOT_DRIVE: db 0 ; Store boot drive number -ERROR_CODE: db 0 ; Store error code from disk read stage2_start: ; Print stage 2 message @@ -36,12 +36,32 @@ stage2_start: call print_string pop ax + push ax call print_hex_word ; Print the word we read - ; If it's 0x0000, kernel didn't load + ; Also check bytes 2-3 + mov ax, 0x1000 + mov es, ax + mov bx, 2 + mov ax, [es:bx] + xor bx, bx + mov es, bx + + mov si, msg_space + call print_string + call print_hex_word + + ; Check if first word is non-zero + pop ax test ax, ax - jz kernel_load_failed + jnz .kernel_found + + ; Kernel is zeros - try reading from different LBA offsets + mov si, msg_searching + call print_string + jmp kernel_load_failed +.kernel_found: mov si, msg_kernel_ok call print_string @@ -67,6 +87,44 @@ load_kernel: push bx push cx push dx + push si + + ; Show what we're about to do + mov si, msg_loading_kernel + call print_string + + ; Check if LBA is available + mov ah, 0x41 + mov bx, 0x55AA + mov dl, [BOOT_DRIVE] + int 0x13 + jc .use_chs ; If carry set, LBA not supported + + ; Use LBA mode + mov si, msg_using_lba + call print_string + + ; Set up DAP (Disk Address Packet) + mov word [dap_size], 0x10 + mov word [dap_sectors], 10 + mov word [dap_offset], 0x0000 + mov word [dap_segment], 0x1000 + mov dword [dap_lba_low], 6 ; LBA 6 = bytes 3072+ (sector 7 in CHS) + mov dword [dap_lba_high], 0 + + ; Read using LBA + mov ah, 0x42 + mov dl, [BOOT_DRIVE] + mov si, dap + int 0x13 + jc kernel_error + + jmp .read_done + +.use_chs: + ; Fall back to CHS mode + mov si, msg_using_chs + call print_string ; Reset disk system first mov ah, 0x00 @@ -74,32 +132,51 @@ load_kernel: int 0x13 ; Set up ES:BX for the destination - ; KERNEL_OFFSET is 0x10000, so we need ES=0x1000, BX=0x0000 mov ax, 0x1000 mov es, ax - xor bx, bx ; BX = 0, so ES:BX = 0x1000:0x0000 = 0x10000 + xor bx, bx - ; Now try loading kernel + ; Read using CHS mov ah, 0x02 ; Read function mov al, 10 ; Number of sectors mov ch, 0 ; Cylinder 0 - mov cl, 7 ; Start at sector 7 + mov cl, 7 ; Sector 7 mov dh, 0 ; Head 0 mov dl, [BOOT_DRIVE] ; Drive number int 0x13 jc kernel_error + +.read_done: + ; Print success + mov si, msg_sectors_read + call print_string + + mov si, msg_newline + call print_string ; Restore ES to 0 xor ax, ax mov es, ax + pop si pop dx pop cx pop bx pop ax ret +; Disk Address Packet for LBA +align 4 +dap: +dap_size: db 0x10 +dap_reserved: db 0 +dap_sectors: dw 0 +dap_offset: dw 0 +dap_segment: dw 0 +dap_lba_low: dd 0 +dap_lba_high: dd 0 + kernel_error: ; Restore ES xor ax, ax @@ -131,10 +208,73 @@ kernel_load_failed: xor ax, ax mov es, ax + ; Kernel is zeros at expected location + ; Let's try reading from different LBA sectors to find it mov si, msg_verify_failed call print_string + + ; Try LBA 5 + mov si, msg_try_lba5 + call print_string + mov word [dap_lba_low], 5 + call try_read_kernel + + ; Try LBA 7 + mov si, msg_try_lba7 + call print_string + mov word [dap_lba_low], 7 + call try_read_kernel + + ; Try LBA 8 + mov si, msg_try_lba8 + call print_string + mov word [dap_lba_low], 8 + call try_read_kernel + jmp $ +try_read_kernel: + push si + ; Read to 0x10000 + mov ax, 0x1000 + mov es, ax + mov word [dap_segment], ax + + mov ah, 0x42 + mov dl, [BOOT_DRIVE] + mov si, dap + int 0x13 + + ; Check what we got + xor bx, bx + mov ax, [es:bx] + + xor cx, cx + mov es, cx + + call print_hex_word + mov si, msg_newline + call print_string + + ; If non-zero, we found it! + test ax, ax + jz .not_found + + mov si, msg_found + call print_string + + ; Jump directly to protected mode! + cli + lgdt [gdt_descriptor] + mov eax, cr0 + or eax, 0x1 + mov cr0, eax + jmp 0x08:protected_mode + +.not_found: + pop si + ret + ; ============================================================ ; PRINT STRING (16-bit) ; ============================================================ @@ -195,11 +335,23 @@ print_hex_word: msg_stage2: db '[STAGE2] Extended bootloader loaded', 0x0D, 0x0A, 0 msg_kernel_loaded: db '[STAGE2] Kernel loaded, switching to Protected Mode...', 0x0D, 0x0A, 0 msg_kernel_error: db '[ERROR] Kernel load failed!', 0x0D, 0x0A, 0 -msg_kernel_check: db '[STAGE2] Verifying kernel load: Read word = 0x', 0 -msg_kernel_ok: db '[STAGE2] Kernel load verified.', 0x0D, 0x0A, 0 -msg_verify_failed: db '[ERROR] Kernel verification failed!', 0x0D, 0x0A, 0 -msg_error_code: db ' Error code: 0x', 0 -msg_drive: db ' Drive number: 0x', 0 +msg_error_code: db ' Error code: ', 0 +msg_drive: db ' Drive: ', 0 +msg_loading_kernel: db '[STAGE2] Loading kernel from disk...', 0x0D, 0x0A, 0 +msg_using_lba: db '[STAGE2] Using LBA mode for disk access', 0x0D, 0x0A, 0 +msg_using_chs: db '[STAGE2] Using CHS mode for disk access', 0x0D, 0x0A, 0 +msg_sectors_read: db '[STAGE2] Sectors read successfully', 0 +msg_newline: db 0x0D, 0x0A, 0 +msg_kernel_check: db '[STAGE2] Verifying kernel load: Read words: ', 0 +msg_space: db ' ', 0 +msg_searching: db '[STAGE2] Kernel not found, searching alternative sectors...', 0x0D, 0x0A, 0 +msg_kernel_ok: db '[STAGE2] Kernel verification successful!', 0x0D, 0x0A, 0 +msg_verify_failed: db '[STAGE2] Kernel verification failed.', 0x0D, 0x0A, 0 +msg_try_lba5: db '[STAGE2] Trying LBA 5...', 0x0D, 0x0A, 0 +msg_try_lba7: db '[STAGE2] Trying LBA 7...', 0x0D, 0x0A, 0 +msg_try_lba8: db '[STAGE2] Trying LBA 8...', 0x0D, 0x0A, 0 +msg_found: db '[STAGE2] Kernel found!', 0x0D, 0x0A, 0 +ERROR_CODE: db 0 ; ============================================================ ; GDT - Global Descriptor Table @@ -488,3 +640,6 @@ print_64: lm_msg: db '[64-BIT] Long mode active...', 0 before_kernel_msg: db '[64-BIT] Calling kernel...', 0 kernel_return_msg: db '[KERNEL] Returned unexpectedly!', 0 + +; Add pading to make the elevator 2560 bytes. +times 2560 - ($ - $$) db 0 diff --git a/kernel.c b/kernel.c index 9183f3b..e8c4e6d 100644 --- a/kernel.c +++ b/kernel.c @@ -33,7 +33,7 @@ void kmain(void) { // Write messages write_string(10, 30, "SORA OS KERNEL", 0x0A); // Green write_string(12, 25, "64-bit kernel running!", 0x0F); // White - write_string(14, 28, "System Initialized", 0x0E); // Yellow + write_string(14, 28, "System Initialized", 0x0E); // Yellow // Infinite loop while (1) {