svn commit: r261090 - stable/10/usr.sbin/bhyve
John Baldwin
jhb at FreeBSD.org
Thu Jan 23 20:35:35 UTC 2014
Author: jhb
Date: Thu Jan 23 20:35:32 2014
New Revision: 261090
URL: http://svnweb.freebsd.org/changeset/base/261090
Log:
MFC 259826,259997,259998:
Support soft power-off via the ACPI S5 state for bhyve guests and wire
up a virtual power button to SIGTERM:
- Implement the PM1_EVT and PM1_CTL registers required by ACPI.
- Emulate the Reset Control register at I/O port 0xcf9.
- Advertise an _S5 package.
- Implement an SMI_CMD register with commands to enable and disable ACPI.
Currently the only change when ACPI is enabled is to enable the virtual
power button via SIGTERM.
- Implement a fixed-feature power button when ACPI is enabled by asserting
PWRBTN_STS in PM1_EVT when SIGTERM is received.
- Add support for EVFILT_SIGNAL events to mevent.
- Implement support for the ACPI system command interrupt (SCI) and assert
it when needed based on the values in PM1_EVT. Mark the SCI as active-low
and level triggered in the MADT and MP Table.
Added:
stable/10/usr.sbin/bhyve/pm.c
- copied, changed from r259826, head/usr.sbin/bhyve/pm.c
Modified:
stable/10/usr.sbin/bhyve/Makefile
stable/10/usr.sbin/bhyve/acpi.c
stable/10/usr.sbin/bhyve/acpi.h
stable/10/usr.sbin/bhyve/bhyverun.c
stable/10/usr.sbin/bhyve/inout.h
stable/10/usr.sbin/bhyve/mevent.c
stable/10/usr.sbin/bhyve/mevent.h
stable/10/usr.sbin/bhyve/mptbl.c
stable/10/usr.sbin/bhyve/pmtmr.c
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/usr.sbin/bhyve/Makefile
==============================================================================
--- stable/10/usr.sbin/bhyve/Makefile Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/Makefile Thu Jan 23 20:35:32 2014 (r261090)
@@ -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: stable/10/usr.sbin/bhyve/acpi.c
==============================================================================
--- stable/10/usr.sbin/bhyve/acpi.c Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/acpi.c Thu Jan 23 20:35:32 2014 (r261090)
@@ -85,8 +85,6 @@ __FBSDID("$FreeBSD$");
#define BHYVE_ASL_SUFFIX ".aml"
#define BHYVE_ASL_COMPILER "/usr/sbin/iasl"
-#define BHYVE_PM_TIMER_ADDR 0x408
-
static int basl_keep_temps;
static int basl_verbose_iasl;
static int basl_ncpu;
@@ -283,11 +281,11 @@ basl_fwrite_madt(FILE *fp)
EFPRINTF(fp, "[0001]\t\tSubtable Type : 02\n");
EFPRINTF(fp, "[0001]\t\tLength : 0A\n");
EFPRINTF(fp, "[0001]\t\tBus : 00\n");
- EFPRINTF(fp, "[0001]\t\tSource : 09\n");
- EFPRINTF(fp, "[0004]\t\tInterrupt : 00000009\n");
+ EFPRINTF(fp, "[0001]\t\tSource : %02X\n", SCI_INT);
+ EFPRINTF(fp, "[0004]\t\tInterrupt : %08X\n", SCI_INT);
EFPRINTF(fp, "[0002]\t\tFlags (decoded below) : 0000\n");
- EFPRINTF(fp, "\t\t\tPolarity : 0\n");
- EFPRINTF(fp, "\t\t\tTrigger Mode : 0\n");
+ EFPRINTF(fp, "\t\t\tPolarity : 3\n");
+ EFPRINTF(fp, "\t\t\tTrigger Mode : 3\n");
EFPRINTF(fp, "\n");
EFFLUSH(fp);
@@ -324,21 +322,27 @@ basl_fwrite_fadt(FILE *fp)
basl_acpi_base + FACS_OFFSET);
EFPRINTF(fp, "[0004]\t\tDSDT Address : %08X\n",
basl_acpi_base + DSDT_OFFSET);
- EFPRINTF(fp, "[0001]\t\tModel : 00\n");
+ EFPRINTF(fp, "[0001]\t\tModel : 01\n");
EFPRINTF(fp, "[0001]\t\tPM Profile : 00 [Unspecified]\n");
- EFPRINTF(fp, "[0002]\t\tSCI Interrupt : 0009\n");
- EFPRINTF(fp, "[0004]\t\tSMI Command Port : 00000000\n");
- EFPRINTF(fp, "[0001]\t\tACPI Enable Value : 00\n");
- EFPRINTF(fp, "[0001]\t\tACPI Disable Value : 00\n");
+ EFPRINTF(fp, "[0002]\t\tSCI Interrupt : %04X\n",
+ SCI_INT);
+ EFPRINTF(fp, "[0004]\t\tSMI Command Port : %08X\n",
+ SMI_CMD);
+ EFPRINTF(fp, "[0001]\t\tACPI Enable Value : %02X\n",
+ BHYVE_ACPI_ENABLE);
+ EFPRINTF(fp, "[0001]\t\tACPI Disable Value : %02X\n",
+ BHYVE_ACPI_DISABLE);
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",
+ 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",
+ 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",
- BHYVE_PM_TIMER_ADDR);
+ IO_PMTMR);
EFPRINTF(fp, "[0004]\t\tGPE0 Block Address : 00000000\n");
EFPRINTF(fp, "[0004]\t\tGPE1 Block Address : 00000000\n");
EFPRINTF(fp, "[0001]\t\tPM1 Event Block Length : 04\n");
@@ -369,15 +373,15 @@ 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 Power Button (V1) : 0\n");
EFPRINTF(fp, "\t\t\tControl Method Sleep Button (V1) : 1\n");
EFPRINTF(fp, "\t\t\tRTC wake not in fixed reg space (V1) : 0\n");
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");
@@ -397,10 +401,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);
@@ -412,7 +416,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",
+ PM1A_EVT_ADDR);
EFPRINTF(fp, "\n");
EFPRINTF(fp,
@@ -431,7 +436,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",
+ PM1A_CNT_ADDR);
EFPRINTF(fp, "\n");
EFPRINTF(fp,
@@ -463,7 +469,7 @@ basl_fwrite_fadt(FILE *fp)
EFPRINTF(fp,
"[0001]\t\tEncoded Access Width : 03 [DWord Access:32]\n");
EFPRINTF(fp, "[0008]\t\tAddress : 00000000%08X\n",
- BHYVE_PM_TIMER_ADDR);
+ IO_PMTMR);
EFPRINTF(fp, "\n");
EFPRINTF(fp, "[0012]\t\tGPE0 Block : [Generic Address Structure]\n");
@@ -603,6 +609,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: stable/10/usr.sbin/bhyve/acpi.h
==============================================================================
--- stable/10/usr.sbin/bhyve/acpi.h Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/acpi.h Thu Jan 23 20:35:32 2014 (r261090)
@@ -29,6 +29,19 @@
#ifndef _ACPI_H_
#define _ACPI_H_
+#define SCI_INT 9
+
+#define SMI_CMD 0xb2
+#define BHYVE_ACPI_ENABLE 0xa0
+#define BHYVE_ACPI_DISABLE 0xa1
+
+#define PM1A_EVT_ADDR 0x400
+#define PM1A_CNT_ADDR 0x404
+
+#define IO_PMTMR 0x408 /* 4-byte i/o port for the timer */
+
+struct vmctx;
+
int acpi_build(struct vmctx *ctx, int ncpu);
#endif /* _ACPI_H_ */
Modified: stable/10/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- stable/10/usr.sbin/bhyve/bhyverun.c Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/bhyverun.c Thu Jan 23 20:35:32 2014 (r261090)
@@ -71,6 +71,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)
@@ -282,12 +283,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: stable/10/usr.sbin/bhyve/inout.h
==============================================================================
--- stable/10/usr.sbin/bhyve/inout.h Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/inout.h Thu Jan 23 20:35:32 2014 (r261090)
@@ -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);
Modified: stable/10/usr.sbin/bhyve/mevent.c
==============================================================================
--- stable/10/usr.sbin/bhyve/mevent.c Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/mevent.c Thu Jan 23 20:35:32 2014 (r261090)
@@ -135,6 +135,9 @@ mevent_kq_filter(struct mevent *mevp)
if (mevp->me_type == EVF_TIMER)
retval = EVFILT_TIMER;
+ if (mevp->me_type == EVF_SIGNAL)
+ retval = EVFILT_SIGNAL;
+
return (retval);
}
@@ -437,7 +440,7 @@ mevent_dispatch(void)
* Block awaiting events
*/
ret = kevent(mfd, NULL, 0, eventlist, MEVENT_MAX, NULL);
- if (ret == -1) {
+ if (ret == -1 && errno != EINTR) {
perror("Error return from kevent monitor");
}
Modified: stable/10/usr.sbin/bhyve/mevent.h
==============================================================================
--- stable/10/usr.sbin/bhyve/mevent.h Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/mevent.h Thu Jan 23 20:35:32 2014 (r261090)
@@ -32,7 +32,8 @@
enum ev_type {
EVF_READ,
EVF_WRITE,
- EVF_TIMER
+ EVF_TIMER,
+ EVF_SIGNAL
};
struct mevent;
Modified: stable/10/usr.sbin/bhyve/mptbl.c
==============================================================================
--- stable/10/usr.sbin/bhyve/mptbl.c Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/mptbl.c Thu Jan 23 20:35:32 2014 (r261090)
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
+#include "acpi.h"
#include "bhyverun.h"
#include "mptbl.h"
@@ -200,13 +201,21 @@ mpt_build_ioint_entries(int_entry_ptr mp
mpie->int_type = INTENTRY_TYPE_INT;
mpie->src_bus_irq = 0;
break;
+ case SCI_INT:
+ /* ACPI SCI is level triggered and active-lo. */
+ mpie->int_flags = INTENTRY_FLAGS_POLARITY_ACTIVELO |
+ INTENTRY_FLAGS_TRIGGER_LEVEL;
+ mpie->int_type = INTENTRY_TYPE_INT;
+ mpie->src_bus_irq = SCI_INT;
+ break;
case 5:
case 10:
case 11:
/*
- * PCI Irqs set to level triggered.
+ * PCI Irqs set to level triggered and active-lo.
*/
- mpie->int_flags = INTENTRY_FLAGS_TRIGGER_LEVEL;
+ mpie->int_flags = INTENTRY_FLAGS_POLARITY_ACTIVELO |
+ INTENTRY_FLAGS_TRIGGER_LEVEL;
mpie->src_bus_id = 0;
/* fall through.. */
default:
Copied and modified: stable/10/usr.sbin/bhyve/pm.c (from r259826, head/usr.sbin/bhyve/pm.c)
==============================================================================
--- head/usr.sbin/bhyve/pm.c Tue Dec 24 16:14:19 2013 (r259826, copy source)
+++ stable/10/usr.sbin/bhyve/pm.c Thu Jan 23 20:35:32 2014 (r261090)
@@ -29,11 +29,20 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
+#include <machine/vmm.h>
+#include <assert.h>
+#include <pthread.h>
+#include <signal.h>
+#include <vmmapi.h>
+
+#include "acpi.h"
#include "inout.h"
+#include "mevent.h"
-#define PM1A_EVT_ADDR 0x400
-#define PM1A_CNT_ADDR 0x404
+static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct mevent *power_button;
+static sig_t old_power_handler;
/*
* Reset Control register at I/O port 0xcf9. Bit 2 forces a system
@@ -63,12 +72,75 @@ reset_handler(struct vmctx *ctx, int vcp
INOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler);
/*
+ * ACPI's SCI is a level-triggered interrupt.
+ */
+static int sci_active;
+
+static void
+sci_assert(struct vmctx *ctx)
+{
+
+ if (sci_active)
+ return;
+ vm_ioapic_assert_irq(ctx, SCI_INT);
+ sci_active = 1;
+}
+
+static void
+sci_deassert(struct vmctx *ctx)
+{
+
+ if (!sci_active)
+ return;
+ vm_ioapic_deassert_irq(ctx, SCI_INT);
+ sci_active = 0;
+}
+
+/*
* 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.
+ * The only power management event supported is a power button upon
+ * receiving SIGTERM.
*/
+static uint16_t pm1_enable, pm1_status;
+
+#define PM1_TMR_STS 0x0001
+#define PM1_BM_STS 0x0010
+#define PM1_GBL_STS 0x0020
+#define PM1_PWRBTN_STS 0x0100
+#define PM1_SLPBTN_STS 0x0200
+#define PM1_RTC_STS 0x0400
+#define PM1_WAK_STS 0x8000
+
+#define PM1_TMR_EN 0x0001
+#define PM1_GBL_EN 0x0020
+#define PM1_PWRBTN_EN 0x0100
+#define PM1_SLPBTN_EN 0x0200
+#define PM1_RTC_EN 0x0400
+
+static void
+sci_update(struct vmctx *ctx)
+{
+ int need_sci;
+
+ /* See if the SCI should be active or not. */
+ need_sci = 0;
+ if ((pm1_enable & PM1_TMR_EN) && (pm1_status & PM1_TMR_STS))
+ need_sci = 1;
+ if ((pm1_enable & PM1_GBL_EN) && (pm1_status & PM1_GBL_STS))
+ need_sci = 1;
+ if ((pm1_enable & PM1_PWRBTN_EN) && (pm1_status & PM1_PWRBTN_STS))
+ need_sci = 1;
+ if ((pm1_enable & PM1_SLPBTN_EN) && (pm1_status & PM1_SLPBTN_STS))
+ need_sci = 1;
+ if ((pm1_enable & PM1_RTC_EN) && (pm1_status & PM1_RTC_STS))
+ need_sci = 1;
+ if (need_sci)
+ sci_assert(ctx);
+ else
+ sci_deassert(ctx);
+}
+
static int
pm1_status_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
uint32_t *eax, void *arg)
@@ -76,8 +148,20 @@ pm1_status_handler(struct vmctx *ctx, in
if (bytes != 2)
return (-1);
+
+ pthread_mutex_lock(&pm_lock);
if (in)
- *eax = 0;
+ *eax = pm1_status;
+ else {
+ /*
+ * Writes are only permitted to clear certain bits by
+ * writing 1 to those flags.
+ */
+ pm1_status &= ~(*eax & (PM1_WAK_STS | PM1_RTC_STS |
+ PM1_SLPBTN_STS | PM1_PWRBTN_STS | PM1_BM_STS));
+ sci_update(ctx);
+ }
+ pthread_mutex_unlock(&pm_lock);
return (0);
}
@@ -85,25 +169,51 @@ 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);
+
+ pthread_mutex_lock(&pm_lock);
if (in)
*eax = pm1_enable;
- else
- pm1_enable = *eax;
+ else {
+ /*
+ * Only permit certain bits to be set. We never use
+ * the global lock, but ACPI-CA whines profusely if it
+ * can't set GBL_EN.
+ */
+ pm1_enable = *eax & (PM1_PWRBTN_EN | PM1_GBL_EN);
+ sci_update(ctx);
+ }
+ pthread_mutex_unlock(&pm_lock);
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);
+static void
+power_button_handler(int signal, enum ev_type type, void *arg)
+{
+ struct vmctx *ctx;
+
+ ctx = arg;
+ pthread_mutex_lock(&pm_lock);
+ if (!(pm1_status & PM1_PWRBTN_STS)) {
+ pm1_status |= PM1_PWRBTN_STS;
+ sci_update(ctx);
+ }
+ pthread_mutex_unlock(&pm_lock);
+}
+
/*
* 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).
*/
+static uint16_t pm1_control;
+
+#define PM1_SCI_EN 0x0001
#define PM1_SLP_TYP 0x1c00
#define PM1_SLP_EN 0x2000
#define PM1_ALWAYS_ZERO 0xc003
@@ -112,7 +222,6 @@ 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);
@@ -121,9 +230,11 @@ pm1_control_handler(struct vmctx *ctx, i
else {
/*
* Various bits are write-only or reserved, so force them
- * to zero in pm1_control.
+ * to zero in pm1_control. Always preserve SCI_EN as OSPM
+ * can never change it.
*/
- pm1_control = *eax & ~(PM1_SLP_EN | PM1_ALWAYS_ZERO);
+ pm1_control = (pm1_control & PM1_SCI_EN) |
+ (*eax & ~(PM1_SLP_EN | PM1_ALWAYS_ZERO));
/*
* If SLP_EN is set, check for S5. Bhyve's _S5_ method
@@ -137,3 +248,41 @@ pm1_control_handler(struct vmctx *ctx, i
return (0);
}
INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);
+
+/*
+ * ACPI SMI Command Register
+ *
+ * This write-only register is used to enable and disable ACPI.
+ */
+static int
+smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
+ uint32_t *eax, void *arg)
+{
+
+ assert(!in);
+ if (bytes != 1)
+ return (-1);
+
+ pthread_mutex_lock(&pm_lock);
+ switch (*eax) {
+ case BHYVE_ACPI_ENABLE:
+ pm1_control |= PM1_SCI_EN;
+ if (power_button == NULL) {
+ power_button = mevent_add(SIGTERM, EVF_SIGNAL,
+ power_button_handler, ctx);
+ old_power_handler = signal(SIGTERM, SIG_IGN);
+ }
+ break;
+ case BHYVE_ACPI_DISABLE:
+ pm1_control &= ~PM1_SCI_EN;
+ if (power_button != NULL) {
+ mevent_delete(power_button);
+ power_button = NULL;
+ signal(SIGTERM, old_power_handler);
+ }
+ break;
+ }
+ pthread_mutex_unlock(&pm_lock);
+ return (0);
+}
+INOUT_PORT(smi_cmd, SMI_CMD, IOPORT_F_OUT, smi_cmd_handler);
Modified: stable/10/usr.sbin/bhyve/pmtmr.c
==============================================================================
--- stable/10/usr.sbin/bhyve/pmtmr.c Thu Jan 23 20:25:38 2014 (r261089)
+++ stable/10/usr.sbin/bhyve/pmtmr.c Thu Jan 23 20:35:32 2014 (r261090)
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <assert.h>
#include <pthread.h>
+#include "acpi.h"
#include "inout.h"
/*
@@ -49,11 +50,10 @@ __FBSDID("$FreeBSD$");
* This implementation will be 32-bits
*/
-#define IO_PMTMR 0x408 /* 4-byte i/o port for the timer */
-
#define PMTMR_FREQ 3579545 /* 3.579545MHz */
static pthread_mutex_t pmtmr_mtx;
+static pthread_once_t pmtmr_once = PTHREAD_ONCE_INIT;
static uint64_t pmtmr_old;
@@ -123,6 +123,7 @@ pmtmr_init(void)
pmtmr_uptime_old = tsnew;
pmtmr_old = timespec_to_pmtmr(&tsnew, &tsold);
}
+ pthread_mutex_init(&pmtmr_mtx, NULL);
}
static uint32_t
@@ -133,13 +134,7 @@ pmtmr_val(void)
uint64_t pmtmr_new;
int error;
- static int inited = 0;
-
- if (!inited) {
- pthread_mutex_init(&pmtmr_mtx, NULL);
- pmtmr_init();
- inited = 1;
- }
+ pthread_once(&pmtmr_once, pmtmr_init);
pthread_mutex_lock(&pmtmr_mtx);
More information about the svn-src-all
mailing list