DM: add guest vm power manager by vuart
vuart can be used as communication channel between VMs; here vuart used to control vm's power off flow; control command is from SOS to UOS Tracked-On: #3564 Signed-off-by: Minggui Cao <minggui.cao@intel.com> Acked-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
parent
00401a1e78
commit
eb5a57b780
|
@ -141,6 +141,7 @@ SRCS += core/sw_load_elf.c
|
||||||
SRCS += core/mevent.c
|
SRCS += core/mevent.c
|
||||||
SRCS += core/gc.c
|
SRCS += core/gc.c
|
||||||
SRCS += core/pm.c
|
SRCS += core/pm.c
|
||||||
|
SRCS += core/pm_vuart.c
|
||||||
SRCS += core/console.c
|
SRCS += core/console.c
|
||||||
SRCS += core/inout.c
|
SRCS += core/inout.c
|
||||||
SRCS += core/mem.c
|
SRCS += core/mem.c
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#include "atomic.h"
|
#include "atomic.h"
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "virtio.h"
|
#include "virtio.h"
|
||||||
|
#include "pm_vuart.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
|
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
|
||||||
|
@ -138,7 +139,8 @@ usage(int code)
|
||||||
" %*s [--part_info part_info_name] [--enable_trusty] [--intr_monitor param_setting]\n"
|
" %*s [--part_info part_info_name] [--enable_trusty] [--intr_monitor param_setting]\n"
|
||||||
" %*s [--vtpm2 sock_path] [--virtio_poll interval] [--mac_seed seed_string]\n"
|
" %*s [--vtpm2 sock_path] [--virtio_poll interval] [--mac_seed seed_string]\n"
|
||||||
" %*s [--vmcfg sub_options] [--dump vm_idx] [--ptdev_no_reset] [--debugexit] \n"
|
" %*s [--vmcfg sub_options] [--dump vm_idx] [--ptdev_no_reset] [--debugexit] \n"
|
||||||
" %*s [--logger-setting param_setting] [--pm_notify_channel] <vm>\n"
|
" %*s [--logger-setting param_setting] [--pm_notify_channel]\n"
|
||||||
|
" %*s [--pm_by_vuart vuart_node] <vm>\n"
|
||||||
" -A: create ACPI tables\n"
|
" -A: create ACPI tables\n"
|
||||||
" -B: bootargs for kernel\n"
|
" -B: bootargs for kernel\n"
|
||||||
" -c: # cpus (default 1)\n"
|
" -c: # cpus (default 1)\n"
|
||||||
|
@ -173,11 +175,12 @@ usage(int code)
|
||||||
" --lapic_pt: enable local apic passthrough\n"
|
" --lapic_pt: enable local apic passthrough\n"
|
||||||
" --rtvm: indicate that the guest is rtvm\n"
|
" --rtvm: indicate that the guest is rtvm\n"
|
||||||
" --logger_setting: params like console,level=4;kmsg,level=3\n"
|
" --logger_setting: params like console,level=4;kmsg,level=3\n"
|
||||||
" --pm_notify_channel: define the channel used to notify guest about power event\n",
|
" --pm_notify_channel: define the channel used to notify guest about power event\n"
|
||||||
|
" --pm_by_vuart:pty,/run/acrn/vuart_vmname or tty,/dev/ttySn\n",
|
||||||
progname, (int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
|
progname, (int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
|
||||||
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
|
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
|
||||||
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
|
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
|
||||||
(int)strnlen(progname, PATH_MAX), "");
|
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "");
|
||||||
|
|
||||||
exit(code);
|
exit(code);
|
||||||
}
|
}
|
||||||
|
@ -421,6 +424,8 @@ guest_pm_notify_init(struct vmctx *ctx)
|
||||||
ioc_init(ctx);
|
ioc_init(ctx);
|
||||||
else if (PWR_EVENT_NOTIFY_PWR_BT == pm_notify_channel)
|
else if (PWR_EVENT_NOTIFY_PWR_BT == pm_notify_channel)
|
||||||
power_button_init(ctx);
|
power_button_init(ctx);
|
||||||
|
else if (PWR_EVENT_NOTIFY_UART == pm_notify_channel)
|
||||||
|
pm_by_vuart_init(ctx);
|
||||||
else
|
else
|
||||||
pr_err("No correct pm notify channel given\n");
|
pr_err("No correct pm notify channel given\n");
|
||||||
}
|
}
|
||||||
|
@ -432,6 +437,8 @@ guest_pm_notify_deinit(struct vmctx *ctx)
|
||||||
ioc_deinit(ctx);
|
ioc_deinit(ctx);
|
||||||
else if (PWR_EVENT_NOTIFY_PWR_BT == pm_notify_channel)
|
else if (PWR_EVENT_NOTIFY_PWR_BT == pm_notify_channel)
|
||||||
power_button_deinit(ctx);
|
power_button_deinit(ctx);
|
||||||
|
else if (PWR_EVENT_NOTIFY_UART == pm_notify_channel)
|
||||||
|
pm_by_vuart_deinit(ctx);
|
||||||
else
|
else
|
||||||
pr_err("No correct pm notify channel given\n");
|
pr_err("No correct pm notify channel given\n");
|
||||||
}
|
}
|
||||||
|
@ -724,6 +731,7 @@ enum {
|
||||||
CMD_OPT_RTVM,
|
CMD_OPT_RTVM,
|
||||||
CMD_OPT_LOGGER_SETTING,
|
CMD_OPT_LOGGER_SETTING,
|
||||||
CMD_OPT_PM_NOTIFY_CHANNEL,
|
CMD_OPT_PM_NOTIFY_CHANNEL,
|
||||||
|
CMD_OPT_PM_BY_VUART,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
|
@ -763,6 +771,7 @@ static struct option long_options[] = {
|
||||||
{"rtvm", no_argument, 0, CMD_OPT_RTVM},
|
{"rtvm", no_argument, 0, CMD_OPT_RTVM},
|
||||||
{"logger_setting", required_argument, 0, CMD_OPT_LOGGER_SETTING},
|
{"logger_setting", required_argument, 0, CMD_OPT_LOGGER_SETTING},
|
||||||
{"pm_notify_channel", required_argument, 0, CMD_OPT_PM_NOTIFY_CHANNEL},
|
{"pm_notify_channel", required_argument, 0, CMD_OPT_PM_NOTIFY_CHANNEL},
|
||||||
|
{"pm_by_vuart", required_argument, 0, CMD_OPT_PM_BY_VUART},
|
||||||
{0, 0, 0, 0 },
|
{0, 0, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -924,6 +933,10 @@ main(int argc, char *argv[])
|
||||||
pm_notify_channel = PWR_EVENT_NOTIFY_UART;
|
pm_notify_channel = PWR_EVENT_NOTIFY_UART;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case CMD_OPT_PM_BY_VUART:
|
||||||
|
if (parse_pm_by_vuart(optarg) != 0)
|
||||||
|
errx(EX_USAGE, "invalid pm-by-vuart params %s", optarg);
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(0);
|
usage(0);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
* Project Acrn
|
||||||
|
* Acrn-dm: pm-vuart
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* vuart can be used communication between SOS and UOS, here it is used as power manager control. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "vmmapi.h"
|
||||||
|
#include "monitor.h"
|
||||||
|
#include "pty_vuart.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#define SHUTDOWN_UOS_CMD "shutdown"
|
||||||
|
#define SHUTDOWN_CMD_ACK "acked"
|
||||||
|
#define CMD_LEN 16
|
||||||
|
#define WAIT_SND_CNT 3
|
||||||
|
#define WAIT_ACK_CNT 5
|
||||||
|
#define MAX_NODE_PATH 128
|
||||||
|
|
||||||
|
static const char * const node_name[] = {
|
||||||
|
"pty",
|
||||||
|
"tty",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum node_type_t {
|
||||||
|
PTY_NODE,
|
||||||
|
TTY_NODE,
|
||||||
|
MAX_NODE_CNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t node_index = MAX_NODE_CNT;
|
||||||
|
static char node_path[MAX_NODE_PATH];
|
||||||
|
static int node_fd = -1;
|
||||||
|
static bool shutdown_uos_thread_started = false;
|
||||||
|
static pthread_t shutdown_uos_thread_pid;
|
||||||
|
|
||||||
|
static int vm_stop_handler(void *arg);
|
||||||
|
static struct monitor_vm_ops vm_ops = {
|
||||||
|
.stop = vm_stop_handler,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* --pm_vuart configuration is in the following 2 forms:
|
||||||
|
* A: pty-link, like: pty,/run/acrn/vuart-vm1, (also set it in -l com2,/run/acrn/vuart-vm1)
|
||||||
|
* the SOS and UOS will communicate by: SOS:pty-link-node <--> SOS:com2 <--> UOS: /dev/ttyS1
|
||||||
|
* B: tty-node, like: tty,/dev/ttyS1, SOS and UOS communicate by: SOS:ttyS1 <--> HV <-->UOS:ttySn
|
||||||
|
*/
|
||||||
|
int parse_pm_by_vuart(const char *opts)
|
||||||
|
{
|
||||||
|
int i, error = -1;
|
||||||
|
char *str, *cpy, *type;
|
||||||
|
|
||||||
|
str = cpy = strdup(opts);
|
||||||
|
type = strsep(&str, ",");
|
||||||
|
|
||||||
|
if (type != NULL) {
|
||||||
|
for (i = 0; i < MAX_NODE_CNT; i++) {
|
||||||
|
if (strcasecmp(type, node_name[i]) == 0) {
|
||||||
|
node_index = i;
|
||||||
|
error = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("pm by vuart node-index = %d\n", node_index);
|
||||||
|
strncpy(node_path, str, MAX_NODE_PATH - 1);
|
||||||
|
|
||||||
|
free(cpy);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pm_by_vuart_init(struct vmctx *ctx)
|
||||||
|
{
|
||||||
|
assert(node_index < MAX_NODE_CNT);
|
||||||
|
|
||||||
|
if (node_index == PTY_NODE) {
|
||||||
|
node_fd = pty_open_virtual_uart(node_path);
|
||||||
|
} else if (node_index == TTY_NODE) {
|
||||||
|
node_fd = open(node_path, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_fd > 0) {
|
||||||
|
if (monitor_register_vm_ops(&vm_ops, ctx, "pm-vuart") < 0) {
|
||||||
|
pr_err("%s: pm-vuart register to VM monitor failed\n", node_path);
|
||||||
|
close(node_fd);
|
||||||
|
node_fd = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr_err("%s open failed, fd=%d\n", node_path, node_fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pm_by_vuart_deinit(struct vmctx *ctx)
|
||||||
|
{
|
||||||
|
close(node_fd);
|
||||||
|
node_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* it read from vuart, and if end is '\0' or '\n' or len = buff-len it will return */
|
||||||
|
static int read_bytes(int fd, uint8_t *buffer, int buf_len)
|
||||||
|
{
|
||||||
|
int rc, offset = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
rc = read(fd, buffer + offset, buf_len - offset);
|
||||||
|
if (rc > 0) {
|
||||||
|
offset += rc;
|
||||||
|
|
||||||
|
if ((buffer[offset - 1] == '\0') || (buffer[offset - 1] == '\n') ||
|
||||||
|
(offset == buf_len)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (rc > 0);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* thread to send shutdown cmd to uos and wait acked from it */
|
||||||
|
static void *shutdown_uos_thread(void *arg)
|
||||||
|
{
|
||||||
|
int rc, wait_snd, wait_ack;
|
||||||
|
char buffer[CMD_LEN];
|
||||||
|
|
||||||
|
wait_snd = WAIT_SND_CNT;
|
||||||
|
while (wait_snd > 0) {
|
||||||
|
rc = write(node_fd, SHUTDOWN_UOS_CMD, strlen(SHUTDOWN_UOS_CMD));
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("send shutdown cmd to uos failed!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1); /* wait 1 second to communicate with UOS */
|
||||||
|
|
||||||
|
wait_ack = WAIT_ACK_CNT;
|
||||||
|
while (wait_ack > 0) {
|
||||||
|
rc = read_bytes(node_fd, (uint8_t *)buffer, CMD_LEN - 1);
|
||||||
|
if ((rc > 0) && strncmp(buffer, SHUTDOWN_CMD_ACK, strlen(SHUTDOWN_CMD_ACK)) == 0) {
|
||||||
|
pr_info("received acked from UOS\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
wait_ack--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait_ack > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_snd--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((wait_snd == 0) && (wait_ack == 0)) {
|
||||||
|
pr_err("not received acked from UOS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown_uos_thread_started = false;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called when acrn-dm receive stop command */
|
||||||
|
static int vm_stop_handler(void *arg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pr_info("pm-vuart stop handler called: node-index=%d\n", node_index);
|
||||||
|
assert(node_index < MAX_NODE_CNT);
|
||||||
|
|
||||||
|
if (node_fd <= 0) {
|
||||||
|
pr_err("no vuart node opened!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shutdown_uos_thread_started) {
|
||||||
|
pr_info("stop cmd send thread started!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown_uos_thread_started = true;
|
||||||
|
ret = pthread_create(&shutdown_uos_thread_pid, NULL, shutdown_uos_thread, NULL);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("failed %s %d\n", __func__, __LINE__);
|
||||||
|
shutdown_uos_thread_pid = 0;
|
||||||
|
shutdown_uos_thread_started = false;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("created shutdown uos thread.\n");
|
||||||
|
pthread_setname_np(shutdown_uos_thread_pid, "shutdown_uos");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Project Acrn
|
||||||
|
* Acrn-dm: pm-vuart
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PM_VUART__
|
||||||
|
#define __PM_VUART__
|
||||||
|
|
||||||
|
int parse_pm_by_vuart(const char *opts);
|
||||||
|
void pm_by_vuart_init(struct vmctx *ctx);
|
||||||
|
void pm_by_vuart_deinit(struct vmctx *ctx);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue