Compatibility: 2.0+
Expects:       (on drives < 32M and DOS < 4.0)
AL    drive number (0=A, 1=B, etc.)
CX    count of sectors to read
DX    beginning sector (DOS logical sector number)
DS:BX transfer address (destination or source buffer)

Expects:       (on drives > 32M and DOS >= 4.0)
AL    drive number (0=A, 1=B, etc.)
CX    ffffH
DX    beginning sector (DOS logical sector number)
DS:BX address of a AbsDiskIORec structure.
                                                                  
Returns: AX    special error code (see below) if CF is set to CY

IMPORTANT! This interrupt leaves one word of data on the
stack.  You must pop it off (see below).
                                                                  
Info: These DOS services provide direct access to any disk sector
available through DOS and installed block device drivers.

   INT 25H reads sectors
   INT 26H writes sectors

CX,DX and...
DS:BX Prior to DOS 4.0, CX specified the sector count and DS:BX pointed
to the transfer buffer.  With DOS 4.0+, a mechanism was added to
allow access to sector numbers higher than 65535 (the largest
number than can fit in the 16-bit CX register).  The layout of
the input parameters changes, depending upon the value in CX.  In
summary:

When CX is NOT equal to ffffH, it specifies now many sectors you
want to read or write, DX indicates the starting sector, and
DS:BX points the data buffer.  Note that values larger than about
1024 (400H) are as much as can be read or written, given the
constraints of conventional  memory.

When CX IS equal to ffffH, you must set DS:BX to point to an
AbsDiskIORec structure which identifies the starting sector,
desired number of sectors, and the location of the memory buffer.
DX is ignored.

Note: Most disks have a sector size of 512 bytes (–ĽK), but you
should not assume that size when allocating the transfer
buffer.  Use fn 1cH or 32H to find the true sector size.

DX (or AbsDiskIORec.lStartSect, when CX=ffffH) specifies the
starting sector, using a DOS logical sector number.

DOS logical sector 0 is the DOS boot sector (the first sector in
the DOS partition).  Logical sector numbers increment first
through each sector on a cylinder, then through each head, and
finally through each cylinder on the drive (the exact layout is
rarely important--just know that you can access any sector from 0
through n, where n can be derived via fn 1cH or 32H).

Notice that the Master Boot Record and any other sectors outside
of the DOS partition are not available through this service.
BIOS INT 13H provides complete access to all parts of a hard
disk.  DOS 3.2+ device drivers provide direct access via fns
440dH 41H (write track) and 440dH 61H (read track).

See File Allocation Table for an overview of how DOS maps logical
sector numbers to physical head/track/sector numbers and how to
convert a cluster number into a logical sector number.

  Pop the Stack!  
INT 25H and INT 26H both leave one 16-bit word of data on the stack (it is
the Flags register that would have been used in an IRET, but was left
there when DOS use a FAR RET to get back to your program.  An IRET was not
used since that would overwrite the value in CF (used to indicate errors).

Be sure to pop one word off of the stack upon return.  See the example,
below.

  Error Codes  
Errors occurring during INT 25H/26H are NOT handled by the INT 24H
critical error handler.  Upon return from INT 25H or INT 26H, the Carry
Flag set (CF=CY=1) when a error occurred.  When CF is set:

AL is a device error code (00H-0cH). It is the same as bits 0-7 of
DI upon INT 24H.

Add 13H to this value (yielding 13H-1fH) and it will match one of
the errors listed under DOS Error Codes.

AH  is one of these values:
80H = attachment failed to respond
40H = disk seek operation failed
08H = Bad CRC on diskette read
04H = requested sector not found
03H = Attempted write on write-protected diskette
02H = some error other than these listed above

  Examples  
Sample use of INT 25H to read the boot sector of a <32 MB diskette:

mov   al,0      ;select drive A
mov   dx,0      ;select the DOS Boot Sector
mov   cx,1      ;read one sector ..
lea   bx,myBuf  ; ... into buffer at DS:BX
INT   25H
pop   dx        ;discard the extra word on the stack
jnc   noErr
...etc...       ;code to handle any disk error (code in AX)
noErr: ...etc...       ;code continues when no error

Sample use of INT 25H to read 20 sectors starting at logical sector 80,000
of a >32 MB hard disk partition:

mov   al,0                         ;select drive C
lea   bx,  ioRec                   ;set up the local AbsDiskIORec
mov   word ptr [bx],  14464        ;large sector number, low word
mov   word ptr [bx+2],1            ;large sector number, high word
mov   word ptr [bx+4],20           ;read 20 sectors
mov   word ptr [bx+6],offset myBuf ;set buffer addr offset
mov   word ptr [bx+8],seg myBuf    ;                segment
INT   25H
pop   dx        ;discard the extra word on the stack
jnc   noErr
...etc...

  Diskette Duplication  
DOS technical documents recommend avoiding INT 25H/26H whenever possible.
For instance, to duplicate diskettes (as with the DOS Diskcopy command),
it is better to use IOCTL Functions:

Fn 440dH 61H (read track)
Fn 440dH 42H (format and verify track)
Fn 440dH 41H (write track)

Of course, that only works if you are certain to be running under
DOS 3.2 or later and the device driver supports IOCTL services.

See Also: INT 13H (ROM-BIOS disk access)
fn 440dH 41H (write track)
fn 440dH 61H (read track)
- -

INT 25H/26H: Absolute Disk Read/Write