Hubbry Logo
search
logo
INT 13H
INT 13H
current hub

INT 13H

logo
Community Hub0 Subscribers
Read side by side
from Wikipedia

INT 13h is shorthand for BIOS interrupt call 13hex, the 20th interrupt vector in an x86-based (IBM PC-descended) computer system. The BIOS typically sets up a real mode interrupt handler at this vector that provides sector-based hard disk and floppy disk read and write services using cylinder-head-sector (CHS) addressing. Modern PC BIOSes also include INT 13h extension functions, originated by IBM and Microsoft in 1992, that provide those same disk access services using 64-bit LBA addressing; with minor additions, these were quasi-standardized by Phoenix Technologies and others as the EDD (Enhanced Disk Drive) BIOS extensions.

INT is an x86 instruction that triggers a software interrupt, and 13hex is the interrupt number (as a hexadecimal value) being called.

Modern computers come with both BIOS INT 13h and UEFI functionality that provides the same services and more, with the exception of UEFI Class 3 that completely removes CSM thus lacks INT 13h and other interrupts. Typically, UEFI drivers use LBA-addressing instead of CHS-addressing.

Overview

[edit]

Under real mode operating systems, such as DOS, calling INT 13h would jump into the computer's ROM-BIOS code for low-level disk services, which would carry out physical sector-based disk read or write operations for the program. In DOS, it serves as the low-level interface for the built-in block device drivers for hard disks and floppy disks. This allows INT 25h and INT 26h to provide absolute disk read/write functions for logical sectors to the FAT file system driver in the DOS kernel, which handles file-related requests through DOS API (INT 21h) functions.

Under protected mode operating systems, such as Microsoft Windows NT derivatives (e.g. NT4, 2000, XP, and Server 2003) and Linux with dosemu, the OS intercepts the call and passes it to the operating system's native disk I/O mechanism. Windows 9x and Windows for Workgroups 3.11 also bypass BIOS routines when using 32-bit Disk Access. Besides performing low-level disk access, INT 13h calls and related BIOS data structures also provide information about the types and capacities of disks (or other DASD devices) attached to the system; when a protected-mode OS boots, it may use that information from the BIOS to enumerate disk hardware so that it (the OS) can load and configure appropriate disk I/O drivers.

The original BIOS real-mode INT 13h interface supports drives of sizes up to about 8 GB using what is commonly referred to as physical CHS addressing. This limit originates from the hardware interface of the IBM PC/XT disk hardware. The BIOS used the cylinder-head-sector (CHS) address given in the INT 13h call, and transferred it directly to the hardware interface. A lesser limit, about 504 MB, was imposed by the combination of CHS addressing limits used by the BIOS and those used by ATA hard disks, which are dissimilar. When the CHS addressing limits of both the BIOS and ATA are combined (i.e. when they are applied simultaneously), the number of 512-byte sectors that can be addressed represent a total of about 504 MB.

The 504 MB limit was overcome using CHS translation, a technique by which the BIOS would simulate a fictitious CHS geometry at the INT 13h interface, while communicating with the ATA drive using its native logical CHS geometry. (By the time the 504 MB barrier was being approached, ATA disks had long before ceased to present their real physical geometry parameters at the external ATA interface.) Translation allows the BIOS, still using CHS addressing, to effectively address ATA disks with sizes up to 8064 MB, the native capacity of the BIOS CHS interface alone. (The ATA interface has a much larger native CHS addressing capacity, so once the "interference" of the CHS limits of BIOS and ATA was resolved by addressing, only the smaller limitation of the BIOS was significant.) CHS translation is sometimes referred to as logical CHS addressing, but that is actually a misnomer since by the time of this BIOS development, ATA CHS addresses were already logical, not physical. The 8064 MB limit originates from a combination of the register value based calling convention used in the INT 13h interface and the goal of maintaining backward compatibility—dictating that the format or size of CHS addresses passed to INT 13h could not be changed to add more bits to one of the fields, e.g. the Cylinder-number field. This limit uses 1024 cylinders, 256 heads, 63 sectors, and 512 byte blocks, allowing exactly 7.875 GiB of addressing (1024 × 256 × 63 × 512 bytes). There were briefly a number of BIOSes that offered incompatible versions of this interface—for example, AWARD AT BIOS and AMI 386sx BIOS have been extended to handle up to 4096 cylinders by placing bits 10 and 11 of the cylinder number into bits 6 and 7 of register DH.

All versions of MS-DOS, (including MS-DOS 7 and Windows 95) have a bug which prevents booting disk drives with 256 heads (register value 0xFF), so many modern BIOSes provide CHS translation mappings with at most 255 (0xFE) heads,[1][2] thus reducing the total addressable space to exactly 8032.5 MiB (approx 7.844 GiB).[3]

To support addressing of even larger disks, an interface known as INT 13h Extensions was introduced by IBM and Microsoft, then later re-published and slightly extended by Phoenix Technologies as part of BIOS Enhanced Disk Drive Services (EDD).[4][5] It defines new functions within the INT 13h service, all having function numbers greater than 40h, that use 64-bit logical block addressing (LBA), which allows addressing up to 8 ZiB. (An ATA drive can also support 28-bit or 48-bit LBA which allows up to 128 GiB or 128 PiB respectively, assuming a 512-byte sector/block size). This is a "packet" interface, because it uses a pointer to a packet of information rather than the register based calling convention of the original INT 13h interface. This packet is a very simple data structure that contains an interface version, data size, and LBAs. For software backward-compatibility, the extended functions are implemented alongside the original CHS functions, and calls to functions from both sets can be intermixed, even for the same drive, with the caveat that the CHS functions cannot reach past the first 8064 MB of the disk.

Some cache drivers flush their buffers when detecting that DOS is bypassed by directly issuing INT 13h from applications. A dummy read via INT 13h can be used as one of several methods to force cache flushing for unknown caches (e.g. before rebooting).[1][2]

AMI BIOSes from around 1990–1991 trash word unaligned buffers. Some DOS and terminate-and-stay-resident programs clobber interrupt enabling and registers so PC DOS and MS-DOS install their own filters to prevent this.[6]

List of INT 13h services

[edit]
Drive Table
DL = 00h 1st floppy disk ( "drive A:" )
DL = 01h 2nd floppy disk ( "drive B:" )
DL = 02h 3rd floppy disk ( "drive C:" )
. . .
DL = 7Fh 128th floppy disk
DL = 80h 1st hard disk
DL = 81h 2nd hard disk
DL = 82h 3rd hard disk
. . .
DL = E0h CD/DVD[citation needed], or 97th hard disk
. . .
DL = FFh 128th hard disk
Function Table
AH = 00h   Reset Disk System
AH = 01h   Get Status of Last Drive Operation
AH = 02h   Read Sectors From Drive
AH = 03h   Write Sectors To Drive
AH = 04h   Verify Sectors
AH = 05h   Format Track
AH = 06h   Format Track Set Bad Sector Flags
AH = 07h   Format Drive starting at Track
AH = 08h   Read Drive Parameters
AH = 09h HD Initialize Disk Controller
AH = 0Ah HD Read Long Sectors From Drive
AH = 0Bh HD Write Long Sectors To Drive
AH = 0Ch HD Move Drive Head To Cylinder
AH = 0Dh HD Reset Disk Drives
AH = 0Eh PS/2 Controller Read Test
AH = 0Fh PS/2 Controller Write Test
AH = 10h HD Test Whether Drive Is Ready
AH = 11h HD Recalibrate Drive
AH = 12h PS/2 Controller RAM Test
AH = 13h PS/2 Drive Test
AH = 14h HD Controller Diagnostic
AH = 15h   Read Drive Type
AH = 16h FD Detect Media Change
AH = 17h FD Set Media Type For Format (used by DOS versions <= 3.1)
AH = 18h FD Set Media Type For Format (used by DOS versions >= 3.2)
AH = 19h   Park Heads
AH = 41h EXT Test Whether Extensions Are Available
AH = 42h EXT Read Sectors From Drive
AH = 43h EXT Write Sectors To Drive
AH = 44h EXT Verify Sectors
AH = 45h EXT Lock/Unlock Drive
AH = 46h EXT Eject Drive
AH = 47h EXT Move Drive Head To Sector
AH = 48h EXT Read Drive Parameters
AH = 49h EXT Detect Media Change
AH = 4Bh EXT Get Drive Emulation Type

