-1

The code below is of a program which tries to list files located in as FAT12 formatted disk.

From my basic understanding I know that in order to find a file you need to look first in the root directory which is located at 19th sector in a physical disk. This root directory is 14 sectors in size.

There is a certain routine I've taken to list files in a FAT12:

Step 1: preparing a memory location to load each sector of the root directory which is location 0x0:0x1000

Step 2: Determining the size of root directory - formular i've used *Root_Directory_Size = (size of each entry * total number of entries) / size of sector*

Step 3: Figuring out the starting sector number of the root directory using the following formular = *(Number of fat * Size of each fat) + Reserved sectors + hidden sectors*

Step 4: After calculating the above offset, the program then starts to load each sector into location 0x0:0x1000, in each entry the program checks for the following first bytes in each entry the empty entry(0xe5) and the 0x00 this bytes indicates either root entry is empty or contains a deleted file

So here the challenge is after doing all this stuff I'm not getting a even character of a existing file on my screen.

;This is a basic program which reads files on FAT12 and displays their names on the screen:

;This program is loaded into RAM by a bootloader not
;bios which I have managed to accomplish
[org 0x00]
[bits 16]

mov ax, 0x2000
mov ds, ax
mov es, ax

;since we ve been loaded by bootloader into memory obviously the value of dl which normally contains
;drive letter has been altered by bootloader program will skip this routine 
;and assume that our first boot drive is byte 0x80
;mov [drive_letter], dl

mov bx, file_name

mov si, bx  ; since bx points to the first entry of the root directory which contains the name of the file
mov di, buffer ; the location of root directory entry
add di, [next_section]
mov cx, 11 ; string length
cld

rep movsb

mov dx, buffer
mov cx, 14
call print_string

mov ah, 8   ; read disk parameter
mov dl, [drive_letter]
int 13h
jc read_error
and cx, 3fh
mov [SectorsPerTrack], cx
movzx dx, dh ; high word has been zeroed out
add dx, 1
mov [Head], dx

xor ax, ax
mov dl, [drive_letter]
int 13h
jc read_error

;#calculating the root start

mov ax, 19 ; root directory logical block begins at 19th sector

mov [root_start], ax ; now we have the starting sector of the root directory

;#load root director entry into memory sector by sector

mov cx, 14
mov ax, [root_start]
mov bx, 0x3000
mov es, bx
xor bx, bx

read_next_sector:
push cx
push ax   ; store lba address in the stack

xor bx, bx

call read_sectors

read_next_entry:
mov si, bx ; since bx points to the first entry of the root directory which contains the name of the file
mov di, buffer ; the location of root directory entry
add di, [next_section]
mov cx, 11 ; string length
cld

rep movsb

push bx
mov bx, [next_section]
add bx, 11
mov [next_section], bx
pop bx

add bx, 32 ; point to the next entry
cmp bx, 512 ; have we exceeded the sector size if yes excute the code below
jne read_next_entry

pop ax  ; retrive the current logical address from the stack
pop cx  ; retrive count from the stack
inc ax  ; load next sector when we loop back again
loop read_next_sector

mov ah, 0x0e
xor bh, bh
mov al, 'L'
int 10h

mov dx, buffer
mov cx, 1000

call print_string

jmp $


print_string:

push cx
out_char:
mov ah, 0x0e
mov bx, dx
mov al, [bx]
xor bh, bh
int 10h
inc dx
pop cx

loop print_string

ret

file_found:
mov ah, 0x0e
xor bh, bh
mov al, 'Z'
int 10h

hlt

jmp $

read_error:
mov ah, 0x0e
xor bh, bh
mov al, 'R'
int 10h

xor ah, ah
int 16h

int 19h

hlt 

jmp $

read_sectors:
push ax
push bx

xor dx, dx
mov bx, [SectorsPerTrack]; sectors per track
div bx

inc dx
mov cl, dl

xor dx, dx
mov bx, [Head] ; number of heads
div bx

mov ch, al
xchg dl, dh

;call other function routines
mov ah, 2
mov al, 1
pop bx
mov dl, [drive_letter]
int 13h
jc read_error
pop ax ; restore logical block address before exiting the read_sector routine

