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 |
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 |
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 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 |
02 | XENIX | ||
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 |
0B | DOS FAT32 | <2TB | CHS |
0C | DOS FAT32 | <2TB | LBA |
0E | DOS FAT16, 32 bit sector number | >=32MB | LBA |
0F | DOS Extended partition | LBA | |
51h | Ontrack extended partition | ||
64h | Novell |
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.
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.
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.