Take the following fdisk input:
o # Create DOS/MBR partition table.
n # Create new partition.
p # Partition type
1 # Partition ID
2048 # Starting sector
+4M # Ending sector
t # Assign said partition to a FAT12 filesystem.
1 # FAT12 filesystem.
a # Mark said partition as bootable.
w # Write partition table.
Now, let's take a look at the MBR, specifically of the partition entry (partition entry starts at 0x80
near the end of the first line).
000001b0: 0000 0000 0000 0000 4a2f 9087 0000 8020 ........J/.....
000001c0: 2100 01a2 2200 0008 0000 0020 0000 0000 !..."...... ....
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
According to the layout of the MBR portion entries (given here and here), the values we can glean the CHS tuple from are 0x20
, 0x21
, 0x00
.
0x20
is rather simple: it equates to the 32nd head.
0x21
contains both the starting sector and the starting cylinder. 0x21
-> 0b00100001
, giving 33
as the sector, and the 8th and the 9th bits of the cylinder resulting in 0
(0b00
).
Combining the cylinder bits of 0b00
(from the 0x21
) and 0b00000000
, we get 0b0000000000
as the cylinder. All in all, we end up with a starting head of 32, a starting sector of 33, and a starting cylinder of 0.
When I try and load this CHS via BIOS interrupts, it complains that the CHS is invalid (I can read other sectors just fine). I assume this is because the head is 32; after all, why would you have a 16-platter hard disk?
tl;dr
Fdisk outputs MBR with CHS values.
My question is if I'm misunderstanding how the CHS value is encoded into the partition entry or if this is a quirk of fdisk.
Best Answer
According to fdisk itself, the C/H/S values are indeed supposed to be:
fdisk doesn't try to match the actual disk geometry – this has long been impossible within the C/H/S limits, so all it does is compute some values that would give the correct result when converted back to LBA.
Code from util-linux
include/pt-mbr.h
:Comment from util-linux
libfdisk/src/dos.c
:You pretend to have a 16-platter hard disk in order to represent more disk space than the C/H/S system could normally represent. With only 64ki cylinders × 255 sectors × 2 heads per platter, all you can reach is ~8 GB per platter and obviously disks have slightly outgrown that by now.
The OS or firmware doesn't control each head individually, it just passes the numbers to the disk via ATA commands and gets data back, so it doesn't really care whether the disk somehow has 255 heads or not. And neither does the disk itself, anymore – the first thing disks now do is use a formula to convert the C/H/S values to linear LBA addresses (assuming the disk was given C/H/S and not LBA to begin with).
So even before BIOSes and OSes switched to dealing directly with LBA, it was already common to use "absurd" C/H/S values in order to access more disk space that the format would normally allow.
All current operating systems just ignore the C/H/S fields in MBRs and deal with LBA exclusively, and apparently that's what "OnTrack Disk Manager" used to do in MS-DOS. (Also, as far as I know, SCSI disks never supported C/H/S to begin with, they were always LBA-only.) I'm somewhat sure that just about any BIOS you'll find these days has native support for LBA via "extended INT 13h" (as Google tells me).