ret

drive_letter db 0x80   
SectorsPerTrack dw 0
Head dw 0

root_size dw 14
root_start dw 0

next_section dw 0

file_name db 'KERNEL  BIN', 0

buffer db 'No file found', 0
buffer1 times 1000 db 0

times 1024 db 0
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847

2 Answers2

1

FAT12 formatted disk.

;since we ve been loaded by bootloader into memory obviously the value of dl which normally contains ;drive letter has been altered by bootloader program will skip this routine ;and assume that our first boot drive is byte 0x80

Wouldn't this be sooner a boot drive code for the first floppy drive, so 0x00?


Your code begins with copying the 11-characters filename KERNEL BIN over the error message No file found. This produces the 13-characters text KERNEL BINnd. Hereafter you print 14 characters to the screen. This is all very strange!


A segmentation problem!

mov cx, 14
mov ax, [root_start]
mov bx, 0x3000
mov es, bx
xor bx, bx
read_next_sector:
push cx
push ax ; store lba address in the stack
xor bx, bx
call read_sectors
read_next_entry:
mov si, bx ; since bx points to the first entry of the root directory which contains the name of the file
mov di, buffer ; the location of root directory entry
add di, [next_section]
mov cx, 11 ; string length
cld
rep movsb

This final movsb wil not move to the buffer that is located in segment 0x2000 because the ES segment register is still pointing at the 0x3000 segment!

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
0

This is a corrected code, that if runs will execute as per expected results. This program will display files and directories stored in FAT12, Son of a file explorer program

Here is the code:

[org 0x4000] ; my bootloader loaded us at loc 0x00:0x4000, so this will be our starting loc of our code
[bits 16]

xor ax, ax
mov ds, ax
mov es, ax

mov bp, 0x9000
mov sp, bp       ; set the stack at the top of our code

%macro set_cursor 2

mov ah, 0x02
xor bh, bh
mov dl, %1
mov dh, %2
int 10h

%endmacro

%macro get_pos 0

mov ah, 03h
xor bh, bh
int 10h

%endmacro

mov ax, 0010h
int 10h

mov dl, 0
mov [drive_letter], dl

mov ah, 8
mov dl, [drive_letter]
int 13h
jc read_error
and cx, 3fh
mov [SectorsPerTrack], cx
movzx dx, dh ; high word has been zeroed out
add dx, 1
mov [Head], dx

xor ax, ax
mov dl, [drive_letter]
int 13h
jc read_error

;#calculating the root start

mov ax, 19 ; root directory logical block begins at 19th sector

mov [root_start], ax ; now we have the starting sector of the root directory

;#load root director entry into memory sector by sector

mov cx, 14
mov ax, [root_start]
xor bx, bx
mov es, bx

read_next_sector:
push cx
push ax   ; store lba address in the stack

mov bx, 0x5000
mov [entry_pointer], word 0
call read_sectors

check_if_empty:
mov al, [bx]
cmp al, 0xe5     ; thats a deleted file skip it
je read_next_entry

mov al, [bx]
cmp al, 0x00     ; there z no file here skip it
je read_next_entry

mov al, [bx+0x08]
cmp al, 'B'    ; wE WANT BINARY Files only
jne read_next_entry

mov al, [bx+0x0b]
cmp al, 0x0f
je read_next_entry     ; just skip the long file names

mov al, [bx+0x0b]
cmp al, 0x10           ; if it is a folder not a file skip it
je read_next_entry

mov al, [bx+0x0b]
cmp al, 0x08          ; if it is a volume label not a file skip it
je read_next_entry

mov al, [bx+0x0b]
cmp al, 0x04         ; if it is a volume label not a file skip it
je read_next_entry

mov al, [bx+0x0b]
cmp al, 0x02        ; if it is a volume label not a file skip it
je read_next_entry

inc word [no_files]    ; get number of files

mov si, bx  ; copy entry
mov di, existing_files ; the location of root directory entry
add di, [next_section]
mov cx, 32 ; copy the whole entry
cld

rep movsb

