From d35463e1959cb64828c3166527b06e4a79cbea5e Mon Sep 17 00:00:00 2001 From: andromeda Date: Fri, 6 Mar 2026 16:53:18 +0100 Subject: reorganise --- bootler/asm/boot.asm | 286 +++++++++++++++++++++++++++++++++++++++++++++++++ bootler/asm/kernel.asm | 23 ++++ 2 files changed, 309 insertions(+) create mode 100644 bootler/asm/boot.asm create mode 100644 bootler/asm/kernel.asm (limited to 'bootler/asm') diff --git a/bootler/asm/boot.asm b/bootler/asm/boot.asm new file mode 100644 index 0000000..5291d58 --- /dev/null +++ b/bootler/asm/boot.asm @@ -0,0 +1,286 @@ +; bootler +; legacy bootloader in nasm-flavoured asm +; 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 + +; 64 bit IDT stuff +IDT_ADDR equ 0x8000 ; bottom of IDT +IDT_SIZE equ 0x1000 ; size of IDT + +IDT_SEGMENT equ 0x0008 ; gdt code segment to jump to for idt calls + +; magic numbers and things +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 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 fs, ax +mov gs, ax +cld + +; activate a20 +mov ax, A20_LINE_ENABLE +int BIOS_INT_MEMORY_OP +jc error +mov si, msg_a20_line +call print + +; 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 + +; read disk +mov ah, 0x02 +int BIOS_INT_DISK_OP +jc error +mov si, msg_disk_read +call print + +; zero es +push ax +xor ax, ax +mov es, ax +pop ax + +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: + mov si, .msg + call print + .msg db "err ", 0x00 + ret + +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 readable (yoinked from https://wiki.osdev.org/Entering_Long_Mode_Directly) +gdt_data: + dq 0x0000000000000000 + dq 0x00209A0000000000 + dq 0x0000920000000000 + +gdt_descriptor: + dw $ - gdt_data - 1 ; size + dd gdt_data ; start + +[bits 64] + +; long mode entry +lm_start: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + ; set up serial device + ; TODO poll and whatnot (in rust??) + mov dx, 0x3F8 + + ; qemu -no-graphic overlaps serial and bios output without this + mov al, 0x0D + out dx, al + mov al, 0x0A + out dx, al + + ; initialize IDT at IDT_ADDR + call idt_init + + int3 ; silly test + + jmp KERNEL_LOAD_ADDR_ES * 0x10 + +idt_init: + ; clear space for idt + mov rdi, IDT_ADDR + push di + mov rcx, IDT_SIZE / 4 + xor rax, rax + cld + rep stosd ; clear double word for each rcx + pop di + + push rdx ; dx contains the output device + ; nothing between here and the `pop rdx` will be able to print + + ; breakpoint + mov rdi, 0x8E ; present, no dpl, interrupt + mov rsi, 0x03 ; breakpoint interrupt + lea rdx, [int_hdl_dummy] + call mk_idt_entry + + pop rdx ; get back dx output device + + lidt [idt_descriptor] + + ret + +int_hdl_dummy: + mov rsi, .msg + call lm_print + iretq + .msg db "INTdummy", 0x0D, 0x0A, 0x00 + +; rdi = flags +; rsi = entry number +; rdx -> handler +mk_idt_entry: + mov rax, rdx + mov rcx, rsi + + shl rcx, 4 ; offset = entry number * 16 + add rcx, IDT_ADDR + + mov word [rcx + 0], ax ; offset + mov word [rcx + 2], IDT_SEGMENT ; code segment + mov word [rcx + 5], di + mov byte [rcx + 4], 0 ; IST (0 = none) + shr rax, 16 + mov word [rcx + 6], ax ; offset + shr rax, 16 + mov dword [rcx + 8], eax ; offset + mov dword [rcx + 12], 0 ; reserved + ret + +lm_print: + .loop + mov al, [rsi] + test al, al + jz .done + out dx, al + inc si + jmp .loop + .done: + ret + +idt_descriptor: + dw IDT_SIZE - 1 ; size + dq IDT_ADDR ; start + +msg_a20_line db "a20 line", 0x0D, 0x0A, 0x00 +msg_disk_read db "disk", 0x0D, 0x0A, 0x00 + +times 510-($-$$) db 0 ; 2 bytes less now +db 0x55 +db 0xAA diff --git a/bootler/asm/kernel.asm b/bootler/asm/kernel.asm new file mode 100644 index 0000000..b4cbb30 --- /dev/null +++ b/bootler/asm/kernel.asm @@ -0,0 +1,23 @@ +[bits 64] + +mov al, 'K' +out dx, al +mov al, 'e' +out dx, al +mov al, 'r' +out dx, al +mov al, 'n' +out dx, al +mov al, 'e' +out dx, al +mov al, 'l' +out dx, al +mov al, 0x0D +out dx, al +mov al, 0x0A +out dx, al +mov al, 0x00 +out dx, al +.done + hlt + jmp .done -- cgit v1.3.1