We are developing an operating system for my personal research and practical education. For the academic purpose, this motivation is similar to MINIX, but we do not focus on theories. Our main objective is to provide knowledges on hardware-related programming. This is one of the most difficult and complex parts when we start the development of operating system from scratch.
The source code is available at the public github repository.
Advanced power management (APM) is a set of APIs implemented as BIOS calls (INT 15h with AH=53h) to manage the power management configuration. The following specification is cited from “PhoenixBIOS 4.0 Revision 6 User's Manual.”
INT 15h AH=53 : for APM 1.0 and APM 1.1 BIOS Services AL = 01h Interface Connect Input BX = 0000h = Power Device ID (APM BIOS) AL = 0Eh APM Driver Version (APM 1.1 only) Input BX = 0000h = BIOS device CH : APM Driver major version number (BCD) CL : APM Driver minor version number (BCD) Output AH : APM Connection major version number (BCD) AL : APM Connection minor version number (BCD) AL = 08h Enable/disable power management Input BX : Power Device ID: 0001h = All PM devices controlled by the BIOS FFFFh = All PM devices controlled by the BIOS (For compatibility with APM 1.0) CX : Function code: 0000h = Disable power management 0001h = Enable power management AL = 07h Set Power State Input BX : Power Device ID: 0001h = All PM devices managed by the BIOS 01XXh = Display 02XXh = Secondary Storage 03XXh = Parallel Ports 04XXh = Serial Ports 05XXh = Network Adapters 06XXh = PCMCIA Sockets E000h-EFFFh = OEM-defined power-device IDs where XXh = Unit Number (0 based) Unit Number FFh = all units in this class CX : Power State: 0000h = APM enabled 0001h = Standby 0002h = Suspend 0003h = Off 0004h = Last Request Processing Notification 0005h = Last Request Rejected 0006h-001Fh = Reserved system states 0020h-003Fh = OEM-defined system states 0040h-007Fh = OEM-defined device states 0080-FFFFh = Reserved device states
The following code tries to power off the machine using the APM API. It should disable PIC not to receive interrupts from peripheral devices before the power off procedure (Line 1). The power off procedure comprises four steps using INT 15h; 1) connecting to APM interface using AL=01h function (Line 4–6), 2) setting the APM driver version to 1.2 using AL=0Eh function (Line 9–12), 3) enabling power management for all devices from software using AL=08h function (Line 15–18), and 4) changing power state to “off” using AL=07h function (Line 20–23). The third step may return an error of 0Ch (function not supported) in some buggy firmware and the fourth step will fail if it really fails, hence we ignore this error.
call disable_pic /* Disable PIC */
/* Power off with APM */
movw $0x5301,%ax /* Connect APM interface */
movw $0x0,%bx /* Specify system BIOS */
int $0x15 /* Return error code in %ah with CF */
jc 1f /* Error */
movw $0x530e,%ax /* Set APM version */
movw $0x0,%bx /* Specify system BIOS */
movw $0x102,%cx /* Version 1.2 */
int $0x15 /* Return error code in %ah with CF */
jc 1f /* Error */
movw $0x5308,%ax /* Enable power management */
movw $0x1,%bx /* All devices managed by the system BIOS */
movw $0x1,%cx /* Enable */
int $0x15 /* Ignore errors */
movw $0x5307,%ax /* Set power state */
movw $0x1,%bx /* All devices managed by the system BIOS */
movw $0x3,%cx /* Off */
int $0x15
1:
/* Implement an error handler here */
This part will be written when ACPI power off code is described in the textbook.