If the second column is empty then the function may be used both for floppy and hard disk.

  • FD: for floppy disk only.
  • HD: for hard disk only.
  • PS/2: for hard disk on PS/2 system only.
  • EXT: part of the INT 13h Extensions which were written in the 1990s to support hard drives with more than 8 GB.

INT 13h AH=00h: Reset Disk System

[edit]
Parameters
AH 00h
DL Drive (bit 7 set means reset both hard and floppy disks)
Results
CF Set on error
AH Return Code

INT 13h AH=01h: Get Status of Last Drive Operation

[edit]
Parameters
AH 01h
DL Drive

Bit 7=0 for floppy drive, bit 7=1 for fixed drive

Results
AH
Return Code
00h Success
01h Invalid Command
02h Cannot Find Address Mark
03h Attempted Write On Write Protected Disk
04h Sector Not Found
05h Reset Failed
06h Disk change line 'active'
07h Drive parameter activity failed
08h DMA overrun
09h Attempt to DMA over 64kb boundary
0Ah Bad sector detected
0Bh Bad cylinder (track) detected
0Ch Media type not found
0Dh Invalid number of sectors
0Eh Control data address mark detected
0Fh DMA out of range
10h CRC/ECC data error
11h ECC corrected data error
20h Controller failure
40h Seek failure
80h Drive timed out, assumed not ready
AAh Drive not ready
BBh Undefined error
CCh Write fault
E0h Status error
FFh Sense operation failed
CF Set On Error, Clear If No Error

INT 13h AH=02h: Read Sectors From Drive

[edit]
Parameters
AH 02h
AL Sectors To Read Count
CH Cylinder
CL Sector
DH Head
DL Drive
ES:BX Buffer Address Pointer
Results
CF Set On Error, Clear If No Error
AH Return Code
AL Actual Sectors Read Count

Remarks

[edit]

Register CX contains both the cylinder number (10 bits, possible values are 0 to 1023) and the sector number (6 bits, possible values are 1 to 63). Cylinder and Sector bits are numbered below:

CX =       ---CH--- ---CL---
cylinder : 76543210 98
sector   :            543210

Examples of translation:

 CX := ( ( cylinder and 255 ) shl 8 ) or ( ( cylinder and 768 ) shr 2 ) or sector;
 cylinder := ( (CX and $FF00) shr 8 ) or ( (CX and $C0) shl 2)
 sector := CX and 63;

Addressing of Buffer should guarantee that the complete buffer is inside the given segment, i.e. ( BX + size_of_buffer ) <= 10000h. Otherwise the interrupt may fail with some BIOS or hardware versions.

Example

[edit]

Assume you want to read 16 sectors (= 2000h bytes) and your buffer starts at memory address 4FF00h. Utilizing memory segmentation, there are different ways to calculate the register values, e.g.:

ES = segment         = 4F00h
BX = offset          =  0F00h
sum = memory address = 4FF00h
would be a good choice because 0F00h + 2000h = 2F00h <= 10000h
ES = segment         = 4000h
BX = offset          =  FF00h
sum = memory address = 4FF00h
would not be a good choice because FF00h + 2000h = 11F00h > 10000h

Function 02h of interrupt 13h may only read sectors of the first 16,450,560 sectors of your hard drive, to read sectors beyond the 8 GB limit you should use function 42h of INT 13h Extensions. Another alternate may be DOS interrupt 25h which reads sectors within a partition.

Code Example

[edit]
    [ORG 7c00h]   ; code starts at 7c00h
    xor ax, ax    ; make sure ds is set to 0
    mov ds, ax
    cld
    ; start putting in values:
    mov ah, 2h    ; int13h function 2
    mov al, 63    ; we want to read 63 sectors
    mov ch, 0     ; from cylinder number 0
    mov cl, 2     ; the sector number 2 - second sector (starts from 1, not 0)
    mov dh, 0     ; head number 0
    xor bx, bx    
    mov es, bx    ; es should be 0
    mov bx, 7e00h ; 512bytes from origin address 7c00h
    int 13h
    jmp 7e00h     ; jump to the next sector
    
    ; to fill this sector and make it bootable:
    times 510-($-$$) db 0 
    dw 0AA55h

After this code section (which the asm file should start with), you may write code and it will be loaded to memory and executed.

Notice how we didn't change dl (the drive). That is because when the computer first loads up, dl is set to the number of the drive that was booted, so assuming we want to read from the drive we booted from, there is no need to change dl, except some emulators such as qemu requires you to specify the dl to the drive you want to read from.

INT 13h AH=03h: Write Sectors To Drive

[edit]
Parameters
AH 03h
AL Sectors To Write Count
CH Track
CL Sector
DH Head
DL Drive
ES:BX Buffer Address Pointer
Results
CF Set On Error, Clear If No Error
AH Return Code
AL Actual Sectors Written Count

INT 13h AH=04h: Verify Sectors From Drive

[edit]
Parameters
AH 04h
AL Sectors To Verify Count
CH Track
CL Sector
DH Head
DL Drive
ES:BX Buffer Address Pointer
Results
CF Set On Error, Clear If No Error
AH Return Code
AL Actual Sectors Verified Count

INT 13h AH=05h: Format Track

[edit]
Parameters
AH 05h
AL Sectors To Format Count
CH Track
CL Sector
DH Head
DL Drive
ES:BX Buffer Address Pointer
4-byte address field
(applies to PC/XT 286,AT, PS/1 and PS/2)
Byte Meaning Allowable Values
1 Track
2 Head
3 Sector
4 Bytes/Sector 0=128, 1-256, 2-512, 3-1024
Results
CF Set On Error, Clear If No Error
AH Return Code

INT 13h AH=06h: Format Track Set Bad Sector Flags

[edit]
Parameters
AH 06h
AL Interleave
CH Track
CL Sector
DH Head
DL Drive
Results
CF Set On Error, Clear If No Error
AH Return Code

INT 13h AH=07h: Format Drive Starting at Track

[edit]
Parameters
AH 07h
AL Interleave
CH Track
CL Sector
DH Head
DL Drive
Results
CF Set On Error, Clear If No Error
AH Return Code

INT 13h AH=08h: Read Drive Parameters

[edit]
Parameters
Registers
AH 08h = function number for read_drive_parameters
DL drive index (e.g. 1st HDD = 80h)
ES:DI[7] set to 0000h:0000h to work around some buggy BIOS
Results
CF Set On Error, Clear If No Error
AH Return Code
DL number of hard disk drives
DH[7] logical last index of heads = number_of - 1 (because index starts with 0)
CX [7:6] [15:8][7] logical last index of cylinders = number_of - 1 (because index starts with 0)

[5:0][7] logical last index of sectors per track = number_of (because index starts with 1)

BL[7] drive type (only AT/PS2 floppies)
ES:DI[7] pointer to drive parameter table (only for floppies)

Remarks

[edit]
  • Logical values of function 08h may/should differ from physical CHS values of function 48h.
  • Result register CX contains both cylinders and sector/track values, see remark of function 02h.

INT 13h AH=09h: Init Drive Pair Characteristics

[edit]
Parameters
AH 09h
DL Drive
Results
CF Set On Error, Clear If No Error
AH Return Code

