Page 1 of 1

Floppy controller state right after boot and other questions

Posted: Sat Mar 12, 2011 12:07 am
by linguofreak
I've recently started a hobby OS project with the goal of using as little code as possible that I did not write myself. This includes assemblers, compilers, and as much BIOS code as I can possibly do without. It's meant to hearken back, as far as possible, to the old days of hand assembling programs and punching them in on the front panel (which x86's, unfortunately, don't have). I'm writing my image files with a text editor and a Java program I wrote that reads in two characters, checks if they're both in one of the ranges 0-9 A-F a-f, and writes out a byte, as well as allowing me to define and use word-length constants (that last part is probably cheating a bit, but keeping track of pointers is a royal *pain* otherwise). I'm disassembling my code for proofreading with HTE.

(Before anyone asks: Yes, I'm five flavors of insane. I have no illusions that I'll get anywhere quickly with this project, and it's not unlikely that it will die an early death, but I'm going to try.)

The first stage of this project will be to write a bootable text editor and a bootable not-really-an-assembler that uses the same syntax as my Java program. But to make anything bootable I have to have a boot sector that loads in the rest of the program from a disk. I already have a boot sector that uses int 0x13 to read the rest of the first track and boot it, which I've used to test some other bits of code, but, of course, I'm trying not to use BIOS, so I'm working on a DMA boot sector. Since I'm pretty much coding in machine code, I'm trying to keep my code as simple as possible to economize on time and to reduce the possibility of errors.

So I have several questions about what state I'm most likely to find the floppy controller in directly after booting off a floppy and how much code I can shave off the tutorials (as well as questions about places where the tutorials argue with each other). I have the feeling that alot of these questions are going to have the answer "highly BIOS dependent", but even rules of thumb will be helpful.

My going-in assumptions:

-This code will be executing under Bochs and on a single, ten year old, physical machine.
-This code will always be loaded from the first floppy drive (drive A: / fd0)
-This code will be used on one physical disk, formatted as a standard 1.44 megabyte 3.5 inch floppy, as well as one floppy image file for Bochs.
-This code is meant to be quick and dirty. It will likely be revisited and cleaned up once I've built myself more usable tools (if I get that far). As such, the standard is "can be generally expected to work", not "best practices".

My questions:

1: Is resetting the controller necessary / advisable immediately after booting from a floppy?

2: Since BIOS has just loaded our boot code from the first sector on the disk, which is on the first cylinder, can we assume that we don't have to calibrate or seek to the first cylinder?

3: When booting from a floppy, does BIOS leave the drive motor on? I think the answer here is "no", given that I've fiddled with writing some boot sector only programs that didn't mess with the FDC at all (either directly or through int 0x13) and saw no indication of continuing drive motor activity, nor do I see no mention in the Intel datasheets that the FDC automatically times out the motors. On the other hand, given that the vast majority of bootable disks are going to be pulling data in from beyond the boot sector, I'd think it would be fairly sensible for the BIOS to leave the motors on on the assumption that they'd be used again in short order. (Of course, "I'd think it would be sensible" does not always mean "sensible", and "sensible" does not always mean "done in practice").

4: After a reset in polling mode, how many "sense interrupt" commands do I need? The Wiki says four, this tutorial seems to say one. The datasheet seems to imply that it's one for each drive on the controller, but I'm not sure if that means "one for each drive that you plan to use" or "one for each drive slot on the controller, whether you use it or not, and whether or not it actually has a drive".

5: The link the Wiki gives to the tutorial at http://forum.osdev.org/viewtopic.php?t=13538 says that it has a few tiny errors. I see a few typo's and such mentioned in the thread following the tutorial. Are there any errors *not* mentioned in the thread that I need to be aware of?

