From owner-freebsd-emulation@freebsd.org Thu Sep 15 08:08:22 2016 Return-Path: Delivered-To: freebsd-emulation@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id F0C35BDBC1B for ; Thu, 15 Sep 2016 08:08:22 +0000 (UTC) (envelope-from ashutosh@xinuos.com) Received: from mailman.ysv.freebsd.org (mailman.ysv.freebsd.org [IPv6:2001:1900:2254:206a::50:5]) by mx1.freebsd.org (Postfix) with ESMTP id D0DD21ABF for ; Thu, 15 Sep 2016 08:08:22 +0000 (UTC) (envelope-from ashutosh@xinuos.com) Received: by mailman.ysv.freebsd.org (Postfix) id CFDE4BDBC19; Thu, 15 Sep 2016 08:08:22 +0000 (UTC) Delivered-To: emulation@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id CF24EBDBC17 for ; Thu, 15 Sep 2016 08:08:22 +0000 (UTC) (envelope-from ashutosh@xinuos.com) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id B573A1ABE for ; Thu, 15 Sep 2016 08:08:22 +0000 (UTC) (envelope-from ashutosh@xinuos.com) Received: by freefall.freebsd.org (Postfix) id B3D6E12E6; Thu, 15 Sep 2016 08:08:22 +0000 (UTC) Delivered-To: vbox@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by freefall.freebsd.org (Postfix) with ESMTP id B294B12E5 for ; Thu, 15 Sep 2016 08:08:22 +0000 (UTC) (envelope-from ashutosh@xinuos.com) Received: from zhost.uxsglobal.com (zhost.xinuos.com [144.202.236.63]) by mx1.freebsd.org (Postfix) with ESMTP id 59C641ABD for ; Thu, 15 Sep 2016 08:08:18 +0000 (UTC) (envelope-from ashutosh@xinuos.com) Received: from localhost (localhost [127.0.0.1]) by zhost.uxsglobal.com (Postfix) with ESMTP id 3D29C880675; Thu, 15 Sep 2016 04:01:14 -0400 (EDT) Received: from zhost.uxsglobal.com ([127.0.0.1]) by localhost (zhost.uxsglobalhost.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 16QUJvtNqlNO; Thu, 15 Sep 2016 04:01:14 -0400 (EDT) Received: from zhost.uxsglobal.com (localhost [127.0.0.1]) by zhost.uxsglobal.com (Postfix) with ESMTP id 05F428806CC; Thu, 15 Sep 2016 04:01:14 -0400 (EDT) Received: from zhost.uxsglobalhost.com (localhost [127.0.0.1]) by zhost.uxsglobal.com (Postfix) with ESMTP id EFB5B880675; Thu, 15 Sep 2016 04:01:13 -0400 (EDT) Date: Thu, 15 Sep 2016 04:01:13 -0400 (EDT) From: Ashutosh Kumar To: vbox@FreeBSD.org Cc: Michael Brinke-Engel , Tim Rice , ashutosh.kumar@techmahindra.com Message-ID: <647512314.1508652.1473926473830.JavaMail.zimbra@xinuos.com> In-Reply-To: <1830242058.1508588.1473926236360.JavaMail.zimbra@xinuos.com> Subject: Guest OS PowerOff issue in vbox 'apm' module for 32-bit protected mode interface. MIME-Version: 1.0 X-Originating-IP: [202.41.204.16] X-Mailer: Zimbra 8.0.6_GA_5922 (ZimbraWebClient - GC52 (Win)/8.0.6_GA_5922) Thread-Topic: Guest OS PowerOff issue in vbox 'apm' module for 32-bit protected mode interface. Thread-Index: nMKvBJtkGx4+yHIHFE5+2GJ7qKEQtw== X-Mailman-Approved-At: Thu, 15 Sep 2016 11:26:14 +0000 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Content-Filtered-By: Mailman/MimeDel 2.1.23 X-BeenThere: freebsd-emulation@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Development of Emulators of other operating systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 15 Sep 2016 08:08:23 -0000 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 =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 =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 =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 =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 =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 =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 =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 =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