Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 Sep 2016 04:01:13 -0400 (EDT)
From:      Ashutosh Kumar <ashutosh@xinuos.com>
To:        vbox@FreeBSD.org
Cc:        Michael Brinke-Engel <mikebren@xinuos.com>, Tim Rice <tim@xinuos.com>,  ashutosh.kumar@techmahindra.com
Subject:   Guest OS PowerOff issue in vbox 'apm' module for 32-bit protected mode interface.
Message-ID:  <647512314.1508652.1473926473830.JavaMail.zimbra@xinuos.com>
In-Reply-To: <1830242058.1508588.1473926236360.JavaMail.zimbra@xinuos.com>

next in thread | previous in thread | raw e-mail | index | archive | help




Hello,=20







In order to understand why a particular OS using the BIOS 'apm' module is a=
ble to poweroff on VMWare but not on VirtualBox(v4.3.38.1), we analyzed the=
 VirtualBox module at source level. The OS is using 32-bit protected interf=
ace of APM to issue power off command to APM module of VirtualBox. Our anal=
ysis is that the issue is in VirtualBox=E2=80=99s implementation of APM=E2=
=80=99s =E2=80=98power off=E2=80=99 in 32-bit protected mode. Please see th=
e detailed explanation below:=20







In 32-bit protected mode when, user issues power off command then the Guest=
 OS calls the function =E2=80=98apm_pm32_entry=E2=80=99 of VirtualBox to ch=
ange the power state to power off. The function =E2=80=98apm_pm32_entry=E2=
=80=99 in VirtualBox then calls function =E2=80=98apm_pm16_entry_from_32=E2=
=80=99 to handle the user call. This function validates the arguments and c=
alls function =E2=80=98apm_worker=E2=80=99 to do the actual work:=20



<snip>=20



; APM function dispatch table=20



apm_disp:=20



dw offset apmf_disconnect ; 04h=20



dw offset apmf_idle ; 05h=20



dw offset apmf_busy ; 06h=20



dw offset apmf_set_state ; 07h=20



dw offset apmf_enable ; 08h=20



dw offset apmf_restore ; 09h=20



dw offset apmf_get_status ; 0Ah=20



dw offset apmf_get_event ; 0Bh=20



dw offset apmf_pwr_state ; 0Ch=20



dw offset apmf_dev_pm ; 0Dh=20



dw offset apmf_version ; 0Eh=20



dw offset apmf_engage ; 0Fh=20



dw offset apmf_get_caps ; 10h=20



apm_disp_end:=20







apm_worker proc near=20







sti ; TODO ?? necessary ??=20







push ax ; check if function is supported...=20



xor ah, ah=20



sub al, 4=20



mov bp, ax=20



shl bp, 1=20



cmp al, (apm_disp_end - apm_disp) / 2=20



pop ax=20



mov ah, 53h ; put back APM function=20



jae apmw_bad_func ; validate function range=20







jmp apm_disp[bp] ; and dispatch=20







apmf_disconnect: ; function 04h=20



jmp apmw_success=20







apmf_idle: ; function 05h=20



sti=20



hlt=20



jmp apmw_success=20







apmf_busy: ; function 06h=20



; jmp apmw_success=20







apmf_set_state: ; function 07h=20



; jmp apmw_success=20







apmf_enable: ; function 08h=20



jmp apmw_success=20







apmf_restore: ; function 09h=20



; jmp apmw_success=20







apmf_get_status: ; function 0Ah=20



jmp apmw_bad_func=20







apmf_get_event: ; function 0Bh=20



mov ah, 80h=20



jmp apmw_failure=20







apmf_pwr_state: ; function 0Ch=20







apmf_dev_pm: ; function 0Dh=20



jmp apmw_bad_func=20







apmf_version: ; function 0Eh=20



mov ax, 0102h=20



jmp apmw_success=20







apmf_engage: ; function 0Fh=20



; TODO do something?=20



jmp apmw_success=20







apmf_get_caps: ; function 10h=20



mov bl, 0 ; no batteries=20



mov cx, 0 ; no special caps=20



jmp apmw_success=20







apmw_success:=20



clc ; successful return=20



ret=20







apmw_bad_func:=20



mov ah, 09h ; unrecognized device ID - generic=20







apmw_failure:=20



stc ; error for unsupported functions=20



ret=20







apm_worker endp=20



</snip>=20







The power off event corresponds to function value 0x7. So, from the dispatc=
h table the code jumps to tag =E2=80=98apmf_set_state=E2=80=99. As we can s=
ee in above code for this tag code simply calls =E2=80=98apmw_success=E2=80=
=99 which returns the call back.=20







So, for 32-bit protected mode interface and for the power off event Virtual=
Box is not actually powering off the system but simply returns the calls ba=
ck as success. Due, to this the OS system does not power off on VirtualBox=
=20







We also cross checked the 32-bit protected code on QEMU=E2=80=99s seabios. =
In seabios the 32-bit protected mode function is =E2=80=98entry_apm32=E2=80=
=99 in file =E2=80=98romlayout.S=E2=80=99. This function then calls the fun=
ction =E2=80=98handle_apm=E2=80=99 to handle the APM call:=20



