mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 04:02:05 +00:00
misc: totally remove misc folder
misc now has a new home: https://github.com/intel/ioc-cbc-tools. The "Execstop" patch will be synced to new git tree soon. ioc-cbc-tools was just added to Clear Linux, and will be added to software-defined-cockpit bundle after this patch merged. Merging this patch may cause some IOC releated feature block until we get a new Clear Linux release. This is the switch window ... Signed-off-by: Alek Du <alek.du@intel.com>
This commit is contained in:
parent
49322ac002
commit
2a656812df
14
Makefile
14
Makefile
@ -9,14 +9,13 @@ ROOT_OUT := $(shell mkdir -p $(O);cd $(O);pwd)
|
||||
HV_OUT := $(ROOT_OUT)/hypervisor
|
||||
DM_OUT := $(ROOT_OUT)/devicemodel
|
||||
TOOLS_OUT := $(ROOT_OUT)/tools
|
||||
MISC_OUT := $(ROOT_OUT)/misc
|
||||
DOC_OUT := $(ROOT_OUT)/doc
|
||||
BUILD_VERSION ?=
|
||||
BUILD_TAG ?=
|
||||
export TOOLS_OUT
|
||||
|
||||
.PHONY: all hypervisor devicemodel tools misc doc
|
||||
all: hypervisor devicemodel tools misc
|
||||
.PHONY: all hypervisor devicemodel tools doc
|
||||
all: hypervisor devicemodel tools
|
||||
|
||||
hypervisor:
|
||||
make -C $(T)/hypervisor HV_OBJDIR=$(HV_OUT) PLATFORM=$(PLATFORM) RELEASE=$(RELEASE) clean
|
||||
@ -35,10 +34,6 @@ tools:
|
||||
mkdir -p $(TOOLS_OUT)
|
||||
make -C $(T)/tools OUT_DIR=$(TOOLS_OUT) RELEASE=$(RELEASE)
|
||||
|
||||
misc: tools
|
||||
mkdir -p $(MISC_OUT)
|
||||
make -C $(T)/misc OUT_DIR=$(MISC_OUT)
|
||||
|
||||
doc:
|
||||
make -C $(T)/doc html BUILDDIR=$(DOC_OUT)
|
||||
|
||||
@ -49,7 +44,7 @@ clean:
|
||||
rm -rf $(ROOT_OUT)
|
||||
|
||||
.PHONY: install
|
||||
install: hypervisor-install devicemodel-install tools-install misc-install
|
||||
install: hypervisor-install devicemodel-install tools-install
|
||||
|
||||
hypervisor-install:
|
||||
make -C $(T)/hypervisor HV_OBJDIR=$(HV_OUT) PLATFORM=$(PLATFORM) RELEASE=$(RELEASE) install
|
||||
@ -62,6 +57,3 @@ devicemodel-install:
|
||||
|
||||
tools-install:
|
||||
make -C $(T)/tools OUT_DIR=$(TOOLS_OUT) install
|
||||
|
||||
misc-install:
|
||||
make -C $(T)/misc OUT_DIR=$(MISC_OUT) install
|
||||
|
@ -1,24 +0,0 @@
|
||||
T := $(CURDIR)
|
||||
|
||||
.PHONY: all cbc_lifecycle cbc_attach
|
||||
all: cbc_lifecycle cbc_attach
|
||||
|
||||
cbc_lifecycle:
|
||||
make -C $(T)/cbc_lifecycle OUT_DIR=$(OUT_DIR)
|
||||
cbc_attach:
|
||||
make -C $(T)/cbc_attach OUT_DIR=$(OUT_DIR)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
make -C $(T)/cbc_lifecycle clean
|
||||
make -C $(T)/cbc_attach clean
|
||||
rm -rf $(OUT_DIR)
|
||||
|
||||
.PHONY: install
|
||||
install: cbc_lifecycle-install cbc_attach-install
|
||||
|
||||
cbc_lifecycle-install:
|
||||
make -C $(T)/cbc_lifecycle OUT_DIR=$(OUT_DIR) install
|
||||
|
||||
cbc_attach-install:
|
||||
make -C $(T)/cbc_attach OUT_DIR=$(OUT_DIR) install
|
@ -1,13 +0,0 @@
|
||||
OUT_DIR ?= .
|
||||
|
||||
all:
|
||||
gcc -o $(OUT_DIR)/cbc_attach cbc_attach.c
|
||||
|
||||
clean:
|
||||
rm -rf $(OUT_DIR)/cbc_attach
|
||||
|
||||
install: $(OUT_DIR)/cbc_attach cbc_attach.service
|
||||
install -d $(DESTDIR)/usr/bin
|
||||
install -t $(DESTDIR)/usr/bin $(OUT_DIR)/cbc_attach
|
||||
install -d $(DESTDIR)/usr/lib/systemd/system/
|
||||
install -p -m 0644 cbc_attach.service $(DESTDIR)/usr/lib/systemd/system/
|
@ -1,412 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) <2018> Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* The cbc_attach tool is a tool similar to ldattach or slcand.
|
||||
* It configures the given serial line for cbc and loads the cbc
|
||||
* line discipline. On exit it switches the line discipline to n_tty.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef ANDROID_BUILD
|
||||
#define APP_INFO "v" VERSION_STRING
|
||||
#else
|
||||
#define APP_INFO ""
|
||||
#endif
|
||||
|
||||
#include <linux/tty.h>
|
||||
#ifndef N_CBCCORE
|
||||
#define N_CBCCORE 27
|
||||
#endif
|
||||
|
||||
#define VERSION_MAJOR 4
|
||||
#define VERSION_MINOR 2
|
||||
#define VERSION_REVISON 2
|
||||
|
||||
#define VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}"
|
||||
|
||||
char const *const cDEFAULT_DEVICE_NAME = "/dev/ttyS1";
|
||||
|
||||
static struct option longOpts[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"baudrate", required_argument, 0, 'b'},
|
||||
{"hardwareFlowControl", no_argument, 0, 'f'},
|
||||
{"min-receive-bytes", required_argument, 0, 'm'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
/* granularity is currently a module parameter -> not set from this tool. */
|
||||
|
||||
void printMainUsage(void)
|
||||
{
|
||||
printf("cbc_attach tool %s - attach cbc line discpline ", APP_INFO);
|
||||
printf("to serial line\n\n");
|
||||
printf("Usage: cbc_attach [OPTION]... [TTY-DEVICE]...\n\n");
|
||||
printf("-h , --help Help\n");
|
||||
printf("-b , --baudrate=<Baudrate> Baudrate e.g.:4000000\n");
|
||||
printf("-f , --hardwareFlowControl Use hardware flow control\n");
|
||||
printf("-m , --min-receive-bytes Minimum number of bytes to ");
|
||||
printf("receive from the serial device ");
|
||||
printf("(range:0-255, default:255)\n");
|
||||
printf("<tty-device> Name of the serial line. ");
|
||||
printf("default: %s\n", cDEFAULT_DEVICE_NAME);
|
||||
}
|
||||
|
||||
|
||||
bool convertBaudRate(const uint32_t baudRateInt, speed_t *baudRate)
|
||||
{
|
||||
switch (baudRateInt) {
|
||||
case 50:
|
||||
*baudRate = B50;
|
||||
break;
|
||||
case 75:
|
||||
*baudRate = B75;
|
||||
break;
|
||||
case 110:
|
||||
*baudRate = B110;
|
||||
break;
|
||||
case 134:
|
||||
*baudRate = B134;
|
||||
break;
|
||||
case 150:
|
||||
*baudRate = B150;
|
||||
break;
|
||||
case 200:
|
||||
*baudRate = B200;
|
||||
break;
|
||||
case 300:
|
||||
*baudRate = B300;
|
||||
break;
|
||||
case 600:
|
||||
*baudRate = B600;
|
||||
break;
|
||||
case 1200:
|
||||
*baudRate = B1200;
|
||||
break;
|
||||
case 1800:
|
||||
*baudRate = B1800;
|
||||
break;
|
||||
case 2400:
|
||||
*baudRate = B2400;
|
||||
break;
|
||||
case 4800:
|
||||
*baudRate = B4800;
|
||||
break;
|
||||
case 9600:
|
||||
*baudRate = B9600;
|
||||
break;
|
||||
case 19200:
|
||||
*baudRate = B19200;
|
||||
break;
|
||||
case 38400:
|
||||
*baudRate = B38400;
|
||||
break;
|
||||
case 57600:
|
||||
*baudRate = B57600;
|
||||
break;
|
||||
case 115200:
|
||||
*baudRate = B115200;
|
||||
break;
|
||||
case 230400:
|
||||
*baudRate = B230400;
|
||||
break;
|
||||
case 460800:
|
||||
*baudRate = B460800;
|
||||
break;
|
||||
case 500000:
|
||||
*baudRate = B500000;
|
||||
break;
|
||||
case 576000:
|
||||
*baudRate = B576000;
|
||||
break;
|
||||
case 921600:
|
||||
*baudRate = B921600;
|
||||
break;
|
||||
case 1000000:
|
||||
*baudRate = B1000000;
|
||||
break;
|
||||
case 1152000:
|
||||
*baudRate = B1152000;
|
||||
break;
|
||||
case 1500000:
|
||||
*baudRate = B1500000;
|
||||
break;
|
||||
case 2000000:
|
||||
*baudRate = B2000000;
|
||||
break;
|
||||
case 2500000:
|
||||
*baudRate = B2500000;
|
||||
break;
|
||||
case 3000000:
|
||||
*baudRate = B3000000;
|
||||
break;
|
||||
case 3500000:
|
||||
*baudRate = B3500000;
|
||||
break;
|
||||
case 4000000:
|
||||
*baudRate = B4000000;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool initTerminal(int deviceFd, const uint32_t baudRateInt,
|
||||
const bool useHardwareFlowControl,
|
||||
const uint8_t minReceiveBytes)
|
||||
{
|
||||
bool success = true;
|
||||
struct termios terminalSettings;
|
||||
|
||||
speed_t baudRate = B0;
|
||||
|
||||
if (!convertBaudRate(baudRateInt, &baudRate)) {
|
||||
printf("Invalid baud rate given %i\n", baudRateInt);
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
int res = tcgetattr(deviceFd, &terminalSettings);
|
||||
|
||||
if (res < 0) {
|
||||
printf("Failed to get terminal settings (error: %s)\n",
|
||||
strerror(errno));
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
terminalSettings.c_cflag = 0;
|
||||
terminalSettings.c_iflag = 0;
|
||||
|
||||
/* set 8n1 */
|
||||
terminalSettings.c_cflag &= ~(PARENB | CSTOPB | CSIZE);
|
||||
terminalSettings.c_cflag |= CS8 | CLOCAL | CREAD;
|
||||
terminalSettings.c_iflag |= IGNPAR;
|
||||
|
||||
if (useHardwareFlowControl)
|
||||
/* Enable hardware flow control. */
|
||||
terminalSettings.c_cflag |= CRTSCTS;
|
||||
else
|
||||
/* Disable hardware flow control.*/
|
||||
terminalSettings.c_cflag &= ~CRTSCTS;
|
||||
|
||||
/* Disable software flow control. */
|
||||
terminalSettings.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||
|
||||
/* Set raw mode. */
|
||||
cfmakeraw(&terminalSettings);
|
||||
|
||||
/* Set VTIME to 1 to get a read() timeout of 100ms. */
|
||||
terminalSettings.c_cc[VTIME] = 1u;
|
||||
|
||||
/* Set VMIN. */
|
||||
terminalSettings.c_cc[VMIN] = minReceiveBytes;
|
||||
|
||||
/* Set baudrate. */
|
||||
int res = cfsetspeed(&terminalSettings, baudRate);
|
||||
|
||||
if (res != 0) {
|
||||
printf("Failed to set serial speed (error: %s)\n",
|
||||
strerror(errno));
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
int res = cfsetospeed(&terminalSettings, baudRate);
|
||||
|
||||
if (res != 0) {
|
||||
printf("Failed to set o/p serial speed (error: %s)\n",
|
||||
strerror(errno));
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
(void)tcflush(deviceFd, TCIFLUSH);
|
||||
int res = tcsetattr(deviceFd, TCSANOW, &terminalSettings);
|
||||
|
||||
if (res != 0) {
|
||||
printf("Failed to set terminal settings (error: %s)\n",
|
||||
strerror(errno));
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void cbc_attach_shutdown(int *const deviceFd)
|
||||
{
|
||||
if (*deviceFd > 0) {
|
||||
int disc = N_TTY;
|
||||
int res = ioctl(*deviceFd, TIOCSETD, &disc);
|
||||
|
||||
if (res != 0)
|
||||
printf("Failed to set line disc tty (error: %s)\n",
|
||||
strerror(errno));
|
||||
|
||||
res = close(*deviceFd);
|
||||
if (res != 0)
|
||||
printf("Failed to close serial device (error: %s)\n",
|
||||
strerror(errno));
|
||||
else
|
||||
*deviceFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool openDevice(int *const deviceFd, char const *const deviceName)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
*deviceFd = open(deviceName, O_RDONLY | O_NOCTTY);
|
||||
if (*deviceFd < 0) {
|
||||
printf("Failed to open serial device %s, error: %s\n",
|
||||
deviceName, strerror(errno));
|
||||
success = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool init(int *const deviceFd,
|
||||
char const *const deviceName,
|
||||
uint32_t const baudRateInt,
|
||||
bool const useHardwareFlowControl,
|
||||
uint8_t const minReceiveBytes)
|
||||
{
|
||||
/* TODO check whether VMIN/VTIME handling is necessary */
|
||||
bool success = true;
|
||||
|
||||
success = openDevice(deviceFd, deviceName);
|
||||
|
||||
if (success) {
|
||||
success = initTerminal(*deviceFd, baudRateInt,
|
||||
useHardwareFlowControl,
|
||||
minReceiveBytes);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
/* Set line discipline. N_CBCCORE is unknown on host.
|
||||
* Use magic number instead of define.
|
||||
*/
|
||||
int disc = N_CBCCORE;
|
||||
int res = ioctl(*deviceFd, TIOCSETD, &disc);
|
||||
|
||||
if (res != 0) {
|
||||
printf("Failed to set line disc cbc (error: %s)\n",
|
||||
strerror(errno));
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the device if initialization has failed. */
|
||||
if (!success)
|
||||
cbc_attach_shutdown(deviceFd);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int optionIndex;
|
||||
int c;
|
||||
bool success;
|
||||
|
||||
char const *deviceName = cDEFAULT_DEVICE_NAME;
|
||||
int baudrate = 4000000;
|
||||
bool useHwFlowControl = false;
|
||||
uint8_t minReceiveBytes = 255;
|
||||
int deviceFd = 0;
|
||||
|
||||
/* Retry times and uint */
|
||||
int retry_time = 30;
|
||||
int retry_uint = 2;
|
||||
|
||||
/* Try to get the CBC device name from an environment variable. */
|
||||
char const *envDeviceName = getenv("CBC_TTY");
|
||||
|
||||
if (envDeviceName)
|
||||
deviceName = envDeviceName;
|
||||
|
||||
/* Parse command line options. */
|
||||
if (argc == 0)
|
||||
return -1;
|
||||
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, "hb:f", longOpts, &optionIndex);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
printMainUsage();
|
||||
return 0;
|
||||
|
||||
case 'b':
|
||||
if (optarg != NULL) {
|
||||
baudrate = atoi(optarg);
|
||||
if (baudrate == 0) {
|
||||
printf("Unknown baudrate %s,exiting\n",
|
||||
optarg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
useHwFlowControl = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
deviceName = argv[optind];
|
||||
|
||||
printf("%s " APP_INFO "Started (pid: %i, CBC device: %s,", argv[0],
|
||||
getpid(), deviceName);
|
||||
printf("baudrate: %i, hw flow control: %s)\n", baudrate,
|
||||
useHwFlowControl ? "on" : "off");
|
||||
do {
|
||||
/* set up serial line */
|
||||
success = init(&deviceFd, deviceName, baudrate,
|
||||
useHwFlowControl, minReceiveBytes);
|
||||
if (success)
|
||||
break;
|
||||
|
||||
sleep(retry_uint);
|
||||
retry_time -= retry_uint;
|
||||
printf("Init failed, retry time is %d seconds\n", retry_time);
|
||||
|
||||
} while (retry_time > 0);
|
||||
|
||||
if (success) {
|
||||
pause();
|
||||
cbc_attach_shutdown(&deviceFd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description=cbc attach
|
||||
DefaultDependencies=no
|
||||
After=sysinit.target local.target
|
||||
Before=basic.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/cbc_attach /dev/ttyS2
|
||||
Restart=no
|
||||
Type=simple
|
||||
|
||||
[Install]
|
||||
WantedBy=basic.target
|
@ -1,14 +0,0 @@
|
||||
|
||||
OUT_DIR ?= .
|
||||
|
||||
$(OUT_DIR)/cbc_lifecycle: cbc_lifecycle.c $(TOOLS_OUT)/libacrn-mngr.a
|
||||
gcc -o $@ cbc_lifecycle.c -pthread -L$(TOOLS_OUT) -lacrn-mngr
|
||||
|
||||
clean:
|
||||
rm $(OUT_DIR)/cbc_lifecycle
|
||||
|
||||
install: $(OUT_DIR)/cbc_lifecycle cbc_lifecycle.service
|
||||
install -d $(DESTDIR)/usr/bin
|
||||
install -t $(DESTDIR)/usr/bin $<
|
||||
install -d $(DESTDIR)/usr/lib/systemd/system/
|
||||
install -p -m 0644 cbc_lifecycle.service $(DESTDIR)/usr/lib/systemd/system/
|
@ -1,490 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* Author: Alek Du <alek.du@intel.com>
|
||||
*
|
||||
* SPDX-License-identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/* CBC lifecycle state machine transition flow
|
||||
*
|
||||
* .-------------------------------------------
|
||||
* -------------+-------------- |
|
||||
* | IOC V IOC | |
|
||||
* (default) ==> (Active) ==> (shutdown) ==> (shutdown delay) (Off)
|
||||
* |_____________|__________________|
|
||||
* _________|________ (ACRN select) ^
|
||||
* ACRN/ ACRN| ACRN\ |
|
||||
* (reboot) (suspend) (shutdown) |
|
||||
* | | | |
|
||||
* ------------------------------------------------------
|
||||
*
|
||||
* IOC: state transition due to cbc-lifecycle wakeup reason
|
||||
* ACRN: state transition due to ACRND IPC request
|
||||
*/
|
||||
|
||||
/* Basic cbc-lifecycle workflow on Service OS
|
||||
* ____________________
|
||||
* | sos lifecycle |
|
||||
* | service |
|
||||
* | |
|
||||
* |*incoming request |(Listen on server socket @ /run/acrn/sos-lcs.socket)
|
||||
* | wakeup reason |
|
||||
* | shutdown |
|
||||
* | reboot |(Requests from ACRN VM manager)
|
||||
* | suspend |
|
||||
* | RTC set wakeup |
|
||||
* | |
|
||||
* |*out events |(Send to ACRN VM manager @ /run/acrn/acrnd.socket)
|
||||
* | vm start |
|
||||
* | vm stop |(Events from /dev/cbc-lifecycle port)
|
||||
* ~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* 3 threads: 1. wake on /dev/cbc-lifecycle and receive wakeup reasons
|
||||
* 2. heartbeat thread to send heartbeat msg to /dev/cbc-lifecycle
|
||||
* 3. server socket handler thread to handle incoming msg
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/tty.h>
|
||||
#include "../../tools/acrn-manager/acrn_mngr.h"
|
||||
|
||||
static char cbcd_name[] = "sos-lcs";
|
||||
static char acrnd_name[] = "acrnd";
|
||||
static char cbc_lifecycle_dev[] = "/dev/cbc-lifecycle";
|
||||
|
||||
typedef enum {
|
||||
S_DEFAULT = 0, /* default, not receiving any status */
|
||||
S_ALIVE = 1, /* receive wakeup_reason bit 0~22 not all 0 */
|
||||
S_SHUTDOWN, /* receive wakeup_reason bit 0~22 off 23 on */
|
||||
S_SHUTDOWN_DELAY, /* before ACRND confirm off, sent delay to IOC */
|
||||
S_ACRND_SHUTDOWN, /* ACRND confirm ioc can off */
|
||||
S_IOC_SHUTDOWN, /* receiving wakeup_reason bit 0~23 off */
|
||||
S_ACRND_REBOOT, /* receive request from ACRND to go reboot */
|
||||
S_ACRND_SUSPEND, /* receive request from ACRND to go S3 */
|
||||
S_MAX,
|
||||
} state_machine_t;
|
||||
|
||||
/* state machine valid transition table */
|
||||
char valid_map[S_MAX][S_MAX] = {
|
||||
{ 1, 1, 1, 0, 0, 0, 0, 0 }, /* default can go alive or shutdown */
|
||||
{ 0, 1, 1, 0, 1, 0, 1, 1 }, /* alive can go S_ACRND_* state */
|
||||
{ 0, 0, 1, 1, 1, 1, 1, 1 }, /* shutdown can go upper states */
|
||||
{ 0, 0, 0, 1, 1, 1, 1, 1 }, /* delay can go upper states */
|
||||
{ 0, 0, 0, 0, 1, 1, 0, 0 }, /* acrnd shutdown can go ioc_shutdown */
|
||||
{ 0, 1, 0, 0, 0, 1, 0, 0 }, /* ioc_shutdown can go alive (s3 case) */
|
||||
{ 0, 0, 0, 0, 0, 1, 1, 0 }, /* acrnd_reboot can only go ioc_shutdown */
|
||||
{ 0, 1, 0, 0, 0, 1, 0, 1 }, /* acrnd_suspend can go alive/ioc_shutdown */
|
||||
};
|
||||
|
||||
const char *state_name[] = {
|
||||
"default",
|
||||
"keep_alive",
|
||||
"shutdown",
|
||||
"shutdown_delay",
|
||||
"acrnd_shutdown",
|
||||
"ioc_shutdown",
|
||||
"acrnd_reboot",
|
||||
"acrnd_suspend",
|
||||
};
|
||||
|
||||
static state_machine_t state;
|
||||
static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
typedef struct {
|
||||
uint8_t header;
|
||||
uint8_t wakeup[3];
|
||||
} __attribute__((packed)) wakeup_reason_frame;
|
||||
|
||||
typedef pthread_t cbc_thread_t;
|
||||
typedef void* (*cbc_thread_func_t)(void *arg);
|
||||
|
||||
/* cbc suppress heartbeat is not used so far, keep here for future use */
|
||||
static char cbc_suppress_heartbeat_1min[] = {0x04, 0x60, 0xEA, 0x00};
|
||||
static char cbc_suppress_heartbeat_5min[] = {0x04, 0xE0, 0x93, 0x04};
|
||||
static char cbc_suppress_heartbeat_10min[] = {0x04, 0xC0, 0x27, 0x09};
|
||||
static char cbc_suppress_heartbeat_30min[] = {0x04, 0x40, 0x77, 0x1B};
|
||||
static char cbc_heartbeat_shutdown[] = {0x02, 0x00, 0x01, 0x00};
|
||||
static char cbc_heartbeat_reboot[] = {0x02, 0x00, 0x02, 0x00};
|
||||
/* hearbeat shutdown ignore number is not used so far for non-native case */
|
||||
static char cbc_heartbeat_shutdown_ignore_1[] = {0x02, 0x00, 0x03, 0x00};
|
||||
static char cbc_heartbeat_reboot_ignore_1[] = {0x02, 0x00, 0x04, 0x00};
|
||||
static char cbc_heartbeat_shutdown_ignore_2[] = {0x02, 0x00, 0x05, 0x00};
|
||||
static char cbc_heartbeat_reboot_ignore_2[] = {0x02, 0x00, 0x06, 0x00};
|
||||
static char cbc_heartbeat_s3[] = {0x02, 0x00, 0x07, 0x00};
|
||||
static char cbc_heartbeat_active[] = {0x02, 0x01, 0x00, 0x00};
|
||||
static char cbc_heartbeat_shutdown_delay[] = {0x02, 0x02, 0x00, 0x00};
|
||||
static char cbc_heartbeat_init[] = {0x02, 0x03, 0x00, 0x00};
|
||||
|
||||
static int cbc_lifecycle_fd = -1;
|
||||
|
||||
static int wakeup_reason;
|
||||
|
||||
static void wait_for_device(const char *dev_name)
|
||||
{
|
||||
int loop = 360; // 180 seconds
|
||||
if (dev_name == NULL)
|
||||
return;
|
||||
|
||||
while (loop--) {
|
||||
if (access(dev_name, F_OK)) {
|
||||
fprintf(stderr, "waiting for %s\n", dev_name);
|
||||
usleep(500000);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int open_cbc_device(const char *cbc_device)
|
||||
{
|
||||
int fd;
|
||||
wait_for_device(cbc_device);
|
||||
|
||||
if ((fd = open(cbc_device, O_RDWR | O_NOCTTY)) < 0) {
|
||||
fprintf(stderr, "%s failed to open %s\n", __func__, cbc_device);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void close_cbc_device(int fd)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static int cbc_send_data(int fd, const char *payload, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while (1) {
|
||||
ret = write(fd, payload, len);
|
||||
if (ret <= 0) {
|
||||
if (errno == EDQUOT) {
|
||||
usleep(1000);
|
||||
break;
|
||||
} else if (errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
fprintf(stderr, "%s issue : %d", __func__,
|
||||
errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cbc_read_data(int fd, char *payload, int len)
|
||||
{
|
||||
int nbytes = 0;
|
||||
|
||||
while (1) {
|
||||
nbytes = read(fd, payload, len);
|
||||
|
||||
if (nbytes < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(stderr, "%s issue %d", __func__, errno);
|
||||
usleep(5000);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static __inline__ int cbc_thread_create(cbc_thread_t *pthread,
|
||||
cbc_thread_func_t start, void *arg)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
return pthread_create(pthread, (const pthread_attr_t *)&attr,
|
||||
start, arg);
|
||||
}
|
||||
|
||||
state_machine_t get_state(void)
|
||||
{
|
||||
state_machine_t _state;
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
_state = state;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
return _state;
|
||||
}
|
||||
|
||||
state_machine_t state_transit(state_machine_t new)
|
||||
{
|
||||
state_machine_t _state;
|
||||
pthread_mutex_lock(&state_mutex);
|
||||
|
||||
_state = state;
|
||||
if (valid_map[state][new]) {
|
||||
state = new;
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
if (_state != new) {
|
||||
fprintf(stderr, "transit (%s to %s)\n",
|
||||
state_name[_state], state_name[new]);
|
||||
_state = new;
|
||||
}
|
||||
} else {
|
||||
pthread_mutex_unlock(&state_mutex);
|
||||
}
|
||||
return _state;
|
||||
}
|
||||
|
||||
static int send_acrnd_stop(void);
|
||||
static int send_acrnd_start(void);
|
||||
|
||||
void *cbc_heartbeat_loop(void)
|
||||
{
|
||||
state_machine_t last_state = S_DEFAULT;
|
||||
const int p_size = sizeof(cbc_heartbeat_init);
|
||||
cbc_send_data(cbc_lifecycle_fd, cbc_heartbeat_init, p_size);
|
||||
fprintf(stderr, "send heartbeat init\n");
|
||||
while (1) {
|
||||
char *heartbeat;
|
||||
state_machine_t cur_state = get_state();
|
||||
|
||||
switch (cur_state) {
|
||||
case S_DEFAULT:
|
||||
heartbeat = NULL;
|
||||
break;
|
||||
case S_ALIVE:
|
||||
if (last_state != S_ALIVE) {
|
||||
send_acrnd_start();
|
||||
}
|
||||
heartbeat = cbc_heartbeat_active;
|
||||
break;
|
||||
case S_SHUTDOWN:
|
||||
/* when ACRND detects our off request, we must wait if
|
||||
* UOS really accept the requst, thus we send shutdown
|
||||
* delay */
|
||||
send_acrnd_stop();
|
||||
cur_state = state_transit(S_SHUTDOWN_DELAY);
|
||||
// falling through
|
||||
case S_SHUTDOWN_DELAY:
|
||||
heartbeat = cbc_heartbeat_shutdown_delay;
|
||||
break;
|
||||
case S_ACRND_SHUTDOWN:
|
||||
heartbeat = cbc_heartbeat_shutdown;
|
||||
break;
|
||||
case S_ACRND_REBOOT:
|
||||
heartbeat = cbc_heartbeat_reboot;
|
||||
break;
|
||||
case S_ACRND_SUSPEND:
|
||||
heartbeat = cbc_heartbeat_s3;
|
||||
break;
|
||||
case S_IOC_SHUTDOWN:
|
||||
if (last_state == S_ACRND_SHUTDOWN)
|
||||
system("shutdown 0");
|
||||
else if (last_state == S_ACRND_REBOOT)
|
||||
system("reboot");
|
||||
else if (last_state == S_ACRND_SUSPEND)
|
||||
system("echo mem > /sys/power/state");
|
||||
//no heartbeat sent from now
|
||||
heartbeat = NULL;
|
||||
break;
|
||||
}
|
||||
if (heartbeat) {
|
||||
cbc_send_data(cbc_lifecycle_fd, heartbeat, p_size);
|
||||
fprintf(stderr, ".");
|
||||
}
|
||||
last_state = cur_state;
|
||||
/* delay 1 second to send next heart beat */
|
||||
sleep(1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *cbc_wakeup_reason_thread(void *arg)
|
||||
{
|
||||
wakeup_reason_frame data;
|
||||
int len;
|
||||
|
||||
while (1) {
|
||||
len = cbc_read_data(cbc_lifecycle_fd, (uint8_t *)&data, sizeof(data));
|
||||
if (len > 0) {
|
||||
if (data.header != 1) {
|
||||
fprintf(stderr, "received wrong wakeup reason");
|
||||
continue;
|
||||
}
|
||||
wakeup_reason = data.wakeup[0] | data.wakeup[1] << 8 | data.wakeup[2] << 16;
|
||||
if (!wakeup_reason)
|
||||
state_transit(S_IOC_SHUTDOWN);
|
||||
else if (!(wakeup_reason & ~(1 << 23)))
|
||||
state_transit(S_SHUTDOWN);
|
||||
else
|
||||
state_transit(S_ALIVE);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int cbcd_fd;
|
||||
|
||||
static void handle_shutdown(struct mngr_msg *msg, int client_fd, void *param)
|
||||
{
|
||||
struct mngr_msg ack;
|
||||
|
||||
ack.magic = MNGR_MSG_MAGIC;
|
||||
ack.msgid = msg->msgid;
|
||||
ack.timestamp = msg->timestamp;
|
||||
ack.data.err = 0;
|
||||
|
||||
fprintf(stderr, "acrnd agreed to shutdown\n");
|
||||
state_transit(S_ACRND_SHUTDOWN);
|
||||
mngr_send_msg(client_fd, &ack, NULL, 0);
|
||||
}
|
||||
|
||||
static void handle_suspend(struct mngr_msg *msg, int client_fd, void *param)
|
||||
{
|
||||
struct mngr_msg ack;
|
||||
|
||||
ack.magic = MNGR_MSG_MAGIC;
|
||||
ack.msgid = msg->msgid;
|
||||
ack.timestamp = msg->timestamp;
|
||||
ack.data.err = 0;
|
||||
|
||||
state_transit(S_ACRND_SUSPEND);
|
||||
mngr_send_msg(client_fd, &ack, NULL, 0);
|
||||
}
|
||||
|
||||
static void handle_reboot(struct mngr_msg *msg, int client_fd, void *param)
|
||||
{
|
||||
struct mngr_msg ack;
|
||||
|
||||
ack.magic = MNGR_MSG_MAGIC;
|
||||
ack.msgid = msg->msgid;
|
||||
ack.timestamp = msg->timestamp;
|
||||
|
||||
ack.data.err = 0;
|
||||
|
||||
state_transit(S_ACRND_REBOOT);
|
||||
mngr_send_msg(client_fd, &ack, NULL, 0);
|
||||
}
|
||||
|
||||
static void handle_wakeup_reason(struct mngr_msg *msg, int client_fd, void *param)
|
||||
{
|
||||
struct mngr_msg ack;
|
||||
|
||||
ack.magic = MNGR_MSG_MAGIC;
|
||||
ack.msgid = msg->msgid;
|
||||
ack.timestamp = msg->timestamp;
|
||||
|
||||
ack.data.reason = wakeup_reason;
|
||||
mngr_send_msg(client_fd, &ack, NULL, 0);
|
||||
}
|
||||
|
||||
static void handle_rtc(struct mngr_msg *msg, int client_fd, void *param)
|
||||
{
|
||||
struct mngr_msg ack;
|
||||
|
||||
ack.magic = MNGR_MSG_MAGIC;
|
||||
ack.msgid = msg->msgid;
|
||||
ack.timestamp = msg->timestamp;
|
||||
|
||||
fprintf(stderr, "%s request rtc timer at %lu, result will be %d\n",
|
||||
msg->data.rtc_timer.vmname, msg->data.rtc_timer.t,
|
||||
ack.data.err);
|
||||
/* Need wait IOC firmware to support RTC */
|
||||
ack.data.err = -1;
|
||||
|
||||
mngr_send_msg(client_fd, &ack, NULL, 0);
|
||||
}
|
||||
|
||||
static int send_acrnd_start(void)
|
||||
{
|
||||
int acrnd_fd;
|
||||
int ret;
|
||||
struct mngr_msg req = {
|
||||
.msgid = ACRND_RESUME,
|
||||
.magic = MNGR_MSG_MAGIC,
|
||||
};
|
||||
struct mngr_msg ack;
|
||||
|
||||
req.timestamp = time(NULL);
|
||||
acrnd_fd = mngr_open_un(acrnd_name, MNGR_CLIENT);
|
||||
if (acrnd_fd < 0) {
|
||||
fprintf(stderr, "cannot open %s socket\n", acrnd_name);
|
||||
return -1;
|
||||
}
|
||||
ret = mngr_send_msg(acrnd_fd, &req, &ack, 2);
|
||||
if (ret > 0)
|
||||
fprintf(stderr, "result %d\n", ack.data.err);
|
||||
mngr_close(acrnd_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int send_acrnd_stop(void)
|
||||
{
|
||||
int acrnd_fd;
|
||||
int ret;
|
||||
struct mngr_msg req = {
|
||||
.msgid = ACRND_STOP,
|
||||
.magic = MNGR_MSG_MAGIC,
|
||||
.data = {
|
||||
.acrnd_stop = {
|
||||
.force = 0,
|
||||
.timeout = 20,
|
||||
},
|
||||
},
|
||||
};
|
||||
struct mngr_msg ack;
|
||||
|
||||
req.timestamp = time(NULL);
|
||||
acrnd_fd = mngr_open_un(acrnd_name, MNGR_CLIENT);
|
||||
if (acrnd_fd < 0) {
|
||||
fprintf(stderr, "cannot open %s socket\n", acrnd_name);
|
||||
return -1;
|
||||
}
|
||||
ret = mngr_send_msg(acrnd_fd, &req, &ack, 2);
|
||||
if (ret > 0)
|
||||
fprintf(stderr, "result %d\n", ack.data.err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
cbc_thread_t wakeup_reason_thread_ptr;
|
||||
|
||||
cbc_lifecycle_fd = open_cbc_device(cbc_lifecycle_dev);
|
||||
if (cbc_lifecycle_fd < 0)
|
||||
goto err_cbc;
|
||||
/* the handle_* function may reply on a close fd, since the client
|
||||
* can close the client_fd and ignore the ack */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
cbcd_fd = mngr_open_un(cbcd_name, MNGR_SERVER);
|
||||
if (cbcd_fd < 0) {
|
||||
fprintf(stderr, "cannot open %s socket\n", cbcd_name);
|
||||
goto err_un;
|
||||
}
|
||||
cbc_thread_create(&wakeup_reason_thread_ptr, cbc_wakeup_reason_thread,
|
||||
NULL); // thread to handle wakeup_reason Rx data
|
||||
|
||||
mngr_add_handler(cbcd_fd, WAKEUP_REASON, handle_wakeup_reason, NULL);
|
||||
mngr_add_handler(cbcd_fd, RTC_TIMER, handle_rtc, NULL);
|
||||
mngr_add_handler(cbcd_fd, SHUTDOWN, handle_shutdown, NULL);
|
||||
mngr_add_handler(cbcd_fd, SUSPEND, handle_suspend, NULL);
|
||||
mngr_add_handler(cbcd_fd, REBOOT, handle_reboot, NULL);
|
||||
cbc_heartbeat_loop();
|
||||
// shouldn't be here
|
||||
mngr_close(cbcd_fd);
|
||||
err_un:
|
||||
close_cbc_device(cbc_lifecycle_fd);
|
||||
err_cbc:
|
||||
return 0;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
[Unit]
|
||||
Description=CBC lifecycle service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/cbc_lifecycle
|
||||
Restart=no
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
Loading…
Reference in New Issue
Block a user