Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ; FAT32 boot sector implementation test (fix and optimization 2)
- ; Note:
- ; * Fixed all bugs reported by @hdk_2
- ; * I changed the code so much which might introduce new bugs.
- cpu 8086
- bits 16
- org 0x7c00
- _start:
- jmp short start
- nop
- _bpb_oem_name:
- db "SMALLOS"
- times 8-($-_bpb_oem_name) db " "
- _bpb_numbytes_sec:
- dw 0x0200
- _bpb_numsec_clus:
- db 0x01
- _bpb_numsec_rsvd:
- dw 0x0020
- _bpb_numfat:
- db 0x02
- _bpb_numroot:
- dw 0x0000
- _bpb_numsec_total16:
- dw 0x0000
- _bpb_media_descriptor:
- db 0xf8
- _bpb_numsec_fat16:
- dw 0x0000
- _bpb_numsec_track:
- dw 0x0020
- _bpb_numheads:
- dw 0x0040
- _bpb_numsec_hidden:
- dd 0x00000000
- _bpb_numsec_total32:
- dd 0x00010000
- _bpb_numsec_fat32:
- dd 0x000001f8
- _bpb_mirror_flags:
- dw 0x0000
- _bpb_fat32_version:
- db 0, 0
- _bpb_offclus_root:
- dd 0x00000002
- _bpb_offsec_fsinfo:
- dw 0x0001
- _bpb_offsec_backup:
- dw 0x0006
- _bpb_fat32_reserved:
- times 12 db 0
- _bpb_physical_drive:
- db 0x00
- _bpb_fat16_reserved:
- db 0x00
- _bpb_ext_boot_sign:
- db 0x29
- _bpb_volume_id:
- dd 0x12345678
- _bpb_volume_label:
- db "SMALLOS"
- times 11-($-_bpb_volume_label) db " "
- _bpb_fs_type:
- db "FAT32"
- times 8-($-_bpb_fs_type) db " "
- %define STK_BASE 0x7be2
- %define REL_BASE 0x7c0b
- %define ADRH_INIT 0x10
- %define ADRH_LIMIT 0x50
- %define ADRH_INFO 0x60
- %define ADDR_INIT ADRH_INIT * 0x100
- %define ADDR_LIMIT ADRH_LIMIT * 0x100
- %define ADDR_INFO ADRH_INFO * 0x100
- %define tmp_dx 0x7be0
- %define tmp_offsec_fat 0x7bdc
- %define tmp_offsec_data 0x7bd8
- %define tmp_ext13h_buf 0x7bf0
- %define bpb_oem_name 0x7c03
- %define bpb_numbytes_sec 0x7c0b
- %define bpb_numsec_clus 0x7c0d
- %define bpb_numsec_rsvd 0x7c0e
- %define bpb_numfat 0x7c10
- %define bpb_numroot 0x7c11
- %define bpb_numsec_total16 0x7c13
- %define bpb_media_descriptor 0x7c15
- %define bpb_numsec_fat16 0x7c16
- %define bpb_numsec_track 0x7c18
- %define bpb_numheads 0x7c1a
- %define bpb_numsec_hidden 0x7c1c
- %define bpb_numsec_total32 0x7c20
- %define bpb_numsec_fat32 0x7c24
- %define bpb_mirror_flags 0x7c28
- %define bpb_fat32_version 0x7c2a
- %define bpb_offclus_root 0x7c2c
- %define bpb_offsec_fsinfo 0x7c30
- %define bpb_offsec_backup 0x7c32
- %define bpb_fat32_reserved 0x7c34
- %define bpb_physical_drive 0x7c40
- %define bpb_fat16_reserved 0x7c41
- %define bpb_ext_boot_sign 0x7c42
- %define bpb_volume_id 0x7c43
- %define bpb_volume_label 0x7c47
- %define bpb_fs_type 0x7c52
- %define rel(x) di-REL_BASE+x
- %define rel_bpb(x) rel(bpb_%+x)
- %define rel_tmp(x) rel(tmp_%+x)
- start:
- ; DL == drive
- ; IF := 0
- cli
- ; AX:=DS:=ES:=SS:=0
- xor ax, ax
- mov ds, ax
- mov es, ax
- mov ss, ax
- ; SP := STK_BASE
- ; DI := REL_BASE
- mov sp, STK_BASE
- mov di, REL_BASE
- push dx ; tmp_dx
- disk_reset:
- ; BIOS CALL: RESET DISK
- ; AH == 0
- ; DL == drive
- ; CF := error
- int 0x13
- jc short _err_boot_2
- disk_check_ext13h:
- mov ah, 0x41
- mov bx, 0x55aa
- ; BIOS CALL: CHECK EXTENDED INT13H
- ; AH == 0x41
- ; BX == 0x55AA
- ; if EXTENDED INT13H is supported:
- ; CF := 0
- ; BX := 0xAA55
- ; CX := (other flags) | 1
- int 0x13
- jc short fs_calc_geom
- sub bx, 0xaa55
- jne short fs_calc_geom
- shr cx, 1
- jnc short fs_calc_geom
- ; BL == 0
- ; SMI1 -> SMC1
- mov byte[_read_disk_branch+1], bl
- fs_calc_geom:
- ; SI:BP := dword(numsec_hidden) + word(numsec_rsvd)
- ; == dword(offsec_fat)
- mov bp, [rel_bpb(numsec_hidden)]
- mov si, [rel_bpb(numsec_hidden)+2]
- add bp, [rel_bpb(numsec_rsvd)]
- adc si, byte 0
- push si ; tmp_offsec_fat+2
- push bp ; tmp_offsec_fat
- ; [numfat] := 0
- ; SI:BP := dword(offsec_data)
- _fs_calc_geom_fat:
- add bp, [rel_bpb(numsec_fat32)]
- adc si, [rel_bpb(numsec_fat32)+2]
- dec byte[rel_bpb(numfat)]
- jnz _fs_calc_geom_fat
- push si ; tmp_offsec_data+2
- push bp ; tmp_offsec_data
- ; BX := ADDR_INIT
- mov bx, ADDR_INIT
- fs_traverse_fat_init:
- ; AX:SI := dword(offclus_root)
- mov ax, [rel_bpb(offclus_root)+2]
- mov si, [rel_bpb(offclus_root)]
- fs_traverse_fat:
- ; AX:SI == dword(cluster)
- ; AX:SI := dword(cluster) - 2
- push ax
- push si
- xor cx, cx
- sub si, byte 2
- sbb ax, cx
- _err_boot_2:
- jc short err_boot
- ; CX == 0
- ; CX := word(numsec_clus)
- mov cl, [rel_bpb(numsec_clus)]
- ; AX == word(cluster_hi)
- ; AX := word(cluster_hi) * word(numsec_clus)
- mul cx
- ; AX := word(cluster_lo)
- ; SI := word(cluster_hi) * word(numsec_clus)
- xchg ax, si
- ; DX:AX := word(cluster_lo) * word(numsec_clus)
- mul cx
- ; SI == word(cluster_hi) * word(numsec_clus)
- ; DX:AX := dword(offsec_clus_read)
- add dx, si
- add ax, [rel_tmp(offsec_data)]
- adc dx, [rel_tmp(offsec_data)+2]
- ; CX == word(numsec_clus)
- fs_traverse_fat_1:
- ; DX:AX++
- call read_disk
- ; SMC2: e8 xxxx (boot_find_file) -> be xxxx (MOV si, xxxx)
- _fs_traverse_fat_call:
- call boot_find_file
- ; BL == 0
- ; boot if BX >= ADDR_LIMIT
- cmp bh, ADRH_LIMIT
- jae short boot
- ; Loop (CX--)
- loop fs_traverse_fat_1
- ; AX:CX := dword(cluster)
- pop cx
- pop ax
- push bx
- ; AX:CX := dword(cluster) * 4
- add cx, cx
- adc ax, ax
- add cx, cx
- adc ax, ax
- ; BP := word(numbytes_sec)
- ; DX := word(offbytes_clus_fat)
- ; CX:AX := dword(offsec_clus_fat)
- mov bp, [rel_bpb(numbytes_sec)]
- call div32_short
- ; DX:AX := dword(offsec_clus_fat)
- ; SI := word(offbytes_clus_fat)
- ; BL == 0
- ; BX := ADDR_INFO -> ADDR_INFO+sec -> ADDR_INFO
- xchg dx, cx
- mov bh, ADRH_INFO
- add ax, [rel_tmp(offsec_fat)]
- adc dx, [rel_tmp(offsec_fat)+2]
- call read_disk
- mov si, cx
- sub bx, [rel_bpb(numbytes_sec)]
- ; [BX+SI] == dword(next_clus)
- ; AX:SI := dword(next_clus)
- ; BP := 0x0FFF
- mov ax, [bx+si+2]
- mov si, [bx+si]
- pop bx
- mov bp, 0x0fff
- and ax, bp
- ; Normal cluster if AX != 0x0FFF
- cmp ax, bp
- jne short fs_traverse_fat
- ; Check terminator
- cmp si, byte -9
- _fs_traverse_fat_1:
- jna short fs_traverse_fat
- ; SMC3: eb xx (err_boot) -> eb 00
- _fs_traverse_fat_branch:
- jmp short err_boot
- boot:
- ; DL := drive
- ; DH := file system type
- ; jump to INIT_ADDR
- mov dl, [rel_tmp(dx)]
- mov dh, 3
- jmp near ADDR_INIT
- ; SUBROUTINE
- err_boot:
- mov si, boot_error_msg
- mov cx, boot_error_msg_end-boot_error_msg
- _err_boot_loop:
- ; DF := 0
- ; AL := char
- cld
- lodsb
- mov ah, 0x0e
- mov bx, 0x0007
- int 0x10
- loop _err_boot_loop
- xor ax, ax
- ; BIOS CALL: WAIT FOR KEY
- ; AH == 0
- int 0x16
- ; BIOS CALL: REBOOT
- int 0x19
- ; just padding :)
- err_boot_final:
- hlt
- jmp short err_boot_final
- ; BOOT PROCEDURE
- boot_found_file:
- ; SI == directory entry
- ; AX:SI := dword(file_clus)
- mov ax, [si+0x14]
- mov si, [si+0x1a]
- ; CH == 0
- ; ZF := 1
- ; SMI2 -> SMC2
- ; SMI3 -> SMC3
- mov byte[_fs_traverse_fat_call], 0xbe
- and byte[_fs_traverse_fat_branch+1], ch
- ; Back to FAT32 traversal
- jmp short _fs_traverse_fat_1
- ; REGISTERS PRESERVED
- ; CX
- ; REGISTERS TO MODIFY
- ; AX, DX, BX
- ; REGISTERS TO DESTROY
- ; SI, BP
- ; PARAMETERS
- ; BX: BUFFER
- ; DX:AX: LBA
- ; RESULTS
- ; BX: address of empty space
- ; DX:AX: LBA+1
- read_disk:
- _read_disk_init:
- push ax
- push cx
- push dx
- _read_disk_branch:
- ; SMC1: eb xx (_read_disk_noext) -> eb 00
- jmp short _read_disk_noext
- _read_disk_ext:
- cld
- ; DI == REL_BASE
- ; SI := ext13h_buf
- ; DI := ext13h_buf
- lea si, [rel_tmp(ext13h_buf)]
- push di
- mov di, si
- ; AX == LBA_LO
- ; AX := 0x0010
- push ax
- mov ax, 0x0010
- stosw
- ; AH == 0
- ; AX := 0x0001
- mov al, 0x01
- stosw
- ; AX := BUFFER
- mov ax, bx
- stosw
- ; AX := 0
- xor ax, ax
- stosw
- ; AX := LBA_LO
- pop ax
- stosw
- ; AX := LBA_HI
- ; DX := LBA_LO
- xchg ax, dx
- stosw
- ; AX := 0
- xor ax, ax
- stosw
- stosw
- ; DI := REL_BASE
- ; EXTENDED READ DISK
- ; AH := 0x42
- ; AL == 0 (may be used by some BIOS)
- ; DL := byte(drive)
- ; SI := ext13h_buf
- ; Contents of ext13h_buf(si):
- ; +00: 0x0010 (size of ext13h_buf)
- ; +02: 0x0001 (sectors to read)
- ; +04: BUFFER
- ; +06: 0x0000 (segment 0)
- ; +08: LBA_LO
- ; +0a: LBA_HI
- ; +0c: 0x0000
- ; +0e: 0x0000
- mov ah, 0x42
- pop di
- _read_disk_perform:
- mov dl, [rel_tmp(dx)]
- int 0x13
- ; CF == error
- jc short err_boot
- _read_disk_fini:
- pop dx
- pop cx
- pop ax
- ; BX += word(numbytes_sec)
- ; DX:AX++
- add bx, [rel_bpb(numbytes_sec)]
- inc ax
- jnz _read_disk_fini_1
- inc dx
- _read_disk_fini_1:
- ret
- ; BOOT PROCEDURE
- ; REGISTERS PRESERVED
- ; CX
- ; REGISTERS TO DESTROY
- ; SI
- ; PARAMETERS
- ; BX: INIT_ADDR + bytes of sector
- ; RESULTS
- ; (jump to boot_find_file_1)
- ; SI: found directory entry
- boot_find_file:
- mov bp, bx
- ; BX := SI := INIT_ADDR
- sub bx, [rel_bpb(numbytes_sec)]
- mov si, bx
- boot_find_file_1:
- ; SI == directory entry
- ; +00-0A: FILE NAME
- ; +0B-0B: FILE ATTRIBUTES
- ; +0D-0C: METADATA?
- ; +0D-0D: CREATE_TIME_MS
- ; +0E-0F: CREATE_TIME
- ; +10-11: CREATE_DATE
- ; +12-13: ACCESS_DATE
- ; +14-15: CLUSTER_HI
- ; +16-17: MODIFY_TIME
- ; +18-19: MODIFY_DATE
- ; +1A-1B: CLUSTER_LO
- ; +1C-1F: FILE_SIZE
- ; [SI+0] == file name (first byte)
- ; no subsequent entries if 0
- ; [SI+0x0B] == file attributes
- ; File attributes to reject:
- ; 0x08: Volume Label (or VFAT File Name)
- ; 0x10: Subdirectory
- ; 0x40: Device
- cmp byte[si], ch
- je short err_boot
- test byte[si+0x0b], 0x58
- jnz short boot_find_file_next
- boot_find_file_cmp:
- ; CX == directory table loop remaining
- ; CX := 11 (length of file name)
- ; SI == directory entry
- ; DI := boot_file
- ; DF := 0
- push cx
- push si
- push di
- mov cl, 0x0b
- mov di, boot_file
- cld
- repe cmpsb
- pop di
- pop si
- pop cx
- ; found directory entry if file names are equal
- je short boot_found_file
- boot_find_file_next:
- ; SI := next directory entry
- add si, byte 0x20
- cmp si, bp
- jb boot_find_file_1
- ret
- ; PART of read_disk
- read_disk_chunk_2:
- _read_disk_noext:
- ; BP := word(numsec_track)
- ; CX:AX := dword(LBA)
- mov bp, [rel_bpb(numsec_track)]
- mov cx, dx
- ; CX:AX := dword(LBA) / word(numsec_track)
- ; == dword(HEAD_CYLINDER)
- ; DX := dword(LBA) % word(numsec_track)
- call div32
- ; SI := DX == word(SECTOR)
- inc dx
- mov si, dx
- and si, byte 0x3f
- ; BP := word(numheads)
- ; CX:AX := dword(HEAD_CYLINDER) / word(numheads)
- ; == dword(CYLINDER)
- ; DX := dword(HEAD_CYLINDER) % word(numheads)
- ; == word(HEAD)
- mov bp, [rel_bpb(numheads)]
- call div32
- ; [INT 13h's CYLINDER is a word value (discard CX)]
- ; CL := 6
- ; AL == byte(CYLINDER_LO)
- ; AH := byte(CYLINDER_HI) << 6
- mov cl, 6
- shl ah, cl
- ; AL := byte(CYLINDER_HI) << 6 | byte(SECTOR)
- ; AH := byte(CYLINDER_LO)
- xchg al, ah
- or ax, si
- ; AX == word(CYLINDER/SECTOR)
- ; CX := word(CYLINDER/SECTOR)
- xchg ax, cx
- ; DL == byte(HEAD)
- ; DH := byte(HEAD)
- mov dh, dl
- ; READ DISK
- ; AX := 0x0201 (0x02: read, 0x01: sectors to read)
- ; DL := byte(drive)
- ; DH == byte(HEAD)
- ; CX == word(CYLINDER/SECTOR)
- ; BX == BUFFER
- mov ax, 0x0201
- jmp short _read_disk_perform
- ; REGISTER TO MODIFY
- ; AX CX DX
- ; PARAMETERS
- ; CX:AX: DIVIDEND
- ; BP: DIVISOR
- ; RESULTS
- ; CX:AX: DIVIDEND / DIVISOR
- ; DX: DIVIDEND % DIVISOR
- div32:
- xchg ax, cx
- div32_short:
- xor dx, dx
- div bp
- xchg ax, cx
- div bp
- ret
- boot_file:
- db 'KERNEL BIN'
- boot_error_msg:
- db 'No System Disk.',0x0d,0x0a
- db 'Press any key to reboot.',0x0d,0x0a
- boot_error_msg_end:
- _end:
- times 512-2-($-$$) db 0x00
- dw 0xaa55
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement