1259826Sjhb/*- 2281887Sjhb * Copyright (c) 2013 Hudson River Trading LLC 3259826Sjhb * Written by: John H. Baldwin <jhb@FreeBSD.org> 4259826Sjhb * All rights reserved. 5259826Sjhb * 6259826Sjhb * Redistribution and use in source and binary forms, with or without 7259826Sjhb * modification, are permitted provided that the following conditions 8259826Sjhb * are met: 9259826Sjhb * 1. Redistributions of source code must retain the above copyright 10259826Sjhb * notice, this list of conditions and the following disclaimer. 11259826Sjhb * 2. Redistributions in binary form must reproduce the above copyright 12259826Sjhb * notice, this list of conditions and the following disclaimer in the 13259826Sjhb * documentation and/or other materials provided with the distribution. 14259826Sjhb * 15259826Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16259826Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17259826Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18259826Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19259826Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20259826Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21259826Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22259826Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23259826Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24259826Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25259826Sjhb * SUCH DAMAGE. 26259826Sjhb */ 27259826Sjhb 28259826Sjhb#include <sys/cdefs.h> 29259826Sjhb__FBSDID("$FreeBSD: releng/11.0/usr.sbin/bhyve/pm.c 281887 2015-04-23 14:22:20Z jhb $"); 30259826Sjhb 31259826Sjhb#include <sys/types.h> 32259998Sjhb#include <machine/vmm.h> 33259826Sjhb 34259998Sjhb#include <assert.h> 35269094Sneel#include <errno.h> 36259998Sjhb#include <pthread.h> 37259998Sjhb#include <signal.h> 38259998Sjhb#include <vmmapi.h> 39259998Sjhb 40259998Sjhb#include "acpi.h" 41259826Sjhb#include "inout.h" 42259998Sjhb#include "mevent.h" 43266125Sjhb#include "pci_irq.h" 44260206Sjhb#include "pci_lpc.h" 45259826Sjhb 46259998Sjhbstatic pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER; 47259998Sjhbstatic struct mevent *power_button; 48259998Sjhbstatic sig_t old_power_handler; 49259826Sjhb 50259826Sjhb/* 51259826Sjhb * Reset Control register at I/O port 0xcf9. Bit 2 forces a system 52259826Sjhb * reset when it transitions from 0 to 1. Bit 1 selects the type of 53259826Sjhb * reset to attempt: 0 selects a "soft" reset, and 1 selects a "hard" 54259826Sjhb * reset. 55259826Sjhb */ 56259826Sjhbstatic int 57259826Sjhbreset_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 58259826Sjhb uint32_t *eax, void *arg) 59259826Sjhb{ 60269094Sneel int error; 61269094Sneel 62259826Sjhb static uint8_t reset_control; 63259826Sjhb 64259826Sjhb if (bytes != 1) 65259826Sjhb return (-1); 66259826Sjhb if (in) 67259826Sjhb *eax = reset_control; 68259826Sjhb else { 69259826Sjhb reset_control = *eax; 70259826Sjhb 71259826Sjhb /* Treat hard and soft resets the same. */ 72269094Sneel if (reset_control & 0x4) { 73269094Sneel error = vm_suspend(ctx, VM_SUSPEND_RESET); 74269094Sneel assert(error == 0 || errno == EALREADY); 75269094Sneel } 76259826Sjhb } 77259826Sjhb return (0); 78259826Sjhb} 79259826SjhbINOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler); 80259826Sjhb 81259826Sjhb/* 82259998Sjhb * ACPI's SCI is a level-triggered interrupt. 83259998Sjhb */ 84259998Sjhbstatic int sci_active; 85259998Sjhb 86259998Sjhbstatic void 87259998Sjhbsci_assert(struct vmctx *ctx) 88259998Sjhb{ 89259998Sjhb 90259998Sjhb if (sci_active) 91259998Sjhb return; 92264468Stychon vm_isa_assert_irq(ctx, SCI_INT, SCI_INT); 93259998Sjhb sci_active = 1; 94259998Sjhb} 95259998Sjhb 96259998Sjhbstatic void 97259998Sjhbsci_deassert(struct vmctx *ctx) 98259998Sjhb{ 99259998Sjhb 100259998Sjhb if (!sci_active) 101259998Sjhb return; 102264468Stychon vm_isa_deassert_irq(ctx, SCI_INT, SCI_INT); 103259998Sjhb sci_active = 0; 104259998Sjhb} 105259998Sjhb 106259998Sjhb/* 107259826Sjhb * Power Management 1 Event Registers 108259826Sjhb * 109259998Sjhb * The only power management event supported is a power button upon 110259998Sjhb * receiving SIGTERM. 111259826Sjhb */ 112259998Sjhbstatic uint16_t pm1_enable, pm1_status; 113259998Sjhb 114259998Sjhb#define PM1_TMR_STS 0x0001 115259998Sjhb#define PM1_BM_STS 0x0010 116259998Sjhb#define PM1_GBL_STS 0x0020 117259998Sjhb#define PM1_PWRBTN_STS 0x0100 118259998Sjhb#define PM1_SLPBTN_STS 0x0200 119259998Sjhb#define PM1_RTC_STS 0x0400 120259998Sjhb#define PM1_WAK_STS 0x8000 121259998Sjhb 122259998Sjhb#define PM1_TMR_EN 0x0001 123259998Sjhb#define PM1_GBL_EN 0x0020 124259998Sjhb#define PM1_PWRBTN_EN 0x0100 125259998Sjhb#define PM1_SLPBTN_EN 0x0200 126259998Sjhb#define PM1_RTC_EN 0x0400 127259998Sjhb 128259998Sjhbstatic void 129259998Sjhbsci_update(struct vmctx *ctx) 130259998Sjhb{ 131259998Sjhb int need_sci; 132259998Sjhb 133259998Sjhb /* See if the SCI should be active or not. */ 134259998Sjhb need_sci = 0; 135259998Sjhb if ((pm1_enable & PM1_TMR_EN) && (pm1_status & PM1_TMR_STS)) 136259998Sjhb need_sci = 1; 137259998Sjhb if ((pm1_enable & PM1_GBL_EN) && (pm1_status & PM1_GBL_STS)) 138259998Sjhb need_sci = 1; 139259998Sjhb if ((pm1_enable & PM1_PWRBTN_EN) && (pm1_status & PM1_PWRBTN_STS)) 140259998Sjhb need_sci = 1; 141259998Sjhb if ((pm1_enable & PM1_SLPBTN_EN) && (pm1_status & PM1_SLPBTN_STS)) 142259998Sjhb need_sci = 1; 143259998Sjhb if ((pm1_enable & PM1_RTC_EN) && (pm1_status & PM1_RTC_STS)) 144259998Sjhb need_sci = 1; 145259998Sjhb if (need_sci) 146259998Sjhb sci_assert(ctx); 147259998Sjhb else 148259998Sjhb sci_deassert(ctx); 149259998Sjhb} 150259998Sjhb 151259826Sjhbstatic int 152259826Sjhbpm1_status_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 153259826Sjhb uint32_t *eax, void *arg) 154259826Sjhb{ 155259826Sjhb 156259826Sjhb if (bytes != 2) 157259826Sjhb return (-1); 158259998Sjhb 159259998Sjhb pthread_mutex_lock(&pm_lock); 160259826Sjhb if (in) 161259998Sjhb *eax = pm1_status; 162259998Sjhb else { 163259998Sjhb /* 164259998Sjhb * Writes are only permitted to clear certain bits by 165259998Sjhb * writing 1 to those flags. 166259998Sjhb */ 167259998Sjhb pm1_status &= ~(*eax & (PM1_WAK_STS | PM1_RTC_STS | 168259998Sjhb PM1_SLPBTN_STS | PM1_PWRBTN_STS | PM1_BM_STS)); 169259998Sjhb sci_update(ctx); 170259998Sjhb } 171259998Sjhb pthread_mutex_unlock(&pm_lock); 172259826Sjhb return (0); 173259826Sjhb} 174259826Sjhb 175259826Sjhbstatic int 176259826Sjhbpm1_enable_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 177259826Sjhb uint32_t *eax, void *arg) 178259826Sjhb{ 179259826Sjhb 180259826Sjhb if (bytes != 2) 181259826Sjhb return (-1); 182259998Sjhb 183259998Sjhb pthread_mutex_lock(&pm_lock); 184259826Sjhb if (in) 185259826Sjhb *eax = pm1_enable; 186259998Sjhb else { 187259998Sjhb /* 188259998Sjhb * Only permit certain bits to be set. We never use 189259998Sjhb * the global lock, but ACPI-CA whines profusely if it 190259998Sjhb * can't set GBL_EN. 191259998Sjhb */ 192259998Sjhb pm1_enable = *eax & (PM1_PWRBTN_EN | PM1_GBL_EN); 193259998Sjhb sci_update(ctx); 194259998Sjhb } 195259998Sjhb pthread_mutex_unlock(&pm_lock); 196259826Sjhb return (0); 197259826Sjhb} 198259826SjhbINOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler); 199259826SjhbINOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler); 200259826Sjhb 201259998Sjhbstatic void 202259998Sjhbpower_button_handler(int signal, enum ev_type type, void *arg) 203259998Sjhb{ 204259998Sjhb struct vmctx *ctx; 205259998Sjhb 206259998Sjhb ctx = arg; 207259998Sjhb pthread_mutex_lock(&pm_lock); 208259998Sjhb if (!(pm1_status & PM1_PWRBTN_STS)) { 209259998Sjhb pm1_status |= PM1_PWRBTN_STS; 210259998Sjhb sci_update(ctx); 211259998Sjhb } 212259998Sjhb pthread_mutex_unlock(&pm_lock); 213259998Sjhb} 214259998Sjhb 215259826Sjhb/* 216259826Sjhb * Power Management 1 Control Register 217259826Sjhb * 218259826Sjhb * This is mostly unimplemented except that we wish to handle writes that 219259826Sjhb * set SPL_EN to handle S5 (soft power off). 220259826Sjhb */ 221259998Sjhbstatic uint16_t pm1_control; 222259998Sjhb 223259998Sjhb#define PM1_SCI_EN 0x0001 224259826Sjhb#define PM1_SLP_TYP 0x1c00 225259826Sjhb#define PM1_SLP_EN 0x2000 226259826Sjhb#define PM1_ALWAYS_ZERO 0xc003 227259826Sjhb 228259826Sjhbstatic int 229259826Sjhbpm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 230259826Sjhb uint32_t *eax, void *arg) 231259826Sjhb{ 232269094Sneel int error; 233259826Sjhb 234259826Sjhb if (bytes != 2) 235259826Sjhb return (-1); 236259826Sjhb if (in) 237259826Sjhb *eax = pm1_control; 238259826Sjhb else { 239259826Sjhb /* 240259826Sjhb * Various bits are write-only or reserved, so force them 241259998Sjhb * to zero in pm1_control. Always preserve SCI_EN as OSPM 242259998Sjhb * can never change it. 243259826Sjhb */ 244259998Sjhb pm1_control = (pm1_control & PM1_SCI_EN) | 245259998Sjhb (*eax & ~(PM1_SLP_EN | PM1_ALWAYS_ZERO)); 246259826Sjhb 247259826Sjhb /* 248259826Sjhb * If SLP_EN is set, check for S5. Bhyve's _S5_ method 249259826Sjhb * says that '5' should be stored in SLP_TYP for S5. 250259826Sjhb */ 251259826Sjhb if (*eax & PM1_SLP_EN) { 252269094Sneel if ((pm1_control & PM1_SLP_TYP) >> 10 == 5) { 253269094Sneel error = vm_suspend(ctx, VM_SUSPEND_POWEROFF); 254269094Sneel assert(error == 0 || errno == EALREADY); 255269094Sneel } 256259826Sjhb } 257259826Sjhb } 258259826Sjhb return (0); 259259826Sjhb} 260259826SjhbINOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler); 261260206SjhbSYSRES_IO(PM1A_EVT_ADDR, 8); 262259998Sjhb 263259998Sjhb/* 264259998Sjhb * ACPI SMI Command Register 265259998Sjhb * 266259998Sjhb * This write-only register is used to enable and disable ACPI. 267259998Sjhb */ 268259998Sjhbstatic int 269259998Sjhbsmi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 270259998Sjhb uint32_t *eax, void *arg) 271259998Sjhb{ 272259998Sjhb 273259998Sjhb assert(!in); 274259998Sjhb if (bytes != 1) 275259998Sjhb return (-1); 276259998Sjhb 277259998Sjhb pthread_mutex_lock(&pm_lock); 278259998Sjhb switch (*eax) { 279259998Sjhb case BHYVE_ACPI_ENABLE: 280259998Sjhb pm1_control |= PM1_SCI_EN; 281259998Sjhb if (power_button == NULL) { 282259998Sjhb power_button = mevent_add(SIGTERM, EVF_SIGNAL, 283259998Sjhb power_button_handler, ctx); 284259998Sjhb old_power_handler = signal(SIGTERM, SIG_IGN); 285259998Sjhb } 286259998Sjhb break; 287259998Sjhb case BHYVE_ACPI_DISABLE: 288259998Sjhb pm1_control &= ~PM1_SCI_EN; 289259998Sjhb if (power_button != NULL) { 290259998Sjhb mevent_delete(power_button); 291259998Sjhb power_button = NULL; 292259998Sjhb signal(SIGTERM, old_power_handler); 293259998Sjhb } 294259998Sjhb break; 295259998Sjhb } 296259998Sjhb pthread_mutex_unlock(&pm_lock); 297259998Sjhb return (0); 298259998Sjhb} 299259998SjhbINOUT_PORT(smi_cmd, SMI_CMD, IOPORT_F_OUT, smi_cmd_handler); 300260206SjhbSYSRES_IO(SMI_CMD, 1); 301266125Sjhb 302266125Sjhbvoid 303266125Sjhbsci_init(struct vmctx *ctx) 304266125Sjhb{ 305266125Sjhb 306266125Sjhb /* 307266125Sjhb * Mark ACPI's SCI as level trigger and bump its use count 308266125Sjhb * in the PIRQ router. 309266125Sjhb */ 310266125Sjhb pci_irq_use(SCI_INT); 311266125Sjhb vm_isa_set_irq_trigger(ctx, SCI_INT, LEVEL_TRIGGER); 312266125Sjhb} 313