// APM BIOS support for the Bochs BIOS // Copyright (C) 2004 Fabrice Bellard // // Debugging extensions, 16-bit interface and extended power options // Copyright (C) 2005 Struan Bartlett // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #if defined(APM_REAL) #define APMSYM(s) apmreal_ ## s #elif defined(APM_PROT16) #define APMSYM(s) apm16_ ## s #elif defined(APM_PROT32) #define APMSYM(s) apm32_ ## s #else #error unsupported APM mode #endif APMSYM(out_str): push eax push ebx mov ebx, eax APMSYM(out_str1): SEG CS mov al, byte ptr [bx] cmp al, #0 je APMSYM(out_str2) outb dx, al inc ebx jmp APMSYM(out_str1) APMSYM(out_str2): pop ebx pop eax ret APMSYM(07_poweroff_str): .ascii "Shutdown" db 0 APMSYM(07_suspend_str): .ascii "Suspend" db 0 APMSYM(07_standby_str): .ascii "Standby" db 0 #if DEBUG_APM APMSYM(put_str): push edx mov dx, #INFO_PORT call APMSYM(out_str) pop edx ret ; print the hex number in eax APMSYM(put_num): push eax push ebx push ecx push edx mov ecx, eax mov bx, #8 mov dx, #INFO_PORT APMSYM(put_num1): mov eax, ecx shr eax, #28 add al, #0x30 cmp al, #0x39 jbe APMSYM(put_num2) add al, #0x27 APMSYM(put_num2): outb dx, al shl ecx, #4 dec bx jne APMSYM(put_num1) pop edx pop ecx pop ebx pop eax ret APMSYM(put_reg): outb dx, al shr eax, #8 outb dx, al shr eax, #8 outb dx, al shr eax, #8 outb dx, al mov eax,ebx call APMSYM(put_num) mov al, #0x3b outb dx,al mov al, #0x20 outb dx,al ret APMSYM(put_regs): push eax push edx push ebx mov dx, #INFO_PORT mov ebx, eax mov eax, #0x3d584145 // 'EAX=' call APMSYM(put_reg) pop ebx push ebx mov eax, #0x3d584245 // 'EBX=' call APMSYM(put_reg) mov ebx, ecx mov eax, #0x3d584345 // 'ECX=' call APMSYM(put_reg) mov ebx, edx mov eax, #0x3d584445 // 'EDX=' call APMSYM(put_reg) mov ebx, esi mov eax, #0x3d495345 // 'ESI=' call APMSYM(put_reg) mov ebx, edi mov eax, #0x3d494445 // 'EDI=' call APMSYM(put_reg) mov al, #0x0a outb dx, al pop ebx pop edx pop eax ret #endif #if defined(APM_PROT32) _apm32_entry: #endif #if defined(APM_PROT16) _apm16_entry: #endif pushf #if defined(APM_REAL) _apmreal_entry: #endif #if DEBUG_APM call APMSYM(put_regs) #endif #if defined(APM_REAL) ;----------------- ; APM installation check APMSYM(00): cmp al, #0x00 jne APMSYM(01) mov ah, #1 // APM major version mov al, #2 // APM minor version mov bh, #0x50 // 'P' mov bl, #0x4d // 'M' // bit 0 : 16 bit interface supported // bit 1 : 32 bit interface supported mov cx, #0x3 jmp APMSYM(ok) ;----------------- ; APM real mode interface connect APMSYM(01): cmp al, #0x01 jne APMSYM(02) jmp APMSYM(ok) ;----------------- ; APM 16 bit protected mode interface connect APMSYM(02): cmp al, #0x02 jne APMSYM(03) mov bx, #_apm16_entry mov ax, #0xf000 // 16 bit code segment base mov si, #0xfff0 // 16 bit code segment size mov cx, #0xf000 // data segment address mov di, #0xfff0 // data segment length jmp APMSYM(ok) ;----------------- ; APM 32 bit protected mode interface connect APMSYM(03): cmp al, #0x03 jne APMSYM(04) mov ax, #0xf000 // 32 bit code segment base mov ebx, #_apm32_entry mov cx, #0xf000 // 16 bit code segment base // 32 bit code segment size (low 16 bits) // 16 bit code segment size (high 16 bits) mov esi, #0xfff0fff0 mov dx, #0xf000 // data segment address mov di, #0xfff0 // data segment length jmp APMSYM(ok) #endif ;----------------- ; APM interface disconnect APMSYM(04): cmp al, #0x04 jne APMSYM(05) jmp APMSYM(ok) ;----------------- ; APM cpu idle APMSYM(05): cmp al, #0x05 jne APMSYM(07) pushf ; XEN sti ; XEN: OS calls us with ints disabled -- better re-enable here! hlt popf ; XEN jmp APMSYM(ok) ;----------------- ; APM Set Power State APMSYM(07): cmp al, #0x07 jne APMSYM(08) cmp bx, #1 jne APMSYM(ok) cmp cx, #3 je APMSYM(07_poweroff) cmp cx, #2 je APMSYM(07_suspend) cmp cx, #1 je APMSYM(07_standby) jne APMSYM(ok) APMSYM(07_poweroff): // send power off event to emulator cli mov dx, #0x8900 mov ax, #APMSYM(07_poweroff_str) call APMSYM(out_str) APMSYM(07_1): hlt jmp APMSYM(07_1) APMSYM(07_suspend): push edx mov dx, #0x8900 mov ax, #APMSYM(07_suspend_str) call APMSYM(out_str) pop edx jmp APMSYM(ok) APMSYM(07_standby): push edx mov dx, #0x8900 mov ax, #APMSYM(07_standby_str) call APMSYM(out_str) pop edx jmp APMSYM(ok) ;----------------- ; APM Enable / Disable APMSYM(08): cmp al, #0x08 jne APMSYM(0a) jmp APMSYM(ok) ;----------------- ; Get Power Status APMSYM(0a): cmp al, #0x0a jne APMSYM(0b) mov bh, #0x01 // on line // mov bh, #0x02 // battery mov bl, #0xff // unknown battery status // mov bl, #0x03 // charging mov ch, #0x80 // no system battery // mov ch, #0x8 // charging mov cl, #0xff // unknown remaining time // mov cl, #50 mov dx, #0xffff // unknown remaining time mov si, #0 // zero battery // mov si, #1 // one battery jmp APMSYM(ok) ;----------------- ; Get PM Event APMSYM(0b): cmp al, #0x0b jne APMSYM(0e) mov ah, #0x80 // no event pending jmp APMSYM(error) ;----------------- ; APM Driver Version APMSYM(0e): cmp al, #0x0e jne APMSYM(0f) mov ah, #1 mov al, #2 jmp APMSYM(ok) ;----------------- ; APM Engage / Disengage APMSYM(0f): cmp al, #0x0f jne APMSYM(10) jmp APMSYM(ok) ;----------------- ; APM Get Capabilities APMSYM(10): cmp al, #0x10 jne APMSYM(unimplemented) mov bl, #0 mov cx, #0 jmp APMSYM(ok) ;----------------- APMSYM(ok): popf clc #if defined(APM_REAL) jmp iret_modify_cf #else retf #endif APMSYM(unimplemented): APMSYM(error): popf stc #if defined(APM_REAL) jmp iret_modify_cf #else retf #endif #undef APM_PROT32 #undef APM_PROT16 #undef APM_REAL #undef APMSYM