The Floppy Drive
2010-12-11
Introduction
Accessing the floppy drive on a PC is one of the most complex tasks. Besides programming the floppy drive controller (FDC), it requires programming the DMA controller, because the FDC uses it to transfer data to and from memory. In this part, we develop all the code necessary to read data from the floppy drive.
DMA
Recall that, in the keyboard handler, we were reading bytes from the keyboard
controller with in al, 60h
. This instruction uses the CPU to read one byte from the keyboard
controller and store it in al
. We can then transfer this byte to memory with a mov
instruction.
The DMA controller allows us to transfer data between peripherals and memory without using the CPU (Well, almost. We use the CPU to program the DMA controller first.) This has the advantage that the CPU can work on other things while data is being transfered in the background. Originally, the DMA controller could also transfer data much faster than the CPU, but the extreme increase of CPU speeds has reversed that picture.
In order to use the DMA controller to transfer data from the FDC to memory, we must initialize the DMA controller with the right parameters. The controller has four channels, 0 through 3. Channel 2 is connected to the FDC. Before we start fiddling with it, we disable the channel. This can be done by writing to the mask register of the DMA controller, located at port 0x0a. We pass the number of the channel to mask in the lower 2 bits, and set bit 2 (this indicates we want to disable the channel).
; Disable channel 2
mov al, 110b
out 0ah, al
Now we can set the type of transfer. We are going to perform a write transfer (meaning that it writes to memory), in single mode (meaning the DMA controller will stop after the transfer is done). For this, we need to write a byte to port 0x0b, which is the controller's mode register. FIXME: Explain value.
; Set single write mode for channel 2
mov al, 01000110b
out 0bh, al
We also need to set the address to transfer data to. When talking to the DMA controller, we specify the address as a 64KB page and an offset within that page. For channel 2, the page number is written to port 0x81, and the offset to port 4. Both registers are 8-bit. For the page register, this is not a problem, as 4 bits are enough to encode any page accessible to the CPU. However, we need 16 bits to encode the offset. The trick used by the DMA controller is that the offset register is written to twice, once for the low byte and once for the high byte. The controller keeps track of which one it expects by means of a flip-flop, which we will need to initialize first. This is accomplished by writing any byte to port 0x0c. The full sequence is as follows:
; Set start address
out 0ch, al ; Initialize flip-flop
; Write offset
mov al, [low_offset]
out 04h, al
mov al, [high_offset]
out 04h, al
; Write page
mov al, [page]
out 081h, al
Next, we specify how much data we want to transfer by writing to port 5. The value to write is the number of 16-bit words, minus one. Just as with the start offset, we write a low and a high byte.
; Set count
out 0ch, al ; Initialize flip-flop
mov al, [low_count]
out 05h, al
mov al, [high_count]
out 05h, al
Finally, we enable the channel. This works just like disabling it, except that bit 2 is cleared.
; Enable channel 2
mov al, 10b
out 0ah, al
That's it for the DMA controller. Now comes the floppy drive.
The Floppy Drive Controller
This section still needs to be written.
Files
The file dma.inc contains code for working with the DMA controller. The file floppy.inc contains code to work with the FDC. syscall.inc contains updated system call numbers for use with the DMA controller and the FDC. Finally, the file floppy_kernel.asm contains a kernel which reads a messages from sectors 18 and 36 on the diskette and displays them.
An example message is contained in secretmessage.txt. This message can be
written to the diskette with a command like dd if=secretmessage.txt
of=/dev/fd0 bs=512 seek=18
. Compiling the kernel and writing it to
the diskette works as usual.