INT 13h AH=0Ah: Read Long Sectors From Drive

[edit]

The only difference between this function and function 02h (see above) is that function 0Ah reads 516 bytes per sector instead of only 512. The last 4 bytes contains the Error Correction Code (ECC), a checksum of sector data.

INT 13h AH=41h: Check Extensions Present

[edit]
Parameters
Registers Description
AH 41h = function number for extensions check[8]
DL drive index (e.g. 1st HDD = 80h)
BX 55AAh
Results
Registers Description
CF Set On Not Present, Clear If Present
AH Error Code or Major Version Number
BX AA55h
CX Interface support bitmask:
  • 1 – Device Access using the packet structure
  • 2 – Drive Locking and Ejecting
  • 4 – Enhanced Disk Drive Support (EDD)

INT 13h AH=42h: Extended Read Sectors From Drive

[edit]
Parameters
Registers Description
AH 42h = function number for extended read
DL drive index (e.g. 1st HDD = 80h)
DS:SI segment:offset pointer to the DAP, see below
DAP : Disk Address Packet
offset range size description
00h 1 byte size of DAP (set this to 10h)
01h 1 byte unused, should be zero
02h..03h 2 bytes number of sectors to be read, (some Phoenix BIOSes are limited to a maximum of 127 sectors)
04h..07h 4 bytes segment:offset pointer to the memory buffer to which sectors will be transferred (note that x86 is little-endian: if declaring the segment and offset separately, the offset must be declared before the segment)
08h..0Fh 8 bytes absolute number of the start of the sectors to be read (1st sector of drive has number 0) using logical block addressing (note that the lower half comes before the upper half)[9]
Results
Registers Description
CF Set On Error, Clear If No Error
AH Return Code

As already stated with int 13h AH=02h, care must be taken to ensure that the complete buffer is inside the given segment, i.e. ( BX + size_of_buffer ) <= 10000h

INT 13h AH=43h: Extended Write Sectors to Drive

[edit]
Parameters
Registers Description
AH 43h = function number for extended write
AL
  • bit 0 = 0: close write check,
  • bit 0 = 1: open write check,
  • bit 1-7:reserved, set to 0
DL drive index (e.g. 1st HDD = 80h)
DS:SI segment:offset pointer to the DAP
Results
Registers Description
CF Set On Error, Clear If No Error
AH Return Code

INT 13h AH=48h: Extended Read Drive Parameters

[edit]
Parameters
Registers Description
AH 48h = function number for extended_read_drive_parameters
DL drive index (e.g. 1st HDD = 80h)
DS:SI segment:offset pointer to Result Buffer, see below
Result Buffer
offset range size description
00h..01h 2 bytes size of Result Buffer (set this to 1Eh)
02h..03h 2 bytes information flags
04h..07h 4 bytes physical number of cylinders = last index + 1
(because index starts with 0)
08h..0Bh 4 bytes physical number of heads = last index + 1
(because index starts with 0)
0Ch..0Fh 4 bytes physical number of sectors per track = last index
(because index starts with 1)
10h..17h 8 bytes absolute number of sectors = last index + 1
(because index starts with 0)
18h..19h 2 bytes bytes per sector
1Ah..1Dh 4 bytes optional pointer to Enhanced Disk Drive (EDD) configuration parameters which may be used for subsequent interrupt 13h Extension calls (if supported)
Results
Registers Description
CF Set On Error, Clear If No Error
AH Return Code

Remark

[edit]

Physical CHS values of function 48h may/should differ from logical values of function 08h.

INT 13h AH=4Bh: Get Drive Emulation Type

[edit]
Parameters
Regsiters Description
AH 4Bh = get drive emulation type
AL 01
DL drive index (e.g. 1st HDD = 80h)
DS:SI points to an empty structure for result . must be 13h in size
Results
Registers Description
CF Set On Error, Clear if No Error
AX Return Code
DS:SI Points to a specification structure
Specification Structure
Offset Size (byte) Description
00h 1 Size of packets in byte (13h)
01h 1 Boot Media Type :
Bits
0 - 3 0000b: No Emulation

0001b: 1.2M Floppy Disk

0010b: 1.44M Floppy Disk

0011b: 2.88M Floppy Disk

0100b: Hard Disk

4-5 Reserved
6 Image Contain ATAPI Driver
7 Image Contain SCSI Driver
02h 1 Drive Number (Drive Index)
03h 1 CD-ROM Controller Number
04h 4 Logical Block Address (LBA) of disk image to emulate
08h 2 Device Specification:

bit 0: Drive is slave instead of master

bits 7-0: LUN and PUN

0Ah 2 Segment Of 3K Buffer For Caching CD-ROMs Reads
0Ch 2 Initial Boot Image Segment Starting From 7c0h Segment
0Eh 2 Number Of Sectors (512 bytes long) To Load
10h 1 Cylinder Count Low Byte (From int 8h)
11h 1 Sector Count (From int 8h)
12h 1 Head Count (From int 8h)

See also

[edit]

References

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
INT 13h is the hexadecimal designation for BIOS interrupt 19 (the 20th interrupt vector) in x86-based IBM PC-compatible computer systems, serving as the primary interface for low-level disk input/output operations on floppy disks and hard drives.[1] It enables software to perform essential tasks such as reading and writing sectors without direct hardware interaction, abstracting the complexities of various disk controllers through the Basic Input/Output System (BIOS).[2] Introduced with the original IBM PC in 1981 for floppy disk services, it was extended in the IBM PC/XT model of 1983 to support hard disks, marking a foundational element of early personal computing storage management.[2][3] The interrupt's functionality is invoked by loading specific registers—such as AH for the subfunction code, DL for the drive number, and CHS (cylinder-head-sector) parameters for addressing—and executing the INT 13h instruction, with results returned via flags like the carry flag (CF) and AH for status codes.[1] Core subfunctions include AH=00h to reset the disk system, AH=01h to retrieve the status of the last operation, AH=02h to read one or more sectors into memory, AH=03h to write sectors from memory to disk, AH=04h to verify sectors, and AH=08h to obtain drive parameters like the number of cylinders, heads, and sectors per track.[1] These operations typically transfer data in 512-byte sectors, with limitations tied to the original hardware: up to 1024 cylinders, 255 heads, and 63 sectors per track under CHS addressing, effectively capping addressable capacity at approximately 8 GB.[3] Early implementations supported only floppy drives in the 1981 IBM PC, with hard disk integration in 1983 relying on ST-506 interface geometries, which later caused compatibility issues as drive capacities grew.[3][2] Over time, INT 13h evolved to address larger storage needs through extensions introduced by IBM and Microsoft in 1992, including functions like AH=41h for installation checks and AH=42h/43h for extended read/write operations using Logical Block Addressing (LBA) via a disk address packet, allowing up to 64-bit sector addressing for capacities beyond 8 GB.[1] Additional subfunctions handle specialized tasks, such as AH=05h for formatting tracks, AH=45h to lock or unlock removable media, and AH=48h for extended drive parameters, with further vendor-specific extensions (e.g., AH=50h+ for caching or SCSI support).[1] While largely superseded by modern operating system drivers and UEFI in contemporary systems, INT 13h remains relevant in bootloaders, legacy environments, and data recovery tools due to its embedded role in the x86 BIOS legacy.[4]

Background and History

Origins in IBM PC BIOS

