APM

From OSDev.wiki
Jump to navigation Jump to search
This page is a work in progress.
This page may thus be incomplete. Its content may be changed in the near future.

APM (Advanced Power Management) is a Power Management standard, developed by Intel and Microsoft, which allows the operating system to control the amount of power sent to devices. ACPI replaces APM as the main power management system for operating systems, mainly because SMP and APM do not mix well.

APM Initialization

The APM standard defines three interfaces through which it the APM BIOS and the operating system can communicate. They are the Real Mode Interface, the 16bit Protected Mode Interface, and the 32bit Protected Mode Interface. Only one of the interfaces may be in use at any given time. Before any of the interfaces can be used, the operating system must check if APM is actually supported (many very new computers don't support APM anymore) and if it is, connect to one of its interfaces. It is a good idea to send a disconnect command prior to connecting to an interface.

Installation Check

This function checks if APM is even supported. It must be performed in Real Mode (or vm86 mode).

;perform an installation check
mov ah,53h            ;this is an APM command
mov al,00h            ;installation check command
xor bx,bx             ;device id (0 = APM BIOS)
int 15h               ;call the BIOS function through interrupt 15h
jc APM_error          ;if the carry flag is set there was an error
                      ;the function was successful
                      ;AX = APM version number
                          ;AH = Major revision number (in BCD format)
                          ;AL = Minor revision number (also BCD format)
                      ;BX = ASCII characters "P" (in BH) and "M" (in BL)
                      ;CX = APM flags (see the official documentation for more details)

Connecting to an interface

This function connects to an APM interface based on the value of interface_number which should be one of the following:

01h = Real Mode Interface
02h = 16bit Protected Mode Interface
03h = 32bit Protected Mode Interface

It must be performed in Real Mode (or vm86 mode).

;connect to an APM interface
mov ah,53h               ;this is an APM command
mov al,[interface_number];see above description
xor bx,bx                ;device id (0 = APM BIOS)
int 15h                  ;call the BIOS function through interrupt 15h
jc APM_error             ;if the carry flag is set there was an error
                         ;otherwise, the function was successful
                         ;The return values are different for each interface.
                         ;The Real Mode Interface returns nothing.

                         ;16-Bit Protected Mode Interface
                         ;AX = Code Segment
                         ;BX = Entry Point (Offset)
                         ;CX = Data Segment
                         ;SI = Code Segment Length
                         ;DI = Data Segment Length

                         ;32-Bit Protected Mode Interface
                         ;AX = 32-Bit Code Segment
                         ;EBX = 32-Bit Entry Point (Offset)
                         ;CX = 16-Bit Code Segment
                         ;DX = Data Segment
                         ;ESI 0:15 = 32-Bit Code Segment Length
                         ;ESI 16:31 = 16-Bit Code Segment Length
                         ;DI = Data Segment Length

The APM driver or OS is responsible for setting up the proper environment for the 16-bit and 32-bit protected mode interface calls. This includes setting up the GDT (or LDT) with a 16-bit code segment and a 16-bit data segment for the 16-Bit protected mode interface, or setting up a 32-bit code segment and a 16-bit code segment, along with a data segment before using the 32-bit protected mode interface.

Note: The 16-bit and 32-bit code segments returned from the function above are the real-mode segments containing the protected mode code. This means that the value returned must first be converted from the real-mode segment number to a linear address. This can be done by shifting the value to the left by 8 bits.

Once these GDT (or LDT) entries have been created, they can be used to call the 16-bit or 32-bit protected mode APM functions, using the value returned above in the BX register as the offset for a far-call into the proper code segment.

Disconnecting from an Interface

This function will disconnect from whatever interface is connected when it is called. If no interface is connected or an error occurs it will set the carry flag upon return. It may be performed in any APM interface mode.

;disconnect from any APM interface
mov ah,53h               ;this is an APM command
mov al,04h               ;interface disconnect command
xor bx,bx                ;device id (0 = APM BIOS)
int 15h                  ;call the BIOS function through interrupt 15h
jc .disconnect_error            ;if the carry flag is set see what the fuss is about. 
jmp .no_error

.disconnect_error:       ;the error code is in ah.
cmp ah,03h               ;if the error code is anything but 03h there was an error.
jne APM_error            ;the error code 03h means that no interface was connected in the first place.
                         
.no_error:
                         ;the function was successful
                         ;Nothing is returned.

Setting APM Driver Version

After an APM interface is connected, APM always runs as if it was version 1.0, to support legacy code. Unfortunately in that mode it isn't possible to do some things as setting the power state for all devices (as needed e.g. to shut the system down). So, if the APM installation check reports a version higher than 1.0, it might be useful to tell the APM that you support 1.1 or 1.2 version using INT 0x15 / AX=0x530E

mov ah,53h               ;this is an APM command
mov al,0eh               ;set driver supported version command
mov bx,0000h             ;device ID of system BIOS
mov ch,01h               ;APM driver major version
mov cl,01h               ;APM driver minor version (can be 01h or 02h if the latter one is supported)
int 15h
jc .version_error
;at this point AX holds the APM version that is connected, AH=major version AL=minor version
;so an additional check might be implemented
jmp .no_error
.version_error:
;ah can hold: 03h if the interface wasn't connected, 09h if the device ID wasn't recognised (BX nonzero), 0Bh if APM v1.1 still isn't engaged
.no_error:
;continue

Controlling Devices

After the operating system has connected to an APM interface it can begin to control the power state of various devices in the computer. Before a given device can be controlled, however, power management for that device must be enabled. Only then can the actual power state of the device be set.

Enabling Power Management

This function will enable power management for all devices. This is, by far, faster than enabling power management for each device separately.

;Enable power management for all devices
mov ah,53h              ;this is an APM command
mov al,08h              ;Change the state of power management...
mov bx,0001h            ;...on all devices to...
mov cx,0001h            ;...power management on.
int 15h                 ;call the BIOS function through interrupt 15h
jc APM_error            ;if the carry flag is set there was an error

To enable power management for a specific device, find the device number for the device in the APM documentation, and put the device number in bx instead of 0001h.

Setting Power States

This function will set the power state of every device to the value of power_state which may be one of the following.

01h = Standby
02h = Suspend
03h = Off

20h...7Fh = OEM-defined power states 

To set the power state for a specific device, find the device number for the device in the APM documentation, and put the device number in bx instead of 0001h.

;Set the power state for all devices
mov ah,53h              ;this is an APM command
mov al,07h              ;Set the power state...
mov bx,0001h            ;...on all devices to...
mov cx,[power_state]    ;see above
int 15h                 ;call the BIOS function through interrupt 15h
jc APM_error            ;if the carry flag is set there was an error

APM Reliability

Because APM is used by calling BIOS functions, it is much simpler to implement in an operating system. These BIOS functions, however, may be buggy or broken on some BIOSes. This is one of the main reasons why ACPI has succeeded.

See Also

Articles

External Links