[Front] [Next Chapter]

Chapter 1 - Implementing Power Management (BatteryMAX) in DR-DOS


Why BatteryMAX?

BatteryMAX(tm) uses the technique of dynamic idle detection to  benefit any computer manufacturer who supplies hardware running off batteries. It can provide significant power savings by detecting what the software is doing, and therefore extends the battery life of the product.

Limitations on battery life mean that the user of a portable computer often has to carry a mains pack with the computer, so undermining the computer's portability. The extension of battery life provided by BatteryMAX means that battery-powered hardware can be used away from a mains power supply for much longer times, and it thus reduces the instances when the user also has to carry the mains power pack.

BatteryMAX can take account of the hardware on which it runs, and so enables OEMs to combine the benefits of BatteryMAX with the superiority of a particular hardware platform.



Functional Overview

A process is idle if it is waiting for some external event to occur, for example for a keystroke or a mouse movement, or for a fixed amount of time to pass. BatteryMAX includes an idle detection feature that monitors all DOS function calls and determines when applications are idle. The DOS kernel then informs the hardware-dependent BIOS when it believes a process is idle.

The kernel also monitors INT 28s, and any attempts to read characters from the console or other devices; these interrupts and the attempts to read characters may be indicators that the machine is idle.

The dynamic monitoring of application DOS calls is backed up by hardware-dependent BIOS code that supplements the information from the kernel. The BIOS checks for TSRs taking over specific interrupts, and uses hardware assistance, for example hardware that checks whether the video has been updated.

The hardware-dependent code is loaded in the form of a character device driver called $IDLE$, which can be linked with the DOS BIOS, or can be loaded dynamically using the CONFIG.SYS DEVICE statement. The $IDLE$ device driver is described in detail in the section $IDLE$ Device Driver. DOS opens this device driver, and uses a Device I/O Control write (INT 21/44H) to pass the address of a common data area, called the Idle State Data Area. This data area is used by both DOS and the $IDLE$ device driver to pass information about the current process and to modify the action of the idle detection code. The section, “Idle State Data Area” describes the individual variables and flags stored in the Idle State Data Area. As part of the Device I/O write, the $IDLE$ device driver initializes a pointer called IDLE_VEC in the common data area to point to the driver handler routine. The handler is called via IDLE_VEC, and the value in the AX register determines which idle routine is invoked.

After the Device I/O write, the device is closed and the driver interface is not used again.



Definitions of Idle

The $IDLE$ device driver may switch the machine into low-power mode:

Idle DOS Functions

To check whether a process is idle, the DOS kernel monitors DOS functions that are typically used by applications when they are idle.

When a predetermined number of consecutive idle DOS function calls have been made, the device driver is called by the kernel, and the driver may decide to switch the machine into low-power mode. This predetermined number is held in variable IDLE_MAX in the Idle State Data Area, and is set by default to 10. Another variable, IDLE_COUNT, counts the number of consecutive idle DOS function calls. IDLE_COUNT  is initially set to the value of IDLE_MAX, and is then decremented by 1 each time there is an idle DOS function call. When IDLE_COUNT reaches 0, the function PROC_IDLE is called and the $IDLE$ driver may switch the machine into low-power mode. If a non-idle DOS call occurs, IDLE_COUNT is reset to the value of IDLE_MAX.

To invoke PROC_IDLE, the device driver handler is called with command code 1 in the AX register.

INT 28s

The driver can switch the machine into low-power mode after a predetermined number of INT 28s have occurred. The predetermined number is held in variable INT28_RELOAD, in the Idle State Data Area, and is set by default to 10. Another variable, INT28_DELAY, counts the consecutive INT 28s. INT28_DELAY is initially set to the value of INT28_RELOAD, and is then decremented by 1 each time an INT28 is executed. When INT28_DELAY reaches 0, the function PROC_INT28 is called, and the driver may decide to switch the machine into low-power mode. If an interrupt other than an INT28 occurs, INT28_DELAY is reset to the value of INT28_RELOAD.

To invoke PROC_INT28, the device driver handler is called via IDLE_VEC with command code 2 in the AX register.

Character Reads

If the DOS kernel attempts to read a character from the console device, but no character is ready, PROC_KEYIN is executed. Register ES:BX points to the device header for the console. The $IDLE$ driver can switch the machine into low-power mode, unless a TSR or an application is present that may require other interrupts to occur. To invoke PROC_KEYIN, the device driver handler is called via IDLE_VEC with command code 3 in the AX register.

