This document concerns only hard drives. Floppy disks, CD-ROM, and ZIP drives are not normally split into partitions. You should familiarize yourself with CHS and LBA sector addressing modes before reading this document.

Here we go

The first sector of the hard disk must contain the information about disk structure. If the disk is booted from, it must also contain a boot loader. As you remember, this sector is at CHS (0, 0, 1) or LBA (0). To verify that this sector is valid, one should read a 16 bit word at offset 1FE from the beginning of this sector and compare it to AA55 (needless to say, the word is in Intel little endian notation). If this word is different from AA55, the hard disk should not be considered valid. The typical behavior of decent operating systems in this case is to silently ignore this hard disk.

The information about disk partitions starts from the predefined offset 1BE from the beginning of the first sector. There are four partition table entries at this offset, each taking up 10h bytes:
Partition Offset
1 1BE
2 1CE
3 1DE
4 1FE
The structure of each entry is below:
Offset in entry Size in bytes Meaning
0 1 Boot indicator
1 1 Beginning head number
2 1 Beginning sector and high cylinder number
3 1 Beginning low cylinder number
4 1 System indicator
5 1 Ending head number
6 1 Ending sector and high cylinder number
7 1 Ending low cylinder number
8 4 Number of sectors preceding the partition
C 4 Number of sectors in the partition
Let us take a closer look at each field and its meaning.

Boot indicator is 80h for bootable partitions and zero for other valid partitions. If it is neither 80h nor zero, the corresponding partition should be considered invalid. Invalid partitions are silently ignored by most of the systems. For the disk to be bootable, exactly one entry must contain 80h in this field. However, the condition when more than one entry is marked as bootable should not be considered fatal error. If two or more of the partitions are bootable, all should be treated as valid partitions.

Beginning cylinder, head, and sector numbers point to the first sector of the partition in CHS notation. Two high bits of "beginning sector and high cylinder number" are two high bits of cylinder number. Similarly, ending cylinder, head, and sector point to the last sector in the partition. They are in exactly the same format.

Sector="sector and high cylinder number" and 4F
Cylinder="low cylinder number"+(("sector and high cylinder number" shr 6) shl 8)

Thus, BIOS imposes the following limitations:
CHS Minimum value Maximum value Number of bits Number of values
Sector 1 64 6 64
Head 0 255 8 256
Cylinder 0 1023 10 1024
If you multiply the values in the last column out and multiply the result by sector size, you will get the hard disk size limitation of 8 GB. If you consider that older IDE implementations supported up to 16 heads, you will get the infamous 512 MB barrier. How this barrier is dealt with was described in previous documents.

If disk was partitioned in LARGE or LBA modes, CHS addresses in these fields are logical CHS addresses. Therefore, you should better use BIOS services to access CHS partitions. But since BIOS is terribly inefficient, you may take a risk of providing the same software CHS translation as it does. To do it, get physical device parameters from the device and logical device parameters from BIOS. If any of them equals to zero, the disk is misconfigured and should not be used. Then compare physical SectorsPerHead against logical SectorsPerHead. If they are not equal, BIOS is using some strange CHS translation mode, and you should use BIOS services to access the partition. If they are equal, divide physical NumberOfCylinders by logical NumberOfCylinders and remember the result. Then divide logical HeadsPerCylinder by physical HeadsPerCylinder. If the quotient is not the same as the result of the previous division, or if the quotient is not the power of two, you should use BIOS services for accessing the partition. Otherwise use this quotient to provide BIOS-like CHS translation.

Certainly, sanity check on these CHS values is absolutely necessary. Systems vary in the ways how they handle this stage. I recommend the following simple algorithm. I insist that you copy partition table to the temporary buffer with easier to handle format. Zero-extend Cylinder, Head, and Sector values to 16 bit words and use signed arithmetic. First of all, make sure that none of the partitions starts at CHS (0, 0, 1). Remove all that do. Then make sure that none of the partitions overlap. If any two partitions do overlap, my best guess would be truncating the preceding partition so that they don't overlap any more. Do this by setting ending sector address of the preceding partition to the beginning sector address of the next partition minus one. Do not forget that arithmetic operations on CHS addresses have peculiarities. After that check that none of the ending sector addresses exceeds physical disk size. Truncate ending sector addresses, if necessary, by setting them to CHS (NumberOfCylinders-1, HeadsPerCylinder-1, SectorsPerHead). Finally, make sure that each partition has at least one sector in it. If beginning sector address is greater than or equal to ending sector address, such partition should be considered invalid. By now you should have valid partition information in your temporary buffer. Use this information to access partitions. But unless you are a disk analyzer program, do not write any changes to the partition table itself.