INT 13H, also known as interrupt 13 hexadecimal, serves as a fundamental BIOS interrupt in x86-based systems for performing low-level disk input/output operations. Introduced as part of the original IBM Personal Computer (PC) BIOS in 1981, it provides an interface for accessing floppy disk drives through functions such as reading sectors, writing sectors, and formatting tracks. This interrupt enables software, including the operating system loader, to interact directly with the disk hardware via the BIOS, abstracting the complexities of the underlying floppy disk controller.[5] The design of INT 13H originated with the IBM PC model 5150, released in August 1981, to support the system's primary storage medium: 5.25-inch floppy disk drives utilizing modified frequency modulation (MFM) or frequency modulation (FM) encoding schemes. These drives, controlled by the NEC μPD765 floppy disk controller integrated into the system board, allowed for double-density operation with a formatted capacity of 160 KB per diskette, organized into 40 tracks (cylinders), 2 sides (heads), and up to 8 sectors per track of 512 bytes each. The interrupt's parameters, passed via CPU registers like CH for cylinder, DH for head, and CL for sector, reflect this floppy-centric architecture, enabling precise addressing in a cylinder-head-sector (CHS) format tailored to the mechanical and electrical characteristics of 5.25-inch media. This setup was essential for the era's personal computing, where floppy disks served as the standard for data storage and program distribution.[5] In the boot process, INT 13H plays a pivotal role by facilitating the initial program load (IPL) from the bootable floppy disk. Upon power-on, the BIOS power-on self-test (POST) checks for a 5.25-inch drive and, if present, invokes INT 13H to read track (cylinder) 0, head 0, sector 1—the boot sector—into memory at physical address 0000:7C00. This sector contains the master boot record, which then loads the operating system. The interrupt's diskette bootstrap loader, embedded in the 40 KB ROM on the system board, ensures reliable execution of this sequence, marking INT 13H as integral to starting the system without relying on more advanced storage.[5] Although initially designed exclusively for floppy disks, INT 13H was extended in the IBM PC XT (model 5160) released in March 1983 to accommodate the introduction of fixed-disk (hard disk) support via the IBM Fixed Disk Adapter. This adaptation reused the same CHS addressing scheme, with cylinders numbered 0-1023 (using 10 bits, packed into the 16-bit CX register), heads 0-255 (8 bits in DH), and sectors 1-63 (6 bits in the low portion of CL), theoretically permitting up to approximately 8 GB of addressable storage at 512 bytes per sector—though early 10 MB drives were limited to 306 cylinders, 4 heads, and 17 sectors per track. These constraints stemmed from the register sizes in the 8088 processor and the need for compatibility with the original floppy functions, establishing foundational limits that influenced subsequent x86 disk I/O designs.[6]

Development and Standardization

Following the introduction of INT 13H in the original IBM PC for floppy disk operations, its expansion to hard disk support and cross-vendor compatibility became a cornerstone of early PC standardization. In 1984, Phoenix Technologies released the first commercially available IBM PC-compatible ROM BIOS through a cleanroom reverse-engineering process, ensuring that PC clones from various manufacturers could reliably implement INT 13H for disk access without infringing on IBM's intellectual property.[7][8] This approach was quickly adopted by other vendors, such as Compaq and American Megatrends, enabling widespread production of compatible systems throughout the 1980s and fostering an open ecosystem for PC hardware.[9] INT 13H achieved de facto standardization as the primary low-level disk interface in Microsoft MS-DOS and IBM PC DOS, where it served as the foundational mechanism for reading and writing sectors directly from the BIOS until higher-level abstractions like INT 21H wrappers emerged in later DOS versions.[2] This integration allowed DOS to abstract hardware differences across floppy and hard drives, promoting portability for applications and bootloaders without vendor-specific code.[3] A pivotal milestone occurred in March 1983 with the release of the IBM PC XT, which extended INT 13H to include hard disk services using cylinder-head-sector (CHS) addressing, supporting the ST-506 interface and enabling the first integrated hard drive options in PCs.[3] Concurrently, IBM PC DOS 2.0 introduced Master Boot Record (MBR) partitioning to manage larger volumes on these 10 MB hard disks, with INT 13H facilitating access to the partitioned structures during boot and file operations.[10] Despite these advances, early implementations of INT 13H faced inherent limitations from CHS addressing, capping accessible drive capacity at 504 MB due to constraints of 1024 cylinders, 16 heads, and 63 sectors per track under IDE protocols.[11] This barrier, rooted in the 1980s hardware design, prompted the development of translation schemes like Extended CHS (ECHS), which remapped logical geometries—such as dividing cylinders and multiplying heads—to simulate larger drives while maintaining compatibility with the INT 13H interface. In 1992, IBM and Microsoft introduced extensions to INT 13H, including functions for installation checks (AH=41h) and extended read/write operations using Logical Block Addressing (LBA) via disk address packets, allowing access to capacities beyond 8 GB.[11][1]

Decline and Legacy Use

As modern operating systems evolved, the reliance on INT 13h for disk I/O diminished significantly starting in the late 1990s, supplanted by native drivers that directly interfaced with hardware controllers for improved efficiency and support for advanced interfaces. Windows NT, introduced in 1993, employed native disk drivers from inception, bypassing BIOS interrupts entirely to achieve better performance and hardware abstraction independent of legacy firmware. Linux kernels similarly shifted to native IDE/ATA and SCSI drivers by the mid-1990s, phasing out BIOS dependencies for core operations as hardware standards like AHCI (introduced in 2004) and NVMe (standardized in 2011) gained prominence. The adoption of UEFI firmware from 2005 onward accelerated this transition by replacing traditional BIOS boot processes with modular services; however, while native UEFI eliminates the need for interrupt-based disk access, many implementations include a Compatibility Support Module (CSM) that emulates legacy BIOS functionality, including INT 13h, for backward compatibility, though CSM is increasingly phased out in modern systems as of 2025.[12][13] Despite its obsolescence in mainstream computing, INT 13h endures in niche domains where legacy BIOS compatibility remains essential. In embedded systems, it facilitates straightforward disk operations on resource-constrained hardware without requiring complex native drivers. Retro computing enthusiasts preserve it for authentic emulation of historical x86 environments, ensuring software from the DOS and early Windows eras functions as originally designed. Bootloaders such as GRUB, when operating in legacy BIOS mode, invoke INT 13h for initial sector reads to load kernel images, leveraging both CHS and LBA addressing to access boot devices before transitioning to protected-mode drivers.[14] Virtualization platforms maintain INT 13h through emulation to support legacy workloads without hardware alterations. QEMU emulates the full BIOS interrupt vector, including disk services, allowing bootloaders and early-stage OS code to interact seamlessly with virtual disks as if on physical legacy hardware. VirtualBox similarly provides BIOS INT 13h support in its legacy boot configurations, enabling compatibility testing and execution of vintage operating systems like MS-DOS or Windows 95. This emulation extends to BIOS option ROMs and floppy/hard disk geometries, preserving behavioral fidelity for development and archival purposes.[12] The legacy nature of INT 13h also exposed systems to security risks, as its direct firmware mediation lacked modern isolation mechanisms. Early malware exploited these BIOS calls to manipulate disk contents undetected; for instance, the CIH virus (also known as Chernobyl), active from 1998, targeted BIOS routines via memory overwrites, corrupting firmware and rendering infected systems inoperable until manual recovery. Such vulnerabilities prompted BIOS vendors to implement safeguards like dual-ROM configurations and write-protection against interrupt-mediated attacks.[15]

Technical Fundamentals

Interrupt Calling Convention

