From owner-svn-src-all@FreeBSD.ORG Thu Jan 23 20:35:35 2014 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 28F42762; Thu, 23 Jan 2014 20:35:35 +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 092F4182B; Thu, 23 Jan 2014 20:35:35 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id s0NKZYbJ017124; Thu, 23 Jan 2014 20:35:34 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id s0NKZXG7017114; Thu, 23 Jan 2014 20:35:33 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <201401232035.s0NKZXG7017114@svn.freebsd.org> From: John Baldwin Date: Thu, 23 Jan 2014 20:35:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r261090 - stable/10/usr.sbin/bhyve X-SVN-Group: stable-10 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: Thu, 23 Jan 2014 20:35:35 -0000 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 #include +#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 +#include +#include +#include +#include +#include + +#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 #include +#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);