Skip to content

Instantly share code, notes, and snippets.

@flysand7
Created December 1, 2021 10:14
Show Gist options
  • Save flysand7/9d412b6d83aa3c9e82f083734ff3b22c to your computer and use it in GitHub Desktop.
Save flysand7/9d412b6d83aa3c9e82f083734ff3b22c to your computer and use it in GitHub Desktop.
A fat32 bootloader within a single partition
org 0x0800
cpu 386
bits 16
;;___________________________________________________________________________;;
;; This file is Volume Boot Record that loads a single file from FAT32
;; onto the address 0x1000 and jumps to that address. I created this file
;; mainly for demonstration that one doesn't need additional sectors for
;; simple bootloaders.
;; The code to this file doesn't take up the whole partition -- there's
;; plenty of space to spend on additional instructions if you'd like. I
;; managed to use this space to switch the processor to 32-bit Protected Mode,
;; although couldn't quite get it to switch to 64-bit Long Mode. I was off by
;; about 154 bytes. Most of this space was being taken up by GDT's though, so
;; perhaps there is a way around.
;; This code expects certain parameters to be set:
;; CS:IP at 0000:7c00
;; DS,ES,SS are all zero
;; dl has drive number
;; bx has current mbr entry
;; Note that code assumes loading from MBR, so it can't be used to partition
;; a floppy disk. Although it may be modified to be able to be loaded from
;; floppy by removing lines 93..95 (and maybe something else, I'm not
;; thinking rn).
;; Please bear with size optimizations :D
start:
BPB:
cld
jmp code
times 3-($-$$) db 0x00
BPB.oem: times 8 db 0
BPB.bps: dw 0
BPB.spc: db 0
BPB.res: dw 0
BPB.fats: db 0
BPB.dir_ents: dw 0
BPB.16.secs: dw 0
BPB.mdesc: db 0
BPB.16.spf: dw 0
BPB.16.spt: dw 0
BPB.16.hds: dw 0
BPB.hid: dd 0
BPB.secs: dd 0
BPB.spf: dd 0
BPB.flg: dw 0
BPB.fat_ver: dw 0
BPB.root_clus: dd 0
BPB.fsinfo_sec: dw 0
BPB.backup_sec: dw 0
times 12 db 0
;; Note(bumbread): DAP is hidden within BPB, within the fields
;; that are not used by our bootloader
DAP:
times 17 db 0
FATINFO:
FATINFO.first_fat_sec: dd 0
FATINFO.first_data_sec: dd 0
db 0
times 0x005A - ($-$$) db 0x00
code:
;; Relocate ourselves to 0x800
mov si, 0x7c00
mov di, 0x0800
mov cx, 0xff
rep movsw
jmp 00:.reloc
.reloc:
xor ecx, ecx
mov bp, BPB
mov word[bp+0x40], 0x0010
mov dword[bp+0x40+0x0c], ecx
mov byte[bp+0x40+0x10], dl
;; Calculate and save the first data sector relative
;; to disk start, and the first fat sector relative to
;; disk start.
mov cx, word[bp+0x16]
test cx, cx
cmovz ecx, dword [bp+0x24]
movzx eax, byte [bp+0x10]
xor edx, edx
mul ecx
movzx ecx, word [bp+0x0e]
add eax, ecx
mov edx, dword[bx+0x08]
add eax, edx
add ecx, edx
mov dword [FATINFO.first_data_sec], eax
mov dword [FATINFO.first_fat_sec], ecx
;; Assume root cluster is 2
;; Note(josh): seems to be a fair assumption
xor eax,eax
inc ax
inc ax
call clus_to_sec
mov di, 0x1000
mov cx, 1
call load_secs
;; Assume the kernel image is in the first
mov bx, 0x1000-32
mov cx, 16
.read_root_file:
add bx, 32
mov al, byte[bx]
test al, al
jz .error
cmp al, 0xe5
je .inc
cmp byte[bx+11], 0x0f
jz .inc
pusha
mov cx, 11
mov si, bx
mov di, kernel_fn
repe cmpsb
jcxz .image_found
popa
.inc:
loop .read_root_file
.error:
jmp $
.image_found:
;; Load cluster number
mov ax, word[bx+0x14]
shl eax, 16
mov ax, word[bx+0x1a]
mov di, 0x1000
mov cx, 1
.read_next_cluster:
push eax
call clus_to_sec
call load_secs
pop eax
cmp eax, 0x0ffffff8
jge .clusters_read
add di, 0x200
push di
mov ebx, eax
shr eax, 7
add eax, dword[FATINFO.first_fat_sec]
mov di, 0x600
call load_secs
and bx, 0x7f
shl bx, 2
mov eax, dword[di+bx]
pop di
jmp .read_next_cluster
.clusters_read:
jmp 0x1000
;; eax=cluster number
;; on return eax=sector index
clus_to_sec:
push ecx
push edx
sub eax, 2
xor edx, edx
movzx ecx, byte[BPB.spc]
mul ecx
add eax, dword[FATINFO.first_data_sec]
pop edx
pop ecx
ret
;; di=where to load
;; eax=sector number where from
;; cx=number of sectors
load_secs:
pushad
mov si, DAP
mov word [si+0x02], cx
mov word [si+0x04], di
mov word [si+0x06], es
mov dword[si+0x08], eax
mov dl, byte[si+0x10]
mov ah, 0x42
int 0x13
popad
ret
;; Note: FILENAMEEXT
kernel_fn: db `TEST `
;; Fill remainder of the code section with zeros
times 510-($-$$) db 0
dw 0xAA55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment