CODE:
.code16gcc
.macro call operand
callw \operand
.endm
.macro ret
retw
.endm
.org 0x7C00
.global _start
_start:
cli
mov $0xFFF0,%sp
xor %ax,%ax
mov %ax,%ds
mov %ax,%es
mov %ax,%ss
# init the disk
xor %ah,%ah
mov $0x80,%dl
int $0x13
jc errorexit
# read the first partition
mov $0x0201,%ax
mov (0x7DBF),%dh
mov (0x7DC0),%cx
mov $0x7E00,%bx
int $0x13
jc errorexit
# pass the API adress and jump
mov $initaccess,%ax
mov $outputnumber,%bx
mov $searchfile,%cx
mov $getfiledata,%dx
mov $errorexit,%si
pushw %ss # %ss should be 0x0000
pushw $0x7E00
retfw
errorexit:
mov %ah,%cl
xor %ax,%ax
mov %ax,%es
mov $0x0300,%ax
xor %bx,%bx
int $0x10
mov $0x1301,%ax
mov $0x0007,%bx
mov $16,%cx
int $0x10
xor %ch,%ch
call outputnumber
mov $0x0D,%al
int $0x10
mov $0x0A,%al
int $0x10
hltloop:
hlt
jmp hltloop
#put number to output on %cx then call this
outputnumber:
# push %ax
# push %cx
# push %dx
# push %bx
pusha
pushw $10
mov $10,%bx
mov %cx,%ax
MAKEOUTPUTLOOP:
xor %dx,%dx
div %bx
push %dx
test %ax,%ax
jnz MAKEOUTPUTLOOP
mov $0x07,%bl
OUTPUTLOOP:
pop %ax
cmp $10,%al
jae OWARIDAYO
add $48,%al
mov $0x0E,%ah
int $0x10
jmp OUTPUTLOOP
OWARIDAYO:
popa
# pop %bx
# pop %dx
# pop %cx
# pop %ax
ret
# set parameters for disk access
# input %ax : address for subroutine readsector
# input %bx : start sector of FAT
# input %cx : start sector of root directory info
# input %dx : start sector of data of files
initaccess:
mov %ax,readsector
mov %bx,start_of_fat
mov %cx,start_of_root
mov %dx,start_of_file
ret
# search specified file from root
# input %dx : address of file name to search
# return %ax : first sector of the file (0 if not found)
# return %bx : file size (lower 16-bits) (undefined if not found)
# return %cx : file size (higher 16-bits) (undefined if not found)
searchfile:
push %si
push %di
push %ds
push %es
xor %bx,%bx
mov %bx,%ds
mov %bx,%es
mov start_of_root,%ax
mov %ax,%cx
mov $0x70,%bh # %bx = 0x7000
call *readsector
mov (0x7E11),%cx
mov $0x20,%cx # debug
SEARCHLOOP:
testb $0x08,0xB(%bx)
jnz SEARCHSKIP
mov %dx,%si
mov %bx,%di
# make it inline to save amount of data
# call filematch
# compare file name
# input %si : file name to search
# input %di : file name on disk
# output : ZF=1 if same, ZF=0 if differ
# breaks %si,%di
filematch:
push %cx
push %ax
mov $11,%cx
dec %si
dec %di
COMPLOOP:
inc %si
inc %di
mov (%si),%al
cmp (%di),%al
jnz COMPEXIT
loop COMPLOOP
COMPEXIT:
pop %ax
pop %cx
# ret
jz SEARCHFOUND
SEARCHSKIP:
add $0x20,%bx
cmp $0x7200,%bx
jb SEARCH_NOTENDOFSECTOR
inc %ax
push %cx
mov %ax,%cx
mov $0x7000,%bx
call *readsector
pop %cx
SEARCH_NOTENDOFSECTOR:
loop SEARCHLOOP
xor %ax,%ax
jmp SEARCHEXIT
SEARCHFOUND:
mov 0x1A(%bx),%ax
mov 0x1E(%bx),%cx
mov 0x1C(%bx),%bx
SEARCHEXIT:
pop %es
pop %ds
pop %di
pop %si
ret
# get data from FAT
# input %ax : the index to get data
# output %ax : cluster ID on the index (overwrite)
getfatdata:
push %bx
push %cx
push %ds
push %es
xor %bx,%bx
mov %bx,%ds
mov %bx,%es
mov $0x72,%bh # %bx = 0x7200
mov %ax,%cx
shr $8,%cx # div by 0x100
cmp fat_cache,%cx
je FAT_CACHE_HIT
mov %cx,fat_cache
add start_of_fat,%cx
call *readsector
FAT_CACHE_HIT:
mov %ax,%cx
# and $0xFF,%cx
xor %ch,%ch
shl $1,%cx
add %cx,%bx
mov (%bx),%ax
pop %es
pop %ds
pop %cx
pop %bx
ret
#convert index of FAT to sector ID
# input %dx : index of FAT
# output %dx : sector ID (overwrite)
fattosector:
push %ax
push %cx
mov %dx,%ax
sub $2,%ax
xor %ch,%ch
mov (0x7E0D),%cl
mul %cx
add start_of_file,%ax
mov %ax,%dx
pop %cx
pop %ax
ret
# get file data from disk
# input %ax : the first sector to read
# input %es:%bx : address to read data (note: if %bx is not a multiple of 0x200, it may be broken)
# input %cx : size to read (note: size written will be rounded up to a multiple of 0x200)
# input %dx : size to read (higher 16 bits)
getfiledata:
test %cx,%cx
jnz NO_NODATATOREAD
test %dx,%dx
jz NODATATOREAD
NO_NODATATOREAD:
pusha
# push %ax
# push %cx
# push %dx
# push %bx
# push %si
push %ds
push %es
mov %dx,%si
xor %dx,%dx
mov %dx,%ds
mov (0x7E0D),%dl
mov %dx,%di
mov %ax,%dx
call fattosector
GETFILELOOP:
push %cx
mov %dx,%cx
call *readsector
pop %cx
inc %dx
dec %di
jnz GETFILE_SAMECLUSTER
push %cx
xor %cx,%cx
mov (0x7E0D),%cl
mov %cx,%di
pop %cx
call getfatdata
mov %ax,%dx
call fattosector
GETFILE_SAMECLUSTER:
add $0x200,%bx
jnc ADDR_NOCARRY
# push %ax
# mov %es,%ax
# add $0x1000,%ax
# add $0x10,%ah
# mov %ax,%es
# pop %ax
mov %es,%bp
add $0x1000,%bp
mov %bp,%es
ADDR_NOCARRY:
sub $0x200,%cx
ja GETFILELOOP
test %si,%si
jz DATAREADEND
dec %si
jmp GETFILELOOP
DATAREADEND:
pop %es
pop %ds
popa
# pop %si
# pop %bx
# pop %dx
# pop %cx
# pop %ax
NODATATOREAD:
ret
errorexit_str:
.ascii "Disk IO error : "
start_of_fat:
.word 0x0000
start_of_root:
.word 0x0000
start_of_file:
.word 0x0000
fat_cache:
.word 0xFFFF
readsector:
.word 0x7C00