assemblynasmx86-16osdevbochs

INT 0x13 / AH = 0x02 works on a floppy image but not when burnt on a flash drive


I am trying to create a simple command system in x86 assembly. The command system is the second stage that is loaded in 0x1000:0000. To see my bootloader, click on this stackoverflow question .

Here is the second stage command system:



[BITS 16]
[ORG 0x0000]      

mov ax, cs
mov ds, ax   
xor cx, cx  
mov bx, welcome_msg
call str_prt
call new_line
mov bx, creator_msg
call str_prt
call new_line
mov bx, boot_msg
call str_prt
call new_line
mov bx, [buffer]

call new_line

mov ah, 0x0e
mov al, 0x0a
int 0x10
mov al, 0x0d
int 0x10
mov al, '>'
int 0x10

loop:
in al, 64h  
test al, 1    
je loop
xor ah, ah
int 0x16
call key_scan
jmp loop

key_scan:
cmp al, 0x08
je back_space
cmp al, 0x0d
je enter
cmp cx, 0x0015 
je end
mov ah, 0x0e
int 0x10
mov bx, buffer
add bx, cx
mov [bx], al
inc cx
jmp end
back_space:
cmp cx, 0x00
je end
dec cx
mov ah, 0x0e
mov al, 0x08
int 0x10
mov al, 0x20
int 0x10
mov al, 0x08
int 0x10
jmp end
enter:
xor cx, cx
mov ah, 0x0e
mov al, 0x0a
int 0x10
mov al, 0x0d
int 0x10
call pro_com
call clear_buffer
mov ah, 0x0e
mov al, '>'
int 0x10
end:
ret

str_prt:
pusha
str:
mov ah, 0x0e
mov al, [bx]
cmp al, '$'
je str_end
int 0x10
add bx, 1
jmp str
str_end:
popa
ret

new_line:
push ax
mov ah, 0x0e
mov al, 0x0a
int 0x10
mov al, 0x0d
int 0x10
pop ax
ret

clear_buffer:
push ax
push bx
push cx
mov bx, buffer
xor cx, cx
xor ax, ax
start:
cmp cx, 0x41
je end_buff
mov [bx], ax
inc bx
inc cx
jmp start
end_buff:
pop cx
pop bx
pop ax
ret

pro_com:
push bx
push ax
mov bx, buffer
mov al, [bx]
cmp al, 'h'
jne help_end
inc bx
mov al, [bx]
cmp al, 'e'
jne help_end
inc bx
mov al, [bx]
cmp al, 'l'
jne help_end
inc bx
mov al, [bx]
cmp al, 'p'
jne help_end
call com_help
jmp pro_end
help_end:
mov bx, buffer
mov al, [bx]
cmp al, 'd'
jne dir_end
inc bx
mov al, [bx]
cmp al, 'i'
jne dir_end
inc bx
mov al, [bx]
cmp al, 'r'
jne dir_end
call com_dir
jmp pro_end
dir_end:
mov bx, not_found
call str_prt
call new_line
pro_end:
pop ax
pop bx
ret

com_help:
push bx
call new_line
mov bx, help1_msg
call str_prt
call new_line
call new_line
pop bx
ret

com_dir:
push ax
push bx
push cx
push dx
mov bx, drive_num
mov dl, [bx]
mov cl, 0x09
mov al, 0x01
mov ch, 0x00
mov cl, 0x09
mov dh, 0x00
com_dir_loop:
call read_dir
cmp cl, 0x12
je false1
inc cx
jmp com_dir_loop
false1:
pop dx
pop cx
pop bx
pop ax 
ret

read_dir:
push ax
push bx
mov bx, 0x1000
mov es, bx
mov bx, 0xe00
call read_disc
clc
mov bx, 0x0e00
mov al, [bx]
cmp al, 'F'
jne read_dir_end
;print file name
mov bx, 0x0e01
call str_prt
call new_line
;----
read_dir_end:
pop bx
pop ax 
mov bx, 0x1000
mov es, bx
ret

