; Reset the disk system using int 13h / AH = 00h disk_reset: pusha stc mov ah, 00h int 13h popa ret ; ------------------------------------ ; Load the root directory into memory (into disk_buffer which is 24000h) disk_load_root: pusha mov ax, 19 ; First sector of root entry call math_lba_to_chs ; Assigns ch, cl and dh the correct values xor ax,ax ; clear ax so I can use it on next line mov dl, [ebr_drive_number] ; Drive number mov ah, 02h ; BIOS ah code for read disk sectors to memory mov al, 0Ch ; Root directory has 12 sectors mov si, root_buffer ; ES:BX should point to our buffer mov bx, si ; repeat drive read 3 times (incase of random error) mov di, 3 ; counter ; This is basically ; for di in range(3,1,1): ; We test to see if we can read the disk 3 times .try_read_disk: ; Try read the floppy three times ; When the disk is tried to be read, the CF flag will be ; set if there's an error, so we just clear it to return it to ; the default state stc ; sets the cf flag int 13h jnc .done_read ; jump if cf = 0 call disk_reset ; Reset drivers of disk dec di ; di -= 1 test di, di ; if di = 0 jnz .try_read_disk jmp .disk_error .disk_error: mov si, disk_read_fail call os_print_string popa ret .done_read: popa ret ; --------------------------------------------- ; Reads a certain number of sectors into memory ; IN ; ax = LBA ; es:bx = area to read to/write from ; [read_write_flag] = 02 or 03 for read or write ; dl = ebr drive number ; int 13h/ah = 02h/03h read/write disk sectors into memory ; al = number of sectors to read ; ah = read/write 02=read, 03=write IMPORTANT ; ch = cylinder number ; cl = sector number ; dh = head number ; dl = drive number ; es:bx = points to data buffer disk_read_or_write: push ax push bx push cx push dx push di ; cl = sector ; ch = cylinder ; dh = head ; dl = drive call math_lba_to_chs ; Get the chs address mov ah, [read_write_flag] mov al, 1 ; repeat drive read 3 times (incase of random error) mov di, 3 ; counter ; This is basically ; for di in range(3,1,1): ; We test to see if we can read the disk 3 times .retry: ; When the disk is tried to be read, the CF flag will be ; set if there's an error, so we just clear it to return it to ; the default state stc ; sets the cf flag int 13h jnc .done_read ; jump if cf = 0 call .disk_reset ; Reset drivers of disk dec di ; di -= 1 test di, di ; if di = 0 jnz .retry .fail_disk_read: pop di pop dx pop cx pop bx pop ax ret ; int 13h / ah = 00h reset disk system .disk_reset: pusha mov ah, 0 ; Reset drive stc int 13h jc .fail_disk_read popa ret .done_read: pop di pop dx pop cx pop bx pop ax ret ; ------------------------------------- ; CLEAR DATA ; Uses the metadata buffer to determine the file size in the data buffer and clears it. disk_clear_file_buffer: pusha mov si, metadata_buffer mov cx, [si+28] ; MOve the filelength into the ax shr cx, 1 ; Divide by 4 because we'll write over using double words mov si, empty_word lodsb ; Load the empty dword mov di, file_buffer .loop: stosb dec cx cmp cx, 0 jbe .loop .finish: popa ret disk_clear_output_buffer: pusha mov cx, 0x7f0 ; Length of the output buffer mov si, empty_word lodsb ; Load the empty word into ax mov di, output_buffer .loop: stosb ; Store empty dword in di dec cx cmp cx, 0 ja .loop .finish: popa ret ; ------------------------------------- ; IN ; si: filename ; OUT ; data_buffer: file contents ; TODO use predefined data for calculations disk_load_file: pusha call os_string_length ; cl = string length cmp cl, 11 ja .filename_too_long mov di, fat12_file_name call os_format_fat_filename ; Prepare values mov si, root_buffer xor bx,bx .search_root: mov di, fat12_file_name ; Move the name of the kernel into di mov cx, 11 ; length of filenames in fat12 push si ; Preserve si repe cmpsb ; Repeat a comparison of bytes between file name and current bytes until it finds a match pop si ; Retrieve si je .found_file add si, 32 ; increment di to the next directory entry inc bx cmp bx, [bdb_dir_entries_count] ; Have we reached the number of directories that exist jl .search_root ; Repeat search jmp .file_not_found ; If the last dir has been searched, then there is no kernel .found_file: call disk_clear_file_buffer mov di, metadata_buffer mov cx, 32 .write_metadata: ; Write data to metadata buffer lodsb stosb sub cx, 1 cmp cx, 0 jne .write_metadata .read_kernel: sub si, 32 mov ax, [si+28] ; File length mov [file_length], ax mov ax, [si+26] ; ax is now a pointer to the pointer to the file relative to the data segments :D add ax, 1Fh mov [file_cluster], ax ; Setup registers for disk read mov si, file_buffer mov bx, si mov dl, [ebr_drive_number] mov ch, 02h mov [read_write_flag], ch ; READ call disk_read_or_write ; Load file from disk into memory jmp .done .file_not_found: mov si, file_not_found call os_print_string jmp .done .filename_too_long: mov si, too_long_filename call os_print_string jmp .done .done: popa ret ; Write data to file ; takes the contents in the data buffer for a fixed ; number of characters definied by [file_length] ; and write it to the file that si points to ; It also must edit the fat entry data disk_write_file: pusha ; Check if file name is too long call os_string_length ; cl = string length cmp cl, 11 ja .filename_too_long ; Convert file name to a fat filename mov di, fat12_file_name call os_format_fat_filename ; Locate the file entry in memory ; Prepare values mov si, root_buffer xor bx,bx .search_root: mov di, fat12_file_name ; Move the name of the kernel into di mov cx, 11 ; length of filenames in fat12 push si ; Preserve si repe cmpsb ; Repeat a comparison of bytes between file name and current bytes until it finds a match pop si ; Retrieve si je .found_file add si, 32 ; increment di to the next directory entry inc bx cmp bx, [bdb_dir_entries_count] ; Have we reached the number of directories that exist jl .search_root ; Repeat search jmp .file_not_found ; If the last dir has been searched, then there is no kernel .found_file: ; Find where the file is on the disk mov ax, [si+28] ; File length entry mov [file_length], ax mov ax, [si+26] ; ax is now a pointer to the pointer to the file relative to the data segments :D add ax, 1Fh mov [file_cluster], ax ; Setup registers for disk read mov si, file_buffer mov bx, si mov dl, [ebr_drive_number] mov ch, 03h mov [read_write_flag], ch ; WRITE call disk_read_or_write ; Load file from disk into memory jmp .finish ; DI now points to a fat12 formatted file name ; Write to those sectors ; Update FAT entry .file_not_found: ; TODO create a file if it's not found mov si, file_not_found call os_print_string jmp .finish .filename_too_long: mov si, too_long_filename call os_print_string jmp .finish .finish: popa ret ; TODO support long file names ; Store a list of the files in file_buffer ; in a human readable format ; OUT ; output_buffer: the list (string) disk_list_contents: pusha mov si, root_buffer mov di, output_buffer .loop: call string_unformat_fat_filename mov cx, 000Ch sub cx, [file_name_length] add di, [file_name_length] mov al, 20h .space_loop: stosb dec cx cmp cx, 0 jne .space_loop .file_attribute: add si, 11d lodsb push si mov si, read_only cmp al, 1h je .add_string mov si, hidden cmp al, 2h je .add_string mov si, system cmp al, 4h je .add_string mov si, volume cmp al, 8h je .add_string mov si, directory cmp al, 10h je .add_string mov si, archive cmp al, 20h je .add_string .after_file_attributes: pop si mov al, 0Ah stosb add si, 20d lodsb ; +1 dec si ; -1 cmp al, 0 ; You've come to the end of the root entries je .finish cmp al, 00E5h ; E5h is a marker that the Fat entry is available je .finish jmp .loop .add_string: .add_string_loop: lodsb cmp ax, 00h je .after_file_attributes stosb jmp .add_string_loop .finish: mov cx, output_buffer sub di, cx mov [file_length], di stosb popa ret