diff --git a/.cargo/config.toml b/.cargo/config.toml index d430fa4..74cdc7b 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,5 @@ [build] target = "x86_64-unknown-none" +rustflags = [ + "-Crelocation-model=static" +] diff --git a/README.md b/README.md index 11c5569..52a1395 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ run with `nix run git+https://git.mtgmonkey.net/andromeda/bootler#bootler` +------ 0x00100000 ------+ | hardware, bios stuff | +------ 0x00080000 ------+ -| pm stack (esp) | from boot.asm +| free | +------ 0x00010200 ------+ | kernel (kernel.asm) | +------ 0x00010000 ------+ @@ -24,7 +24,17 @@ run with `nix run git+https://git.mtgmonkey.net/andromeda/bootler#bootler` +------ 0x00007E00 ------+ | bootloader (boot.asm) | +------ 0x00007C00 ------+ -| real mode stack (sp) | from boot.asm +| stack | TODO get real stack ++------ 0x00005000 ------+ +| PT | ++------ 0x00004000 ------+ +| PDT | ++------ 0x00003000 ------+ +| PDPT | ++------ 0x00002000 ------+ +| PML4T | ++------ 0x00001000 ------+ +| free | +------ 0x00000500 ------+ | bios stuff | +------ 0x00000000 ------+ diff --git a/asm/boot.asm b/asm/boot.asm index bb852ef..29e807c 100644 --- a/asm/boot.asm +++ b/asm/boot.asm @@ -3,156 +3,210 @@ ; 2026 Andromeda ; GPL licensed +LOAD_ADDR equ 0x7C00 + +KERNEL_START equ 2 ; first sector on disk to load kernel from; 1 indexed +KERNEL_SIZE equ 1 ; length of kernel in sectors +KERNEL_LOAD_ADDR_ES equ 0x1000 ; kernel to be loaded at es * 0x10 + 0x0000 + +PAGE_TABLE_LOAD_ADDR equ 0x1000 ; start of page table; 4 * pt size +PAGE_TABLE_SIZE equ 0x1000 ; size of page table in bytes + +A20_LINE_ENABLE equ 0x2401 ; magic number in ax to enable a20 line with 0x15 +BIOS_INT_DISK_OP equ 0x13 +BIOS_INT_MEMORY_OP equ 0x15 + +CR0_PE equ 1 << 0 ; Protected Mode Enabled +CR0_PG equ 1 << 31 ; Paging + +CR4_PAE equ 1 << 5 ; Physical Address Extension +CR4_PGE equ 1 << 7 ; Page Global Enabled + +MSR_IA32_EFER equ 0xC0000080 ; Extended Feature Enable model-specific Register + [bits 16] -[org 0x7C00] ; address where bootloader is loaded +[org LOAD_ADDR] + +jmp 0x0000:.cs_reset ; in case it loads us at 0x7C00:0x0000 +.cs_reset: xor ax, ax +mov ss, ax +mov sp, LOAD_ADDR ; stack builds down, loader faces up mov ds, ax mov es, ax -mov ss, ax -mov sp, 0x7C00 - -mov ah, 0x0E -mov al, 'R' -int 0x10 -mov al, 'e' -int 0x10 -mov al, 'a' -int 0x10 -mov al, 'l' -int 0x10 -mov al, 0x0D -int 0x10 -mov al, 0x0A -int 0x10 -mov al, 0x00 ; stops serial and bios output from overlapping in qemu -nographic -int 0x10 ; output +mov fs, ax +mov gs, ax +cld ; activate a20 -mov ax, 0x2401 -int 0x15 -jc error +mov ax, A20_LINE_ENABLE +int BIOS_INT_MEMORY_OP +jc error_a20_line +mov si, msg_a20_line +call print -; load kernel -; 'docs' from https://www.ctyme.com/intr/rb-0607.htm -mov ah, 0x02 -mov al, 1 ; number of sectors to read (must be nonzero) -mov ch, 0 ; low eight bits of cylinder number -mov cl, 2 ; sector number 1-63 (bits 0-5); high two bits of cylinder (bits 6-7, - ; hard disk only) -mov dh, 0 ; head number -; dl is already set by bios -mov bx, 0x1000 ; data buffer +; prep to read disk +mov al, KERNEL_SIZE ; size in sectors, min. 1 +mov ch, 0 ; cylinder +mov cl, KERNEL_START ; start sector, 1-indexed +mov dh, 0 ; head +; dl set by bios +mov bx, KERNEL_LOAD_ADDR_ES ; load addr es:bx mov es, bx xor bx, bx -int 0x13 ; read disk -jc error -; load gdt -lgdt [gdt_descriptor] +; read disk +mov ah, 0x02 +int BIOS_INT_DISK_OP +jc error_disk_read +mov si, msg_disk_read +call print -; jump to pm -cli -mov eax, cr0 -or eax, 1 -mov cr0, eax -jmp 0x08:pm_start +; zero es +push ax +xor ax, ax +mov es, ax +pop ax -error: - mov al, 'e' - int 0x10 - mov al, 'r' - int 0x10 - mov al, 'r' - int 0x10 - mov al, 'o' - int 0x10 - mov al, 'r' - int 0x10 - jmp $ +mov edi, PAGE_TABLE_LOAD_ADDR +jmp lm_load +; expects: +; es:edi -> 16kb for page table +; ss:esp -> stack +; heavily based on https://wiki.osdev.org/Entering_Long_Mode_Directly +lm_load: + ; clear page table + push di + mov ecx, PAGE_TABLE_SIZE + xor eax, eax + cld + rep stosd ; clear space for all 4 tables + pop di + + ; PML4TE0 + lea eax, [es:di + PAGE_TABLE_SIZE] + or eax, 11b + mov [es:di], eax + + ; PDPT0E0 + lea eax, [es:di + 2 * PAGE_TABLE_SIZE] + or eax, 11b + mov [es:di + PAGE_TABLE_SIZE], eax + + ; PDT0E0 + lea eax, [es:di + 3 * PAGE_TABLE_SIZE] + or eax, 11b + mov [es:di + 2 * PAGE_TABLE_SIZE], eax + + ; PT0 + push di + lea di, [di + 3 * PAGE_TABLE_SIZE] + mov eax, 0x11 + + .set_pt_entry + mov [es:di], eax + add eax, 0x1000 + add di, 8 + cmp eax, 0x200000 ; size of page + jb .set_pt_entry + + pop di + + ; disable interrupts from PIC by masking all interrupts + mov al, 0xFF ; mask + out 0xA1, al + out 0x21, al + + ; PAE, PGE + mov eax, CR4_PAE | CR4_PGE + mov cr4, eax + + ; cr3 -> PML4TE0 + mov edx, edi + mov cr3, edx + + ; highs LME bit in EFER + mov ecx, MSR_IA32_EFER + rdmsr + or eax, 0x00000100 + wrmsr + + ; activate long mode + mov ebx, cr0 + or ebx, CR0_PG | CR0_PE + mov cr0, ebx + + cli + lgdt [gdt_descriptor] + + jmp 0x08:lm_start + +error_a20_line: + mov si, .msg + call print + jmp done + .msg db "err a20 line", 0x00 + +error_disk_read: + mov si, .msg + call print + jmp done + .msg db "err disk read", 0x00 + +done: + hlt + jmp done + +print: + pushad + .loop + lodsb + test al, al + je .done + mov ah, 0x0E + int 0x10 + jmp .loop + .done + popad + ret + +; TODO make real idt +empty_idt: + dw 0 ; length + dd 0 ; base + +; TODO make readable (yoinked from https://wiki.osdev.org/Entering_Long_Mode_Directly) gdt_data: - ; null segment dq 0x0000000000000000 - ; code segment - dw 0xFFFF - dw 0x0000 - - db 0x00 - db 10011010b ; 32-bit code segment, present, ring 0 - db 11001111b ; limit bits 16-19 - db 0x00 - - ; data segment - dw 0xFFFF - dw 0x0000 - - db 0x00 - db 10010010b ; 32-bit data segment, present, ring 0 - db 11001111b ; limit bits 16-19 - db 0x00 + dq 0x00209A0000000000 + dq 0x0000920000000000 gdt_descriptor: dw $ - gdt_data - 1 ; size dd gdt_data ; start -[bits 32] +[bits 64] -; entry point -pm_start: - ; data segment registers +; long mode entry +lm_start: mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax - mov esp, 0x80000 - ; TODO actually configure COM1 - mov dx, 0x3F8 ; COM1 - mov al, 'P' - out dx, al - mov al, 'r' - out dx, al - mov al, 'o' - out dx, al - mov al, 't' - out dx, al - mov al, 'e' - out dx, al - mov al, 'c' - out dx, al - mov al, 't' - out dx, al - mov al, 'e' - out dx, al - mov al, 'd' - out dx, al - mov al, 0x0D - out dx, al - mov al, 0x0A - out dx, al + ; set up serial device + ; TODO poll and whatnot (in rust??) + mov dx, 0x3F8 - jmp 0x08:0x10000 + jmp KERNEL_LOAD_ADDR_ES * 0x10 + +msg_a20_line db "a20 line", 0x0D, 0x0A, 0x00 +msg_disk_read db "disk read", 0x0D, 0x0A, 0x00 -pm_error: - mov al, 'p' - out dx, al - mov al, 'm' - out dx, al - mov al, 'e' - out dx, al - mov al, 'r' - out dx, al - mov al, 'r' - out dx, al - mov al, 'o' - out dx, al - mov al, 'r' - out dx, al - jmp $ - times 510-($-$$) db 0 ; 2 bytes less now db 0x55 db 0xAA diff --git a/asm/kernel.asm b/asm/kernel.asm index 23c0d5d..b4cbb30 100644 --- a/asm/kernel.asm +++ b/asm/kernel.asm @@ -1,4 +1,4 @@ -[bits 32] +[bits 64] mov al, 'K' out dx, al @@ -18,6 +18,6 @@ mov al, 0x0A out dx, al mov al, 0x00 out dx, al -jmp $ - -times 512-($-$$) db 0 +.done + hlt + jmp .done diff --git a/nix/pkgs/bootle.nix b/nix/pkgs/bootle.nix index 5c3c63d..dd21018 100644 --- a/nix/pkgs/bootle.nix +++ b/nix/pkgs/bootle.nix @@ -23,7 +23,11 @@ in (naersk'.buildPackage { release = true; # build std - cargoBuildOptions = x: x ++ ["-Zbuild-std=core,compiler_builtins,alloc" "-Zbuild-std-features=compiler-builtins-mem"]; + cargoBuildOptions = x: + x + ++ [ + "-Zbuild-std=core,compiler_builtins" + ]; postInstall = '' ld --oformat binary \ diff --git a/src/lib.rs b/src/lib.rs index c6cb39e..f942513 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,15 +6,22 @@ use core::panic::PanicInfo; #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { // 'k' - loop{unsafe {core::arch::asm!( - "out dx, al", in("al") 0x6Bu8 - )}} + print("kernel\n"); + loop {} +} + +fn print(s: &str) { + let mut bytes = s.bytes(); + while let Some(b) = bytes.next() { + unsafe {core::arch::asm!( + "out dx, al" + , in("al") b + )}; + }; } #[panic_handler] fn panic(_: &PanicInfo) -> ! { - // 'p' - loop{unsafe {core::arch::asm!( - "out dx, al", in("al") 0x70u8 - )}} + print("panicked"); + loop {} }