INT 13h is invoked by software through the x86 INT instruction with the interrupt number 13h, which triggers the BIOS disk services handler pointed to by the corresponding entry in the Interrupt Vector Table (IVT) located at physical memory address 0x0000004C.[5] This vector typically resolves to a handler routine in the system ROM BIOS, such as at segment F000h offset EC59h in the original IBM PC implementation.[5] The interrupt operates exclusively in real mode, aligning with the 8086/8088 architecture of early PC systems, where the processor switches to the handler's code segment and executes the disk operation routine.[16] Parameters for the interrupt are passed via CPU registers, with the AH register holding the subfunction code to select the specific disk operation (such as values from 00h to 0Ah for basic services).[16] The DL register specifies the target drive, using bit 7 to distinguish between floppy (bits 0-3 for drive selection, e.g., 00h for the first floppy) and hard disk drives (e.g., 80h for the first hard disk).[5] Other registers, such as CH, CL, DH, and AL, may carry additional parameters like track, sector, head, and sector count details depending on the subfunction, but these are prepared by the calling software prior to invocation.[16] Upon completion, the handler returns control to the caller using the standard x86 interrupt return mechanism (IRET instruction), with success or failure indicated by the Carry Flag (CF): CF is cleared for successful operations and set for errors.[5] The AH register provides a status code, where 00h denotes success and non-zero values signal specific errors, while AL or AX may return results such as the number of sectors processed.[16] All other registers are preserved by the BIOS handler according to real-mode conventions, ensuring minimal disruption to the caller's state.[5] Stack usage during INT 13h invocation is minimal and follows the x86 real-mode interrupt protocol: the CPU automatically pushes the flags, code segment (CS), and instruction pointer (IP) onto the stack upon entry, allowing the handler to use additional stack space if needed for temporary variables or subroutine calls.[16] The BIOS routine adheres to the established application binary interface (ABI) for interrupts, avoiding unnecessary stack depth and restoring the original stack pointer upon return to maintain program integrity.[5]

Register Parameters and Return Values

The INT 13H interrupt handler in the IBM PC BIOS uses the x86 register set to pass parameters and receive return values for disk operations, following the standard BIOS calling convention where inputs are placed in registers prior to the interrupt invocation and outputs are set by the handler upon return.[17] The primary input register for function selection is AH, which specifies the operation (e.g., 02H for reading sectors, 03H for writing sectors), while DL selects the target drive, with values from 00H to 7FH designating floppy disk drives and 80H to FFH for hard disk drives.[17] For operations involving sector addressing in CHS (Cylinder-Head-Sector) mode, the registers CH, CL, and DH encode the location: CH holds the low 8 bits of the cylinder number, DH specifies the head, and CL contains the sector number in its low 6 bits along with the high 2 bits of the cylinder in bits 7-6.[17] The AL register indicates the number of sectors to transfer, typically ranging from 1 to 255, though the actual limit depends on the drive's geometry and the function invoked to prevent crossing track boundaries.[17] In read and write functions, the data buffer is specified via the segment:offset pair ES:BX, where the buffer must reside in conventional memory below 1 MB and, for reliable DMA transfers, should be aligned on a 16-byte (paragraph) boundary to match the BIOS's underlying hardware constraints.[12] Upon completion, the carry flag CF is cleared (CF=0) to indicate success, with AL updated to reflect the actual number of sectors transferred or verified.[17] If an error occurs, CF is set (CF=1), AH holds the error code (e.g., 01H for invalid function, 02H for address mark not found), and other registers may be altered unpredictably.[17] These conventions apply across most functions, with variations such as the absence of ES:BX in parameter retrieval calls like AH=08H, which instead returns drive geometry in CH, CL, and DH.[17]
RegisterCommon Input RoleCommon Output Role
AHFunction code (e.g., 02H read, 03H write)Error/status code on failure (e.g., 01H invalid)
ALSector count (1-255)Sectors successfully transferred on success
DLDrive number (00H-7FH floppy, 80H-FFH hard)Unchanged or drive-specific info
CHCylinder low 8 bitsMax cylinders (in param retrieval)
CLSector (low 6 bits) + cylinder high 2 bitsMax sectors/track (in param retrieval)
DHHead numberMax heads (in param retrieval)
ES:BXData buffer address (read/write)Unchanged
CFN/A0=success, 1=error

Error Handling and Status Codes

In the INT 13H BIOS disk interrupt, errors are primarily indicated by the carry flag (CF) being set to 1 upon return, signaling a failure in the requested operation, while CF=0 denotes success.[18] The AH register then provides an 8-bit status code, with 00h representing successful completion and non-zero values specifying the error type; these codes are also stored in the BIOS Data Area at offsets 0040:0041h for diskettes and 0040:0074h for fixed disks.[18] [19] Common error codes returned in AH include 01h for an invalid function request, 02h for an address mark not found, 03h for a write-protect error, 04h for a sector not found, 10h for an uncorrectable CRC or ECC data error, 40h for a seek operation failure, 80h for a timeout, and AAh for a drive not ready.[18] [19] These codes differ slightly between diskette (DL < 80h) and fixed disk (DL >= 80h) operations, with diskettes emphasizing media-related issues like change line activity (06h) and fixed disks including controller-specific faults like bad track detected (0Bh).[19] For extended error information, certain functions may set additional flags or return details in registers like AL (e.g., sectors transferred before failure) or store extended status in the BIOS Data Area, though this varies by BIOS implementation and device type.[18] [20] Handling errors typically involves first checking the carry flag and AH after an INT 13H call; for ongoing status, programmers can invoke subfunction AH=01h to poll the last operation's result without altering hardware state.[20] Transient errors, such as seek failures (40h) or timeouts (80h), warrant retry logic—commonly up to three attempts following a disk system reset via AH=00h to recalibrate drives and clear controller states.[18] [20] Persistent or critical errors may require user intervention, like media replacement for write-protect (03h) or no-media conditions. A key limitation of INT 13H error reporting is the absence of standardized text messages or descriptive strings, forcing applications to interpret numeric codes and map them to custom error handling or user-facing prompts.[18] Additionally, partial transfers (e.g., fewer sectors read than requested due to errors) can leave AL unreliable, and error details may not fully capture hardware nuances without vendor-specific extensions.[12] [20]
Error Code (Hex)MeaningTypical Context
01hInvalid function requestGeneral
02hAddress mark not foundGeneral
03hWrite protect errorDiskette/Fixed Disk
04hSector not foundGeneral
10hUncorrectable CRC/ECC errorDiskette/Fixed Disk
40hSeek operation failedGeneral
80hTimeoutGeneral
AAhDrive not readyFixed Disk

Core Disk Operations

System Reset and Status Check

The INT 13H interrupt provides two fundamental functions for system reset and status checking of disk drives: the reset operation (AH=00h) and the status query (AH=01h). These functions are essential for initializing disk controllers and verifying the outcome of prior operations, ensuring reliable low-level disk access in x86-based systems. The reset function recalibrates drive heads by seeking to track 0, while the status function retrieves the result of the most recent INT 13H call on a specified drive, aiding in error detection without initiating new hardware actions.[21][22] For the reset operation (AH=00h), the BIOS resets the disk controller associated with the drive specified in DL (00h-7Fh for floppies, 80h-FFh for hard disks), forcing recalibration of the read/write heads to track 0. Input registers are limited to AH=00h and DL=drive number; upon success, the carry flag (CF) is cleared and AH=00h is returned, while failure sets CF and places a BIOS disk error code in AH (e.g., 01h for invalid function or 80h for timeout). In systems like IBM PS/2 models (e.g., 35SX, 40SX), issuing a reset to one hard drive may affect both master and slave drives due to shared controller behavior. If the bit 7 of DL is set (indicating a hard disk), some BIOS implementations, such as Phoenix BIOS, reset both hard disk and floppy disk controllers simultaneously. This function is typically invoked prior to read or write operations to ensure the drive is in a known state, though it can take several seconds on older hardware due to the mechanical seek process.[21][23] The status query (AH=01h) examines the outcome of the last INT 13H operation on the drive in DL, returning the status without altering hardware state. Inputs are AH=01h and DL=drive number; success clears CF and sets AH=00h, while errors set CF and load AH with a code such as 03h (write-protected), 06h (media changed, specific to floppies), or 80h (timeout). Some BIOS variants, like the IBM PS/2 Model 30/286, also place the status in AL. This function is particularly useful for detecting media changes in floppy drives, where a 06h code signals the need to reinitialize parameters after disk ejection or swap. It is commonly called after any disk operation to confirm completion, but its results persist across calls until a new operation overwrites them, with variations in implementation (e.g., status location in AH or AL) depending on the BIOS.[22] These functions have key use cases in bootloaders and low-level drivers, where reset ensures drive readiness before data transfers, and status checks enable robust error handling, such as retrying operations on transient faults. Limitations include BIOS-specific behaviors—e.g., not all systems clear floppy status automatically on media change—and the potential for the reset to inadvertently affect multiple drives in multi-drive configurations, requiring careful DL selection to avoid unnecessary recalibrations. General error codes, like those in AH, provide brief context for failures but are detailed in broader INT 13H documentation.[21][22]

