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:
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).
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.
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.
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.