If the DOS kernel attempts to read a character from a device other than the console, and no character is ready, PROC_DEVIN is executed. Register ES:BX points to the device header, and if the device uses interrupts, the $IDLE$ driver can switch the machine into low-power mode until a character is sent, unless a TSR or application is present that may require other interrupts to occur. To invoke PROC_DEVIN, the device driver handler is called via IDLE_VEC with command code 4 in the AX register.



Idle State Data Area

This section describes the flags and variables held in the common data area, the Idle State Data Area. The functions of several of these variables have already been described in previous sections.

The address of the Idle State Data Area is passed to the $IDLE$ device driver at the end of the DOS initialization phase. It is used by the kernel to communicate process state information to the driver, and by the driver to modify the kernel Idle Detection routines. The data area contains the following variables and flags:

Name

Initialization values

Start Address

Flag Size (bytes)

IDLE_COUNT

0

0000H

2

IDLE_MAX

10

0002H

2

IDLE_FLAGS

IDLE_ENABLE

0004H

2

IDLE_VEC

0

0006H

4

INT28_DELAY

0

000AH

2

INT28_RELOAD

10

000CH

2

IDLE_INDOS

indos_flag

000EH

2

OEM_RESERVED

0

0010H

4

The resultant layout of the Idle State Data Area is illustrated below:

Idle State Data Area

IDLE_COUNT

IDLE_COUNT is decremented every time the current DOS process calls an IDLE function. All other DOS function calls reset IDLE_COUNT to IDLE_MAX. When IDLE_COUNT is decremented to 0, the BIOS is called with the PROC_IDLE command.

IDLE_MAX

IDLE_MAX contains the number of consecutive idle function calls that must be made before the BIOS is called with the PROC_IDLE command. This value is initialized to 10, but it can be modified by the driver to a value that better reflects the performance and architecture of the host machine.

IDLE_FLAGS

The idle flags are listed below.

IDLE_DOSFUNC

Flag Name

Value

Function

IDLE_COMMAND

0001H

Command processor active

0002H

DOS call made

IDLE_ON

4000H

Reset when idle checking enabled

IDLE_ENABLE

8000H

Reset when $IDLE$ loaded and active

IDLE_COMMAND

This flag is set whenever the current process is the command processor COMMAND.COM. The flag is reset when a new application is loaded or the command processor is terminated.

IDLE_DOSFUNC

This flag is set whenever an active DOS function call is made. The flag enables the BIOS to detect if an application that is polling the keyboard status, using the ROM BIOS, is also making any DOS calls. The $IDLE$ driver can reset the flag at any time.

IDLE_ON and IDLE_ENABLE

These two flags together enable the idle detection code. Only when both flags have been RESET will the idle detection code be enabled.  $IDLE$ must reset IDLE_ENABLE after IDLE_VEC (see the next section "IDLE_VEC") has been initialized. $IDLE$ can set the flag if idle detection must be disabled for any reason.

IDLE_ON is reset by default, and the kernel uses this flag to implement the IDLE ON/OFF command. The $IDLE$ device driver should not modify this flag.

IDLE_VEC

This is a double word pointer that must be initialized to point to the driver handler routine. This routine must preserve all registers apart from AX, and return using the RET FAR instruction. The $IDLE$ driver is called with the AX register holding one of the command codes shown below in the section "BIOS IDLE Command Interface". On entry to the handler, the DS register points to the segment of the Idle State Data Area.

BIOS IDLE Command Interface

The following table lists the idle routines, the command code by which they are called, and the function of the routine.

PROC_INT28

Routine Name

AX

Function

PROC_IDLE

1

Process is idle

2

INT 28 polling loop

PROC_KEYIN

3

Keyboard input

PROC_DEVIN

4

Device input routine

The section “Definitions of Idle” described the circumstances in which each of the four routines shown in the table above is called. To summarize:

INT28_DELAY

INT28_DELAY is decremented by 1 when an INT 28 is executed. After INT28_RELOAD consecutive INT 28's have been executed, INT28_DELAY is at 0, and the $IDLE$ device driver is called with the PROC_INT28 command.

INT28_RELOAD

INT28_RELOAD contains the number of consecutive INT 28's that must be called before the PROC_INT28 command is called.

IDLE_INDOS

IDLE_INDOS is an offset pointer to the DOS INDOS_FLAG, which is in the same segment as the Idle State Data Area. This byte is non-zero whenever a DOS function is being processed. The $IDLE$ device driver must not modify the value of either this pointer or the INDOS flag.

OEM_RESERVED

This double word is reserved as scratch space for the $IDLE$ driver. The first word entry is used by the example $IDLE$ device driver for the variable IDLE_CNTDN. This reserved field is not used by the kernel.



$IDLE$ Device Driver

