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 #include <sys/types.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <pthread.h>
33 #include <signal.h>
34 #include <stdbool.h>
35 #include <pthread.h>
36 
37 #include "vmmapi.h"
38 #include "acpi.h"
39 #include "inout.h"
40 #include "mevent.h"
41 #include "irq.h"
42 #include "lpc.h"
43 #include "monitor.h"
44 #include "log.h"
45 #include "vm_event.h"
46 
47 static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;
48 static struct mevent *power_button;
49 static sig_t old_power_handler;
50 
51 /*
52  * Reset Control register at I/O port 0xcf9.  Bit 2 forces a system
53  * reset when it transitions from 0 to 1.  Bit 1 selects the type of
54  * reset to attempt: 0 selects a "soft" reset, and 1 selects a "hard"
55  * reset.
56  */
57 static int
reset_handler(struct vmctx * ctx,int vcpu,int in,int port,int bytes,uint32_t * eax,void * arg)58 reset_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
59 	      uint32_t *eax, void *arg)
60 {
61 	static uint8_t reset_control;
62 
63 	if (bytes != 1)
64 		return -1;
65 	if (in)
66 		*eax = reset_control;
67 	else {
68 		reset_control = *eax;
69 
70 		if (*eax & 0x8) {
71 			pr_notice("full reset\r\n");
72 			vm_suspend(ctx, VM_SUSPEND_FULL_RESET);
73 			mevent_notify();
74 			reset_control = 0;
75 		} else if (*eax & 0x4) {
76 			pr_notice("system reset\r\n");
77 			vm_suspend(ctx, VM_SUSPEND_SYSTEM_RESET);
78 			mevent_notify();
79 		}
80 	}
81 	return 0;
82 }
83 INOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler);
84 
85 /*
86  * ACPI's SCI is a level-triggered interrupt.
87  */
88 static int sci_active;
89 
90 static void
sci_assert(struct vmctx * ctx)91 sci_assert(struct vmctx *ctx)
92 {
93 	if (sci_active)
94 		return;
95 	vm_set_gsi_irq(ctx, SCI_INT, GSI_SET_HIGH);
96 	sci_active = 1;
97 }
98 
99 static void
sci_deassert(struct vmctx * ctx)100 sci_deassert(struct vmctx *ctx)
101 {
102 	if (!sci_active)
103 		return;
104 	vm_set_gsi_irq(ctx, SCI_INT, GSI_SET_LOW);
105 	sci_active = 0;
106 }
107 
108 /*
109  * Power Management 1 Event Registers
110  *
111  * The only power management event supported is a power button upon
112  * receiving SIGTERM.
113  */
114 static uint16_t pm1_enable, pm1_status;
115 
116 #define	PM1_TMR_STS		0x0001
117 #define	PM1_BM_STS		0x0010
118 #define	PM1_GBL_STS		0x0020
119 #define	PM1_PWRBTN_STS		0x0100
120 #define	PM1_SLPBTN_STS		0x0200
121 #define	PM1_RTC_STS		0x0400
122 #define	PM1_WAK_STS		0x8000
123 
124 #define	PM1_TMR_EN		0x0001
125 #define	PM1_GBL_EN		0x0020
126 #define	PM1_PWRBTN_EN		0x0100
127 #define	PM1_SLPBTN_EN		0x0200
128 #define	PM1_RTC_EN		0x0400
129 
130 /*
131  * Power Management 1 Control Register
132  *
133  * This is mostly unimplemented except that we wish to handle writes that
134  * set SPL_EN to handle S5 (soft power off).
135  */
136 static uint16_t pm1_control;
137 
138 static void
sci_update(struct vmctx * ctx)139 sci_update(struct vmctx *ctx)
140 {
141 	int need_sci;
142 
143 	/*
144 	 * Followed ACPI spec, should trigger SMI if SCI_EN is zero.
145 	 * Return directly due to ACRN do not support SMI so far.
146 	 */
147 	if (!(pm1_control & VIRTUAL_PM1A_SCI_EN))
148 		return;
149 
150 	/* See if the SCI should be active or not. */
151 	need_sci = 0;
152 	if ((pm1_enable & PM1_TMR_EN) && (pm1_status & PM1_TMR_STS))
153 		need_sci = 1;
154 	if ((pm1_enable & PM1_GBL_EN) && (pm1_status & PM1_GBL_STS))
155 		need_sci = 1;
156 	if ((pm1_enable & PM1_PWRBTN_EN) && (pm1_status & PM1_PWRBTN_STS))
157 		need_sci = 1;
158 	if ((pm1_enable & PM1_SLPBTN_EN) && (pm1_status & PM1_SLPBTN_STS))
159 		need_sci = 1;
160 	if ((pm1_enable & PM1_RTC_EN) && (pm1_status & PM1_RTC_STS))
161 		need_sci = 1;
162 	if (need_sci)
163 		sci_assert(ctx);
164 	else
165 		sci_deassert(ctx);
166 }
167 
168 static int
pm1_status_handler(struct vmctx * ctx,int vcpu,int in,int port,int bytes,uint32_t * eax,void * arg)169 pm1_status_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
170 		   uint32_t *eax, void *arg)
171 {
172 	if (bytes != 2)
173 		return -1;
174 
175 	pthread_mutex_lock(&pm_lock);
176 	if (in)
177 		*eax = pm1_status;
178 	else {
179 		/*
180 		 * Writes are only permitted to clear certain bits by
181 		 * writing 1 to those flags.
182 		 */
183 		pm1_status &= ~(*eax & (PM1_WAK_STS | PM1_RTC_STS |
184 		    PM1_SLPBTN_STS | PM1_PWRBTN_STS | PM1_BM_STS));
185 		sci_update(ctx);
186 	}
187 	pthread_mutex_unlock(&pm_lock);
188 
189 	return 0;
190 }
191 
192 void
pm_backto_wakeup(struct vmctx * ctx)193 pm_backto_wakeup(struct vmctx *ctx)
194 {
195 	/* According to ACPI 5.0 Table 4-16: bit 15, WAK_STS should be
196 	 * set when system transition to the working state
197 	 */
198 	pm1_status |= PM1_WAK_STS;
199 }
200 
201 static int
pm1_enable_handler(struct vmctx * ctx,int vcpu,int in,int port,int bytes,uint32_t * eax,void * arg)202 pm1_enable_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
203 		   uint32_t *eax, void *arg)
204 {
205 	if (bytes != 2)
206 		return -1;
207 
208 	pthread_mutex_lock(&pm_lock);
209 	if (in)
210 		*eax = pm1_enable;
211 	else {
212 		/*
213 		 * Only permit certain bits to be set.  We never use
214 		 * the global lock, but ACPI-CA whines profusely if it
215 		 * can't set GBL_EN.
216 		 */
217 		pm1_enable = *eax & (PM1_RTC_EN | PM1_PWRBTN_EN | PM1_GBL_EN);
218 		sci_update(ctx);
219 	}
220 	pthread_mutex_unlock(&pm_lock);
221 
222 	return 0;
223 }
224 INOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler);
225 INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler);
226 
227 void
inject_power_button_event(struct vmctx * ctx)228 inject_power_button_event(struct vmctx *ctx)
229 {
230 	pr_info("press power button\n");
231 	pthread_mutex_lock(&pm_lock);
232 	if (!(pm1_status & PM1_PWRBTN_STS)) {
233 		pm1_status |= PM1_PWRBTN_STS;
234 		sci_update(ctx);
235 	}
236 	pthread_mutex_unlock(&pm_lock);
237 }
238 
239 static void
power_button_handler(int signal,enum ev_type type,void * arg)240 power_button_handler(int signal, enum ev_type type, void *arg)
241 {
242 	if (arg)
243 		inject_power_button_event(arg);
244 }
245 
246 static void
send_poweroff_event(void)247 send_poweroff_event(void)
248 {
249 	struct vm_event event;
250 	event.type = VM_EVENT_POWEROFF;
251 	dm_send_vm_event(&event);
252 }
253 
254 static int
pm1_control_handler(struct vmctx * ctx,int vcpu,int in,int port,int bytes,uint32_t * eax,void * arg)255 pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
256 		    uint32_t *eax, void *arg)
257 {
258 	if (bytes != 2)
259 		return -1;
260 	if (in)
261 		*eax = pm1_control;
262 	else {
263 		/*
264 		 * Various bits are write-only or reserved, so force them
265 		 * to zero in pm1_control.  Always preserve SCI_EN as OSPM
266 		 * can never change it.
267 		 */
268 		pm1_control = (pm1_control & VIRTUAL_PM1A_SCI_EN) |
269 		    (*eax & ~(VIRTUAL_PM1A_SLP_EN | VIRTUAL_PM1A_ALWAYS_ZERO));
270 
271 		/*
272 		 * If SLP_EN is set, check for S5.  ACRN-DM's _S5_ method
273 		 * says that '5' should be stored in SLP_TYP for S5.
274 		 */
275 		if (*eax & VIRTUAL_PM1A_SLP_EN) {
276 			if ((pm1_control & VIRTUAL_PM1A_SLP_TYP) >> 10 == 5) {
277 				send_poweroff_event();
278 				vm_suspend(ctx, VM_SUSPEND_POWEROFF);
279 			}
280 
281 			if ((pm1_control & VIRTUAL_PM1A_SLP_TYP) >> 10 == 3) {
282 				vm_suspend(ctx, VM_SUSPEND_SUSPEND);
283 			}
284 		}
285 	}
286 	return 0;
287 }
288 INOUT_PORT(pm1_control, VIRTUAL_PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);
289 SYSRES_IO(PM1A_EVT_ADDR, 8);
290 
291 /*
292  * ACPI SMI Command Register
293  *
294  * This write-only register is used to enable and disable ACPI.
295  */
296 static int
smi_cmd_handler(struct vmctx * ctx,int vcpu,int in,int port,int bytes,uint32_t * eax,void * arg)297 smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
298 		uint32_t *eax, void *arg)
299 {
300 	if (in || (bytes != 1))
301 		return -1;
302 
303 	pthread_mutex_lock(&pm_lock);
304 	switch (*eax & 0xFF) {
305 	case ACPI_ENABLE:
306 		pm1_control |= VIRTUAL_PM1A_SCI_EN;
307 		/*
308 		 * FIXME: ACPI_ENABLE/ACPI_DISABLE only impacts SCI_EN via SMI
309 		 * command register, not impact power button emulation. so need
310 		 * to remove all power button emulation from here.
311 		 */
312 		if (power_button == NULL) {
313 
314 			/*
315 			 * TODO: For the SIGTERM, IOC mediator also needs to
316 			 * support it, and SIGTERM handler needs to be written
317 			 * as one common interface for both APCI power button
318 			 * and IOC mediator in future.
319 			 */
320 			power_button = mevent_add(SIGTERM, EVF_SIGNAL,
321 				power_button_handler, ctx, NULL, NULL);
322 			old_power_handler = signal(SIGTERM, SIG_IGN);
323 		}
324 		break;
325 	case ACPI_DISABLE:
326 		pm1_control &= ~VIRTUAL_PM1A_SCI_EN;
327 		if (power_button != NULL) {
328 			mevent_delete(power_button);
329 			power_button = NULL;
330 			signal(SIGTERM, old_power_handler);
331 		}
332 		break;
333 	}
334 	pthread_mutex_unlock(&pm_lock);
335 	return 0;
336 }
337 INOUT_PORT(smi_cmd, SMI_CMD, IOPORT_F_OUT, smi_cmd_handler);
338 SYSRES_IO(SMI_CMD, 1);
339 
340 void
sci_init(struct vmctx * ctx)341 sci_init(struct vmctx *ctx)
342 {
343 	/*
344 	 * Mark ACPI's SCI as level trigger and bump its use count
345 	 * in the PIRQ router.
346 	 */
347 	pci_irq_use(SCI_INT);
348 }
349