Sector Read Operations

The sector read operation in INT 13H is invoked by setting the AH register to 02h, which directs the BIOS to transfer a specified number of sectors from the disk into system memory. This function supports reading between 1 and 128 sectors, with the exact count provided in the AL register, starting from the logical address defined by the cylinder (CH), head (DH), and sector (CL) registers. The target drive is selected via the DL register, where values 00h-03h indicate floppy drives and 80h or higher denote fixed disks. The data is loaded into a buffer pointed to by the ES:BX register pair, assuming a standard sector size of 512 bytes each.[18] Upon invocation, the BIOS first verifies the drive parameters and resets the disk system if necessary to ensure the media is accessible. It then translates the CHS address into the physical location on the disk, positioning the read/write head accordingly. For floppy disks, the operation requires all sectors to reside on the same cylinder and head to avoid repositioning, while fixed disks permit crossing track boundaries within the requested count. Data transfer occurs via DMA (Direct Memory Access) where supported, or programmed I/O as a fallback, with the BIOS handling low-level controller commands to the disk hardware. If errors arise during transfer, such as CRC mismatches, the BIOS may attempt hardware-level ECC (Error-Correcting Code) correction for floppies, reporting success only if the data is recoverable.[18][24] The buffer specified by ES:BX must reside in conventional memory below 1 MB and be aligned on a paragraph boundary to support DMA operations without overflow issues; crossing a 64 KB segment boundary during transfer will cause failure. Upon completion, the carry flag (CF) is cleared for success, with AH set to 00h and AL reflecting the actual sectors transferred (potentially fewer than requested on partial success). Errors set CF and populate AH with a status code, such as 10h for uncorrectable ECC errors or 11h for corrected ones, necessitating a follow-up status check via AH=01h.[18][24] A common example is reading the boot sector from the primary hard disk (drive 80h) at cylinder 0, head 0, sector 1:
mov ah, 02h      ; Read sectors function
mov al, 01h      ; Number of sectors: 1
mov ch, 00h      ; [Cylinder](/page/Cylinder): 0
mov cl, 01h      ; Sector: 1 (low bits), cylinder high bits: 0
mov dh, 00h      ; Head: 0
mov dl, 80h      ; Drive: first hard disk
mov bx, 7C00h    ; Buffer offset (ES assumed 0000h for [boot sector](/page/Boot_sector))
mov es, 0000h    ; Buffer segment
int 13h          ; Invoke [BIOS](/page/BIOS) interrupt
jc error_handler ; Jump if [carry flag](/page/Carry_flag) set (error)
This snippet loads the 512-byte boot sector into memory at 0000:7C00h, a standard location for bootloaders.[18] Key remarks include the requirement for a prior disk reset (AH=00h) on multi-tasking systems or after media changes to clear any pending states, and the prohibition of requests exceeding the drive's track capacity, which triggers errors like invalid command (AH=01h). The operation assumes DMA-safe buffers to prevent hardware faults, and partial transfers on error demand manual retry logic in calling code.[18][24]

Sector Write Operations

The sector write operation of the INT 13H BIOS interrupt is invoked by setting AH to 03h, which transfers a specified number of sectors from a memory buffer at ES:BX to the target disk location using cylinder-head-sector (CHS) addressing.[18] The number of sectors is given in AL (must be nonzero), the low eight bits of the cylinder in CH, the sector number (bits 0-5, 1-based) and high two bits of the cylinder (bits 6-7) in CL, the head number in DH, and the drive number in DL (00h-7Fh for floppies, 80h-FFh for hard disks).[18][25] This function supports both floppy disks and hard disks, with floppy operations potentially requiring prior configuration via AH=04h for non-standard sector sizes.[18] Before writing, the BIOS validates parameters such as drive number and sector range, checks for write protection (returning error 03h if protected), and for floppies, verifies the diskette change signal to ensure media consistency; if changed and unresettable, it fails with error 06h.[18] The data transfer then occurs to the specified CHS locations, updating the disk system status upon completion.[18] On success, the carry flag (CF) is cleared, AH is set to 00h, and AL holds the number of sectors transferred; errors set CF, place the status in AH (e.g., 10h for uncorrectable ECC/CRC error or write fault on bad sectors), and may leave AL with the sectors actually written in some implementations.[18][26] For robust usage, particularly with floppies where motor or media issues are common, a disk system reset (AH=00h) precedes the write, and status is checked afterward (AH=01h) to confirm completion without errors like 10h on defective sectors.[25] Errors often necessitate retrying after reset, as mechanical delays and media verification contribute to slower performance compared to reads.[18] The following assembly code example demonstrates writing one sector to drive 0, cylinder 0, head 0, sector 1, assuming a 512-byte buffer at segment:offset buffer_seg:buffer_off:
    mov     ax, 0       ; reset disk system
    mov     ah, 00h
    int     13h
    jc      reset_error

    mov     ax, buffer_seg
    mov     es, ax      ; set ES to buffer segment
    mov     bx, buffer_off  ; set BX to buffer offset

    mov     ah, 03h     ; write function
    mov     al, 1       ; one sector
    mov     ch, 0       ; [cylinder](/page/Cylinder) 0 (low bits)
    mov     cl, 1       ; sector 1 (bits 0-5), cylinder high=0
    mov     dh, 0       ; head 0
    mov     dl, 0       ; drive 0 (floppy A:)
    int     13h
    jc      write_error

    mov     ah, 01h     ; get status
    int     13h
    jc      status_error ; AH has [error code](/page/Error_code), e.g., 10h for [bad sector](/page/Bad_sector)

    ; success: AL has sectors written (1)
write_error:
    ; [handle](/page/Handle) error, AH=03h (protected) or 10h ([bad sector](/page/Bad_sector)), etc.
reset_error:
    ; [handle](/page/Handle) reset failure
status_error:
    ; [handle](/page/Handle) post-write status failure
[26][25]

Track and Drive Management

Sector Verification

