IDLE DR-DOS

I have a laptop. Sometimes I run VMs on it, and some of those VMs run DOS. When a DOS VM does not have any power management, the laptop quickly lets me know by kicking up the fan speed. It is Very Annoying. So annoying that I really want to avoid the situation.

In newer versions of PC DOS and MS-DOS, the included POWER.EXE utility takes care of it, for the most part. But DR-DOS does not ship with any power management utility. That is despite the fact that since version 5.0, DR-DOS has a very promising-sounding IDLE command built in. Sadly, it does nothing:

DR-DOS 6.0 refuses to even try idling

The online help in DR-DOS 5.0/6.0 or Novell DOS 7.0 does not even mention the IDLE command. Scouring the depths of the Internet revealed a potentially helpful document titled Implementing Power Management (BatteryMAX) in DR-DOS.

In short, said document explains that DR-DOS has hooks for power management, but requires a driver called (internally) $IDLE$ to be installed in order to actually do anything. OEMs were supposed to ship such a driver. DRI/Novell/Caldera had a development kit with sample drivers that OEMs could use as a starting point.

But alas, it appears that the development kit didn’t survive, and I failed to find a single release of DR-DOS that would include a power management driver. So close, and yet so far!

But wait! The documentation mentions that Digital Research patented BatteryMAX and was granted U.S. Patent No. 5,355,501. Only… the actual patent is just a pile of patentese gobbledygook, nearly impossible to decipher and not too useful.

Except… except… the PDF version of the patent consists of about 80% source code listings that no one bothered to OCR!

Those source code listings start with excerpts from DR-DOS itself, showing how the power management hooks are implemented in the OS. But it gets better. This is followed by a source code for a device driver called IDLE86.SYS, a rudimentary but perhaps functional implementation of the $IDLE$ driver from 1990.

So… I typed the whole thing in, because experience taught me that it’s much faster than correcting a horrible quality OCR. Fixed a couple of typos, linked, and loaded in a Novell DOS 7.0 VM. Amazingly, it worked! The laptop fan immediately calmed down when DOS sat on the command prompt.

But not when I ran, say, the editor that comes with Novell DOS. After a bit of debugging, I found another typo that prevented idling from working when the idle check wasn’t invoked from DOS itself. After fixing that, the VM idled also when running random editors. Very promising!

How $IDLE$ Works

The $IDLE$ driver source code provided in patent 5,355,501 is what one might call a functioning sample. It’s meant to be adapted to interface with hardware-specific power management, but simply executes the HLT instruction when it decides that the system should enter the idle state.

Unlike POWER.EXE, which functions independently of DOS, the $IDLE$ driver utilizes hooks provided by DR-DOS. Thus there is for example no need to intercept INT 28h, because DR-DOS will call into the $IDLE$ driver when INT 28h is invoked and certain conditions are satisfied.

There is a small data structure, called the Idle State Data Area, which is used for communication between the DR-DOS kernel and the $IDLE$ driver. The interface is documented in good detail and discussing it here would be redundant.

The sample IDLE86.SYS driver, in addition to using the Idle State Data Area, also intercepts INT 8h and INT 16h.

INT 16h is intercepted to enable idling of applications which call the keyboard BIOS services directly, rather than going through DOS. Full-screen DOS applications typically do that, especially if they also support a mouse.

If INT 16h is invoked and the INDOS flag is set, indicating that DOS itself is calling INT 16h, IDLE86.SYS passes through the call to the BIOS; DR-DOS will call the idling function directly.

Otherwise, when INT 16h function 00h or 10h is called, the IDLE86.SYS driver goes to idle state right away; in this situation, the calling application is blocked until a key is pressed.

Calling any other INT 16h functions is considered polling and IDLE86.SYS may go to idle state. This is based on a heuristic which tries to guess whether the application is doing anything much besides polling the keyboard.

To that end, IDLE86.SYS uses the 8253/8254 Programmable Interval Timer (PIT) to measure how many timer ticks it takes to poll the keyboard state and query the Real-Time Clock (RTC). If the keyboard is polled a certain number of times and very little time elapsed, the system is considered idle and the IDLE86.SYS driver goes into idle state.

