acrn-hypervisor/hypervisor/debug/shell_public.c

422 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);
}
}
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;
}