Created
December 1, 2021 10:14
-
-
Save flysand7/9d412b6d83aa3c9e82f083734ff3b22c to your computer and use it in GitHub Desktop.
A fat32 bootloader within a single partition
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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