<snip>=20



void VISIBLE16 VISIBLE32SEG=20



handle_apm(struct bregs *regs)=20



{=20



debug_enter(regs, DEBUG_HDL_apm);=20



handle_1553(regs);=20



}=20







void=20



handle_1553(struct bregs *regs)=20



{=20



if (! CONFIG_APMBIOS) {=20



set_code_invalid(regs, RET_EUNSUPPORTED);=20



return;=20



}=20







//debug_stub(regs);=20



switch (regs->al) {=20



case 0x00: handle_155300(regs); break;=20



case 0x01: handle_155301(regs); break;=20



case 0x02: handle_155302(regs); break;=20



case 0x03: handle_155303(regs); break;=20



case 0x04: handle_155304(regs); break;=20



case 0x05: handle_155305(regs); break;=20



case 0x06: handle_155306(regs); break;=20



case 0x07: handle_155307(regs); break;=20



case 0x08: handle_155308(regs); break;=20



case 0x0a: handle_15530a(regs); break;=20



case 0x0b: handle_15530b(regs); break;=20



case 0x0e: handle_15530e(regs); break;=20



case 0x0f: handle_15530f(regs); break;=20



case 0x10: handle_155310(regs); break;=20



default: handle_1553XX(regs); break;=20



}=20



}=20







// APM Set Power State=20



static void=20



handle_155307(struct bregs *regs)=20



{=20



if (regs->bx !=3D 1) {=20



set_success(regs);=20



return;=20



}=20



switch (regs->cx) {=20



case 1:=20



dprintf(1, "APM standby request\n");=20



break;=20



case 2:=20



dprintf(1, "APM suspend request\n");=20



break;=20



case 3:=20



apm_shutdown();=20



break;=20



}=20



set_success(regs);=20



}=20







void=20



apm_shutdown(void)=20



{=20



u16 pm1a_cnt =3D GET_GLOBAL(acpi_pm1a_cnt);=20



if (pm1a_cnt)=20



outw(0x2000, pm1a_cnt);=20







irq_disable();=20



for (;;)=20



hlt();=20



}=20



</snip>=20







So, QEMU issues an internal ACPI request to power off the system when user =
issues a power off in 32-bit protected mode.=20







However, the real mode interface of APM module works fine in VirtualBox. Wh=
en user issues power off command and since this is not 32-bit protected mod=
e the function =E2=80=98apm_pm32_entry=E2=80=99 is not called instead call =
comes to function =E2=80=98apm_function=E2=80=99 with AL set to 0x7 and CX =
set to 0x3:=20



<snip>=20



case APM_SET_PWR:=20



// @todo: validate device ID=20



// @todo: validate current connection state=20



switch (CX) {=20



case APM_PS_STANDBY:=20



apm_out_str("Standby", APM_PORT);=20



break;=20



case APM_PS_SUSPEND:=20



apm_out_str("Suspend", APM_PORT);=20



break;=20



case APM_PS_OFF:=20



apm_out_str("Shutdown", APM_PORT); /* Should not return. */=20



break;=20



default:=20



SET_AH(APM_ERR_INVAL_PARAM);=20



SET_CF();=20



}=20



break;=20



</snip>=20



In this case the code writes a string =E2=80=9CShutdown=E2=80=9D on port AP=
M_PORT i.e 0x8900. This port number is polled by VirtualBox Bochs BIOS. On =
receiving data on this port the function =E2=80=98pcbiosIOPortWrite=E2=80=
=99 in file =E2=80=98DevPcBios.cpp=E2=80=99 is called. It handles it as fol=
lows:=20



<snip>=20



/*=20



* Bochs BIOS shutdown request.=20



*/=20



if (cb =3D=3D 1 && Port =3D=3D 0x8900)=20



{=20



static const unsigned char szShutdown[] =3D "Shutdown";=20



PDEVPCBIOS pThis =3D PDMINS_2_DATA(pDevIns, PDEVPCBIOS);=20



if (u32 =3D=3D szShutdown[pThis->iShutdown])=20



{=20



pThis->iShutdown++;=20



if (pThis->iShutdown =3D=3D 8)=20



{=20



pThis->iShutdown =3D 0;=20



LogRel(("PcBios: 8900h shutdown request\n"));=20



return PDMDevHlpVMPowerOff(pDevIns);=20



}=20



}=20



else=20



pThis->iShutdown =3D 0;=20



return VINF_SUCCESS;=20



}=20



</snip>=20



As we can see it issues a power off request if the string received on port =
is =E2=80=9CShutdown=E2=80=9D.=20







If you can provide your inputs on following points then it will be very hel=
pful to u=20

    1. Have you come across a similar issue and what would be your suggesti=
on on fixing this?=20
    2. We think that the fix should be in VirtualBox and is this something =
you can do or we can do or we need to raise this issue with VirtualBox. Ple=
ase suggest?=20



Regards,=20
Ashutosh=20
+91 9899653573=20




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?647512314.1508652.1473926473830.JavaMail.zimbra>