Bootloader freezes on div instruction

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
alethiophile
Member
Member
Posts: 90
Joined: Sat May 30, 2009 10:28 am

Bootloader freezes on div instruction

Post by alethiophile »

I have written a function to load FAT meta-data to memory from the hard disk, for a bootloader. In this function, I have a div instruction to get the size in sectors of the rootdir, knowing its size in bytes. This div instruction freezes the bootloader. The function follows:

Code: Select all

;; Method: load_FAT_data
;;--------------------------------------
;; di => where to load
;;--------------------------------------
;; Loads the boot sector, FATs, and root directory
;; of the FAT filesystem on disk 0x80 to di. di must
;; point to enough space. Returns the number of sectors
;; read.
load_FAT_data:
	push	ebp
	mov	ebp,	esp
	sub	esp,	4	;; space for return value
	pusha
	push	fs

lfd_read_bpb:
	xor	ecx,	ecx
	mov	bx,	di	;; offset to read to
	xor	eax,	eax	;; reading the first sector
	mov	fs,	ax	;; no segment variable
	mov	cx,	1	;; only reading bpb sector
	call	read_sectors
	add	word [ebp - 4],	cx	;; for return value

lfd_read_FATs:
	mov	ax,	word [di + 22]	;; sectors per FAT
	mul	byte [di + 16]	   	;; number of FATs
	mov	cx,  	ax 		;; that's how many sectors we need load
	
	mov	ax,	word [di + 14]	;; FATs start right after the reserved sectors
	
	add	bx,	0x200		;; read to sector after bpb
	call	read_sectors		
	add	word [ebp - 4],	cx	;; for return value

lfd_read_rootdir:
	add	ax,	cx		;; rootdir is right after FATs, so add number just loaded
	push	ax			;; save ax so we can use it for calculations
	
	mov	cx,	ax		;; num sectors loaded last
	mov	dx,	0x200		;; size of a sector
	mul	dx			;; number of bytes loaded last
	add	bx,	ax		;; add to memory index
	
	mov	ax,	word [di + 17]	;; # of rootdir entries
	mov	dx,	0x20 	   	;; 32-byte entry
	mul	dx
	mov	edx,	0x200		;; # of bytes per sector
	div	edx ;; <- this is the instruction that freezes it
	mov	cx,	ax

	pop	ax
	call	read_sectors
	add	word [ebp - 4],	cx	;; return value
	
	pop	fs
	popa
	mov	ax,	word [ebp - 4]	;; return value
	mov	esp,	ebp
	pop	ebp
	ret
I have stepped through the function in Bochs debugger and verified that this instruction is the problem. The bochs register dump immediately before the instruction is:

Code: Select all

eax: 0x00004000 16384
ecx: 0x00000080 128
edx: 0x00000200 512
ebx: 0x00009e00 40448
esp: 0x00009be1 39905
ebp: 0x00009bf9 39929
esi: 0x00008ea5 36517
edi: 0x00009c00 39936
eip: 0x00008d95
eflags 0x00000206
id vip vif ac vm rf nt IOPL=0 of df IF tf sf zf af PF cf
This seems like it contains the correct values. I also have some similar code in my first-stage bootloader, for the same purpose, and it works well. Does anyone have an idea as to the problem?
If I had an OS, there would be a link here.
User avatar
alethiophile
Member
Member
Posts: 90
Joined: Sat May 30, 2009 10:28 am

Re: Bootloader freezes on div instruction

Post by alethiophile »

Update: I now have replaced the divide-by-512 with a right-shift by 9, and it works. Hence, this is less urgent. I'm still curious, however, about why the div would cause the loader to freeze.
If I had an OS, there would be a link here.
User avatar
mintie
Posts: 6
Joined: Wed Jun 03, 2009 8:44 pm
Location: North Carolina, USA

Re: Bootloader freezes on div instruction

Post by mintie »

Could your read_sectors function depend upon the value in edx being 0x200?
User avatar
alethiophile
Member
Member
Posts: 90
Joined: Sat May 30, 2009 10:28 am

Re: Bootloader freezes on div instruction

Post by alethiophile »

No; read_sectors only uses edx internally, and preserves its value. No assumption is made about its contents.
If I had an OS, there would be a link here.
User avatar
mintie
Posts: 6
Joined: Wed Jun 03, 2009 8:44 pm
Location: North Carolina, USA

Re: Bootloader freezes on div instruction

