Terminate and Stay Resident
|This article needs additional citations for verification. (October 2009)|
||This article may be too technical for most readers to understand. (October 2012)|
Terminate and Stay Resident (TSR) is a computer system call in DOS computer operating systems that returns control to the system as if the program has quit, but keeps the program in memory, to be revived later by a hardware or software interrupt.
Many software vendors use this call to create the appearance of multitasking by transferring control back to the terminated program on automatic or externally-generated events, such as pressing a certain key on the keyboard. Some TSR programs are effectively device drivers for hardware not directly supported by the operating system, while others are small utility programs offering frequently-used functionality such as scheduling and contact directories.
Normally in DOS operating systems, only one program can run at any given time. To stop running, it gives control back to the DOS shell program, COMMAND.COM, using the system call INT 21h/4Ch. The memory and system resources that were used by the program are then marked as unused. This in effect makes it impossible to restart parts of it again without reloading it from scratch. However, if a program ends with the system call INT 27h or INT 21h/31h, the operating system does not reuse a certain specified part of the program's memory.
The original call, INT 27h, is called 'terminate but stay resident', hence the name 'TSR'. Using this call, a program can make up to 64 KB of its memory resident. MS-DOS version 2.0 introduced an improved call, INT 21h/function 31h ('Keep Process'), which removed this limitation and let the program return an exit code. Before making this call, the program can install one or several interrupt handlers pointing into itself, so that it can be called again. Installing a hardware interrupt vector allows such a program to react to hardware events. Installing a software interrupt vector allows it to be called by the currently running program. Installing a timer interrupt handler allows a TSR to run periodically (see ISA and programmable interval timer, especially the section "IBM PC compatible").
The typical method of utilizing an interrupt vector involves reading its present value (the address), storing it within the memory space of the TSR, and installing a pointer to its own code. The stored address is called before or after the TSR has received the interrupt and has finished its processing, in effect forming a singly linked list of interrupt handlers, also called interrupt service routines, or ISRs. This procedure of installing ISRs is called chaining or hooking an interrupt or an interrupt vector.
By chaining the interrupt vectors TSR programs could take complete control of the computer. A TSR could have one of two behaviors:
- Take complete control of an interrupt by not calling other TSRs that had previously altered the same interrupt vector.
- Cascade with other TSRs by calling the old interrupt vector. This could be done before or after they executed their actual code. This way TSRs could form a chain of programs where each one calls the next one.
The 'terminate and stay resident' method was used by most DOS viruses which could either take control of the PC or stay in the background. Viruses would react to disk I/O or execution events by infecting executable (.EXE or .COM) files when they were run and data files when they were opened.
Parts of DOS itself, especially in DOS versions 5.0 and later, used this same technique to perform useful functions, such as the DOSKEY command-line editor and various other installable utilities which were installed by running them at the command line (manually, from AUTOEXEC.BAT or through
INSTALL from within CONFIG.SYS) rather than loading them as device drivers through
DEVICE statements in CONFIG.SYS.
A TSR program can be loaded at any time; sometimes, they are loaded immediately after the operating system's boot, by being explicitly loaded in the AUTOEXEC.BAT batch program, or alternatively at the user's request (for example, Borland's Sidekick and Turbo Debugger, Quicken's QuickPay, or FunStuff Software's Personal Calendar). These programs will, as 'TSR' implies, stay resident in memory while other programs are executing. Some of them do not have an option for unloading themselves from memory, so calling TSR means the program will remain in memory until a reboot. However unloading is possible externally, using utilities like the MARK.EXE/RELEASE.EXE combo by TurboPower Software or soft reboot TSRs which will catch a specific key combination and release all TSRs loaded after them. As the chain of ISRs is singly linked, there is no provision for discovering the previous handler's address (other than attempting to trace back the interrupt chain), or to inform its predecessor that it needs to update its "next address to which to jump" not to point to the TSR which desires to remove itself, so that in order to safely unload TSRs in the middle of a chain, stubs had to be left in memory in most cases, thereby causing memory fragmentation. This gave rise to TSR cooperation frameworks such as TesSeRact and AMIS.
To manage problems with many TSR programs sharing the same interrupt, a method called Alternate Multiplex Interrupt Specification (AMIS) was proposed by Ralf Brown as an improvement over previously used services offered via INT 2Fh. AMIS provides ways to share software interrupts in a controlled manner. It is modeled after IBM's Interrupt Sharing Protocol, originally invented for sharing hardware interrupts of an x86 processor. AMIS services are available via Int 2Dh.
The proposal never gained a widespread traction among programmers in its days. It existed alongside several other competing specifications of varying sophistication.
While very useful, or even essential to overcome DOS's limitations, TSR programs had a reputation as troublemakers. Many of the programs effectively hijacked the operating system in varying documented or undocumented ways, often causing systems to crash on their activation or deactivation when used with particular application programs or other TSRs. As explained above, some viruses were coded as TSRs, and were deliberately troublesome. Additionally, all program code in DOS systems, even those with large amounts of physical RAM, had to be loaded into the first 640 KB of RAM (the conventional memory). TSRs were no exception, and took chunks from that 640 KB that were thus unavailable to application programs. This meant that writing a TSR was a challenge of achieving the smallest possible size for it, and checking it for compatibility with a lot of software products from different vendors—often a very frustrating task.
In the late 1980s and early 1990s, many video games on the PC platform pushed up against this limit and left less and less space for TSRs—even essential ones like CD-ROM drivers—and arranging things so that there was enough free RAM to run the games, while keeping the necessary TSRs present, became a black art. Many gamers had several boot disks with different configurations for different games. In later versions of MS-DOS, "boot menu" scripts allowed various configurations to be selectable via a single "boot disk". In the mid- to later 1990s, while many games were still written for DOS, the 640 KB limit was eventually overcome by putting parts of the game's data and/or program code above the first 1 MB of memory and using the code below 640 KB to access the extended memory (using DOS extension methods), with code being swapped into the lowest 1 MB of RAM as overlays. Because programming with many overlays is a challenge in and of itself, once the program was too big to fit entirely into about 512 KB, use of extended memory was almost always done using a third-party DOS extender implementing VCPI or DPMI, because it becomes much easier and faster to access memory above the 1 MB boundary, and possible to run code in that area, when the x86 processor is switched from real mode to protected mode. However, since DOS and most DOS programs run in real mode (VCPI or DPMI makes a protected mode program look like a real mode program to DOS and the rest of the system by switching back and forth between the two modes), DOS TSRs and device drivers also run in real mode, and so any time one gets control, the DOS extender has to switch back to real mode until it relinquishes control, incurring a time penalty (unless they utilize techniques such as DPMS or CLOAKING).
With the arrival of expanded memory boards and especially of Intel 80386 processors in the second half of the 1980s, it became possible to use memory above 640 KB to load TSRs. This required complex software solutions, named expanded memory managers. Some memory managers are QRAM and QEMM by Quarterdeck, 386Max by Qualitas, CEMM by Compaq and later EMM386 by Microsoft. The memory areas usable for loading TSRs above 640 KB are called "upper memory blocks" (UMBs) and loading programs into them is called loading high. Later, memory managers started including programs which would try to automatically determine how to best allocate TSRs between low and high memory (Quarterdeck's Optimize or Microsoft's MemMaker) in order to try to maximize the available space in the first 640 KB.
With the development of games using DOS extenders (an early example was Doom) which bypassed the 640 KB barrier, many of the issues relating to TSRs disappeared, and with the widespread adoption of Microsoft Windows and especially Windows 95 (followed by Windows 98) — which rendered most TSRs unnecessary and some TSRs incompatible — the TSR faded into the obsolescence, though Win16 applications could do TSR-like tricks such as patching the interrupt descriptor table (IDT) because Windows allowed it. TSRs have now almost disappeared, as multitasking operating systems such as Windows Vista, Windows 7, Mac OS X, and Linux provide the facilities for multiple programs and device drivers to run simultaneously without the need for special programming tricks, and the modern notion of protected memory makes the kernel and its modules exclusively responsible for modifying an interrupt table.
- An early TSR
- comp.os.msdos.programmer FAQ - How can I write a TSR (Terminate-and-Stay-Resident) utility?
- The Alternate Multiplex Interrupt Specification (AMIS), v.3.5
- AMISLIB - a function library to write self-highloading, removable TSRs in assembler
- A to Z of C; a free book on DOS programming in C; Chapter 27 - PDF (80 KB)
- IBM's Interrupt-Sharing Protocol, zip archive, 6.5 KB (Simtel)