2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2013 Hudson River Trading LLC
5 * Written by: John H. Baldwin <jhb@FreeBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 * Copyright 2018 Joyent, Inc.
31 * Copyright 2020 Oxide Computer Company
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/types.h>
38 #include <machine/vmm.h>
57 static pthread_mutex_t pm_lock
= PTHREAD_MUTEX_INITIALIZER
;
59 static struct mevent
*power_button
;
60 static sig_t old_power_handler
;
62 struct vmctx
*pwr_ctx
;
65 static unsigned gpe0_active
;
66 static unsigned gpe0_enabled
;
67 static const unsigned gpe0_valid
= (1u << GPE_VMGENC
);
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"
76 reset_handler(struct vmctx
*ctx __unused
, int in
,
77 int port __unused
, int bytes
, uint32_t *eax
, void *arg __unused
)
81 static uint8_t reset_control
;
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
);
98 INOUT_PORT(reset_reg
, 0xCF9, IOPORT_F_INOUT
, reset_handler
);
101 * ACPI's SCI is a level-triggered interrupt.
103 static int sci_active
;
106 sci_assert(struct vmctx
*ctx
)
111 vm_isa_assert_irq(ctx
, SCI_INT
, SCI_INT
);
116 sci_deassert(struct vmctx
*ctx
)
121 vm_isa_deassert_irq(ctx
, SCI_INT
, SCI_INT
);
126 * Power Management 1 Event Registers
128 * The only power management event supported is a power button upon
131 static uint16_t pm1_enable
, pm1_status
;
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
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
148 sci_update(struct vmctx
*ctx
)
152 /* See if the SCI should be active or not. */
154 if ((pm1_enable
& PM1_TMR_EN
) && (pm1_status
& PM1_TMR_STS
))
156 if ((pm1_enable
& PM1_GBL_EN
) && (pm1_status
& PM1_GBL_STS
))
158 if ((pm1_enable
& PM1_PWRBTN_EN
) && (pm1_status
& PM1_PWRBTN_STS
))
160 if ((pm1_enable
& PM1_SLPBTN_EN
) && (pm1_status
& PM1_SLPBTN_STS
))
162 if ((pm1_enable
& PM1_RTC_EN
) && (pm1_status
& PM1_RTC_STS
))
164 if ((gpe0_enabled
& gpe0_active
) != 0)
174 pm1_status_handler(struct vmctx
*ctx
, int in
,
175 int port __unused
, int bytes
, uint32_t *eax
, void *arg __unused
)
181 pthread_mutex_lock(&pm_lock
);
186 * Writes are only permitted to clear certain bits by
187 * writing 1 to those flags.
189 pm1_status
&= ~(*eax
& (PM1_WAK_STS
| PM1_RTC_STS
|
190 PM1_SLPBTN_STS
| PM1_PWRBTN_STS
| PM1_BM_STS
));
193 pthread_mutex_unlock(&pm_lock
);
198 pm1_enable_handler(struct vmctx
*ctx
, int in
,
199 int port __unused
, int bytes
, uint32_t *eax
, void *arg __unused
)
205 pthread_mutex_lock(&pm_lock
);
210 * Only permit certain bits to be set. We never use
211 * the global lock, but ACPI-CA whines profusely if it
214 pm1_enable
= *eax
& (PM1_RTC_EN
| PM1_PWRBTN_EN
| PM1_GBL_EN
);
217 pthread_mutex_unlock(&pm_lock
);
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
);
225 power_button_handler(int signal __unused
, enum ev_type type __unused
, void *arg
)
230 pthread_mutex_lock(&pm_lock
);
231 if (!(pm1_status
& PM1_PWRBTN_STS
)) {
232 pm1_status
|= PM1_PWRBTN_STS
;
235 pthread_mutex_unlock(&pm_lock
);
240 * Initiate graceful power off.
244 power_button_handler(int signal
, siginfo_t
*type
, void *cp
)
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.
258 pthread_mutex_lock(&pm_lock
);
259 if (!(pm1_status
& PM1_PWRBTN_STS
)) {
260 pm1_status
|= PM1_PWRBTN_STS
;
263 pthread_mutex_unlock(&pm_lock
);
268 * Power Management 1 Control Register
270 * This is mostly unimplemented except that we wish to handle writes that
271 * set SPL_EN to handle S5 (soft power off).
273 static uint16_t pm1_control
;
275 #define PM1_SCI_EN 0x0001
276 #define PM1_SLP_TYP 0x1c00
277 #define PM1_SLP_EN 0x2000
278 #define PM1_ALWAYS_ZERO 0xc003
281 pm1_control_handler(struct vmctx
*ctx
, int in
,
282 int port __unused
, int bytes
, uint32_t *eax
, void *arg __unused
)
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.
296 pm1_control
= (pm1_control
& PM1_SCI_EN
) |
297 (*eax
& ~(PM1_SLP_EN
| PM1_ALWAYS_ZERO
));
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.
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
);
312 INOUT_PORT(pm1_control
, PM1A_CNT_ADDR
, IOPORT_F_INOUT
, pm1_control_handler
);
314 SYSRES_IO(PM1A_EVT_ADDR
, 8);
318 acpi_raise_gpe(struct vmctx
*ctx
, unsigned bit
)
322 assert(bit
< (IO_GPE0_LEN
* (8 / 2)));
324 assert((mask
& ~gpe0_valid
) == 0);
326 pthread_mutex_lock(&pm_lock
);
329 pthread_mutex_unlock(&pm_lock
);
333 gpe0_sts(struct vmctx
*ctx
, int in
, int port __unused
,
334 int bytes
, uint32_t *eax
, void *arg __unused
)
337 * ACPI 6.2 specifies the GPE register blocks are accessed
343 pthread_mutex_lock(&pm_lock
);
348 gpe0_active
&= ~(*eax
& gpe0_valid
);
351 pthread_mutex_unlock(&pm_lock
);
354 INOUT_PORT(gpe0_sts
, IO_GPE0_STS
, IOPORT_F_INOUT
, gpe0_sts
);
357 gpe0_en(struct vmctx
*ctx
, int in
, int port __unused
,
358 int bytes
, uint32_t *eax
, void *arg __unused
)
363 pthread_mutex_lock(&pm_lock
);
367 gpe0_enabled
= (*eax
& gpe0_valid
);
370 pthread_mutex_unlock(&pm_lock
);
373 INOUT_PORT(gpe0_en
, IO_GPE0_EN
, IOPORT_F_INOUT
, gpe0_en
);
376 * ACPI SMI Command Register
378 * This write-only register is used to enable and disable ACPI.
381 smi_cmd_handler(struct vmctx
*ctx
, int in
, int port __unused
,
382 int bytes
, uint32_t *eax
, void *arg __unused
)
389 pthread_mutex_lock(&pm_lock
);
391 case BHYVE_ACPI_ENABLE
:
392 pm1_control
|= PM1_SCI_EN
;
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
);
401 case BHYVE_ACPI_DISABLE
:
402 pm1_control
&= ~PM1_SCI_EN
;
404 if (power_button
!= NULL
) {
405 mevent_delete(power_button
);
407 signal(SIGTERM
, old_power_handler
);
412 pthread_mutex_unlock(&pm_lock
);
415 INOUT_PORT(smi_cmd
, SMI_CMD
, IOPORT_F_OUT
, smi_cmd_handler
);
417 SYSRES_IO(SMI_CMD
, 1);
421 sci_init(struct vmctx
*ctx
)
425 * Mark ACPI's SCI as level trigger and bump its use count
426 * in the PIRQ router.
428 pci_irq_use(SCI_INT
);
429 vm_isa_set_irq_trigger(ctx
, SCI_INT
, LEVEL_TRIGGER
);
434 * Install SIGTERM signal handler for graceful power off.
436 struct sigaction act
;
440 act
.sa_sigaction
= power_button_handler
;
441 (void) sigaction(SIGTERM
, &act
, NULL
);
447 void pmtmr_init(struct vmctx
*ctx
)
451 /* Attach in-kernel PM timer emulation to correct IO port */
452 err
= vm_pmtmr_set_location(ctx
, IO_PMTMR
);