Carnegie Mellon
SCS logo
Computer Science Department
home
syllabus
staff
schedule
lecture
projects
homeworks
QA
 
 

15-410 IDE device driver page


The Organization of a Hard Disk

A hard disk is composed of one or more disk-shaped pieces of magnetic media. Unlike floppy disks (which contain magnetic media that is, well, floppy), the disks in a hard disk are rigid, hence the name hard disk. Each disk in a hard disk is referred to as a platter. Information can be stored on either side of this platter, and each side of a platter is referred to as a surface.

Each surface is further divided by concentric circles organizing it into tracks. The last step is to divide each track into some number of sectors. The sectors within a track occupy an equal amount of surface area. These sectors are the unit of transfer for a disk; you may not read or write less than one sector. For most modern hard disks, a sector contains 512 bytes.

Modern hard disks get more complicated than this - for example, they compensate for the fact that with this simple scheme, tracks near the outside of the surface would have much larger sectors than the tracks near the inside. However we will not go into such details here.

In fact, through a convenient abstraction known as logical block addressing, or LBA addressing (yes, that is technically logical block addressing addressing, but that is unfortunately the way the term is used), the geometry of the disk need not be a concern to you. LBA addressing numbers the sectors throughout the disk (all sectors on all surfaces) from zero on up, so that the disk appears to the system programmer like a large array of sectors. This simplification does not come completely for free (you should think about why), but it does make your job easier.

By convention, the first sector of the disk (sector zero) is not available for use by the file system. This sector is the boot sector. It contains important information such as a bootstrap program or partition table information. For this reason overwriting the first sector of the disk normally has catastrophic effects. You must ensure that your code never writes to sector zero.

Blocks vs. Sectors

A block is different than a sector in that it is the minimum unit of transfer for the file system. You may choose to make blocks equal to one sector, or you may choose to have blocks larger than one sector. A block must be an integer multiple of sectors, however.

Using the Disk

Like the devices you supported in projects one and three, communication with the disk is done through I/O ports using functions like inb and outb. Configuring and using the disk is a little more complicated than reading scancodes from the keyboard. The disk must be properly configured first, and there are several steps needed to initiate a read or a write. For this reason we have supplied you with a very simple disk driver, disk.c.

It is important to remember that only one request may be sent to the disk at any given time. If you try to initiate an IDE transfer while another transfer is already pending, an error will occur and the device driver will cause your kernel to panic.

The disk driver has the following interface (defined in disk.h):

void disk_handler(void)

This is the C-language interrupt handler. You will need to write an appropriate assembly-language wrapper for it and install the wrapper in slot DISK_IDT_ENTRY of the IDT (use an interrupt gate rather than a trap gate).

int disk_init(disk_callback_t read_callback, disk_callback_t write_callback)

Blocks until the disk is ready (on power-up a real disk may need time to begin responding to commands), and finds out how big the disk is. SUCCESS and ERROR are returned as appropriate. You will need to call this function, directly or indirectly, during the setup phase of your kernel.

The two callback functions, disk_read_callback() and disk_write_callback(), will be called when each outstanding read or write transfer completes. As the callbacks you provide just might perform process management, the driver will invoke them with interrupts disabled, after the PIC has been acknowledged (by now this should make sense to you; if it doesn't, you may have a conceptual problem which should be addressed before you proceed).

void disk_read_sector(int sector_num, char *dest, int sector_count)

Initiates an IDE operation to read the specified sectors from the disk and immediately returns to the caller. Eventually the sectors will be stored sequentially starting at the address dest.

void disk_write_sector(int sector_num, char *source, int sector_count)

Initiates an IDE operation to write the specified sectors to the disk and immediately returns to the caller. Eventually the sectors will be taken sequentially starting at the address source.

int disk_sectors(void)

Returns the number of sectors available on the disk. You must call this after calling disk_init() (and having disk_init() return SUCCESS).

Files

The IDE disk driver tarball contains disk.c and inc/disk.h.

In order for your simulated PC to support a disk, you will need a slightly different wrapper script. Copy your simics-linux.sh to something like simics-p4 and edit the latter, changing pebsim-p3 to pebsim-p4. If running that wrapper script doesn't create your hd.img, feel free to put anything there you wish.

You will note that the IDE disk we are providing you with is unusually small (in particular, it is smaller than the amount of RAM we gave you!). This is mainly to save AFS space...we are investigating a way to increase the disk size available to you.

You should not structurally change the files we give you. In other words, unless you need to change the behavior of the disk driver, which we discourage, your disk-related code should not be placed in disk.c.

We reserve the right to make changes to these files later via the "update" mechanism.


[Last modified Saturday January 10, 2004]