Skip to content
FreeDOSDeep Dive July 11, 2026 4 min readViews unavailable

Upper Memory Blocks and Loading TSRs High

How DOS power users reclaimed precious conventional memory by relocating device drivers and resident programs into unused gaps in the upper memory area, and why that space wasn't uniform across different machines.

Loading device drivers and terminate-and-stay-resident (TSR) programs “high” — into Upper Memory Blocks rather than conventional memory — was one of the most impactful, and most fiddly, memory optimization techniques available to DOS users trying to maximize the conventional memory available for whatever large application or game they actually wanted to run.

What upper memory actually is

The address range from 640K to 1MB was reserved on the original IBM PC for hardware use — video memory, the BIOS ROM, and address space for expansion card ROMs and memory-mapped I/O. Critically, no single system actually used the entire reserved range for these purposes; the specific gaps left unused depended entirely on a given machine’s actual hardware configuration — how much video memory was mapped where, which expansion cards were installed and what address ranges they claimed, and whether the BIOS itself was fully using its allotted space.

Why this meant every machine’s available upper memory differed

Because the actual unused gaps in the 640K–1MB region depended on a machine’s specific hardware, there was no universal, guaranteed amount of Upper Memory Block space available — one system might have a generous 100K+ of usable UMB space if it had modest video memory requirements and few expansion cards, while another, more heavily equipped system might have very little usable gap space at all. This is why DOS memory optimization guides of the era so often emphasized experimentation specific to your own machine, rather than offering a single, universal configuration that would work identically everywhere.

EMM386’s role in exposing this space

On 386-and-later systems, EMM386.EXE (or an equivalent third-party memory manager) was responsible for actually detecting the specific unused gaps in a given machine’s upper memory area and making them available to DOS as loadable UMBs — this detection needed to be done carefully, since incorrectly assuming a region was free when it was actually in active hardware use could cause serious conflicts or crashes, which is part of why EMM386 configuration sometimes required manually specifying exclude/include ranges when its automatic detection didn’t correctly identify a specific machine’s actual layout.

Loading device drivers high with DEVICEHIGH

Once UMBs were available, CONFIG.SYS’s DEVICEHIGH= directive (rather than the ordinary DEVICE=) loaded a specified driver into upper memory rather than conventional memory, directly freeing up that driver’s memory footprint from the precious sub-640K conventional memory space:

DEVICEHIGH=C:\DOS\MOUSE.SYS

Loading TSRs high with LOADHIGH

The equivalent technique for TSR programs loaded from AUTOEXEC.BAT (or interactively) used the LOADHIGH (or its common abbreviation LH) command:

LOADHIGH C:\UTILS\DOSKEY.COM

Both directives attempt to fit the specified driver or program into available UMB space; if there wasn’t a large enough contiguous free block available at load time, DOS would silently fall back to loading it into conventional memory instead, which is why the order in which multiple drivers and TSRs were loaded high genuinely mattered — loading larger items first, while more UMB space was still available and less fragmented, generally succeeded more often than attempting the same in a less favorable order.

Why this actually mattered so much in practice

For DOS gaming specifically, this optimization was frequently the literal difference between a game running at all and refusing to start with an “insufficient memory” error — many DOS-era games required a specific minimum amount of free conventional memory to run, and a system with several device drivers and TSRs loaded conventionally (a mouse driver, a CD-ROM driver, a sound card driver, DOSKEY) could easily fall short of that minimum, while the identical set of drivers loaded high, freeing that same memory back into the conventional pool, could push the system over the required threshold.

MEMMAKER and automated optimization

Later versions of MS-DOS included MEMMAKER, a utility that automated much of this trial-and-error process — testing different loading orders and configurations semi-automatically to find a working arrangement that maximized free conventional memory without manual, iterative CONFIG.SYS and AUTOEXEC.BAT editing. FreeDOS provides equivalent tooling for the same purpose, reflecting how genuinely common and important this specific optimization was across the DOS ecosystem, important enough to justify dedicated automated tooling rather than leaving it as a purely manual, trial-and-error exercise for every user to work through independently.

Why this remains relevant for retrocomputing and emulation today

Anyone running genuine DOS-era software today, whether on period hardware or under DOSBox-style emulation, still occasionally hits the same “insufficient memory” walls original users faced, and understanding upper memory optimization — recognizing which drivers can be safely relocated high, and in what order — remains directly, practically useful for actually getting demanding period software to run correctly, rather than being purely a historical curiosity about how DOS memory management used to work.