$IDLE$ is a special character device driver that contains all the hardware-dependent code to support dynamic idle detection. It can either be linked into the DOS BIOS or loaded dynamically. It must support the four device functions shown below. This table lists the function name, the function number, and the effect of the function.

Name

Function Number

Effect

CMD_INIT

0

Initialize driver

CMD_OUTPUT_IOCTL

12

IOCTL output

CMD_DEVICE_OPEN

13

Device OPEN

CMD_DEVICE_CLOSE

14

Device CLOSE

The commands are issued in the following order:

CMD_INIT
CMD_DEVICE_OPEN
CMD_OUTPUT_IOCTL
CMD_DEVICE_CLOSE

The functions of the initialization, open, and close routines are  described in the DR-DOS System and Programmer's Guide. The CMD_OUTPUT_IOCTL function is called to transfer a double word address to the driver. This address is a pointer to the Idle State Data Area. The device driver is expected to initialize IDLE_VEC to point to the device handling routine, and then to reset the IDLE_ENABLE bit in IDLE_FLAGS.

The $IDLE$ device driver must also monitor any hardware-specific status functions that an application may use. By using this hardware status information, hardware assistance, and the status information from the data area, the $IDLE$ device driver can switch the system into low-power mode when the application is not making any DOS calls.

Example $IDLE$ Device Driver

An example installable $IDLE$ device driver, IDLE.SYS, is provided. You can link the driver into the DOS BIOS, or you can load it by adding the following statement to the CONFIG.SYS file:

DEVICE=[path\]IDLE.SYS [/V]

The /V option forces the $IDLE$ driver to display real-time idle status information when an application is running in text mode. This option is described in the section "Real-time Idle Status Information".

If one of the following events occurs, the $IDLE$ device driver uses a HLT (Halt) instruction to simulate the powering down of the processor:

Before the $IDLE$ device driver simulates the powering down, it uses any available hardware assistance to detect if the application is accessing other components in the system. For example, the application may be polling a serial port, or updating a graphics screen. If this is the case, the device driver immediately returns to the calling process.

The driver is able to make the distinction between a program that is genuinely idle, polling the keyboard in a tight loop, and one that is active but also polling the keyboard to test for an abort key to be pressed. The driver makes this distinction by monitoring the time taken to go idle. If the time is within a specified period (defined below), the driver assumes that the program is idle, polling in a tight loop for a key to be pressed. If the time is outside the specified limit, the driver assumes that some processing has occurred in between polling the keyboard, and should return immediately without idling. A local variable, IDLE_CNTDN, specifies the time against which the actual time taken to go idle is compared. The initial value for this variable is calculated from the formula:

IDLE_CNTDN=(INT16_TIME+RTC_TIME)*(IDLE_MAX*2)

where:

INT16_TIME is the time taken to perform a ROM BIOS INT 16H function 1, (keyboard status check)

RTC_TIME is the time taken to perform a read of the real-time clock using the ROM BIOS INT 1AH function 2, (read real-time clock).

It is not possible to give a static figure for IDLE_CNTDN, because performance varies from machine to machine. The value of IDLE_CNTDN is therefore calculated during execution of the CMD_OUTPUT_IOCTL function. The times are calculated by reading the 8253 timer chip at the start and end of the ROM BIOS calls, and then calculating the elapsed time.

Some TSR keyboard enhancement programs may load and take over the ROM BIOS keyboard handler after $IDLE$ has loaded. The $IDLE$ driver dynamically detects if this occurs, and recalculates IDLE_CNTDN by repeating the calculations test that it performed during the CMD_OUTPUT_IOCTL function.

When it has decided to go idle, the driver must determine what hardware event will force the system to simulate power up. Therefore, if the current application or a TSR has taken over the timer interrupt in order to steal processor time, the system must be “Powered Up” at the next timer interrupt. The system normally wakes up on any hardware event, but if the system is idling as a result of a keyboard read, it wakes only when a keyboard input occurs.

The example driver automatically takes advantage of the emulated hardware support provided by the IDLE386.SYS device driver, if it is loaded. The IDLE386.SYS driver is described in the section "IDLE386.SYS".

Real-time Idle Status Information

As explained in the section "Example $IDLE$ Device Driver, you can load the device driver IDLE.SYS by adding the following statement to the CONFIG.SYS file:

DEVICE=[path\]IDLE.SYS [/V]

The /V option forces the $IDLE$ device driver to display real-time idle status information when an application is running in text mode. If the application is running in graphics mode, the display is not updated. The status information consists of a two-character field in the top-left corner of the screen, and a multi-character field in the top-right corner of the screen.

