How MS-DOS Allocates Memory via INT 21h Function 48h

In MS-DOS 6.22, memory allocation through Interrupt 21h, Function 48h provides dynamic conventional (and optionally upper) memory management by traversing a linked chain of Memory Control Blocks (MCBs). When an application requests a block of memory, the operating system evaluates available memory pools against the requested size in paragraphs, applies the active allocation strategy, updates or splits the corresponding MCB, and returns the segment address of the allocated space or an error code indicating insufficient memory.

Register Interface and Parameters

To invoke the memory allocation function, a program sets the CPU registers as follows:

  • AH: 48h (the DOS function dispatcher index)
  • BX: The number of 16-byte paragraphs requested

Upon return, the CPU Carry Flag (CF) denotes success or failure:

  • Success (CF = 0): AX contains the initial segment base address of the allocated memory block (the first usable paragraph immediately following its MCB).
  • Failure (CF = 1): AX contains an error code (typically 08h for "Insufficient Memory" or 07h for "Memory Control Blocks Destroyed"), and BX returns the size in paragraphs of the largest contiguous free block found.

Memory Control Block (MCB) Structure

MS-DOS manages memory as a singly linked list of arenas. Every block of memory is preceded by a 16-byte (one paragraph) header known as an MCB or Arena Header.

An MCB contains the following structure:

  • Offset 00h (1 byte): Block type identifier. ASCII 'M' (4Dh) indicates an intermediate block; ASCII 'Z' (5Ah) indicates the final block in the chain.
  • Offset 01h–02h (Word): Owner Process Segment Prefix (PSP). A value of 0000h indicates that the block is free. Any non-zero value represents the segment address of the program that owns it.
  • Offset 03h–04h (Word): Size of the memory block immediately following this MCB, measured in 16-byte paragraphs.
  • Offset 05h–07h (3 bytes): Reserved by DOS.
  • Offset 08h–0Fh (8 bytes): ASCII name of the owning program (introduced in DOS 4.0 and retained in 6.22).

Internal Execution and Traversal

When INT 21h, AH=48h executes, the DOS kernel carries out the following operational steps:

  1. Chain Traversal: DOS locates the first MCB via an internal variable stored in the DOS List of Lists (SysVars). It then walks through the chain paragraph by paragraph by calculating the segment address of the next MCB: Next_MCB_Segment = Current_MCB_Segment + Current_MCB_Size + 1.
  2. Strategy Evaluation: DOS checks the allocation strategy set for the system (configured via INT 21h, AX=5801h). The default strategy is First Fit (allocating the first free block that is large enough). Alternative strategies include Best Fit (allocating the block closest in size to minimize fragmentation) and Last Fit (allocating from the highest available address down).
  3. Upper Memory Blocks (UMBs): If the program or system has enabled UMB linking (via INT 21h, AX=5803h), DOS will include upper memory arenas (between 640 KB and 1 MB) in this search path according to the active strategy.

Allocation and Block Splitting

Once DOS selects a free block (Owner == 0000h) that satisfies the requested paragraph count:

  • Exact Match: If the free block's size equals the requested paragraphs, or is larger by less than two paragraphs (insufficient room to build another MCB and hold data), DOS claims the entire block. It assigns the caller's PSP segment address to the Owner field of the MCB.
  • Block Splitting: If the free block is larger than the requested size plus one paragraph, DOS divides the block:
    1. The existing MCB retains its position, but its size field is reduced to match the requested paragraph count.
    2. The Owner field is updated to the calling program’s PSP.
    3. A new MCB is created directly after the newly allocated space at Segment = Current_MCB_Segment + Requested_Size + 1.
    4. The new MCB inherits the previous MCB's chain byte ('M' or 'Z'), sets its own Owner field to 0000h (free), and sets its size to the remaining paragraphs minus one (for its own header).
    5. The original MCB's type byte is forced to 'M'.

Completion

If a valid block is found and configured, DOS clears the Carry Flag and returns AX = Target_MCB_Segment + 1.

If the end of the chain ('Z') is reached without fulfilling the request, DOS sets the Carry Flag, records the size of the largest available unallocated block found during the traversal into BX, loads error code 08h into AX, and terminates the call. If any MCB header type byte contains a value other than 'M' or 'Z', DOS aborts the search, sets the Carry Flag, and returns error code 07h, indicating a corrupted memory chain.