; asmsyntax=nasm [org 0x7c00] [bits 16] boot: cli mov ax, 0x8000 mov ss, ax mov sp, 0xffff push cs pop ds xor bx, bx mov ah, 0x0e mov si, message lodsb .lewp: int 0x10 lodsb cmp al, 0 jne .lewp ; Enable A20 mov ax, 0x2401 int 0x15 ; HACK: Load the ELF kernel at 0xf000. Assuming that the first ; LOAD header has a file offset of 0x1000, this puts _start ; at 0x10000 which we jump to later. ; This is all quite rickety. mov bx, 0xf00 mov es, bx xor bx, bx mov cx, word [cur_lba] .sector_loop: call convert_lba_to_chs mov ah, 0x02 ; cmd 0x02 - Read Disk Sectors mov al, 1 ; 1 sector at a time mov dl, 0 ; drive 0 (fd0) int 0x13 jc fug mov ah, 0x0e mov al, '.' int 0x10 inc word [cur_lba] mov cx, word [cur_lba] cmp cx, 900 jz .sector_loop_end mov bx, es add bx, 0x20 mov es, bx xor bx, bx jmp .sector_loop .sector_loop_end: call durk ; Turn off the floppy motor. mov dx, 0x3f2 xor al, al out dx, al ; Let's look at the ELF header. mov bx, 0xf00 mov fs, bx cmp [fs:0], dword 0x464c457f ; ELF magic: { 0x7f "ELF" } jne fug cmp [fs:24], dword 0x10000 ; Entry should be 0x10000 jne fug mov ebx, dword [fs:28] ; EBX <- program header table mov ecx, dword [fs:44] ; ECX <- program header count ; Let's find the BSS and clear it. parse_program_header: cmp [fs:ebx], dword 0x1 ; Is Load segment? jne .next cmp [fs:ebx+24], dword 0x6 ; Is read+write but not execute? jne .next mov edi, [fs:ebx+8] ; EDI <- p_vaddr add edi, [fs:ebx+16] ; skip over 'p_filesz' bytes (leave them intact) push ecx sub edi, [fs:ebx+16] ; skip over 'p_filesz' bytes (see above) ; Since we're in 16-bit real mode, create a segment address. mov eax, edi shr eax, 4 mov es, ax and edi, 0xf mov ecx, [fs:ebx+20] ; ECX <- p_memsz xor al, al rep stosb pop ecx .next: add ebx, 32 loop parse_program_header ; Okay we're all set to go! lets_go: lgdt [cs:test_gdt_ptr] mov eax, cr0 or al, 1 mov cr0, eax jmp 0x08:pmode durk: push cs pop ds xor bx, bx mov ah, 0x0e mov si, msg_sectors_loaded lodsb .lewp: int 0x10 lodsb cmp al, 0 jne .lewp ret pmode: [bits 32] mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax mov esp, 0x4000 xor eax, eax xor ebx, ebx xor ecx, ecx xor edx, edx xor ebp, ebp xor esi, esi xor edi, edi jmp 0x10000 hlt test_gdt_ptr: dw (test_gdt_end-test_gdt) dd test_gdt test_gdt: dd 0 dd 0 dd 0x0000ffff dd 0x00cf9a00 dd 0x0000ffff dd 0x00cf9200 dd 0 dd 0 dd 0 dd 0 test_gdt_end: [bits 16] fug: xor bx, bx mov ah, 0x0e mov si, fug_message lodsb .lewp: int 0x10 lodsb cmp al, 0 jne .lewp cli hlt ; Input: ; ; AX = LBA ; ; Output: ; ; CX and DH = C/H/S address formatted for Int13,2 ; CL = sector (LBA % sectors_per_track) + 1 ; ; 1.44M floppy stats: ; (sectors_per_track: 18) ; (heads: 2) ; (sectors: 2880) convert_lba_to_chs: mov ax, cx ; AX = LBA/spt, DX = LBA%spt xor dx, dx div word [sectors_per_track] ; CL = sector (LBA % sectors_per_track) + 1 mov cl, dl inc cl ; CH = track (LBA / sectors_per_track) / heads mov ch, al shr ch, 1 ; AX = (LBA/spt)/heads, DX = (LBA/spt)%heads xor dx, dx div word [heads] ; DH = sector (LBA / sectors_per_track) % heads mov dh, dl ret cur_lba: dw 1 sectors_per_track: dw 18 heads: dw 2 msg_sectors_loaded: db "done!", 0x0d, 0x0a, 0 message: db "Loading kernel", 0 fug_message: db "FUG!", 0x0d, 0x0a, 0 times 510-($-$$) db 0 dw 0xaa55