How MS-DOS 6.22 Manages TSRs in Upper Memory Blocks
In MS-DOS 6.22, loading Terminate and Stay Resident (TSR) programs
into Upper Memory Blocks (UMBs) preserves valuable conventional memory
(the first 640 KB) for primary applications. This system operates
through a coordinated pipeline involving the extended memory manager
HIMEM.SYS, the expanded memory emulator
EMM386.EXE, and internal DOS memory management functions.
By remapping physical extended memory into unmapped address holes in the
Upper Memory Area (640 KB to 1024 KB), DOS establishes UMBs, tracks them
via Memory Control Blocks (MCBs), and uses the LOADHIGH
(LH) utility to allocate, size, and retain TSR code in high
memory.
Preparing the Upper Memory Area
Before MS-DOS can allocate high memory to a TSR, it must create addressable memory between 640 KB (A0000h) and 1 MB (FFFFFh). This region is reserved for video RAM, expansion card ROMs, and the system BIOS. Unused regions within this space are called "holes."
To expose these holes as usable RAM:
HIMEM.SYSis loaded viaCONFIG.SYSto manage Extended Memory (XMS).EMM386.EXEis loaded with parameters such asNOEMSorRAM. Using the 80386 processor’s paged memory capabilities,EMM386maps 4 KB pages of extended memory into the unused physical address ranges of the Upper Memory Area.- The directive
DOS=UMB(orDOS=HIGH,UMB) is parsed inCONFIG.SYS. This directs MS-DOS to initialize data structures capable of managing these newly created blocks alongside standard conventional memory.
Linking UMBs into the MCB Chain
MS-DOS tracks allocated and free memory through Memory Control Blocks
(MCBs). An MCB is a 16-byte record placed immediately before every
managed block of memory, containing a signature (M for
intermediate blocks, Z for the final block in a chain), the
owner's Process Identifier (PID), and the block's length in 16-byte
paragraphs.
By default, the standard DOS allocation functions (INT 21h, Function 48h) operate only on the conventional memory chain. When UMB support is active, MS-DOS maintains the UMBs in a secondary chain or merges them logically above conventional memory.
Programmatic access to UMBs relies on INT 21h, Function 58h:
- Get/Set Allocation Strategy (Subfunctions 00h/01h): Controls whether DOS searches for memory using First Fit, Best Fit, or Last Fit.
- Get/Set UMB Link State (Subfunctions 02h/03h): Directs DOS whether or not to include UMBs in general memory searches.
The LOADHIGH Execution Sequence
When a user executes LOADHIGH <program.exe> (or
LH) from the command line or AUTOEXEC.BAT, the
command interpreter (COMMAND.COM) performs a specific
sequence to isolate high memory for the target application:
- Query and Link:
LOADHIGHcalls INT 21h, Function 5803h to temporarily link the UMB chain to the active allocation list. - Strategy Shift: It calls INT 21h, Function 5801h to set the allocation strategy to prioritize high memory over low memory (typically using high-memory-first fit strategies).
- Execution: DOS reads the TSR executable into the selected UMB. If the program requires more memory during initialization than is available in any single contiguous UMB, DOS falls back to conventional memory unless explicit memory region switches are supplied.
- Restoration: Once the program has started, DOS resets the allocation strategy and unlinks the UMB chain, preventing non-UMB-aware applications launched later from unintentionally allocating upper memory.
Memory Sizing and the TSR Handshake
TSR programs typically consist of two parts: initialization code (run once and discarded) and resident code (remains active to intercept interrupts). Managing memory for these programs requires dynamically handling the difference in size between these two stages:
- Transient Overhead: During launch, the TSR occupies an allocation equal to its full file size plus working stack and scratchpad areas.
- Termination via INT 21h, Function 31h: When initialization is complete, the TSR calls the DOS "Keep Process" function (INT 21h, Function 31h). The program passes a return code and the exact number of 16-byte paragraphs of memory it needs to preserve in the resident segment.
- MCB Truncation: MS-DOS receives the request, updates the length field in the TSR’s MCB to reflect only the resident paragraphs, and marks the remaining trailing memory within that UMB as free.
- Fragment Recycling: The freed paragraphs immediately re-enter the UMB pool. If another small TSR or driver is loaded afterward, it can claim this newly vacated space within the same block.
Handling UMB Fragmentation with Region Specifiers
Because the Upper Memory Area is physically interrupted by video memory and adapter ROMs, UMBs are naturally fragmented into disjointed pools (e.g., one block at C800h–CFFFh and another at E000h–EFFFh). If a TSR requires 30 KB to initialize but only 10 KB to stay resident, it will fail to load if the largest free contiguous block is only 25 KB, even if total free UMB space exceeds 30 KB.
MS-DOS 6.22 handles this with the /L switch inside the
LOADHIGH command:
LOADHIGH /L:region1[,minsize1][;region2[,minsize2]...] <program.exe>
- Region Assignment: Tells DOS to place the program into a specific contiguous UMB segment (Region 1, Region 2, etc.), identified by DOS’s internal numbering of disconnected regions.
- Minimum Size (
minsize): Forces DOS to verify that the target region can accommodate the temporary initialization footprint before executing the file. This ensures that the TSR will not abort halfway through initialization due to an out-of-memory error inside the high memory pool.