mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-04-30 04:33:58 +00:00
433 lines
11 KiB
C
433 lines
11 KiB
C
/*
|
|
* Copyright (C) 2018 Intel Corporation. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <hypervisor.h>
|
|
#include <hv_lib.h>
|
|
#include <acrn_common.h>
|
|
#include <hv_arch.h>
|
|
#include <hv_debug.h>
|
|
#include "shell_internal.h"
|
|
|
|
/* Shell that uses serial I/O */
|
|
static struct shell *serial_session;
|
|
|
|
static int shell_register_cmd(struct shell *p_shell,
|
|
const char *cmd,
|
|
const char *cmd_param,
|
|
const char *cmd_help_str,
|
|
int (*cmd_fcn)(struct shell *, int, char **))
|
|
{
|
|
int status = 0;
|
|
struct shell_cmd *p_cmd;
|
|
uint32_t cmd_mem_size;
|
|
|
|
if ((p_shell == NULL) || (cmd == NULL) ||
|
|
(cmd_help_str == NULL) || (cmd_fcn == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Check if a duplicate command exists */
|
|
p_cmd = shell_find_cmd(p_shell, cmd);
|
|
if (p_cmd != NULL) {
|
|
/* Requested command is already registered */
|
|
pr_err("Error: Command %s is already registered.", cmd);
|
|
status = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
/* Requested command is not already registered. So allocate enough
|
|
* memory for the command structure and the command, parameter and the
|
|
* help text strings along with the corresponding null terminating
|
|
* character/s.
|
|
*/
|
|
cmd_mem_size = sizeof(struct shell_cmd)
|
|
+ (strnlen_s(cmd, SHELL_CMD_MAX_LEN) + 1);
|
|
|
|
/* If command takes any parameters, need to allocate memory for storing
|
|
* parameter string.
|
|
*/
|
|
if (cmd_param)
|
|
cmd_mem_size += strnlen_s(cmd_param, SHELL_PARA_MAX_LEN) + 1;
|
|
|
|
/* If help text is provided for command, need to allocate memory for
|
|
* storing help string.
|
|
*/
|
|
if (cmd_help_str)
|
|
cmd_mem_size += strnlen_s(cmd_help_str, SHELL_HELP_MAX_LEN) + 1;
|
|
|
|
p_cmd = (struct shell_cmd *) calloc(1, cmd_mem_size);
|
|
if (p_cmd == NULL) {
|
|
status = -ENOMEM;
|
|
goto exit;
|
|
}
|
|
|
|
/* The command structure, command string, it's parameter string and
|
|
* the associated help string are all stored in contiguous memory
|
|
* locations. So the cmd string immediately follows the command
|
|
* structure..
|
|
*/
|
|
p_cmd->str = (char *)p_cmd + sizeof(struct shell_cmd);
|
|
strncpy_s(p_cmd->str, SHELL_CMD_MAX_LEN, cmd, SHELL_CMD_MAX_LEN);
|
|
|
|
/* Check if this command does take any parameters... */
|
|
if (cmd_param) {
|
|
/* The command parameter string immediately follows the command
|
|
* string in memory.
|
|
*/
|
|
p_cmd->cmd_param = p_cmd->str
|
|
+ (strnlen_s(cmd, SHELL_CMD_MAX_LEN) + 1);
|
|
strcpy_s(p_cmd->cmd_param, SHELL_PARA_MAX_LEN, cmd_param);
|
|
}
|
|
|
|
/* Check if help string is provided for the command.. */
|
|
if (cmd_help_str) {
|
|
if (cmd_param) {
|
|
/* The command help string immediately follows the
|
|
* parameter string in memory | cmd_structure |
|
|
* cmd_str | param_str | help_str |
|
|
*/
|
|
p_cmd->help_str = p_cmd->cmd_param +
|
|
(strnlen_s(cmd_param, SHELL_PARA_MAX_LEN) + 1);
|
|
|
|
strcpy_s(p_cmd->help_str,
|
|
SHELL_HELP_MAX_LEN, cmd_help_str);
|
|
} else {
|
|
/* No command parameter/s. Help string immediately
|
|
* follows the cmd string | cmd_structure | cmd_str |
|
|
* help_str |
|
|
*/
|
|
p_cmd->help_str = p_cmd->str +
|
|
(strnlen_s(cmd, SHELL_CMD_MAX_LEN) + 1);
|
|
|
|
strcpy_s(p_cmd->help_str,
|
|
SHELL_HELP_MAX_LEN, cmd_help_str);
|
|
}
|
|
}
|
|
|
|
/* Set the command function. */
|
|
p_cmd->fcn = cmd_fcn;
|
|
|
|
INIT_LIST_HEAD(&p_cmd->node);
|
|
list_add(&p_cmd->node, &p_shell->cmd_list);
|
|
|
|
/* Update command count. */
|
|
p_shell->cmd_count++;
|
|
|
|
status = 0;
|
|
|
|
exit:
|
|
return status;
|
|
}
|
|
|
|
int shell_init(void)
|
|
{
|
|
int status;
|
|
|
|
status = shell_construct(&serial_session);
|
|
if (status != 0)
|
|
return status;
|
|
|
|
/* Set the function pointers for the shell i/p and o/p functions */
|
|
serial_session->session_io.io_init = shell_init_serial;
|
|
serial_session->session_io.io_deinit = shell_terminate_serial;
|
|
serial_session->session_io.io_puts = shell_puts_serial;
|
|
serial_session->session_io.io_getc = shell_getc_serial;
|
|
serial_session->session_io.io_special = shell_special_serial;
|
|
serial_session->session_io.io_echo_on = (bool)true;
|
|
|
|
/* Initialize the handler for the serial port that will be used
|
|
* for shell i/p and o/p
|
|
*/
|
|
status = serial_session->session_io.io_init(serial_session);
|
|
|
|
/* Register command handlers for the shell commands that are available
|
|
* by default
|
|
*/
|
|
if (status == 0) {
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_HELP,
|
|
SHELL_CMD_HELP_PARAM,
|
|
SHELL_CMD_HELP_HELP,
|
|
shell_cmd_help);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_HELP);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VM_LIST,
|
|
SHELL_CMD_VM_LIST_PARAM,
|
|
SHELL_CMD_VM_LIST_HELP,
|
|
shell_list_vm);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VM_LIST);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VCPU_LIST,
|
|
SHELL_CMD_VCPU_LIST_PARAM,
|
|
SHELL_CMD_VCPU_LIST_HELP,
|
|
shell_list_vcpu);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VCPU_LIST);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VCPU_PAUSE,
|
|
SHELL_CMD_VCPU_PAUSE_PARAM,
|
|
SHELL_CMD_VCPU_PAUSE_HELP,
|
|
shell_pause_vcpu);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VCPU_PAUSE);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VCPU_RESUME,
|
|
SHELL_CMD_VCPU_RESUME_PARAM,
|
|
SHELL_CMD_VCPU_RESUME_HELP,
|
|
shell_resume_vcpu);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VCPU_RESUME);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VCPU_DUMPREG,
|
|
SHELL_CMD_VCPU_DUMPREG_PARAM,
|
|
SHELL_CMD_VCPU_DUMPREG_HELP,
|
|
shell_vcpu_dumpreg);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VCPU_DUMPREG);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VCPU_DUMPMEM,
|
|
SHELL_CMD_VCPU_DUMPMEM_PARAM,
|
|
SHELL_CMD_VCPU_DUMPMEM_HELP,
|
|
shell_vcpu_dumpmem);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VCPU_DUMPMEM);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VM_CONSOLE,
|
|
SHELL_CMD_VM_CONSOLE_PARAM,
|
|
SHELL_CMD_VM_CONSOLE_HELP,
|
|
shell_to_sos_console);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VM_CONSOLE);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_INTERRUPT,
|
|
SHELL_CMD_INTERRUPT_PARAM,
|
|
SHELL_CMD_INTERRUPT_HELP,
|
|
shell_show_cpu_int);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_INTERRUPT);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_PTDEV,
|
|
SHELL_CMD_PTDEV_PARAM,
|
|
SHELL_CMD_PTDEV_HELP,
|
|
shell_show_ptdev_info);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_PTDEV);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_REQ,
|
|
SHELL_CMD_REQ_PARAM,
|
|
SHELL_CMD_REQ_HELP,
|
|
shell_show_req_info);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_REQ);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VIOAPIC,
|
|
SHELL_CMD_VIOAPIC_PARAM,
|
|
SHELL_CMD_VIOAPIC_HELP,
|
|
shell_show_vioapic_info);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VIOAPIC);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_IOAPIC,
|
|
SHELL_CMD_IOAPIC_PARAM,
|
|
SHELL_CMD_IOAPIC_HELP,
|
|
shell_show_ioapic_info);
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_IOAPIC);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_VMEXIT,
|
|
SHELL_CMD_VMEXIT_PARAM,
|
|
SHELL_CMD_VMEXIT_HELP,
|
|
shell_show_vmexit_profile);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_VMEXIT);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_LOGDUMP,
|
|
SHELL_CMD_LOGDUMP_PARAM,
|
|
SHELL_CMD_LOGDUMP_HELP,
|
|
shell_dump_logbuf);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_LOGDUMP);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_GET_LOG_LVL,
|
|
SHELL_CMD_GET_LOG_LVL_PARAM,
|
|
SHELL_CMD_GET_LOG_LVL_HELP,
|
|
shell_get_loglevel);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_GET_LOG_LVL);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_SET_LOG_LVL,
|
|
SHELL_CMD_SET_LOG_LVL_PARAM,
|
|
SHELL_CMD_SET_LOG_LVL_HELP,
|
|
shell_set_loglevel);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_SET_LOG_LVL);
|
|
}
|
|
|
|
status = shell_register_cmd(serial_session,
|
|
SHELL_CMD_CPUID,
|
|
SHELL_CMD_CPUID_PARAM,
|
|
SHELL_CMD_CPUID_HELP,
|
|
shell_cpuid);
|
|
|
|
if (status != 0) {
|
|
pr_err("Error: Command \"%s\" registration failed.",
|
|
SHELL_CMD_CPUID);
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
int shell_puts(struct shell *p_shell, char *str_ptr)
|
|
{
|
|
int status;
|
|
|
|
if ((p_shell != NULL) && (p_shell->session_io.io_puts != NULL) &&
|
|
(str_ptr != NULL)) {
|
|
/* Transmit data using this shell session's 'puts' function */
|
|
p_shell->session_io.io_puts(p_shell, str_ptr);
|
|
|
|
status = 0;
|
|
} else {
|
|
/* Error: Invalid request */
|
|
status = -EINVAL;
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
int shell_set_name(struct shell *p_shell, char *name)
|
|
{
|
|
int status;
|
|
|
|
if ((p_shell != NULL) && (name != NULL)) {
|
|
strncpy_s((void *) p_shell->name, SHELL_NAME_MAX_LEN,
|
|
(void *) name, SHELL_NAME_MAX_LEN - 1);
|
|
|
|
/* Ensure null terminated string */
|
|
p_shell->name[SHELL_NAME_MAX_LEN - 1] = 0;
|
|
|
|
status = 0;
|
|
} else {
|
|
status = -EINVAL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void shell_kick_session(void)
|
|
{
|
|
/* Kick the shell */
|
|
kick_shell(serial_session);
|
|
}
|
|
|
|
int shell_switch_console(void)
|
|
{
|
|
struct vuart *vuart;
|
|
|
|
vuart = vuart_console_active();
|
|
if (vuart == NULL)
|
|
return -EINVAL;
|
|
|
|
vuart->active = false;
|
|
/* Output that switching to ACRN shell */
|
|
shell_puts(serial_session,
|
|
"\r\n\r\n----- Entering ACRN Shell -----\r\n");
|
|
return 0;
|
|
}
|