How MS-DOS 6.22 MEM Checks Memory Residency
The MS-DOS 6.22 MEM utility analyzes system memory
residency by querying internal DOS structures to walk the chain of
Memory Control Blocks (MCBs), inspect Program Segment Prefixes (PSPs),
and traverse system device driver headers. Rather than monitoring active
execution, MEM.EXE reconstructs a static snapshot of
resident programs, drivers, and Upper Memory Blocks (UMBs) by
interpreting the memory arena headers linked throughout conventional and
high memory.
Locating the System Arena via the List of Lists
To begin its evaluation, MEM.EXE must locate where
usable memory begins. It does this by issuing an undocumented DOS system
call: Interrupt 21h, Function 52h (Get List of
Lists, also known as SYSVARS).
The pointer returned by this interrupt contains references to critical DOS internal variables:
- A pointer to the first conventional Memory Control Block.
- The head of the system device driver chain.
- Pointers to open file tables and drive parameters.
By retrieving the address of the first MCB from the List of Lists,
MEM establishes the starting point for traversing
conventional memory (the first 640 KB).
Traversing the MCB Chain
MS-DOS manages contiguous memory using MCBs (also referred to as arena headers). Each MCB occupies exactly one paragraph (16 bytes) immediately preceding the memory block it describes:
- Signature Byte (Offset
00h): Holds an ASCII'M'(4Dh) to indicate a standard linked block, or'Z'(5Ah) to mark the final block in the chain. - Owner Field (Offset
01h): A 16-bit segment address pointing to the PSP of the program that owns the allocation. - Size Field (Offset
03h): A 16-bit integer defining the size of the allocated block in 16-byte paragraphs. - Reserved/Name Field (Offset
08h): In DOS 4.0 and higher, including 6.22, bytes08hthrough0Fhcontain an 8-character ASCII string representing the program name.
MEM.EXE reads the first MCB, records the owner and size,
and calculates the address of the next MCB by adding the block's
paragraph count plus one (for the header itself) to the current segment
address. It repeats this process until it encounters the
'Z' delimiter.
Resolving Resident Programs and TSRs
When traversing the MCB chain, MEM determines the nature
of each resident block by examining the Owner field:
- Free Memory: An owner value of
0000hdesignates an unallocated block. - Operating System Segments: An owner value of
0008hindicates memory reserved by DOS system data or device drivers. - Program/TSR Memory: If the owner address matches the segment of the memory block directly following the MCB, the block contains a Program Segment Prefix (PSP), identifying a primary executable or Terminate and Stay Resident (TSR) program.
- Environment and Secondary Blocks: If the owner points elsewhere in memory, the block represents auxiliary storage, such as an environment block, data buffer, or sub-allocation associated with a resident program.
To verify executable authenticity, MEM reads the target
PSP at offset 00h to check for the standard DOS exit
instruction (CD 20h or INT 20h). It then
inspects the PSP’s environment segment (located at offset
2Ch) to parse the program’s full path and filename if the
8-byte MCB name field is unpopulated.
Scanning Device Drivers
Device drivers loaded via CONFIG.SYS bypass standard
PSP-based program execution. To track their residency, MEM
traverses the device driver chain located in the List of Lists.
Each device header points to the next via a standard far pointer
(offset 00h). MEM reads the driver attributes,
determines whether it is a character or block device, extracts the
device name, and matches the driver's memory segment to the surrounding
MCB allocations.
Querying Upper Memory Blocks (UMBs) and XMS
For systems running HIMEM.SYS and
EMM386.EXE, MEM.EXE inspects upper memory
(between 640 KB and 1 MB):
- XMS Driver Detection:
MEMcalls Interrupt2Fh, Function4300hto verify the presence of an Extended Memory Specification (XMS) manager. - UMB Chain Query: If UMB support is active,
MEMlinks upper memory blocks into its residency check. DOS 6.22 links UMBs into the main MCB chain or treats them as secondary MCB chains managed via internal sub-functions (Interrupt21h, Function58h, sub-functions02hand03hto get/set UMB link status). - High Memory Area (HMA):
MEMissues standard XMS calls (Interrupt2Fh, Function4310h) to report whether DOS itself or another driver is resident in the 64 KB High Memory Area.
Formatting the Output
Once the traversal routines gather the sizes, types, and names of all
active segments, MEM.EXE aggregates the data based on user
flags:
- Default: Summarizes total conventional, upper, and extended memory along with largest executable program sizes.
- /C (Classify): Groups memory blocks by executable name, totaling conventional and UMB allocations.
- /D (Debug): Outputs a raw, sequential breakdown of every MCB, internal device driver segment, and empty hole in memory.
- /M (Module): Filters the traversal to display only allocations and sub-allocations owned by a specific resident program.