If /V is specified, and PROC_IDLE or PROC_INT28 is executed, the driver increments the top-left character (column 1, row 1) before it enters low-power mode. For example, if the character A is at that position, it becomes B. The driver updates the video memory, so that if you are editing a text file the text is not corrupted. If a PROC_KEYIN or PROC_DEVIN routine is executed, the driver increments the character at row 1, column 2 before entering low-power mode. This status display thus  indicates when low-power mode is entered and what commands the $IDLE$ driver has received.

For example, if you enter the command DIR at the command line prompt, the character at row 1, column 2 increments after both the downstroke and upstroke for each key. This indicates that the DOS kernel is receiving the PROC_KEYIN commands to “go to sleep” until the next key is pressed or released. The time between increments is the time spent in low-power mode.

If you run a word processor that makes frequent keyboard status checks, the character at row 1, column 1 increments rapidly. This indicates that the DR-DOS kernel has made a PROC_INT28 or PROC_IDLE call to the IDLE86.SYS device driver. The driver increments the character before it enters low-power mode, but wakes up again at the next interrupt. Normally, the timer interrupt causes the driver to exit low-power mode, but the DOS kernel soon detects inactivity again, and increments the character again. Typically, the character is incrementing 18 times a second (the resolution of the timer tick), and so the rate of change on the screen is rapid.

The multi-character status display at the top-right corner of the screen indicates how long the DOS kernel takes to detect that an application is idle; that is, the time required for IDLE_COUNT or INT28_DELAY to count down from their initialization value to zero. The value is displayed in units of 1,200,000ths of a second, in hexadecimal.



Idle Detection Support Environment

Two test programs, IDLE386.SYS and IDLESTAT.EXE, are supplied to assist in the evaluation of system performance, and to provide some indication of the time the machine spends idle. These programs require a 80386 PC/AT compatible, or a 80386 IBM PS/2 system.

Note: While you are running the programs, it is not possible to run other 386-based software that operates in protected mode, for example EMM386.SYS, Microsoft® Windows™ 3.x, or Lotus 1-2-3® release 3.

The device driver IDLE386.SYS places the CPU into 80386 Protect mode, and runs DOS as a Virtual 8086 task. In this mode, IDLE386.SYS can perform its two main functions:

IDLE386.SYS is loaded by including the following statement in the CONFIG.SYS file:

DEVICE=[path\]IDLE386.SYS

The IDLESTAT program displays information generated by the IDLE386 driver about how long the CPU has been idle, and allows you to edit some fields in the Idle State Data Area. Timing information is available only if IDLE386.SYS is loaded.

The timing data collected by IDLE386.SYS is stored in a structure at the address pointed to by the INT 60H Interrupt Service Routine (ISR) vector.

You can load IDLESTAT.EXE from either the command line or from AUTOEXEC.BAT.

IDLE386.SYS

In Virtual 8086 mode, there are certain events, such as reading protected ports or executing privileged instructions, that cause the DOS session to be interrupted. IDLE386.SYS can then handle the event before it returns control to DOS and the 8086 application. The functions that the IDLE386.SYS driver traps or emulates are as follows:

Bit 0 Wake-up on timer INT 8H event

Bit 1 Wake-up on keyboard INT 9H event

Bit 2 Wake-up on INT AH

Bit 3 Wake-up on INT BH

Bit 4 Wake-up on INT CH

Bit 5 Wake-up on INT DH

Bit 6 Wake-up on INT EH

Bit 7 Wake-up on INT FH

There is a description of how the example $IDLE$ driver uses writes to IDLE_PORT in the section “Functional Overview of IDLE386.SYS.”)

Bit 0

Set if an IN or OUT instruction has accessed COM1 (I/O address 3F8H to 3FFH) since the  ACTIVITY_PORT was last read.

Bit 1

Set if an IN or OUT instruction has accessed COM2 (I/O address 2F8H to 2FFH) since the ACTIVITY_PORT was last read.

Bit 2

Reserved (0)

Bit 3

Reserved (0)

Bit 4

Reserved (0)

Bit 5

Reserved (0)

Bit 6

Set if a write operation has been performed to the video RAM (Segment A000H to BFFFH) since the ACTIVITY_PORT was last read.

Bit 7

Reserved (0)

All bits are reset to zero after a read from the port.

Functional Overview of IDLE386.SYS

The example $IDLE$ idle detection driver simulates going to sleep by writing to IDLE_PORT and then performing a HLT instruction. The value written to IDLE_PORT is a bit map of those hardware interrupts that the CPU must wake-up to, and service.

