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.