The sector verification function of INT 13H, invoked with AH=04h, performs a non-destructive integrity check on specified disk sectors without transferring data to system memory. This operation verifies the structural validity of the sectors using error-correcting codes, ensuring that the data fields remain consistent as recorded on the media. On fixed disks (hard drives), it employs Error Correction Code (ECC) mechanisms to detect and potentially correct errors in data fields (up to 5 bits per sector), while Cyclic Redundancy Check (CRC) is applied to ID fields using the polynomial X16+X12+X5+1X^{16} + X^{12} + X^5 + 1. For floppy disks, the verification primarily relies on CRC checks to confirm sector headers and data integrity without full data comparison to memory.[27][28] Input parameters for the verify function mirror those of the sector read operation (AH=02h), utilizing Cylinder-Head-Sector (CHS) addressing: AL specifies the number of sectors to verify (1 to 128, or up to 256 if AL=00h on some fixed disk implementations); CH holds the low 8 bits of the cylinder number (0-1023, with higher bits in CL bits 6-7 for extended support); CL contains the sector number in bits 0-5 (starting from 1) and the high 2 bits of the cylinder; DH indicates the head number (0-15); and DL denotes the drive (00h-7Fh for floppies, 80h-FFh for hard disks, with bit 7 set for the latter). Unlike read operations, no data buffer address (ES:BX) is required for data transfer, though early BIOS versions (pre-November 1985) may expect it to be set for compatibility. Upon invocation, the BIOS positions the read/write head and performs the check, advancing sequentially across sectors within the same cylinder and head for efficiency.[27][28] This function is particularly suited for post-write confirmation to validate that sectors were recorded correctly without the overhead of reloading data into memory, and for media testing during disk diagnostics to assess physical integrity across multiple sectors. It enables efficient verification of large contiguous areas, such as entire tracks, by specifying higher sector counts in AL, reducing the need for repeated interrupts. On floppy disks, retries (up to three) are recommended before a disk reset (AH=00h) to account for motor spin-up delays or transient errors like media changes.[27][28] Return values include the carry flag (CF=0 for success, CF=1 for error) and AH holding the status code (00h for successful verification; non-zero values indicate failures, such as 11h for uncorrectable or recoverable ECC errors, or 10h for ID not found). The same error codes as sector read operations are returned, allowing consistent handling across disk functions. However, verification is less reliable on hard disks compared to floppy media, as ECC corrections may mask subtle data inconsistencies without full read validation, and persistent errors may necessitate a drive reset.[27][28]

Track Formatting

The track formatting functions within INT 13h provide low-level mechanisms for initializing disk media by writing sector headers and gaps, essential for preparing floppy disks or hard disk tracks prior to data storage.[29] These operations require direct hardware access and are inherently destructive, potentially leading to complete data loss if executed on non-empty media, particularly hard disks where controller-specific behaviors vary.[26] Sector sizes supported range from 128 to 1024 bytes, determined by the format buffer contents, while drive parameters such as maximum sectors per track influence the operation's scope.[29] The AH=05h function formats a single track on the specified head and cylinder, applicable to both floppy and fixed disks. For floppy disks, input registers include AH=05h, CH for the track number, DH for the head (0 or 1), DL for the drive (0x00 for A:, 0x01 for B:), and ES:BX pointing to an array of 4-byte sector ID entries per sector, where each entry specifies the track number (offset 0), head number (offset 1), starting sector number (offset 2), and sector length code (offset 3: 0x00 for 128 bytes, 0x01 for 256 bytes, 0x02 for 512 bytes, 0x03 for 1024 bytes); AL holds the number of sectors to format, derived from the INT 1E parameter table.[29] On successful completion, the carry flag is cleared and AH=00h; errors set the carry flag with AH indicating codes such as 0x01 (invalid function) or 0x04 (sector not found).[26] For fixed disks, particularly XT-type controllers, AL specifies the interleave value, CL bits 6-7 hold high cylinder bits (with CH for low bits), and ES:BX points to a 512-byte buffer where the first 2 × (sectors per track) bytes define sector types (e.g., 0x00 for good sectors) and numbers, enabling gap and density control via controller commands.[29] This function demands prior controller reset (AH=00h) and is unsupported on some modern emulators without specific handling.[29] AH=06h performs a bad sector format on fixed disks, similar to AH=05h but with provisions for defect management by flagging and skipping problematic sectors during the process. Input parameters mirror AH=05h for fixed disks, with AL as the interleave value, CH/CL/DH/DL specifying the cylinder, sector, head, and drive, and ES:BX to a 512-byte buffer containing an interleave table that identifies bad sectors (e.g., via non-zero flags) to be marked or reassigned without writing data headers.[26] Primarily used on IBM PC XT and Portable systems, it sets bad sector flags in the controller's defect list, ensuring reliable media preparation; output follows the standard carry flag and AH status, with errors like 0x80 (DMA boundary error) common on misaligned buffers.[30] This operation is restricted to hard disks and requires low-level controller access, often preceded by a diagnostic (AH=04h on some systems), highlighting its role in maintenance rather than routine formatting.[26] The AH=07h function enables multi-track formatting on fixed disks (XT/Portable), formatting from the given track onward across the drive, using AL for interleave, the same CH/CL/DH/DL setup, and ES:BX for the 512-byte buffer to handle extended geometry.[31] Success clears the carry flag with AH=00h, while failures return error codes via AH, such as 0x02 (address mark not found), and this function is dangerous without backups due to its potential to overwrite entire drive areas.[26] Overall, these functions underscore the need for precise buffer preparation and error checking to avoid media corruption.[29]

Drive Parameter Retrieval

Drive parameter retrieval in INT 13H encompasses BIOS functions that query or configure essential characteristics of disk drives, such as geometry and type, enabling software to adapt operations to hardware constraints. These functions are foundational for low-level disk management in x86 systems, particularly in early IBM PC-compatible architectures.[32] The primary function for querying basic drive parameters is AH=08h, which returns the maximum cylinder, head, and sector counts for a specified drive, along with the total number of drives supported by the system. To invoke it, AH is set to 08h, DL specifies the drive number (with bit 7 set for hard disks), and ES:DI is typically 0000h:0000h to mitigate BIOS bugs. On success (CF clear), AH=00h, CH holds the low 8 bits of the maximum cylinder number, CL's low 6 bits (bits 0-5) indicate the maximum sectors per track, CL's high 2 bits (bits 6-7) provide the upper bits of the maximum cylinder, DH gives the maximum head number (last head is DH+1), and DL reports the total number of drives. For floppy drives on AT/PS/2 systems, BL indicates the drive type (e.g., 01h for 360 KB 2D), and ES:DI points to an 11-byte parameter table; however, this table is not returned for hard disks in standard implementations. This function is supported on PC, XT286, PS/2, ESDI, and SCSI systems but may return success erroneously for invalid drives, necessitating verification against the value in DL. Notably, the 10-bit cylinder encoding (8 from CH + 2 from CL) limits the reported maximum to 1024 cylinders, a constraint that historically influenced partitioning tools like FDISK to cap usable space accordingly, even on larger drives.[32][32] AH=09h serves to initialize the hard disk controller with specific drive characteristics, effectively setting type flags for a drive pair (primary and secondary). It is invoked with AH=09h and DL indicating the drive (80h for the first hard disk, 81h for the second). On success (CF clear), AH=00h; otherwise, CF is set and AH holds the error code. On PC/XT systems, it uses the parameter table at interrupt vector 41h; on AT and later systems (including PS/2), it references vector 41h for the first drive and 46h for the second, allowing configuration based on CMOS or switch settings. This function is rarely used in modern contexts due to its dependency on fixed hardware parameters and potential for disrupting drive operation if misapplied, but it was critical for early hard disk setup in AT-style BIOSes.[33][33] For more comprehensive retrieval, the IBM/MS INT 13H extensions introduce AH=48h, which populates a buffer with detailed physical drive parameters, including geometry and capacity, surpassing the limitations of AH=08h. Input requires AH=48h, DL as the drive number (80h-FFh), and DS:SI pointing to a buffer (minimum size 1Ah for version 1.x, up to 42h for EDD 3.0). On success (CF clear, AH=00h), the buffer is filled: offset 00h (WORD) returns the actual data size; 02h (WORD) flags (e.g., bit 0 for removable media); 04h-0Bh (DWORDs) for physical cylinders, heads, and sectors per track; 0Ch-13h (QWORD) for total sectors; 14h-15h (WORD) for bytes per sector (typically 512); and later offsets (from 16h in v1.x) for EDD parameters or device path information in v3.0 (e.g., host bus like "PCI", interface type like "ATA"). If the input buffer size is smaller than required, partial data is returned, omitting advanced fields like device path (requiring at least 1Eh bytes for v3.0). This function, part of the extensions detected via AH=41h, provides essential context for large drives and is prioritized for applications needing accurate capacity and geometry beyond 1024 cylinders.[34][34]