The IDLE386.SYS driver traps the write to IDLE_PORT, and uses the value written to mask out interrupts not required at the PIC (Programmable Interrupt Controller). However, the INT 8H timer tick interrupt is always enabled, so that IDLE386.SYS can keep track of how long the CPU has been idle. When the HLT instruction is executed, a protection violation occurs, which enables IDLE386.SYS to start a timer and to suspend the CPU until an interrupt occurs. Execution of the HLT instruction emulates the CPU being powered down, in so far that it is not executing the 8086 task, because it is looping in protect mode. When an interrupt does occur, it will only be one that is allowed, because interrupts that were not required were masked out at the PIC before going to sleep. When an INT 8H occurs, the bit map written to IDLE_PORT is checked to see if the CPU should wake up on the event. If it should not, then the DOS task remains suspended, simulating the CPU being switched off.

If the event should be serviced, the time spent idle is calculated by reading the timer chip and adding this value to an accumulative idle count, which is stored in a structure pointed to by INT 60H. The 8086 interrupt is serviced, and control is passed back to the task that was active before the CPU became idle (to the instruction following the HLT instruction).

IDLESTAT

When the IDLESTAT program has been loaded, it is activated  when you press SYSREQ (Alt+SYSREQ on some keyboards), and immediately interrogates the data collected by IDLE386.SYS. IDLESTAT displays the information in a pop-up menu that shows:

When the menu is displayed, you can reset the elapsed and idle times to zero by pressing F10.

The idle time is stored in units of INT 8H timer ticks, that is, 18.2 units per second. The time is therefore converted to seconds by dividing by 18. The percentage time spent idle is calculated by dividing the elapsed time by 100, then dividing the idle time by this value.

The IDLESTAT menu also displays the current settings for the following variables from the Idle State Data Area:

The menu initially displays the system defaults for these variables, but you can change them in order to asses the impact on performance of different values. You change them by using the up and down arrow keys to select a variable, then using the plus and minus keys on the keypad to increment or decrement the values. If you press the Shift key in conjunction with the plus or minus key, this increases the resolution of the change by a factor of 16 (10Hex). The changes that you make to these variables are written back to the Idle State Data Area, and the new settings take effect as soon as you exit from the menu. You can reset the original system defaults by pressing F9 while the IDLESTAT menu is displayed.



Hardware Requirements

BatteryMAX works by monitoring status-related calls to the DOS interface or to the ROM BIOS; for example, calls to obtain the keyboard status, or the time and date.

However, some applications appear to BatteryMAX to be polling the state of the machine when they are in fact doing other tasks and accessing the hardware directly. BatteryMAX needs hardware support to cater for these situations. Examples of such applications are communications or graphics packages. A communications program may be running in a tight loop, looking at the modem line for incoming characters, and then at the keyboard for user input. BatteryMAX cannot monitor the hardware, and will see only continuous calls for the keyboard status. BatteryMAX will thus think that the application is idle even if it is transferring data. Hardware support is needed in this example to enable BatteryMAX to know when the application is accessing the communications port.

Similarly, a graphics application may appear to be idle if it is  polling the keyboard for a terminating key while it builds a complex image on the screen.

Before BatteryMAX decides to the put a machine into low-power mode, it needs to be able to look at a hardware port in order to check whether the application has accessed a communications port, screen display, or other polled device. The hardware support should be in the form of a port or ports that have a bit dedicated to each polled hardware device on the machine. The bit should be set when the associated device is accessed by an application, and should then be reset by BatteryMAX after it has read the bit. This form of hardware support means that every time BatteryMAX decides to switch the machine into low-power mode, the decision can be conditional upon the contents of the port. If a bit is set, BatteryMAX knows that since it last reset the bit, the application has accessed the associated hardware. BatteryMAX then decides whether it is appropriate to switch the machine into low-power mode.

Device driver IDLE386.SYS supports this procedure. It monitors writes to the video display and serial ports, and  sets the appropriate bit on the port emulated by the IDLE386.SYS device driver. OEMs need to provide similar functionality for their hardware in order to provide the necessary hardware support for dynamic idle detection.

Transition Speed

BatteryMAX operates by switching power mode at a rate of, typically, 18 times per second. (This rate varies with the application. The CPU returns to high-power mode to service interrupts, and the rate of switching can be higher or lower than 18 times per second, depending on the rate of external hardware interrupts.) Effective power saving is therefore dependent upon the hardware being able to effect rapid transitions between low and high power modes. If the hardware transition is significantly slower than the rate at which the software monitors the status changes, the level of power saving that BatteryMAX provides will be correspondingly reduced.


[Front] [Next Chapter]

info@caldera.com
Copyright © 1976, 1982, 1988, 1990, 1991, 1992 and 1997 Caldera, Inc. All rights reserved.