DOS INT 25h and 26h: Absolute Sector I/O Without Filesystem Safety Nets
Understand DOS absolute disk reads and writes, logical drive-relative sectors, extended descriptors, stack quirks, cache hazards, and safe image-based testing.
DOS INT 25h and INT 26h provide absolute disk read and write operations against a DOS logical drive. They are not BIOS INT 13h: the caller addresses a DOS drive number and logical sectors, while DOS resolves that drive through its configured block-device and partition state. These calls bypass normal file allocation, directory updates, and application-level safeguards, which makes them useful for carefully designed imaging or repair tools - and dangerous for casual file access.
The word “absolute” is relative to the selected logical DOS volume, not necessarily the physical disk’s first sector. This distinction is essential on partitioned media. A sector number copied from a whole-disk image or BIOS utility may refer to a different location than the same number passed to DOS. Before any write, establish the exact drive mapping, sector-size assumptions, active cache/device stack, and a tested recovery image.
What these calls do - and do not do
INT 25h reads sectors and INT 26h writes them. Unlike INT 21h file calls, they do not walk paths, honor file sharing, allocate clusters, update directory entries, or preserve file-system invariants for the caller. A writer that changes a FAT or directory sector must understand every related copy, allocation bit, checksum, and cache entry that can be affected. A successful sector transfer is not the same as a successful filesystem transaction.
The BIOS interfaces described in the INT 13h guide use firmware drive numbers and CHS or BIOS LBA conventions. DOS absolute I/O instead uses the DOS logical drive numbering convention (typically A: as drive number zero, B: as one, and so on) and sectors visible through the DOS block layer. Redirectors and drivers can make the visible drive differ from a physical disk. Do not infer a physical device or partition offset from a letter alone.
Legacy request form
The classic request supplies the DOS drive in AL, a sector count in CX, the starting logical sector in DX, and a transfer buffer at DS:BX. The basic form uses a 16-bit sector number and count. The buffer must remain readable or writable for the entire transfer and must satisfy the constraints of the DOS and device stack. Do not hard-code 512 bytes as a universal sector size unless the target volume and device path have been verified to use it.
In the legacy interface, the interrupt returns with an unusual stack convention: the saved flag word remains on the caller’s stack. Test the returned carry condition before cleaning that stack word, and clean it on both the success and error paths. Otherwise each call can leave the stack two bytes out of balance, eventually corrupting a return address or local variables.
; Example shape only: DS:BX -> a correctly sized buffer,
; AL = DOS drive index, CX = sectors, DX = starting logical sector.
int 25h
jc read_failed ; inspect returned CF before stack cleanup
add sp, 2 ; discard INT 25h's saved flag word
jmp read_complete
read_failed:
add sp, 2 ; cleanup is required on the error path too
; AX contains DOS error information for diagnosis
The example is 16-bit assembly pseudocode and omits segment setup, buffer sizing, register preservation, and application-specific logging. Test the target kernel’s exact convention in a disposable image. The FreeDOS entry wrapper explicitly preserves the original flag image on the stack for MS-DOS compatibility; do not “fix” that behavior by assuming an ordinary IRET frame.
Extended sector descriptors
The 16-bit starting-sector field is inadequate for larger volumes. A widely used extended form sets CX=FFFFh and points DS:BX to a descriptor containing a 32-bit logical block number, a 16-bit sector count, and a far pointer to the data buffer. The FreeDOS kernel’s implementation uses that layout when it sees the marker count. Confirm the descriptor packing and pointer representation for the precise DOS specification and compiler ABI being targeted; a C far pointer’s offset/segment representation must match the bytes expected by the assembly interface.
This marker means the count comes from the descriptor; it does not mean the operation transfers 65,535 sectors. Validate additions and multiplication before allocating the buffer, ensure the final sector lies within the intended logical volume, and reject a request that wraps the 32-bit LBA or exceeds the media. Use a structure with explicit-width fields and a known 16-bit memory model rather than relying on host-side structure packing.
Errors, partial work, and drive state
On an invalid or unavailable logical drive, DOS can fail before issuing device I/O. Device errors may include not-ready, write-protect, or other block-layer failures. Save the returned status immediately and report the operation’s drive, LBA, count, and direction. A count-based request can fail after earlier work or interact with a driver that handles sectors in smaller chunks; design recovery around verified on-disk state, not an assumption that the entire request was atomic.
The current FreeDOS kernel has implementation-specific behavior worth respecting: its INT 25h/26h handler validates the DOS drive and obtains its DPB; its FAT32 path rejects non-boot-sector absolute access in the code path guarded by its FAT32 build logic. That is evidence about the cited kernel source, not a universal rule for every FreeDOS build, Windows 95 DOS box, or other DOS-compatible system. Probe and test the exact target instead of promising that a raw call can reach every sector on every volume.
Cache coherence and metadata risk
A direct write can conflict with DOS buffers that contain dirty or previously read metadata. FreeDOS’s handler invalidates relevant cached state around absolute writes, but that is a kernel implementation measure, not journaling or transaction support. Another cache TSR, block driver, redirector, or emulator may add additional state. A raw reader can observe stale data if another layer has buffered writes; a raw writer can make a mounted filesystem’s in-memory view disagree with disk.
Never use absolute writes against a mounted volume while DOS or an application can still mutate it. Quiesce the volume, stop programs and TSR work that may touch it, and prefer operating on a complete image while the guest is shut down. If the task truly requires modifying a live filesystem, use the filesystem’s supported APIs or a tool that understands the on-disk format and can establish exclusive access. Do not assume that calling INT 21h/AH=0Dh or COMMIT converts a raw sector update into a safe transaction.
Image-based validation procedure
- Create a byte-for-byte copy of a disposable disk image and record its checksum. Keep the original read-only.
- Identify which DOS drive maps to the target volume, its partition start, sector size, total logical sectors, and whether the target call uses the legacy or extended descriptor.
- Read a harmless sector from a known test volume and compare the bytes with an independently parsed image offset. Confirm logical-sector addressing before attempting any write.
- Write only to an allocated scratch image or test volume. Change a known nonessential sector, read it back through both the same API and the offline image, then restore the original bytes.
- Run filesystem checks against the scratch copy after the test. Compare directory listings and checksums, then discard the image and repeat from a clean copy.
- Exercise invalid drive, out-of-range LBA, write-protected media, and injected I/O error cases. Confirm the caller cleans the stack on all paths and reports the DOS status.
The independent image comparison is important: a second INT 25h read can repeat the same cached or translated view and is not proof that the physical image changed. Likewise, a VM snapshot must be flushed and closed through the hypervisor’s supported procedure before host-side inspection.
Choosing the right layer
Use DOS file APIs for files and directories. Use INT 13h only when firmware-level disk access is actually required and the program correctly handles BIOS drive numbering, geometry translation, and extensions. Use INT 25h/26h only when the program needs DOS logical-sector access and owns the risks of bypassing filesystem operations. If the requirement is merely to make a sector copy for recovery, an offline host-side image tool is often easier to audit and less likely to damage a running volume.
Absolute I/O becomes safe only when the address space is unambiguous, the volume is quiescent, the transfer bounds are checked, the calling convention is handled exactly, and a recoverable image exists. The interface offers control, not protection; every invariant the filesystem normally maintains becomes the caller’s responsibility.
Related:
- FreeDOS and BIOS INT 13h: CHS, LBA Extensions, and Safe Disk Access
- Diagnosing FAT Corruption on FreeDOS Without Making Recovery Worse
Sources: