In the PC world, living with the BIOS disk interface is definitely a nightmare. This section documents how awful the chaos is and how GRUB deals with the BIOS disks.
CHS -- Cylinder/Head/Sector -- is the traditional way to address sectors on a disk. There are at least two types of CHS addressing; the CHS that is used at the INT 13H interface and the CHS that is used at the ATA device interface. In the MFM/RLL/ESDI and early ATA days the CHS used at the INT 13H interface was the same as the CHS used at the device interface.
Today we have CHS translating BIOS types that can use one CHS at the INT 13H interface and a different CHS at the device interface. These two types of CHS will be called the logical CHS or L-CHS and the physical CHS or P-CHS in this section. L-CHS is the CHS used at the INT 13H interface and P-CHS is the CHS used at the device interface.
The L-CHS used at the INT 13 interface allows up to 256 heads, up to 1024 cylinders and up to 63 sectors. This allows support of up to 8GB drives. This scheme started with either ESDI or SCSI adapters many years ago.
The P-CHS used at the device interface allows up to 16 heads up to 65535 cylinders, and up to 63 sectors. This allows access to about 2^26 sectors (32GB) on an ATA device. When a P-CHS is used at the INT 13H interface it is limited to 1024 cylinders, 16 heads and 63 sectors. This is where the old 528MB limit originated.
LBA -- Logical Block Address -- is another way of addressing sectors that uses a simple numbering scheme starting with zero as the address of the first sector on a device. The ATA standard requires that cylinder 0, head 0, sector 1 address the same sector as addressed by LBA 0. LBA addressing can be used at the ATA interface if the ATA device supports it. LBA addressing is also used at the INT 13H interface by the AH=4xH read/write calls.
ATA devices may also support LBA at the device interface. LBA allows access to approximately 2^28 sectors (137GB) on an ATA device.
A SCSI host adapter can convert a L-CHS directly to an LBA used in the SCSI read/write commands. On a PC today, SCSI is also limited to 8GB when CHS addressing is used at the INT 13H interface.
First, all OS's that want to be co-resident with another OS (and that is all of the PC based OS's that we know of) must use INT 13H to determine the capacity of a hard disk. And that capacity information must be determined in L-CHS mode. Why is this? Because:
During the boot processing, all of the disk read accesses are done in L-CHS mode via INT 13H and this includes loading the first of the OS's kernel code or boot manager's code.
Second, because there can be multiple BIOS types in any one system, each drive may be under the control of a different type of BIOS. For example, drive 80H (the first hard drive) could be controlled by the original system BIOS, drive 81H (the second drive) could be controlled by a option ROM BIOS and drive 82H (the third drive) could be controlled by a software driver. Also, be aware that each drive could be a different type, for example, drive 80H could be an MFM drive, drive 81H could be an ATA drive, drive 82H could be a SCSI drive.
Third, not all OS's understand or use BIOS drive numbers greater than 81H. Even if there is INT 13H support for drives 82H or greater, the OS may not use that support.
Fourth, the BIOS INT 13H configuration calls are:
An ATA disk must implement both CHS and LBA addressing and must at any given time support only one P-CHS at the device interface. And, the drive must maintain a strict relationship between the sector addressing in CHS mode and LBA mode. Quoting the ATA-2 document:
LBA = ( (cylinder * heads_per_cylinder + heads ) * sectors_per_track ) + sector - 1 where heads_per_cylinder and sectors_per_track are the current translation mode values.
This algorithm can also be used by a BIOS or an OS to convert a L-CHS to an LBA.
This algorithm can be reversed such that an LBA can be converted to a CHS:
cylinder = LBA / (heads_per_cylinder * sectors_per_track) temp = LBA % (heads_per_cylinder * sectors_per_track) head = temp / sectors_per_track sector = temp % sectors_per_track + 1
While most OS's compute disk addresses in an LBA scheme, an OS like DOS must convert that LBA to a CHS in order to call INT 13H.
The basic problem is that there is no requirement that a CHS translating BIOS followed these rules. There are many other algorithms that can be implemented to perform a similar function. Today, there are at least two popular implementations: the Phoenix implementation (described above) and the non-Phoenix implementations. Because a protected mode OS that does not want to use INT 13H must implement the same CHS translation algorithm. If it doesn't, your data gets scrambled.
In the perfect world of tomorrow, maybe only LBA will be used. But today we are faced with the following problems:
These are difficult problems to overcome in today's industry environment. The result: chaos.
Real mode only. These functions are the traditional CHS mode disk interface. GRUB calls them only if LBA mode is not available.
INT 13H, AH=02h reads sectors into memory.
Input:
AH | 02h |
AL | The number of sectors to read (must be non-zero). |
CH | Low 8 bits of cylinder number. |
CL | Sector number in bits 0-5, and high 2 bits of | cylinder number in bits 6-7.
DH | Head number. |
DL | Drive number (bit 7 set for hard disk). |
ES:BX | Data buffer. |
Output:
CF | Set on error. |
AH | Status. |
AL | The number of sectors transferred (only valid if CF | set for some BIOSes).
INT 13H, AH=03h writes disk sectors.
Input:
AH | 03h |
AL | The number of sectors to write (must be non-zero). |
CH | Low 8 bits of cylinder number. |
CL | Sector number in bits 0-5, and high 2 bits of | cylinder number in bits 6-7.
DH | Head number. |
DL | Drive number (bit 7 set for hard disk). |
ES:BX | Data buffer. |
Output:
CF | Set on error. |
AH | Status. |
AL | The number of sectors transferred (only valid if CF | set for some BIOSes).
INT 13H, AH=08h returns drive parameters. For systems predating the IBM PC/AT, this call is only valid for hard disks.
Input:
AH | 08h |
DL | Drive number (bit 7 set for hard disk). |
Output:
CF | Set on error. |
AH | 0. |
AL | 0 on at least some BIOSes. |
BL | Drive type (AT/PS2 floppies only). |
CH | Low 8 bits of maximum cylinder number. |
CL | Maximum sector number in bits 0-5, and high 2 bits | of maximum cylinder number in bits 6-7.
DH | Maximum head number. |
DL | The number of drives. |
ES:DI | Drive parameter table (floppies only). |
Real mode only. These functions are IBM/MS INT 13 Extensions to support LBA mode. GRUB uses them if available so that it can read/write over 8GB area.
INT 13, AH=41h checks if LBA is supported.
Input:
AH | 41h. |
BX | 55AAh. |
DL | Drive number. |
Output:
CF | Set on error. |
AH | Major version of extensions (10h for 1.x, 20h for | 2.0 / EDD-1.0, 21h for 2.1 / EDD-1.1 and 30h for EDD-3.0) if successful, otherwise 01h (the error code of invalid function).
BX | AA55h if installed. |
AL | Internal use. |
CX | API subset support bitmap (see below). |
DH | Extension version. |
The bitfields for the API subset support bitmap are(11):
Bit(s) | Description |
0 | Extended disk access functions (AH=42h-44h, 47h, 48h) | supported.
1 | Removable drive controller functions (AH=45h, 46h, 48h, | 49h, INT 15H, AH=52h) supported.
2 | Enhanced disk drive (EDD) functions (AH=48h, 4Eh) | supported.
3-15 | Reserved (0). |
INT 13, AH=42h reads sectors into memory.
Input:
AH | 42h. |
DL | Drive number. |
DS:SI | Disk Address Packet (see below). |
Output:
CF | Set on error. |
AH | 0 if successful, otherwise error code. |
The format of Disk Address Packet is:
Offset (hex) | Size (byte) | Description |
00 | 1 | 10h (The size of packet). |
01 | 1 | Reserved (0). |
02 | 2 | The number of blocks to transfer (max 007F for | Phoenix EDD).
04 | 4 | Transfer buffer (SEGMENT:OFFSET). |
08 | 8 | Starting absolute block number. |
INT 13, AH=43h writes disk sectors.
Input:
AH | 43h. |
AL | Write flags (In version 1.0 and 2.0, bit 0 is the | flag for verify write and other bits are reserved (0). In version 2.1, 00h and 01h indicates write without verify, and 02h indicates write with verify.
DL | Drive number. |
DS:SI | Disk Address Packet (see above). |
Output:
CF | Set on error. |
AH | 0 if successful, otherwise error code. |
INT 13, AH=48h returns drive parameters. GRUB only makes use of the total number of sectors, and ignore the CHS information, because only L-CHS makes sense. See section CHS addressing and LBA addressing, for more information.
Input:
AH | 48h. |
DL | Drive number. |
DS:SI | Buffer for drive parameters (see below). |
Output:
CF | Set on error. |
AH | 0 if successful, otherwise error code. |
The format of drive parameters is:
Offset (hex) | Size (byte) | Description |
00 | 2 | The size of buffer. Before calling this function, | set to the maximum buffer size, at least 1Ah. The size actually filled is returned (1Ah for version 1.0, 1Eh for 2.x and 42h for 3.0).
02 | 2 | Information flags (see below). |
04 | 4 | The number of physical cylinders. |
08 | 4 | The number of physical heads. |
0C | 4 | The number of physical sectors per track. |
10 | 8 | The total number of sectors. |
18 | 2 | The bytes per sector. |
v2.0 and later | ||
1A | 4 | EDD configuration parameters. |
v3.0 | ||
1E | 2 | Signature BEDD to indicate presence of Device Path | information.
20 | 1 | The length of Device Path information, including | signature and this byte (24h for version 3.0).
21 | 3 | Reserved (0). |
24 | 4 | ASCIZ name of host bus (`ISA' or `PCI'). |
28 | 8 | ASCIZ name of interface type (`ATA', | `ATAPI', `SCSI', `USB', `1394' or `FIBRE').
30 | 8 | Interface Path. |
38 | 8 | Device Path. |
40 | 1 | Reserved (0). |
41 | 1 | Checksum of bytes 1Eh-40h (2's complement of sum, | which makes the 8 bit sum of bytes 1Eh-41h equal to 00h).
The information flags are:
Bit(s) | Description |
0 | DMA boundary errors handles transparently. |
1 | CHS information is valid. |
2 | Removable drive. |
3 | Write with verify supported. |
4 | Drive has change-line support (required if drive is | removable).
5 | Drive can be locked (required if drive is removable). |
6 | CHS information set to maximum supported values, not | current media.
7-15 | Reserved (0). |
Go to the first, previous, next, last section, table of contents.