You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
898 lines
21 KiB
898 lines
21 KiB
/* |
|
* Copyright (c) 2019 Intel corporation |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/init.h> |
|
#include <stdio.h> |
|
#include <ctype.h> |
|
#include <zephyr/kernel.h> |
|
#include <mipi_syst.h> |
|
#include <zephyr/spinlock.h> |
|
#include <zephyr/sys/__assert.h> |
|
#include <zephyr/sys/check.h> |
|
#include <zephyr/linker/utils.h> |
|
#include <zephyr/logging/log.h> |
|
#include <zephyr/logging/log_ctrl.h> |
|
#include <zephyr/logging/log_output.h> |
|
|
|
static struct mipi_syst_header log_syst_header; |
|
static struct mipi_syst_handle log_syst_handle; |
|
|
|
#define HEXDUMP_BYTES_IN_LINE 16 |
|
|
|
#define STRING_BUF_MAX_LEN 128 |
|
|
|
#if defined(MIPI_SYST_PCFG_ENABLE_PLATFORM_STATE_DATA) |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
static mipi_syst_u16 master = 128; |
|
static mipi_syst_u16 channel = 1; |
|
|
|
static struct stp_writer_data writer_state; |
|
#elif !defined(CONFIG_MIPI_SYST_RAW_DATA) |
|
static const char pattern[] = "SYS-T RAW DATA: "; |
|
static const char valToHex[] = "0123456789ABCDEF"; |
|
#endif |
|
|
|
static int out_func(int c, void *ctx) |
|
{ |
|
const struct log_output *out_ctx = (const struct log_output *)ctx; |
|
|
|
out_ctx->buf[out_ctx->control_block->offset] = (uint8_t)c; |
|
out_ctx->control_block->offset++; |
|
|
|
__ASSERT_NO_MSG(out_ctx->control_block->offset <= out_ctx->size); |
|
|
|
if (out_ctx->control_block->offset == out_ctx->size) { |
|
log_output_flush(out_ctx); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
static void stp_write_putNibble(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u8 n) |
|
{ |
|
p->current |= (n << 4); |
|
p->byteDone = !p->byteDone; |
|
|
|
if (p->byteDone) { |
|
out_func(p->current, systh->systh_platform.log_output); |
|
p->current = 0; |
|
} else { |
|
p->current >>= 4; |
|
} |
|
} |
|
|
|
static void stp_write_flush(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p) |
|
{ |
|
if (!p->byteDone) { |
|
stp_write_putNibble(systh, p, 0); |
|
} |
|
} |
|
|
|
static void stp_write_d4(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u8 v) |
|
{ |
|
stp_write_putNibble(systh, p, v); |
|
} |
|
|
|
static void stp_write_payload8(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u8 v) |
|
{ |
|
stp_write_d4(systh, p, v); |
|
stp_write_d4(systh, p, v>>4); |
|
} |
|
|
|
static void stp_write_payload16(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u16 v) |
|
{ |
|
stp_write_payload8(systh, p, (mipi_syst_u8)v); |
|
stp_write_payload8(systh, p, (mipi_syst_u8)(v>>8)); |
|
} |
|
|
|
static void stp_write_payload32(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u32 v) |
|
{ |
|
stp_write_payload16(systh, p, (mipi_syst_u16)v); |
|
stp_write_payload16(systh, p, (mipi_syst_u16)(v>>16)); |
|
} |
|
|
|
static void stp_write_payload64(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u64 v) |
|
{ |
|
stp_write_payload32(systh, p, (mipi_syst_u32)v); |
|
stp_write_payload32(systh, p, (mipi_syst_u32)(v>>32)); |
|
} |
|
|
|
static mipi_syst_u64 deltaTime(struct stp_writer_data *p) |
|
{ |
|
mipi_syst_u64 delta; |
|
|
|
delta = mipi_syst_get_epoch() - p->timestamp; |
|
return delta * 60; |
|
} |
|
|
|
static void stp_write_d32mts(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u32 v) |
|
{ |
|
stp_write_d4(systh, p, 0xA); |
|
stp_write_payload32(systh, p, v); |
|
|
|
stp_write_d4(systh, p, 0xE); |
|
stp_write_payload64(systh, p, deltaTime(p)); |
|
} |
|
|
|
static void stp_write_d64mts(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u64 v) |
|
{ |
|
stp_write_d4(systh, p, 0xB); |
|
stp_write_payload64(systh, p, v); |
|
|
|
stp_write_d4(systh, p, 0xE); |
|
stp_write_payload64(systh, p, deltaTime(p)); |
|
} |
|
|
|
static void stp_write_d32ts(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u32 v) |
|
{ |
|
stp_write_d4(systh, p, 0xF); |
|
stp_write_d4(systh, p, 0x6); |
|
|
|
stp_write_payload32(systh, p, v); |
|
|
|
stp_write_d4(systh, p, 0xE); |
|
stp_write_payload64(systh, p, deltaTime(p)); |
|
} |
|
|
|
static void stp_write_d8(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u8 v) |
|
{ |
|
stp_write_d4(systh, p, 0x4); |
|
stp_write_payload8(systh, p, v); |
|
} |
|
|
|
static void stp_write_d16(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u16 v) |
|
{ |
|
stp_write_d4(systh, p, 0x5); |
|
stp_write_payload16(systh, p, v); |
|
} |
|
|
|
static void stp_write_d32(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u32 v) |
|
{ |
|
stp_write_d4(systh, p, 0x6); |
|
stp_write_payload32(systh, p, v); |
|
} |
|
|
|
#if defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO) |
|
static void stp_write_d64(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, mipi_syst_u64 v) |
|
{ |
|
stp_write_d4(systh, p, 0x7); |
|
stp_write_payload64(systh, p, v); |
|
} |
|
#endif |
|
|
|
static void stp_write_flag(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p) |
|
{ |
|
stp_write_d4(systh, p, 0xF); |
|
stp_write_d4(systh, p, 0xE); |
|
} |
|
|
|
static void stp_write_async(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p) |
|
{ |
|
for (int i = 0; i < 21; ++i) { |
|
stp_write_d4(systh, p, 0xF); |
|
} |
|
|
|
stp_write_d4(systh, p, 0x0); |
|
} |
|
|
|
static void stp_write_version(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p) |
|
{ |
|
stp_write_d4(systh, p, 0xF); |
|
stp_write_d4(systh, p, 0x0); |
|
stp_write_d4(systh, p, 0x0); |
|
|
|
stp_write_d4(systh, p, 0x3); |
|
|
|
p->master = 0; |
|
p->channel = 0; |
|
} |
|
|
|
static void stp_write_freq(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p) |
|
{ |
|
stp_write_d4(systh, p, 0xF); |
|
stp_write_d4(systh, p, 0x0); |
|
stp_write_d4(systh, p, 0x8); |
|
stp_write_payload32(systh, p, 60 * 1000 * 1000); |
|
} |
|
|
|
static void stp_write_setMC(struct mipi_syst_handle *systh, |
|
struct stp_writer_data *p, |
|
mipi_syst_u16 master, |
|
mipi_syst_u16 channel) |
|
{ |
|
if (!(p->recordCount++ % 20)) { |
|
stp_write_async(systh, p); |
|
stp_write_version(systh, p); |
|
stp_write_freq(systh, p); |
|
} |
|
|
|
if (p->master != master) { |
|
stp_write_d4(systh, p, 0xF); |
|
stp_write_d4(systh, p, 0x1); |
|
stp_write_payload16(systh, p, master); |
|
|
|
p->master = master; |
|
p->channel = 0; |
|
} |
|
|
|
if (p->channel != channel) { |
|
stp_write_d4(systh, p, 0xF); |
|
stp_write_d4(systh, p, 0x3); |
|
stp_write_payload16(systh, p, channel); |
|
|
|
p->channel = channel; |
|
} |
|
} |
|
#else |
|
static void write_raw(struct mipi_syst_handle *systh, const void *p, int n) |
|
{ |
|
int i; |
|
uint8_t c; |
|
|
|
#if defined(MIPI_SYST_BIG_ENDIAN) |
|
for (i = n - 1; i >= 0; --i) { |
|
#else |
|
for (i = 0; i < n; ++i) { |
|
#endif |
|
c = ((const uint8_t *)p)[i]; |
|
#if defined(CONFIG_MIPI_SYST_RAW_DATA) |
|
out_func(c, systh->systh_platform.log_output); |
|
#else |
|
out_func(valToHex[c >> 0x4], systh->systh_platform.log_output); |
|
out_func(valToHex[c & 0xF], systh->systh_platform.log_output); |
|
#endif |
|
} |
|
} |
|
#endif |
|
|
|
static void write_d8(struct mipi_syst_handle *systh, uint8_t v) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
struct stp_writer_data *writer = |
|
systh->systh_header->systh_platform.stpWriter; |
|
|
|
stp_write_d8(systh, writer, v); |
|
#else |
|
write_raw(systh, &v, sizeof(v)); |
|
#endif |
|
} |
|
|
|
static void write_d16(struct mipi_syst_handle *systh, uint16_t v) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
struct stp_writer_data *writer = |
|
systh->systh_header->systh_platform.stpWriter; |
|
|
|
stp_write_d16(systh, writer, v); |
|
#else |
|
write_raw(systh, &v, sizeof(v)); |
|
#endif |
|
} |
|
|
|
static void write_d32(struct mipi_syst_handle *systh, uint32_t v) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
struct stp_writer_data *writer = |
|
systh->systh_header->systh_platform.stpWriter; |
|
|
|
stp_write_d32(systh, writer, v); |
|
#else |
|
write_raw(systh, &v, sizeof(v)); |
|
#endif |
|
} |
|
|
|
#if defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO) |
|
static void write_d64(struct mipi_syst_handle *systh, uint64_t v) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
struct stp_writer_data *writer = |
|
systh->systh_header->systh_platform.stpWriter; |
|
|
|
stp_write_d64(systh, writer, v); |
|
#else |
|
write_raw(systh, &v, sizeof(v)); |
|
#endif |
|
} |
|
#endif |
|
|
|
static void write_d32ts(struct mipi_syst_handle *systh, uint32_t v) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
struct stp_writer_data *writer = |
|
systh->systh_header->systh_platform.stpWriter; |
|
|
|
stp_write_setMC(systh, writer, |
|
systh->systh_platform.master, |
|
systh->systh_platform.channel); |
|
stp_write_d32ts(systh, writer, v); |
|
#elif defined(CONFIG_MIPI_SYST_RAW_DATA) |
|
ARG_UNUSED(systh); |
|
|
|
write_raw(systh, &v, sizeof(v)); |
|
#else |
|
for (int i = 0; i < strlen(pattern); i++) { |
|
out_func(pattern[i], systh->systh_platform.log_output); |
|
} |
|
|
|
write_raw(systh, &v, sizeof(v)); |
|
#endif |
|
} |
|
|
|
static void write_d32mts(struct mipi_syst_handle *systh, mipi_syst_u32 v) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
struct stp_writer_data *writer = |
|
systh->systh_header->systh_platform.stpWriter; |
|
|
|
stp_write_setMC(systh, writer, |
|
systh->systh_platform.master, |
|
systh->systh_platform.channel); |
|
stp_write_d32mts(systh, writer, v); |
|
#else |
|
ARG_UNUSED(systh); |
|
ARG_UNUSED(v); |
|
#endif |
|
} |
|
|
|
static void write_d64mts(struct mipi_syst_handle *systh, mipi_syst_u64 v) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
struct stp_writer_data *writer = |
|
systh->systh_header->systh_platform.stpWriter; |
|
|
|
stp_write_setMC(systh, writer, |
|
systh->systh_platform.master, |
|
systh->systh_platform.channel); |
|
stp_write_d64mts(systh, writer, v); |
|
#else |
|
ARG_UNUSED(systh); |
|
ARG_UNUSED(v); |
|
#endif |
|
} |
|
|
|
static void write_flag(struct mipi_syst_handle *systh) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
struct stp_writer_data *writer = |
|
systh->systh_header->systh_platform.stpWriter; |
|
|
|
stp_write_flag(systh, writer); |
|
stp_write_flush(systh, writer); |
|
#elif defined(CONFIG_MIPI_SYST_RAW_DATA) |
|
ARG_UNUSED(systh); |
|
#else |
|
uint32_t flag = systh->systh_platform.flag; |
|
|
|
if ((flag & LOG_OUTPUT_FLAG_CRLF_NONE) != 0U) { |
|
return; |
|
} |
|
|
|
if ((flag & LOG_OUTPUT_FLAG_CRLF_LFONLY) != 0U) { |
|
out_func('\n', systh->systh_platform.log_output); |
|
} else { |
|
out_func('\r', systh->systh_platform.log_output); |
|
out_func('\n', systh->systh_platform.log_output); |
|
} |
|
#endif |
|
} |
|
#endif |
|
|
|
#if defined(MIPI_SYST_PCFG_ENABLE_TIMESTAMP) |
|
mipi_syst_u64 mipi_syst_get_epoch(void) |
|
{ |
|
return k_uptime_ticks(); |
|
} |
|
#endif |
|
|
|
static void update_systh_platform_data(struct mipi_syst_handle *handle, |
|
const struct log_output *log_output, |
|
uint32_t flag) |
|
{ |
|
#if defined(MIPI_SYST_PCFG_ENABLE_PLATFORM_STATE_DATA) |
|
handle->systh_platform.flag = (mipi_syst_u32)flag; |
|
handle->systh_platform.log_output = (struct log_output *)log_output; |
|
#endif |
|
} |
|
|
|
#if defined(CONFIG_LOG_MIPI_SYST_OUTPUT_LOG_MSG_SRC_ID) |
|
/** |
|
* @brief Set module ID in the origin unit of Sys-T message |
|
* |
|
* Note that this only sets the module ID if |
|
* CONFIG_LOG_MIPI_SYST_OUTPUT_LOG_MSG_SRC_ID is enabled. |
|
* Otherwise, this is a no-op as the module ID is set to |
|
* default at boot time, and no need to be set again. |
|
* |
|
* @param handle Pointer to mipi_syst_handle struct |
|
* @param module_id Module ID to be set (range 0x00 - 0x7F) |
|
*/ |
|
static void update_handle_origin_unit(struct mipi_syst_handle *handle, |
|
int16_t module_id) |
|
{ |
|
handle->systh_tag.et_modunit = |
|
_MIPI_SYST_MK_MODUNIT_ORIGIN( |
|
module_id, |
|
CONFIG_LOG_MIPI_SYST_MSG_DEFAULT_UNIT_ID |
|
); |
|
} |
|
#endif |
|
|
|
#if defined(MIPI_SYST_PCFG_ENABLE_PLATFORM_HANDLE_DATA) |
|
/* |
|
* Platform specific SyS-T handle initialization hook function |
|
* |
|
* @param systh pointer to the SyS-T handle structure |
|
*/ |
|
static void platform_handle_init(struct mipi_syst_handle *systh) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
if (channel > 127) { |
|
++master; |
|
channel = 1; |
|
} |
|
|
|
systh->systh_platform.channel = channel++; |
|
systh->systh_platform.master = master; |
|
#endif |
|
|
|
#if defined(MIPI_SYST_PCFG_LENGTH_FIELD) |
|
MIPI_SYST_ENABLE_HANDLE_LENGTH(systh, 1); |
|
#endif |
|
|
|
#if defined(MIPI_SYST_PCFG_ENABLE_TIMESTAMP) |
|
MIPI_SYST_ENABLE_HANDLE_TIMESTAMP(systh, 1); |
|
#endif |
|
} |
|
|
|
static void platform_handle_release(struct mipi_syst_handle *systh) |
|
{ |
|
ARG_UNUSED(systh); |
|
} |
|
#endif |
|
|
|
/* |
|
* Platform specific global state initialization hook function |
|
* |
|
* @param systh pointer to the new SyS-T handle structure |
|
* @param platform_data user defined data for the init function. |
|
* |
|
*/ |
|
static void mipi_syst_platform_init(struct mipi_syst_header *systh, |
|
const void *platform_data) |
|
{ |
|
#if defined(CONFIG_MIPI_SYST_STP) |
|
writer_state.byteDone = 0; |
|
writer_state.current = 0; |
|
writer_state.master = 0; |
|
writer_state.channel = 0; |
|
writer_state.recordCount = 0; |
|
writer_state.timestamp = mipi_syst_get_epoch(); |
|
|
|
systh->systh_platform.stpWriter = &writer_state; |
|
#endif |
|
|
|
#if defined(MIPI_SYST_PCFG_ENABLE_PLATFORM_HANDLE_DATA) |
|
systh->systh_inith = platform_handle_init; |
|
systh->systh_releaseh = platform_handle_release; |
|
#endif |
|
#if defined(MIPI_SYST_PCFG_ENABLE_PLATFORM_STATE_DATA) |
|
systh->systh_platform.write_d8 = write_d8; |
|
systh->systh_platform.write_d16 = write_d16; |
|
systh->systh_platform.write_d32 = write_d32; |
|
#if defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO) |
|
systh->systh_platform.write_d64 = write_d64; |
|
#endif |
|
systh->systh_platform.write_d32ts = write_d32ts; |
|
systh->systh_platform.write_d32mts = write_d32mts; |
|
systh->systh_platform.write_d64mts = write_d64mts; |
|
systh->systh_platform.write_flag = write_flag; |
|
#endif |
|
} |
|
|
|
/* |
|
* 0 MIPI_SYST_SEVERITY_MAX no assigned severity |
|
* 1 MIPI_SYST_SEVERITY_FATAL critical error level |
|
* 2 MIPI_SYST_SEVERITY_ERROR error message level |
|
* 3 MIPI_SYST_SEVERITY_WARNING warning message level |
|
* 4 MIPI_SYST_SEVERITY_INFO information message level |
|
* 5 MIPI_SYST_SEVERITY_USER1 user defined level 5 |
|
* 6 MIPI_SYST_SEVERITY_USER2 user defined level 6 |
|
* 7 MIPI_SYST_SEVERITY_DEBUG debug information level |
|
*/ |
|
static uint32_t level_to_syst_severity(uint32_t level) |
|
{ |
|
uint32_t ret; |
|
|
|
switch (level) { |
|
case LOG_LEVEL_NONE: |
|
ret = 0U; |
|
break; |
|
case LOG_LEVEL_ERR: |
|
ret = 2U; |
|
break; |
|
case LOG_LEVEL_WRN: |
|
ret = 3U; |
|
break; |
|
case LOG_LEVEL_INF: |
|
ret = 4U; |
|
break; |
|
case LOG_LEVEL_DBG: |
|
ret = 7U; |
|
break; |
|
default: |
|
ret = 7U; |
|
break; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static void hexdump_line_print(const uint8_t *data, uint32_t length, |
|
uint32_t severity) |
|
{ |
|
char hexdump_buf[HEXDUMP_BYTES_IN_LINE * 4 + 4]; |
|
|
|
hexdump_buf[sizeof(hexdump_buf) - 1] = '\0'; |
|
char *buf = &hexdump_buf[0]; |
|
|
|
for (int i = 0; i < HEXDUMP_BYTES_IN_LINE; i++) { |
|
if (i > 0 && !(i % 8)) { |
|
*buf = ' '; |
|
buf++; |
|
} |
|
|
|
if (i < length) { |
|
sprintf(buf, "%02x ", data[i]); |
|
} else { |
|
sprintf(buf, " "); |
|
} |
|
|
|
buf += 3; |
|
} |
|
|
|
*buf = '|'; |
|
buf++; |
|
|
|
for (int i = 0; i < HEXDUMP_BYTES_IN_LINE; i++) { |
|
if (i > 0 && !(i % 8)) { |
|
*buf = ' '; |
|
buf++; |
|
} |
|
|
|
if (i < length) { |
|
unsigned char c = (unsigned char)data[i]; |
|
|
|
*buf = isprint((int)c) ? c : '.'; |
|
} else { |
|
*buf = ' '; |
|
} |
|
|
|
buf++; |
|
} |
|
|
|
MIPI_SYST_PRINTF(&log_syst_handle, severity, "%s", hexdump_buf); |
|
} |
|
|
|
static void hexdump2_print(const uint8_t *data, uint32_t length, |
|
uint32_t severity) |
|
{ |
|
while (length != 0U) { |
|
uint32_t part_len = MIN(length, HEXDUMP_BYTES_IN_LINE); |
|
|
|
hexdump_line_print(data, part_len, severity); |
|
|
|
data += part_len; |
|
length -= part_len; |
|
} |
|
} |
|
|
|
static int mipi_vprintf_formatter(cbprintf_cb out, void *ctx, |
|
const char *fmt, va_list ap) |
|
{ |
|
struct log_msg *msg = ctx; |
|
uint32_t severity = level_to_syst_severity(log_msg_get_level(msg)); |
|
|
|
MIPI_SYST_VPRINTF(&log_syst_handle, severity, fmt, ap); |
|
|
|
return 0; |
|
} |
|
|
|
#ifdef CONFIG_LOG_MIPI_SYST_USE_CATALOG |
|
|
|
#ifdef CONFIG_64BIT |
|
#define MIPI_SYST_CATMSG_ARGS_COPY MIPI_SYST_CATALOG64_ARGS_COPY |
|
#else |
|
#define MIPI_SYST_CATMSG_ARGS_COPY MIPI_SYST_CATALOG32_ARGS_COPY |
|
#endif |
|
|
|
static inline bool is_in_log_strings_section(const void *addr) |
|
{ |
|
TYPE_SECTION_START_EXTERN(const char *, log_strings); |
|
TYPE_SECTION_END_EXTERN(const char *, log_strings); |
|
|
|
if (((const char *)addr >= (const char *)TYPE_SECTION_START(log_strings)) && |
|
((const char *)addr < (const char *)TYPE_SECTION_END(log_strings))) { |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
static struct k_spinlock payload_lock; |
|
static uint8_t payload_buf[CONFIG_LOG_MIPI_SYST_CATALOG_ARGS_BUFFER_SIZE]; |
|
|
|
static int mipi_catalog_formatter(cbprintf_cb out, void *ctx, |
|
const char *fmt, va_list ap) |
|
{ |
|
struct log_msg *msg = ctx; |
|
uint32_t severity = level_to_syst_severity(log_msg_get_level(msg)); |
|
k_spinlock_key_t key; |
|
|
|
union { |
|
mipi_syst_u64 v64; |
|
mipi_syst_u32 v32; |
|
|
|
unsigned int u; |
|
unsigned long lu; |
|
unsigned long long llu; |
|
|
|
double d; |
|
|
|
void *p; |
|
} val; |
|
|
|
const char *s; |
|
size_t arg_sz; |
|
|
|
uint8_t *argp = payload_buf; |
|
const uint8_t * const argEob = payload_buf + sizeof(payload_buf); |
|
|
|
size_t payload_sz; |
|
|
|
key = k_spin_lock(&payload_lock); |
|
|
|
for (int arg_tag = va_arg(ap, int); |
|
arg_tag != CBPRINTF_PACKAGE_ARG_TYPE_END; |
|
arg_tag = va_arg(ap, int)) { |
|
|
|
switch (arg_tag) { |
|
case CBPRINTF_PACKAGE_ARG_TYPE_CHAR: |
|
__fallthrough; |
|
case CBPRINTF_PACKAGE_ARG_TYPE_UNSIGNED_CHAR: |
|
__fallthrough; |
|
case CBPRINTF_PACKAGE_ARG_TYPE_SHORT: |
|
__fallthrough; |
|
case CBPRINTF_PACKAGE_ARG_TYPE_UNSIGNED_SHORT: |
|
__fallthrough; |
|
case CBPRINTF_PACKAGE_ARG_TYPE_INT: |
|
__fallthrough; |
|
case CBPRINTF_PACKAGE_ARG_TYPE_UNSIGNED_INT: |
|
val.u = (unsigned int)va_arg(ap, unsigned int); |
|
arg_sz = sizeof(unsigned int); |
|
break; |
|
|
|
case CBPRINTF_PACKAGE_ARG_TYPE_LONG: |
|
__fallthrough; |
|
case CBPRINTF_PACKAGE_ARG_TYPE_UNSIGNED_LONG: |
|
val.lu = (unsigned long)va_arg(ap, unsigned long); |
|
arg_sz = sizeof(unsigned long); |
|
break; |
|
|
|
case CBPRINTF_PACKAGE_ARG_TYPE_LONG_LONG: |
|
__fallthrough; |
|
case CBPRINTF_PACKAGE_ARG_TYPE_UNSIGNED_LONG_LONG: |
|
val.llu = (unsigned long long)va_arg(ap, unsigned long long); |
|
arg_sz = sizeof(unsigned long long); |
|
break; |
|
|
|
case CBPRINTF_PACKAGE_ARG_TYPE_FLOAT: |
|
__fallthrough; |
|
case CBPRINTF_PACKAGE_ARG_TYPE_DOUBLE: |
|
val.d = (double)va_arg(ap, double); |
|
arg_sz = sizeof(double); |
|
break; |
|
|
|
case CBPRINTF_PACKAGE_ARG_TYPE_LONG_DOUBLE: |
|
/* Handle long double as double */ |
|
val.d = (double)va_arg(ap, long double); |
|
arg_sz = sizeof(double); |
|
break; |
|
|
|
case CBPRINTF_PACKAGE_ARG_TYPE_PTR_VOID: |
|
val.p = (void *)va_arg(ap, void *); |
|
arg_sz = sizeof(void *); |
|
break; |
|
|
|
case CBPRINTF_PACKAGE_ARG_TYPE_PTR_CHAR: |
|
s = va_arg(ap, char *); |
|
while (argp < argEob) { |
|
*argp++ = *s; |
|
if (*s == 0) { |
|
break; |
|
} |
|
s++; |
|
|
|
if (argp == argEob) { |
|
goto no_space; |
|
} |
|
} |
|
continue; |
|
|
|
default: |
|
k_spin_unlock(&payload_lock, key); |
|
return -EINVAL; |
|
} |
|
|
|
if (argp + arg_sz >= argEob) { |
|
goto no_space; |
|
} |
|
|
|
if (arg_sz == sizeof(mipi_syst_u64)) { |
|
val.v64 = MIPI_SYST_HTOLE64(val.v64); |
|
memcpy(argp, &val.v64, sizeof(val.v64)); |
|
} else { |
|
val.v32 = MIPI_SYST_HTOLE32(val.v32); |
|
memcpy(argp, &val.v32, sizeof(val.v32)); |
|
} |
|
argp += arg_sz; |
|
} |
|
|
|
/* Calculate how much buffer has been used */ |
|
payload_sz = argp - payload_buf; |
|
|
|
MIPI_SYST_CATMSG_ARGS_COPY(&log_syst_handle, severity, |
|
(uintptr_t)fmt, |
|
payload_buf, |
|
payload_sz); |
|
|
|
k_spin_unlock(&payload_lock, key); |
|
|
|
return 0; |
|
|
|
no_space: |
|
k_spin_unlock(&payload_lock, key); |
|
return -ENOSPC; |
|
} |
|
#endif /* CONFIG_LOG_MIPI_SYST_USE_CATALOG */ |
|
|
|
void log_output_msg_syst_process(const struct log_output *output, |
|
struct log_msg *msg, uint32_t flag) |
|
{ |
|
size_t len, hexdump_len; |
|
|
|
update_systh_platform_data(&log_syst_handle, output, flag); |
|
|
|
#ifdef CONFIG_LOG_MIPI_SYST_OUTPUT_LOG_MSG_SRC_ID |
|
uint8_t level = log_msg_get_level(msg); |
|
bool raw_string = (level == LOG_LEVEL_INTERNAL_RAW_STRING); |
|
int16_t source_id = CONFIG_LOG_MIPI_SYST_MSG_DEFAULT_MODULE_ID; |
|
|
|
/* Set the log source ID as Sys-T message module ID */ |
|
if (!raw_string) { |
|
void *source = (void *)log_msg_get_source(msg); |
|
|
|
if (source != NULL) { |
|
source_id = log_source_id(source); |
|
} |
|
} |
|
|
|
update_handle_origin_unit(&log_syst_handle, source_id); |
|
#endif |
|
|
|
uint8_t *data = log_msg_get_package(msg, &len); |
|
|
|
if (len) { |
|
#ifdef CONFIG_LOG_MIPI_SYST_USE_CATALOG |
|
struct cbprintf_package_hdr_ext *pkg_hdr = (void *)data; |
|
bool is_cat_msg = false, skip = false; |
|
|
|
if (is_in_log_strings_section(pkg_hdr->fmt)) { |
|
if ((pkg_hdr->hdr.desc.pkg_flags & CBPRINTF_PACKAGE_ARGS_ARE_TAGGED) == |
|
CBPRINTF_PACKAGE_ARGS_ARE_TAGGED) { |
|
/* |
|
* Only if the package has tagged argument and |
|
* the format string is in the log strings section, |
|
* then we treat it as catalog message, because: |
|
* |
|
* 1. mipi_catalog_formatter() can only deal with |
|
* tagged arguments; and, |
|
* 2. the collateral XML file only contains strings |
|
* in the log strings section. |
|
*/ |
|
is_cat_msg = true; |
|
} else { |
|
/* |
|
* The format string is in log strings section |
|
* but the package does not have tagged argument. |
|
* This cannot be processed as a catalog message, |
|
* and also means we cannot print the message as |
|
* it is highly likely that the log strings section |
|
* has been stripped from binary and cannot be |
|
* accessed. |
|
*/ |
|
skip = true; |
|
} |
|
} |
|
|
|
if (is_cat_msg) { |
|
(void)cbpprintf_external(NULL, |
|
mipi_catalog_formatter, |
|
msg, data); |
|
} else if (!skip) |
|
#endif |
|
{ |
|
#ifdef CONFIG_CBPRINTF_PACKAGE_HEADER_STORE_CREATION_FLAGS |
|
struct cbprintf_package_desc *pkg_desc = (void *)data; |
|
|
|
CHECKIF((pkg_desc->pkg_flags & CBPRINTF_PACKAGE_ARGS_ARE_TAGGED) == |
|
CBPRINTF_PACKAGE_ARGS_ARE_TAGGED) { |
|
/* |
|
* Tagged arguments are to be used with catalog messages, |
|
* and should not be used for non-tagged ones. |
|
*/ |
|
return; |
|
} |
|
#endif |
|
|
|
|
|
(void)cbpprintf_external(NULL, |
|
mipi_vprintf_formatter, |
|
msg, data); |
|
} |
|
} |
|
|
|
data = log_msg_get_data(msg, &hexdump_len); |
|
if (hexdump_len) { |
|
uint32_t severity = level_to_syst_severity(log_msg_get_level(msg)); |
|
|
|
hexdump2_print(data, hexdump_len, severity); |
|
} |
|
} |
|
|
|
static int syst_init(void) |
|
{ |
|
|
|
MIPI_SYST_INIT_STATE(&log_syst_header, |
|
mipi_syst_platform_init, (void *)0); |
|
|
|
MIPI_SYST_INIT_HANDLE_STATE(&log_syst_header, |
|
&log_syst_handle, NULL); |
|
|
|
log_syst_handle.systh_tag.et_guid = 0; |
|
|
|
#ifndef CONFIG_LOG_MIPI_SYST_OUTPUT_LOG_MSG_SRC_ID |
|
/* Set the default here once as it won't be modified anymore. */ |
|
log_syst_handle.systh_tag.et_modunit = |
|
_MIPI_SYST_MK_MODUNIT_ORIGIN( |
|
CONFIG_LOG_MIPI_SYST_MSG_DEFAULT_MODULE_ID, |
|
CONFIG_LOG_MIPI_SYST_MSG_DEFAULT_UNIT_ID |
|
); |
|
#endif |
|
|
|
return 0; |
|
} |
|
|
|
SYS_INIT(syst_init, POST_KERNEL, 0);
|
|
|