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 <zhi.jin@intel.com>
Signed-off-by: Liu, Xiaojing <xiaojing.liu@intel.com>
Reviewed-by: CHEN Gang <gang.c.chen@intel.com>
Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
Zhi Jin 2018-08-01 13:23:35 +08:00 committed by wenlingz
parent 3c6df9b70c
commit 6367650a70
8 changed files with 183 additions and 13 deletions

View File

@ -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

View File

@ -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);

106
hypervisor/debug/npk_log.c Normal file
View File

@ -0,0 +1,106 @@
/*
* Copyright (C) 2018 Intel Corporation.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <hypervisor.h>
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));
}

View File

@ -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;
}

View File

@ -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 "[<console_loglevel> [<mem_loglevel> " \
"[npk_loglevel]]]"
#define SHELL_CMD_LOG_LVL_HELP "get(para is NULL), or set loglevel [0-6]"
#define SHELL_CMD_CPUID "cpuid"

View File

@ -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;

View File

@ -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, ...);

View File

@ -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 */