Floppy disk reads using the BIOS...

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.
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Floppy disk reads using the BIOS...

Post by JJeronimo »

My FAT12 filesystem parsing boot sector code has this BIOS wrapper to perform sector reads. (FASM syntax)

Code: Select all

; [ES:BX] - Buffer
; AX - Sector Number (inside Filesystem)
readsector:
		pusha

		add	ax, word [.base]

		xor	dx, dx	
		div	word [BOOT_BLOCK.SpT]
		mov	cx, dx		;Sector number (remainder) to CX...

		xor	dx, dx
		div	word [BOOT_BLOCK.Heads]
		mov	dh, dl		;Head number (remainder) to DH...
		
		mov	ch, al		;Track number (result) to CH...

		mov	dl, [.drive]	;From [...] ...

		mov	al, 1		;1 sector...


	.rep:	mov	ah, 00h		;Reset
		int	13h		;Call BIOS...
		mov	ah, 02h		;Read...
		int	13h		;Call BIOS...
		jc	.rep

		popa
		ret

   .drive	db 0	;To modify from another function
   .base	dd 1	;Base sector of FAT filesystem
I'd been testing using Bochs, but paying attention to error handling (look at the carry flag test after int 13h)... Now, on real hardware the BIOS call keeps failing on some specific read (which occurs in the data area). I was unable to determine the error code, since I don't have an integer printing function in this boot sector (BTW it barely fits in the 512 bytes), but at some point I've put a VGA write in the routine that handled the read error (branched by the jc instruction), and for some strange reason it started to work. But then as I altered the function over and over I hadn't been able to make a similar effect once again (nor even explain it)...

JJ
Last edited by JJeronimo on Sat May 05, 2007 9:35 am, edited 1 time in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

Have you tried leaving out the recalibration call? I don't use it and my bootloader works just fine.

