1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2013 Hudson River Trading LLC 5 * Written by: John H. Baldwin <jhb@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 /* 30 * Copyright 2018 Joyent, Inc. 31 * Copyright 2020 Oxide Computer Company 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/types.h> 38 #include <machine/vmm.h> 39 40 #include <assert.h> 41 #include <errno.h> 42 #include <pthread.h> 43 #ifndef __FreeBSD__ 44 #include <stdlib.h> 45 #endif 46 #include <signal.h> 47 #include <vmmapi.h> 48 49 #include "acpi.h" 50 #include "inout.h" 51 #ifdef __FreeBSD__ 52 #include "mevent.h" 53 #endif 54 #include "pci_irq.h" 55 #include "pci_lpc.h" 56 57 static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER; 58 #ifdef __FreeBSD__ 59 static struct mevent *power_button; 60 static sig_t old_power_handler; 61 #else 62 struct vmctx *pwr_ctx; 63 #endif 64 65 static unsigned gpe0_active; 66 static unsigned gpe0_enabled; 67 static const unsigned gpe0_valid = (1u << GPE_VMGENC); 68 69 /* 70 * Reset Control register at I/O port 0xcf9. Bit 2 forces a system 71 * reset when it transitions from 0 to 1. Bit 1 selects the type of 72 * reset to attempt: 0 selects a "soft" reset, and 1 selects a "hard" 73 * reset. 74 */ 75 static int 76 reset_handler(struct vmctx *ctx __unused, int in, 77 int port __unused, int bytes, uint32_t *eax, void *arg __unused) 78 { 79 int error; 80 81 static uint8_t reset_control; 82 83 if (bytes != 1) 84 return (-1); 85 if (in) 86 *eax = reset_control; 87 else { 88 reset_control = *eax; 89 90 /* Treat hard and soft resets the same. */ 91 if (reset_control & 0x4) { 92 error = vm_suspend(ctx, VM_SUSPEND_RESET); 93 assert(error == 0 || errno == EALREADY); 94 } 95 } 96 return (0); 97 } 98 INOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler); 99 100 /* 101 * ACPI's SCI is a level-triggered interrupt. 102 */ 103 static int sci_active; 104 105 static void 106 sci_assert(struct vmctx *ctx) 107 { 108 109 if (sci_active) 110 return; 111 vm_isa_assert_irq(ctx, SCI_INT, SCI_INT); 112 sci_active = 1; 113 } 114 115 static void 116 sci_deassert(struct vmctx *ctx) 117 { 118 119 if (!sci_active) 120 return; 121 vm_isa_deassert_irq(ctx, SCI_INT, SCI_INT); 122 sci_active = 0; 123 } 124 125 /* 126 * Power Management 1 Event Registers 127 * 128 * The only power management event supported is a power button upon 129 * receiving SIGTERM. 130 */ 131 static uint16_t pm1_enable, pm1_status; 132 133 #define PM1_TMR_STS 0x0001 134 #define PM1_BM_STS 0x0010 135 #define PM1_GBL_STS 0x0020 136 #define PM1_PWRBTN_STS 0x0100 137 #define PM1_SLPBTN_STS 0x0200 138 #define PM1_RTC_STS 0x0400 139 #define PM1_WAK_STS 0x8000 140 141 #define PM1_TMR_EN 0x0001 142 #define PM1_GBL_EN 0x0020 143 #define PM1_PWRBTN_EN 0x0100 144 #define PM1_SLPBTN_EN 0x0200 145 #define PM1_RTC_EN 0x0400 146 147 static void 148 sci_update(struct vmctx *ctx) 149 { 150 int need_sci; 151 152 /* See if the SCI should be active or not. */ 153 need_sci = 0; 154 if ((pm1_enable & PM1_TMR_EN) && (pm1_status & PM1_TMR_STS)) 155 need_sci = 1; 156 if ((pm1_enable & PM1_GBL_EN) && (pm1_status & PM1_GBL_STS)) 157 need_sci = 1; 158 if ((pm1_enable & PM1_PWRBTN_EN) && (pm1_status & PM1_PWRBTN_STS)) 159 need_sci = 1; 160 if ((pm1_enable & PM1_SLPBTN_EN) && (pm1_status & PM1_SLPBTN_STS)) 161 need_sci = 1; 162 if ((pm1_enable & PM1_RTC_EN) && (pm1_status & PM1_RTC_STS)) 163 need_sci = 1; 164 if ((gpe0_enabled & gpe0_active) != 0) 165 need_sci = 1; 166 167 if (need_sci) 168 sci_assert(ctx); 169 else 170 sci_deassert(ctx); 171 } 172 173 static int 174 pm1_status_handler(struct vmctx *ctx, int in, 175 int port __unused, int bytes, uint32_t *eax, void *arg __unused) 176 { 177 178 if (bytes != 2) 179 return (-1); 180 181 pthread_mutex_lock(&pm_lock); 182 if (in) 183 *eax = pm1_status; 184 else { 185 /* 186 * Writes are only permitted to clear certain bits by 187 * writing 1 to those flags. 188 */ 189 pm1_status &= ~(*eax & (PM1_WAK_STS | PM1_RTC_STS | 190 PM1_SLPBTN_STS | PM1_PWRBTN_STS | PM1_BM_STS)); 191 sci_update(ctx); 192 } 193 pthread_mutex_unlock(&pm_lock); 194 return (0); 195 } 196 197 static int 198 pm1_enable_handler(struct vmctx *ctx, int in, 199 int port __unused, int bytes, uint32_t *eax, void *arg __unused) 200 { 201 202 if (bytes != 2) 203 return (-1); 204 205 pthread_mutex_lock(&pm_lock); 206 if (in) 207 *eax = pm1_enable; 208 else { 209 /* 210 * Only permit certain bits to be set. We never use 211 * the global lock, but ACPI-CA whines profusely if it 212 * can't set GBL_EN. 213 */ 214 pm1_enable = *eax & (PM1_RTC_EN | PM1_PWRBTN_EN | PM1_GBL_EN); 215 sci_update(ctx); 216 } 217 pthread_mutex_unlock(&pm_lock); 218 return (0); 219 } 220 INOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler); 221 INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler); 222 223 #ifdef __FreeBSD__ 224 static void 225 power_button_handler(int signal __unused, enum ev_type type __unused, void *arg) 226 { 227 struct vmctx *ctx; 228 229 ctx = arg; 230 pthread_mutex_lock(&pm_lock); 231 if (!(pm1_status & PM1_PWRBTN_STS)) { 232 pm1_status |= PM1_PWRBTN_STS; 233 sci_update(ctx); 234 } 235 pthread_mutex_unlock(&pm_lock); 236 } 237 238 #else 239 /* 240 * Initiate graceful power off. 241 */ 242 /*ARGSUSED*/ 243 static void 244 power_button_handler(int signal, siginfo_t *type, void *cp) 245 { 246 /* 247 * In theory, taking the 'pm_lock' mutex from within this signal 248 * handler could lead to deadlock if the main thread already held this 249 * mutex. In reality, this mutex is local to this file and all of the 250 * other usage in this file only occurs in functions which are FreeBSD 251 * specific (and thus currently not used). Thus, for consistency with 252 * the other code in this file, we take the mutex, but in the future, 253 * if these other functions are ever enabled for use on non-FreeBSD 254 * systems and these functions could be called directly by a thread 255 * (which would then hold the mutex), then we need to revisit the use 256 * of this mutex in this signal handler. 257 */ 258 pthread_mutex_lock(&pm_lock); 259 if (!(pm1_status & PM1_PWRBTN_STS)) { 260 pm1_status |= PM1_PWRBTN_STS; 261 sci_update(pwr_ctx); 262 } 263 pthread_mutex_unlock(&pm_lock); 264 } 265 #endif 266 267 /* 268 * Power Management 1 Control Register 269 * 270 * This is mostly unimplemented except that we wish to handle writes that 271 * set SPL_EN to handle S5 (soft power off). 272 */ 273 static uint16_t pm1_control; 274 275 #define PM1_SCI_EN 0x0001 276 #define PM1_SLP_TYP 0x1c00 277 #define PM1_SLP_EN 0x2000 278 #define PM1_ALWAYS_ZERO 0xc003 279 280 static int 281 pm1_control_handler(struct vmctx *ctx, int in, 282 int port __unused, int bytes, uint32_t *eax, void *arg __unused) 283 { 284 int error; 285 286 if (bytes != 2) 287 return (-1); 288 if (in) 289 *eax = pm1_control; 290 else { 291 /* 292 * Various bits are write-only or reserved, so force them 293 * to zero in pm1_control. Always preserve SCI_EN as OSPM 294 * can never change it. 295 */ 296 pm1_control = (pm1_control & PM1_SCI_EN) | 297 (*eax & ~(PM1_SLP_EN | PM1_ALWAYS_ZERO)); 298 299 /* 300 * If SLP_EN is set, check for S5. Bhyve's _S5_ method 301 * says that '5' should be stored in SLP_TYP for S5. 302 */ 303 if (*eax & PM1_SLP_EN) { 304 if ((pm1_control & PM1_SLP_TYP) >> 10 == 5) { 305 error = vm_suspend(ctx, VM_SUSPEND_POWEROFF); 306 assert(error == 0 || errno == EALREADY); 307 } 308 } 309 } 310 return (0); 311 } 312 INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler); 313 #ifdef __FreeBSD__ 314 SYSRES_IO(PM1A_EVT_ADDR, 8); 315 #endif 316 317 void 318 acpi_raise_gpe(struct vmctx *ctx, unsigned bit) 319 { 320 unsigned mask; 321 322 assert(bit < (IO_GPE0_LEN * (8 / 2))); 323 mask = (1u << bit); 324 assert((mask & ~gpe0_valid) == 0); 325 326 pthread_mutex_lock(&pm_lock); 327 gpe0_active |= mask; 328 sci_update(ctx); 329 pthread_mutex_unlock(&pm_lock); 330 } 331 332 static int 333 gpe0_sts(struct vmctx *ctx, int in, int port __unused, 334 int bytes, uint32_t *eax, void *arg __unused) 335 { 336 /* 337 * ACPI 6.2 specifies the GPE register blocks are accessed 338 * byte-at-a-time. 339 */ 340 if (bytes != 1) 341 return (-1); 342 343 pthread_mutex_lock(&pm_lock); 344 if (in) 345 *eax = gpe0_active; 346 else { 347 /* W1C */ 348 gpe0_active &= ~(*eax & gpe0_valid); 349 sci_update(ctx); 350 } 351 pthread_mutex_unlock(&pm_lock); 352 return (0); 353 } 354 INOUT_PORT(gpe0_sts, IO_GPE0_STS, IOPORT_F_INOUT, gpe0_sts); 355 356 static int 357 gpe0_en(struct vmctx *ctx, int in, int port __unused, 358 int bytes, uint32_t *eax, void *arg __unused) 359 { 360 if (bytes != 1) 361 return (-1); 362 363 pthread_mutex_lock(&pm_lock); 364 if (in) 365 *eax = gpe0_enabled; 366 else { 367 gpe0_enabled = (*eax & gpe0_valid); 368 sci_update(ctx); 369 } 370 pthread_mutex_unlock(&pm_lock); 371 return (0); 372 } 373 INOUT_PORT(gpe0_en, IO_GPE0_EN, IOPORT_F_INOUT, gpe0_en); 374 375 /* 376 * ACPI SMI Command Register 377 * 378 * This write-only register is used to enable and disable ACPI. 379 */ 380 static int 381 smi_cmd_handler(struct vmctx *ctx, int in, int port __unused, 382 int bytes, uint32_t *eax, void *arg __unused) 383 { 384 385 assert(!in); 386 if (bytes != 1) 387 return (-1); 388 389 pthread_mutex_lock(&pm_lock); 390 switch (*eax) { 391 case BHYVE_ACPI_ENABLE: 392 pm1_control |= PM1_SCI_EN; 393 #ifdef __FreeBSD__ 394 if (power_button == NULL) { 395 power_button = mevent_add(SIGTERM, EVF_SIGNAL, 396 power_button_handler, ctx); 397 old_power_handler = signal(SIGTERM, SIG_IGN); 398 } 399 #endif 400 break; 401 case BHYVE_ACPI_DISABLE: 402 pm1_control &= ~PM1_SCI_EN; 403 #ifdef __FreeBSD__ 404 if (power_button != NULL) { 405 mevent_delete(power_button); 406 power_button = NULL; 407 signal(SIGTERM, old_power_handler); 408 } 409 #endif 410 break; 411 } 412 pthread_mutex_unlock(&pm_lock); 413 return (0); 414 } 415 INOUT_PORT(smi_cmd, SMI_CMD, IOPORT_F_OUT, smi_cmd_handler); 416 #ifdef __FreeBSD__ 417 SYSRES_IO(SMI_CMD, 1); 418 #endif 419 420 void 421 sci_init(struct vmctx *ctx) 422 { 423 424 /* 425 * Mark ACPI's SCI as level trigger and bump its use count 426 * in the PIRQ router. 427 */ 428 pci_irq_use(SCI_INT); 429 vm_isa_set_irq_trigger(ctx, SCI_INT, LEVEL_TRIGGER); 430 431 #ifndef __FreeBSD__ 432 { 433 /* 434 * Install SIGTERM signal handler for graceful power off. 435 */ 436 struct sigaction act; 437 438 pwr_ctx = ctx; 439 act.sa_flags = 0; 440 act.sa_sigaction = power_button_handler; 441 (void) sigaction(SIGTERM, &act, NULL); 442 } 443 #endif 444 } 445 446 #ifndef __FreeBSD__ 447 void pmtmr_init(struct vmctx *ctx) 448 { 449 int err; 450 451 /* Attach in-kernel PM timer emulation to correct IO port */ 452 err = vm_pmtmr_set_location(ctx, IO_PMTMR); 453 assert(err == 0); 454 } 455 #endif 456