Page 1 of 1

'LBA out of range' error on loading sectors from bootloader

Posted: Sat May 30, 2009 12:44 pm
by alethiophile
I am trying to write a two-stage bootloader. The first stage is supposed to parse the FAT root directory, look for the second stage (2BOOT.BIN), and load it. I am having trouble with my read_sectors code, that uses BIOS interrupt 0x13, function 0x42, to read a given number of sectors from disk to memory. The relevant code:

Code: Select all

;; Method: read_sectors
;;--------------------------------------
;; cx = num sectors to read
;; eax = disk offset
;; es:bx => buffer to read to
;;--------------------------------------
;; Reads the number of sectors in cx from the disk offset in eax to the location es:bx.
;; Uses BIOS int 0x13. May not work if you have an old BIOS. The boot sector checks this.
;; Destroys values in eax, edx, esi, ecx
eoemsg	    db "Error in read_sectors, please reboot", 13, 10, 0

read_sectors:
	;; Make a disk address packet
	mov	byte [diskaddr],	0x10		;; packet size
	mov	byte [diskaddr+1],	0x00		;; reserved byte
	mov	word [diskaddr+2],	cx		;; num sectors
	mov	word [diskaddr+4],	es		;; offset to write to
	mov	word [diskaddr+6],	bx
	mov	dword [diskaddr+8],	eax		;; disk address (LBA)
	mov	dword [diskaddr+0x0b],	0x00

	xor	ecx,  ecx
	mov	cx,   5					;; try 5 times, then exit on error
try_again:
	mov	si,   diskaddr				;; address of disk packet
	mov	ah,   0x42				;; instruction code
	mov	dl,   0x80				;; disk to read (hard disk)
	
	int	0x13
	jnc	rs_done
	loop	try_again				;; try again on error
	jmp	exit_on_error			;; after 5 tries, exit	

rs_done:
	ret

exit_on_error:
	mov	si,	eoemsg
	call	print

	jmp	$
I run this to load the root directory of the FAT12 filesystem on the device. Every time the interrupt is called, it returns an error and Bochs outputs:

Code: Select all

int13_harddisk: function 42. LBA out of range
. The code runs 5 times, hence prints 5 errors, and then exits on error. I run it in the Bochs debugger. When I break at the start of the function and print the registers, the output is:

Code: Select all

eax: 0x00000013 19
ecx: 0x0000000e 14
edx: 0x00000000 0
ebx: 0x00000200 512
esp: 0x0000fffd 65533
ebp: 0x00000000 0
esi: 0x000e7c58 949336
edi: 0x0000ffac 65452
eip: 0x00007db3
eflags 0x00000246
id vip vif ac vm rf nt IOPL=0 of df IF tf sf ZF af PF cf
These don't look like unreasonable values. Does anyone have any idea what the problem is?

Re: 'LBA out of range' error on loading sectors from bootloader

Posted: Sat May 30, 2009 1:41 pm
by kmtdk
well
i have found 1 (BIG) error , and you shoul have double cheked against code error when writing to memory :D

and i understand the hdd, because when you say "mov dword [diskaddr+0x08],eax you are writting the HIGH part of that Qword (tjek http://www.ctyme.com/intr/rb-0708.htm for a describing on packet strucktur). so in order to write to the low part, write :
mov dword [diskaddr+0x08+0x04] , eax
or just add 4 and 8, so it gives 0xc and write [diskaddr+0x0c] .....

KMT dk


edit:
and by the way, delete the line :
mov [diskaddr+0x0b],0x00
it will just make problems ! :P

Re: 'LBA out of range' error on loading sectors from bootloader

Posted: Sat May 30, 2009 6:44 pm
by alethiophile
Thanks for the help. I have not done much in assembly before this project, so I am liable to make fairly stupid errors. So, if I understand you correctly, the out-of-range error issue is a symptom of me not dealing with little/big-endianness? Also, what's this big error you refer to? And why should I delete the move to diskaddr+0x0b?

EDIT:
Reading it again, I now understand what you're talking about with the lba-out-of-range error. However, even having made the modification you suggest, I get the same error.

Re: 'LBA out of range' error on loading sectors from bootloader

Posted: Sat May 30, 2009 7:18 pm
by Dex
Have you tryed
To read or write, first you need to set up a "Disk Address Packet Structure" in memory, on a DWORD (4 byte) boundary

Re: 'LBA out of range' error on loading sectors from bootloader

Posted: Sat May 30, 2009 8:24 pm
by alethiophile
Dex wrote:Have you tryed
To read or write, first you need to set up a "Disk Address Packet Structure" in memory, on a DWORD (4 byte) boundary
diskaddr points to a disk address packet. Its space is allocated in the bootloader, but not shown in the code snippet. All the mov instructions are used to set up the structure.

EDIT:
I ran through it byte by byte in memory, and it turned out that I had originally initialized the packet space to non-zero in order that I could find its offset in a dump of the file, and not set it to zero again. Having fixed that bug, I still had the same error. Groveling through memory dumps line by line, I remembered that the qword 'starting absolute block number' in the address packet is supposed to be little-endian. I undid the first change suggested, and it worked like a charm. *sigh...* Now on to a new and interested bug.

Re: 'LBA out of range' error on loading sectors from bootloader

Posted: Sun May 31, 2009 12:14 am
by bewing
Um, you also have es and bx stored in reverse order in your disk address packet. I don't think anyone has mentioned that yet.

Re: 'LBA out of range' error on loading sectors from bootloader

Posted: Sun May 31, 2009 7:26 am
by kop99

Code: Select all

   mov   word [diskaddr+4],   es      ;; offset to write to
   mov   word [diskaddr+6],   bx
Are you going to read sectors in es:bx?
Then try that following code.

Code: Select all

   mov   word [diskaddr+4],   bx      ;; offset to write to
   mov   word [diskaddr+6],   es