From owner-svn-src-all@FreeBSD.ORG Tue Dec 24 16:14:21 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 662A3DE1; Tue, 24 Dec 2013 16:14:21 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 5129A1E34; Tue, 24 Dec 2013 16:14:21 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rBOGELOV067294; Tue, 24 Dec 2013 16:14:21 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id rBOGEKDb067288; Tue, 24 Dec 2013 16:14:20 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <201312241614.rBOGEKDb067288@svn.freebsd.org> From: John Baldwin Date: Tue, 24 Dec 2013 16:14:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r259826 - head/usr.sbin/bhyve X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Dec 2013 16:14:21 -0000 Author: jhb Date: Tue Dec 24 16:14:19 2013 New Revision: 259826 URL: http://svnweb.freebsd.org/changeset/base/259826 Log: Support soft power-off via the ACPI S5 state for bhyve guests. - Implement the PM1_EVT and PM1_CTL registers required by ACPI. The PM1_EVT register is mostly a dummy as bhyve doesn't support any of the hardware-initiated events. The only bit of PM1_CNT that is implemented are the sleep request bits (SPL_EN and SLP_TYP) which request a graceful power off for S5. In particular, for S5, bhyve exits with a non-zero value which terminates the loop in vmrun.sh. - Emulate the Reset Control register at I/O port 0xcf9 and advertise it as the reset register via ACPI. - Advertise an _S5 package. - Extend the in/out interface to allow an in/out handler to request that the hypervisor trigger a reset or power-off. - While here, note that all vCPUs in a guest support C1 ("hlt"). Reviewed by: neel (earlier version) Added: head/usr.sbin/bhyve/pm.c (contents, props changed) Modified: head/usr.sbin/bhyve/Makefile head/usr.sbin/bhyve/acpi.c head/usr.sbin/bhyve/bhyverun.c head/usr.sbin/bhyve/inout.h Modified: head/usr.sbin/bhyve/Makefile ============================================================================== --- head/usr.sbin/bhyve/Makefile Tue Dec 24 15:56:16 2013 (r259825) +++ head/usr.sbin/bhyve/Makefile Tue Dec 24 16:14:19 2013 (r259826) @@ -10,7 +10,7 @@ MAN= bhyve.8 SRCS= acpi.c atpic.c bhyverun.c block_if.c consport.c dbgport.c elcr.c SRCS+= inout.c legacy_irq.c mem.c mevent.c mptbl.c pci_ahci.c SRCS+= pci_emul.c pci_hostbridge.c pci_lpc.c pci_passthru.c pci_virtio_block.c -SRCS+= pci_virtio_net.c pci_uart.c pit_8254.c pmtmr.c post.c rtc.c +SRCS+= pci_virtio_net.c pci_uart.c pit_8254.c pm.c pmtmr.c post.c rtc.c SRCS+= uart_emul.c virtio.c xmsr.c spinup_ap.c .PATH: ${.CURDIR}/../../sys/amd64/vmm Modified: head/usr.sbin/bhyve/acpi.c ============================================================================== --- head/usr.sbin/bhyve/acpi.c Tue Dec 24 15:56:16 2013 (r259825) +++ head/usr.sbin/bhyve/acpi.c Tue Dec 24 16:14:19 2013 (r259826) @@ -85,6 +85,8 @@ __FBSDID("$FreeBSD$"); #define BHYVE_ASL_SUFFIX ".aml" #define BHYVE_ASL_COMPILER "/usr/sbin/iasl" +#define BHYVE_PM1A_EVT_ADDR 0x400 +#define BHYVE_PM1A_CNT_ADDR 0x404 #define BHYVE_PM_TIMER_ADDR 0x408 static int basl_keep_temps; @@ -342,9 +344,11 @@ basl_fwrite_fadt(FILE *fp) EFPRINTF(fp, "[0001]\t\tACPI Disable Value : 00\n"); EFPRINTF(fp, "[0001]\t\tS4BIOS Command : 00\n"); EFPRINTF(fp, "[0001]\t\tP-State Control : 00\n"); - EFPRINTF(fp, "[0004]\t\tPM1A Event Block Address : 00000000\n"); + EFPRINTF(fp, "[0004]\t\tPM1A Event Block Address : %08X\n", + BHYVE_PM1A_EVT_ADDR); EFPRINTF(fp, "[0004]\t\tPM1B Event Block Address : 00000000\n"); - EFPRINTF(fp, "[0004]\t\tPM1A Control Block Address : 00000000\n"); + EFPRINTF(fp, "[0004]\t\tPM1A Control Block Address : %08X\n", + BHYVE_PM1A_CNT_ADDR); EFPRINTF(fp, "[0004]\t\tPM1B Control Block Address : 00000000\n"); EFPRINTF(fp, "[0004]\t\tPM2 Control Block Address : 00000000\n"); EFPRINTF(fp, "[0004]\t\tPM Timer Block Address : %08X\n", @@ -379,7 +383,7 @@ basl_fwrite_fadt(FILE *fp) EFPRINTF(fp, "[0004]\t\tFlags (decoded below) : 00000000\n"); EFPRINTF(fp, "\t\t\tWBINVD instruction is operational (V1) : 1\n"); EFPRINTF(fp, "\t\t\tWBINVD flushes all caches (V1) : 0\n"); - EFPRINTF(fp, "\t\t\tAll CPUs support C1 (V1) : 0\n"); + EFPRINTF(fp, "\t\t\tAll CPUs support C1 (V1) : 1\n"); EFPRINTF(fp, "\t\t\tC2 works on MP system (V1) : 0\n"); EFPRINTF(fp, "\t\t\tControl Method Power Button (V1) : 1\n"); EFPRINTF(fp, "\t\t\tControl Method Sleep Button (V1) : 1\n"); @@ -387,7 +391,7 @@ basl_fwrite_fadt(FILE *fp) EFPRINTF(fp, "\t\t\tRTC can wake system from S4 (V1) : 0\n"); EFPRINTF(fp, "\t\t\t32-bit PM Timer (V1) : 1\n"); EFPRINTF(fp, "\t\t\tDocking Supported (V1) : 0\n"); - EFPRINTF(fp, "\t\t\tReset Register Supported (V2) : 0\n"); + EFPRINTF(fp, "\t\t\tReset Register Supported (V2) : 1\n"); EFPRINTF(fp, "\t\t\tSealed Case (V3) : 0\n"); EFPRINTF(fp, "\t\t\tHeadless - No Video (V3) : 1\n"); EFPRINTF(fp, "\t\t\tUse native instr after SLP_TYPx (V3) : 0\n"); @@ -407,10 +411,10 @@ basl_fwrite_fadt(FILE *fp) EFPRINTF(fp, "[0001]\t\tBit Width : 08\n"); EFPRINTF(fp, "[0001]\t\tBit Offset : 00\n"); EFPRINTF(fp, "[0001]\t\tEncoded Access Width : 01 [Byte Access:8]\n"); - EFPRINTF(fp, "[0008]\t\tAddress : 0000000000000001\n"); + EFPRINTF(fp, "[0008]\t\tAddress : 0000000000000CF9\n"); EFPRINTF(fp, "\n"); - EFPRINTF(fp, "[0001]\t\tValue to cause reset : 00\n"); + EFPRINTF(fp, "[0001]\t\tValue to cause reset : 06\n"); EFPRINTF(fp, "[0003]\t\tReserved : 000000\n"); EFPRINTF(fp, "[0008]\t\tFACS Address : 00000000%08X\n", basl_acpi_base + FACS_OFFSET); @@ -422,7 +426,8 @@ basl_fwrite_fadt(FILE *fp) EFPRINTF(fp, "[0001]\t\tBit Width : 20\n"); EFPRINTF(fp, "[0001]\t\tBit Offset : 00\n"); EFPRINTF(fp, "[0001]\t\tEncoded Access Width : 02 [Word Access:16]\n"); - EFPRINTF(fp, "[0008]\t\tAddress : 0000000000000001\n"); + EFPRINTF(fp, "[0008]\t\tAddress : 00000000%08X\n", + BHYVE_PM1A_EVT_ADDR); EFPRINTF(fp, "\n"); EFPRINTF(fp, @@ -441,7 +446,8 @@ basl_fwrite_fadt(FILE *fp) EFPRINTF(fp, "[0001]\t\tBit Width : 10\n"); EFPRINTF(fp, "[0001]\t\tBit Offset : 00\n"); EFPRINTF(fp, "[0001]\t\tEncoded Access Width : 02 [Word Access:16]\n"); - EFPRINTF(fp, "[0008]\t\tAddress : 0000000000000001\n"); + EFPRINTF(fp, "[0008]\t\tAddress : 00000000%08X\n", + BHYVE_PM1A_CNT_ADDR); EFPRINTF(fp, "\n"); EFPRINTF(fp, @@ -613,6 +619,11 @@ basl_fwrite_dsdt(FILE *fp) EFPRINTF(fp, "DefinitionBlock (\"bhyve_dsdt.aml\", \"DSDT\", 2," "\"BHYVE \", \"BVDSDT \", 0x00000001)\n"); EFPRINTF(fp, "{\n"); + EFPRINTF(fp, " Name (_S5, Package (0x02)\n"); + EFPRINTF(fp, " {\n"); + EFPRINTF(fp, " 0x05,\n"); + EFPRINTF(fp, " Zero,\n"); + EFPRINTF(fp, " })\n"); EFPRINTF(fp, " Scope (_SB)\n"); EFPRINTF(fp, " {\n"); EFPRINTF(fp, " Device (PCI0)\n"); Modified: head/usr.sbin/bhyve/bhyverun.c ============================================================================== --- head/usr.sbin/bhyve/bhyverun.c Tue Dec 24 15:56:16 2013 (r259825) +++ head/usr.sbin/bhyve/bhyverun.c Tue Dec 24 16:14:19 2013 (r259826) @@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$"); #define VMEXIT_RESTART 2 /* restart current instruction */ #define VMEXIT_ABORT 3 /* abort the vm run loop */ #define VMEXIT_RESET 4 /* guest machine has reset */ +#define VMEXIT_POWEROFF 5 /* guest machine has powered off */ #define MB (1024UL * 1024) #define GB (1024UL * MB) @@ -296,12 +297,17 @@ vmexit_inout(struct vmctx *ctx, struct v return (vmexit_handle_notify(ctx, vme, pvcpu, eax)); error = emulate_inout(ctx, vcpu, in, port, bytes, &eax, strictio); - if (error == 0 && in) + if (error == INOUT_OK && in) error = vm_set_register(ctx, vcpu, VM_REG_GUEST_RAX, eax); - if (error == 0) + switch (error) { + case INOUT_OK: return (VMEXIT_CONTINUE); - else { + case INOUT_RESET: + return (VMEXIT_RESET); + case INOUT_POWEROFF: + return (VMEXIT_POWEROFF); + default: fprintf(stderr, "Unhandled %s%c 0x%04x\n", in ? "in" : "out", bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'), port); Modified: head/usr.sbin/bhyve/inout.h ============================================================================== --- head/usr.sbin/bhyve/inout.h Tue Dec 24 15:56:16 2013 (r259825) +++ head/usr.sbin/bhyve/inout.h Tue Dec 24 16:14:19 2013 (r259826) @@ -33,6 +33,12 @@ struct vmctx; +/* Handler return values. */ +#define INOUT_ERROR -1 +#define INOUT_OK 0 +#define INOUT_RESET 1 +#define INOUT_POWEROFF 2 + typedef int (*inout_func_t)(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg); Added: head/usr.sbin/bhyve/pm.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.sbin/bhyve/pm.c Tue Dec 24 16:14:19 2013 (r259826) @@ -0,0 +1,139 @@ +/*- + * Copyright (c) 2013 Advanced Computing Technologies LLC + * Written by: John H. Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "inout.h" + +#define PM1A_EVT_ADDR 0x400 +#define PM1A_CNT_ADDR 0x404 + +/* + * Reset Control register at I/O port 0xcf9. Bit 2 forces a system + * reset when it transitions from 0 to 1. Bit 1 selects the type of + * reset to attempt: 0 selects a "soft" reset, and 1 selects a "hard" + * reset. + */ +static int +reset_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, + uint32_t *eax, void *arg) +{ + static uint8_t reset_control; + + if (bytes != 1) + return (-1); + if (in) + *eax = reset_control; + else { + reset_control = *eax; + + /* Treat hard and soft resets the same. */ + if (reset_control & 0x4) + return (INOUT_RESET); + } + return (0); +} +INOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler); + +/* + * Power Management 1 Event Registers + * + * bhyve doesn't support any power management events currently, so the + * status register always returns zero. The enable register preserves + * its value but has no effect. + */ +static int +pm1_status_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, + uint32_t *eax, void *arg) +{ + + if (bytes != 2) + return (-1); + if (in) + *eax = 0; + return (0); +} + +static int +pm1_enable_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, + uint32_t *eax, void *arg) +{ + static uint16_t pm1_enable; + + if (bytes != 2) + return (-1); + if (in) + *eax = pm1_enable; + else + pm1_enable = *eax; + return (0); +} +INOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler); +INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler); + +/* + * Power Management 1 Control Register + * + * This is mostly unimplemented except that we wish to handle writes that + * set SPL_EN to handle S5 (soft power off). + */ +#define PM1_SLP_TYP 0x1c00 +#define PM1_SLP_EN 0x2000 +#define PM1_ALWAYS_ZERO 0xc003 + +static int +pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, + uint32_t *eax, void *arg) +{ + static uint16_t pm1_control; + + if (bytes != 2) + return (-1); + if (in) + *eax = pm1_control; + else { + /* + * Various bits are write-only or reserved, so force them + * to zero in pm1_control. + */ + pm1_control = *eax & ~(PM1_SLP_EN | PM1_ALWAYS_ZERO); + + /* + * If SLP_EN is set, check for S5. Bhyve's _S5_ method + * says that '5' should be stored in SLP_TYP for S5. + */ + if (*eax & PM1_SLP_EN) { + if ((pm1_control & PM1_SLP_TYP) >> 10 == 5) + return (INOUT_POWEROFF); + } + } + return (0); +} +INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);