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