For more information on disk drives and PC bootup, see the BIOS/hardware reference.
DOS hard drives may be 'partitioned' to form several 'logical drives' (which are normally each assigned their own drive letter by DOS). Only one partition at a time can be marked 'bootable'. The partition table information is contained in the master boot record (the true boot record, "MBR") of the drive, which resides on the first logical sector (of the first track or cylinder on the first head). That first sector also contains the MBR code, which determines the bootable partition and loads the boot sector (first logical sector) of that partition, executing it as if it was itself a boot record (loaded at the same location, registers contain the same values). It is possible to install several different operating systems on one computer in this way, especially if the standard MBR code is replaced in order to allow the bootable partition to be seleced at boot time.
There is a limit of four entries in the master partition table. DOS allows these entries to contain pointers to 'extended partition tables', whose format is exactly the same as for the main partition table except there is no boot code (the space normally reserved for the boot code is empty). All the extended partitions should exist within the space reserved by the extended partition entry - only two of the extended partitions are meant to be used, the first as a normal partition, the second as another extended partition (optional).
The DOS boot sector contains as a first instruction a 'jmp' (code 0EBh for DOS 3.x+) to the real code. The boot sector contains various information about the disk, including a BIOS parameter block, as well as some DOS startup code, which loads (part of) IO.SYS or the equivalent and passes control to it. The exact workings may be DOS specific and version specific.
Any sectors before the boot sector of a logical DOS drive are considered to be 'hidden' sectors. The DOS kernel does not interpret hidden sectors (it is up to the disk device drivers, which are usually internal to DOS anyway, to skip 'hidden' sectors). Normal floppy drives have 0 hidden sectors. Hard drive partitions will have a number reflecting their location on the drive. Note that the whole first head of the first cylinder is (usually) reserved for the partition table, even though it is only the first sector which is actually used.
Following the hidden sectors are 'reserved' sectors usually used only for the boot sector. Following this are the File Allocation Tables (FATs). The FATs should all be identical (there are normally two). They contain a map of cluster usage (the data area sectors are grouped into 'clusters'. The number of sectors per cluster does not vary for any particular disk, and depends on the number of sectors - DOS can only map a certain number of clusters; if there are more sectors than the maximum number of clusters, then more than one sector is assigned to each cluster). The FATs also mark bad clusters, and give the order of clusters for a file.
Following the last FAT is the root directory. The root directory is variable size but must be contiguos (and under DOS cannot normally change size once initiated). The root directory contains information about the files and directories branching from the root directory. All further directories are themselves stored as files, in the same format as the root directory.
Interestingly enough, the volume label for a floppy is usually stored within the boot sector, but the volume label for a hard drive is stored as a root directory entry and the space reserved in the boot sector is left blank with spaces. The DOS 'DIR' command returns the one in the directory if present, or the one in the boot sector if not.
| Offset | Description |
| 0000h | Code to load and execute currently bootable partition. |
| 01BEh | Partition table entry #1 |
| 01CEh | Partition table entry #2 |
| 01DEh | Partition table entry #3 |
| 01EEh | Partition table entry #4 |
| 01FEh | Bootable sector signature 55h, AAh (55h low) |
| Offset | Description |
| 0000h | Boot indicator. 0 - inactive, 80h - bootable |
| 0001h | Beginning head |
| 0002h | Beginning sector (in bits 0-5), and bits 9-8 of the beginning cylinder (in bits 7-6) |
| 0003h | Beginning cylinder (bits 7-0) |
| 0004h | System indicator |
| 0005h | End head |
| 0006h | End sector (in bits 0-5) and bits 9-8 of the ending cylinder (in bits 7-6) |
| 0007h | End cylinder (bits 7-0) |
| 0008h | DWORD absolute starting sector |
| 000Ch | DWORD absolute ending sector |
Beginning/ending head/sector/cylinder: These are the same values that should be used when accessing the partition via the BIOS INT 13H interface (i.e. they are logical CHS numbers as understood by the BIOS, not necessarily physical CHS numbers as understood by the drive hardware.
In determining the sector/head/track from an absolute sector number, the sector is incremented first (is the least significant portion), then the head, then the track/cylinder (most significant portion). Sector numbers start at 1, head/cylinder numbers start at 0.
Also, the 2 most significant bits of the (10 bit) cylinder number are stored in the 2 most significant bits of the byte at offset 02h/06h. The other bits in this byte form a 6 bit sector number. Thanks to Rick Ondrejicka for pointing out that I had originally missed this.
By convention, paritions always start on a cylinder boundary (that is, sector 1, head 0 of some cylinder. The exception is a partition starting in cylinder 0, which will start at head 1/sector 1. This usually leaves most of the first track (cylinder 0/head 0) unused; it contains only the MBR. This unused space is often used by boot manager software.
If a partition starts or ends at a cylinder address beyond what is representable in the partition table, convention seems to be to "max out" the relevant CHS values so that they are the highest legal values given the geometry of the drive (as represented by the BIOS INT 13H interace). It may be that all CHS values are maxed out (linux utilities do this) or just the cylinder number (Windows XP seems to do this).
System indicator: 0 = not defined/unknown, 1 = DOS 12-bit FAT, 2-3 = XENIX, 4 = DOS 16 bit FAT with 512 or less bytes/cluster (<32 MB), 5 = Extended DOS partition, 6 = large (bigger than 32MB) DOS partition with 16 bit FAT, >512 bytes/cluster.
| Offset | Description |
| 0000h | JMP instruction, code 0EBh for DOS 3.x+ |
| 0003h | (8 bytes) OEM name. Identifier of creator of boot record |
| 000Bh | WORD bytes per sector |
| BIOS PARAMETER BLOCK | |
| 000Dh | BYTE Sectors per cluster |
| 000Eh | WORD Reserved sectors |
| 0010h | BYTE Number of FATs |
| 0011h | WORD Maximum number of root directory entries |
| 0013h | WORD Total number of sectors |
| 0015h | BYTE media descriptor |
| 0016h | WORD sectors per FAT |
| (BPB ends) | |
| 0018h | WORD sectors per track |
| 001Ah | WORD number of heads |
| 001Ch | WORD number of hidden sectors (see also next) |
| EXTENDED BOOT RECORD INFO (DOS 4.0+) | |
| 001Eh | WORD number of hidden sectors (high WORD) |
| 0020h | DWORD Total number of sectors |
| 0024h | WORD Physical drive number (as passed to BIOS) |
| 0026h | BYTE Extended information signature (29h) |
| 0027h | DWORD disk serial number |
| 002Bh | 11 BYTEs volume label (floppys only, see main text) |
| 0036h | 8 BYTEs file system. FAT12 or FAT16 (padded with spaces) |
Bytes per sector: Must be an integer power of 2 (eg, 64, 128, 256). Floppy disks are normally 512 bytes/sector; most fixed disks are also 512 bytes/sector.
Total number of sectors: Excludes hidden sectors. If zero in the BPB, the field in the extended boot record information is used and vice versa.
Media descriptor: Used to give an indication of the media (disk) type. Normal values are 0 for an extended DOS partition, 0F0h for a (18 sector/80 track) 1.44MB 3 1/2 inch floppy, 0F8h for a hard drive, 0FDh for a (9 sector/40 track) 360KB 5 1/4 inch floppy (unverified) or a (9 sector/80 track) 720KB 3 1/2 inch (verified) , 0F9h for a (80 track 15 sector) 1.2MB 5 1/4 inch floppy. '0' seems to be the best way to go for anything else. The media descriptor byte doesn't appear to actually mean very much.
First two entries: Reserved. The first byte of the first entry is also the media descriptor byte.
Further entries: (MAX is 0xffff for 16 bit fats, 0xfff for 12 bit fats)
| 0 | if the cluster is unused (free, available) |
| (MAX-7) to MAX | Last cluster in file |
| (MAX-8) | bad cluster |
| (MAX-15) to (MAX-8) | reserved cluster |
| Anything else: | Next cluster in file chain (this is the number of the appropriate entry in the FAT table, so #2 is the first non-reserved cluster) |
Note also that all subdirectories (but not the root directory) contain entries for the '.' (this subdirectory) and '..' (parent directory) directories, as displayed in a normal directory listing.
| Offset | Description | 0 | (11 bytes) file name or (on hard disks) volume label. For file names, the first 8 bytes are the name before the extension (left justified, padded with spaces) and the final 3 bytes are the extension. If the first byte is 0, this entry is invalid and is the last entry. If it is E5h**, the file has been deleted. If it is 5, the first character is actually an 0E5h (but the file has not been deleted). |
| 0Bh | File attributes: bit 0 - read only flag bit 1 - hidden file flag bit 2 - system file flag bit 3 - volume label flag (indicates entry is a volume label) bit 4 - file is a subdirectory (in same format as directory) bit 5 - archive bit (file modified since last backup), set by DOS bit 6 & 7 - reserved |
| 0Ch | (10 bytes) reserved |
| Time and date stamp give time of last file modification | |
| 16h | (2 bytes) timestamp (bits 0-4 : seconds in two second increments, bits 5-10 : minutes, bits 11-15 : hours [from 0-23]) |
| 18h | (2 bytes) datestamp (bits 0-4 : day of month, 5-8 : month, 9-15 : years since 1980) |
| 1Ah | (2 bytes) First cluster of file (2 = first cluster after root dir). A value of 0 is used in 'parent directory' ('..') entries to indicate that the parent is the root directory. |
| 1Ch | (4 bytes) File size in bytes. |