Skip to content

Commit 566e882

Browse files
yliu80Eddie Dong
authored andcommitted
dm: power button emulation by acrnctl command.
when UOS is running, "acrnctl suspend vm" and "acrnctl stop vm" commands are able to trigger a SCI interrupt, then UOS enters sleep or shutdown according to the default behavior of the power button. The default behavior is based on UOS power button setting. Tracked-On: #2560 Signed-off-by: Yuan Liu <yuan1.liu@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
1 parent 32a7b4f commit 566e882

File tree

1 file changed

+59
-5
lines changed
  • devicemodel/arch/x86

1 file changed

+59
-5
lines changed

devicemodel/arch/x86/pm.c

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,17 @@
4444
#include "mevent.h"
4545
#include "irq.h"
4646
#include "lpc.h"
47+
#include "monitor.h"
4748

4849
#define POWER_BUTTON_EVENT 116
50+
#define POWER_BUTTON_NAME "power_button"
4951
static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;
5052
static struct mevent *power_button;
5153
static sig_t old_power_handler;
5254

5355
static struct mevent *input_evt0;
5456
static int pwrbtn_fd = -1;
57+
static bool monitor_run;
5558
/*
5659
* Reset Control register at I/O port 0xcf9. Bit 2 forces a system
5760
* reset when it transitions from 0 to 1. Bit 1 selects the type of
@@ -217,11 +220,8 @@ INOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler);
217220
INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler);
218221

219222
static void
220-
power_button_handler(int signal, enum ev_type type, void *arg)
223+
power_button_press_emulation(struct vmctx *ctx)
221224
{
222-
struct vmctx *ctx;
223-
224-
ctx = arg;
225225
pthread_mutex_lock(&pm_lock);
226226
if (!(pm1_status & PM1_PWRBTN_STS)) {
227227
pm1_status |= PM1_PWRBTN_STS;
@@ -230,6 +230,13 @@ power_button_handler(int signal, enum ev_type type, void *arg)
230230
pthread_mutex_unlock(&pm_lock);
231231
}
232232

233+
static void
234+
power_button_handler(int signal, enum ev_type type, void *arg)
235+
{
236+
if (arg)
237+
power_button_press_emulation(arg);
238+
}
239+
233240
static void
234241
input_event0_handler(int fd, enum ev_type type, void *arg)
235242
{
@@ -241,7 +248,7 @@ input_event0_handler(int fd, enum ev_type type, void *arg)
241248
return;
242249

243250
if (ev.code == POWER_BUTTON_EVENT && ev.value == 1)
244-
power_button_handler(fd, type, arg);
251+
power_button_press_emulation(arg);
245252
}
246253

247254
/*
@@ -297,6 +304,31 @@ pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
297304
INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);
298305
SYSRES_IO(PM1A_EVT_ADDR, 8);
299306

307+
static int
308+
vm_stop_handler(void *arg)
309+
{
310+
if (!arg)
311+
return -EINVAL;
312+
313+
power_button_press_emulation(arg);
314+
return 0;
315+
}
316+
317+
static int
318+
vm_suspend_handler(void *arg)
319+
{
320+
/*
321+
* Invoke vm_stop_handler directly in here since suspend of UOS is
322+
* set by UOS power button setting.
323+
*/
324+
return vm_stop_handler(arg);
325+
}
326+
327+
static struct monitor_vm_ops vm_ops = {
328+
.stop = vm_stop_handler,
329+
.suspend = vm_suspend_handler,
330+
};
331+
300332
/*
301333
* ACPI SMI Command Register
302334
*
@@ -314,6 +346,11 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
314346
switch (*eax) {
315347
case ACPI_ENABLE:
316348
pm1_control |= PM1_SCI_EN;
349+
/*
350+
* FIXME: ACPI_ENABLE/ACPI_DISABLE only impacts SCI_EN via SMI
351+
* command register, not impact power button emulation. so need
352+
* to remove all power button emulation from here.
353+
*/
317354
if (power_button == NULL) {
318355

319356
/*
@@ -327,6 +364,10 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
327364
old_power_handler = signal(SIGTERM, SIG_IGN);
328365
}
329366
if (input_evt0 == NULL) {
367+
/*
368+
* FIXME: check /sys/bus/acpi/devices/LNXPWRBN\:00/input to
369+
* get input event node instead hardcode in here.
370+
*/
330371
pwrbtn_fd = open("/dev/input/event0", O_RDONLY);
331372
if (pwrbtn_fd < 0)
332373
fprintf(stderr, "open input event0 error=%d\n",
@@ -335,6 +376,19 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
335376
input_evt0 = mevent_add(pwrbtn_fd, EVF_READ,
336377
input_event0_handler, ctx, NULL, NULL);
337378
}
379+
380+
/*
381+
* Suspend or shutdown UOS by acrnctl suspend and
382+
* stop command.
383+
*/
384+
if (monitor_run == false) {
385+
if (monitor_register_vm_ops(&vm_ops, ctx,
386+
POWER_BUTTON_NAME) < 0)
387+
fprintf(stderr,
388+
"failed to register vm ops for power button\n");
389+
else
390+
monitor_run = true;
391+
}
338392
break;
339393
case ACPI_DISABLE:
340394
pm1_control &= ~PM1_SCI_EN;

0 commit comments

Comments
 (0)