What i can imagine is that the recalibration interferes with the read: the reset will move the head to track 0, while the read must move it again. This may upset the drive. Consider: the read may fail several times because of seeking and such, but instead of letting it settle you keep moving it around, so the drive never gets a chance to become stable and get your data off. (it also explains why it only happens out on the disk - the main FAT structures are on track 0.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Post by JJeronimo »

Combuster wrote:Have you tried leaving out the recalibration call? I don't use it and my bootloader works just fine.
I think so, but I'll try once (again), cause I'm not sure...
What i can imagine is that the recalibration interferes with the read: the reset will move the head to track 0, while the read must move it again.
I thought about that when I read in the RBIL that the reset sent the heads back to track 0, but I'm not entirely sure of having tried to comment out the reset...
This may upset the drive. Consider: the read may fail several times because of seeking and such, but instead of letting it settle you keep moving it around, so the drive never gets a chance to become stable and get your data off. (it also explains why it only happens out on the disk - the main FAT structures are on track 0.
Yes, yes... Makes sense... I'll try, then...

JJ
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Post by JJeronimo »

JJeronimo wrote:
Combuster wrote:Have you tried leaving out the recalibration call? I don't use it and my bootloader works just fine.
I think so, but I'll try once (again), cause I'm not sure...
No. Didn't work.
Thanks, anyway...
I don't have much time to investigate now... Perhaps in the weekend I'll try more possibilities...

JJ
User avatar
mathematician
Member
Member
Posts: 437
Joined: Fri Dec 15, 2006 5:26 pm
Location: Church Stretton Uk

Post by mathematician »

You could try putting in a few milliseconds delay between each call to int 13h. One of the functions attached to int 15h could do that for you. The CPU can move itself a lot faster than the floppy disk controller, and the latter might need time to catch up.
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Post by JJeronimo »

mathematician wrote:You could try putting in a few milliseconds delay between each call to int 13h.
Nope... I put a wait cycle (don't worry, I was just to see the effect) and didn't work.

See if the CHS computations are right and if I packed the address in the way BIOS likes...

The problem is in my code. FreeDOS has correctly read the floppy on the very same computer. Linux has read the floppy, and windows xp too (and copied the file from it), on another computer (where my bootsector doesn't work either). I've already tried another floppy but the effect is the same...

I think I'm going crazy!





Now, another thing: what's exactly the segmented address where the BIOS jumps to the boot sector? Is it 0x0000:0x7C00 or is it to 0x07C0:0x0000?
Is it really important to do the far jump to a known seg:offset address? (assuming that my code depends upon this knowledge)

Thanks,
JJ
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

Take a look at this functional FAT12 boot sector, it could help you compare what you are doing wrong:

http://www.osdev.org/phpBB2/viewtopic.p ... 99&start=3

Also, these 2 base addresses are the same because:

07C0:0000 == (07C0<<4)+0000 == 0x7C00
0000:7C00 == (0000<<4)+7C00 == 0x7C00

That's the address where the BIOS loads the boot sector. The final address of your kernel is jumped to by your MBR once you have done all your tasks and you decide where it will go. Try using UnReal Mode to simplify the segment issues.
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Post by JJeronimo »

~ wrote:Take a look at this functional FAT12 boot sector, it could help you compare what you are doing wrong:

http://www.osdev.org/phpBB2/viewtopic.p ... 99&start=3
OK

Also, these 2 base addresses are the same because:

07C0:0000 == (07C0<<4)+0000 == 0x7C00
0000:7C00 == (0000<<4)+7C00 == 0x7C00
Of course. In the case you hadn't noticed, I'm no dumb...
That's the address where the BIOS loads the boot sector. The final address of your kernel is jumped to by your MBR once you have done all your tasks and you decide where it will go.
What I asked is, WHAT are the contents of CS:IP after loading? Because with 0000:7C00 and with 07C0:0000 the segment base is different, so in the first case the boot sector's base offset is 0x7C00, but in the second one it's 0x0000... And if I want to access data declared inside my code, as I do, (or write self-modifying code) I'll write it in the wrong place if the wrong CS is assumed...
Did you understand?

http://www.osdev.org/wiki/Boot_sequence ... oot_Record
Read the first two paragraphs of this section...
Try using UnReal Mode to simplify the segment issues.
Of course not! If I'm programming in Real Mode I'll address the RM issues... And... Unreal Mode only works on 386+ but I want my boot sector to work independently of this. The processor test will be done latter, in the kernel (or the second stage loader, I don't know already)...
And unreal mode would solve nothing, because the problem is WHERE the BIOS jumps. And the BIOS doesn't take 32-bit addresses as arguments...

JJ
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post by Candy »

JJeronimo wrote:Of course. In the case you hadn't noticed, I'm no dumb...
That's the address where the BIOS loads the boot sector. The final address of your kernel is jumped to by your MBR once you have done all your tasks and you decide where it will go.
What I asked is, WHAT are the contents of CS:IP after loading? Because with 0000:7C00 and with 07C0:0000 the segment base is different, so in the first case the boot sector's base offset is 0x7C00, but in the second one it's 0x0000... And if I want to access data declared inside my code, as I do, (or write self-modifying code) I'll write it in the wrong place if the wrong CS is assumed...
Did you understand?
Undefined, of course. Naturally, your first 20 test machines give the same result and the very first you show your program on to your girlfriend tends to be different.

Try prepending "jmp 0x7C0:0003" to your bootsector for certainty, or live with the uncertainty. You don't have to use absolute jumps anyway and you can reload DS/ES with 0.
User avatar
mathematician
Member
Member
Posts: 437
Joined: Fri Dec 15, 2006 5:26 pm
Location: Church Stretton Uk

Post by mathematician »

JJeronimo wrote:Now, another thing: what's exactly the segmented address where the BIOS jumps to the boot sector? Is it 0x0000:0x7C00 or is it to 0x07C0:0x0000?
Is it really important to do the far jump to a known seg:offset address? (assuming that my code depends upon this knowledge)

Thanks,
JJ
It is 0:7C00.
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Post by JJeronimo »

Candy wrote:Undefined, of course.
Thanks...
So why are there so many boot sectors that don't pay attention to this?
Naturally, your first 20 test machines give the same result and the very first you show your program on to your girlfriend tends to be different.
Murphy's Laws! And Love's, too!...
Try prepending "jmp 0x7C0:0003" to your bootsector for certainty, or live with the uncertainty. You don't have to use absolute jumps anyway and you can reload DS/ES with 0.
Ok, ok, ok... I hadn't remembered this point... cause x86 jumps are always relative, save for far ones...
So I don't need to far jump in the beginning of the bootsector, cause the only thing that matters is data registers...

JJ
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Post by JJeronimo »

New data. The sector that it refuses to read is sector 35, this is, the last sector of track 0 (side two)... Does it help?



Edit: It's not sector 35... it's sector 36 of the disk, this is, first sector of second track... I've made confusion because the first usable floppy sector is sector 1...

JJ
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Post by JJeronimo »

JJeronimo wrote:Edit: (...) I've made confusion because the first usable floppy sector is sector 1...
Thanks a lot, but I've just discovered as I re-read one of the first documents I first read about floppy disks... The problem was: the first sector of each track is reserved and [1] it doesn't contain anything and [2] for some reason the BIOS (or the floppy drive) is unable to read it and [3] for an even more obscure reason the BIOS of Bochs is uncompatible with this behaviour...


PS: I think we should add this to the Bochs page on the wiki...

JJ
JJeronimo
Member
Member
Posts: 202
Joined: Wed Oct 18, 2006 3:29 pm

Post by JJeronimo »

Sorry, but I still don't understand, and now I don't know what's correct...
The floppy has 2880 writable sectors, right? So the sectors number 0 of each track as writable, aren't they?

If not, why does the command "hexedit /dev/fd0" (on Linux, if you have hexedit installed) indicates 0x168000 (which is equal to 80*2*18, the CHS geometry of 1.44 floppy disks) as the first non-existent byte?
Or are the 0-sectors a BIOS' abstraction?

JJ
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Sector numbers are 1 based, that is they start at 1 and the last addressable sector is number 18. There is no sector number 0.
Post Reply