CS-220, Sec. 90, Week 12C R. Eckert DISK I/O Both hard and floppy disks store information magnetically. They are non- volatile storage devices since the information remains on the disk after the computer is turned off. They are also writable in the sense that the information on a disk can be changed by writing new information--which replaces the information that was stored previously. Floppy diskettes are also highly portable, as it is easy to transport a diskette from one computer to another. As shown in the diagram below, a disk or diskette rotates under a "read/write head" that can be moved in or out over the disk's surface. The surface of the disk can be magnetized by causing a current to flow in a tiny coil inside the read/write head. In the case of a floppy diskette, the read/write head is in contact with the surface of the disk; in the case of a hard disk, it floats over the surface. In either case information is stored by changing the magnetism of the disk surface underneith the read/write head. In the simplest systems a change of magnetic flux can represent a one, and the absence of a change in magnetic flux a zero. When in write mode, the read/write head acts like an electromagnet that, depending on the direction of electric current flowing in its coil, magnetizes the disk surface in one direction or another as it goes by. In read mode the coil senses changes in magnetic flux. As should be evident by this very brief description, disk storage is serial (one bit at a time) in nature. The surface of a disk is organized into concentric tracks, each of which is divided into sections of an arc called sectors. In the case of floppy disks, a very common organization (Double sided, high density, DSHD) is to have 80 tracks on each side of the floppy, each of which is divided into 18 sectors. In this scheme each sector can hold 512 bytes of information stored serially. In order to read data from or write data to a floppy disk, the read/write head must be moved over the correct track, and we must wait until the correct sector comes around and is under it. Then, when writing, the system must extract each bit of each byte to be stored and send signals to the hardware that will either change or not change the magnetic flux in the coil. All of the bits must be sent while the sector is still under the read/write head. In reading, the process is similar, but the coil detects changes (or no changes) in magnetism on the surface which must be interpretted as ones or zeroes, assembled into bytes, and stored in the computer's memory. In either case timing is critical. To facilitate the process of reading or writing disk data, the floppy disk drive is controlled by an integrated circuit called a floppy disk controller (FDC). This device can send signals to the drive mechanism that make the read/write head move in or out and can detect when a given sector is under the read/write head. It can also send signals to the floppy disk drive to read or write a bit. Since this level of control is very low-level and very difficult to achieve, the FDC is organized so that certain signals it receives from the microprocessor can cause it to send the necessary signals to the disk drive to do things like read or write an entire sector. It can also tell the processor when a new byte has been assembled (reading) and is ready to be stored in memory or when it is ready to receive a new byte (writing) for serialization and output to the disk. In many microcomputer systems, communication between the microprocessor and the FDC is through I/O ports, in a way reminiscent of the printer (although much more complex). DIRECT TRACK/SECTOR DISK I/O One way of doing disk I/O would be to use the FDC directly by monitoring FDC status ports, sending appropriate commands to FDC command ports, and reading or writing data from or to appropriate data ports. An easier way would be to use operating system services to perform the same tasks. For example, on a PC, BIOS int 25h can be used to perform an "absolute disk read", and BIOS int 26h an "absolute disk write." In either case, CX must be loaded with the number of sectors to read or written, AL the disk drive to be used (A=0, B=1, C=2, etc.), DX the "starting logical sector number", which for a double sided high density diskette would be: logical sector # = (sector - 1) + (head * 18) + (track * 36), where
1<=sector<=18 0<=head<=1 0<=track<=79 DS:BX must also be loaded with the start address of a block of memory (buffer) that will be used to hold the incoming data in the case of a disk read and which must contain the data to be stored in the case of a disk write. For either of these two BIOS services, the carry flag indicates whether (0) or not (1) the the operation was successful. If it failed (CF=1), and AH register will indicate what the problem was as follows: AH=1 ==> bad command Ah=2 ==> bad address mark AH=3 ==> write protected disk AH=4 ==> sector not found AH=8 ==> Direct Memory Access failure AH=10h ==> Cyclic Redundancy Check error AH=20h ==> disk controller error AH=40h ==> seek error AH=80h ==> device not responding (time out) There is one other consideration in using int 25h and int 26h. Both of them use the stack to preserve the flags--and do not restore the stack pointer to its original value. Consequently you must do a pop (or add 2 to the stack pointer) to re-align the stack after invoking either interrupt. USING BIOS INT 13H TO DO DIRECT TRACK/SECTOR DISK I/O Int 13h in many ways combines the services of int 25h and int 26h to read or write one or more sectors of informaton. To read disk sectors, load AH with a 2; to write, load AH with a 3. The other registers should be set up as follows: AL = number of sectors to transfer ES:BX must point to the memory buffer providing or receiving the data CH = track number (0-79 for a DS/HD floppy disk) CL = sector number (0-17 for DS/HD floppy disk) DH = head or side number (0 or 1 for DS/HD floppy disk) DL = drive number (0=A, 1=B, 2=C, 3=D, etc.) After invoking int 13h, if the carry flag is 0, the disk transfer was done successfully and AL will contain the actual number of sectors read or written. If the carry flag is 1, AH will conatain a status code that indicates what the problem was. The same codes are used as for int 25h and int 26h. USING DOS (INT 21H) SERVICES FOR HIGH-LEVEL DISK I/O Accessing the FDC directly or using BIOS services that write to specified disk tracks and sectors can be very dangerous if the disk contains other information that is important. Most operating systems have some sort of file system for saving and reading information using named files. In the case of the PC, DOS maintains something called a File Allocation Table (FAT), which, in simplest terms, maps file names to the tracks and sectors of the disk where the data in the file is actually stored. Again on a PC, there are DOS services (accessed with int 21h, as usual) that allow us to do disk I/O using named files. Some of these services are: 3Ch (create a file), 3Dh (open--make accessible for reading or writing--an existing file), 3Eh (close an open file), 3F (read from a file, 40h (write to a file), and 42h (seek--move a file position pointer to a given position in the file). In all but the first two of these, the file is specified by providing a 16-bit number called a file handle. This number is obtained when the file is first created or opened. A brief description of these DOS disk services is now given. CREATE FILE: AH=3Ch CX=file attibute (00h==>normal file, 01h==>read only, 02==>hidden, 04==>DOS system file, 08==>volume label, 10h==>subdirectory, 20h==>archive file DS:DX=address of the zero-terminated string that specifies the file name. If successful, CF=0 and AX will contain the file handle that will be used for subsequent accesses to the file. OPEN EXISTING FILE: AH=3Dh AL=Mode flags (00==>read only, 01==>write only, 02==>read/write DS:DX=address of the zero-terminated string that specifies the file name. If successful, CF=0 and AX will contain the file handle that will be used for subsequent accesses to the file. CLOSE FILE: AH=3Eh BX=file handle specifying file to be closed. If successful, CF=0. READ FROM FILE: AH=3Fh BX=file handle specifying file to be read CX=number of bytes to be read DS:DX=start address of memory block (buffer) where the incoming data will be stored. If successful, CF=0 and AX will contain the number of bytes actually read. WRITE TO FILE: AH=40h BX=file handle specifying file to be written CX=number of bytes to be written DS:DX=start address of memory block (buffer) containing the data to be written. If successful, CF=0 and AX will contain the number of bytes actually written. SEEK: AH=42h BX=file handle specifying file to be written CX:DX=byte offset (how far to move file position pointer) AL=origin of move (00==>from start of file, 01==>from current location,. 03==>from end of file If successful, CF=0 and DX/AX will contain the new file position pointer location from the start of the file.