rendered paste body;
; Copyright (c) Eike Dehling 2004, all rights reserved
;
; Compile with nasm, write to first sector of a floppy, have fun
;
[BITS 16]
[ORG 0x7c00]
; -------------------------------------
; disk description
; -------------------------------------
jmp short start ; 3 bytes to e.g. jump
nop
db "EikeBoot" ; 8 byte label / OemId
dw 512 ; bytes per sector
db 1 ; sectors per cluster
dw 1 ; size of the bootloader, in sectors
db 2 ; number of copies of the FAT
dw 224 ; number of entries in Root-Dir
dw 2880 ; 16-bit number of sectors
db 0xf0 ; media descriptor
dw 9 ; number of sectors per FAT
dw 18 ; sectors per track
dw 2 ; number of heads
dd 0 ; number of hidden sectors
dd 0 ; 32-bit number of sectors
db 0 ; bios drive number
db 0 ; reserved
db 0x29 ; extended boot signature
dd 0 ; volume ID
db "NO NAME "; volume label
db "FAT12 " ; filesystem type
; -------------------------------------
; bootloader code
; -------------------------------------
print_io_error_trampoline:
jmp print_io_error ; out of range crap :(
start:
; set segments, bios may set 0x07c0:0x0000 or 0x0000:0x7c00
jmp 0:start2
start2: mov ax, 0
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7000
; save boot device
mov byte [bootdev], dl
; reset disks
mov ah, 0
mov dl, byte [bootdev]
int 0x13
; load FAT
mov ah, 0x02 ; read from disk
mov al, 9 ; number of sectors to read
mov bx, fatbuf ; es: bx = buffer
mov ch, 0 ; track ((1 / 18) / 2)
mov cl, 2 ; sector (1 % 18 + 1)
mov dh, 0 ; head ((1 / 18) % 2)
mov dl, byte [bootdev] ; dl = device, but that's still correct
int 0x13
jc print_io_error_trampoline
; load root directory
mov ah, 0x02 ; read from disk
mov al, 14 ; number of sectors to read
mov bx, rootdir ; es: bx = buffer
mov ch, 0 ; track ((19 / 18) / 2)
mov cl, 2 ; sector (19 % 18 + 1)
mov dh, 1 ; head ((19 / 18) % 2)
mov dl, byte [bootdev] ; dl = device, but that's still correct
int 0x13
jc print_io_error_trampoline
; find file
mov ax, rootdir ; ax = pointer to current dir-entry
cld
find_start:
mov si, ax ; point si to current filename
mov di, filename ; point di to the filename we need
mov cx, 11 ; compare max 11 bytes
repe cmpsb
je found_file
add ax, 32 ; done yet?
cmp ax, rootdir_end
jne find_start
; print error and halt
mov si, file_not_found
call print
jmp $
found_file:
; save cluster
mov si, ax
mov ax, word [si + 26] ; load cluster of file from the directory entry
mov word [cluster], ax
; decode FAT
mov cx, 512*(9/3) ; number of entries in the fat.
mov si, fatbuf
mov di, fatdecoded
;
; XXX - WATCH OUT, THIS REALLY NEEDS TO USE EAX, EBX & CO!!!
;
fat_decode_loop: ; load dword, split into two pieces of 12 bits, and discard last byte
lodsd ; load dword
dec si ; need only 3 bytes
mov ebx, eax
and eax, 0xFFF ; mask
stosw
mov eax, ebx
shr eax, 12
and eax, 0xFFF ; shift & mask
stosw
loop fat_decode_loop
; load file:
; es:bx = buffer
; ds:si = decoded fat buffer
; rest is for temporary usage only
; prepare buffer
mov ax, 0x1000
mov es, ax
mov bx, 0
mov ax, word [cluster]
load_loop:
; calculate next cluster
mov si, ax
shl si, 1
mov cx, word [fatdecoded + si]
mov word [cluster], cx
; calculate track, head and sector
add ax, 31 ; ax = logical sector
mov dx, 0
mov di, 18
div di
mov cl, dl
add cl, 1 ; cl = sector = (logical % 18 + 1)
mov dx, 0
mov di, 2
div di
mov ch, al ; ch = track = ((logical / 18) / 2)
mov dh, dl ; dh = head = ((logical / 18) % 2)
; read data
mov ah, 0x02
mov al, 1
mov dl, byte [bootdev]
int 0x13
jc print_io_error
add bx, 512
; done?
mov ax, word [cluster]
cmp ax, 0xFF8
jb load_loop
; DEBUG: print loaded file && halt
;mov si, 0
;mov di, 0
;mov ax, 0x1000
;mov ds, ax
;mov ax, 0xb800
;mov es, ax
;mov cx, 2000
;mov al, ' '
;print_file_loop:
;movsb
;stosb
;loop print_file_loop
;jmp $
; execute file?
; jmp 0x1000:0x0000
; jmp $
; disable interrupts
cli
; load our GDT
lgdt [gdt]
; enable protected mode ...
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08 : dword cs_flush ; jump into 32-bit
[BITS 32]
cs_flush:
; setup segements
mov eax, 0x10
mov ds, eax
mov es, eax
mov ss, eax
mov fs, eax
mov gs, eax
; make stack-register p-mode compliant
shl esp, 4
; clear flags
push dword 0
popf
; Execute loaded file ...
jmp 0x10000
[BITS 16]
; -------------------------------------
; procedures
; -------------------------------------
print_io_error:
mov si, io_error
call print
jmp $
; print zero-terminated string (without formatting)
; ds:si = string
; es:di = position on screen
print:
mov ax, 0xb800
mov es, ax
mov di, 0
print_loop:
lodsw
cmp al, 0
jz print_done
stosw
jmp print_loop
print_done:
ret
; -------------------------------------
; data & variables (not in a separate section, cause that makes padding to the
; 512 byte border easier)
; -------------------------------------
; filename
filename: db "KERNEL BIN"
; messages
io_error: db "I / O e r r o r ", 0
file_not_found: db "F i l e n o t f o u n d ", 0
executing: db "E x e c u t i n g . . . ", 0
gdt:
dw (gdtend - gdt)
dd gdt
dw 0 ; first entry is our gdt-pointer
dd 0x0000ffff, 0x00cf9a00 ; second entry: code
dd 0x0000ffff, 0x00cf9200 ; third entry: data
gdtend: ; end
; boot signature
resb 510 - ($ - $$) ; align at 512 bytes
dw 0xAA55
; -------------------------------------
; BSS data (starts at 0x8000, that leaves 32k space in the first 64k segment)
; -------------------------------------
[ABSOLUTE 0x8000]
; boot device
bootdev: resb 1
; first cluster of the file we need
cluster: resw 1
; FAT buffer
fatbuf: resb 9 * 512
; root directory
rootdir: resb 224 * 32
rootdir_end:
; buffer for decoding the FAT
fatdecoded: resb (9 * 512 * 3) / 2