This is an automated email from the ASF dual-hosted git repository. ccollins pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git
commit 29e37f3760c88e3925ee7c07f95b51cff22dba6c Author: Christopher Collins <ccoll...@apache.org> AuthorDate: Wed Jan 17 17:12:52 2018 -0800 OS-agnostic command handlers: fs, img, os. --- cmd/fs_mgmt/include/fs_mgmt/fs_mgmt.h | 41 +++ cmd/fs_mgmt/include/fs_mgmt/fs_mgmt_impl.h | 77 +++++ cmd/fs_mgmt/src/fs_mgmt.c | 250 ++++++++++++++++ cmd/fs_mgmt/src/fs_mgmt_config.h | 26 ++ cmd/fs_mgmt/src/stubs.c | 46 +++ cmd/img_mgmt/include/img_mgmt/image.h | 82 ++++++ cmd/img_mgmt/include/img_mgmt/img_mgmt.h | 49 ++++ cmd/img_mgmt/include/img_mgmt/img_mgmt_impl.h | 107 +++++++ cmd/img_mgmt/src/img_mgmt.c | 400 ++++++++++++++++++++++++++ cmd/img_mgmt/src/img_mgmt_config.h | 22 ++ cmd/img_mgmt/src/img_mgmt_priv.h | 96 +++++++ cmd/img_mgmt/src/img_mgmt_state.c | 315 ++++++++++++++++++++ cmd/img_mgmt/src/img_mgmt_util.c | 39 +++ cmd/img_mgmt/src/stubs.c | 64 +++++ cmd/os_mgmt/include/os_mgmt/os_mgmt.h | 64 +++++ cmd/os_mgmt/include/os_mgmt/os_mgmt_impl.h | 62 ++++ cmd/os_mgmt/src/os_mgmt.c | 190 ++++++++++++ cmd/os_mgmt/src/os_mgmt_config.h | 22 ++ cmd/os_mgmt/src/stubs.c | 38 +++ 19 files changed, 1990 insertions(+) diff --git a/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt.h b/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt.h new file mode 100644 index 0000000..38173fd --- /dev/null +++ b/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt.h @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_FS_MGMT_ +#define H_FS_MGMT_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Command IDs for file system management group. + */ +#define FS_MGMT_ID_FILE 0 + +/** + * @brief Registers the file system management command handler group. + */ +void fs_mgmt_register_group(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt_impl.h b/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt_impl.h new file mode 100644 index 0000000..3cb30b8 --- /dev/null +++ b/cmd/fs_mgmt/include/fs_mgmt/fs_mgmt_impl.h @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @file + * @brief Declares implementation-specific functions required by file system + * management. The default stubs can be overridden with functions that + * are compatible with the host OS. + */ + +#ifndef H_FS_MGMT_IMPL_ +#define H_FS_MGMT_IMPL_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Retrieves the length of the file at the specified path. + * + * @param path The path of the file to query. + * @param out_len On success, the file length gets written here. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int fs_mgmt_impl_filelen(const char *path, size_t *out_len); + +/** + * @brief Reads the specified chunk of file data. + * + * @param path The path of the file to read from. + * @param offset The byte offset to read from. + * @param len The number of bytes to read. + * @param out_data On success, the file data gets written here. + * @param out_len On success, the number of bytes actually read + * gets written here. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int fs_mgmt_impl_read(const char *path, size_t offset, size_t len, + void *out_data, size_t *out_len); + +/** + * @brief Writes the specified chunk of file data. A write to offset 0 must + * truncate the file; other offsets must append. + * + * @param path The path of the file to write to. + * @param offset The byte offset to write to. + * @param data The data to write to the file. + * @param len The number of bytes to write. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int fs_mgmt_impl_write(const char *path, size_t offset, const void *data, + size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cmd/fs_mgmt/src/fs_mgmt.c b/cmd/fs_mgmt/src/fs_mgmt.c new file mode 100644 index 0000000..2ce7fc2 --- /dev/null +++ b/cmd/fs_mgmt/src/fs_mgmt.c @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <limits.h> +#include <string.h> +#include "cborattr/cborattr.h" +#include "mgmt/mgmt.h" +#include "fs_mgmt/fs_mgmt.h" +#include "fs_mgmt/fs_mgmt_impl.h" +#include "fs_mgmt_config.h" + +static mgmt_handler_fn fs_mgmt_file_download; +static mgmt_handler_fn fs_mgmt_file_upload; + +static struct { + /** Whether an upload is currently in progress. */ + bool uploading; + + /** Expected offset of next upload request. */ + size_t off; + + /** Total length of file currently being uploaded. */ + size_t len; +} fs_mgmt_ctxt; + +static const struct mgmt_handler fs_mgmt_handlers[] = { + [FS_MGMT_ID_FILE] = { + .mh_read = fs_mgmt_file_download, + .mh_write = fs_mgmt_file_upload, + }, +}; + +#define FS_MGMT_HANDLER_CNT \ + sizeof fs_mgmt_handlers / sizeof fs_mgmt_handlers[0] + +static struct mgmt_group fs_mgmt_group = { + .mg_handlers = fs_mgmt_handlers, + .mg_handlers_count = FS_MGMT_HANDLER_CNT, + .mg_group_id = MGMT_GROUP_ID_FS, +}; + +/** + * Command handler: fs file (read) + */ +static int +fs_mgmt_file_download(struct mgmt_ctxt *ctxt) +{ + uint8_t file_data[FS_MGMT_DL_CHUNK_SIZE]; + char path[FS_MGMT_PATH_SIZE + 1]; + unsigned long long off; + CborError err; + size_t bytes_read; + size_t file_len; + int rc; + + const struct cbor_attr_t dload_attr[] = { + { + .attribute = "off", + .type = CborAttrUnsignedIntegerType, + .addr.uinteger = &off, + }, + { + .attribute = "name", + .type = CborAttrTextStringType, + .addr.string = path, + .len = sizeof path, + }, + { 0 }, + }; + + off = ULLONG_MAX; + rc = cbor_read_object(&ctxt->it, dload_attr); + if (rc != 0 || off == ULLONG_MAX) { + return MGMT_ERR_EINVAL; + } + + /* Only the response to the first download request contains the total file + * length. + */ + if (off == 0) { + rc = fs_mgmt_impl_filelen(path, &file_len); + if (rc != 0) { + return rc; + } + } + + /* Read the requested chunk from the file. */ + rc = fs_mgmt_impl_read(path, off, FS_MGMT_DL_CHUNK_SIZE, + file_data, &bytes_read); + if (rc != 0) { + return rc; + } + + /* Encode the response. */ + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "off"); + err |= cbor_encode_uint(&ctxt->encoder, off); + err |= cbor_encode_text_stringz(&ctxt->encoder, "data"); + err |= cbor_encode_byte_string(&ctxt->encoder, file_data, bytes_read); + err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); + err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK); + if (off == 0) { + err |= cbor_encode_text_stringz(&ctxt->encoder, "len"); + err |= cbor_encode_uint(&ctxt->encoder, file_len); + } + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Encodes a file upload response. + */ +static int +fs_mgmt_file_upload_rsp(struct mgmt_ctxt *ctxt, int rc, unsigned long long off) +{ + CborError err; + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); + err |= cbor_encode_int(&ctxt->encoder, rc); + err |= cbor_encode_text_stringz(&ctxt->encoder, "off"); + err |= cbor_encode_uint(&ctxt->encoder, off); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: fs file (write) + */ +static int +fs_mgmt_file_upload(struct mgmt_ctxt *ctxt) +{ + uint8_t file_data[FS_MGMT_UL_CHUNK_SIZE]; + char file_name[FS_MGMT_PATH_SIZE + 1]; + unsigned long long len; + unsigned long long off; + size_t data_len; + size_t new_off; + int rc; + + const struct cbor_attr_t uload_attr[5] = { + [0] = { + .attribute = "off", + .type = CborAttrUnsignedIntegerType, + .addr.uinteger = &off, + .nodefault = true + }, + [1] = { + .attribute = "data", + .type = CborAttrByteStringType, + .addr.bytestring.data = file_data, + .addr.bytestring.len = &data_len, + .len = sizeof(file_data) + }, + [2] = { + .attribute = "len", + .type = CborAttrUnsignedIntegerType, + .addr.uinteger = &len, + .nodefault = true + }, + [3] = { + .attribute = "name", + .type = CborAttrTextStringType, + .addr.string = file_name, + .len = sizeof(file_name) + }, + [4] = { 0 }, + }; + + len = ULLONG_MAX; + off = ULLONG_MAX; + rc = cbor_read_object(&ctxt->it, uload_attr); + if (rc != 0 || off == ULLONG_MAX || file_name[0] == '\0') { + return MGMT_ERR_EINVAL; + } + + if (off == 0) { + /* Total file length is a required field in the first chunk request. */ + if (len == ULLONG_MAX) { + return MGMT_ERR_EINVAL; + } + + fs_mgmt_ctxt.uploading = true; + fs_mgmt_ctxt.off = 0; + fs_mgmt_ctxt.len = len; + } else { + if (!fs_mgmt_ctxt.uploading) { + return MGMT_ERR_EINVAL; + } + + if (off != fs_mgmt_ctxt.off) { + /* Invalid offset. Drop the data and send the expected offset. */ + return fs_mgmt_file_upload_rsp(ctxt, MGMT_ERR_EINVAL, + fs_mgmt_ctxt.off); + } + } + + new_off = fs_mgmt_ctxt.off + data_len; + if (new_off > fs_mgmt_ctxt.len) { + /* Data exceeds image length. */ + return MGMT_ERR_EINVAL; + } + + if (data_len > 0) { + /* Write the data chunk to the file. */ + rc = fs_mgmt_impl_write(file_name, off, file_data, data_len); + if (rc != 0) { + return rc; + } + fs_mgmt_ctxt.off = new_off; + } + + if (fs_mgmt_ctxt.off == fs_mgmt_ctxt.len) { + /* Upload complete. */ + fs_mgmt_ctxt.uploading = false; + } + + /* Send the response. */ + return fs_mgmt_file_upload_rsp(ctxt, 0, fs_mgmt_ctxt.off); +} + +void +fs_mgmt_register_group(void) +{ + mgmt_register_group(&fs_mgmt_group); +} diff --git a/cmd/fs_mgmt/src/fs_mgmt_config.h b/cmd/fs_mgmt/src/fs_mgmt_config.h new file mode 100644 index 0000000..81fb7dd --- /dev/null +++ b/cmd/fs_mgmt/src/fs_mgmt_config.h @@ -0,0 +1,26 @@ +#ifndef H_FS_MGMT_CONFIG_ +#define H_FS_MGMT_CONFIG_ + +#if defined MYNEWT + +#include "syscfg/syscfg.h" + +#define FS_MGMT_DL_CHUNK_SIZE MYNEWT_VAL(FS_MGMT_DL_CHUNK_SIZE) +#define FS_MGMT_PATH_SIZE MYNEWT_VAL(FS_MGMT_PATH_SIZE) +#define FS_MGMT_UL_CHUNK_SIZE MYNEWT_VAL(FS_MGMT_UL_CHUNK_SIZE) + +#elif defined __ZEPHYR__ + +#define FS_MGMT_DL_CHUNK_SIZE CONFIG_FS_MGMT_DL_CHUNK_SIZE +#define FS_MGMT_PATH_SIZE CONFIG_FS_MGMT_PATH_SIZE +#define FS_MGMT_UL_CHUNK_SIZE CONFIG_FS_MGMT_UL_CHUNK_SIZE + +#else + +/* No direct support for this OS. The application needs to define the above + * settings itself. + */ + +#endif + +#endif diff --git a/cmd/fs_mgmt/src/stubs.c b/cmd/fs_mgmt/src/stubs.c new file mode 100644 index 0000000..8b6ab83 --- /dev/null +++ b/cmd/fs_mgmt/src/stubs.c @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * These stubs get linked in when there is no equivalent OS-specific + * implementation. + */ + +#include "mgmt/mgmt.h" +#include "fs_mgmt/fs_mgmt_impl.h" + +int __attribute__((weak)) +fs_mgmt_impl_filelen(const char *path, size_t *out_len) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +fs_mgmt_impl_read(const char *path, size_t offset, size_t len, + void *out_data, size_t *out_len) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +fs_mgmt_impl_write(const char *path, size_t offset, const void *data, + size_t len) +{ + return MGMT_ERR_ENOTSUP; +} diff --git a/cmd/img_mgmt/include/img_mgmt/image.h b/cmd/img_mgmt/include/img_mgmt/image.h new file mode 100644 index 0000000..d390783 --- /dev/null +++ b/cmd/img_mgmt/include/img_mgmt/image.h @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_IMAGE_ +#define H_IMAGE_ + +#include <inttypes.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define IMAGE_MAGIC 0x96f3b83d +#define IMAGE_TLV_INFO_MAGIC 0x6907 + +#define IMAGE_HEADER_SIZE 32 + +/** Image header flags. */ +#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */ + +/** Image trailer TLV types. */ +#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ + +/** Image TLV-specific definitions. */ +#define IMAGE_HASH_LEN 32 + +struct image_version { + uint8_t iv_major; + uint8_t iv_minor; + uint16_t iv_revision; + uint32_t iv_build_num; +}; + +/** Image header. All fields are in little endian byte order. */ +struct image_header { + uint32_t ih_magic; + uint32_t ih_load_addr; + uint16_t ih_hdr_size; /* Size of image header (bytes). */ + uint16_t _pad2; + uint32_t ih_img_size; /* Does not include header. */ + uint32_t ih_flags; /* IMAGE_F_[...]. */ + struct image_version ih_ver; + uint32_t _pad3; +}; + +/** Image TLV header. All fields in little endian. */ +struct image_tlv_info { + uint16_t it_magic; + uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */ +}; + +/** Image trailer TLV format. All fields in little endian. */ +struct image_tlv { + uint8_t it_type; /* IMAGE_TLV_[...]. */ + uint8_t _pad; + uint16_t it_len; /* Data length (not including TLV header). */ +}; + +_Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE, + "struct image_header not required size"); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cmd/img_mgmt/include/img_mgmt/img_mgmt.h b/cmd/img_mgmt/include/img_mgmt/img_mgmt.h new file mode 100644 index 0000000..865964d --- /dev/null +++ b/cmd/img_mgmt/include/img_mgmt/img_mgmt.h @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_IMG_MGMT_ +#define H_IMG_MGMT_ + +#include <inttypes.h> +struct image_version; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Command IDs for image management group. + */ +#define IMG_MGMT_ID_STATE 0 +#define IMG_MGMT_ID_UPLOAD 1 +#define IMG_MGMT_ID_FILE 2 +#define IMG_MGMT_ID_CORELIST 3 +#define IMG_MGMT_ID_CORELOAD 4 +#define IMG_MGMT_ID_ERASE 5 + +/** + * @brief Registers the image management command handler group. + */ +void img_mgmt_register_group(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_IMG_MGMT_ */ diff --git a/cmd/img_mgmt/include/img_mgmt/img_mgmt_impl.h b/cmd/img_mgmt/include/img_mgmt/img_mgmt_impl.h new file mode 100644 index 0000000..d0898ef --- /dev/null +++ b/cmd/img_mgmt/include/img_mgmt/img_mgmt_impl.h @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @file + * @brief Declares implementation-specific functions required by image + * management. The default stubs can be overridden with functions that + * are compatible with the host OS. + */ + +#ifndef H_IMG_MGMT_IMPL_ +#define H_IMG_MGMT_IMPL_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Ensures the spare slot (slot 1) is fully erased. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int img_mgmt_impl_erase_slot(void); + +/** + * @brief Marks the image in the specified slot as pending. On the next reboot, + * the system will perform a boot of the specified image. + * + * @param slot The slot to mark as pending. In the typical + * use case, this is 1. + * @param permanent Whether the image should be used permanently or + * only tested once: + * 0=run image once, then confirm or + * revert. + * 1=run image forever. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int img_mgmt_impl_write_pending(int slot, bool permanent); + +/** + * @brief Marks the image in slot 0 as confirmed. The system will continue + * booting into the image in slot 0 until told to boot from a different slot. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int img_mgmt_impl_write_confirmed(void); + +/** + * @brief Reads the specified chunk of data from an image slot. + * + * @param slot The index of the slot to read from. + * @param offset The offset within the slot to read from. + * @param dst On success, the read data gets written here. + * @param num_bytes The number of byets to read. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int img_mgmt_impl_read(int slot, unsigned int offset, void *dst, + unsigned int num_bytes); + +/** + * @brief Writes the specified chunk of image data to slot 1. + * + * @param offset The offset within slot 1 to write to. + * @param data The image data to write. + * @param num_bytes The number of bytes to read. + * @param last Whether this chunk is the end of the image: + * false=additional image chunks are + * forthcoming. + * true=last image chunk; flush unwritten data + * to disk. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int img_mgmt_impl_write_image_data(unsigned int offset, const void *data, + unsigned int num_bytes, bool last); + +/** + * @brief Indicates the type of swap operation that will occur on the next + * reboot, if any. + * + * @return An IMG_MGMT_SWAP_TYPE_[...] code. + */ +int img_mgmt_impl_swap_type(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cmd/img_mgmt/src/img_mgmt.c b/cmd/img_mgmt/src/img_mgmt.c new file mode 100644 index 0000000..fe91397 --- /dev/null +++ b/cmd/img_mgmt/src/img_mgmt.c @@ -0,0 +1,400 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <limits.h> +#include <assert.h> +#include <string.h> + +#include "cborattr/cborattr.h" +#include "mgmt/mgmt.h" + +#include "img_mgmt/image.h" +#include "img_mgmt/img_mgmt.h" +#include "img_mgmt/img_mgmt_impl.h" +#include "img_mgmt_priv.h" +#include "img_mgmt_config.h" + +static mgmt_handler_fn img_mgmt_upload; +static mgmt_handler_fn img_mgmt_erase; + +static const struct mgmt_handler img_mgmt_handlers[] = { + [IMG_MGMT_ID_STATE] = { + .mh_read = img_mgmt_state_read, + .mh_write = img_mgmt_state_write, + }, + [IMG_MGMT_ID_UPLOAD] = { + .mh_read = NULL, + .mh_write = img_mgmt_upload + }, + [IMG_MGMT_ID_ERASE] = { + .mh_read = NULL, + .mh_write = img_mgmt_erase + }, +}; + +#define IMG_MGMT_HANDLER_CNT \ + sizeof(img_mgmt_handlers) / sizeof(img_mgmt_handlers[0]) + +static struct mgmt_group img_mgmt_group = { + .mg_handlers = (struct mgmt_handler *)img_mgmt_handlers, + .mg_handlers_count = IMG_MGMT_HANDLER_CNT, + .mg_group_id = MGMT_GROUP_ID_IMAGE, +}; + +static struct { + /* Whether an upload is currently in progress. */ + bool uploading; + + /** Expected offset of next upload request. */ + size_t off; + + /** Total length of image currently being uploaded. */ + size_t len; +} img_mgmt_ctxt; + +/** + * Finds the TLVs in the specified image slot, if any. + */ +static int +img_mgmt_find_tlvs(const struct image_header *hdr, + int slot, size_t *start_off, size_t *end_off) +{ + struct image_tlv_info tlv_info; + int rc; + + rc = img_mgmt_impl_read(slot, *start_off, &tlv_info, sizeof tlv_info); + if (rc != 0) { + /* Read error. */ + return MGMT_ERR_EUNKNOWN; + } + + if (tlv_info.it_magic != IMAGE_TLV_INFO_MAGIC) { + /* No TLVs. */ + return MGMT_ERR_ENOENT; + } + + *start_off += sizeof tlv_info; + *end_off = *start_off + tlv_info.it_tlv_tot; + + return 0; +} + +/* + * Reads the version and build hash from the specified image slot. + */ +int +img_mgmt_read_info(int image_slot, struct image_version *ver, uint8_t *hash, + uint32_t *flags) +{ + struct image_header hdr; + struct image_tlv tlv; + size_t data_off; + size_t data_end; + bool hash_found; + int rc; + + rc = img_mgmt_impl_read(image_slot, 0, &hdr, sizeof hdr); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + + if (ver != NULL) { + memset(ver, 0xff, sizeof(*ver)); + } + if (hdr.ih_magic == IMAGE_MAGIC) { + if (ver != NULL) { + memcpy(ver, &hdr.ih_ver, sizeof(*ver)); + } + } else if (hdr.ih_magic == 0xffffffff) { + return MGMT_ERR_ENOENT; + } else { + return MGMT_ERR_EUNKNOWN; + } + + if (flags != NULL) { + *flags = hdr.ih_flags; + } + + /* Read the image's TLVs. All images are required to have a hash TLV. If + * the hash is missing, the image is considered invalid. + */ + data_off = hdr.ih_hdr_size + hdr.ih_img_size; + rc = img_mgmt_find_tlvs(&hdr, image_slot, &data_off, &data_end); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + + hash_found = false; + while (data_off + sizeof tlv <= data_end) { + rc = img_mgmt_impl_read(image_slot, data_off, &tlv, sizeof tlv); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + if (tlv.it_type == 0xff && tlv.it_len == 0xffff) { + return MGMT_ERR_EUNKNOWN; + } + if (tlv.it_type != IMAGE_TLV_SHA256 || tlv.it_len != IMAGE_HASH_LEN) { + /* Non-hash TLV. Skip it. */ + data_off += sizeof tlv + tlv.it_len; + continue; + } + + if (hash_found) { + /* More than one hash. */ + return MGMT_ERR_EUNKNOWN; + } + hash_found = true; + + data_off += sizeof tlv; + if (hash != NULL) { + if (data_off + IMAGE_HASH_LEN > data_end) { + return MGMT_ERR_EUNKNOWN; + } + rc = img_mgmt_impl_read(image_slot, data_off, hash, + IMAGE_HASH_LEN); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + } + } + + if (!hash_found) { + return MGMT_ERR_EUNKNOWN; + } + + return 0; +} + +/* + * Finds image given version number. Returns the slot number image is in, + * or -1 if not found. + */ +int +img_mgmt_find_by_ver(struct image_version *find, uint8_t *hash) +{ + int i; + struct image_version ver; + + for (i = 0; i < 2; i++) { + if (img_mgmt_read_info(i, &ver, hash, NULL) != 0) { + continue; + } + if (!memcmp(find, &ver, sizeof(ver))) { + return i; + } + } + return -1; +} + +/* + * Finds image given hash of the image. Returns the slot number image is in, + * or -1 if not found. + */ +int +img_mgmt_find_by_hash(uint8_t *find, struct image_version *ver) +{ + int i; + uint8_t hash[IMAGE_HASH_LEN]; + + for (i = 0; i < 2; i++) { + if (img_mgmt_read_info(i, ver, hash, NULL) != 0) { + continue; + } + if (!memcmp(hash, find, IMAGE_HASH_LEN)) { + return i; + } + } + return -1; +} + +/** + * Command handler: image erase + */ +static int +img_mgmt_erase(struct mgmt_ctxt *ctxt) +{ + CborError err; + int rc; + + rc = img_mgmt_impl_erase_slot(); + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); + err |= cbor_encode_int(&ctxt->encoder, rc); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Encodes an image upload response. + */ +static int +img_mgmt_encode_upload_rsp(struct mgmt_ctxt *ctxt, int status) +{ + CborError err; + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); + err |= cbor_encode_int(&ctxt->encoder, status); + err |= cbor_encode_text_stringz(&ctxt->encoder, "off"); + err |= cbor_encode_int(&ctxt->encoder, img_mgmt_ctxt.off); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + return 0; +} + +/** + * Processes an upload request specifying an offset of 0 (i.e., the first image + * chunk). The caller is responsible for encoding the response. + */ +static int +img_mgmt_upload_first_chunk(struct mgmt_ctxt *ctxt, const uint8_t *req_data, + size_t len) +{ + struct image_header hdr; + int rc; + + if (len < sizeof hdr) { + return MGMT_ERR_EINVAL; + } + + memcpy(&hdr, req_data, sizeof hdr); + if (hdr.ih_magic != IMAGE_MAGIC) { + return MGMT_ERR_EINVAL; + } + + if (img_mgmt_slot_in_use(1)) { + /* No free slot. */ + return MGMT_ERR_ENOMEM; + } + + rc = img_mgmt_impl_erase_slot(); + if (rc != 0) { + return rc; + } + + img_mgmt_ctxt.uploading = true; + img_mgmt_ctxt.off = 0; + img_mgmt_ctxt.len = 0; + + return 0; +} + +/** + * Command handler: image upload + */ +static int +img_mgmt_upload(struct mgmt_ctxt *ctxt) +{ + uint8_t img_mgmt_data[IMG_MGMT_UL_CHUNK_SIZE]; + unsigned long long len; + unsigned long long off; + size_t data_len; + size_t new_off; + bool last; + int rc; + + const struct cbor_attr_t off_attr[4] = { + [0] = { + .attribute = "data", + .type = CborAttrByteStringType, + .addr.bytestring.data = img_mgmt_data, + .addr.bytestring.len = &data_len, + .len = sizeof(img_mgmt_data) + }, + [1] = { + .attribute = "len", + .type = CborAttrUnsignedIntegerType, + .addr.uinteger = &len, + .nodefault = true + }, + [2] = { + .attribute = "off", + .type = CborAttrUnsignedIntegerType, + .addr.uinteger = &off, + .nodefault = true + }, + [3] = { 0 }, + }; + + len = ULLONG_MAX; + off = ULLONG_MAX; + data_len = 0; + rc = cbor_read_object(&ctxt->it, off_attr); + if (rc || off == ULLONG_MAX) { + return MGMT_ERR_EINVAL; + } + + if (off == 0) { + /* Total image length is a required field in the first request. */ + if (len == ULLONG_MAX) { + return MGMT_ERR_EINVAL; + } + + rc = img_mgmt_upload_first_chunk(ctxt, img_mgmt_data, data_len); + if (rc != 0) { + return rc; + } + img_mgmt_ctxt.len = len; + } else { + if (!img_mgmt_ctxt.uploading) { + return MGMT_ERR_EINVAL; + } + + if (off != img_mgmt_ctxt.off) { + /* Invalid offset. Drop the data and send the expected offset. */ + return img_mgmt_encode_upload_rsp(ctxt, 0); + } + } + + new_off = img_mgmt_ctxt.off + data_len; + if (new_off > img_mgmt_ctxt.len) { + /* Data exceeds image length. */ + return MGMT_ERR_EINVAL; + } + last = new_off == img_mgmt_ctxt.len; + + if (data_len > 0) { + rc = img_mgmt_impl_write_image_data(off, img_mgmt_data, data_len, + last); + if (rc != 0) { + return rc; + } + } + + img_mgmt_ctxt.off = new_off; + if (last) { + /* Upload complete. */ + img_mgmt_ctxt.uploading = false; + } + + return img_mgmt_encode_upload_rsp(ctxt, 0); +} + +void +img_mgmt_register_group(void) +{ + mgmt_register_group(&img_mgmt_group); +} diff --git a/cmd/img_mgmt/src/img_mgmt_config.h b/cmd/img_mgmt/src/img_mgmt_config.h new file mode 100644 index 0000000..4ec8295 --- /dev/null +++ b/cmd/img_mgmt/src/img_mgmt_config.h @@ -0,0 +1,22 @@ +#ifndef H_IMG_MGMT_CONFIG_ +#define H_IMG_MGMT_CONFIG_ + +#if defined MYNEWT + +#include "syscfg/syscfg.h" + +#define IMG_MGMT_UL_CHUNK_SIZE MYNEWT_VAL(IMG_MGMT_UL_CHUNK_SIZE) + +#elif defined __ZEPHYR__ + +#define IMG_MGMT_UL_CHUNK_SIZE CONFIG_IMG_MGMT_UL_CHUNK_SIZE + +#else + +/* No direct support for this OS. The application needs to define the above + * settings itself. + */ + +#endif + +#endif diff --git a/cmd/img_mgmt/src/img_mgmt_priv.h b/cmd/img_mgmt/src/img_mgmt_priv.h new file mode 100644 index 0000000..a8a3a28 --- /dev/null +++ b/cmd/img_mgmt/src/img_mgmt_priv.h @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_IMG_PRIV_ +#define H_IMG_PRIV_ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define IMG_MGMT_SWAP_TYPE_NONE 0 +#define IMG_MGMT_SWAP_TYPE_TEST 1 +#define IMG_MGMT_SWAP_TYPE_PERM 2 +#define IMG_MGMT_SWAP_TYPE_REVERT 3 + +/* + * Response to list: + * { + * "images":[ <version1>, <version2>] + * } + * + * + * Request to boot to version: + * { + * "test":<version> + * } + * + * + * Response to boot read: + * { + * "test":<version>, + * "main":<version>, + * "active":<version> + * } + * + * + * Request to image upload: + * { + * "off":<offset>, + * "len":<img_size> inspected when off = 0 + * "data":<base64encoded binary> + * } + * + * + * Response to upload: + * { + * "off":<offset> + * } + * + * + * Request to image upload: + * { + * "off":<offset> + * "name":<filename> inspected when off = 0 + * "len":<file_size> inspected when off = 0 + * "data":<base64encoded binary> + * } + */ + +struct mgmt_ctxt; + +int img_mgmt_core_erase(struct mgmt_ctxt *); +int img_mgmt_core_list(struct mgmt_ctxt *); +int img_mgmt_core_load(struct mgmt_ctxt *); +int img_mgmt_find_by_hash(uint8_t *find, struct image_version *ver); +int img_mgmt_find_by_ver(struct image_version *find, uint8_t *hash); +int img_mgmt_read_info(int image_slot, struct image_version *ver, + uint8_t *hash, uint32_t *flags); +int img_mgmt_slot_in_use(int slot); +int img_mgmt_state_read(struct mgmt_ctxt *ctxt); +int img_mgmt_state_write(struct mgmt_ctxt *njb); +int img_mgmt_ver_str(const struct image_version *ver, char *dst); + +#ifdef __cplusplus +} +#endif + +#endif /* __IMG_PRIV_H */ diff --git a/cmd/img_mgmt/src/img_mgmt_state.c b/cmd/img_mgmt/src/img_mgmt_state.c new file mode 100644 index 0000000..bca3aed --- /dev/null +++ b/cmd/img_mgmt/src/img_mgmt_state.c @@ -0,0 +1,315 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <assert.h> +#include "cbor.h" +#include "cborattr/cborattr.h" +#include "mgmt/mgmt.h" +#include "img_mgmt/img_mgmt.h" +#include "img_mgmt/image.h" +#include "img_mgmt_priv.h" +#include "img_mgmt/img_mgmt_impl.h" + +#define IMG_MGMT_STATE_F_PENDING 0x01 +#define IMG_MGMT_STATE_F_CONFIRMED 0x02 +#define IMG_MGMT_STATE_F_ACTIVE 0x04 +#define IMG_MGMT_STATE_F_PERMANENT 0x08 + +#define IMG_MGMT_VER_MAX_STR_LEN 25 /* 255.255.65535.4294967295\0 */ + +/** + * Collects information about the specified image slot. + */ +static uint8_t +img_mgmt_state_flags(int query_slot) +{ + uint8_t flags; + int swap_type; + + assert(query_slot == 0 || query_slot == 1); + + flags = 0; + + /* Determine if this is is pending or confirmed (only applicable for + * unified images and loaders. + */ + swap_type = img_mgmt_impl_swap_type(); + switch (swap_type) { + case IMG_MGMT_SWAP_TYPE_NONE: + if (query_slot == 0) { + flags |= IMG_MGMT_STATE_F_CONFIRMED; + flags |= IMG_MGMT_STATE_F_ACTIVE; + } + break; + + case IMG_MGMT_SWAP_TYPE_TEST: + if (query_slot == 0) { + flags |= IMG_MGMT_STATE_F_CONFIRMED; + } else if (query_slot == 1) { + flags |= IMG_MGMT_STATE_F_PENDING; + } + break; + + case IMG_MGMT_SWAP_TYPE_PERM: + if (query_slot == 0) { + flags |= IMG_MGMT_STATE_F_CONFIRMED; + } else if (query_slot == 1) { + flags |= IMG_MGMT_STATE_F_PENDING | IMG_MGMT_STATE_F_PERMANENT; + } + break; + + case IMG_MGMT_SWAP_TYPE_REVERT: + if (query_slot == 0) { + flags |= IMG_MGMT_STATE_F_ACTIVE; + } else if (query_slot == 1) { + flags |= IMG_MGMT_STATE_F_CONFIRMED; + } + break; + } + + /* Slot 0 is always active. */ + /* XXX: The slot 0 assumption only holds when running from flash. */ + if (query_slot == 0) { + flags |= IMG_MGMT_STATE_F_ACTIVE; + } + + return flags; +} + +/** + * Indicates whether any image slot is pending (i.e., whether a test swap will + * happen on the next reboot. + */ +static int +img_mgmt_state_any_pending(void) +{ + return img_mgmt_state_flags(0) & IMG_MGMT_STATE_F_PENDING || + img_mgmt_state_flags(1) & IMG_MGMT_STATE_F_PENDING; +} + +/** + * Indicates whether the specified slot has any flags. If no flags are set, + * the slot can be freely erased. + */ +int +img_mgmt_slot_in_use(int slot) +{ + uint8_t state_flags; + + state_flags = img_mgmt_state_flags(slot); + return state_flags & IMG_MGMT_STATE_F_ACTIVE || + state_flags & IMG_MGMT_STATE_F_CONFIRMED || + state_flags & IMG_MGMT_STATE_F_PENDING; +} + +/** + * Sets the pending flag for the specified image slot. That is, the system + * will swap to the specified image on the next reboot. If the permanent + * argument is specified, the system doesn't require a confirm after the swap + * occurs. + */ +int +img_mgmt_state_set_pending(int slot, int permanent) +{ + uint8_t state_flags; + int rc; + + state_flags = img_mgmt_state_flags(slot); + + /* Unconfirmed slots are always runable. A confirmed slot can only be + * run if it is a loader in a split image setup. + */ + if (state_flags & IMG_MGMT_STATE_F_CONFIRMED && slot != 0) { + return MGMT_ERR_EBADSTATE; + } + + rc = img_mgmt_impl_write_pending(slot, permanent); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + + return 0; +} + +/** + * Confirms the current image state. Prevents a fallback from occurring on the + * next reboot if the active image is currently being tested. + */ +int +img_mgmt_state_confirm(void) +{ + int rc; + + /* Confirm disallowed if a test is pending. */ + if (img_mgmt_state_any_pending()) { + return MGMT_ERR_EBADSTATE; + } + + rc = img_mgmt_impl_write_confirmed(); + if (rc != 0) { + return MGMT_ERR_EUNKNOWN; + } + + return 0; +} + +/** + * Command handler: image state read + */ +int +img_mgmt_state_read(struct mgmt_ctxt *ctxt) +{ + char vers_str[IMG_MGMT_VER_MAX_STR_LEN]; + uint8_t hash[IMAGE_HASH_LEN]; /* SHA256 hash */ + struct image_version ver; + CborEncoder images; + CborEncoder image; + CborError err; + uint32_t flags; + uint8_t state_flags; + int rc; + int i; + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "images"); + + err |= cbor_encoder_create_array(&ctxt->encoder, &images, + CborIndefiniteLength); + for (i = 0; i < 2; i++) { + rc = img_mgmt_read_info(i, &ver, hash, &flags); + if (rc != 0) { + continue; + } + + state_flags = img_mgmt_state_flags(i); + + err |= cbor_encoder_create_map(&images, &image, + CborIndefiniteLength); + err |= cbor_encode_text_stringz(&image, "slot"); + err |= cbor_encode_int(&image, i); + + err |= cbor_encode_text_stringz(&image, "version"); + img_mgmt_ver_str(&ver, vers_str); + err |= cbor_encode_text_stringz(&image, vers_str); + + err |= cbor_encode_text_stringz(&image, "hash"); + err |= cbor_encode_byte_string(&image, hash, IMAGE_HASH_LEN); + + err |= cbor_encode_text_stringz(&image, "bootable"); + err |= cbor_encode_boolean(&image, !(flags & IMAGE_F_NON_BOOTABLE)); + + err |= cbor_encode_text_stringz(&image, "pending"); + err |= cbor_encode_boolean(&image, + state_flags & IMG_MGMT_STATE_F_PENDING); + + err |= cbor_encode_text_stringz(&image, "confirmed"); + err |= cbor_encode_boolean(&image, + state_flags & IMG_MGMT_STATE_F_CONFIRMED); + + err |= cbor_encode_text_stringz(&image, "active"); + err |= cbor_encode_boolean(&image, + state_flags & IMG_MGMT_STATE_F_ACTIVE); + + err |= cbor_encode_text_stringz(&image, "permanent"); + err |= cbor_encode_boolean(&image, + state_flags & IMG_MGMT_STATE_F_PERMANENT); + + err |= cbor_encoder_close_container(&images, &image); + } + + err |= cbor_encoder_close_container(&ctxt->encoder, &images); + + err |= cbor_encode_text_stringz(&ctxt->encoder, "splitStatus"); + err |= cbor_encode_int(&ctxt->encoder, 0); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: image state write + */ +int +img_mgmt_state_write(struct mgmt_ctxt *ctxt) +{ + uint8_t hash[IMAGE_HASH_LEN]; + size_t hash_len; + bool confirm; + int slot; + int rc; + + const struct cbor_attr_t write_attr[] = { + [0] = { + .attribute = "hash", + .type = CborAttrByteStringType, + .addr.bytestring.data = hash, + .addr.bytestring.len = &hash_len, + .len = sizeof(hash), + }, + [1] = { + .attribute = "confirm", + .type = CborAttrBooleanType, + .addr.boolean = &confirm, + .dflt.boolean = false, + }, + [2] = { 0 }, + }; + + hash_len = 0; + rc = cbor_read_object(&ctxt->it, write_attr); + if (rc != 0) { + return MGMT_ERR_EINVAL; + } + + /* Determine which slot is being operated on. */ + if (hash_len == 0) { + if (confirm) { + slot = 0; + } else { + /* A 'test' without a hash is invalid. */ + return MGMT_ERR_EINVAL; + } + } else { + slot = img_mgmt_find_by_hash(hash, NULL); + if (slot < 0) { + return MGMT_ERR_EINVAL; + } + } + + if (slot == 0 && confirm) { + /* Confirm current setup. */ + rc = img_mgmt_state_confirm(); + } else { + rc = img_mgmt_state_set_pending(slot, confirm); + } + if (rc != 0) { + return rc; + } + + /* Send the current image state in the response. */ + rc = img_mgmt_state_read(ctxt); + if (rc != 0) { + return rc; + } + + return 0; +} diff --git a/cmd/img_mgmt/src/img_mgmt_util.c b/cmd/img_mgmt/src/img_mgmt_util.c new file mode 100644 index 0000000..5889f61 --- /dev/null +++ b/cmd/img_mgmt/src/img_mgmt_util.c @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "img_mgmt/image.h" +#include "img_mgmt/img_mgmt.h" + +int +img_mgmt_ver_str(const struct image_version *ver, char *dst) +{ + if (ver->iv_build_num != 0) { + return sprintf(dst, "%u.%u.%u.%lu", + ver->iv_major, ver->iv_minor, ver->iv_revision, + (unsigned long)ver->iv_build_num); + } else { + return sprintf(dst, "%u.%u.%u", + ver->iv_major, ver->iv_minor, ver->iv_revision); + } +} diff --git a/cmd/img_mgmt/src/stubs.c b/cmd/img_mgmt/src/stubs.c new file mode 100644 index 0000000..fa440dc --- /dev/null +++ b/cmd/img_mgmt/src/stubs.c @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * These stubs get linked in when there is no equivalent OS-specific + * implementation. + */ + +#include "mgmt/mgmt.h" +#include "img_mgmt/img_mgmt_impl.h" + +int __attribute__((weak)) +img_mgmt_impl_erase_slot(void) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +img_mgmt_impl_write_pending(int slot, bool permanent) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +img_mgmt_impl_write_confirmed(void) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +img_mgmt_impl_read(int slot, unsigned int offset, void *dst, + unsigned int num_bytes) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +img_mgmt_impl_write_image_data(unsigned int offset, const void *data, + unsigned int num_bytes, bool last) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +img_mgmt_impl_swap_type(void) +{ + return MGMT_ERR_ENOTSUP; +} diff --git a/cmd/os_mgmt/include/os_mgmt/os_mgmt.h b/cmd/os_mgmt/include/os_mgmt/os_mgmt.h new file mode 100644 index 0000000..493d227 --- /dev/null +++ b/cmd/os_mgmt/include/os_mgmt/os_mgmt.h @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_OS_MGMT_ +#define H_OS_MGMT_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct mgmt_ctxt; + +/** + * Command IDs for OS management group. + */ +#define OS_MGMT_ID_ECHO 0 +#define OS_MGMT_ID_CONS_ECHO_CTRL 1 +#define OS_MGMT_ID_TASKSTAT 2 +#define OS_MGMT_ID_MPSTAT 3 +#define OS_MGMT_ID_DATETIME_STR 4 +#define OS_MGMT_ID_RESET 5 + +#define OS_MGMT_TASK_NAME_LEN 32 + +struct os_mgmt_task_info { + uint8_t oti_prio; + uint8_t oti_taskid; + uint8_t oti_state; + uint16_t oti_stkusage; + uint16_t oti_stksize; + uint32_t oti_cswcnt; + uint32_t oti_runtime; + uint32_t oti_last_checkin; + uint32_t oti_next_checkin; + + char oti_name[OS_MGMT_TASK_NAME_LEN]; +}; + +/** + * @brief Registers the OS management command handler group. + */ +void os_mgmt_register_group(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_MGMT_ */ diff --git a/cmd/os_mgmt/include/os_mgmt/os_mgmt_impl.h b/cmd/os_mgmt/include/os_mgmt/os_mgmt_impl.h new file mode 100644 index 0000000..252ba75 --- /dev/null +++ b/cmd/os_mgmt/include/os_mgmt/os_mgmt_impl.h @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @file + * @brief Declares implementation-specific functions required by OS management. + * The default stubs can be overridden with functions that are + * compatible with the host OS. + */ + +#ifndef H_OS_MGMT_IMPL_ +#define H_OS_MGMT_IMPL_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_mgmt_task_info; + +/** + * @brief Retrieves information about the specified task. + * + * @param idx The index of the task to query. + * @param out_info On success, the requested information gets + * written here. + * + * @return 0 on success; + * MGMT_ERR_ENOENT if no such task exists; + * Other MGMT_ERR_[...] code on failure. + */ +int os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info); + +/** + * @brief Schedules a near-immediate system reset. There must be a slight + * delay before the reset occurs to allow time for the mgmt response to be + * delivered. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int os_mgmt_impl_reset(unsigned int delay_ms); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cmd/os_mgmt/src/os_mgmt.c b/cmd/os_mgmt/src/os_mgmt.c new file mode 100644 index 0000000..ed359d8 --- /dev/null +++ b/cmd/os_mgmt/src/os_mgmt.c @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <assert.h> +#include <string.h> +#include "cbor.h" +#include "cborattr/cborattr.h" +#include "mgmt/mgmt.h" +#include "os_mgmt/os_mgmt.h" +#include "os_mgmt/os_mgmt_impl.h" +#include "os_mgmt_config.h" + +static mgmt_handler_fn os_mgmt_echo; +static mgmt_handler_fn os_mgmt_reset; +static mgmt_handler_fn os_mgmt_taskstat_read; + +static const struct mgmt_handler os_mgmt_group_handlers[] = { + [OS_MGMT_ID_ECHO] = { + os_mgmt_echo, os_mgmt_echo + }, + [OS_MGMT_ID_TASKSTAT] = { + os_mgmt_taskstat_read, NULL + }, + [OS_MGMT_ID_RESET] = { + NULL, os_mgmt_reset + }, +}; + +#define OS_MGMT_GROUP_SZ \ + (sizeof os_mgmt_group_handlers / sizeof os_mgmt_group_handlers[0]) + +static struct mgmt_group os_mgmt_group = { + .mg_handlers = os_mgmt_group_handlers, + .mg_handlers_count = OS_MGMT_GROUP_SZ, + .mg_group_id = MGMT_GROUP_ID_OS, +}; + +/** + * Command handler: os echo + */ +static int +os_mgmt_echo(struct mgmt_ctxt *ctxt) +{ + char echo_buf[128]; + CborError err; + + const struct cbor_attr_t attrs[2] = { + [0] = { + .attribute = "d", + .type = CborAttrTextStringType, + .addr.string = echo_buf, + .nodefault = 1, + .len = sizeof echo_buf, + }, + [1] = { + .attribute = NULL + } + }; + + echo_buf[0] = '\0'; + + err = cbor_read_object(&ctxt->it, attrs); + if (err != 0) { + return MGMT_ERR_EINVAL; + } + + err |= cbor_encode_text_stringz(&ctxt->encoder, "r"); + err |= cbor_encode_text_string(&ctxt->encoder, echo_buf, strlen(echo_buf)); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Encodes a single taskstat entry. + */ +static int +os_mgmt_taskstat_encode_one(struct CborEncoder *encoder, + const struct os_mgmt_task_info *task_info) +{ + CborEncoder task_map; + CborError err; + + err = 0; + err |= cbor_encode_text_stringz(encoder, task_info->oti_name); + err |= cbor_encoder_create_map(encoder, &task_map, CborIndefiniteLength); + err |= cbor_encode_text_stringz(&task_map, "prio"); + err |= cbor_encode_uint(&task_map, task_info->oti_prio); + err |= cbor_encode_text_stringz(&task_map, "tid"); + err |= cbor_encode_uint(&task_map, task_info->oti_taskid); + err |= cbor_encode_text_stringz(&task_map, "state"); + err |= cbor_encode_uint(&task_map, task_info->oti_state); + err |= cbor_encode_text_stringz(&task_map, "stkuse"); + err |= cbor_encode_uint(&task_map, task_info->oti_stkusage); + err |= cbor_encode_text_stringz(&task_map, "stksiz"); + err |= cbor_encode_uint(&task_map, task_info->oti_stksize); + err |= cbor_encode_text_stringz(&task_map, "cswcnt"); + err |= cbor_encode_uint(&task_map, task_info->oti_cswcnt); + err |= cbor_encode_text_stringz(&task_map, "runtime"); + err |= cbor_encode_uint(&task_map, task_info->oti_runtime); + err |= cbor_encode_text_stringz(&task_map, "last_checkin"); + err |= cbor_encode_uint(&task_map, task_info->oti_last_checkin); + err |= cbor_encode_text_stringz(&task_map, "next_checkin"); + err |= cbor_encode_uint(&task_map, task_info->oti_next_checkin); + err |= cbor_encoder_close_container(encoder, &task_map); + + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: os taskstat + */ +static int +os_mgmt_taskstat_read(struct mgmt_ctxt *ctxt) +{ + struct os_mgmt_task_info task_info; + struct CborEncoder tasks_map; + CborError err; + int task_idx; + int rc; + + err = 0; + err |= cbor_encode_text_stringz(&ctxt->encoder, "tasks"); + err |= cbor_encoder_create_map(&ctxt->encoder, &tasks_map, + CborIndefiniteLength); + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + /* Iterate the list of tasks, encoding each. */ + for (task_idx = 0; ; task_idx++) { + rc = os_mgmt_impl_task_info(task_idx, &task_info); + if (rc == MGMT_ERR_ENOENT) { + /* No more tasks to encode. */ + break; + } else if (rc != 0) { + return rc; + } + + rc = os_mgmt_taskstat_encode_one(&tasks_map, &task_info); + if (rc != 0) { + return rc; + } + } + + err = cbor_encoder_close_container(&ctxt->encoder, &tasks_map); + if (err != 0) { + return MGMT_ERR_ENOMEM; + } + + return 0; +} + +/** + * Command handler: os reset + */ +static int +os_mgmt_reset(struct mgmt_ctxt *ctxt) +{ + return os_mgmt_impl_reset(OS_MGMT_RESET_MS); +} + +void +os_mgmt_register_group(void) +{ + mgmt_register_group(&os_mgmt_group); +} diff --git a/cmd/os_mgmt/src/os_mgmt_config.h b/cmd/os_mgmt/src/os_mgmt_config.h new file mode 100644 index 0000000..d388dec --- /dev/null +++ b/cmd/os_mgmt/src/os_mgmt_config.h @@ -0,0 +1,22 @@ +#ifndef H_OS_MGMT_CONFIG_ +#define H_OS_MGMT_CONFIG_ + +#if defined MYNEWT + +#include "syscfg/syscfg.h" + +#define OS_MGMT_RESET_MS MYNEWT_VAL(OS_MGMT_RESET_MS) + +#elif defined __ZEPHYR__ + +#define OS_MGMT_RESET_MS CONFIG_OS_MGMT_RESET_MS + +#else + +/* No direct support for this OS. The application needs to define the above + * settings itself. + */ + +#endif + +#endif diff --git a/cmd/os_mgmt/src/stubs.c b/cmd/os_mgmt/src/stubs.c new file mode 100644 index 0000000..c17532b --- /dev/null +++ b/cmd/os_mgmt/src/stubs.c @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * These stubs get linked in when there is no equivalent OS-specific + * implementation. + */ + +#include "mgmt/mgmt.h" +#include "os_mgmt/os_mgmt_impl.h" + +int __attribute__((weak)) +os_mgmt_impl_task_info(int idx, struct os_mgmt_task_info *out_info) +{ + return MGMT_ERR_ENOTSUP; +} + +int __attribute__((weak)) +os_mgmt_impl_reset(unsigned int delay_ms) +{ + return MGMT_ERR_ENOTSUP; +} -- To stop receiving notification emails like this one, please contact ccoll...@apache.org.