add [next_section], word 32      ; skip by size of each entry to avoid overriding

read_next_entry:
add [entry_pointer], word 32
add bx, 32 ; point to the next entry
cmp [entry_pointer], word 512 ; have we exceeded the sector size if yes execute the code below
jnae check_if_empty

pop ax  ; retrieve the current logical address from the stack
pop cx  ; retrieve count from the stack
inc ax  ; load next sector when we loop back again
loop read_next_sector

jmp _done

_done:

mov cx, [no_files]
mov [save_no], word cx

call update_menu

jmp show_h_item  ; default highlighted item on the menu

h_item:      ; highlight the desired item using up or down keys
xor ah, ah
int 16h

cmp ah, 0x48     ; up_key
je dec_index

cmp ah, 0x50
je inc_index    ; down key       

cmp ah, 0x1c    ; Enter key
je execute_file 

jmp h_item

inc_index:
add [file_pointer], word 32  ; points to the actual entry

jmp show_h_item

dec_index:
sub [file_pointer], word 32  ; points to the actual entry

jmp show_h_item

show_h_item:

call update_menu

mov dx, [file_pointer]
shr dx, 4 ; same as (file_pointer value / 32) * 2
xchg dl, dh

set_cursor 1, dh
mov dx, existing_files
add dx, [file_pointer]
mov cx, 11
mov bl, 4
call print_string

jmp h_item

execute_file:
pusha

mov bx, existing_files
add bx, [file_pointer]   ;  get details of the selected file entry
mov cx, [bx+0x1a]        ; get first cluster number of a file

xor ax, ax
mov es, ax               ; set es segment to zero

mov bx, 0x8000           ; load our file at location 0x00:0x4500

read_file_next_sector:
mov ax, cx               ; copy cluster number to ax - lba register
add ax, 31               ; align our cluster with the data area
push cx
call read_sectors
pop cx
add bx, 512

mov ax, cx
shr ax, 1
add ax, cx

mov si, ax               ; copy cluster number to si

mov dx, [0x1000+si]      ; get cluster number or end_of_file byte from fat table
test cx, 1
jnz .odd
and dx, 0fffh
jmp .done
.odd:
shr dx, 4

.done:
mov cx, dx
cmp cx, 0xff8
jl read_file_next_sector

mov ah, 0x0e
xor bh, bh
mov al, '='
mov bl, 15
int 10h

jmp 0x00:0x8000

jmp $

update_menu:

mov [pointer], word 0

mov cx, [save_no]
mov [no_files], word cx  ; will fix this when we return 

set_cursor  1, 0
mov dh, 0

.display_files1:

set_cursor 1, dh
mov dx, existing_files
add dx, [pointer]
mov cx, 11
mov bl, 15 ; white on text
call print_string

add [pointer], word 32   ; get the next entry
dec word [no_files]

get_pos
add dh, 2

cmp [no_files], word 0
jne .display_files1

ret

print_string:

sub dx, 1

.print_char:
push cx
inc dx
mov ah, 0x0e
mov si, dx
mov al, [si]
xor bh, bh

int 10h
pop cx
loop .print_char

ret

jmp $

read_error:
mov ah, 0x0e
xor bh, bh
mov al, 'R'
int 10h

xor ah, ah
int 16h

int 19h

hlt 

jmp $

read_sectors:
push ax
push bx

xor dx, dx
mov bx, [SectorsPerTrack]; sectors per track
div bx

inc dx
mov cl, dl

xor dx, dx
mov bx, [Head] ; number of heads
div bx

mov ch, al
xchg dl, dh

;call other function routines
mov ah, 2
mov al, 1
pop bx
mov dl, [drive_letter]
int 13h
jc read_error
pop ax ; restore logical block address before exiting the read_sector routine

ret

drive_letter db 0
SectorsPerTrack dw 0
Head dw 0

root_size dw 14
root_start dw 0
entry_pointer dw 0

next_section dw 0

next_sectionb dw 0

no_files dw 0

save_no dw 0

pointer dw 0

file_pointer dw 0

file_name db 'KERNEL  BIN', 0

existing_files:
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459