]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/bhyve/pm.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / bhyve / pm.c
1 /*-
2  * Copyright (c) 2013 Hudson River Trading LLC
3  * Written by: John H. Baldwin <jhb@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/types.h>
32 #include <machine/vmm.h>
33
34 #include <assert.h>
35 #include <errno.h>
36 #include <pthread.h>
37 #include <signal.h>
38 #include <vmmapi.h>
39
40 #include "acpi.h"
41 #include "inout.h"
42 #include "mevent.h"
43 #include "pci_irq.h"
44 #include "pci_lpc.h"
45
46 static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;
47 static struct mevent *power_button;
48 static sig_t old_power_handler;
49
50 /*
51  * Reset Control register at I/O port 0xcf9.  Bit 2 forces a system
52  * reset when it transitions from 0 to 1.  Bit 1 selects the type of
53  * reset to attempt: 0 selects a "soft" reset, and 1 selects a "hard"
54  * reset.
55  */
56 static int
57 reset_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
58     uint32_t *eax, void *arg)
59 {
60         int error;
61
62         static uint8_t reset_control;
63
64         if (bytes != 1)
65                 return (-1);
66         if (in)
67                 *eax = reset_control;
68         else {
69                 reset_control = *eax;
70
71                 /* Treat hard and soft resets the same. */
72                 if (reset_control & 0x4) {
73                         error = vm_suspend(ctx, VM_SUSPEND_RESET);
74                         assert(error == 0 || errno == EALREADY);
75                 }
76         }
77         return (0);
78 }
79 INOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler);
80
81 /*
82  * ACPI's SCI is a level-triggered interrupt.
83  */
84 static int sci_active;
85
86 static void
87 sci_assert(struct vmctx *ctx)
88 {
89
90         if (sci_active)
91                 return;
92         vm_isa_assert_irq(ctx, SCI_INT, SCI_INT);
93         sci_active = 1;
94 }
95
96 static void
97 sci_deassert(struct vmctx *ctx)
98 {
99
100         if (!sci_active)
101                 return;
102         vm_isa_deassert_irq(ctx, SCI_INT, SCI_INT);
103         sci_active = 0;
104 }
105
106 /*
107  * Power Management 1 Event Registers
108  *
109  * The only power management event supported is a power button upon
110  * receiving SIGTERM.
111  */
112 static uint16_t pm1_enable, pm1_status;
113
114 #define PM1_TMR_STS             0x0001
115 #define PM1_BM_STS              0x0010
116 #define PM1_GBL_STS             0x0020
117 #define PM1_PWRBTN_STS          0x0100
118 #define PM1_SLPBTN_STS          0x0200
119 #define PM1_RTC_STS             0x0400
120 #define PM1_WAK_STS             0x8000
121
122 #define PM1_TMR_EN              0x0001
123 #define PM1_GBL_EN              0x0020
124 #define PM1_PWRBTN_EN           0x0100
125 #define PM1_SLPBTN_EN           0x0200
126 #define PM1_RTC_EN              0x0400
127
128 static void
129 sci_update(struct vmctx *ctx)
130 {
131         int need_sci;
132
133         /* See if the SCI should be active or not. */
134         need_sci = 0;
135         if ((pm1_enable & PM1_TMR_EN) && (pm1_status & PM1_TMR_STS))
136                 need_sci = 1;
137         if ((pm1_enable & PM1_GBL_EN) && (pm1_status & PM1_GBL_STS))
138                 need_sci = 1;
139         if ((pm1_enable & PM1_PWRBTN_EN) && (pm1_status & PM1_PWRBTN_STS))
140                 need_sci = 1;
141         if ((pm1_enable & PM1_SLPBTN_EN) && (pm1_status & PM1_SLPBTN_STS))
142                 need_sci = 1;
143         if ((pm1_enable & PM1_RTC_EN) && (pm1_status & PM1_RTC_STS))
144                 need_sci = 1;
145         if (need_sci)
146                 sci_assert(ctx);
147         else
148                 sci_deassert(ctx);
149 }
150
151 static int
152 pm1_status_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
153     uint32_t *eax, void *arg)
154 {
155
156         if (bytes != 2)
157                 return (-1);
158
159         pthread_mutex_lock(&pm_lock);
160         if (in)
161                 *eax = pm1_status;
162         else {
163                 /*
164                  * Writes are only permitted to clear certain bits by
165                  * writing 1 to those flags.
166                  */
167                 pm1_status &= ~(*eax & (PM1_WAK_STS | PM1_RTC_STS |
168                     PM1_SLPBTN_STS | PM1_PWRBTN_STS | PM1_BM_STS));
169                 sci_update(ctx);
170         }
171         pthread_mutex_unlock(&pm_lock);
172         return (0);
173 }
174
175 static int
176 pm1_enable_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
177     uint32_t *eax, void *arg)
178 {
179
180         if (bytes != 2)
181                 return (-1);
182
183         pthread_mutex_lock(&pm_lock);
184         if (in)
185                 *eax = pm1_enable;
186         else {
187                 /*
188                  * Only permit certain bits to be set.  We never use
189                  * the global lock, but ACPI-CA whines profusely if it
190                  * can't set GBL_EN.
191                  */
192                 pm1_enable = *eax & (PM1_PWRBTN_EN | PM1_GBL_EN);
193                 sci_update(ctx);
194         }
195         pthread_mutex_unlock(&pm_lock);
196         return (0);
197 }
198 INOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler);
199 INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler);
200
201 static void
202 power_button_handler(int signal, enum ev_type type, void *arg)
203 {
204         struct vmctx *ctx;
205
206         ctx = arg;
207         pthread_mutex_lock(&pm_lock);
208         if (!(pm1_status & PM1_PWRBTN_STS)) {
209                 pm1_status |= PM1_PWRBTN_STS;
210                 sci_update(ctx);
211         }
212         pthread_mutex_unlock(&pm_lock);
213 }
214
215 /*
216  * Power Management 1 Control Register
217  *
218  * This is mostly unimplemented except that we wish to handle writes that
219  * set SPL_EN to handle S5 (soft power off).
220  */
221 static uint16_t pm1_control;
222
223 #define PM1_SCI_EN      0x0001
224 #define PM1_SLP_TYP     0x1c00
225 #define PM1_SLP_EN      0x2000
226 #define PM1_ALWAYS_ZERO 0xc003
227
228 static int
229 pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
230     uint32_t *eax, void *arg)
231 {
232         int error;
233
234         if (bytes != 2)
235                 return (-1);
236         if (in)
237                 *eax = pm1_control;
238         else {
239                 /*
240                  * Various bits are write-only or reserved, so force them
241                  * to zero in pm1_control.  Always preserve SCI_EN as OSPM
242                  * can never change it.
243                  */
244                 pm1_control = (pm1_control & PM1_SCI_EN) |
245                     (*eax & ~(PM1_SLP_EN | PM1_ALWAYS_ZERO));
246
247                 /*
248                  * If SLP_EN is set, check for S5.  Bhyve's _S5_ method
249                  * says that '5' should be stored in SLP_TYP for S5.
250                  */
251                 if (*eax & PM1_SLP_EN) {
252                         if ((pm1_control & PM1_SLP_TYP) >> 10 == 5) {
253                                 error = vm_suspend(ctx, VM_SUSPEND_POWEROFF);
254                                 assert(error == 0 || errno == EALREADY);
255                         }
256                 }
257         }
258         return (0);
259 }
260 INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);
261 SYSRES_IO(PM1A_EVT_ADDR, 8);
262
263 /*
264  * ACPI SMI Command Register
265  *
266  * This write-only register is used to enable and disable ACPI.
267  */
268 static int
269 smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
270     uint32_t *eax, void *arg)
271 {
272
273         assert(!in);
274         if (bytes != 1)
275                 return (-1);
276
277         pthread_mutex_lock(&pm_lock);
278         switch (*eax) {
279         case BHYVE_ACPI_ENABLE:
280                 pm1_control |= PM1_SCI_EN;
281                 if (power_button == NULL) {
282                         power_button = mevent_add(SIGTERM, EVF_SIGNAL,
283                             power_button_handler, ctx);
284                         old_power_handler = signal(SIGTERM, SIG_IGN);
285                 }
286                 break;
287         case BHYVE_ACPI_DISABLE:
288                 pm1_control &= ~PM1_SCI_EN;
289                 if (power_button != NULL) {
290                         mevent_delete(power_button);
291                         power_button = NULL;
292                         signal(SIGTERM, old_power_handler);
293                 }
294                 break;
295         }
296         pthread_mutex_unlock(&pm_lock);
297         return (0);
298 }
299 INOUT_PORT(smi_cmd, SMI_CMD, IOPORT_F_OUT, smi_cmd_handler);
300 SYSRES_IO(SMI_CMD, 1);
301
302 void
303 sci_init(struct vmctx *ctx)
304 {
305
306         /*
307          * Mark ACPI's SCI as level trigger and bump its use count
308          * in the PIRQ router.
309          */
310         pci_irq_use(SCI_INT);
311         vm_isa_set_irq_trigger(ctx, SCI_INT, LEVEL_TRIGGER);
312 }