svn commit: r259826 - head/usr.sbin/bhyve

John Baldwin jhb at FreeBSD.org
Tue Dec 24 16:14:21 UTC 2013


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 <jhb at FreeBSD.org>
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#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);


More information about the svn-src-all mailing list