Post by mintie »

If I remember this right, when you do a 32 bit divide with edx, it divides edx:eax by edx, so you're actually dividing 0x02004000 by 0x200 instead of doing 0x4000/0x200.
Try replacing it with

Code: Select all

mov edx, 0
mov ecx, 0x200
div ecx
Or something similar depending on what registers you use.
User avatar
alethiophile
Member
Member
Posts: 90
Joined: Sat May 30, 2009 10:28 am

Re: Bootloader freezes on div instruction

Post by alethiophile »

OK, thanks. I'm now using a right shift instead of a div, but it's good to know why that failed.
If I had an OS, there would be a link here.
User avatar
mintie
Posts: 6
Joined: Wed Jun 03, 2009 8:44 pm
Location: North Carolina, USA

Re: Bootloader freezes on div instruction

Post by mintie »

You're welcome, and besides it's better to use that right shift, it's way quicker than a div :P
User avatar
Masterkiller
Member
Member
Posts: 153
Joined: Sat May 05, 2007 6:20 pm

Re: Bootloader freezes on div instruction

Post by Masterkiller »

Dividing on a 32-bit value (register or memory) divides value of EDX:EAX (forming 64-bit number) to that 32-bit value.
For example if edx=0x200; eax=0x200; your division will do: 0x0000020000000200/0x00000200 = 0x100000001 | 0; Quitient as you see is 33-bit value and it is stored in 32-bit register EAX, the remainder is stored in EDX. Since you cannot store 33-bit value into 32-bit register, instruction will fire an exception. Exception in real-mode are handled, but causes the program to freeze. (For example Bochs execute IRET an restart the DIV instruction, then again CPU fires an exeption and instruction is restarted again, again and again).
You should always keep the divident in EDX:EAX, or if it is 32-bit, zero the edx before division.
ALCA OS: Project temporarity suspended!
Current state: real-mode kernel-FS reader...
User avatar
mintie
Posts: 6
Joined: Wed Jun 03, 2009 8:44 pm
Location: North Carolina, USA

Re: Bootloader freezes on div instruction

Post by mintie »

Whoops, thanks haha, I just realized I mean to put 0x0000020000004000 instead of 0x02004000. That was from me making sure the same thing happened with 16-bit registers, and i forgot it was with 32-bit registers in that code.
User avatar
kop99
Member
Member
Posts: 120
Joined: Fri May 15, 2009 2:58 am

Re: Bootloader freezes on div instruction

Post by kop99 »

Instead of div, you can use shr command.
It's better good than div's performance.

Code: Select all

shr eax, 0x9
quok
Member
Member
Posts: 490
Joined: Wed Oct 18, 2006 10:43 pm
Location: Kansas City, KS, USA

Re: Bootloader freezes on div instruction

Post by quok »

kop99 wrote:Instead of div, you can use shr command.
It's better good than div's performance.

Code: Select all

shr eax, 0x9
The problem here though is that using shr is completely and totally wrong. The OP wants to get the size of the FAT root directory in sectors. The BPB contains a field that holds the size of a sector in bytes. That is what you want to use. It is almost always 512, but it may not be, so coding in a 9 bit right shift is definitely not the right way to go.

shr may be faster than div (although div is heavily optimized for using powers of 2), but converting a sector size that is already in bytes to the proper number of bits to shift by is non-trivial at best. Especially in a bootsector where you're already quite constrained on available space. Besides, it's a bootsector and you're only doing this calculation once. This is not the right place for speed optimizations. :)
User avatar
kop99
Member
Member
Posts: 120
Joined: Fri May 15, 2009 2:58 am

Re: Bootloader freezes on div instruction

Post by kop99 »

it may not be, so coding in a 9 bit right shift is definitely not the right way to go.
Maybe your advice is right.
But I naver see that sector size isn't 512byte...
User avatar
alethiophile
Member
Member
Posts: 90
Joined: Sat May 30, 2009 10:28 am

Re: Bootloader freezes on div instruction

Post by alethiophile »

For one thing, this is a second-stage bootloader, so I'm not as constrained on space. But this will only fail on filesystems that are formatted really weirdly, and since I'm using this to parse a filesystem that I'm formatting, I don't see a problem with using a hard-coded value for div (or shr). Non-512-byte sectors might be a concern in actual OS drivers, but not for the bootloader.
If I had an OS, there would be a link here.
Post Reply