2026-06-15
The asker has two seemingly equivalent calls to INT 13h (BIOS disk service, AH=2 = read sectors). Both target offset 0 in a segment, but only the second fails with AH=09h. The difference is the destination segment: ES=0x1000 works, ES=0x1ff0 fails — even though the offset is the same and only one sector (512 bytes) is being read.
Why this is interesting: the error code is the giveaway, but it's only obvious if you know your legacy hardware. AH=09h from INT 13h is "DMA boundary error: attempt to DMA across 64K boundary". This isn't a BIOS quirk — it's a hardware limitation of the original IBM PC's Intel 8237 DMA controller, which uses a 16-bit address register plus a separate 8-bit page register. The controller can't increment from 0xFFFF to 0x10000; it would just wrap inside the current 64KB page.
The arithmetic:
ES:BX = 0x1000:0x0000 → linear address 0x10000. One sector (512 bytes) lands in 0x10000–0x101FF. All inside the 64KB page 0x10000–0x1FFFF. ✓ES:BX = 0x1ff0:0x0000 → linear address 0x1FF00. One sector lands in 0x1FF00–0x200FF. This straddles the boundary at 0x20000. ✗The DMA controller physically cannot do that transfer, so the BIOS floppy driver returns AH=09h before touching the disk.
Can you read to physical 0x20000? Yes — but the buffer has to be entirely within a single 64KB-aligned page. Pick an ES:BX whose linear address starts at 0x20000 (or any address such that start and start+count−1 share the same top 8 bits of the 20-bit physical address). Examples that work:
ES=0x2000, BX=0x0000 → 0x20000–0x201FF, inside page 0x20000–0x2FFFF. ✓ES=0x1000, BX=0xF000 → 0x1F000–0x1F1FF, inside page 0x10000–0x1FFFF. ✓Gotchas:
movsw the data to its final destination — this also sidesteps the issue for hard disks on some BIOSes that share the same limitation for ISA-era DMA paths.