Similar logic is used for INT 28h. If INT 28h is called in rapid succession, the application is considered idle. Note that calling INT 28h does not automatically mean that an application is idle. Invoking INT 28h is a way to let background programs execute every now and then.

IDLE86.SYS also hooks INT 8h, the timer tick interrupt. The hook does very little, only resetting internal counters and continuing to the previously installed handler. This is done to ensure that applications must appear to be idle rapidly, within one timer tick, in order to be considered really idle.

When idling due to repeated invocations of INT 16h or INT 28h, IDLE86.SYS tries to assess whether the system is active. Without access to power management hardware, this is difficult. For testing and demonstration purposes, DRI had a separate driver called IDLE386.SYS which ran DOS in V86 mode and used standard 386 hardware to intercept access to video memory and some I/O ports. This was used in lieu of actual power management hardware to detect whether the system is performing some activity even though it might appear idle. The source code for IDLE386.SYS is not provided in the patent, but it would be impractical in any case because the driver prevents memory managers or other protected-mode software from running.

Without IDLE386.SYS, all that IDLE86.SYS does is check whether the floppy motor is on. When it is, IDLE86.SYS considers the system active and won’t enter the idle state.

As mentioned above, when the floppy motor is on, idling is prevented. That avoids a situation where the floppy motor is on and idle state is entered with the timer interrupt masked. That would prevent the floppy motor from being turned off after the normal timeout.

Experience shows that IDLE86.SYS is very quick to detect idle state, much faster than POWER.EXE. That is because POWER.EXE has a relatively long ramp-down period, only entering idle state some time after idling is first detected. As a consequence, for example typematic key repeat may completely prevent POWER.EXE from idling. IDLE86.SYS in contrast must detect idle state within one timer tick (about 1/18 sec) to enter the idle state at all.

Because IDLE86.SYS plugs into DR-DOS, it is controlled by the DR-DOS IDLE command. IDLE OFF disables idle detection and IDLE ON turns it on again. This might be used if the $IDLE$ driver incorrectly decides that the system is idle when it’s not (presumably because some activity it doesn’t or can’t detect is occurring).

Sleeping Harder

The IDLE86.SYS driver presented in the patent shows one interesting idea which isn’t fully realized in the sample code. When the driver detects that no one else hooked the timer related interrupt vectors (INT 8h, INT 1Ch, INT 28h), it may mask the timer interrupt while idling. The logic is quite straightforward: If no TSR hooked anything depending on timer ticks, it then the timer tick is only used by the BIOS to keep time and possibly turn off the floppy motor. When the system goes into idle state waiting for keyboard input, timer interrupts are masked, and the CPU is only woken up when some other interrupt arrives. At that point IDLE86.SYS reads the RTC and updates the BIOS tick count.

While the idea is quite interesting, it has serious drawbacks in practice. One is that quite often, some TSR does hook timer related interrupts; one such example is NWCACHE from Novell DOS 7.0. The sleep optimization therefore can’t kick in because IDLE86.SYS cannot be sure that timer ticks aren’t required.

The other problem is that the RTC only has 1-second resolution. Therefore, once the system wakes up, it cannot restore the timer tick count precisely and the BIOS timer tick count will be inaccurate. This may not be much of a problem in practice, and the algorithm could perhaps be improved. However, since many common configuration prevent this optimization anyway, it’s not likely to be worth fixing.

DR-DOS 5.0/6.0 Caveat

Experience with IDLE86.SYS and DR-DOS 5.0 and 6.0 clearly shows that DRI never shipped the driver in the form that was published in the patent. Because when DR-DOS 5.0 or 6.0 runs with EMM386.SYS (aka MemoryMAX) loaded, the idle driver has no effect.

It’s not that the idle driver doesn’t work—it works just fine. The trouble is that when it executes the HLT instruction, a #GP fault is triggered (which is normal—HLT is a privileged instruction), and EMM386.SYS “handles” it by simply continuing execution.

In other words, the $IDLE$ driver tries to halt, but EMM386.SYS doesn’t play ball and effectively ignores HLT instructions. This is the case even with the most recent EMM386.SYS for DR-DOS 6.0 dated April 27, 1992.

