mgmt: mcumgr: lib: cmd: os: Add device information handler

The device information handler can be used to retrieve information about
the configuration of the configured device such as board name, board
revision, firmware version and build date.

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
This commit is contained in:
Jamie McCrae 2022-10-17 10:27:08 +01:00 committed by Fabio Baltieri
commit 656a910b1e
6 changed files with 571 additions and 0 deletions

View file

@ -20,3 +20,10 @@ if (CONFIG_REBOOT)
endif()
target_link_libraries(mgmt_mcumgr INTERFACE mgmt_mcumgr_grp_os)
if(DEFINED CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME)
set(MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR ${PROJECT_BINARY_DIR}/os_mgmt_auto)
file(MAKE_DIRECTORY ${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR})
file(WRITE ${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR}/os_mgmt_build_date.c "/* Auto generated file, do not edit */\n#include <stdint.h>\nuint8_t *MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME = __TIMESTAMP__;")
zephyr_library_sources(${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR}/os_mgmt_build_date.c)
endif()

View file

@ -123,4 +123,39 @@ config OS_MGMT_ECHO
config OS_MGMT_MCUMGR_PARAMS
bool "MCUMGR Parameters retrieval command"
config MCUMGR_GRP_OS_INFO
bool "Support for info command"
help
Can be used similarly to the unix/linux uname command for retrieving system information
including kernel version, processor architecture and board name.
if MCUMGR_GRP_OS_INFO
config MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE
int "Maximum response size for info command"
default 256
range 32 512
help
The maximum size of the response to the info command, will use a stack buffer of this
size to store the data in. If the output response is too big then the output will not be
present in the response, which will just contain the result code (rc) of memory error.
config MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
bool "Custom info hooks"
depends on MCUMGR_MGMT_NOTIFICATION_HOOKS
help
Supports adding custom command/character processing to the info command by using
registered callbacks. Data can be appended to the struct provided in the callback.
config MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
bool "Show build date and time"
help
Will allow returning the build date and time of the firmware by using the info with
format option 'b' (will also be returned with all responses by using 'a').
Note: This will invalidate reproducible builds of the firmware as it will embed the
build date/time in the output firmware image.
endif
endif

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2022 Zephyr authors
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_OS_MGMT_PROCESSOR_
#define H_OS_MGMT_PROCESSOR_
#ifdef __cplusplus
extern "C" {
#endif
/**
* Processor name (used in uname output command)
* Will be unknown if processor type is not listed
* (List extracted from /cmake/gcc-m-cpu.cmake)
*/
#if defined(CONFIG_ARM)
#if defined(CONFIG_CPU_CORTEX_M0)
#define PROCESSOR_NAME "cortex-m0"
#elif defined(CONFIG_CPU_CORTEX_M0PLUS)
#define PROCESSOR_NAME "cortex-m0plus"
#elif defined(CONFIG_CPU_CORTEX_M1)
#define PROCESSOR_NAME "cortex-m1"
#elif defined(CONFIG_CPU_CORTEX_M3)
#define PROCESSOR_NAME "cortex-m3"
#elif defined(CONFIG_CPU_CORTEX_M4)
#define PROCESSOR_NAME "cortex-m4"
#elif defined(CONFIG_CPU_CORTEX_M7)
#define PROCESSOR_NAME "cortex-m7"
#elif defined(CONFIG_CPU_CORTEX_M23)
#define PROCESSOR_NAME "cortex-m23"
#elif defined(CONFIG_CPU_CORTEX_M33)
#if defined(CONFIG_ARMV8_M_DSP)
#define PROCESSOR_NAME "cortex-m33"
#else
#define PROCESSOR_NAME "cortex-m33+nodsp"
#endif
#elif defined(CONFIG_CPU_CORTEX_M55)
#if defined(CONFIG_ARMV8_1_M_MVEF)
#define PROCESSOR_NAME "cortex-m55"
#elif defined(CONFIG_ARMV8_1_M_MVEI)
#define PROCESSOR_NAME "cortex-m55+nomve.fp"
#elif defined(CONFIG_ARMV8_M_DSP)
#define PROCESSOR_NAME "cortex-m55+nomve"
#else
#define PROCESSOR_NAME "cortex-m55+nodsp"
#endif
#elif defined(CONFIG_CPU_CORTEX_R4)
#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP)
#define PROCESSOR_NAME "cortex-r4f"
#else
#define PROCESSOR_NAME "cortex-r4"
#endif
#elif defined(CONFIG_CPU_CORTEX_R5)
#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP)
#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION)
#define PROCESSOR_NAME "cortex-r5+nofp.dp"
#else
#define PROCESSOR_NAME "cortex-r5"
#endif
#else
#define PROCESSOR_NAME "cortex-r5+nofp"
#endif
#elif defined(CONFIG_CPU_CORTEX_R7)
#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP)
#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION)
#define PROCESSOR_NAME "cortex-r7+nofp.dp"
#else
#define PROCESSOR_NAME "cortex-r7"
#endif
#else
#define PROCESSOR_NAME "cortex-r7+nofp"
#endif
#elif defined(CONFIG_CPU_CORTEX_R52)
#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP)
#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION)
#define PROCESSOR_NAME "cortex-r52+nofp.dp"
#else
#define PROCESSOR_NAME "cortex-r52"
#endif
#else
#define PROCESSOR_NAME "cortex-r52"
#endif
#elif defined(CONFIG_CPU_CORTEX_A9)
#define PROCESSOR_NAME "cortex-a9"
#endif
#elif defined(CONFIG_ARM64)
#if defined(CONFIG_CPU_CORTEX_A53)
#define PROCESSOR_NAME "cortex-a53"
#if defined(CONFIG_CPU_CORTEX_A55)
#define PROCESSOR_NAME "cortex-a55"
#elif defined(CONFIG_CPU_CORTEX_A72)
#define PROCESSOR_NAME "cortex-a72"
#elif defined(CONFIG_CPU_CORTEX_R82)
#define PROCESSOR_NAME "armv8.4-a+nolse"
#endif
#endif
#elif defined(CONFIG_ARC)
#if defined(CONFIG_CPU_EM4_FPUS)
#define PROCESSOR_NAME "em4_fpus"
#elif defined(CONFIG_CPU_EM4_DMIPS)
#define PROCESSOR_NAME "em4_dmips"
#elif defined(CONFIG_CPU_EM4_FPUDA)
#define PROCESSOR_NAME "em4_fpuda"
#elif defined(CONFIG_CPU_HS3X)
#define PROCESSOR_NAME "archs"
#elif defined(CONFIG_CPU_HS5X)
#define PROCESSOR_NAME "hs5x"
#elif defined(CONFIG_CPU_HS6X)
#define PROCESSOR_NAME "hs6x"
#elif defined(CONFIG_CPU_EM4)
#define PROCESSOR_NAME "arcem"
#elif defined(CONFIG_CPU_EM6)
#define PROCESSOR_NAME "arcem"
#endif
#elif defined(CONFIG_X86)
#if defined(CONFIG_X86_64)
#define PROCESSOR_NAME "x86_64"
#else
#define PROCESSOR_NAME "x86"
#endif
#elif defined(CONFIG_RISCV)
#define PROCESSOR_NAME "riscv"
#endif
#ifndef PROCESSOR_NAME
#warning "Processor type could not be determined"
#define PROCESSOR_NAME "unknown"
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_OS_MGMT_PROCESSOR_ */

View file

@ -28,6 +28,18 @@
#include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
#endif
#ifdef CONFIG_MCUMGR_GRP_OS_INFO
#include <stdio.h>
#include <version.h>
#include <os_mgmt_processor.h>
#include <mgmt/mcumgr/util/zcbor_bulk.h>
#if defined(CONFIG_NET_HOSTNAME_ENABLE)
#include <zephyr/net/hostname.h>
#elif defined(CONFIG_BT)
#include <zephyr/bluetooth/bluetooth.h>
#endif
#endif
#ifdef CONFIG_REBOOT
static void os_mgmt_reset_work_handler(struct k_work *work);
static void os_mgmt_reset_cb(struct k_timer *timer);
@ -54,6 +66,19 @@ struct thread_iterator_info {
};
#endif
/* Specifies what the "all" ('a') of info parameter shows */
#define OS_MGMT_INFO_FORMAT_ALL \
OS_MGMT_INFO_FORMAT_KERNEL_NAME | OS_MGMT_INFO_FORMAT_NODE_NAME | \
OS_MGMT_INFO_FORMAT_KERNEL_RELEASE | OS_MGMT_INFO_FORMAT_KERNEL_VERSION | \
(IS_ENABLED(CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME) ? \
OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME : 0) | \
OS_MGMT_INFO_FORMAT_MACHINE | OS_MGMT_INFO_FORMAT_PROCESSOR | \
OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM | OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
extern uint8_t *MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME;
#endif
/**
* Command handler: os echo
*/
@ -318,6 +343,302 @@ os_mgmt_mcumgr_params(struct smp_streamer *ctxt)
}
#endif
#ifdef CONFIG_MCUMGR_GRP_OS_INFO
/**
* Command handler: os info
*/
static int os_mgmt_info(struct smp_streamer *ctxt)
{
struct zcbor_string format = { 0 };
uint8_t output[CONFIG_MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE] = { 0 };
zcbor_state_t *zse = ctxt->writer->zs;
zcbor_state_t *zsd = ctxt->reader->zs;
uint32_t format_bitmask = 0;
bool prior_output = false;
size_t i = 0;
size_t decoded;
bool custom_os_name = false;
int rc;
uint16_t output_length = 0;
uint16_t valid_formats = 0;
struct zcbor_map_decode_key_val fs_info_decode[] = {
ZCBOR_MAP_DECODE_KEY_VAL(format, zcbor_tstr_decode, &format),
};
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
struct os_mgmt_info_check check_data = {
.format = &format,
.format_bitmask = &format_bitmask,
.valid_formats = &valid_formats,
.custom_os_name = &custom_os_name,
};
struct os_mgmt_info_append append_data = {
.format_bitmask = &format_bitmask,
.all_format_specified = false,
.output = output,
.output_length = &output_length,
.buffer_size = sizeof(output),
.prior_output = &prior_output,
};
#endif
if (zcbor_map_decode_bulk(zsd, fs_info_decode, ARRAY_SIZE(fs_info_decode), &decoded)) {
return MGMT_ERR_EINVAL;
}
/* Process all input characters in format value */
while (i < format.len) {
switch (format.value[i]) {
case 'a': {
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
append_data.all_format_specified = true;
#endif
format_bitmask = OS_MGMT_INFO_FORMAT_ALL;
++valid_formats;
break;
}
case 's': {
format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_NAME;
++valid_formats;
break;
}
case 'n': {
format_bitmask |= OS_MGMT_INFO_FORMAT_NODE_NAME;
++valid_formats;
break;
}
case 'r': {
format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_RELEASE;
++valid_formats;
break;
}
case 'v': {
format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_VERSION;
++valid_formats;
break;
}
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
case 'b': {
format_bitmask |= OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME;
++valid_formats;
break;
}
#endif
case 'm': {
format_bitmask |= OS_MGMT_INFO_FORMAT_MACHINE;
++valid_formats;
break;
}
case 'p': {
format_bitmask |= OS_MGMT_INFO_FORMAT_PROCESSOR;
++valid_formats;
break;
}
case 'i': {
format_bitmask |= OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM;
++valid_formats;
break;
}
case 'o': {
format_bitmask |= OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM;
++valid_formats;
break;
}
default: {
break;
}
}
++i;
}
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
/* Run callbacks to see if any additional handlers will add options */
(void)mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_INFO_CHECK, &check_data,
sizeof(check_data));
#endif
if (valid_formats != format.len) {
/* A provided format specifier is not valid */
return MGMT_ERR_EINVAL;
} else if (format_bitmask == 0) {
/* If no value is provided, use default of kernel name */
format_bitmask = OS_MGMT_INFO_FORMAT_KERNEL_NAME;
}
/* Process all options in order and append to output string */
if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_NAME) {
rc = snprintf(output, (sizeof(output) - output_length), "Zephyr");
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_NODE_NAME) {
/* Get hostname, if enabled */
#if defined(CONFIG_NET_HOSTNAME_ENABLE)
/* From network */
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), net_hostname_get());
#elif defined(CONFIG_BT)
/* From Bluetooth */
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), bt_get_name());
#else
/* Not available */
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
"%sunknown", (prior_output == true ? " " : ""));
#endif
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_NODE_NAME;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_RELEASE) {
#ifdef BUILD_VERSION
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), STRINGIFY(BUILD_VERSION));
#else
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
"%sunknown", (prior_output == true ? " " : ""));
#endif
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_KERNEL_RELEASE;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_VERSION) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), KERNEL_VERSION_STRING);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_KERNEL_VERSION;
}
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
if (format_bitmask & OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"),
MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME;
}
#endif
if (format_bitmask & OS_MGMT_INFO_FORMAT_MACHINE) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), CONFIG_ARCH);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_MACHINE;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_PROCESSOR) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s" : "%s"), PROCESSOR_NAME);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_PROCESSOR;
}
if (format_bitmask & OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
(prior_output == true ? " %s%s%s" : "%s%s%s"), CONFIG_BOARD,
(sizeof(CONFIG_BOARD_REVISION) > 1 ? "@" : ""),
CONFIG_BOARD_REVISION);
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM;
}
/* If custom_os_name is not set (by extension code) then return the default OS name of
* Zephyr
*/
if (format_bitmask & OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM && custom_os_name == false) {
rc = snprintf(&output[output_length], (sizeof(output) - output_length),
"%sZephyr", (prior_output == true ? " " : ""));
if (rc < 0 || rc >= (sizeof(output) - output_length)) {
goto fail;
} else {
output_length += (uint16_t)rc;
}
prior_output = true;
format_bitmask &= ~OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM;
}
#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
/* Call custom handler command for additional output/processing */
rc = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_INFO_APPEND, &append_data,
sizeof(append_data));
if (rc != MGMT_ERR_EOK) {
return rc;
}
#endif
if (zcbor_tstr_put_lit(zse, "output") &&
zcbor_tstr_encode_ptr(zse, output, output_length)) {
return MGMT_ERR_EOK;
}
fail:
return MGMT_ERR_EMSGSIZE;
}
#endif
static const struct mgmt_handler os_mgmt_group_handlers[] = {
#ifdef CONFIG_OS_MGMT_ECHO
[OS_MGMT_ID_ECHO] = {
@ -339,6 +660,11 @@ static const struct mgmt_handler os_mgmt_group_handlers[] = {
os_mgmt_mcumgr_params, NULL
},
#endif
#ifdef CONFIG_MCUMGR_GRP_OS_INFO
[OS_MGMT_ID_INFO] = {
os_mgmt_info, NULL
},
#endif
};
#define OS_MGMT_GROUP_SZ ARRAY_SIZE(os_mgmt_group_handlers)