From 9e4224793bb4eed7491fc7cb959133dd34fee2f9 Mon Sep 17 00:00:00 2001 From: AfonsoCMSousa Date: Tue, 18 Nov 2025 22:58:28 +0000 Subject: [PATCH] Feat: CPU Exceptions and load errors are now shown. --- SoraOS | Bin 522 -> 0 bytes boot.asm | 257 +++++++-------------------- build.sh | 75 +++++++- elevator.asm | 490 +++++++++++++++++++++++++++++++++++++++++++++++++++ kernel.asm | 15 ++ kernel.c | 51 ++++-- linker.ld | 42 ++--- 7 files changed, 692 insertions(+), 238 deletions(-) delete mode 100755 SoraOS create mode 100644 elevator.asm create mode 100644 kernel.asm diff --git a/SoraOS b/SoraOS deleted file mode 100755 index 01961b6b991fb442f648b025e7378c592e1bff9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 522 zcmYk1JxBs!7{{Nx{35mYh@!!U7onk{BTSmp5{?$lqYnrR1y3C6BuBWS$<(EY$h}$9P;yC2cN_VW_07u6BgjRR^tS?XO30Ghj623 zXjEB`_#39ZBjN&>b^$FG=pmC-$3yk!A+rNGhl)k*iCsQNWliEkXtVf0iNASU05C|v zi@yeBnoz@w-2(9&Z^O9Yg4pWH4Y@opG>=j`f`S{0Cjb7ivAI@PssiW@-O!u5r9W1K zJb+ZPP0a1Pu|8XP4?dTr(yL@fT5M4|jkB%x~qGr>S%{$PTcDUjxR9ssI20 diff --git a/boot.asm b/boot.asm index 0a3f2ba..145b349 100644 --- a/boot.asm +++ b/boot.asm @@ -1,221 +1,94 @@ ; File: boot.asm -[org 0x7c00] ; BIOS loads us at 0x7C00 -[bits 16] ; We start in 16-bit Real Mode +; Stage 1 Bootloader (Master Boot Record - exactly 512 bytes) +; Job: Load Stage 2 from disk and jump to it + +[org 0x7c00] +[bits 16] + +STAGE2_OFFSET equ 0x7e00 ; Load stage2 right after boot sector start: + ; Set up segments xor ax, ax mov ds, ax mov es, ax mov ss, ax mov sp, 0x7c00 + + ; IMPORTANT: Save boot drive number (BIOS passes it in DL) + push dx + ; Clear screen mov ah, 0x00 mov al, 0x03 - int 0x10 + int 0x10 - mov si, real_msg + ; Print loading message + mov si, msg_loading call print_string - cli + ; Load Stage 2 from disk + ; Read 5 sectors (sectors 2-6) - gives us 2.5KB for Stage 2 + pop dx ; Restore boot drive + push dx ; Save it again for stage 2 + mov bx, STAGE2_OFFSET ; Destination + mov dh, 5 ; Number of sectors + ; DL already has drive number + call load_disk - lgdt [gdt_descriptor] + ; Jump to Stage 2 (DL still has boot drive number) + pop dx ; Pass drive number to stage 2 in DL + jmp STAGE2_OFFSET + +; ============================================================ +; LOAD DISK - Read sectors using BIOS INT 0x13 +; ============================================================ +load_disk: + push dx - mov eax, cr0 - or eax, 0x1 - mov cr0, eax + mov ah, 0x02 ; Read function + mov al, dh ; Number of sectors + mov ch, 0 ; Cylinder 0 + mov cl, 2 ; Start at sector 2 + mov dh, 0 ; Head 0 + + int 0x13 + jc disk_error + + pop dx + cmp al, dh + jne disk_error + ret - ; Far jump into 32-bit mode. - jmp 0x08:init_pm +disk_error: + mov si, msg_error + call print_string + jmp $ -; --- Helper: Print String (BIOS INT 0x10) --- +; ============================================================ +; PRINT STRING +; ============================================================ print_string: pusha - mov ah, 0x0e ; INT 0x10 "Teletype Output" function + mov ah, 0x0e .loop: - lodsb ; Load byte at [SI] into AL, increment SI - cmp al, 0 ; Check for null terminator - je .done - int 0x10 ; Call BIOS video interrupt + lodsb + test al, al + jz .done + int 0x10 jmp .loop .done: popa ret -real_msg: db '[REAL] - Loaded successfully.', 0x0D, 0x0A, 0 +; ============================================================ +; DATA +; ============================================================ +msg_loading: db '[STAGE1] Loading SoraOS...', 0x0D, 0x0A, 0 +msg_error: db '[ERROR] Disk read failed!', 0x0D, 0x0A, 0 -; --- GDT (Global Descriptor Table) --- -align 8 -gdt_start: - -gdt_null: - dq 0x0 - -gdt_code32: ; 32-bit code segment (selector 0x08) - dw 0xffff ; Limit 0:15 - dw 0x0000 ; Base 0:15 - db 0x00 ; Base 16:23 - db 10011010b ; Access: present, ring 0, code, executable, readable - db 11001111b ; Flags: 4KB granularity, 32-bit | Limit 16:19 - db 0x00 ; Base 24:31 - -gdt_data32: ; 32-bit data segment (selector 0x10) - dw 0xffff - dw 0x0000 - db 0x00 - db 10010010b ; Access: present, ring 0, data, writable - db 11001111b - db 0x00 - -gdt_code64: ; 64-bit code segment (selector 0x18) - dw 0xffff - dw 0x0000 - db 0x00 - db 10011010b ; Access: present, ring 0, code, executable, readable - db 10101111b ; Flags: 4KB granularity, 64-bit, limit 16:19 - db 0x00 - -gdt_data64: ; 64-bit data segment (selector 0x20) - dw 0xffff - dw 0x0000 - db 0x00 - db 10010010b - db 10101111b - db 0x00 - -gdt_end: - -gdt_descriptor: - dw gdt_end - gdt_start - 1 - dd gdt_start - -; ================================================== -; 32-BIT PROTECTED MODE -; ================================================== -[bits 32] -init_pm: - ; Set up segments - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - mov esp, 0x90000 - - ; Print message in Protected Mode - ; Print to VGA memory - mov edi, 0xb8000 - mov al, 'P' - mov ah, 0x0f - mov [edi], ax - add edi, 2 - mov al, 'M' - mov [edi], ax - add edi, 2 - mov al, '3' - mov [edi], ax - add edi, 2 - mov al, '2' - mov [edi], ax - - ; Set up page tables for identity mapping first 2MB - ; PML4[0] -> PDPT - mov edi, 0x1000 - mov dword [edi], 0x2003 ; Present, Writable, points to 0x2000 - add edi, 4 - mov dword [edi], 0 - - ; PDPT[0] -> PD - mov edi, 0x2000 - mov dword [edi], 0x3003 ; Present, Writable, points to 0x3000 - add edi, 4 - mov dword [edi], 0 - - ; PD[0] -> 2MB page at physical 0x0 - mov edi, 0x3000 - mov dword [edi], 0x83 ; Present, Writable, Page Size (2MB) - add edi, 4 - mov dword [edi], 0 - - ; Load CR3 with PML4 address - mov eax, 0x1000 - mov cr3, eax - - ; Enable PAE (Physical Address Extension) - mov eax, cr4 - or eax, 0x20 - mov cr4, eax - - ; Enable Long Mode in EFER MSR - mov ecx, 0xC0000080 - rdmsr - or eax, 0x100 - wrmsr - - ; Enable Paging (activates Long Mode) - mov eax, cr0 - or eax, 0x80000000 - mov cr0, eax - - ; Far jump to 64-bit code - jmp 0x18:long_mode_start - - jmp $ - -; --- 64-bit Long Mode --- -[bits 64] -long_mode_start: - ; Set up segments (most are ignored in 64-bit mode) - mov ax, 0x20 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - ; Set up stack - mov rsp, 0x90000 - - ; Clear screen and print "SORA OS 64" - mov rdi, 0xb8000 - mov rcx, 80*25 - mov ax, 0x0f20 ; White space - rep stosw - - ; Print message - mov rdi, 0xb8000 - mov rsi, long_msg - call print_string_64 - - ; Hang - jmp $ - -; --- 64-bit Print String --- -print_string_64: - mov ah, 0x0f ; White on black -.loop: - lodsb - test al, al - jz .done - stosw ; Write character + attribute - jmp .loop -.done: - ret - -long_msg: db 'SoraOS 64-BIT', 0 - -; --- The Magic Boot Sector Footer --- -; Fill the rest of the 512 bytes with zeros +; ============================================================ +; BOOT SIGNATURE +; ============================================================ times 510-($-$$) db 0 -; The BIOS signature (must be at the very end) dw 0xAA55 - -section .bss -align 4096 -pml4_table: - resb 4096 -pdpt_table: - resb 4096 -pd_table: - resb 4096 - diff --git a/build.sh b/build.sh index be6b741..7281593 100755 --- a/build.sh +++ b/build.sh @@ -1,12 +1,71 @@ -#!/bin/sh -export PATH=/usr/local/cross/bin:$PATH +#!/bin/bash +# Complete build script for SoraOS with 2-stage bootloader -# 1. Assemble raw binary -echo ">>> Assembling boot.asm to boot.bin..." +set -e # Exit on any error + +echo "===================================" +echo " SoraOS Build System v1.0" +echo "===================================" + +# Colors +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# 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 -# 2. Run QEMU as a raw disk drive -echo ">>> Running QEMU with boot.bin..." -qemu-system-x86_64 -drive format=raw,file=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 -echo "Done!" +# Step 3: Assemble kernel entry point +echo -e "${BLUE}[3/6]${NC} Assembling kernel entry..." +nasm -f elf64 kernel.asm -o 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 + +# 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 + +# Step 6: Create OS image +echo -e "${BLUE}[6/6]${NC} Creating OS image..." +cat boot.bin elevator.bin kernel.bin > os-image.bin + +# Pad to floppy size (1.44MB) +truncate -s 1440K os-image.bin + +echo "" +echo -e "${GREEN}✓ Build complete!${NC}" +echo "" +echo "===================================" +echo "File Layout:" +echo "===================================" +echo "Sector 1: Stage 1 (MBR)" +echo "Sectors 2-6: Stage 2 (Extended Bootloader)" +echo "Sectors 7+: Kernel" +echo "" + +# Show sizes +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) +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 + + +echo -e "${GREEN}Done!${NC}" diff --git a/elevator.asm b/elevator.asm new file mode 100644 index 0000000..faada1a --- /dev/null +++ b/elevator.asm @@ -0,0 +1,490 @@ +; File: elevator.asm +; 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 + mov si, msg_stage2 + call print_string + + ; Save boot drive number (passed from stage1 in DL) + mov [BOOT_DRIVE], dl + + ; Load kernel from disk + call load_kernel + + ; Verify kernel was loaded - check for signature + ; Check if there's actual code at 0x10000 + mov ax, 0x1000 + mov es, ax + xor bx, bx + mov ax, [es:bx] ; Read first 2 bytes of kernel + + ; Show what we read (for debugging) + push ax + xor ax, ax + mov es, ax + + mov si, msg_kernel_check + call print_string + + pop ax + call print_hex_word ; Print the word we read + + ; If it's 0x0000, kernel didn't load + test ax, ax + jz kernel_load_failed + + mov si, msg_kernel_ok + call print_string + + ; Disable interrupts + cli + + ; Load GDT + lgdt [gdt_descriptor] + + ; Enable Protected Mode + mov eax, cr0 + or eax, 0x1 + mov cr0, eax + + ; Far jump to 32-bit code + jmp 0x08:protected_mode + +; ============================================================ +; LOAD KERNEL FROM DISK +; ============================================================ +load_kernel: + push ax + push bx + push cx + push dx + + ; Reset disk system first + mov ah, 0x00 + mov dl, [BOOT_DRIVE] + 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 + + ; Now try loading kernel + mov ah, 0x02 ; Read function + mov al, 10 ; Number of sectors + mov ch, 0 ; Cylinder 0 + mov cl, 7 ; Start at sector 7 + mov dh, 0 ; Head 0 + mov dl, [BOOT_DRIVE] ; Drive number + + int 0x13 + jc kernel_error + + ; Restore ES to 0 + xor ax, ax + mov es, ax + + pop dx + pop cx + pop bx + pop ax + ret + +kernel_error: + ; Restore ES + xor ax, ax + mov es, ax + + ; Save error code + mov byte [ERROR_CODE], ah + + mov si, msg_kernel_error + call print_string + + ; Show error code + mov si, msg_error_code + call print_string + + ; Print error code as hex + mov al, [ERROR_CODE] + call print_hex + + ; Show drive number we tried to use + mov si, msg_drive + call print_string + mov al, [BOOT_DRIVE] + call print_hex + + jmp $ + +kernel_load_failed: + xor ax, ax + mov es, ax + + mov si, msg_verify_failed + call print_string + jmp $ + +; ============================================================ +; PRINT STRING (16-bit) +; ============================================================ +print_string: + pusha + mov ah, 0x0e +.loop: + lodsb + test al, al + jz .done + int 0x10 + jmp .loop +.done: + popa + ret + +; ============================================================ +; PRINT HEX BYTE (for debugging) +; ============================================================ +print_hex: + push ax + push bx + + mov bl, al + shr al, 4 ; Get high nibble + call print_nibble + + mov al, bl + and al, 0x0F ; Get low nibble + call print_nibble + + pop bx + pop ax + ret + +print_nibble: + cmp al, 9 + jle .digit + add al, 7 ; Convert to A-F +.digit: + add al, '0' + mov ah, 0x0e + int 0x10 + ret + +; Print a 16-bit word as hex +print_hex_word: + push ax + mov al, ah ; Print high byte first + call print_hex + pop ax + call print_hex ; Print low byte + ret + +; ============================================================ +; MESSAGES +; ============================================================ +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 + +; ============================================================ +; GDT - Global Descriptor Table +; ============================================================ +align 8 +gdt_start: + +gdt_null: + dq 0x0 + +gdt_code32: ; Selector 0x08 + dw 0xffff + dw 0x0000 + db 0x00 + db 10011010b + db 11001111b + db 0x00 + +gdt_data32: ; Selector 0x10 + dw 0xffff + dw 0x0000 + db 0x00 + db 10010010b + db 11001111b + db 0x00 + +gdt_code64: ; Selector 0x18 + dw 0xffff + dw 0x0000 + db 0x00 + db 10011010b + db 10101111b + db 0x00 + +gdt_data64: ; Selector 0x20 + dw 0xffff + dw 0x0000 + db 0x00 + db 10010010b + db 10101111b + db 0x00 + +gdt_end: + +gdt_descriptor: + dw gdt_end - gdt_start - 1 ; Limit (size - 1) + dd gdt_start ; Base address (org already adjusts this) + +; ============================================================ +; 32-BIT PROTECTED MODE +; ============================================================ +[bits 32] +protected_mode: + ; Set up segments + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov esp, 0x90000 + + ; Print to VGA + mov edi, 0xb8000 + mov esi, pm_msg + call print_pm + + ; Clear page table area (12KB starting at 0x1000) + mov edi, 0x1000 + mov ecx, 3072 ; 12KB / 4 bytes = 3072 dwords + xor eax, eax + rep stosd + + ; Set up page tables + ; PML4[0] -> PDPT at 0x2000 + mov dword [0x1000], 0x2003 + + ; PDPT[0] -> PD at 0x3000 + mov dword [0x2000], 0x3003 + + ; Identity map first 4MB (two 2MB pages) + ; PD[0] -> First 2MB + mov dword [0x3000], 0x00000083 + mov dword [0x3004], 0x00000000 + + ; PD[1] -> Second 2MB (covers 0x200000 - 0x3FFFFF) + mov dword [0x3008], 0x00200083 + mov dword [0x300C], 0x00000000 + + ; Load page table + mov eax, 0x1000 + mov cr3, eax + + ; Enable PAE + mov eax, cr4 + or eax, 0x20 + mov cr4, eax + + ; Enable Long Mode + mov ecx, 0xC0000080 + rdmsr + or eax, 0x100 + wrmsr + + ; Enable Paging + mov eax, cr0 + or eax, 0x80000000 + mov cr0, eax + + ; Jump to 64-bit mode + jmp 0x18:long_mode + +; Print in 32-bit protected mode +print_pm: + mov ah, 0x0f +.loop: + lodsb + test al, al + jz .done + stosw + jmp .loop +.done: + ret + +pm_msg: db '[PM32] Setting up Long Mode...', 0 + +; ============================================================ +; 64-BIT LONG MODE +; ============================================================ +[bits 64] +long_mode: + ; Set up segments + mov ax, 0x20 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov rsp, 0x90000 + + ; Set up a minimal IDT to prevent triple faults + ; Point all interrupts to a dummy handler + call setup_idt + + ; Print message on line 3 + mov rdi, 0xb8000 + (160 * 2) + mov rsi, lm_msg + call print_64 + + ; Write a marker before jumping to kernel (for debugging) + mov rdi, 0xb8000 + (160 * 3) + mov rsi, before_kernel_msg + call print_64 + + ; JUMP TO KERNEL! + call KERNEL_OFFSET + + ; If kernel returns, show error + mov rdi, 0xb8000 + (160 * 4) + mov rsi, kernel_return_msg + call print_64 + jmp $ + +; Set up a minimal IDT +setup_idt: + ; Fill IDT with different handlers for different exceptions + mov rdi, 0x4000 ; IDT location + + ; Set up first 32 entries (CPU exceptions) with specific handlers + mov rcx, 32 + mov rax, exception_handler + +.fill_exceptions: + mov word [rdi], ax ; Offset low + mov word [rdi + 2], 0x18 ; Code segment + mov byte [rdi + 4], 0 ; IST + mov byte [rdi + 5], 0x8E ; Present, interrupt gate + shr rax, 16 + mov word [rdi + 6], ax ; Offset middle + shr rax, 16 + mov dword [rdi + 8], eax ; Offset high + mov dword [rdi + 12], 0 ; Reserved + + mov rax, exception_handler ; Restore for next iteration + add rdi, 16 + loop .fill_exceptions + + ; Fill remaining entries (32-255) with dummy handler + mov rcx, 224 + mov rax, dummy_handler + +.fill_rest: + mov word [rdi], ax + mov word [rdi + 2], 0x18 + mov byte [rdi + 4], 0 + mov byte [rdi + 5], 0x8E + shr rax, 16 + mov word [rdi + 6], ax + shr rax, 16 + mov dword [rdi + 8], eax + mov dword [rdi + 12], 0 + + mov rax, dummy_handler + add rdi, 16 + loop .fill_rest + + ; Load IDT + lidt [idt_descriptor] + ret + +; Exception handler - shows what went wrong +exception_handler: + ; Save registers + push rax + push rbx + + ; Get exception number from stack + ; (not perfectly accurate but good enough for debugging) + + ; Write "EXCEPTION!" in red at line 5 + mov rbx, 0xb8000 + (160 * 5) + mov rax, 0x0C450C580C430C45 ; "ECXE" in red + mov [rbx], rax + mov rax, 0x0C4F0C490C540C50 ; "PTIO" in red + mov [rbx + 8], rax + mov word [rbx + 16], 0x0C21 ; "!" in red + + ; Show the instruction pointer where it failed + mov rax, [rsp + 16] ; Get RIP from stack (after our 2 pushes) + mov rbx, 0xb8000 + (160 * 6) + + ; Write "RIP: " + mov word [rbx], 0x0F52 ; 'R' + mov word [rbx + 2], 0x0F49 ; 'I' + mov word [rbx + 4], 0x0F50 ; 'P' + mov word [rbx + 6], 0x0F3A ; ':' + mov word [rbx + 8], 0x0F20 ; ' ' + + ; Print RIP value as hex + mov rcx, 16 + mov rbx, 0xb8000 + (160 * 6) + 10 +.print_rip: + rol rax, 4 + mov dl, al + and dl, 0x0F + cmp dl, 9 + jle .digit + add dl, 7 +.digit: + add dl, '0' + mov byte [rbx], dl + mov byte [rbx + 1], 0x0F + add rbx, 2 + dec rcx + jnz .print_rip + + ; Restore and halt + pop rbx + pop rax + + ; Infinite loop instead of iretq + cli + hlt + jmp $ + +; Dummy interrupt handler for IRQs (not CPU exceptions) +dummy_handler: + iretq + +idt_descriptor: + dw (256 * 16) - 1 ; Limit (256 entries * 16 bytes) + dq 0x4000 ; Base address + +; Print in 64-bit mode +print_64: + mov ah, 0x0f +.loop: + lodsb + test al, al + jz .done + stosw + jmp .loop +.done: + ret + +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 diff --git a/kernel.asm b/kernel.asm new file mode 100644 index 0000000..8fffe69 --- /dev/null +++ b/kernel.asm @@ -0,0 +1,15 @@ +; File: kernel.asm +; Assembly entry point for the kernel +[bits 64] +[extern kmain] ; kmain is defined in kernel.c + +global _start ; Make _start visible to linker + +_start: + ; We're already in 64-bit mode with stack set up + ; Just call the C kernel + call kmain + + ; If kmain returns, hang + jmp $ + diff --git a/kernel.c b/kernel.c index 73011b6..9183f3b 100644 --- a/kernel.c +++ b/kernel.c @@ -1,15 +1,42 @@ -// file: kerlnel.c +// File: kernel.c +// SoraOS Kernel - Main entry point + +// Simple helper to write a character at a specific position +static inline void write_char(int row, int col, char c, unsigned char color) { + volatile unsigned short *vga = (volatile unsigned short *)0xB8000; + int pos = (row * 80) + col; + vga[pos] = (color << 8) | c; +} + +// Simple helper to write a string +static void write_string(int row, int col, const char *str, unsigned char color) { + int i = 0; + while (str[i] != '\0') { + write_char(row, col + i, str[i], color); + i++; + } +} + +// Clear the entire screen +static void clear_screen(void) { + volatile unsigned short *vga = (volatile unsigned short *)0xB8000; + int i; + for (i = 0; i < 80 * 25; i++) { + vga[i] = (0x00 << 8) | ' '; + } +} void kmain(void) { - // Kernel main function - // Set VGA memory address - volatile unsigned short *VGA_mem = (unsigned short *)0xB8000; - - VGA_mem[0] = (0x07 << 8) | 'S'; - VGA_mem[1] = (0x07 << 8) | 'O'; - VGA_mem[2] = (0x07 << 8) | 'R'; - VGA_mem[3] = (0x07 << 8) | 'A'; - VGA_mem[4] = (0x07 << 8) | ' '; - VGA_mem[5] = (0x07 << 8) | 'O'; - VGA_mem[6] = (0x07 << 8) | 'S'; + // Clear screen + clear_screen(); + + // 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 + + // Infinite loop + while (1) { + __asm__ volatile ("hlt"); + } } diff --git a/linker.ld b/linker.ld index d077ac7..e477fcb 100644 --- a/linker.ld +++ b/linker.ld @@ -1,36 +1,26 @@ +/* Linker script for SoraOS kernel */ OUTPUT_FORMAT(binary) ENTRY(_start) SECTIONS { -/* Set the location counter to 0x100000 (1MB) */ -. = 0x100000; + /* Kernel loaded at 0x10000 (64KB) by stage2 bootloader */ + . = 0x10000; -.multiboot : -{ - KEEP(*(.multiboot)) -} + .text : { + *(.text) + } -/* Define the .text section at the current location */ -.text : -{ - /* Put all .text sections from all input files here */ - *(.text) -} + .rodata : { + *(.rodata) + } -/* Define the .data section immediately after .text */ -.data : -{ - /* Put all .data sections §from all input files here */ - *(.data) -} + .data : { + *(.data) + } -/* Define the .bss section immediately after .data */ -.bss : -{ - /* Put all .bss sections from all input files here */ - *(.bss) -} - -/* End of the linker script */ + .bss : { + *(.bss) + *(COMMON) + } }