Note that the problem is not in any way specific to the IDLE86.SYS driver. Any power management utility using the HLT instruction has the same problem.

Novell DOS 7.0 does not have this deficiency and idling using the HLT instruction works with or without EMM386 loaded.

Missing Functionality

There is one useful piece of functionality that the IDLE86.SYS driver (as presented in the patent) does not implement. That is the DPMI INT 2Fh/1680h idle service. The DPMI specification was published at about the same time the patent was filed, so the lack of this functionality is hardly surprising.

Note that there is a significant difference between INT 28h and INT 2Fh/1680h. INT 28h might be periodically called from a busy application with the expectation that INT 28h returns quickly and execution continues.

In contrast, INT 2Fh/1680h is meant to be executed when an application decides that it is idle. It does not require any heuristics in the power management driver and takes effect immediately. The IBM PC DOS 7 Technical Update clearly states: This API (applications program interface) [INT 2Fh/1680h] should be used by all PC DOS 7 applications to indicate when they are idle.

Note that INT 2Fh/1680h was not originally intended for power management. Instead, it was designed for multi-tasking environments running DOS applications (OS/2 2.0, Win386). However, it turns out to be the same problem: If an application is idle and can let other applications execute, it is also idle and can let the machine go into a low-power state.

Idle History

It is apparent that when Digital Research patented BatteryMAX in 1990, the functionality was not developed from scratch. Far from it. As mentioned above, the problem of detecting idle applications for the purposes of power management is in fact the same problem as detecting idle applications for the purposes of multi-tasking.

Digital Research developed Concurrent CP/M-86 and later Concurrent DOS throughout the 1980s. Experience from detecting idle applications in the Concurrent DOS environment was directly applicable to BatteryMAX.

This is probably also the reason why DRI’s $IDLE$ driver is much more tightly integrated with the OS than the IBM/MS POWER.EXE driver. In Concurrent DOS, the idle detection had to be built in and couldn’t depend on custom hardware.

Trying It Out

I took IDLE86.SYS, very slightly modified it, and renamed to DRIDLE.SYS (to indicate the DR-DOS connection). A test version of the driver is available here.

The driver was lightly tested with DR-DOS 5.0, 6.0, and Novell DOS 7.0. It has a noticeable effect on CPU utilization, although it might not work in all circumstances. Note also the restriction mentioned above—EMM386.SYS shipped with DR-DOS 5.0/6.0 prevents the HLT instruction from actually halting the system.

The driver does not (yet?) support INT 2Fh/1680h. It is however likely to work with typical applications which poll the keyboard in a loop.

The driver can be loaded on PC DOS/MS-DOS. It will not do anything useful, but won’t harm anything either.

The driver may be improved in the future… or not.

This entry was posted in Computing History, Development, Digital Research. Bookmark the permalink.