6: To wrap up all of the above and reiterate the main point of all my questions: What steps are *absolutely necessary* to bring the first track of a floppy into memory without the use of int 0x13, when the floppy in question is the boot medium, the format is known, and the computer that will be executing the code is more or less known (IE, no curveballs from hardware differences as long as Bochs doesn't throw a wrench into the works).

Re: Floppy controller state right after boot and other quest

Posted: Sat Mar 12, 2011 12:52 am
by bewing
First off, *I* wrote the wiki article on the FDC, so you won't hear anything different from what is there, from me.

1. No. The BIOS just used the floppy, and it is clearly in a functional state.

2. The problem is the real machine. There is a good chance that you may need to retry your read several times. And that may require a recalibration. I doubt you need to seek. But I think that the point is that since you are only aiming at two very specific platforms, all you need to do is try it and see. Bochs (or ReBochs) will certainly not require a seek or recalibrate (or even a retry).

3. The BIOS needs IRQ0 turned on when dealing with the floppy. Why? Because turning off the floppy motors is part of the IRQ0 timer handler -- it has flags, and checks 18.2 times per second, and turns off the motors of any drives that are on after a couple of seconds. It also turns them off just before transferring control to your bootsector. So you can assume the motor is off, but you are going to be turning it right back on anyway, and the spindle certainly is still at full speed.

4. I said 4, I still say 4. One for each theoretical drive on each channel. The controller pretends the drives all exist, and each one needs a Sense Interrupt, to become active again -- and they activate in a particular order.

5. As I recall, the errors I spotted were in setting up the registers for the DMA. The wrong register numbers were used. Be very careful about that. Read the ISA DMA article with extreme care.

6. Nothing much. 10 lines of ASM to set up the DMA. 20 to do the floppy "read" command. 10 more to test for an error and loop. And maybe 10 more for a potential recalibrate.

Re: Floppy controller state right after boot and other quest

Posted: Sat Mar 12, 2011 1:42 am
by linguofreak
bewing wrote:3. The BIOS needs IRQ0 turned on when dealing with the floppy. Why? Because turning off the floppy motors is part of the IRQ0 timer handler -- it has flags, and checks 18.2 times per second, and turns off the motors of any drives that are on after a couple of seconds. It also turns them off just before transferring control to your bootsector. So you can assume the motor is off, but you are going to be turning it right back on anyway, and the spindle certainly is still at full speed.
I've got somewhere to be early tomorrow morning, so I'll have more to say later, but I will say this: A question that I almost asked, but decided against 'cause my post was getting long, was "How quickly does BIOS go from loading the bootsector code at 7c00 to actually handing control over to 7c00?". And the reason I was wondering was because I wanted to know if the spindle might have been given time to stop. Your answer here clears that up very nicely. It seems that it would be rather brain dead for BIOS to go and do very much between loading the boot sector and handing over control, but "nobody would be that stupid" can be a Really Bad assumption, and, as I said, "sensible" doesn't always mean "done in practice".

EDIT:
First off, *I* wrote the wiki article on the FDC, so you won't hear anything different from what is there, from me.

1. No. The BIOS just used the floppy, and it is clearly in a functional state.
Something gave me the impression that it might be in a functional state but I might not be able to know exactly what that state was, and that I might have to reset to be certain of the state of the controller (I think I might have confused some FDC stuff with the flip-flop on the DMA controller or something).
2. The problem is the real machine. There is a good chance that you may need to retry your read several times. And that may require a recalibration. I doubt you need to seek. But I think that the point is that since you are only aiming at two very specific platforms, all you need to do is try it and see. Bochs (or ReBochs) will certainly not require a seek or recalibrate (or even a retry).
We'll see how rusty my floppy drive / floppy is. If I can get away with it I may just panic if the first try doesn't work.
4. I said 4, I still say 4. One for each theoretical drive on each channel. The controller pretends the drives all exist, and each one needs a Sense Interrupt, to become active again -- and they activate in a particular order.
But this is a "best practices" issue, right? Not a "None of the drives will work until you've given a Sense Interrupt for each one of them" issue?
5. As I recall, the errors I spotted were in setting up the registers for the DMA. The wrong register numbers were used. Be very careful about that. Read the ISA DMA article with extreme care.
OK, thanks, I'll keep that in mind.
6. Nothing much. 10 lines of ASM to set up the DMA. 20 to do the floppy "read" command. 10 more to test for an error and loop. And maybe 10 more for a potential recalibrate.
OK. Thanks.

Re: Floppy controller state right after boot and other quest

Posted: Sat Mar 12, 2011 11:39 pm
by DavidCooper
linguofreak wrote:I've recently started a hobby OS project with the goal of using as little code as possible that I did not write myself. This includes assemblers, compilers, and as much BIOS code as I can possibly do without. It's meant to hearken back, as far as possible, to the old days of hand assembling programs and punching them in on the front panel (which x86's, unfortunately, don't have). I'm writing my image files with a text editor and a Java program I wrote that reads in two characters, checks if they're both in one of the ranges 0-9 A-F a-f, and writes out a byte, as well as allowing me to define and use word-length constants (that last part is probably cheating a bit, but keeping track of pointers is a royal *pain* otherwise). I'm disassembling my code for proofreading with HTE.

(Before anyone asks: Yes, I'm five flavors of insane. I have no illusions that I'll get anywhere quickly with this project, and it's not unlikely that it will die an early death, but I'm going to try.)
So you're working directly with machine code numbers in hex and not using assembler? I too program directly in machine code (though I use decimals instead of hex), so I can tell you that your project should be both possible and practical - being insane is absolutely not a requirement for this. You might like to have a look at my machine code editor to see if it's a better option than doing everything through a text editor - it allows you to write machine code straight into memory locations where you'll can sometimes edit code even while it's running.
3: When booting from a floppy, does BIOS leave the drive motor on? I think the answer here is "no", given that I've fiddled with writing some boot sector only programs that didn't mess with the FDC at all (either directly or through int 0x13) and saw no indication of continuing drive motor activity, nor do I see no mention in the Intel datasheets that the FDC automatically times out the motors. On the other hand, given that the vast majority of bootable disks are going to be pulling data in from beyond the boot sector, I'd think it would be fairly sensible for the BIOS to leave the motors on on the assumption that they'd be used again in short order. (Of course, "I'd think it would be sensible" does not always mean "sensible", and "sensible" does not always mean "done in practice").
If you leave the interrupts on, the motor will switch off after a couple of seconds. If you disable the interrupts before that point, the motor will not stop. If you want to leave the interrupts on you can prevent the motor being switched off by posting a large number into byte 440h in the BDA every ten seconds or so. If you set a very low value for that byte so that the BIOS switches the motor off within a single tick of the system timer, you could then turn it on again directly via the appropriate port, but the BIOS may continue to tick the byte in 440h down and switch the motor off again when it gets to 0. (By the way, Bochs doesn't update the BDA properly, so don't write any delay loops that depend on 440h or 46Ch changing.) Another option would be to write your own system timer interrupt routine so that the motor isn't switched off by the BIOS (store the existing vector so that you can restore it afterwards if necessary). You'll only be doing that of course if you intend to do a similar thing with the FDC interrupt routine, replacing the vector with one pointing to your own code. If you disable the interrupts you won't have any problems with the BIOS interfering with play, but don't be tempted to bypass the DMA as Bochs can't handle the FDC running in DMA-off mode.

Bear in mind that your OS won't be able to boot directly on a modern machine that lacks an internal floppy drive if you don't use the BIOS - I've just changed from doing what you're setting out to do to using the BIOS instead for that reason. If I was starting out from scratch now, I'd still want to write my own FDC driver, but I'd write code to do all loads and saves through the BIOS first and then write my own code to do the same job later on in 32-bit mode, allowing the OS to be switched into a non-BIOS-load/save mode whenever it's running on a machine with an internal floppy drive.

Re: Floppy controller state right after boot and other quest

Posted: Sun Mar 13, 2011 12:58 am
by bewing
linguofreak wrote: But this is a "best practices" issue, right? Not a "None of the drives will work until you've given a Sense Interrupt for each one of them" issue?
No. If you only send one Sense Interrupt, then only one drive will work. If you only have one actual drive (and it happens to be the right one), then you just got lucky.

Re: Floppy controller state right after boot and other quest

Posted: Sun Mar 13, 2011 2:23 am
by linguofreak
bewing wrote:
linguofreak wrote: But this is a "best practices" issue, right? Not a "None of the drives will work until you've given a Sense Interrupt for each one of them" issue?
No. If you only send one Sense Interrupt, then only one drive will work. If you only have one actual drive (and it happens to be the right one), then you just got lucky.
OK. Lucky works. As long as the FDC activates each drive in a consistent order, I figure that my chances that my machine's one physical drive is hooked up to the first line are pretty good. If I'm wrong, the worst that happens is that I have to rewrite some code and kick myself for not having written it that way in the first place...

Re: Floppy controller state right after boot and other quest

Posted: Sun Mar 13, 2011 2:53 am
by linguofreak
DavidCooper wrote:
linguofreak wrote:I've recently started a hobby OS project with the goal of using as little code as possible that I did not write myself. This includes assemblers, compilers, and as much BIOS code as I can possibly do without. It's meant to hearken back, as far as possible, to the old days of hand assembling programs and punching them in on the front panel (which x86's, unfortunately, don't have). I'm writing my image files with a text editor and a Java program I wrote that reads in two characters, checks if they're both in one of the ranges 0-9 A-F a-f, and writes out a byte, as well as allowing me to define and use word-length constants (that last part is probably cheating a bit, but keeping track of pointers is a royal *pain* otherwise). I'm disassembling my code for proofreading with HTE.

(Before anyone asks: Yes, I'm five flavors of insane. I have no illusions that I'll get anywhere quickly with this project, and it's not unlikely that it will die an early death, but I'm going to try.)
So you're working directly with machine code numbers in hex and not using assembler? I too program directly in machine code (though I use decimals instead of hex), so I can tell you that your project should be both possible and practical - being insane is absolutely not a requirement for this. You might like to have a look at my machine code editor to see if it's a better option than doing everything through a text editor - it allows you to write machine code straight into memory locations where you'll can sometimes edit code even while it's running.
Part of the point is to use as little existing software as possible. Think of it as being as near as I can get to switching binary in through the front panel. Even my own hex-text-to-binary-image converter is cheating a bit in that it uses existing code (Java) to do more than just convert a hexadecimal text stream into a binary image (since I'm defining constants there as well).

Also, hex really makes stuff like this a lot easier than decimal does. Firstoff, all the Intel processor documentation (and probably most x86 opcode references of any kind out there) uses hexadecimal opcodes, so I can just lift the opcodes straight off the datasheets rather than converting them into decimal. Secondly, since one hex digit represents exactly four bits, hex is a lot easier to work with when you have to wrangle with individual bits, which you have to do quite a lot at this level.
Bear in mind that your OS won't be able to boot directly on a modern machine that lacks an internal floppy drive if you don't use the BIOS - I've just changed from doing what you're setting out to do to using the BIOS instead for that reason. If I was starting out from scratch now, I'd still want to write my own FDC driver, but I'd write code to do all loads and saves through the BIOS first and then write my own code to do the same job later on in 32-bit mode, allowing the OS to be switched into a non-BIOS-load/save mode whenever it's running on a machine with an internal floppy drive.
This code is going to be running on a particular machine that does have an internal floppy for quite a while. Portability is not a goal at this stage.

Re: Floppy controller state right after boot and other quest

Posted: Sun Mar 13, 2011 2:55 pm
by DavidCooper
linguofreak wrote:Part of the point is to use as little existing software as possible. Think of it as being as near as I can get to switching binary in through the front panel. Even my own hex-text-to-binary-image converter is cheating a bit in that it uses existing code (Java) to do more than just convert a hexadecimal text stream into a binary image (since I'm defining constants there as well).
Have you thought of avoiding hex as well and just using keys 0 to 7 to input bits (or even just 0 and 1)?
Also, hex really makes stuff like this a lot easier than decimal does. Firstoff, all the Intel processor documentation (and probably most x86 opcode references of any kind out there) uses hexadecimal opcodes, so I can just lift the opcodes straight off the datasheets rather than converting them into decimal.
I chose to work with decimal because it's far easier to read - a screenful of hex makes every value look alike, whereas a screenful of decimals shows up the pattern of the code and lets you identify the major content of the screen in an instant. But I'm not suggesting that you should switch to decimals - I'm looking forward to seeing what you come up with and how you get on with it precisely because you're doing it in hex.
Secondly, since one hex digit represents exactly four bits, hex is a lot easier to work with when you have to wrangle with individual bits, which you have to do quite a lot at this level.
You don't actually have to do very much of that at all, and on the few occasions when you do, it's easy enough to do it with decimals - you soon learn all the multiples of 16 (and indeed of 8 ) between 0 and 256, so converting to binary becomes trivial. But you should stick with hex regardless as you're already comfortable with it.
This code is going to be running on a particular machine that does have an internal floppy for quite a while. Portability is not a goal at this stage.
People are throwing out their old equipment at an alarming rate, so make sure you collect a few spare machines now while they're still easy to come by, and don't get any that lack a reset button. Your particular machine might start sparking like mine recently did and you may end up with the purity of your OS being thrown out the window as you're forced to work within both Bochs and someone else's operating system. I completely understand why you want to avoid using the BIOS as much as possible because I felt the same way about it in the past and shunned it, but in doing so I painted myself into a very uninteresting corner from which I have only recently managed to escape. We're building on shifting sands, so keep looking ahead so that you don't spend years building anything that's doomed to become instant archaeology.

Re: Floppy controller state right after boot and other quest

Posted: Tue Mar 22, 2011 9:33 pm
by linguofreak
bewing wrote:5. As I recall, the errors I spotted were in setting up the registers for the DMA. The wrong register numbers were used. Be very careful about that. Read the ISA DMA article with extreme care.
I'm reading through the ISA DMA article, and the example code at the bottom doesn't match the rest of the article. It starts out:

Code: Select all

out 0x0a, 0x05      ; mask DMA channel 2 and 0
Now, 0x05 will do exactly what the comment says it will do if we write it to the multichannel mask register. The problem is that the rest of the article says that the multichannel mask register is 0x0f, not 0x0a (which the article says is the single channel mask register). So it appears that this example code is buggy. (If I interpret it correctly, it will mask channel 1, right?).

The tutorial uses port 0x0a, like the example code, but uses the correct value (0x06) for masking channel 2 with the single channel mask register. Other than that, AFAICT, the DMA register numbers in the tutorial match up with both the code and the text of the ISA DMA article.

EDIT: Also, can it be assumed that BIOS has left the FDC set up for DMA (at least on machines more recent than 2000 or so), or must one explicitly set the DOR IRQ bit to 1 and send a specify with NDMA = 0?

Re: Floppy controller state right after boot and other quest

Posted: Wed Mar 23, 2011 2:04 am
by Combuster
linguofreak wrote:EDIT: Also, can it be assumed that BIOS has left the FDC set up for DMA (at least on machines more recent than 2000 or so), or must one explicitly set the DOR IRQ bit to 1 and send a specify with NDMA = 0?
General wisdom wrote:Assumption is the mother of all ****-ups

Re: Floppy controller state right after boot and other quest

Posted: Wed Mar 23, 2011 8:32 am
by bewing
You are right about the 0x5 -- even taking into account that this is a code snippet, 5 is clearly a bad value. I fixed it in the wiki.

And I'd agree with Combuster. There is no reason at all why the BIOS would be using DMA. DMA is only useful in a multitasking OS, which the BIOS is not.

Re: Floppy controller state right after boot and other quest

Posted: Thu Mar 24, 2011 11:33 pm
by linguofreak
It works!

I actually ended up writing the code to send a specify command but not using it: On my first test in Bochs I ran straight in to a bug that led to a panic when I tried to send the specify. So I commented the code sending the specify to see if it was the problem. It wasn't, but I found the bug without uncommenting the code.

Now to put together a payload that actually does something...