From 6367650a706c34653365027d74f561c5d9f028a1 Mon Sep 17 00:00:00 2001 From: Zhi Jin Date: Wed, 1 Aug 2018 13:23:35 +0800 Subject: [PATCH] hv: debug: add the hypervisor NPK log The npk_log is a log destination for the hypervisor, similar to the console_log and the mem_log. It can be enabled/disabled/configured by the SOS kernel via the hypercall HC_SETUP_HV_NPK_LOG. The configuration includes: 1. Set the MMIO base address of the reserved NPK master. 2. Set the log level of the hypervisor NPK log. After that, the npk_log can be enabled to write the hypervisor logs to the MMIO address of the reserved NPK master with a simple header. Signed-off-by: Zhi Jin Signed-off-by: Liu, Xiaojing Reviewed-by: CHEN Gang Acked-by: Anthony Xu --- hypervisor/arch/x86/Kconfig | 6 +- hypervisor/debug/logmsg.c | 9 ++- hypervisor/debug/npk_log.c | 106 ++++++++++++++++++++++++++ hypervisor/debug/shell.c | 25 +++--- hypervisor/debug/shell_priv.h | 3 +- hypervisor/include/arch/x86/per_cpu.h | 1 + hypervisor/include/debug/logmsg.h | 2 + hypervisor/include/debug/npk_log.h | 44 +++++++++++ 8 files changed, 183 insertions(+), 13 deletions(-) create mode 100644 hypervisor/debug/npk_log.c diff --git a/hypervisor/arch/x86/Kconfig b/hypervisor/arch/x86/Kconfig index e07c75bea..ba7d6adbc 100644 --- a/hypervisor/arch/x86/Kconfig +++ b/hypervisor/arch/x86/Kconfig @@ -50,7 +50,7 @@ config LOG_BUF_SIZE config LOG_DESTINATION int "Bitmap of consoles where logs are printed" - default 3 + default 7 config CPU_UP_TIMEOUT int "Timeout in ms when bringing up secondary CPUs" @@ -99,6 +99,10 @@ config MEM_LOGLEVEL_DEFAULT int "Default loglevel in memory" default 5 +config NPK_LOGLEVEL_DEFAULT + int "Default loglevel for the hypervisor NPK log" + default 5 + config LOW_RAM_SIZE hex "Size of the low RAM region" default 0x00010000 diff --git a/hypervisor/debug/logmsg.c b/hypervisor/debug/logmsg.c index 7d6e09678..034e9de32 100644 --- a/hypervisor/debug/logmsg.c +++ b/hypervisor/debug/logmsg.c @@ -89,14 +89,17 @@ void do_logmsg(uint32_t severity, const char *fmt, ...) uint16_t pcpu_id; bool do_console_log; bool do_mem_log; + bool do_npk_log; char *buffer; do_console_log = (((logmsg.flags & LOG_FLAG_STDOUT) != 0U) && (severity <= console_loglevel)); do_mem_log = (((logmsg.flags & LOG_FLAG_MEMORY) != 0U) && (severity <= mem_loglevel)); + do_npk_log = ((logmsg.flags & LOG_FLAG_NPK) != 0U && + (severity <= npk_loglevel)); - if (!do_console_log && !do_mem_log) { + if (!do_console_log && !do_mem_log && !do_npk_log) { return; } @@ -124,6 +127,10 @@ void do_logmsg(uint32_t severity, const char *fmt, ...) - strnlen_s(buffer, LOG_MESSAGE_MAX_SIZE), fmt, args); va_end(args); + /* Check if flags specify to output to NPK */ + if (do_npk_log) + npk_log_write(buffer, strnlen_s(buffer, LOG_MESSAGE_MAX_SIZE)); + /* Check if flags specify to output to stdout */ if (do_console_log) { spinlock_irqsave_obtain(&(logmsg.lock), &rflags); diff --git a/hypervisor/debug/npk_log.c b/hypervisor/debug/npk_log.c new file mode 100644 index 000000000..1075da8fa --- /dev/null +++ b/hypervisor/debug/npk_log.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 Intel Corporation. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +static int npk_log_enabled, npk_log_setup_ref; +static uint64_t base; + +static inline int npk_write(const char *value, void *addr, size_t sz) +{ + int ret = -1; + + if (sz >= 8U) { + mmio_write64(*(uint64_t *)value, addr); + ret = 8; + } else if (sz >= 4U) { + mmio_write32(*(uint32_t *)value, addr); + ret = 4; + } else if (sz >= 2U) { + mmio_write16(*(uint16_t *)value, addr); + ret = 2; + } else if (sz >= 1U) { + mmio_write8(*(uint8_t *)value, addr); + ret = 1; + } + + return ret; +} + +void npk_log_setup(struct hv_npk_log_param *param) +{ + int i; + + pr_info("HV_NPK_LOG: cmd %d param 0x%llx\n", param->cmd, + param->mmio_addr); + + param->res = HV_NPK_LOG_RES_KO; + if (atomic_inc_return(&npk_log_setup_ref) > 1) + goto out; + + switch (param->cmd) { + case HV_NPK_LOG_CMD_CONF: + if (param->mmio_addr || param->loglevel != 0xffffU) + param->res = HV_NPK_LOG_RES_OK; + case HV_NPK_LOG_CMD_ENABLE: + if (param->mmio_addr) + base = param->mmio_addr; + if (param->loglevel != 0xffffU) + npk_loglevel = param->loglevel; + if (base && param->cmd == HV_NPK_LOG_CMD_ENABLE) { + if (!npk_log_enabled) + for (i = 0; i < phys_cpu_num; i++) + per_cpu(npk_log_ref, i) = 0; + param->res = HV_NPK_LOG_RES_OK; + npk_log_enabled = 1; + } + break; + case HV_NPK_LOG_CMD_DISABLE: + npk_log_enabled = 0; + param->res = HV_NPK_LOG_RES_OK; + break; + case HV_NPK_LOG_CMD_QUERY: + param->res = npk_log_enabled ? HV_NPK_LOG_RES_ENABLED : + HV_NPK_LOG_RES_DISABLED; + param->loglevel = npk_loglevel; + param->mmio_addr = base; + break; + default: + pr_err("HV_NPK_LOG: unknown cmd (%d)\n", param->cmd); + break; + } + +out: + pr_info("HV_NPK_LOG: result %d\n", param->res); + atomic_dec32((uint32_t *)&npk_log_setup_ref); +} + +void npk_log_write(const char *buf, size_t buf_len) +{ + uint32_t cpu_id = get_cpu_id(); + struct npk_chan *channel = (struct npk_chan *)base; + const char *p = buf; + int sz; + uint32_t ref; + size_t len; + + if (!npk_log_enabled || !channel) + return; + + /* calculate the channel offset based on cpu_id and npk_log_ref */ + ref = (atomic_inc_return((int *)&per_cpu(npk_log_ref, cpu_id)) - 1) + & HV_NPK_LOG_REF_MASK; + channel += (cpu_id << HV_NPK_LOG_REF_SHIFT) + ref; + len = min(buf_len, HV_NPK_LOG_MAX); + mmio_write32(HV_NPK_LOG_HDR, &(channel->DnTS)); + mmio_write16(len, &(channel->Dn)); + + for (sz = 0; sz >= 0; p += sz) + sz = npk_write(p, &(channel->Dn), buf + len - p); + + mmio_write8(0U, &(channel->FLAG)); + + atomic_dec32(&per_cpu(npk_log_ref, cpu_id)); +} diff --git a/hypervisor/debug/shell.c b/hypervisor/debug/shell.c index eeddaf90f..a079c6778 100644 --- a/hypervisor/debug/shell.c +++ b/hypervisor/debug/shell.c @@ -128,6 +128,7 @@ static struct shell_cmd shell_cmds[] = { /* The initial log level*/ uint32_t console_loglevel = CONFIG_CONSOLE_LOGLEVEL_DEFAULT; uint32_t mem_loglevel = CONFIG_MEM_LOGLEVEL_DEFAULT; +uint32_t npk_loglevel = CONFIG_NPK_LOGLEVEL_DEFAULT; static struct shell hv_shell; static struct shell *p_shell = &hv_shell; @@ -872,17 +873,21 @@ static int shell_loglevel(int argc, char **argv) { char str[MAX_STR_SIZE] = {0}; - if (argc == 1) { - snprintf(str, MAX_STR_SIZE, - "console_loglevel: %u, mem_loglevel: %u\r\n", - console_loglevel, mem_loglevel); - shell_puts(str); - } else if (argc == 2) { - console_loglevel = atoi(argv[1]); - } else if (argc == 3) { - console_loglevel = atoi(argv[1]); + switch (argc) { + case 4: + npk_loglevel = atoi(argv[3]); + case 3: mem_loglevel = atoi(argv[2]); - } else { + case 2: + console_loglevel = atoi(argv[1]); + break; + case 1: + snprintf(str, MAX_STR_SIZE, "console_loglevel: %u, " + "mem_loglevel: %u, npk_loglevel: %u\r\n", + console_loglevel, mem_loglevel, npk_loglevel); + shell_puts(str); + break; + default: return -EINVAL; } diff --git a/hypervisor/debug/shell_priv.h b/hypervisor/debug/shell_priv.h index 159254ead..2563c245f 100644 --- a/hypervisor/debug/shell_priv.h +++ b/hypervisor/debug/shell_priv.h @@ -90,7 +90,8 @@ struct shell { #define SHELL_CMD_LOGDUMP_HELP "log buffer dump" #define SHELL_CMD_LOG_LVL "loglevel" -#define SHELL_CMD_LOG_LVL_PARAM "[console_loglevel] [mem_loglevel]" +#define SHELL_CMD_LOG_LVL_PARAM "[ [ " \ + "[npk_loglevel]]]" #define SHELL_CMD_LOG_LVL_HELP "get(para is NULL), or set loglevel [0-6]" #define SHELL_CMD_CPUID "cpuid" diff --git a/hypervisor/include/arch/x86/per_cpu.h b/hypervisor/include/arch/x86/per_cpu.h index 5d2655c6a..a7fd32ae4 100644 --- a/hypervisor/include/arch/x86/per_cpu.h +++ b/hypervisor/include/arch/x86/per_cpu.h @@ -23,6 +23,7 @@ struct per_cpu_region { uint64_t *sbuf[ACRN_SBUF_ID_MAX]; uint64_t vmexit_cnt[64]; uint64_t vmexit_time[64]; + uint32_t npk_log_ref; #endif uint64_t irq_count[NR_IRQS]; uint64_t softirq_pending; diff --git a/hypervisor/include/debug/logmsg.h b/hypervisor/include/debug/logmsg.h index c8de4c567..51fad560e 100644 --- a/hypervisor/include/debug/logmsg.h +++ b/hypervisor/include/debug/logmsg.h @@ -19,6 +19,7 @@ /* Logging flags */ #define LOG_FLAG_STDOUT 0x00000001U #define LOG_FLAG_MEMORY 0x00000002U +#define LOG_FLAG_NPK 0x00000004U #define LOG_ENTRY_SIZE 80 /* Size of buffer used to store a message being logged, * should align to LOG_ENTRY_SIZE. @@ -29,6 +30,7 @@ extern uint32_t console_loglevel; extern uint32_t mem_loglevel; +extern uint32_t npk_loglevel; void init_logmsg(__unused uint32_t mem_size, uint32_t flags); void print_logmsg_buffer(uint16_t pcpu_id); void do_logmsg(uint32_t severity, const char *fmt, ...); diff --git a/hypervisor/include/debug/npk_log.h b/hypervisor/include/debug/npk_log.h index 4e169d0b4..80e693795 100644 --- a/hypervisor/include/debug/npk_log.h +++ b/hypervisor/include/debug/npk_log.h @@ -6,7 +6,51 @@ #ifndef NPK_LOG_H #define NPK_LOG_H +#define HV_NPK_LOG_REF_SHIFT 2U +#define HV_NPK_LOG_REF_MASK ((1U << HV_NPK_LOG_REF_SHIFT) - 1U) + +#define HV_NPK_LOG_MAX 1024U +#define HV_NPK_LOG_HDR 0x01000242U + +enum { + HV_NPK_LOG_CMD_INVALID, + HV_NPK_LOG_CMD_CONF, + HV_NPK_LOG_CMD_ENABLE, + HV_NPK_LOG_CMD_DISABLE, + HV_NPK_LOG_CMD_QUERY, +}; + +enum { + HV_NPK_LOG_RES_INVALID, + HV_NPK_LOG_RES_OK, + HV_NPK_LOG_RES_KO, + HV_NPK_LOG_RES_ENABLED, + HV_NPK_LOG_RES_DISABLED, +}; + +struct hv_npk_log_param; + +struct npk_chan { + uint64_t Dn; + uint64_t DnM; + uint64_t DnTS; + uint64_t DnMTS; + uint64_t USER; + uint64_t USER_TS; + uint32_t FLAG; + uint32_t FLAG_TS; + uint32_t MERR; + uint32_t unused; +} __packed; + +#ifdef HV_DEBUG +void npk_log_setup(struct hv_npk_log_param *param); +void npk_log_write(const char *buf, size_t len); +#else static inline void npk_log_setup(__unused struct hv_npk_log_param *param) {} +static inline void npk_log_write(__unused const char *buf, __unused size_t len) +{} +#endif /* HV_DEBUG */ #endif /* NPK_LOG_H */