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>
This commit is contained in:
Yuan Liu 2019-02-28 14:34:29 +08:00 committed by Eddie Dong
parent 32a7b4f179
commit 566e8824da
1 changed files with 59 additions and 5 deletions

View File

@ -44,14 +44,17 @@
#include "mevent.h"
#include "irq.h"
#include "lpc.h"
#include "monitor.h"
#define POWER_BUTTON_EVENT 116
#define POWER_BUTTON_NAME "power_button"
static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;
static struct mevent *power_button;
static sig_t old_power_handler;
static struct mevent *input_evt0;
static int pwrbtn_fd = -1;
static bool monitor_run;
/*
* Reset Control register at I/O port 0xcf9. Bit 2 forces a system
* 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);
INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler);
static void
power_button_handler(int signal, enum ev_type type, void *arg)
power_button_press_emulation(struct vmctx *ctx)
{
struct vmctx *ctx;
ctx = arg;
pthread_mutex_lock(&pm_lock);
if (!(pm1_status & PM1_PWRBTN_STS)) {
pm1_status |= PM1_PWRBTN_STS;
@ -230,6 +230,13 @@ power_button_handler(int signal, enum ev_type type, void *arg)
pthread_mutex_unlock(&pm_lock);
}
static void
power_button_handler(int signal, enum ev_type type, void *arg)
{
if (arg)
power_button_press_emulation(arg);
}
static void
input_event0_handler(int fd, enum ev_type type, void *arg)
{
@ -241,7 +248,7 @@ input_event0_handler(int fd, enum ev_type type, void *arg)
return;
if (ev.code == POWER_BUTTON_EVENT && ev.value == 1)
power_button_handler(fd, type, arg);
power_button_press_emulation(arg);
}
/*
@ -297,6 +304,31 @@ pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);
SYSRES_IO(PM1A_EVT_ADDR, 8);
static int
vm_stop_handler(void *arg)
{
if (!arg)
return -EINVAL;
power_button_press_emulation(arg);
return 0;
}
static int
vm_suspend_handler(void *arg)
{
/*
* Invoke vm_stop_handler directly in here since suspend of UOS is
* set by UOS power button setting.
*/
return vm_stop_handler(arg);
}
static struct monitor_vm_ops vm_ops = {
.stop = vm_stop_handler,
.suspend = vm_suspend_handler,
};
/*
* ACPI SMI Command Register
*
@ -314,6 +346,11 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
switch (*eax) {
case ACPI_ENABLE:
pm1_control |= PM1_SCI_EN;
/*
* FIXME: ACPI_ENABLE/ACPI_DISABLE only impacts SCI_EN via SMI
* command register, not impact power button emulation. so need
* to remove all power button emulation from here.
*/
if (power_button == NULL) {
/*
@ -327,6 +364,10 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
old_power_handler = signal(SIGTERM, SIG_IGN);
}
if (input_evt0 == NULL) {
/*
* FIXME: check /sys/bus/acpi/devices/LNXPWRBN\:00/input to
* get input event node instead hardcode in here.
*/
pwrbtn_fd = open("/dev/input/event0", O_RDONLY);
if (pwrbtn_fd < 0)
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,
input_evt0 = mevent_add(pwrbtn_fd, EVF_READ,
input_event0_handler, ctx, NULL, NULL);
}
/*
* Suspend or shutdown UOS by acrnctl suspend and
* stop command.
*/
if (monitor_run == false) {
if (monitor_register_vm_ops(&vm_ops, ctx,
POWER_BUTTON_NAME) < 0)
fprintf(stderr,
"failed to register vm ops for power button\n");
else
monitor_run = true;
}
break;
case ACPI_DISABLE:
pm1_control &= ~PM1_SCI_EN;