Skip to content
FreeDOSDeep Dive Published Updated 6 min readViews unavailable

BIOS INT 15h AH=88h: The Legacy Extended-Memory Count

Interpret INT 15h AH=88h as a bounded BIOS memory count, check carry and support limits, and keep it separate from E820 and XMS allocation.

BIOS INT 15h, function AH=88h, is a legacy query for extended memory. On the IBM AT and certain later IBM-compatible systems described in the BIOS reference, it reports a count of contiguous 1 KiB blocks beginning at physical address 100000h (1 MiB), as determined by POST. It is useful when maintaining old software that expects this interface, but it is not a modern physical-memory map and it does not reserve or allocate any RAM.

The critical distinction is between what firmware reports, what the memory map says, and what a DOS memory manager has actually made available to a program. A returned count is a compatibility datum from a particular BIOS path. Do not add it to conventional memory and announce that the result is freely writable or available to your application.

Calling convention and units

The basic call sets AH=88h and invokes INT 15h. On a documented supported BIOS, the returned AX is the number of contiguous 1 KiB blocks above 1 MiB. Carry clear indicates a successful result; carry set indicates an unsupported or failed request. IBM’s reference documents older systems returning error codes such as 80h or 86h in AH, depending on machine family. Save the status immediately and do not read AX as a count after carry reports failure.

mov     ah, 88h
int     15h
jc      extended_memory_unavailable
; AX now contains the count of 1 KiB blocks for this BIOS interface.
mov     [blocks_1k], ax

The code is a register-level illustration. It does not test that the BIOS follows the IBM convention or make a protected-mode BIOS call safe from a DOS extender. A DPMI client must use the host’s real-mode interface or its documented memory API rather than issuing a raw real-mode BIOS interrupt from protected mode.

To convert the value to bytes, multiply the block count by 1024 using a type wide enough for the result. Preserve the original 16-bit count for diagnostics and avoid overflow in a narrow intermediate. The units are not bytes, not 64 KiB paragraphs, and not megabytes. A 16-bit return register also places an interface-specific ceiling on the representable count; do not infer that the reported value covers all installed memory on a large modern machine.

Contiguous count is not a map

The word “contiguous” is essential. AH=88h gives one count beginning at a specified base, not a list of usable and reserved ranges. It cannot describe holes, address aliases, adapter windows, firmware-reserved regions, high memory remapping, or different memory types. It also does not express why a region is unavailable.

The count is based on POST’s view and the BIOS implementation. A value can be lower than installed physical RAM because the old interface has limited scope or firmware choices. A value can be stale or misleading if a clone implements only a compatibility approximation. Use E820 when the boot environment needs a typed memory map, and still pass that information through the memory manager that owns allocation. E820 itself is a map, not a license to overwrite every range labeled usable after other software has started.

It does not grant DOS memory

DOS conventional memory, XMS, EMS, UMBs, and DPMI memory are separate allocation models. Calling AH=88h does not return an XMS handle, map an EMS page, enable A20, establish a selector, or protect another program’s pages. A program that writes to 100000h + offset merely because a BIOS count was nonzero can corrupt the machine or fail to access memory at all.

If an application needs extended memory under DOS, it should negotiate with the installed XMS manager. An EMS program should use the EMS manager’s page-frame and handle interface. A protected-mode client should use DPMI. Those providers know the ownership and mapping state for the environment. AH=88h is suitable for compatibility reporting or boot-time diagnostics that explicitly state its limited meaning.

Do not try to “fix” a low AH=88h result by writing a larger value into the BIOS Data Area. That changes a report, not the memory map or allocation authority. It can encourage later code to overwrite firmware data, an option ROM, a memory hole, or a region reserved by a memory manager.

Compare interfaces without conflating results

A diagnostic can present multiple values side by side: INT 12h conventional memory, INT 15h AH=88h extended-memory count, E820 ranges when available, and the XMS provider’s reported free memory. Label each with its source and unit. They answer different questions and may legitimately disagree.

For example, the BIOS count may describe memory beginning at 1 MiB, while XMS free memory can be lower because a manager or driver has already allocated blocks. E820 may report reserved regions beyond the contiguous range that AH=88h can represent. An E820 map entry can indicate installed RAM that the currently loaded DOS profile does not expose through XMS. None of these observations alone proves a hardware fault.

Treat the reported count as a snapshot of one firmware initialization path. If a boot manager, option ROM, or emulator changes how memory is presented, the numbers can differ without any DIMM failure. Compare the firmware identity and boot profile before escalating a discrepancy. Never combine the count with a high-memory value from another API unless the ranges and units are proven disjoint; otherwise the report may double-count address space or include reserved memory.

Failure and compatibility handling

Check carry before consuming AX. Preserve AH on failure, record the BIOS identity and emulator profile, and report “unsupported” separately from “zero blocks.” A clone may return nonstandard values; if the result is implausible, compare it with the matching machine reference and independent memory-manager information rather than silently correcting it.

The function is an old real-mode BIOS service. It may not exist in early PCs, and a virtual environment can expose only a compatibility implementation. An application that cannot operate safely without a high-memory map should not silently fall back to this function. It should require the appropriate provider or fail with a clear explanation.

Do not run an address probe that writes test patterns to memory simply to validate this count. Memory tests belong in a controlled boot stage before DOS, and they must account for parity, caching, chipset mappings, and reserved ranges. A production DOS diagnostic should be read-only and should not touch physical memory beyond a documented API.

Acceptance checks

Test one BIOS known to support the function and one known to return unsupported status. Confirm that carry is checked before the count is used, errors are labeled with the returned status, conversion arithmetic does not overflow, and output says “contiguous 1 KiB blocks above 1 MiB reported by BIOS,” not “free RAM.” Where E820 and XMS are present, display them as independent interfaces with their own units and ownership.

Record the exact machine or VM, BIOS version, returned AX and AH, carry state, conventional-memory result, E820 availability, and XMS provider response. Re-run after changing memory-manager configuration to demonstrate that an AH=88h result is not an allocation result. This environment has no DOS BIOS on which to execute the call; the snippet is a sourced calling-convention example, not a runtime test.

AH=88h remains useful for legacy compatibility and historical firmware inspection. Its output is one BIOS-reported contiguous count, not a complete map and not application-owned memory. Keep the provenance and units explicit, then use XMS, EMS, DPMI, or another documented memory owner for actual allocation.

Related:

Sources:

Comments