xref: /illumos-gate/usr/src/cmd/bhyve/pm.c (revision 32640292)
1bf21cd93STycho Nightingale /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick Mooney  *
44c87aefeSPatrick Mooney  * Copyright (c) 2013 Hudson River Trading LLC
5bf21cd93STycho Nightingale  * Written by: John H. Baldwin <jhb@FreeBSD.org>
6bf21cd93STycho Nightingale  * All rights reserved.
7bf21cd93STycho Nightingale  *
8bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
9bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
10bf21cd93STycho Nightingale  * are met:
11bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
12bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
13bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
14bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
15bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
16bf21cd93STycho Nightingale  *
17bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27bf21cd93STycho Nightingale  * SUCH DAMAGE.
28bf21cd93STycho Nightingale  */
294c87aefeSPatrick Mooney /*
304c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
310e1453c3SPatrick Mooney  * Copyright 2020 Oxide Computer Company
324c87aefeSPatrick Mooney  */
33bf21cd93STycho Nightingale 
34bf21cd93STycho Nightingale #include <sys/cdefs.h>
35bf21cd93STycho Nightingale 
36bf21cd93STycho Nightingale #include <sys/types.h>
37bf21cd93STycho Nightingale #include <machine/vmm.h>
38bf21cd93STycho Nightingale 
39bf21cd93STycho Nightingale #include <assert.h>
404c87aefeSPatrick Mooney #include <errno.h>
41bf21cd93STycho Nightingale #include <pthread.h>
42bf21cd93STycho Nightingale #ifndef	__FreeBSD__
43bf21cd93STycho Nightingale #include <stdlib.h>
44bf21cd93STycho Nightingale #endif
45bf21cd93STycho Nightingale #include <signal.h>
46bf21cd93STycho Nightingale #include <vmmapi.h>
47bf21cd93STycho Nightingale 
48bf21cd93STycho Nightingale #include "acpi.h"
49bf21cd93STycho Nightingale #include "inout.h"
50bf21cd93STycho Nightingale #ifdef	__FreeBSD__
51bf21cd93STycho Nightingale #include "mevent.h"
52bf21cd93STycho Nightingale #endif
53bf21cd93STycho Nightingale #include "pci_irq.h"
54bf21cd93STycho Nightingale #include "pci_lpc.h"
55bf21cd93STycho Nightingale 
56bf21cd93STycho Nightingale static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;
57bf21cd93STycho Nightingale #ifdef	__FreeBSD__
58bf21cd93STycho Nightingale static struct mevent *power_button;
59bf21cd93STycho Nightingale static sig_t old_power_handler;
604c87aefeSPatrick Mooney #else
614c87aefeSPatrick Mooney struct vmctx *pwr_ctx;
62bf21cd93STycho Nightingale #endif
63bf21cd93STycho Nightingale 
64154972afSPatrick Mooney static unsigned gpe0_active;
65154972afSPatrick Mooney static unsigned gpe0_enabled;
66154972afSPatrick Mooney static const unsigned gpe0_valid = (1u << GPE_VMGENC);
67154972afSPatrick Mooney 
68bf21cd93STycho Nightingale /*
69bf21cd93STycho Nightingale  * Reset Control register at I/O port 0xcf9.  Bit 2 forces a system
70bf21cd93STycho Nightingale  * reset when it transitions from 0 to 1.  Bit 1 selects the type of
71bf21cd93STycho Nightingale  * reset to attempt: 0 selects a "soft" reset, and 1 selects a "hard"
72bf21cd93STycho Nightingale  * reset.
73bf21cd93STycho Nightingale  */
74bf21cd93STycho Nightingale static int
reset_handler(struct vmctx * ctx __unused,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)7559d65d31SAndy Fiddaman reset_handler(struct vmctx *ctx __unused, int in,
7659d65d31SAndy Fiddaman     int port __unused, int bytes, uint32_t *eax, void *arg __unused)
77bf21cd93STycho Nightingale {
784c87aefeSPatrick Mooney 	int error;
794c87aefeSPatrick Mooney 
80bf21cd93STycho Nightingale 	static uint8_t reset_control;
81bf21cd93STycho Nightingale 
82bf21cd93STycho Nightingale 	if (bytes != 1)
83bf21cd93STycho Nightingale 		return (-1);
84bf21cd93STycho Nightingale 	if (in)
85bf21cd93STycho Nightingale 		*eax = reset_control;
86bf21cd93STycho Nightingale 	else {
87bf21cd93STycho Nightingale 		reset_control = *eax;
88bf21cd93STycho Nightingale 
89bf21cd93STycho Nightingale 		/* Treat hard and soft resets the same. */
90bf21cd93STycho Nightingale 		if (reset_control & 0x4) {
91bf21cd93STycho Nightingale 			error = vm_suspend(ctx, VM_SUSPEND_RESET);
92bf21cd93STycho Nightingale 			assert(error == 0 || errno == EALREADY);
93bf21cd93STycho Nightingale 		}
94bf21cd93STycho Nightingale 	}
95bf21cd93STycho Nightingale 	return (0);
96bf21cd93STycho Nightingale }
97bf21cd93STycho Nightingale INOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler);
98bf21cd93STycho Nightingale 
99bf21cd93STycho Nightingale /*
100bf21cd93STycho Nightingale  * ACPI's SCI is a level-triggered interrupt.
101bf21cd93STycho Nightingale  */
102bf21cd93STycho Nightingale static int sci_active;
103bf21cd93STycho Nightingale 
104bf21cd93STycho Nightingale static void
sci_assert(struct vmctx * ctx)105bf21cd93STycho Nightingale sci_assert(struct vmctx *ctx)
106bf21cd93STycho Nightingale {
107bf21cd93STycho Nightingale 
108bf21cd93STycho Nightingale 	if (sci_active)
109bf21cd93STycho Nightingale 		return;
110bf21cd93STycho Nightingale 	vm_isa_assert_irq(ctx, SCI_INT, SCI_INT);
111bf21cd93STycho Nightingale 	sci_active = 1;
112bf21cd93STycho Nightingale }
113bf21cd93STycho Nightingale 
114bf21cd93STycho Nightingale static void
sci_deassert(struct vmctx * ctx)115bf21cd93STycho Nightingale sci_deassert(struct vmctx *ctx)
116bf21cd93STycho Nightingale {
117bf21cd93STycho Nightingale 
118bf21cd93STycho Nightingale 	if (!sci_active)
119bf21cd93STycho Nightingale 		return;
120bf21cd93STycho Nightingale 	vm_isa_deassert_irq(ctx, SCI_INT, SCI_INT);
121bf21cd93STycho Nightingale 	sci_active = 0;
122bf21cd93STycho Nightingale }
123bf21cd93STycho Nightingale 
124bf21cd93STycho Nightingale /*
125bf21cd93STycho Nightingale  * Power Management 1 Event Registers
126bf21cd93STycho Nightingale  *
127bf21cd93STycho Nightingale  * The only power management event supported is a power button upon
128bf21cd93STycho Nightingale  * receiving SIGTERM.
129bf21cd93STycho Nightingale  */
130bf21cd93STycho Nightingale static uint16_t pm1_enable, pm1_status;
131bf21cd93STycho Nightingale 
132bf21cd93STycho Nightingale #define	PM1_TMR_STS		0x0001
133bf21cd93STycho Nightingale #define	PM1_BM_STS		0x0010
134bf21cd93STycho Nightingale #define	PM1_GBL_STS		0x0020
135bf21cd93STycho Nightingale #define	PM1_PWRBTN_STS		0x0100
136bf21cd93STycho Nightingale #define	PM1_SLPBTN_STS		0x0200
137bf21cd93STycho Nightingale #define	PM1_RTC_STS		0x0400
138bf21cd93STycho Nightingale #define	PM1_WAK_STS		0x8000
139bf21cd93STycho Nightingale 
140bf21cd93STycho Nightingale #define	PM1_TMR_EN		0x0001
141bf21cd93STycho Nightingale #define	PM1_GBL_EN		0x0020
142bf21cd93STycho Nightingale #define	PM1_PWRBTN_EN		0x0100
143bf21cd93STycho Nightingale #define	PM1_SLPBTN_EN		0x0200
144bf21cd93STycho Nightingale #define	PM1_RTC_EN		0x0400
145bf21cd93STycho Nightingale 
146bf21cd93STycho Nightingale static void
sci_update(struct vmctx * ctx)147bf21cd93STycho Nightingale sci_update(struct vmctx *ctx)
148bf21cd93STycho Nightingale {
149bf21cd93STycho Nightingale 	int need_sci;
150bf21cd93STycho Nightingale 
151bf21cd93STycho Nightingale 	/* See if the SCI should be active or not. */
152bf21cd93STycho Nightingale 	need_sci = 0;
153bf21cd93STycho Nightingale 	if ((pm1_enable & PM1_TMR_EN) && (pm1_status & PM1_TMR_STS))
154bf21cd93STycho Nightingale 		need_sci = 1;
155bf21cd93STycho Nightingale 	if ((pm1_enable & PM1_GBL_EN) && (pm1_status & PM1_GBL_STS))
156bf21cd93STycho Nightingale 		need_sci = 1;
157bf21cd93STycho Nightingale 	if ((pm1_enable & PM1_PWRBTN_EN) && (pm1_status & PM1_PWRBTN_STS))
158bf21cd93STycho Nightingale 		need_sci = 1;
159bf21cd93STycho Nightingale 	if ((pm1_enable & PM1_SLPBTN_EN) && (pm1_status & PM1_SLPBTN_STS))
160bf21cd93STycho Nightingale 		need_sci = 1;
161bf21cd93STycho Nightingale 	if ((pm1_enable & PM1_RTC_EN) && (pm1_status & PM1_RTC_STS))
162bf21cd93STycho Nightingale 		need_sci = 1;
163154972afSPatrick Mooney 	if ((gpe0_enabled & gpe0_active) != 0)
164154972afSPatrick Mooney 		need_sci = 1;
165154972afSPatrick Mooney 
166bf21cd93STycho Nightingale 	if (need_sci)
167bf21cd93STycho Nightingale 		sci_assert(ctx);
168bf21cd93STycho Nightingale 	else
169bf21cd93STycho Nightingale 		sci_deassert(ctx);
170bf21cd93STycho Nightingale }
171bf21cd93STycho Nightingale 
172bf21cd93STycho Nightingale static int
pm1_status_handler(struct vmctx * ctx,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)17359d65d31SAndy Fiddaman pm1_status_handler(struct vmctx *ctx, int in,
17459d65d31SAndy Fiddaman     int port __unused, int bytes, uint32_t *eax, void *arg __unused)
175bf21cd93STycho Nightingale {
176bf21cd93STycho Nightingale 
177bf21cd93STycho Nightingale 	if (bytes != 2)
178bf21cd93STycho Nightingale 		return (-1);
179bf21cd93STycho Nightingale 
180bf21cd93STycho Nightingale 	pthread_mutex_lock(&pm_lock);
181bf21cd93STycho Nightingale 	if (in)
182bf21cd93STycho Nightingale 		*eax = pm1_status;
183bf21cd93STycho Nightingale 	else {
184bf21cd93STycho Nightingale 		/*
185bf21cd93STycho Nightingale 		 * Writes are only permitted to clear certain bits by
186bf21cd93STycho Nightingale 		 * writing 1 to those flags.
187bf21cd93STycho Nightingale 		 */
188bf21cd93STycho Nightingale 		pm1_status &= ~(*eax & (PM1_WAK_STS | PM1_RTC_STS |
189bf21cd93STycho Nightingale 		    PM1_SLPBTN_STS | PM1_PWRBTN_STS | PM1_BM_STS));
190bf21cd93STycho Nightingale 		sci_update(ctx);
191bf21cd93STycho Nightingale 	}
192bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pm_lock);
193bf21cd93STycho Nightingale 	return (0);
194bf21cd93STycho Nightingale }
195bf21cd93STycho Nightingale 
196bf21cd93STycho Nightingale static int
pm1_enable_handler(struct vmctx * ctx,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)19759d65d31SAndy Fiddaman pm1_enable_handler(struct vmctx *ctx, int in,
19859d65d31SAndy Fiddaman     int port __unused, int bytes, uint32_t *eax, void *arg __unused)
199bf21cd93STycho Nightingale {
200bf21cd93STycho Nightingale 
201bf21cd93STycho Nightingale 	if (bytes != 2)
202bf21cd93STycho Nightingale 		return (-1);
203bf21cd93STycho Nightingale 
204bf21cd93STycho Nightingale 	pthread_mutex_lock(&pm_lock);
205bf21cd93STycho Nightingale 	if (in)
206bf21cd93STycho Nightingale 		*eax = pm1_enable;
207bf21cd93STycho Nightingale 	else {
208bf21cd93STycho Nightingale 		/*
209bf21cd93STycho Nightingale 		 * Only permit certain bits to be set.  We never use
210bf21cd93STycho Nightingale 		 * the global lock, but ACPI-CA whines profusely if it
211bf21cd93STycho Nightingale 		 * can't set GBL_EN.
212bf21cd93STycho Nightingale 		 */
2136960cd89SAndy Fiddaman 		pm1_enable = *eax & (PM1_RTC_EN | PM1_PWRBTN_EN | PM1_GBL_EN);
214bf21cd93STycho Nightingale 		sci_update(ctx);
215bf21cd93STycho Nightingale 	}
216bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pm_lock);
217bf21cd93STycho Nightingale 	return (0);
218bf21cd93STycho Nightingale }
219bf21cd93STycho Nightingale INOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler);
220bf21cd93STycho Nightingale INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler);
221bf21cd93STycho Nightingale 
222bf21cd93STycho Nightingale #ifdef	__FreeBSD__
223bf21cd93STycho Nightingale static void
power_button_handler(int signal __unused,enum ev_type type __unused,void * arg)22459d65d31SAndy Fiddaman power_button_handler(int signal __unused, enum ev_type type __unused, void *arg)
225bf21cd93STycho Nightingale {
226bf21cd93STycho Nightingale 	struct vmctx *ctx;
227bf21cd93STycho Nightingale 
228bf21cd93STycho Nightingale 	ctx = arg;
229bf21cd93STycho Nightingale 	pthread_mutex_lock(&pm_lock);
230bf21cd93STycho Nightingale 	if (!(pm1_status & PM1_PWRBTN_STS)) {
231bf21cd93STycho Nightingale 		pm1_status |= PM1_PWRBTN_STS;
232bf21cd93STycho Nightingale 		sci_update(ctx);
233bf21cd93STycho Nightingale 	}
234bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pm_lock);
235bf21cd93STycho Nightingale }
2364c87aefeSPatrick Mooney 
2374c87aefeSPatrick Mooney #else
2384c87aefeSPatrick Mooney /*
2394c87aefeSPatrick Mooney  * Initiate graceful power off.
2404c87aefeSPatrick Mooney  */
2414c87aefeSPatrick Mooney /*ARGSUSED*/
2424c87aefeSPatrick Mooney static void
power_button_handler(int signal,siginfo_t * type,void * cp)2434c87aefeSPatrick Mooney power_button_handler(int signal, siginfo_t *type, void *cp)
2444c87aefeSPatrick Mooney {
2454c87aefeSPatrick Mooney 	/*
2464c87aefeSPatrick Mooney 	 * In theory, taking the 'pm_lock' mutex from within this signal
2474c87aefeSPatrick Mooney 	 * handler could lead to deadlock if the main thread already held this
2484c87aefeSPatrick Mooney 	 * mutex. In reality, this mutex is local to this file and all of the
2494c87aefeSPatrick Mooney 	 * other usage in this file only occurs in functions which are FreeBSD
2504c87aefeSPatrick Mooney 	 * specific (and thus currently not used). Thus, for consistency with
2514c87aefeSPatrick Mooney 	 * the other code in this file, we take the mutex, but in the future,
2524c87aefeSPatrick Mooney 	 * if these other functions are ever enabled for use on non-FreeBSD
2534c87aefeSPatrick Mooney 	 * systems and these functions could be called directly by a thread
2544c87aefeSPatrick Mooney 	 * (which would then hold the mutex), then we need to revisit the use
2554c87aefeSPatrick Mooney 	 * of this mutex in this signal handler.
2564c87aefeSPatrick Mooney 	 */
2574c87aefeSPatrick Mooney 	pthread_mutex_lock(&pm_lock);
2584c87aefeSPatrick Mooney 	if (!(pm1_status & PM1_PWRBTN_STS)) {
2594c87aefeSPatrick Mooney 		pm1_status |= PM1_PWRBTN_STS;
2604c87aefeSPatrick Mooney 		sci_update(pwr_ctx);
2614c87aefeSPatrick Mooney 	}
2624c87aefeSPatrick Mooney 	pthread_mutex_unlock(&pm_lock);
2634c87aefeSPatrick Mooney }
264bf21cd93STycho Nightingale #endif
265bf21cd93STycho Nightingale 
266bf21cd93STycho Nightingale /*
267bf21cd93STycho Nightingale  * Power Management 1 Control Register
268bf21cd93STycho Nightingale  *
269bf21cd93STycho Nightingale  * This is mostly unimplemented except that we wish to handle writes that
270bf21cd93STycho Nightingale  * set SPL_EN to handle S5 (soft power off).
271bf21cd93STycho Nightingale  */
272bf21cd93STycho Nightingale static uint16_t pm1_control;
273bf21cd93STycho Nightingale 
274bf21cd93STycho Nightingale #define	PM1_SCI_EN	0x0001
275bf21cd93STycho Nightingale #define	PM1_SLP_TYP	0x1c00
276bf21cd93STycho Nightingale #define	PM1_SLP_EN	0x2000
277bf21cd93STycho Nightingale #define	PM1_ALWAYS_ZERO	0xc003
278bf21cd93STycho Nightingale 
279bf21cd93STycho Nightingale static int
pm1_control_handler(struct vmctx * ctx,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)28059d65d31SAndy Fiddaman pm1_control_handler(struct vmctx *ctx, int in,
28159d65d31SAndy Fiddaman     int port __unused, int bytes, uint32_t *eax, void *arg __unused)
282bf21cd93STycho Nightingale {
2834c87aefeSPatrick Mooney 	int error;
284bf21cd93STycho Nightingale 
285bf21cd93STycho Nightingale 	if (bytes != 2)
286bf21cd93STycho Nightingale 		return (-1);
287bf21cd93STycho Nightingale 	if (in)
288bf21cd93STycho Nightingale 		*eax = pm1_control;
289bf21cd93STycho Nightingale 	else {
290bf21cd93STycho Nightingale 		/*
291bf21cd93STycho Nightingale 		 * Various bits are write-only or reserved, so force them
292bf21cd93STycho Nightingale 		 * to zero in pm1_control.  Always preserve SCI_EN as OSPM
293bf21cd93STycho Nightingale 		 * can never change it.
294bf21cd93STycho Nightingale 		 */
295bf21cd93STycho Nightingale 		pm1_control = (pm1_control & PM1_SCI_EN) |
296bf21cd93STycho Nightingale 		    (*eax & ~(PM1_SLP_EN | PM1_ALWAYS_ZERO));
297bf21cd93STycho Nightingale 
298bf21cd93STycho Nightingale 		/*
299bf21cd93STycho Nightingale 		 * If SLP_EN is set, check for S5.  Bhyve's _S5_ method
300bf21cd93STycho Nightingale 		 * says that '5' should be stored in SLP_TYP for S5.
301bf21cd93STycho Nightingale 		 */
302bf21cd93STycho Nightingale 		if (*eax & PM1_SLP_EN) {
303bf21cd93STycho Nightingale 			if ((pm1_control & PM1_SLP_TYP) >> 10 == 5) {
304bf21cd93STycho Nightingale 				error = vm_suspend(ctx, VM_SUSPEND_POWEROFF);
305bf21cd93STycho Nightingale 				assert(error == 0 || errno == EALREADY);
306bf21cd93STycho Nightingale 			}
307bf21cd93STycho Nightingale 		}
308bf21cd93STycho Nightingale 	}
309bf21cd93STycho Nightingale 	return (0);
310bf21cd93STycho Nightingale }
311bf21cd93STycho Nightingale INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);
312bf21cd93STycho Nightingale #ifdef	__FreeBSD__
313bf21cd93STycho Nightingale SYSRES_IO(PM1A_EVT_ADDR, 8);
314bf21cd93STycho Nightingale #endif
315bf21cd93STycho Nightingale 
316154972afSPatrick Mooney void
acpi_raise_gpe(struct vmctx * ctx,unsigned bit)317154972afSPatrick Mooney acpi_raise_gpe(struct vmctx *ctx, unsigned bit)
318154972afSPatrick Mooney {
319154972afSPatrick Mooney 	unsigned mask;
320154972afSPatrick Mooney 
321154972afSPatrick Mooney 	assert(bit < (IO_GPE0_LEN * (8 / 2)));
322154972afSPatrick Mooney 	mask = (1u << bit);
323154972afSPatrick Mooney 	assert((mask & ~gpe0_valid) == 0);
324154972afSPatrick Mooney 
325154972afSPatrick Mooney 	pthread_mutex_lock(&pm_lock);
326154972afSPatrick Mooney 	gpe0_active |= mask;
327154972afSPatrick Mooney 	sci_update(ctx);
328154972afSPatrick Mooney 	pthread_mutex_unlock(&pm_lock);
329154972afSPatrick Mooney }
330154972afSPatrick Mooney 
331154972afSPatrick Mooney static int
gpe0_sts(struct vmctx * ctx,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)33259d65d31SAndy Fiddaman gpe0_sts(struct vmctx *ctx, int in, int port __unused,
33359d65d31SAndy Fiddaman     int bytes, uint32_t *eax, void *arg __unused)
334154972afSPatrick Mooney {
335154972afSPatrick Mooney 	/*
336154972afSPatrick Mooney 	 * ACPI 6.2 specifies the GPE register blocks are accessed
337154972afSPatrick Mooney 	 * byte-at-a-time.
338154972afSPatrick Mooney 	 */
339154972afSPatrick Mooney 	if (bytes != 1)
340154972afSPatrick Mooney 		return (-1);
341154972afSPatrick Mooney 
342154972afSPatrick Mooney 	pthread_mutex_lock(&pm_lock);
343154972afSPatrick Mooney 	if (in)
344154972afSPatrick Mooney 		*eax = gpe0_active;
345154972afSPatrick Mooney 	else {
346154972afSPatrick Mooney 		/* W1C */
347154972afSPatrick Mooney 		gpe0_active &= ~(*eax & gpe0_valid);
348154972afSPatrick Mooney 		sci_update(ctx);
349154972afSPatrick Mooney 	}
350154972afSPatrick Mooney 	pthread_mutex_unlock(&pm_lock);
351154972afSPatrick Mooney 	return (0);
352154972afSPatrick Mooney }
353154972afSPatrick Mooney INOUT_PORT(gpe0_sts, IO_GPE0_STS, IOPORT_F_INOUT, gpe0_sts);
354154972afSPatrick Mooney 
355154972afSPatrick Mooney static int
gpe0_en(struct vmctx * ctx,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)35659d65d31SAndy Fiddaman gpe0_en(struct vmctx *ctx, int in, int port __unused,
35759d65d31SAndy Fiddaman     int bytes, uint32_t *eax, void *arg __unused)
358154972afSPatrick Mooney {
359154972afSPatrick Mooney 	if (bytes != 1)
360154972afSPatrick Mooney 		return (-1);
361154972afSPatrick Mooney 
362154972afSPatrick Mooney 	pthread_mutex_lock(&pm_lock);
363154972afSPatrick Mooney 	if (in)
364154972afSPatrick Mooney 		*eax = gpe0_enabled;
365154972afSPatrick Mooney 	else {
366154972afSPatrick Mooney 		gpe0_enabled = (*eax & gpe0_valid);
367154972afSPatrick Mooney 		sci_update(ctx);
368154972afSPatrick Mooney 	}
369154972afSPatrick Mooney 	pthread_mutex_unlock(&pm_lock);
370154972afSPatrick Mooney 	return (0);
371154972afSPatrick Mooney }
372154972afSPatrick Mooney INOUT_PORT(gpe0_en, IO_GPE0_EN, IOPORT_F_INOUT, gpe0_en);
373154972afSPatrick Mooney 
374bf21cd93STycho Nightingale /*
375bf21cd93STycho Nightingale  * ACPI SMI Command Register
376bf21cd93STycho Nightingale  *
377bf21cd93STycho Nightingale  * This write-only register is used to enable and disable ACPI.
378bf21cd93STycho Nightingale  */
379bf21cd93STycho Nightingale static int
smi_cmd_handler(struct vmctx * ctx,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)38059d65d31SAndy Fiddaman smi_cmd_handler(struct vmctx *ctx, int in, int port __unused,
38159d65d31SAndy Fiddaman     int bytes, uint32_t *eax, void *arg __unused)
382bf21cd93STycho Nightingale {
383bf21cd93STycho Nightingale 
384bf21cd93STycho Nightingale 	assert(!in);
385bf21cd93STycho Nightingale 	if (bytes != 1)
386bf21cd93STycho Nightingale 		return (-1);
387bf21cd93STycho Nightingale 
388bf21cd93STycho Nightingale 	pthread_mutex_lock(&pm_lock);
389bf21cd93STycho Nightingale 	switch (*eax) {
390bf21cd93STycho Nightingale 	case BHYVE_ACPI_ENABLE:
391bf21cd93STycho Nightingale 		pm1_control |= PM1_SCI_EN;
392bf21cd93STycho Nightingale #ifdef	__FreeBSD__
393bf21cd93STycho Nightingale 		if (power_button == NULL) {
394bf21cd93STycho Nightingale 			power_button = mevent_add(SIGTERM, EVF_SIGNAL,
395bf21cd93STycho Nightingale 			    power_button_handler, ctx);
396bf21cd93STycho Nightingale 			old_power_handler = signal(SIGTERM, SIG_IGN);
397bf21cd93STycho Nightingale 		}
398bf21cd93STycho Nightingale #endif
399bf21cd93STycho Nightingale 		break;
400bf21cd93STycho Nightingale 	case BHYVE_ACPI_DISABLE:
401bf21cd93STycho Nightingale 		pm1_control &= ~PM1_SCI_EN;
402bf21cd93STycho Nightingale #ifdef	__FreeBSD__
403bf21cd93STycho Nightingale 		if (power_button != NULL) {
404bf21cd93STycho Nightingale 			mevent_delete(power_button);
405bf21cd93STycho Nightingale 			power_button = NULL;
406bf21cd93STycho Nightingale 			signal(SIGTERM, old_power_handler);
407bf21cd93STycho Nightingale 		}
408bf21cd93STycho Nightingale #endif
409bf21cd93STycho Nightingale 		break;
410bf21cd93STycho Nightingale 	}
411bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pm_lock);
412bf21cd93STycho Nightingale 	return (0);
413bf21cd93STycho Nightingale }
414bf21cd93STycho Nightingale INOUT_PORT(smi_cmd, SMI_CMD, IOPORT_F_OUT, smi_cmd_handler);
415bf21cd93STycho Nightingale #ifdef	__FreeBSD__
416bf21cd93STycho Nightingale SYSRES_IO(SMI_CMD, 1);
417bf21cd93STycho Nightingale #endif
418bf21cd93STycho Nightingale 
419bf21cd93STycho Nightingale void
sci_init(struct vmctx * ctx)420bf21cd93STycho Nightingale sci_init(struct vmctx *ctx)
421bf21cd93STycho Nightingale {
422bf21cd93STycho Nightingale 
423bf21cd93STycho Nightingale 	/*
424bf21cd93STycho Nightingale 	 * Mark ACPI's SCI as level trigger and bump its use count
425bf21cd93STycho Nightingale 	 * in the PIRQ router.
426bf21cd93STycho Nightingale 	 */
427bf21cd93STycho Nightingale 	pci_irq_use(SCI_INT);
428bf21cd93STycho Nightingale 	vm_isa_set_irq_trigger(ctx, SCI_INT, LEVEL_TRIGGER);
4294c87aefeSPatrick Mooney 
4304c87aefeSPatrick Mooney #ifndef	__FreeBSD__
4314c87aefeSPatrick Mooney 	{
4324c87aefeSPatrick Mooney 		/*
4334c87aefeSPatrick Mooney 		 * Install SIGTERM signal handler for graceful power off.
4344c87aefeSPatrick Mooney 		 */
4354c87aefeSPatrick Mooney 		struct sigaction act;
4364c87aefeSPatrick Mooney 
4374c87aefeSPatrick Mooney 		pwr_ctx = ctx;
4384c87aefeSPatrick Mooney 		act.sa_flags = 0;
4394c87aefeSPatrick Mooney 		act.sa_sigaction = power_button_handler;
4404c87aefeSPatrick Mooney 		(void) sigaction(SIGTERM, &act, NULL);
4414c87aefeSPatrick Mooney 	}
4424c87aefeSPatrick Mooney #endif
443bf21cd93STycho Nightingale }
4440e1453c3SPatrick Mooney 
4450e1453c3SPatrick Mooney #ifndef	__FreeBSD__
pmtmr_init(struct vmctx * ctx)4460e1453c3SPatrick Mooney void pmtmr_init(struct vmctx *ctx)
4470e1453c3SPatrick Mooney {
4480e1453c3SPatrick Mooney 	int err;
4490e1453c3SPatrick Mooney 
4500e1453c3SPatrick Mooney 	/* Attach in-kernel PM timer emulation to correct IO port */
4510e1453c3SPatrick Mooney 	err = vm_pmtmr_set_location(ctx, IO_PMTMR);
4520e1453c3SPatrick Mooney 	assert(err == 0);
4530e1453c3SPatrick Mooney }
4540e1453c3SPatrick Mooney #endif
455