9 Responses to IDLE DR-DOS

  1. Ruik says:

    Hi,
    Would the APM BIOS INT 0x15 AX = 0x5305 (set CPU idle) work? With some luck it might trigger something else than STI/HLT e.g. some SMM callback which would get it out of EMM386.
    Thanks,
    Rudolf

  2. zeurkous says:

    Might be worth mentioning that we now have DOSidle to do the job. Does
    the latter work{, well} w/ DR-DOS?

  3. Stuart Axon says:

    Lovely stuff, I look forward to reading about the int 2f/1680 enhancement.

    I noticed the patent has expired so freedoms should probably go ahead an implement this.

  4. Michal Necasek says:

    Potentially yes. My experience is that at least on newer machines (late 1990s), APM BIOS just uses HLT because it makes a huge difference with modern-ish CPUs. Early 1990s machines might do something else. Some newer machines might use SMI, some might not.

    So yes, if you’re lucky APM would help, if you’re not it would be exactly the same.

  5. JC Dumas says:

    Hi. First time posting, long time fan. While I miss most of the technicalities, being a former OS/2 user and lover of good writing, I really enjoy this site.

    I was about to point out a typo but it seems, now that I’m double-checking it, that it as been corrected. Or most likely, I just can’t read. So.. keep up the good work. 🙂

  6. My name says:

    Interesting post! A bit off-topic perhaps but my first PC with an IBM PS/1 2133 (486SX) which had an IBM unique feature called Rapid Resume. It was essentially like standby and hibernate in today’s term. For instance you could configure the machine in the BIOS so that when the physical power button was pressed it would save the whole machine state to disk before powering off. It seemed to work in all system modes (DOS, windows, inside apps etc.) It was quite acomplicated setup… A program had to be executed in autoexec.bat (ps1pfile) to point out to the BIOS in advance the location of the save area (the hibernation file). The file had to be pre allocated and contiguous and the ibm utilities would make sure to allocate it on the uncompressed “host drive” on machines where doublespace was used. There is a patent application here. It’s quite exiciting and there is a lot of complex details in it. For instance, how to find the address of the page table when the button is pressed in v86 mode? Requires bios to scan memory and use various heuristics. Same for GDT and other structures.
    https://patents.google.com/patent/EP0635778A2/en

    The link to this discussion is that the fundamental mechanism for how the bios got control after the user presses the button seems to be based on the operating system (or in DOS, power.exe) periodically calling the APM BIOS function “get event” which gives the BIOS a chance to check various hw registers to see if power button has been activated etc. and trigger the hibernate sequence as appropriate.

    I am wondering if there was an alternative hardware mechanism that could work if running a not APM aware os?

    Would love to some day see all of this implemented in a PS/1 emulator. Would love to assist with it but I don’t have a PS/1 myself making this difficult.

  7. Nathan Anderson says:

    My name:

    Rapid Resume had a surprisingly long life…at least, I’m fairly sure it existed well into the Pentium era of (some) IBM machines, if my memory is correct that my ThinkPad 770 from the late 90s also had this exact feature, which I believe was also called/marketed as Rapid Resume. As I recall, it could be made to work on operating systems other than DOS & Win9x if they supported APM, *but* the only supported file system for writing the hibernation file to was FAT. So you’d have to maintain a dedicated FAT partition for it in the event you were running OS/2 on HPFS, WinNT on NTFS, or Linux on ext2.

    It was a super-cool first-party feature to have implemented in a BIOS, though, for sure!

  8. Chris M. says:

    There were plenty of laptops that supported Suspend-To-Disk in the late 90s. Some Compaq Presarios come to mind. There were even some desktop motherboards that supported it. AOpen had the feature in their Award BIOS. Thing is, like already mentioned, you needed a FAT16 partition to write the file.

    Rapid Resume on the PS/1 was pretty robust. I recall suspending protected mode DOS games, audio and all, and they survived the resume without any problems.

  9. Rugxulo says:

    I bought DR-DOS 7.03 (circa 1999) online in 2004, but I only ever ran it on an old Pentium 166 (no MMX). It’s basically an improved version of Novell DOS 7, very good but some hardcoded limits: FAT16 only, no LFNs, and the multitasking was limited to 64 MB per task and needed its EMM386 loaded with its DPMI enabled (with no swapping). I rarely multitasked, but I did have a fancy DCONFIG.SYS menu (and third-party RAM drive, software cache, mouse driver, text editor, debugger, ANSI driver, cmdline history TSR, grep, etc).

    My favorite text editor, TDE, when compiled by DJGPP, effectively used its __dpmi_yield() function, which is just INT 2Fh AX=1680H. (But I don’t recall what environment that actually helped. Maybe NTVDM.) I do vaguely recall Japheth saying that NTVDM needed to call that indirectly via INT 31H AX=0300H in order to work.

    * https://www.delorie.com/djgpp/doc/libc/libc_279.html
    * https://www.delorie.com/djgpp/doc/dpmi/api/310300.html

    (I did also hack and rebuild TDE to shell out a background task using a specific DR-DOS API, if available. But, like I said, I rarely needed that.)

    For whatever reason, they stopped selling DR-DOS 7.03 online in 2018 or so. These days I only use FreeDOS. They have some IDLEHALT support in the kernel that can be enabled in FDCONFIG.SYS. Or just use their FDAPM utility.

    * http://wiki.freedos.org/wiki/index.php/FDAPM

    Oh, even IDLEHALT=2 will apparently provide INT 2FH, AX=1680H.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.