Extensions and Advanced Features

Extension Detection

The extension detection for INT 13H is performed using subfunction AH=41h, which allows software to query whether the BIOS supports enhanced disk services beyond the legacy CHS addressing limitations. This call verifies the presence of extensions that enable Logical Block Addressing (LBA) and other advanced features for accessing larger storage devices. To invoke it, the caller sets AH to 41h, BX to the magic value 55AAh as a signature, and DL to the target drive number (80h for the first hard disk, up to FFh for additional drives). Upon execution via interrupt 13h, the BIOS checks for compatibility and responds accordingly.[35][36] If extensions are supported, the carry flag (CF) is cleared, BX is returned as AA55h to confirm the signature match, and CL provides a bitmap of supported API subsets: bit 0 set indicates device access via packet structures (essential for extended read/write operations), bit 1 set denotes support for drive locking and ejecting (useful for removable media), and bit 2 set signals Enhanced Disk Drive (EDD) capabilities for versions 3.0 and later. CH is reserved and set to 0. For extension versions 2.0 and higher, DH holds the major version number (e.g., 20h for 2.0) and DL the minor version number, while earlier versions like 1.0 do not populate these fields. If unsupported, CF is set and AH returns 01h indicating an invalid function.[35][36] Introduced in 1992 by IBM and Microsoft, with subsequent adoption and enhancements by Phoenix Technologies and other BIOS vendors such as Award, version 1.0 of the extensions provided basic LBA support (up to 28 bits, addressing approximately 128 GB), addressing the 8.4 GB limit of traditional CHS geometry (1024 cylinders × 256 heads × 63 sectors × 512 bytes). Subsequent versions, such as 2.0 and the EDD specification starting at 3.0, extended this to 64-bit addressing, supporting up to 9.4 zettabytes theoretically, which became crucial for drives exceeding 8 GB in capacity during the 1990s.[37][36] In practice, operating systems like early Windows NT and Linux kernels invoke this detection routine during boot to probe for extension availability before attempting advanced disk operations; if unsupported, they fall back to legacy CHS or basic LBA modes to ensure compatibility with older hardware. This mechanism was pivotal in transitioning from the 504 MB barrier of pre-LBA BIOSes to supporting multi-gigabyte drives without requiring custom drivers at the OS level.[37][36]

Extended Sector Access

The extended sector access functions in INT 13H provide advanced mechanisms for reading and writing sectors on storage devices, surpassing the limitations of traditional CHS addressing by incorporating Logical Block Addressing (LBA) and packet-based transfers. These functions are part of the Enhanced Disk Drive (EDD) extensions, enabling support for larger drives and more efficient data operations on compatible BIOS implementations.[36] The extended read function (AH=42h) transfers one or more sectors from the specified drive to system memory using a Disk Address Packet (DAP) structure pointed to by DS:SI. The drive is selected via DL, with the packet specifying the transfer buffer, sector count, and starting LBA. Upon success, the carry flag is cleared and AH=00h; on error, the carry flag is set and AH contains the error code, with the DAP's block count updated to reflect sectors successfully transferred before the failure. This function supports LBA addressing, where the BIOS translates the LBA to CHS if the device lacks native LBA support, thereby bypassing the 504 MB CHS limit imposed by 10-bit cylinder addressing in legacy operations.[38][36] The extended write function (AH=43h) performs a similar transfer but from memory to the drive, with AL = 00h for write without verification (standard); some BIOS implementations support AL = 02h for write with verification, returning AH=01h if unsupported. Input parameters mirror those of the read function, including the DAP at DS:SI and drive in DL. Success clears the carry flag with AH=00h; errors set the carry flag and AH to the error code, updating the DAP block count accordingly. Like the read function, it leverages LBA for compatibility with drives exceeding CHS constraints.[36][38] The read long function (AH=0Ah), a legacy extension available on AT-class systems and later, reads a single sector using CHS addressing (CH for cylinder, DH for head, CL for sector, DL=drive). The sector count in AL must be 1, with the transfer buffer at ES:BX. It returns 513 bytes per sector: 512 bytes of user data followed by a single ECC byte for error correction. This differs from standard reads by including the ECC data, aiding in error detection, though it remains limited to one sector and CHS mode without LBA support.[39] The DAP structure, located at DS:SI for extended read and write operations, defines the transfer parameters and varies by packet size to accommodate different addressing modes. For basic LBA28 support, the packet size is 10h bytes; for LBA48 and extended memory addressing (EDD-3.0), it is 18h bytes. The structure supports up to 127 sectors per transfer in standard implementations, though the field allows for larger counts in extended configurations.[36][38]
OffsetSizeDescription
00hBYTEPacket size (10h for LBA28, 18h for LBA48/EDD-3.0)
01hBYTEReserved (must be 00h)
02hWORDNumber of blocks to transfer (1-127 typically, up to 0xFFFF in extended mode)
04hDWORD32-bit transfer buffer address (offset low word, segment high word)
08hQWORDStarting 64-bit LBA (low 32 bits for LBA28, low 48 bits for LBA48; BIOS converts to CHS if needed)
10hQWORD64-bit flat transfer buffer address (used if offset 04h is FFFF:FFFFh; only for packet size 18h)
These functions require prior detection of EDD support via AH=41h to ensure compatibility. Less common variants include long write (AH=0Bh, similar to AH=0Ah but for writing 513-byte sectors with ECC) and specialized long verify operations, which are not universally implemented across BIOS vendors.[36][39]

Emulation and Parameter Extensions

The INT 13h function AH=48h, known as Extended Read Drive Parameters, enables retrieval of detailed physical parameters for a storage device, extending beyond traditional 16-bit or 24-bit addressing limitations. This function requires the caller to provide the drive number in DL and the address of a result buffer (minimum 0x1E or 30 bytes) in DS:SI, with the buffer size specified in the first word (e.g., 0x1E for basic EDD parameters, 0x30 for DPI inclusion). Upon successful execution (carry flag clear, AH=0), the buffer populates with key data including the number of physical cylinders, heads, and sectors per track (each as 32-bit values), the total number of sectors as a 64-bit LBA value supporting up to 2^64 addressable sectors, and the bytes per sector (typically 512 but extensible to larger sizes). If the buffer is at least 0x30 bytes, it also includes a pointer to the Device Path Information (DPI) structure, which details the host bus type (e.g., ISA, PCI), interface type (e.g., ATA, SCSI), and path information such as I/O ports, IRQ, and DMA settings. This DPI extension, introduced in EDD 3.0, facilitates precise device identification and configuration in multi-device environments.[36] Emulation modes in the INT 13h extensions allow BIOS to present non-standard devices, such as CD-ROM drives, as familiar floppy or hard disk types to legacy software. Emulation modes for devices like CD-ROMs (e.g., via the El Torito specification) allow the BIOS to present the media as a floppy or hard disk to legacy software. The active emulation type is reflected in drive parameters obtained via AH=08h or AH=48h, supporting floppy (1.2 MB, 1.44 MB, or 2.88 MB), hard disk, or no-emulation modes for booting without dedicated drivers.[40] These extensions address critical limitations in older INT 13h functions, such as AH=08h, by providing 64-bit LBA support to detect and access drives exceeding the 137 GB barrier imposed by 28-bit addressing (approximately 2^28 sectors at 512 bytes each). This proves essential for OS installers and bootloaders targeting large-capacity hard disks, where traditional CHS geometry translations fail. EDD 3.0, released in 1997, further enhances this by incorporating host bus and interface details in the DPI, enabling better support for diverse peripherals like SCSI and ATAPI CD-ROMs through unified INT 13h access, while maintaining backward compatibility.[36]

References

User Avatar
No comments yet.