EttinOS/src/LOADF.INC

479 lines
8.9 KiB
Plaintext

;Load a file named at SI as a string ending in a null to the offset BX
;and store the file size in CX and the error codes in AL:
; * AL = 0x0: Succesful load
; * AL = 0x1: Drive not found
; * AL = 0x2: Unable to read disk
; * AL = 0x4: File or command not found
; * AL = 0x8: Not enough memory
loadf:
;Store BX, DX, SI, and DI in the stack
push bx
push dx
push si
push di
;Store the current drive and offset
mov word [.pointer], bx
mov dl, byte [drive]
mov byte [.drive], dl
;Change the drive if needed
;Check for a drive specification
cmp byte [si + 0x1], ":"
jne .convert
;Get the BIOS equipment list
int 0x11
;Get the number of floppy drives
times 0x6 shr ax, 0x1
and ax, 0x3
inc ax
;Set the loop and drive letter counters and the drive letter and number
mov cx, ax
mov di, driveletters
mov al, [si]
mov dl, 0x0
;Check which drive to change to
.checkdrive:
cmp al, [di]
je .contchdrive
inc di
cmp al, [di]
je .contchdrive
inc di
inc dl
loop .checkdrive
;Set AL to 0x1, CX to 0x0, and print an error message
mov si, .driverrormsg
mov ah, 0x2
int 0x21
mov al, 0x1
mov cx, 0x0
jmp .done
;Change the drive
.contchdrive:
mov [.drive], dl
;Move to the file name
add si, 0x2
;Set DI at .file and initialise it with spaces
.convert:
mov di, .file
mov cx, 0xb
mov al, 0x20
rep stosb
sub di, 0xb
;Convert the main part of the file name into FAT format
;Set the length counter
mov bl, 0x8
;Load a character
.nameloop:
lodsb
;Check for a period
cmp al, 0x2e
je .initext
;Check for everything else and convert to upper case
call .checkconv
;Load the next character
jmp .nameloop
;Convert the extension into FAT format
;Set DI and the length counter for the extension
.initext:
mov bl, 0x3
mov di, .file+0x8
;Load a character
.extloop:
lodsb
;Check for a period
push ax
cmp al, 0x2e
je .error
pop ax
;Check for everything else and convert to upper case
call .checkconv
;Load the next character
jmp .extloop
;Set AL to 0x4, CX to 0x0, and print an error message
.error:
pop ax
mov si, .filerrormsg
mov ah, 0x2
int 0x21
mov al, 0x4
mov cx, 0x0
jmp .done
;Find and load the file
.load:
pop ax
;Load the disk description table
;Set the source
mov dl, [.drive]
mov ch, 0x0
mov dh, 0x0
mov cl, 0x1
;Set the destination
mov si, buffer
mov bx, si
;Set the size
mov al, 0x1
;Load the disk description table
mov ah, 0x2
int 0x13
jnc .storevalues
;Set AL to 0x2, CX to 0x0, and print an error message
mov si, .diskerrormsg
mov ah, 0x2
int 0x21
mov al, 0x2
mov cx, 0x0
jmp .done
;Store the disk values used for the rest of the call
.storevalues:
mov ax, [buffer + 0xb]
mov [.sectorsize], ax
mov al, [buffer + 0xd]
mov [.clustersize], al
mov ax, [buffer + 0xe]
mov [.reservedsectors], ax
mov al, [buffer + 0x10]
mov [.fats], al
mov ax, [buffer + 0x11]
mov [.rootentries], ax
mov ax, [buffer + 0x16]
mov [.sectorsperfat], ax
mov ax, [buffer + 0x18]
mov [.sectorspertrack], ax
mov ax, [buffer + 0x1a]
mov [.heads], ax
;Calculate and store variables not found in the BPB
;Start of the root
mov ah, 0x0
mov al, [.fats]
mul word [.sectorsperfat]
add ax, [.reservedsectors]
mov [.rootstart], ax
;Size of the root in sectors
mov ax, [.rootentries]
mov dx, 0x20
mul dx
mov dx, 0x0
div word [.sectorsize]
mov [.rootsectors], ax
;Start of data
add ax, [.rootstart]
mov [.datastart], ax
;Load the root
;Set the source
mov ax, [.rootstart]
;Set the destination
mov si, buffer
mov bx, si
;Set the size
mov cx, [.rootsectors]
;Store the source and the loop counter in the stack
.loadrootsector:
push ax
push cx
;Set the source
call .calcsource
;Set the size
mov al, 0x1
;Load a sector
mov ah, 0x2
int 0x13
;Load the loop counter and the source from the stack
pop cx
pop ax
;Set the next sector
add ax, 0x1
add bx, word [.sectorsize]
;Load the next sector
loop .loadrootsector
;Search the root for the file entry
;Set DI to the root
mov di, buffer
;Set the number of root entries
mov cx, word [.rootentries]
;Set the entry pointer
mov ax, 0x0
;Store the loop counter in the stack
.search:
push cx
;Check for the file entry
mov si, .file
mov cx, 0xb
rep cmpsb
je .checksize
;Set DI at the next entry
add ax, 0x20
mov di, buffer
add di, ax
;Load the loop counter from the stack
pop cx
;Search the next entry
loop .search
;Set AL to 0x4, CX to 0x0, and print an error message
mov si, .filerrormsg
mov ah, 0x2
int 0x21
mov al, 0x4
mov cx, 0x0
jmp .done
;Check and store the file size
;Load CX from the stack
.checksize:
pop cx
;Check for files larger than 64 KiB
cmp word [di + 0x13], 0x0
jne .sizerror
;Get the cluster size in bytes
mov ah, 0x0
mov al, [.clustersize]
mul word [.sectorsize]
mov bx, ax
;Store the file size
mov ax, [di + 0x11]
mov word [.size], ax
;Check for files smaller than 64 KiB but too large to fit into memory
jc .sizerror
dec ax
mov dx, 0x0
div bx
mul bx
add ax, [.pointer]
jnc .loadfat
;Set AL to 0x8, CX to 0x0, and print an error message
.sizerror:
mov si, .sizerrormsg
mov ah, 0x2
int 0x21
mov al, 0x8
mov cx, 0x0
jmp .done
;Load the FAT
.loadfat:
;Store the address of the first cluster
mov ax, [di + 0xf]
mov [.cluster], ax
;Set the source
mov ax, [.reservedsectors]
call .calcsource
;Set the destination
mov bx, buffer
;Set the size
mov ax, [.sectorsperfat]
;Load the FAT
mov ah, 0x2
int 0x13
;Load a cluster
.loadcluster:
;Set the source
mov ax, word [.cluster]
sub ax, 0x2
mul byte [.clustersize]
add ax, [.datastart]
;Set the destination
mov bx, word [.pointer]
;Set the size
mov ch, 0x0
mov cl, byte [.clustersize]
;Store the loop counter in the stack
.loadsector:
push cx
;Set the source
call .calcsource
;Set the size
push ax
mov al, 0x1
;Load a sector
mov ah, 0x2
int 0x13
pop ax
;Set the next sector
add ax, 0x1
add bx, word [.sectorsize]
;Load the loop counter from the stack
pop cx
;Load the next sector
loop .loadsector
;Calculate the next cluster
;Check if the cluster is even or odd
mov ax, [.cluster]
mov dx, 0x0
mov bx, 0x3
mul bx
mov bx, 0x2
div bx
mov si, buffer
add si, ax
mov ax, word [si]
or dx, dx
jz .even
;If the cluster is odd shift out the first four bits
times 0x4 shr ax, 0x1
jmp .contcalc
;If the cluster is even mask out the final four bits
.even:
and ax, 0xfff
.contcalc:
;Check for the file end
cmp ax, 0xff8
jge .success
;Store the address of the next cluster
mov word [.cluster], ax
;Set the destination of the next cluster
mov ax, [.sectorsize]
mul word [.clustersize]
add word [.pointer], ax
;Load the next cluster
jmp .loadcluster
;Set AL to 0x0 and load the file size to CX if the load was succesful
.success:
mov al, 0x0
mov cx, [.size]
;Clear the stack
.done:
;Load DI, SI, DX, and BX from the stack
pop di
pop si
pop dx
pop bx
;Set AH to its initial value
mov ah, 0x0
;Return
iret
;Data
.drive db 0x0
.sectorsize dw 0x0 ;bytes
.clustersize db 0x0 ;sectors
.reservedsectors dw 0x0
.fats db 0x0
.rootentries dw 0x0
.sectorsperfat dw 0x0
.sectorspertrack dw 0x0
.heads dw 0x0
.rootstart dw 0x0
.rootsectors dw 0x0
.datastart dw 0x0
.file times 0xb db 0x20
.size dw 0x0
.cluster dw 0x0
.pointer dw 0x0
.driverrormsg db "Drive not found", 0x0
.diskerrormsg db "Unable to read disk", 0x0
.filerrormsg db "File or command not found", 0x0
.sizerrormsg db "Not enough memory", 0x0
;***
;Check the file name and convert to upper case
.checkconv:
;Check for the string end, length limit, and invalid characters
;Check for the string end
cmp al, 0x0
je .load
;Check for the length limit
cmp bl, 0x0
je .error
;Check for invalid characters
cmp al, 0x22
je .error
cmp al, 0x2a
jl .contcheck1
cmp al, 0x2c
jg .contcheck1
jmp .error
.contcheck1:
cmp al, 0x2f
je .error
cmp al, 0x3a
jl .contcheck2
cmp al, 0x3f
jg .contcheck2
jmp .error
.contcheck2:
cmp al, 0x5b
jl .contcheck3
cmp al, 0x5d
jg .contcheck3
jmp .error
.contcheck3:
cmp al, 0x7c
je .error
;Check for lower case and convert it to upper case
;Check for lower case
cmp al, 0x61
jl .storech
cmp al, 0x7a
jg .storech
;Convert lower to upper case
sub al, 0x20
;Store the character
.storech:
stosb
;Decrease the counter
dec bl
;Return
ret
;***
;Calculate the source arguments for loading data from the disk
.calcsource:
;Store AX and BX in the stack
push ax
push bx
;Calculate the cylinder, head, and sector
;Store the logical sector in BX
mov bx, ax
;Calculate the sector
mov dx, 0x0
div word [.sectorspertrack]
add dl, 0x1
mov cl, dl
;Load the logical sector from BX
mov ax, bx
;Calculate the head and cylinder
mov dx, 0x0
div word [.sectorspertrack]
mov dx, 0x0
div word [.heads]
mov dh, dl ;Head
mov ch, al ;Cylinder
;Load the drive number
mov dl, byte [.drive]
;Load BX and AX from the stack
pop bx
pop ax
;Return
ret