Now I would like to say a couple of words about compatibility. Many programs expect that the very first partition starts at CHS (0, 1, 1) and that all partitions except the first one start at even cylinder boundaries, CHS (2*k, 0, 1). They also expect that partitions cover the disk completely and are consecutive on the disk. If you are paranoid, also make sure that the very first partition is bootable.

Number of sectors preceding the partition is its LBA address. Number of sectors in the partition is its LBA length. Note that these values are essentially duplicating the CHS values that are described above. They must define exactly the same partition as CHS values. When LBA and CHS values are in conflict, some heuristics is necessary. Check system indicator to find out which values should be used. Give precedence to LBA values in LBA partitions and to CHS values in CHS partitions. Do not make any assumptions about the partitions you don't know. You should not access them anyway.

The same sanity check should be performed on LBA values, as was on CHS values. Remove the partitions that start at LBA (0). If any two partitions overlap, truncate the preceding partition. Make sure that none of the sums of partition address and size exceeds disk capacity and truncate partition size if necessary. Remove partitions that have zero size.

Note that sanity check across CHS and LBA partitions would be very nice. If CHS and LBA addresses are consistent for each partition, it is easier to perform this check by converting all addresses to LBA, doing the check, and then converting the results back to CHS. Unfortunately, if CHS and LBA addresses of any partition are in conflict, sanity check can do more harm than good because of different CHS translation modes. My recommendation in this case is to do separate sanity checks between CHS partitions and LBA partitions, but not across them.

Some of the system indicators are in the table below:
Value System Capacity Translation mode
00 Unknown
01 DOS FAT12, 16 bit sector number <10MB CHS
04 DOS FAT16, 16 bit sector number <32MB CHS
05 DOS Extended partition CHS
06 DOS 4.0 FAT16, 32 bit sector number >=32MB CHS
0E DOS FAT16, 32 bit sector number >=32MB LBA
0F DOS Extended partition LBA
51h Ontrack extended partition
64h Novell
Note that 2 TB limit for partition type 0C is not in contradiction with BIOS 8 GB limitation because LBA addressing is used. However, I don't know where the 2 TB limit for partition type 0B comes from. Well, it comes from one of the documents in the Microsoft Knowledge Base, but I fail to see how the CHS partition larger than 8 GB can be implemented.

This table does not mean to be exhaustive. New operating systems and utilities appear and die here and there, so this table will always be incomplete. Common sense says that when you find an unfamiliar value in the table, you should not attempt to modify any of the sectors in this partition. The best policy is to silently ignore such partition.

DOS Extended Partitions

Two of the system indicators deserve special attention. They are extended DOS partitions 05 and 0F. Extended DOS partition contains a secondary partition table and some space for nested partitions. The secondary partition table is right at the beginning sector of the DOS extended partition. Its format is almost the same as that of the main partition table described above. However, some things must be taken into consideration.

Extended partition must have one or two entries. I do not encourage you to handle the situation when extended partition has more than two entries because this partition is very DOS specific and unlikely to be changed. I think, it is safe to check only the first two entries of the extended partition.

One of the entries should define a DOS partition. For this entry, CHS and LBA addresses are relative to the sector containing the secondary partition table. Another entry may define the deeper nested extended DOS partition. In this case, CHS and LBA addresses are relative to the beginning of the physical disk. This also implies that there can be many nested extended partitions, so the function that looks through them should keep track of used resources and handle the situation when it runs out of buffers. All nested partitions must fall within the mother extended partition. Truncate them if they don't. None of the partitions can be bootable, but this should be taken into consideration only by special disk analyzing programs.

Finally, primary partition may have multiple extended partition entries.

Other DOS Notes

The information below is specific to DOS operating system.

Everything that is not DOS extended partition is called primary partition. For the unclear reasons DOS manuals say that every partition table should contain only one primary partition. But DOS does support multiple primary partitions correctly, and you should too.

Letters for DOS disks are assigned in the following order. Letters 'A' and 'B' are assigned to floppy drives. If there is one floppy drive, it is assigned 'A'. The letter 'C ' is assigned to the first primary partition on the first hard drive. The next letters are assigned to first primary partitions on all hard drives. Then go volumes inside the extended partitions on all hard drives, in the order they appear. First, all extended partitions on the first drive are given letters, then - on the second drive, etc. Then the remaining primary partitions on all drives are assigned letters. Finally, CD-ROM drives take their share of letters. Note that the letters that CD-ROM drives have can be configured by software.

Author:  Alex Verstak  3/10/1998