read_disc:
mov ah, 0x02   
int 0x13   
ret

buffer times 20 db 0

drive_num:
db 0


welcome_msg:
db 'Welcome to matriXos$'
creator_msg:
db 'Created by Vishnu Shankar.B$'
boot_msg:
db 'Booting command line interface...$'
not_found:
db 'Command cannot be resolved!$'
help1_msg:
db 'Help not avilable!$'


jmp $
times 3584 - ($ - $$) db 0




The command "dir" (com_dir) is supposed to read and print a string that begins with letter 'F' that is put in beginning if each sectors 9 - 18 (track 0)(CHS). I have put the strings in place with help an hex editor.
I converted the code to an image file. It works fine in Bochs emulator, but when I burn the image file on a flash drive and boot it in my computer, it prints garbage.
Can somebody tell me what is wrong?
Thanks in advance.


Solution

  • In my previous answer, I happened to remove the line in your bootloader that sets DL to zero . Your bootloader did this:

    mov dl,0x0  ;Drive = 0 (Floppy)
    

    This needs to be removed. I have now given a reason for this in my previous answer with this comment:

    This hard codes the boot drive to the Floppy A:. If you boot off of USB, hard drive, or Floppy B: your code won't work because the drive number likely won't be zero in those cases. The BIOS passes the actual boot drive that was used to load your bootloader. That value is in the register DL. This is the value you should be using for BIOS disk functions. Since DL already contains the boot drive, we just use it as-is.

    Reuse the value in DL that is passed to your bootloader for drive reads and writes, but also pass this value to your second stage! Since your bootloader doesn't actually destroy the contents of DL you should just have to move DL into your drive_num variable. You can do this right after you set up the DS register in the second stage like this:

    [BITS 16]
    [ORG 0x0000]
    
    mov ax, cs
    mov ds, ax
    mov [drive_num], dl    ; drive_num = the boot drive the BIOS booted from
    

    If you ever modify your bootloader so that it destroys the contents of the DX, or DL register then you should consider pushing it on the stack after your bootloader starts and then popping it off (restoring it) just before you do the jump to your second stage.

    In the bootloader I presented to you in the previous answer, I started it this way:

    xor ax, ax
    mov ds, ax        ; DS=0
    
    cli               ; Turn off interrupts for SS:SP update
                      ; to avoid a problem with buggy 8088 CPUs
    mov ss, ax        ; SS = 0x0000
    mov sp, 0x7c00    ; SP = 0x7c00
                      ; We'll set the stack starting just below
                      ; where the bootloader is at 0x0:0x7c00. The
                      ; stack can be placed anywhere in usable and
                      ; unused RAM.
    sti               ; Turn interrupts back on
    

    After setting up the stack we can save the DX register by doing this:

    xor ax, ax
    mov ds, ax        ; DS=0
    
    cli               ; Turn off interrupts for SS:SP update
                      ; to avoid a problem with buggy 8088 CPUs
    mov ss, ax        ; SS = 0x0000
    mov sp, 0x7c00    ; SP = 0x7c00
                      ; We'll set the stack starting just below
                      ; where the bootloader is at 0x0:0x7c00. The
                      ; stack can be placed anywhere in usable and
                      ; unused RAM.
    sti               ; Turn interrupts back on
    push dx           ; Save DX register (which includes DL) on stack
    

    Now that it is saved, we can restore its value just before we jump to the second stage. This code:

    jmp 0x1000:0000   ; Jump to 0x1000, start of second stage
    

    Would now do this:

    pop dx            ; Restore DX register (which includes DL)
    jmp 0x1000:0000   ; Jump to 0x1000, start of second stage
    

    This effectively passes DL (boot drive) to our second stage even in the event that we might destroy its contents during the execution of our boot loader. Our second stage then has the ability to reuse that value for doing its own BIOS disk reads and writes.