I'm writing a 16-bit real mode Assembly x86 routine to read the disk, but it doesn't work properly. It is for my Operative System, if it can help.
Here's my code, you can paste, compile with NASM and emulate:
mov bl, dl
mov ah, 0x2
mov al, 0xa
mov ch, 0
mov cl, 2
mov dh, 0
mov dl, bl
mov bx, 0x0
mov es, bx
mov bx, 0x7e00
int 0x13
jc __end
mov bx, 0x7e00
__loop:
mov ah, 0x0e
mov al, [bx]
int 0x10
cmp bx, 0x7e00+0xa
je __end
inc bx
jmp __loop
__end:
mov ah, 0x0e
mov al, "!"
int 0x10
jmp $
times 510 - ( $ - $$ ) db 0x0
dw 0xaa55
times 2048 db 'A'
As you can see in the code, I am trying to read 10 sectors (0xa). To test this I wanted to print out the rode bytes at 0x7e00, and at the end an exclamation mark !
to notice the end of the function. In the first test it wrote me only a few blank spaces and my !
. To be certain if all worked, I filled 4 sectors with A
s. I re-tried, and Bochs printed only a few A
s and so !
. The output fits in a single line, to give you an idea. So it didn't seem like it was reading 10 sectors.
What am I missing? Thank you for any answer.
The output fits in a single line, to give you an idea. So it didn't seem like it was reading 10 sectors.
A bit of a hasty conclusion this is. There's always the possibility that the outputting itself went wrong, no matter where the data came from.
And indeed that is the case, but contrary to what everybody involved till now (including you yourself) have said about you having printed 10 characters, I see that your endeavors were actually printing 11 characters! Not important you say? It is the famous one-off error, well-known to anyone that programs.
mov bx, 0x7e00 __loop: mov ah, 0x0e mov al, [bx] int 0x10 cmp bx, 0x7e00+0xa je __end inc bx jmp __loop __end:
By the time your loop sees the address 0x7E0A, the char at that particular address has already been printed. This was indeed the eleventh byte from the range 0x7E00 .. 0x7E0A.
The solution lies in where you place that inc bx
instruction. And if you do it right you will also have removed one of those jumps:
mov bx, 0x7E00
__loop:
mov al, [bx]
mov ah, 0x0E ; BIOS.Teletype
int 0x10
inc bx
cmp bx, 0x7E00 + 0x000A
jb __loop ; For as long as we stay BELOW 0x7E0A
__end:
Now that the one-off error has gone, printing whole sectors is a breeze. Just apply a factor of 512
(size of a sector):
mov bx, 0x7E00
__loop:
mov al, [bx]
mov ah, 0x0E ; BIOS.Teletype
int 0x10
inc bx
cmp bx, 0x7E00 + 0x000A * 512
jb __loop ; For as long as we stay BELOW 0x9200
__end:
Don't forget to initialize DS so the mov al, [bx]
instruction works properly:
xor bx, bx
mov ds, bx
mov es, bx
mov bx, 0x7E00
int 0x13