From b137da69b7aff537494e6ed562775d6e1a606dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 10:30:25 +0100 Subject: [PATCH 01/38] [nrf fromtree] zcbor: Copy source and header files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit from zcbor 0.8.0 Signed-off-by: Øyvind Rønningstad (cherry picked from commit ad5f0ac1b2e3ce3fca4e746b492d453e578b9dc1) (cherry picked from commit 51a782127408dd50cac90239f52acfd1a36ba844) --- boot/zcbor/include/zcbor_common.h | 290 +++++--- boot/zcbor/include/zcbor_debug.h | 69 -- boot/zcbor/include/zcbor_decode.h | 491 +++++++------ boot/zcbor/include/zcbor_encode.h | 260 +++---- boot/zcbor/include/zcbor_print.h | 161 +++++ boot/zcbor/include/zcbor_tags.h | 94 +++ boot/zcbor/src/zcbor_common.c | 270 +++++++- boot/zcbor/src/zcbor_decode.c | 1073 +++++++++++++++++++++++------ boot/zcbor/src/zcbor_encode.c | 342 +++++---- 9 files changed, 2079 insertions(+), 971 deletions(-) delete mode 100644 boot/zcbor/include/zcbor_debug.h create mode 100644 boot/zcbor/include/zcbor_print.h create mode 100644 boot/zcbor/include/zcbor_tags.h diff --git a/boot/zcbor/include/zcbor_common.h b/boot/zcbor/include/zcbor_common.h index f44ded6ad..879889713 100644 --- a/boot/zcbor/include/zcbor_common.h +++ b/boot/zcbor/include/zcbor_common.h @@ -1,8 +1,3 @@ -/* - * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 - */ - /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -15,6 +10,8 @@ #include #include #include +#include +#include "zcbor_tags.h" #ifdef __cplusplus extern "C" { @@ -43,54 +40,25 @@ struct zcbor_string_fragment { /** Size to use in struct zcbor_string_fragment when the real size is unknown. */ #define ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH SIZE_MAX -#ifdef ZCBOR_VERBOSE -#include -#define zcbor_trace() (printk("bytes left: %zu, byte: 0x%x, elem_count: 0x%" PRIxFAST32 ", err: %d, %s:%d\n",\ - (size_t)state->payload_end - (size_t)state->payload, *state->payload, state->elem_count, \ - state->constant_state ? state->constant_state->error : 0, __FILE__, __LINE__)) - -#define zcbor_print_assert(expr, ...) \ -do { \ - printk("ASSERTION \n \"" #expr \ - "\"\nfailed at %s:%d with message:\n ", \ - __FILE__, __LINE__); \ - printk(__VA_ARGS__);\ -} while(0) -#define zcbor_print(...) printk(__VA_ARGS__) -#else -#define zcbor_trace() ((void)state) -#define zcbor_print_assert(...) -#define zcbor_print(...) -#endif - -#ifdef ZCBOR_ASSERTS -#define zcbor_assert(expr, ...) \ -do { \ - if (!(expr)) { \ - zcbor_print_assert(expr, __VA_ARGS__); \ - ZCBOR_FAIL(); \ - } \ -} while(0) -#define zcbor_assert_state(expr, ...) \ -do { \ - if (!(expr)) { \ - zcbor_print_assert(expr, __VA_ARGS__); \ - ZCBOR_ERR(ZCBOR_ERR_ASSERTION); \ - } \ -} while(0) -#else -#define zcbor_assert(expr, ...) -#define zcbor_assert_state(expr, ...) -#endif - #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif +#ifndef MAX +#define MAX(a, b) (((a) < (b)) ? (b) : (a)) +#endif + #ifndef ZCBOR_ARRAY_SIZE #define ZCBOR_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif +/* Endian-dependent offset of smaller integer in a bigger one. */ +#ifdef ZCBOR_BIG_ENDIAN +#define ZCBOR_ECPY_OFFS(dst_len, src_len) ((dst_len) - (src_len)) +#else +#define ZCBOR_ECPY_OFFS(dst_len, src_len) (0) +#endif /* ZCBOR_BIG_ENDIAN */ + #if SIZE_MAX <= UINT64_MAX /** The ZCBOR_SUPPORTS_SIZE_T will be defined if processing of size_t type variables directly * with zcbor_size_ functions is supported. @@ -102,6 +70,7 @@ do { \ struct zcbor_state_constant; +/** The zcbor_state_t structure is used for both encoding and decoding. */ typedef struct { union { uint8_t *payload_mut; @@ -110,31 +79,59 @@ union { processed. */ }; uint8_t const *payload_bak; /**< Temporary backup of payload. */ - uint_fast32_t elem_count; /**< The current element is part of a LIST or a MAP, - and this keeps count of how many elements are - expected. This will be checked before processing - and decremented if the element is correctly - processed. */ + size_t elem_count; /**< The current element is part of a LIST or a MAP, + and this keeps count of how many elements are + expected. This will be checked before processing + and decremented if the element is correctly + processed. */ uint8_t const *payload_end; /**< The end of the payload. This will be checked against payload before processing each element. */ - bool indefinite_length_array; /**< Is set to true if the decoder is currently - decoding the contents of an indefinite- - length array. */ bool payload_moved; /**< Is set to true while the state is stored as a backup if @ref zcbor_update_state is called, since that function updates the payload_end of all backed-up states. */ + +/* This is the "decode state", the part of zcbor_state_t that is only used by zcbor_decode.c. */ +struct { + bool indefinite_length_array; /**< Is set to true if the decoder is currently + decoding the contents of an indefinite- + length array. */ + bool counting_map_elems; /**< Is set to true while the number of elements of the + current map are being counted. */ +#ifdef ZCBOR_MAP_SMART_SEARCH + uint8_t *map_search_elem_state; /**< Optional flags to use when searching unordered + maps. If this is not NULL and map_elem_count + is non-zero, this consists of one flag per element + in the current map. The n-th bit can be set to 0 + to indicate that the n-th element in the + map should not be searched. These are manipulated + via zcbor_elem_processed() or + zcbor_unordered_map_search(), and should not be + manipulated directly. */ +#else + size_t map_elems_processed; /**< The number of elements of an unordered map + that have been processed. */ +#endif + size_t map_elem_count; /**< Number of elements in the current unordered map. + This also serves as the number of bits (not bytes) + in the map_search_elem_state array (when applicable). */ +} decode_state; struct zcbor_state_constant *constant_state; /**< The part of the state that is not backed up and duplicated. */ } zcbor_state_t; struct zcbor_state_constant { zcbor_state_t *backup_list; - uint_fast32_t current_backup; - uint_fast32_t num_backups; + size_t current_backup; + size_t num_backups; int error; #ifdef ZCBOR_STOP_ON_ERROR bool stop_on_error; +#endif + bool manually_process_elem; /**< Whether an (unordered map) element should be automatically + marked as processed when found via @ref zcbor_search_map_key. */ +#ifdef ZCBOR_MAP_SMART_SEARCH + uint8_t *map_search_elem_state_end; /**< The end of the @ref map_search_elem_state buffer. */ #endif }; @@ -152,27 +149,42 @@ typedef bool(zcbor_decoder_t)(zcbor_state_t *, void *); */ typedef enum { - ZCBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer - ZCBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer - ZCBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String - ZCBOR_MAJOR_TYPE_TSTR = 3, ///! Text String - ZCBOR_MAJOR_TYPE_LIST = 4, ///! List - ZCBOR_MAJOR_TYPE_MAP = 5, ///! Map - ZCBOR_MAJOR_TYPE_TAG = 6, ///! Semantic Tag - ZCBOR_MAJOR_TYPE_PRIM = 7, ///! Primitive Type + ZCBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer + ZCBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer + ZCBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String + ZCBOR_MAJOR_TYPE_TSTR = 3, ///! Text String + ZCBOR_MAJOR_TYPE_LIST = 4, ///! List + ZCBOR_MAJOR_TYPE_MAP = 5, ///! Map + ZCBOR_MAJOR_TYPE_TAG = 6, ///! Semantic Tag + ZCBOR_MAJOR_TYPE_SIMPLE = 7, ///! Simple values and floats } zcbor_major_type_t; +/** Extract the major type, i.e. the first 3 bits of the header byte. */ +#define ZCBOR_MAJOR_TYPE(header_byte) ((zcbor_major_type_t)(((header_byte) >> 5) & 0x7)) + +/** Extract the additional info, i.e. the last 5 bits of the header byte. */ +#define ZCBOR_ADDITIONAL(header_byte) ((header_byte) & 0x1F) /** Convenience macro for failing out of a decoding/encoding function. */ #define ZCBOR_FAIL() \ do {\ - zcbor_trace(); \ + zcbor_log("ZCBOR_FAIL "); \ + zcbor_trace_file(state); \ return false; \ } while(0) +#define ZCBOR_FAIL_IF(expr) \ +do {\ + if (expr) { \ + zcbor_log("ZCBOR_FAIL_IF(" #expr ") "); \ + ZCBOR_FAIL(); \ + } \ +} while(0) + #define ZCBOR_ERR(err) \ do { \ + zcbor_log("ZCBOR_ERR(%d) ", err); \ zcbor_error(state, err); \ ZCBOR_FAIL(); \ } while(0) @@ -180,6 +192,7 @@ do { \ #define ZCBOR_ERR_IF(expr, err) \ do {\ if (expr) { \ + zcbor_log("ZCBOR_ERR_IF(" #expr ", %d) ", err); \ ZCBOR_ERR(err); \ } \ } while(0) @@ -205,11 +218,12 @@ do { \ #define ZCBOR_VALUE_IS_8_BYTES 27 ///! The next 8 bytes contain the value. #define ZCBOR_VALUE_IS_INDEFINITE_LENGTH 31 ///! The list or map has indefinite length, and will instead be terminated by a 0xFF token. -#define ZCBOR_BOOL_TO_PRIM ((uint8_t)20) ///! In CBOR, false/true have the values 20/21 +#define ZCBOR_BOOL_TO_SIMPLE ((uint8_t)20) ///! In CBOR, false/true have the values 20/21 #define ZCBOR_FLAG_RESTORE 1UL ///! Restore from the backup. Overwrite the current state with the state from the backup. #define ZCBOR_FLAG_CONSUME 2UL ///! Consume the backup. Remove the backup from the stack of backups. -#define ZCBOR_FLAG_TRANSFER_PAYLOAD 4UL ///! Keep the pre-restore payload after restoring. +#define ZCBOR_FLAG_KEEP_PAYLOAD 4UL ///! Keep the pre-restore payload after restoring. +#define ZCBOR_FLAG_KEEP_DECODE_STATE 8UL ///! Keep the pre-restore decode state (everything only used for decoding) #define ZCBOR_SUCCESS 0 #define ZCBOR_ERR_NO_BACKUP_MEM 1 @@ -226,47 +240,30 @@ do { \ #define ZCBOR_ERR_WRONG_RANGE 12 #define ZCBOR_ERR_ITERATIONS 13 #define ZCBOR_ERR_ASSERTION 14 +#define ZCBOR_ERR_PAYLOAD_OUTDATED 15 ///! Because of a call to @ref zcbor_update_state +#define ZCBOR_ERR_ELEM_NOT_FOUND 16 +#define ZCBOR_ERR_MAP_MISALIGNED 17 +#define ZCBOR_ERR_ELEMS_NOT_PROCESSED 18 +#define ZCBOR_ERR_NOT_AT_END 19 +#define ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE 20 +#define ZCBOR_ERR_INVALID_VALUE_ENCODING 21 ///! When ZCBOR_CANONICAL is defined, and the incoming data is not encoded with minimal length. #define ZCBOR_ERR_UNKNOWN 31 /** The largest possible elem_count. */ -#ifdef UINT_FAST32_MAX -#define ZCBOR_MAX_ELEM_COUNT UINT_FAST32_MAX -#else -#define ZCBOR_MAX_ELEM_COUNT ((uint_fast32_t)(-1L)) -#endif +#define ZCBOR_MAX_ELEM_COUNT SIZE_MAX /** Initial value for elem_count for when it just needs to be large. */ -#define ZCBOR_LARGE_ELEM_COUNT (ZCBOR_MAX_ELEM_COUNT - 16) - - -/** Values defined by RFC8949 via www.iana.org/assignments/cbor-tags/cbor-tags.xhtml */ -enum zcbor_rfc8949_tag { - ZCBOR_TAG_TIME_TSTR = 0, ///! text string Standard date/time string - ZCBOR_TAG_TIME_NUM = 1, ///! integer or float Epoch-based date/time - ZCBOR_TAG_UBIGNUM_BSTR = 2, ///! byte string Unsigned bignum - ZCBOR_TAG_BIGNUM_BSTR = 3, ///! byte string Negative bignum - ZCBOR_TAG_DECFRAC_ARR = 4, ///! array Decimal fraction - ZCBOR_TAG_BIGFLOAT_ARR = 5, ///! array Bigfloat - ZCBOR_TAG_2BASE64URL = 21, ///! (any) Expected conversion to base64url encoding - ZCBOR_TAG_2BASE64 = 22, ///! (any) Expected conversion to base64 encoding - ZCBOR_TAG_2BASE16 = 23, ///! (any) Expected conversion to base16 encoding - ZCBOR_TAG_BSTR = 24, ///! byte string Encoded CBOR data item - ZCBOR_TAG_URI_TSTR = 32, ///! text string URI - ZCBOR_TAG_BASE64URL_TSTR = 33, ///! text string base64url - ZCBOR_TAG_BASE64_TSTR = 34, ///! text string base64 - ZCBOR_TAG_MIME_TSTR = 36, ///! text string MIME message - ZCBOR_TAG_CBOR = 55799, ///! (any) Self-described CBOR -}; +#define ZCBOR_LARGE_ELEM_COUNT (ZCBOR_MAX_ELEM_COUNT - 15) /** Take a backup of the current state. Overwrite the current elem_count. */ -bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count); +bool zcbor_new_backup(zcbor_state_t *state, size_t new_elem_count); /** Consult the most recent backup. In doing so, check whether elem_count is * less than or equal to max_elem_count. * Also, take action based on the flags (See ZCBOR_FLAG_*). */ -bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, uint_fast32_t max_elem_count); +bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, size_t max_elem_count); /** Convenience function for starting encoding/decoding of a union. * @@ -294,17 +291,30 @@ bool zcbor_union_end_code(zcbor_state_t *state); * If there is no struct zcbor_state_constant (n_states == 1), error codes are * not available. * This means that you get a state with (n_states - 2) backups. - * payload, payload_len, and elem_count are used to initialize the first state. - * in the array, which is the state that can be passed to cbor functions. + * payload, payload_len, elem_count, and elem_state are used to initialize the first state. + * The elem_state is only needed for unordered maps, when ZCBOR_MAP_SMART_SEARCH is enabled. + * It is ignored otherwise. + */ +void zcbor_new_state(zcbor_state_t *state_array, size_t n_states, + const uint8_t *payload, size_t payload_len, size_t elem_count, + uint8_t *elem_state, size_t elem_state_bytes); + +/** Do boilerplate entry function procedure. + * Initialize states, call function, and check the result. */ -void zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states, - const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); +int zcbor_entry_function(const uint8_t *payload, size_t payload_len, + void *result, size_t *payload_len_out, zcbor_state_t *state, zcbor_decoder_t func, + size_t n_states, size_t elem_count); #ifdef ZCBOR_STOP_ON_ERROR -/** Check stored error and fail if present, but only if stop_on_error is true. */ +/** Check stored error and fail if present, but only if stop_on_error is true. + * + * @retval true No error found + * @retval false An error was found + */ static inline bool zcbor_check_error(const zcbor_state_t *state) { - struct zcbor_state_constant *cs = state->constant_state; + struct zcbor_state_constant *cs = state->constant_state; return !(cs && cs->stop_on_error && cs->error); } #endif @@ -355,9 +365,9 @@ static inline bool zcbor_payload_at_end(const zcbor_state_t *state) * For use when the payload is divided into multiple chunks. * * This function also updates all backups to the new payload_end. - * This sets a flag so that if a backup is processed with the flag - * @ref ZCBOR_FLAG_RESTORE, but without the flag - * @ref ZCBOR_FLAG_TRANSFER_PAYLOAD since this would cause an invalid state. + * This sets a flag so that @ref zcbor_process_backup fails if a backup is + * processed with the flag @ref ZCBOR_FLAG_RESTORE, but without the flag + * @ref ZCBOR_FLAG_KEEP_PAYLOAD since this would cause an invalid state. * * @param[inout] state The current state, will be updated with * the new payload pointer. @@ -382,7 +392,7 @@ void zcbor_update_state(zcbor_state_t *state, * found, or if any fragment value is NULL. */ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, - uint_fast32_t num_fragments); + size_t num_fragments); /** Assemble the fragments into a single string. * @@ -401,7 +411,77 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, * The buffer might still be written to. */ bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, - uint_fast32_t num_fragments, uint8_t *result, size_t *result_len); + size_t num_fragments, uint8_t *result, size_t *result_len); + +/** Compare two struct zcbor_string instances. + * + * @param[in] str1 A string + * @param[in] str2 A string to compare to @p str1 + * + * @retval true if the strings are identical + * @retval false if length or contents don't match, or one one or both strings is NULL. + */ +bool zcbor_compare_strings(const struct zcbor_string *str1, + const struct zcbor_string *str2); + +/** Calculate the length of a CBOR string, list, or map header. + * + * This can be used to find the start of the CBOR object when you have a + * pointer to the start of the contents. The function assumes that the header + * will be the shortest it can be. + * + * @param[in] num_elems The number of elements in the string, list, or map. + * + * @return The length of the header in bytes (1-9). + */ +size_t zcbor_header_len(uint64_t value); + +/** Like @ref zcbor_header_len but for integer of any size <= 8. */ +size_t zcbor_header_len_ptr(const void *const value, size_t value_len); + +/** Convert a float16 value to float32. + * + * @param[in] input The float16 value stored in a uint16_t. + * + * @return The resulting float32 value. + */ +float zcbor_float16_to_32(uint16_t input); + +/** Convert a float32 value to float16. + * + * @param[in] input The float32 value. + * + * @return The resulting float16 value as a uint16_t. + */ +uint16_t zcbor_float32_to_16(float input); + +#ifdef ZCBOR_MAP_SMART_SEARCH +static inline size_t zcbor_round_up(size_t x, size_t align) +{ + return (((x) + (align) - 1) / (align) * (align)); +} + +#define ZCBOR_BITS_PER_BYTE 8 +/** Calculate the number of bytes needed to hold @p num_flags 1 bit flags + */ +static inline size_t zcbor_flags_to_bytes(size_t num_flags) +{ + return zcbor_round_up(num_flags, ZCBOR_BITS_PER_BYTE) / ZCBOR_BITS_PER_BYTE; +} + +/** Calculate the number of zcbor_state_t instances needed to hold @p num_flags 1 bit flags + */ +static inline size_t zcbor_flags_to_states(size_t num_flags) +{ + return zcbor_round_up(num_flags, sizeof(zcbor_state_t) * ZCBOR_BITS_PER_BYTE) + / (sizeof(zcbor_state_t) * ZCBOR_BITS_PER_BYTE); +} + +#define ZCBOR_FLAG_STATES(n_flags) zcbor_flags_to_states(n_flags) + +#else +#define ZCBOR_FLAG_STATES(n_flags) 0 +#endif #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_debug.h b/boot/zcbor/include/zcbor_debug.h deleted file mode 100644 index 5f9b4778f..000000000 --- a/boot/zcbor/include/zcbor_debug.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZCBOR_DEBUG_H__ -#define ZCBOR_DEBUG_H__ - -#include -#include -#include -#include "zcbor_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -__attribute__((used)) -static void zcbor_print_compare_lines(const uint8_t *str1, const uint8_t *str2, uint32_t size) -{ - for (uint32_t j = 0; j < size; j++) { - printk ("%x ", str1[j]); - } - printk("\r\n"); - for (uint32_t j = 0; j < size; j++) { - printk ("%x ", str2[j]); - } - printk("\r\n"); - for (uint32_t j = 0; j < size; j++) { - printk ("%x ", str1[j] != str2[j]); - } - printk("\r\n"); - printk("\r\n"); -} - -__attribute__((used)) -static void zcbor_print_compare_strings(const uint8_t *str1, const uint8_t *str2, uint32_t size) -{ - for (uint32_t i = 0; i <= size / 16; i++) { - printk("line %d (char %d)\r\n", i, i*16); - zcbor_print_compare_lines(&str1[i*16], &str2[i*16], - MIN(16, (size - i*16))); - } - printk("\r\n"); -} - -__attribute__((used)) -static void zcbor_print_compare_strings_diff(const uint8_t *str1, const uint8_t *str2, uint32_t size) -{ - bool printed = false; - for (uint32_t i = 0; i <= size / 16; i++) { - if (memcmp(&str1[i*16], &str2[i*16], MIN(16, (size - i*16)) != 0)) { - printk("line %d (char %d)\r\n", i, i*16); - zcbor_print_compare_lines(&str1[i*16], &str2[i*16], - MIN(16, (size - i*16))); - printed = true; - } - } - if (printed) { - printk("\r\n"); - } -} - -#ifdef __cplusplus -} -#endif - -#endif /* ZCBOR_DEBUG_H__ */ diff --git a/boot/zcbor/include/zcbor_decode.h b/boot/zcbor/include/zcbor_decode.h index 53ce94db4..61a6f1763 100644 --- a/boot/zcbor/include/zcbor_decode.h +++ b/boot/zcbor/include/zcbor_decode.h @@ -1,8 +1,3 @@ -/* - * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 - */ - /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -28,213 +23,222 @@ extern "C" { */ -/** The following applies to all single-value decode functions that don't have docs. +/** See @ref zcbor_new_state() */ +void zcbor_new_decode_state(zcbor_state_t *state_array, size_t n_states, + const uint8_t *payload, size_t payload_len, size_t elem_count, + uint8_t *elem_state, size_t elem_state_bytes); + +/** Convenience macro for declaring and initializing a decoding state with backups. * - * @param[inout] state The current state of the decoding. - * @param[out] result Where to place the decoded value. + * This gives you a state variable named @p name. The variable functions like + * a pointer. + * + * @param[in] name The name of the new state variable. + * @param[in] num_backups The number of backup slots to keep in the state. + * @param[in] payload The payload to work on. + * @param[in] payload_size The size (in bytes) of @p payload. + * @param[in] elem_count The starting elem_count (typically 1). + * @param[in] n_flags For use if ZCBOR_MAP_SMART_SEARCH is enabled, ignored otherwise. + * The total number of unordered map search flags needed. + * I.e. the largest number of elements expected in an unordered map, + * including elements in nested unordered maps. + */ +#define ZCBOR_STATE_D(name, num_backups, payload, payload_size, elem_count, n_flags) \ +zcbor_state_t name[((num_backups) + 2 + ZCBOR_FLAG_STATES(n_flags))]; \ +do { \ + zcbor_new_decode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count, \ + (uint8_t *)&name[(num_backups) + 1], ZCBOR_FLAG_STATES(n_flags) * sizeof(zcbor_state_t)); \ +} while(0) + + +/** The following applies to all _decode() functions listed directly below. + * + * @param[inout] state The current state of the decoding. + * @param[out] result Where to place the decoded value. + * @param[in] result_size (if present) Size in bytes of the memory at @p result * * @retval true If the value was decoded correctly. * @retval false If the value has the wrong type, the payload overflowed, the * element count was exhausted, or the value was larger than can * fit in the result variable. + * Use zcbor_peek_error() to see the error code. */ - -/** Decode and consume a pint/nint. */ -bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result); -bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result); -bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result); -bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result); -bool zcbor_size_decode(zcbor_state_t *state, size_t *result); -bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size); - -/** The following applies to all _expect() functions that don't have docs. - * - * @param[inout] state The current state of the decoding. - * @param[in] result The expected value. +bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result); /* pint/nint */ +bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result); /* pint/nint */ +bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result); /* pint */ +bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result); /* pint */ +bool zcbor_size_decode(zcbor_state_t *state, size_t *result); /* pint */ +bool zcbor_int_decode(zcbor_state_t *state, void *result, size_t result_size); /* pint/nint */ +bool zcbor_uint_decode(zcbor_state_t *state, void *result, size_t result_size); /* pint */ +bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result); /* bstr */ +bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result); /* tstr */ +bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result); /* CBOR tag */ +bool zcbor_simple_decode(zcbor_state_t *state, uint8_t *result); /* CBOR simple value */ +bool zcbor_bool_decode(zcbor_state_t *state, bool *result); /* boolean CBOR simple value */ +bool zcbor_float16_decode(zcbor_state_t *state, float *result); /* IEEE754 float16 */ +bool zcbor_float16_bytes_decode(zcbor_state_t *state, uint16_t *result); /* IEEE754 float16 raw bytes */ +bool zcbor_float16_32_decode(zcbor_state_t *state, float *result); /* IEEE754 float16 or float32 */ +bool zcbor_float32_decode(zcbor_state_t *state, float *result); /* IEEE754 float32 */ +bool zcbor_float32_64_decode(zcbor_state_t *state, double *result); /* IEEE754 float32 or float64 */ +bool zcbor_float64_decode(zcbor_state_t *state, double *result); /* IEEE754 float64 */ +bool zcbor_float_decode(zcbor_state_t *state, double *result); /* IEEE754 float16, float32, or float64 */ + +/** The following applies to all _expect() and _pexpect() functions listed directly below. + * + * @param[inout] state The current state of the decoding. + * @param[in] expected The expected value. * * @retval true If the result was decoded correctly and has the expected value. * @retval false If the decoding failed or the result doesn't have the * expected value. + * Use zcbor_peek_error() to see the error code. */ -/** Consume and expect a pint/nint with a certain value. */ -bool zcbor_int32_expect(zcbor_state_t *state, int32_t result); -bool zcbor_int64_expect(zcbor_state_t *state, int64_t result); -bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t result); -bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t result); -bool zcbor_size_expect(zcbor_state_t *state, size_t result); +bool zcbor_int32_expect(zcbor_state_t *state, int32_t expected); /* pint/nint */ +bool zcbor_int64_expect(zcbor_state_t *state, int64_t expected); /* pint/nint */ +bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t expected); /* pint */ +bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t expected); /* pint */ +bool zcbor_size_expect(zcbor_state_t *state, size_t expected); /* pint */ +bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *expected); /* bstr */ +bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *expected); /* tstr */ +bool zcbor_tag_expect(zcbor_state_t *state, uint32_t expected); /* CBOR tag */ +bool zcbor_simple_expect(zcbor_state_t *state, uint8_t expected); /* CBOR simple value */ +bool zcbor_bool_expect(zcbor_state_t *state, bool expected); /* boolean CBOR simple value */ +bool zcbor_nil_expect(zcbor_state_t *state, void *unused); /* 'nil' CBOR simple value */ +bool zcbor_undefined_expect(zcbor_state_t *state, void *unused); /* 'undefined' CBOR simple value */ +bool zcbor_float16_expect(zcbor_state_t *state, float expected); /* IEEE754 float16 */ +bool zcbor_float16_bytes_expect(zcbor_state_t *state, uint16_t expected); /* IEEE754 float16 raw bytes */ +bool zcbor_float16_32_expect(zcbor_state_t *state, float expected); /* IEEE754 float16 or float32 */ +bool zcbor_float32_expect(zcbor_state_t *state, float expected); /* IEEE754 float32 */ +bool zcbor_float32_64_expect(zcbor_state_t *state, double expected); /* IEEE754 float32 or float64 */ +bool zcbor_float64_expect(zcbor_state_t *state, double expected); /* IEEE754 float64 */ +bool zcbor_float_expect(zcbor_state_t *state, double expected); /* IEEE754 float16, float32, or float64 */ + +/** Like the _expect() functions but the value is passed through a pointer. + * (for use as a zcbor_decoder_t function) */ +bool zcbor_int32_pexpect(zcbor_state_t *state, int32_t *expected); /* pint/nint */ +bool zcbor_int64_pexpect(zcbor_state_t *state, int64_t *expected); /* pint/nint */ +bool zcbor_uint32_pexpect(zcbor_state_t *state, uint32_t *expected); /* pint */ +bool zcbor_uint64_pexpect(zcbor_state_t *state, uint64_t *expected); /* pint */ +bool zcbor_size_pexpect(zcbor_state_t *state, size_t *expected); /* pint */ +bool zcbor_tag_pexpect(zcbor_state_t *state, uint32_t *expected); /* CBOR tag */ +bool zcbor_simple_pexpect(zcbor_state_t *state, uint8_t *expected); /* CBOR simple value */ +bool zcbor_bool_pexpect(zcbor_state_t *state, bool *expected); /* boolean CBOR simple value */ +bool zcbor_float16_pexpect(zcbor_state_t *state, float *expected); /* IEEE754 float16 */ +bool zcbor_float16_bytes_pexpect(zcbor_state_t *state, uint16_t *expected); /* IEEE754 float16 raw bytes */ +bool zcbor_float16_32_pexpect(zcbor_state_t *state, float *expected); /* IEEE754 float16 or float32 */ +bool zcbor_float32_pexpect(zcbor_state_t *state, float *expected); /* IEEE754 float32 */ +bool zcbor_float32_64_pexpect(zcbor_state_t *state, double *expected); /* IEEE754 float32 or float64 */ +bool zcbor_float64_pexpect(zcbor_state_t *state, double *expected); /* IEEE754 float64 */ +bool zcbor_float_pexpect(zcbor_state_t *state, double *expected); /* IEEE754 float16, float32, or float64 */ /** Consume and expect a pint/nint with a certain value, within a union. * * Calls @ref zcbor_union_elem_code then @ref zcbor_[u]int[32|64]_expect. */ -bool zcbor_int32_expect_union(zcbor_state_t *state, int32_t result); -bool zcbor_int64_expect_union(zcbor_state_t *state, int64_t result); -bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result); -bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result); - -/** Decode and consume a bstr/tstr */ -bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result); -bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *result); -bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result); -bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *result); - -/** Consume and expect a bstr/tstr with the value of the provided string literal. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to expect. A pointer to the string. - * @param[in] len The length of the string pointed to by @p string. - */ -static inline bool zcbor_bstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len) -{ - struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; - - return zcbor_bstr_expect(state, &zs); -} -static inline bool zcbor_tstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len) -{ - struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; - - return zcbor_tstr_expect(state, &zs); -} - - -/** Consume and expect a bstr/tstr with the value of the provided string literal. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to expect. A string literal, e.g. "Foo", so - * that sizeof(string) - 1 is the length of the string. - */ -#define zcbor_bstr_expect_lit(state, string) \ - zcbor_bstr_expect_ptr(state, string, sizeof(string) - 1) -#define zcbor_tstr_expect_lit(state, string) \ - zcbor_tstr_expect_ptr(state, string, sizeof(string) - 1) - -/** Consume and expect a bstr/tstr with the value of the provided null-terminated string. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to expect. Must be a null-terminated string, - * so that strlen can be used. - */ -#define zcbor_bstr_expect_term(state, string) \ - zcbor_bstr_expect_ptr(state, string, strlen(string)) -#define zcbor_tstr_expect_term(state, string) \ - zcbor_tstr_expect_ptr(state, string, strlen(string)) - -/** Consume and expect a bstr/tstr with the value of the provided char array literal. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to expect. An array literal, e.g. {'F', 'o', 'o'}, - * so that sizeof(string) is the length of the string. - */ -#define zcbor_bstr_expect_arr(state, string) \ - zcbor_bstr_expect_ptr(state, string, (sizeof(string))) -#define zcbor_tstr_expect_arr(state, string) \ - zcbor_tstr_expect_ptr(state, string, (sizeof(string))) - -/** Decode and consume a tag. */ -bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result); -bool zcbor_tag_expect(zcbor_state_t *state, uint32_t result); - -/** Decode and consume a boolean primitive value. */ -bool zcbor_bool_decode(zcbor_state_t *state, bool *result); -bool zcbor_bool_expect(zcbor_state_t *state, bool result); - -/** Decode and consume a float */ -bool zcbor_float32_decode(zcbor_state_t *state, float *result); -bool zcbor_float32_expect(zcbor_state_t *state, float result); -bool zcbor_float64_decode(zcbor_state_t *state, double *result); -bool zcbor_float64_expect(zcbor_state_t *state, double result); -bool zcbor_float_decode(zcbor_state_t *state, double *result); -bool zcbor_float_expect(zcbor_state_t *state, double result); - -/** Consume and expect a "nil"/"undefined" primitive value. - * - * @param[inout] state The current state of the encoding. - * @param[in] unused Unused parameter to maintain signature parity with - * @ref zcbor_decoder_t. - */ -bool zcbor_nil_expect(zcbor_state_t *state, void *unused); -bool zcbor_undefined_expect(zcbor_state_t *state, void *unused); - -/** Skip a single element, regardless of type and value. - * - * @param[inout] state The current state of the encoding. - * @param[in] unused Unused parameter to maintain signature parity with - * @ref zcbor_decoder_t. - */ -bool zcbor_any_skip(zcbor_state_t *state, void *unused); +bool zcbor_int32_expect_union(zcbor_state_t *state, int32_t expected); +bool zcbor_int64_expect_union(zcbor_state_t *state, int64_t expected); +bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t expected); +bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t expected); -/** Decode and consume a bstr header. +/** Decode and consume a list/map header. * - * The rest of the string can be decoded as CBOR. + * The contents of the list can be decoded via subsequent function calls. * A state backup is created to keep track of the element count. - * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + * Call @ref zcbor_list_end_decode / @ref zcbor_map_end_decode when done + * decoding the contents of the list/map * * @retval true Header decoded correctly * @retval false Header decoded incorrectly, or backup failed. */ -bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result); - -/** Finalize decoding a CBOR-encoded bstr. - * - * Restore element count from backup. +bool zcbor_list_start_decode(zcbor_state_t *state); +bool zcbor_map_start_decode(zcbor_state_t *state); +bool zcbor_unordered_map_start_decode(zcbor_state_t *state); + +/** Search for a key in a map. + * + * The CBOR spec allows elements (key-value pairs) in maps to appear in any order. + * This function should be used when the order of elements is unknown. + * + * This must only be used while inside a map that has been entered via + * @ref zcbor_unordered_map_start_decode. Use @ref zcbor_unordered_map_end_decode + * when leaving the map. + * + * This function searches for keys. When this function returns successfully, + * the @p state is pointing to the value corresponding to the found key. + * Therefore, to be able to call this function again, the value must first be + * decoded or skipped. + * + * When searching unordered maps, the found elements must be kept track of. + * By default, this function automatically keeps track, which means it keeps a + * running count of the number of found elements, which is checked when exiting + * the map. You can do this manually instead, see @ref zcbor_elem_processed and + * @ref manually_process_elem. If ZCBOR_MAP_SMART_SEARCH is defined, a flag is + * kept for each element, instead of a rolling count. + * + * @note Unless ZCBOR_MAP_SMART_SEARCH is defined, + * elements are not individually marked as processed, so they may + * be returned again in a subsequent call to this function, if it is + * matched by the @p key_decoder of that call. Because of this, you should + * only use this function when you know the @p key_decoder matches no more + * than one of the keys. Typically this means all keys are known strings + * or integers, i.e. the @p key_decoder is typically a _pexpect() function. + * + * When searching for strings, there are convenience functions available, + * see the zcbor_search_key_* functions. + * + * @param[in] key_decoder A decoding function that will be tried against all + * keys in the map until it returns true, at which point + * @ref zcbor_unordered_map_search will return true. + * For example, a zcbor_*_pexpect() function. + * @param[inout] state The current state of decoding. Must be currently decoding + * the contents of a map, and pointing to one (any) of the + * keys, not one of the values. If successful, the @p state + * will be pointing to the value corresponding to the + * matched key. If unsuccessful, the @p state will be + * unchanged. + * @param[inout] key_result This will be passed as the second argument to the + * @p key_decoder. + * + * @retval true If the key was found, i.e. @p key_decoder returned true. + * @retval false If the key was not found after searching all map elements. + * Or the map was pointing to a value (not a key). + * Or an unexpected error happened while skipping elements or + * jumping from the end of the map to the start. */ -bool zcbor_bstr_end_decode(zcbor_state_t *state); +bool zcbor_unordered_map_search(zcbor_decoder_t key_decoder, zcbor_state_t *state, void *key_result); -/** Start decoding a bstr/tstr, even if the payload contains only part of it. - * - * This must be followed by a call to @ref zcbor_update_state, which can be - * followed by a call to @ref zcbor_next_fragment. Do not call this function - * again on subsequent fragments of the same string. +/** Find a specific bstr/tstr key as part of a map with unknown element order. * - * This consumes the remaining payload as long as it belongs to the string. + * Uses @ref zcbor_unordered_map_search under the hood. Please refer to those docs + * for the conditions under which this can be called. + * Refer to the docs for zcbor_(t|b)str_expect_* (e.g. @ref zcbor_bstr_expect_ptr) + * for parameter docs. */ -bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); -bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); +bool zcbor_search_key_bstr_ptr(zcbor_state_t *state, char const *ptr, size_t len); +bool zcbor_search_key_tstr_ptr(zcbor_state_t *state, char const *ptr, size_t len); +bool zcbor_search_key_bstr_term(zcbor_state_t *state, char const *str, size_t maxlen); +bool zcbor_search_key_tstr_term(zcbor_state_t *state, char const *str, size_t maxlen); +#define zcbor_search_key_bstr_lit(state, str) zcbor_search_key_bstr_ptr(state, str, sizeof(str) - 1) +#define zcbor_search_key_tstr_lit(state, str) zcbor_search_key_tstr_ptr(state, str, sizeof(str) - 1) +#define zcbor_search_key_bstr_arr(state, str) zcbor_search_key_bstr_ptr(state, str, (sizeof(str))) +#define zcbor_search_key_tstr_arr(state, str) zcbor_search_key_tstr_ptr(state, str, (sizeof(str))) -/** Extract the next fragment of a string. +/** (Optional) Call this function to mark an (unordered map) element as processed. * - * Use this function to extract all but the first fragment. - */ -void zcbor_next_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *prev_fragment, - struct zcbor_string_fragment *result); - -/** Decode and consume a bstr header, assuming the payload does not contain the whole bstr. + * @note This should not be called unless the @ref manually_process_elem flag is set. + * By default, i.e. when @ref manually_process_elem is not set, this function is + * called internally by @ref zcbor_unordered_map_search whenever a key is found. * - * The rest of the string can be decoded as CBOR. - * A state backup is created to keep track of the element count. - * Call @ref zcbor_update_state followed by @ref zcbor_bstr_next_fragment when - * the current payload has been exhausted. - * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. - */ -bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *result); - -/** Start decoding the next fragment of a string. + * By default, this function increments the internal count @ref map_elems_processed. * - * Use this function to extract all but the first fragment of a CBOR-encoded - * bstr. - */ -void zcbor_bstr_next_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *prev_fragment, - struct zcbor_string_fragment *result); - -/** Can be used on any fragment to tell if it is the final fragment of the string. */ -bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment); - -/** Decode and consume a list/map header. + * If ZCBOR_MAP_SMART_SEARCH is defined, this function instead clears a flag for the + * element (key-value pair) that is currently being processed, or that has just been + * processed, meaning the element won't be found again via @ref zcbor_unordered_map_search. * - * The contents of the list can be decoded via subsequent function calls. - * A state backup is created to keep track of the element count. - * Call @ref zcbor_list_end_decode / @ref zcbor_map_end_decode when done - * decoding the contents of the list/map - * - * @retval true Header decoded correctly - * @retval false Header decoded incorrectly, or backup failed. + * @ref zcbor_unordered_map_end_decode will fail if @ref map_elems_processed does not + * match the number of elements in the map, or if any of the map element's flag is set. */ -bool zcbor_list_start_decode(zcbor_state_t *state); -bool zcbor_map_start_decode(zcbor_state_t *state); +bool zcbor_elem_processed(zcbor_state_t *state); /** Finalize decoding a list/map * @@ -244,13 +248,33 @@ bool zcbor_map_start_decode(zcbor_state_t *state); * Use @ref zcbor_list_map_end_force_decode to forcibly consume the backup if * something has gone wrong. * + * In all successful cases, the state is returned pointing to the byte/element + * after the list/map in the payload. + * * @retval true Everything ok. * @retval false Element count not correct. */ bool zcbor_list_end_decode(zcbor_state_t *state); bool zcbor_map_end_decode(zcbor_state_t *state); +bool zcbor_unordered_map_end_decode(zcbor_state_t *state); bool zcbor_list_map_end_force_decode(zcbor_state_t *state); +/** Find whether the state is at the end of a list or map. + */ +bool zcbor_array_at_end(zcbor_state_t *state); + +/** Skip a single element, regardless of type and value. + * + * This means if the element is a map or list, this function will recursively + * skip all its contents. + * This function will also skip any tags preceeding the element. + * + * @param[inout] state The current state of the decoding. + * @param[in] unused Unused parameter to maintain signature parity with + * @ref zcbor_decoder_t. + */ +bool zcbor_any_skip(zcbor_state_t *state, void *unused); + /** Decode 0 or more elements with the same type and constraints. * * The decoded values will appear consecutively in the @p result array. @@ -293,6 +317,8 @@ bool zcbor_list_map_end_force_decode(zcbor_state_t *state); * The result pointer is moved @p result_len bytes for * each call to @p decoder, i.e. @p result refers to * an array of result variables. + * Should not be an _expect() function, use + * _pexpect() instead. * @param[out] result Where to place the decoded values. Must be an array * of at least @p max_decode elements. * @param[in] result_len The length of each result variable. Must be the @@ -302,9 +328,9 @@ bool zcbor_list_map_end_force_decode(zcbor_state_t *state); * @retval false If @p decoder failed before having decoded @p min_decode * values. */ -bool zcbor_multi_decode(uint_fast32_t min_decode, uint_fast32_t max_decode, uint_fast32_t *num_decode, +bool zcbor_multi_decode(size_t min_decode, size_t max_decode, size_t *num_decode, zcbor_decoder_t decoder, zcbor_state_t *state, void *result, - uint_fast32_t result_len); + size_t result_len); /** Attempt to decode a value that might not be present in the data. * @@ -317,31 +343,102 @@ bool zcbor_multi_decode(uint_fast32_t min_decode, uint_fast32_t max_decode, uint * * @return Should always return true. */ -bool zcbor_present_decode(uint_fast32_t *present, +bool zcbor_present_decode(bool *present, zcbor_decoder_t decoder, zcbor_state_t *state, void *result); -/** See @ref zcbor_new_state() */ -void zcbor_new_decode_state(zcbor_state_t *state_array, uint_fast32_t n_states, - const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); -/** Convenience macro for declaring and initializing a state with backups. +/** Supplementary string (bstr/tstr) decoding functions: */ + +/** Consume and expect a bstr/tstr with the value of the provided char/uint8_t array. * - * This gives you a state variable named @p name. The variable functions like - * a pointer. + * @param[inout] state The current state of the decoding. + * @param[in] str The value to expect. A pointer to the string/array. + * _term() uses strnlen(), so @p str must be null-terminated. + * _lit() uses sizeof()-1, so @p str must be a (null-terminated) string literal. + * _arr() uses sizeof(), so @p str must be a uint8_t array (not null-terminated). + * @param[in] len (if present) The length of the string pointed to by @p str + * @param[in] maxlen (if present) The maximum length of the string pointed to by @p str. + * This value is passed to strnlen. + */ +bool zcbor_bstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len); +bool zcbor_tstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len); +bool zcbor_bstr_expect_term(zcbor_state_t *state, char const *str, size_t maxlen); +bool zcbor_tstr_expect_term(zcbor_state_t *state, char const *str, size_t maxlen); +#define zcbor_bstr_expect_lit(state, str) zcbor_bstr_expect_ptr(state, str, sizeof(str) - 1) +#define zcbor_tstr_expect_lit(state, str) zcbor_tstr_expect_ptr(state, str, sizeof(str) - 1) +#define zcbor_bstr_expect_arr(state, str) zcbor_bstr_expect_ptr(state, str, sizeof(str)) +#define zcbor_tstr_expect_arr(state, str) zcbor_tstr_expect_ptr(state, str, sizeof(str)) + +/** Decode and consume a bstr header. * - * @param[in] name The name of the new state variable. - * @param[in] num_backups The number of backup slots to keep in the state. - * @param[in] payload The payload to work on. - * @param[in] payload_size The size (in bytes) of @p payload. - * @param[in] elem_count The starting elem_count (typically 1). + * The rest of the string can be decoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + * + * @param[inout] state The current state of the decoding. + * @param[out] result The resulting string, for reference. The string should be decoded via + * functions from this API since state is pointing to the start of the string, + * not the end. + * + * @retval true Header decoded correctly + * @retval false Header decoded incorrectly, or backup failed, or payload is not large enough + * to contain the contents of the string. Use @ref zcbor_bstr_start_decode_fragment + * for decoding fragmented payloads. */ -#define ZCBOR_STATE_D(name, num_backups, payload, payload_size, elem_count) \ -zcbor_state_t name[((num_backups) + 2)]; \ -do { \ - zcbor_new_decode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count); \ -} while(0) +bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result); + +/** Finalize decoding a CBOR-encoded bstr. + * + * Restore element count from backup. + */ +bool zcbor_bstr_end_decode(zcbor_state_t *state); + + +/** Supplementary string (bstr/tstr) decoding functions for fragmented payloads: */ + +/** Start decoding a bstr/tstr, even if the payload contains only part of it. + * + * This must be followed by a call to @ref zcbor_update_state, which can be + * followed by a call to @ref zcbor_next_fragment. Do not call this function + * again on subsequent fragments of the same string. + * + * This consumes the remaining payload as long as it belongs to the string. + */ +bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); +bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); + +/** Extract the next fragment of a string. + * + * Use this function to extract all but the first fragment. + */ +void zcbor_next_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *prev_fragment, + struct zcbor_string_fragment *result); + +/** Decode and consume a bstr header, assuming the payload does not contain the whole bstr. + * + * The rest of the string can be decoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_update_state followed by @ref zcbor_bstr_next_fragment when + * the current payload has been exhausted. + * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + */ +bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *result); + +/** Start decoding the next fragment of a string. + * + * Use this function to extract all but the first fragment of a CBOR-encoded + * bstr. + */ +void zcbor_bstr_next_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *prev_fragment, + struct zcbor_string_fragment *result); + +/** Can be used on any fragment to tell if it is the final fragment of the string. */ +bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment); #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_encode.h b/boot/zcbor/include/zcbor_encode.h index 40bcccfe1..89b0a97bf 100644 --- a/boot/zcbor/include/zcbor_encode.h +++ b/boot/zcbor/include/zcbor_encode.h @@ -1,8 +1,3 @@ -/* - * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 - */ - /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -21,6 +16,7 @@ extern "C" { #endif + /** The zcbor_encode library provides functions for encoding CBOR data elements. * * See The README for an introduction to CBOR, including the meaning of pint, @@ -28,130 +24,72 @@ extern "C" { */ -/** The following param and retval docs apply to all single value encoding functions - * - * @param[inout] state The current state of the encoding. - * @param[in] input The value to encode. - * - * @retval true Everything is ok. - * @retval false If the payload is exhausted. Or an unexpected error happened. - */ - -/** Encode a pint/nint. */ -bool zcbor_int32_put(zcbor_state_t *state, int32_t input); -bool zcbor_int64_put(zcbor_state_t *state, int64_t input); -bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input); -bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input); -bool zcbor_size_put(zcbor_state_t *state, size_t input); - -/** Encode a pint/nint from a pointer. - * - * Can be used for bulk encoding with @ref zcbor_multi_encode. - */ -bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_size); -bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input); -bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input); -bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input); -bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input); -bool zcbor_size_encode(zcbor_state_t *state, const size_t *input); - -/** Encode a bstr. */ -bool zcbor_bstr_encode(zcbor_state_t *state, const struct zcbor_string *input); -/** Encode a tstr. */ -bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input); - -/** Encode a pointer to a string as a bstr/tstr. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to encode. A pointer to the string - * @param[in] len The length of the string pointed to by @p string. - */ -static inline bool zcbor_bstr_encode_ptr(zcbor_state_t *state, const char *ptr, size_t len) -{ - const struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; - - return zcbor_bstr_encode(state, &zs); -} -static inline bool zcbor_tstr_encode_ptr(zcbor_state_t *state, const char *ptr, size_t len) -{ - const struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; - - return zcbor_tstr_encode(state, &zs); -} - -/** Encode a string literal as a bstr/tstr. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to encode. A string literal, e.g. "Foo", so - * that sizeof(string) - 1 is the length of the string. - */ -#define zcbor_bstr_put_lit(state, string) \ - zcbor_bstr_encode_ptr(state, string, sizeof(string) - 1) -#define zcbor_tstr_put_lit(state, string) \ - zcbor_tstr_encode_ptr(state, string, sizeof(string) - 1) +/** See @ref zcbor_new_state() */ +void zcbor_new_encode_state(zcbor_state_t *state_array, size_t n_states, + uint8_t *payload, size_t payload_len, size_t elem_count); -/** Encode null-terminated string as a bstr/tstr. +/** Convenience macro for declaring and initializing an encoding state with backups. * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to encode. Must be a null-terminated string, - * so that strlen can be used. - */ -#define zcbor_bstr_put_term(state, string) \ - zcbor_bstr_encode_ptr(state, string, strlen(string)) -#define zcbor_tstr_put_term(state, string) \ - zcbor_tstr_encode_ptr(state, string, strlen(string)) - -/** Encode a char array literal as a bstr/tstr. + * This gives you a state variable named @p name. The variable functions like + * a pointer. * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to encode. An array literal, e.g. {'F', 'o', 'o'}, - * so that sizeof(string) is the length of the string. + * @param[in] name The name of the new state variable. + * @param[in] num_backups The number of backup slots to keep in the state. + * @param[in] payload The payload to work on. + * @param[in] payload_size The size (in bytes) of @p payload. + * @param[in] elem_count The starting elem_count (typically 1). */ -#define zcbor_bstr_put_arr(state, string) \ - zcbor_bstr_encode_ptr(state, string, sizeof(string)) -#define zcbor_tstr_put_arr(state, string) \ - zcbor_tstr_encode_ptr(state, string, sizeof(string)) - -/** Encode a tag. Must be called before encoding the value being tagged. */ -bool zcbor_tag_encode(zcbor_state_t *state, uint32_t input); - -/** Encode a boolean primitive value. */ -bool zcbor_bool_put(zcbor_state_t *state, bool input); -bool zcbor_bool_encode(zcbor_state_t *state, const bool *input); +#define ZCBOR_STATE_E(name, num_backups, payload, payload_size, elem_count) \ +zcbor_state_t name[((num_backups) + 2)]; \ +do { \ + zcbor_new_encode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count); \ +} while(0) -/** Encode a float */ -bool zcbor_float32_put(zcbor_state_t *state, float input); -bool zcbor_float32_encode(zcbor_state_t *state, const float *input); -bool zcbor_float64_put(zcbor_state_t *state, double input); -bool zcbor_float64_encode(zcbor_state_t *state, const double *input); -/** Encode a "nil"/"undefined" primitive value. @p unused should be NULL. +/** The following applies to all _put and _encode functions listed directly below. * - * @param[inout] state The current state of the encoding. - * @param[in] unused Unused parameter to maintain signature parity with - * @ref zcbor_encoder_t. - */ -bool zcbor_nil_put(zcbor_state_t *state, const void *unused); -bool zcbor_undefined_put(zcbor_state_t *state, const void *unused); - -/** Encode a bstr header. + * The difference between _put and _encode is only in the argument type, + * but when a @ref zcbor_encoder_t is needed, such as for @ref zcbor_multi_encode, + * the _encode variant must be used. * - * The rest of the string can be encoded as CBOR. - * A state backup is created to keep track of the element count. - * Call @ref zcbor_bstr_end_encode when done encoding the contents of the bstr. - * - * @param[inout] state The current state of the encoding. - * - * @retval true Header encoded correctly - * @retval false Header encoded incorrectly, or backup failed. - */ -bool zcbor_bstr_start_encode(zcbor_state_t *state); - -/** Finalize encoding a CBOR-encoded bstr. + * @param[inout] state The current state of the encoding. + * @param[in] input The value to encode. * - * Restore element count from backup. - */ -bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); + * @retval true Everything is ok. + * @retval false If the payload is exhausted. Or an unexpected error happened. + * Use zcbor_peek_error() to see the error code. + */ +bool zcbor_int32_put(zcbor_state_t *state, int32_t input); /* pint/nint */ +bool zcbor_int64_put(zcbor_state_t *state, int64_t input); /* pint/nint */ +bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input); /* pint */ +bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input); /* pint */ +bool zcbor_size_put(zcbor_state_t *state, size_t input); /* pint */ +bool zcbor_tag_put(zcbor_state_t *state, uint32_t tag); /* CBOR tag */ +bool zcbor_simple_put(zcbor_state_t *state, uint8_t input); /* CBOR simple value */ +bool zcbor_bool_put(zcbor_state_t *state, bool input); /* boolean CBOR simple value */ +bool zcbor_nil_put(zcbor_state_t *state, const void *unused); /* 'nil' CBOR simple value */ +bool zcbor_undefined_put(zcbor_state_t *state, const void *unused); /* 'undefined' CBOR simple value */ +bool zcbor_float16_put(zcbor_state_t *state, float input); /* IEEE754 float16 */ +bool zcbor_float16_bytes_put(zcbor_state_t *state, uint16_t input); /* IEEE754 float16 raw bytes */ +bool zcbor_float32_put(zcbor_state_t *state, float input); /* IEEE754 float32 */ +bool zcbor_float64_put(zcbor_state_t *state, double input); /* IEEE754 float64 */ + +bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input); /* pint/nint */ +bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input); /* pint/nint */ +bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input); /* pint */ +bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input); /* pint */ +bool zcbor_size_encode(zcbor_state_t *state, const size_t *input); /* pint */ +bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_size); +bool zcbor_uint_encode(zcbor_state_t *state, const void *input_uint, size_t uint_size); +bool zcbor_bstr_encode(zcbor_state_t *state, const struct zcbor_string *input); /* bstr */ +bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input); /* tstr */ +bool zcbor_tag_encode(zcbor_state_t *state, uint32_t *tag); /* CBOR tag. Note that zcbor_tag_encode()'s argument was changed to be a pointer. See also zcbor_tag_put(). */ +bool zcbor_simple_encode(zcbor_state_t *state, uint8_t *input); /* CBOR simple value */ +bool zcbor_bool_encode(zcbor_state_t *state, const bool *input); /* boolean CBOR simple value */ +bool zcbor_float16_encode(zcbor_state_t *state, const float *input); /* IEEE754 float16 */ +bool zcbor_float16_bytes_encode(zcbor_state_t *state, const uint16_t *input); /* IEEE754 float16 raw bytes */ +bool zcbor_float32_encode(zcbor_state_t *state, const float *input); /* IEEE754 float32 */ +bool zcbor_float64_encode(zcbor_state_t *state, const double *input); /* IEEE754 float64 */ /** Encode a list/map header. * @@ -169,8 +107,8 @@ bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); * call. * Only used when ZCBOR_CANONICAL is defined. */ -bool zcbor_list_start_encode(zcbor_state_t *state, uint_fast32_t max_num); -bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num); +bool zcbor_list_start_encode(zcbor_state_t *state, size_t max_num); +bool zcbor_map_start_encode(zcbor_state_t *state, size_t max_num); /** Encode the end of a list/map. Do some checks and deallocate backup. * @@ -189,8 +127,8 @@ bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num); * @ref zcbor_list_start_encode call. * Only used when ZCBOR_CANONICAL is defined. */ -bool zcbor_list_end_encode(zcbor_state_t *state, uint_fast32_t max_num); -bool zcbor_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num); +bool zcbor_list_end_encode(zcbor_state_t *state, size_t max_num); +bool zcbor_map_end_encode(zcbor_state_t *state, size_t max_num); bool zcbor_list_map_end_force_encode(zcbor_state_t *state); /** Encode 0 or more elements with the same type and constraints. @@ -241,49 +179,59 @@ bool zcbor_list_map_end_force_encode(zcbor_state_t *state); * @retval false If @p encoder failed before having encoded @p min_encode * values. */ -bool zcbor_multi_encode(uint_fast32_t num_encode, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input, - uint_fast32_t result_len); +bool zcbor_multi_encode(size_t num_encode, zcbor_encoder_t encoder, + zcbor_state_t *state, const void *input, size_t result_len); /** Works like @ref zcbor_multi_encode * * But first checks that @p num_encode is between @p min_encode and @p max_encode. */ -bool zcbor_multi_encode_minmax(uint_fast32_t min_encode, uint_fast32_t max_encode, const uint_fast32_t *num_encode, - zcbor_encoder_t encoder, zcbor_state_t *state, const void *input, - uint_fast32_t input_len); +bool zcbor_multi_encode_minmax(size_t min_encode, size_t max_encode, + const size_t *num_encode, zcbor_encoder_t encoder, + zcbor_state_t *state, const void *input, size_t input_len); -/** Runs @p encoder on @p state and @p input if @p present is true. - * - * Calls @ref zcbor_multi_encode under the hood. - */ -bool zcbor_present_encode(const uint_fast32_t *present, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input); -/** See @ref zcbor_new_state() */ -void zcbor_new_encode_state(zcbor_state_t *state_array, uint_fast32_t n_states, - uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); +/* Supplementary string (bstr/tstr) encoding functions: */ -/** Convenience macro for declaring and initializing a state with backups. +/** Encode a char/uint8_t pointer as a bstr/tstr. * - * This gives you a state variable named @p name. The variable functions like - * a pointer. + * @param[inout] state The current state of the encoding. + * @param[in] str The value to encode. A pointer to the string/array. + * _term() uses strnlen(), so @p str must be null-terminated. + * _lit() uses sizeof()-1, so @p str must be a (null-terminated) string literal. + * _arr() uses sizeof(), so @p str must be a uint8_t array (not null-terminated). + * @param[in] len (if present) The length of the string pointed to by @p str + * @param[in] maxlen (if present) The maximum length of the string pointed to by @p str. + * This value is passed to strnlen. + */ +bool zcbor_bstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len); +bool zcbor_tstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len); +bool zcbor_bstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen); +bool zcbor_tstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen); +#define zcbor_bstr_put_lit(state, str) zcbor_bstr_encode_ptr(state, str, sizeof(str) - 1) +#define zcbor_tstr_put_lit(state, str) zcbor_tstr_encode_ptr(state, str, sizeof(str) - 1) +#define zcbor_bstr_put_arr(state, str) zcbor_bstr_encode_ptr(state, str, sizeof(str)) +#define zcbor_tstr_put_arr(state, str) zcbor_tstr_encode_ptr(state, str, sizeof(str)) + +/** Encode a bstr header. * - * @param[in] name The name of the new state variable. - * @param[in] num_backups The number of backup slots to keep in the state. - * @param[in] payload The payload to work on. - * @param[in] payload_size The size (in bytes) of @p payload. - * @param[in] elem_count The starting elem_count (typically 1). + * The rest of the string can be encoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_bstr_end_encode when done encoding the contents of the bstr. + * + * @param[inout] state The current state of the encoding. + * + * @retval true Header encoded correctly + * @retval false Header encoded incorrectly, or backup failed. */ -#define ZCBOR_STATE_E(name, num_backups, payload, payload_size, elem_count) \ -zcbor_state_t name[((num_backups) + 2)]; \ -do { \ - zcbor_new_encode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count); \ -} while(0) +bool zcbor_bstr_start_encode(zcbor_state_t *state); + +/** Finalize encoding a CBOR-encoded bstr. + * + * This writes the final size of the bstr to the header. + * Restore element count from backup. + */ +bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_print.h b/boot/zcbor/include/zcbor_print.h new file mode 100644 index 000000000..18f8656c5 --- /dev/null +++ b/boot/zcbor/include/zcbor_print.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZCBOR_PRINT_H__ +#define ZCBOR_PRINT_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ZCBOR_PRINT_FUNC +#include +#define zcbor_do_print(...) printf(__VA_ARGS__) +#else +#define zcbor_do_print(...) ZCBOR_PRINT_FUNC(__VA_ARGS__) +#endif + +#ifdef ZCBOR_VERBOSE +#define zcbor_trace_raw(state) (zcbor_do_print("rem: %zu, cur: 0x%x, ec: 0x%zx, err: %d",\ + (size_t)state->payload_end - (size_t)state->payload, *state->payload, state->elem_count, \ + state->constant_state ? state->constant_state->error : 0)) +#define zcbor_trace(state, appendix) do { \ + zcbor_trace_raw(state); \ + zcbor_do_print(", %s\n", appendix); \ +} while(0) +#define zcbor_trace_file(state) do { \ + zcbor_trace_raw(state); \ + zcbor_do_print(", %s:%d\n", __FILE__, __LINE__); \ +} while(0) + +#define zcbor_log_assert(expr, ...) \ +do { \ + zcbor_do_print("ASSERTION \n \"" #expr \ + "\"\nfailed at %s:%d with message:\n ", \ + __FILE__, __LINE__); \ + zcbor_do_print(__VA_ARGS__);\ +} while(0) +#define zcbor_log(...) zcbor_do_print(__VA_ARGS__) +#else +#define zcbor_trace(state, appendix) +#define zcbor_trace_file(state) ((void)state) +#define zcbor_log_assert(...) +#define zcbor_log(...) +#endif + +#ifdef ZCBOR_ASSERTS +#define zcbor_assert(expr, ...) \ +do { \ + if (!(expr)) { \ + zcbor_log_assert(expr, __VA_ARGS__); \ + ZCBOR_FAIL(); \ + } \ +} while(0) +#define zcbor_assert_state(expr, ...) \ +do { \ + if (!(expr)) { \ + zcbor_log_assert(expr, __VA_ARGS__); \ + ZCBOR_ERR(ZCBOR_ERR_ASSERTION); \ + } \ +} while(0) +#else +#define zcbor_assert(expr, ...) +#define zcbor_assert_state(expr, ...) +#endif + +__attribute__((used)) +static void zcbor_print_compare_lines(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + for (uint32_t j = 0; j < size; j++) { + zcbor_do_print("%x ", str1[j]); + } + zcbor_do_print("\r\n"); + for (uint32_t j = 0; j < size; j++) { + zcbor_do_print("%x ", str2[j]); + } + zcbor_do_print("\r\n"); + for (uint32_t j = 0; j < size; j++) { + zcbor_do_print("%x ", str1[j] != str2[j]); + } + zcbor_do_print("\r\n"); + zcbor_do_print("\r\n"); +} + +__attribute__((used)) +static void zcbor_print_compare_strings(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + for (uint32_t i = 0; i <= size / 16; i++) { + zcbor_do_print("line %d (char %d)\r\n", i, i*16); + zcbor_print_compare_lines(&str1[i*16], &str2[i*16], + MIN(16, (size - i*16))); + } + zcbor_do_print("\r\n"); +} + +__attribute__((used)) +static void zcbor_print_compare_strings_diff(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + bool printed = false; + for (uint32_t i = 0; i <= size / 16; i++) { + if (memcmp(&str1[i*16], &str2[i*16], MIN(16, (size - i*16))) != 0) { + zcbor_do_print("line %d (char %d)\r\n", i, i*16); + zcbor_print_compare_lines(&str1[i*16], &str2[i*16], + MIN(16, (size - i*16))); + printed = true; + } + } + if (printed) { + zcbor_do_print("\r\n"); + } +} + +__attribute__((used)) +static const char *zcbor_error_str(int error) +{ + #define ZCBOR_ERR_CASE(err) case err: \ + return #err; /* The literal is static per C99 6.4.5 paragraph 5. */\ + + switch(error) { + ZCBOR_ERR_CASE(ZCBOR_SUCCESS) + ZCBOR_ERR_CASE(ZCBOR_ERR_NO_BACKUP_MEM) + ZCBOR_ERR_CASE(ZCBOR_ERR_NO_BACKUP_ACTIVE) + ZCBOR_ERR_CASE(ZCBOR_ERR_LOW_ELEM_COUNT) + ZCBOR_ERR_CASE(ZCBOR_ERR_HIGH_ELEM_COUNT) + ZCBOR_ERR_CASE(ZCBOR_ERR_INT_SIZE) + ZCBOR_ERR_CASE(ZCBOR_ERR_FLOAT_SIZE) + ZCBOR_ERR_CASE(ZCBOR_ERR_ADDITIONAL_INVAL) + ZCBOR_ERR_CASE(ZCBOR_ERR_NO_PAYLOAD) + ZCBOR_ERR_CASE(ZCBOR_ERR_PAYLOAD_NOT_CONSUMED) + ZCBOR_ERR_CASE(ZCBOR_ERR_WRONG_TYPE) + ZCBOR_ERR_CASE(ZCBOR_ERR_WRONG_VALUE) + ZCBOR_ERR_CASE(ZCBOR_ERR_WRONG_RANGE) + ZCBOR_ERR_CASE(ZCBOR_ERR_ITERATIONS) + ZCBOR_ERR_CASE(ZCBOR_ERR_ASSERTION) + ZCBOR_ERR_CASE(ZCBOR_ERR_PAYLOAD_OUTDATED) + ZCBOR_ERR_CASE(ZCBOR_ERR_ELEM_NOT_FOUND) + ZCBOR_ERR_CASE(ZCBOR_ERR_MAP_MISALIGNED) + ZCBOR_ERR_CASE(ZCBOR_ERR_ELEMS_NOT_PROCESSED) + ZCBOR_ERR_CASE(ZCBOR_ERR_NOT_AT_END) + ZCBOR_ERR_CASE(ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE) + ZCBOR_ERR_CASE(ZCBOR_ERR_INVALID_VALUE_ENCODING) + } + #undef ZCBOR_ERR_CASE + + return "ZCBOR_ERR_UNKNOWN"; +} + +__attribute__((used)) +static void zcbor_print_error(int error) +{ + zcbor_do_print("%s\r\n", zcbor_error_str(error)); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZCBOR_PRINT_H__ */ diff --git a/boot/zcbor/include/zcbor_tags.h b/boot/zcbor/include/zcbor_tags.h new file mode 100644 index 000000000..89148776c --- /dev/null +++ b/boot/zcbor/include/zcbor_tags.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZCBOR_TAGS_H__ +#define ZCBOR_TAGS_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Values defined by RFCs via www.iana.org/assignments/cbor-tags/cbor-tags.xhtml */ +enum zcbor_tag { + ZCBOR_TAG_TIME_TSTR = 0, ///! text string [RFC8949] Standard date/time string + ZCBOR_TAG_TIME_NUM = 1, ///! integer or float [RFC8949] Epoch-based date/time + ZCBOR_TAG_UBIGNUM_BSTR = 2, ///! byte string [RFC8949] Unsigned bignum + ZCBOR_TAG_BIGNUM_BSTR = 3, ///! byte string [RFC8949] Negative bignum + ZCBOR_TAG_DECFRAC_ARR = 4, ///! array [RFC8949] Decimal fraction + ZCBOR_TAG_BIGFLOAT_ARR = 5, ///! array [RFC8949] Bigfloat + ZCBOR_TAG_COSE_ENCRYPT0 = 16, ///! COSE_Encrypt0 [RFC9052] COSE Single Recipient Encrypted Data Object + ZCBOR_TAG_COSE_MAC0 = 17, ///! COSE_Mac0 [RFC9052] COSE MAC w/o Recipients Object + ZCBOR_TAG_COSE_SIGN1 = 18, ///! COSE_Sign1 [RFC9052] COSE Single Signer Data Object + ZCBOR_TAG_2BASE64URL = 21, ///! (any) [RFC8949] Expected conversion to base64url encoding + ZCBOR_TAG_2BASE64 = 22, ///! (any) [RFC8949] Expected conversion to base64 encoding + ZCBOR_TAG_2BASE16 = 23, ///! (any) [RFC8949] Expected conversion to base16 encoding + ZCBOR_TAG_BSTR = 24, ///! byte string [RFC8949] Encoded CBOR data item + ZCBOR_TAG_URI_TSTR = 32, ///! text string [RFC8949] URI + ZCBOR_TAG_BASE64URL_TSTR = 33, ///! text string [RFC8949] base64url + ZCBOR_TAG_BASE64_TSTR = 34, ///! text string [RFC8949] base64 + ZCBOR_TAG_REGEX = 35, ///! text string [RFC7049] Regular expression (UTF-8) + ZCBOR_TAG_MIME_TSTR = 36, ///! text string [RFC8949] MIME message + ZCBOR_TAG_LANG_TSTR = 38, ///! array [RFC9290] Text string with language tag + ZCBOR_TAG_MULTI_DIM_ARR_R = 40, ///! array of arrays [RFC8746] Multi-dimensional array, row-major order + ZCBOR_TAG_HOMOG_ARR = 41, ///! array [RFC8746] Homogeneous array + ZCBOR_TAG_YANG_BITS = 42, ///! text string [RFC9254] YANG bits datatype; see Section 6.7. + ZCBOR_TAG_YANG_ENUM = 43, ///! text string [RFC9254] YANG enumeration datatype; see Section 6.6. + ZCBOR_TAG_YANG_IDENTITYREF = 44, ///! uint/tstr [RFC9254] YANG identityref datatype; see Section 6.10. + ZCBOR_TAG_YANK_INSTANCE_ID = 45, ///! uint/tstr/array [RFC9254] YANG instance-identifier datatype; see Section 6.13. + ZCBOR_TAG_SID = 46, ///! uint [RFC9254] YANG Schema Item iDentifier (sid); see Section 3.2. + ZCBOR_TAG_IPV4 = 52, ///! bstr or array [RFC9164] IPv4 + ZCBOR_TAG_IPV6 = 54, ///! bstr or array [RFC9164] IPv6 + ZCBOR_TAG_CWT = 61, ///! CWT [RFC8392] CBOR Web Token + ZCBOR_TAG_TYPED_ARR_U8 = 64, ///! byte string [RFC8746] uint8 Typed Array + ZCBOR_TAG_TYPED_ARR_U16_BE = 65, ///! byte string [RFC8746] uint16, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U32_BE = 66, ///! byte string [RFC8746] uint32, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U64_BE = 67, ///! byte string [RFC8746] uint64, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U8_CA = 68, ///! byte string [RFC8746] uint8 Typed Array, clamped arithmetic + ZCBOR_TAG_TYPED_ARR_U16_LE = 69, ///! byte string [RFC8746] uint16, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U32_LE = 70, ///! byte string [RFC8746] uint32, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U64_LE = 71, ///! byte string [RFC8746] uint64, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S8 = 72, ///! byte string [RFC8746] sint8 Typed Array + ZCBOR_TAG_TYPED_ARR_S16_BE = 73, ///! byte string [RFC8746] sint16, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S32_BE = 74, ///! byte string [RFC8746] sint32, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S64_BE = 75, ///! byte string [RFC8746] sint64, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S16_LE = 77, ///! byte string [RFC8746] sint16, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S32_LE = 78, ///! byte string [RFC8746] sint32, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S64_LE = 79, ///! byte string [RFC8746] sint64, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F16_BE = 80, ///! byte string [RFC8746] IEEE 754 binary16, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F32_BE = 81, ///! byte string [RFC8746] IEEE 754 binary32, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F64_BE = 82, ///! byte string [RFC8746] IEEE 754 binary64, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F128_BE = 83, ///! byte string [RFC8746] IEEE 754 binary128, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F16_LE = 84, ///! byte string [RFC8746] IEEE 754 binary16, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F32_LE = 85, ///! byte string [RFC8746] IEEE 754 binary32, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F64_LE = 86, ///! byte string [RFC8746] IEEE 754 binary64, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F128_LE = 87, ///! byte string [RFC8746] IEEE 754 binary128, little endian, Typed Array + ZCBOR_TAG_COSE_ENCRYPT = 96, ///! COSE_Encrypt [RFC9052] COSE Encrypted Data Object + ZCBOR_TAG_COSE_MAC = 97, ///! COSE_Mac [RFC9052] COSE MACed Data Object + ZCBOR_TAG_COSE_SIGN = 98, ///! COSE_Sign [RFC9052] COSE Signed Data Object + ZCBOR_TAG_EPOCH_DAYS = 100, ///! integer [RFC8943] Number of days since the epoch date 1970-01-01 + ZCBOR_TAG_REL_OID_BER_SDNV = 110, ///! bstr/array/map [RFC9090] relative object identifier (BER encoding); SDNV [RFC6256] sequence + ZCBOR_TAG_OID_BER = 111, ///! bstr/array/map [RFC9090] object identifier (BER encoding) + ZCBOR_TAG_PEN_REL_OID_BER = 112, ///! bstr/array/map [RFC9090] object identifier (BER encoding), relative to 1.3.6.1.4.1 + ZCBOR_TAG_DOTS_SIG_CHAN_OBJ = 271, ///! DOTS sig chan obj [RFC9132] DDoS Open Threat Signaling (DOTS) signal channel object + ZCBOR_TAG_FULL_DATE_STR = 1004, ///! tstr (UTF-8) [RFC8943] Full-date string + ZCBOR_TAG_MULTI_DIM_ARR_C = 1040, ///! array of arrays [RFC8746] Multi-dimensional array, column-major order + ZCBOR_TAG_CBOR = 55799, ///! (any) [RFC8949] Self-described CBOR + ZCBOR_TAG_CBOR_SEQ_FILE = 55800, ///! tagged bstr [RFC9277] indicates that the file contains CBOR Sequences + ZCBOR_TAG_CBOR_FILE_LABEL = 55801, ///! tagged bstr [RFC9277] indicates that the file starts with a CBOR-Labeled Non-CBOR Data label. + ZCBOR_TAG_COAP_CT = 1668546817, ///! bstr or (any) [RFC9277] Start of range: the representation of content-format ct < 65025 is indicated by tag number TN(ct) = 0x63740101 + (ct / 255) * 256 + ct % 255 + ZCBOR_TAG_COAP_CT_END = 1668612095, ///! bstr or (any) [RFC9277] End of range: the representation of content-format ct < 65025 is indicated by tag number TN(ct) = 0x63740101 + (ct / 255) * 256 + ct % 255 +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* ZCBOR_TAGS_H__ */ diff --git a/boot/zcbor/src/zcbor_common.c b/boot/zcbor/src/zcbor_common.c index e7a5e3aee..1caf80668 100644 --- a/boot/zcbor/src/zcbor_common.c +++ b/boot/zcbor/src/zcbor_common.c @@ -1,8 +1,3 @@ -/* - * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 - */ - /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -14,6 +9,7 @@ #include #include #include "zcbor_common.h" +#include "zcbor_print.h" _Static_assert((sizeof(size_t) == sizeof(void *)), "This code needs size_t to be the same length as pointers."); @@ -21,7 +17,7 @@ _Static_assert((sizeof(size_t) == sizeof(void *)), _Static_assert((sizeof(zcbor_state_t) >= sizeof(struct zcbor_state_constant)), "This code needs zcbor_state_t to be at least as large as zcbor_backups_t."); -bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count) +bool zcbor_new_backup(zcbor_state_t *state, size_t new_elem_count) { ZCBOR_CHECK_ERROR(); @@ -36,39 +32,41 @@ bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count) /* use the backup at current_backup - 1, since otherwise, the 0th * backup would be unused. */ - uint_fast32_t i = (state->constant_state->current_backup) - 1; + size_t i = (state->constant_state->current_backup) - 1; memcpy(&state->constant_state->backup_list[i], state, sizeof(zcbor_state_t)); state->elem_count = new_elem_count; + zcbor_log("New backup (level %zu)\n", i); + return true; } bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, - uint_fast32_t max_elem_count) + size_t max_elem_count) { - const uint8_t *payload = state->payload; - const uint_fast32_t elem_count = state->elem_count; - ZCBOR_CHECK_ERROR(); + zcbor_state_t local_copy = *state; if (state->constant_state->current_backup == 0) { - zcbor_print("No backups available.\r\n"); + zcbor_log("No backups available.\r\n"); ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_ACTIVE); } - if (flags & ZCBOR_FLAG_RESTORE) { - /* use the backup at current_backup - 1, since otherwise, the - * 0th backup would be unused. */ - uint_fast32_t i = state->constant_state->current_backup - 1; + /* use the backup at current_backup - 1, since otherwise, the + * 0th backup would be unused. */ + size_t i = state->constant_state->current_backup - 1; - if (!(flags & ZCBOR_FLAG_TRANSFER_PAYLOAD)) { + zcbor_log("Process backup (level %zu, flags 0x%x)\n", i, flags); + + if (flags & ZCBOR_FLAG_RESTORE) { + if (!(flags & ZCBOR_FLAG_KEEP_PAYLOAD)) { if (state->constant_state->backup_list[i].payload_moved) { - zcbor_print("Payload pointer out of date.\r\n"); - ZCBOR_FAIL(); + zcbor_log("Payload pointer out of date.\r\n"); + ZCBOR_ERR(ZCBOR_ERR_PAYLOAD_OUTDATED); } } memcpy(state, &state->constant_state->backup_list[i], @@ -79,14 +77,19 @@ bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, state->constant_state->current_backup--; } - if (elem_count > max_elem_count) { - zcbor_print("elem_count: %" PRIuFAST32 " (expected max %" PRIuFAST32 ")\r\n", - elem_count, max_elem_count); + if (local_copy.elem_count > max_elem_count) { + zcbor_log("elem_count: %zu (expected max %zu)\r\n", + local_copy.elem_count, max_elem_count); ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT); } - if (flags & ZCBOR_FLAG_TRANSFER_PAYLOAD) { - state->payload = payload; + if (flags & ZCBOR_FLAG_KEEP_PAYLOAD) { + state->payload = local_copy.payload; + } + + if (flags & ZCBOR_FLAG_KEEP_DECODE_STATE) { + /* Copy decode state */ + state->decode_state = local_copy.decode_state; } return true; @@ -95,7 +98,7 @@ bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, static void update_backups(zcbor_state_t *state, uint8_t const *new_payload_end) { if (state->constant_state) { - for (int i = 0; i < state->constant_state->current_backup; i++) { + for (unsigned int i = 0; i < state->constant_state->current_backup; i++) { state->constant_state->backup_list[i].payload_end = new_payload_end; state->constant_state->backup_list[i].payload_moved = true; } @@ -128,17 +131,26 @@ bool zcbor_union_end_code(zcbor_state_t *state) return true; } -void zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states, - const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +void zcbor_new_state(zcbor_state_t *state_array, size_t n_states, + const uint8_t *payload, size_t payload_len, size_t elem_count, + uint8_t *flags, size_t flags_bytes) { state_array[0].payload = payload; state_array[0].payload_end = payload + payload_len; state_array[0].elem_count = elem_count; - state_array[0].indefinite_length_array = false; state_array[0].payload_moved = false; + state_array[0].decode_state.indefinite_length_array = false; +#ifdef ZCBOR_MAP_SMART_SEARCH + state_array[0].decode_state.map_search_elem_state = flags; + state_array[0].decode_state.map_elem_count = 0; +#else + state_array[0].decode_state.map_elems_processed = 0; + (void)flags; + (void)flags_bytes; +#endif state_array[0].constant_state = NULL; - if(n_states < 2) { + if (n_states < 2) { return; } @@ -150,6 +162,10 @@ void zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states, state_array[0].constant_state->error = ZCBOR_SUCCESS; #ifdef ZCBOR_STOP_ON_ERROR state_array[0].constant_state->stop_on_error = false; +#endif + state_array[0].constant_state->manually_process_elem = false; +#ifdef ZCBOR_MAP_SMART_SEARCH + state_array[0].constant_state->map_search_elem_state_end = flags + flags_bytes; #endif if (n_states > 2) { state_array[0].constant_state->backup_list = &state_array[1]; @@ -167,7 +183,7 @@ void zcbor_update_state(zcbor_state_t *state, bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, - uint_fast32_t num_fragments) + size_t num_fragments) { size_t total_len = 0; @@ -175,7 +191,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, return false; } - for (uint_fast32_t i = 0; i < num_fragments; i++) { + for (size_t i = 0; i < num_fragments; i++) { if (fragments[i].offset != total_len) { return false; } @@ -196,7 +212,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, } if (num_fragments && (fragments[0].total_len == ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH)) { - for (uint_fast32_t i = 0; i < num_fragments; i++) { + for (size_t i = 0; i < num_fragments; i++) { fragments[i].total_len = total_len; } } @@ -205,7 +221,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, } bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, - uint_fast32_t num_fragments, uint8_t *result, size_t *result_len) + size_t num_fragments, uint8_t *result, size_t *result_len) { size_t total_len = 0; @@ -213,7 +229,7 @@ bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, return false; } - for (uint_fast32_t i = 0; i < num_fragments; i++) { + for (size_t i = 0; i < num_fragments; i++) { if ((total_len > *result_len) || (fragments[i].fragment.len > (*result_len - total_len))) { return false; @@ -226,3 +242,189 @@ bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, *result_len = total_len; return true; } + + +bool zcbor_compare_strings(const struct zcbor_string *str1, + const struct zcbor_string *str2) +{ + return (str1 != NULL) && (str2 != NULL) + && (str1->value != NULL) && (str2->value != NULL) && (str1->len == str2->len) + && (memcmp(str1->value, str2->value, str1->len) == 0); +} + + +size_t zcbor_header_len(uint64_t value) +{ + if (value <= ZCBOR_VALUE_IN_HEADER) { + return 1; + } else if (value <= 0xFF) { + return 2; + } else if (value <= 0xFFFF) { + return 3; + } else if (value <= 0xFFFFFFFF) { + return 5; + } else { + return 9; + } +} + + +size_t zcbor_header_len_ptr(const void *const value, size_t value_len) +{ + uint64_t val64 = 0; + + if (value_len > sizeof(val64)) { + return 0; + } + + memcpy(((uint8_t*)&val64) + ZCBOR_ECPY_OFFS(sizeof(val64), value_len), value, value_len); + return zcbor_header_len(val64); +} + + +int zcbor_entry_function(const uint8_t *payload, size_t payload_len, + void *result, size_t *payload_len_out, zcbor_state_t *state, zcbor_decoder_t func, + size_t n_states, size_t elem_count) +{ + zcbor_new_state(state, n_states, payload, payload_len, elem_count, NULL, 0); + + bool ret = func(state, result); + + if (!ret) { + int err = zcbor_pop_error(state); + + err = (err == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : err; + return err; + } + + if (payload_len_out != NULL) { + *payload_len_out = MIN(payload_len, + (size_t)state[0].payload - (size_t)payload); + } + return ZCBOR_SUCCESS; +} + + +/* Float16: */ +#define F16_SIGN_OFFS 15 /* Bit offset of the sign bit. */ +#define F16_EXPO_OFFS 10 /* Bit offset of the exponent. */ +#define F16_EXPO_MSK 0x1F /* Bitmask for the exponent (right shifted by F16_EXPO_OFFS). */ +#define F16_MANTISSA_MSK 0x3FF /* Bitmask for the mantissa. */ +#define F16_MAX 65520 /* Lowest float32 value that rounds up to float16 infinity. + * (65519.996 rounds to 65504) */ +#define F16_MIN_EXPO 24 /* Negative exponent of the non-zero float16 value closest to 0 (2^-24) */ +#define F16_MIN (1.0f / (1 << F16_MIN_EXPO)) /* The non-zero float16 value closest to 0 (2^-24) */ +#define F16_MIN_NORM (1.0f / (1 << 14)) /* The normalized float16 value closest to 0 (2^-14) */ +#define F16_BIAS 15 /* The exponent bias of normalized float16 values. */ + +/* Float32: */ +#define F32_SIGN_OFFS 31 /* Bit offset of the sign bit. */ +#define F32_EXPO_OFFS 23 /* Bit offset of the exponent. */ +#define F32_EXPO_MSK 0xFF /* Bitmask for the exponent (right shifted by F32_EXPO_OFFS). */ +#define F32_MANTISSA_MSK 0x7FFFFF /* Bitmask for the mantissa. */ +#define F32_BIAS 127 /* The exponent bias of normalized float32 values. */ + +/* Rounding: */ +#define SUBNORM_ROUND_MSK (F32_MANTISSA_MSK | (1 << F32_EXPO_OFFS)) /* mantissa + lsb of expo for + * tiebreak. */ +#define SUBNORM_ROUND_BIT_MSK (1 << (F32_EXPO_OFFS - 1)) /* msb of mantissa (0x400000) */ +#define NORM_ROUND_MSK (F32_MANTISSA_MSK >> (F16_EXPO_OFFS - 1)) /* excess mantissa when going from + * float32 to float16 + 1 extra bit + * for tiebreak. */ +#define NORM_ROUND_BIT_MSK (1 << (F32_EXPO_OFFS - F16_EXPO_OFFS - 1)) /* bit 12 (0x1000) */ + + +float zcbor_float16_to_32(uint16_t input) +{ + uint32_t sign = input >> F16_SIGN_OFFS; + uint32_t expo = (input >> F16_EXPO_OFFS) & F16_EXPO_MSK; + uint32_t mantissa = input & F16_MANTISSA_MSK; + + if ((expo == 0) && (mantissa != 0)) { + /* Subnormal float16 - convert to normalized float32 */ + return ((float)mantissa * F16_MIN) * (sign ? -1 : 1); + } else { + /* Normalized / zero / Infinity / NaN */ + uint32_t new_expo = (expo == 0 /* zero */) ? 0 + : (expo == F16_EXPO_MSK /* inf/NaN */) ? F32_EXPO_MSK + : (expo + (F32_BIAS - F16_BIAS)); + uint32_t value32 = (sign << F32_SIGN_OFFS) | (new_expo << F32_EXPO_OFFS) + | (mantissa << (F32_EXPO_OFFS - F16_EXPO_OFFS)); + return *(float *)&value32; + } +} + + +uint16_t zcbor_float32_to_16(float input) +{ + uint32_t value32 = *(uint32_t *)&input; + + uint32_t sign = value32 >> F32_SIGN_OFFS; + uint32_t expo = (value32 >> F32_EXPO_OFFS) & F32_EXPO_MSK; + uint32_t mantissa = value32 & F32_MANTISSA_MSK; + + uint16_t value16 = (uint16_t)(sign << F16_SIGN_OFFS); + + float abs_input; + *(uint32_t *)&abs_input = value32 & ~(1 << F32_SIGN_OFFS); + + if (abs_input <= (F16_MIN / 2)) { + /* 0 or too small for float16. Round down to 0. value16 is already correct. */ + } else if (abs_input < F16_MIN) { + /* Round up to 2^(-24) (F16_MIN), has other rounding rules than larger values. */ + value16 |= 0x0001; + } else if (abs_input < F16_MIN_NORM) { + /* Subnormal float16 (normal float32) */ + uint32_t adjusted_mantissa = + /* Adjust for the purposes of checking rounding. */ + /* The lsb of expo is needed for the cases where expo is 103 (minimum). */ + ((value32 << (expo - (F32_BIAS - F16_MIN_EXPO))) & SUBNORM_ROUND_MSK); + uint16_t rounding_bit = + /* "Round to nearest, ties to even". */ + /* 0x400000 means ties go down towards even. (0xC00000 means ties go up.) */ + (adjusted_mantissa & SUBNORM_ROUND_BIT_MSK) + && (adjusted_mantissa != SUBNORM_ROUND_BIT_MSK); + value16 |= ((uint16_t)(abs_input * (1 << 24)) + rounding_bit); /* expo is 0 */ + } else if (abs_input < F16_MAX) { + /* Normal float16 (normal float32) */ + uint16_t rounding_bit = + /* Bit 13 of the mantissa represents which way to round, except for the */ + /* special case where bits 0-12 and 14 are 0. */ + /* This is because of "Round to nearest, ties to even". */ + /* 0x1000 means ties go down towards even. (0x3000 means ties go up.) */ + ((mantissa & NORM_ROUND_BIT_MSK) + && ((mantissa & NORM_ROUND_MSK) != NORM_ROUND_BIT_MSK)); + value16 |= (uint16_t)((expo - (F32_BIAS - F16_BIAS)) << F16_EXPO_OFFS); + value16 |= (uint16_t)(mantissa >> (F32_EXPO_OFFS - F16_EXPO_OFFS)); + value16 += rounding_bit; /* Might propagate to exponent. */ + } else if (expo != F32_EXPO_MSK || !mantissa) { + /* Infinite, or finite normal float32 too large for float16. Round up to inf. */ + value16 |= (F16_EXPO_MSK << F16_EXPO_OFFS); + } else { + /* NaN */ + /* Preserve msbit of mantissa. */ + uint16_t new_mantissa = (uint16_t)(mantissa >> (F32_EXPO_OFFS - F16_EXPO_OFFS)); + value16 |= (F16_EXPO_MSK << F16_EXPO_OFFS) | (new_mantissa ? new_mantissa : 1); + } + + return value16; +} + + +/** Weak strnlen() implementation in case it is not available. + * + * This function is in the public domain, according to: + * https://github.com/arm-embedded/gcc-arm-none-eabi.debian/blob/master/src/libiberty/strnlen.c + */ +__attribute__((__weak__)) +size_t strnlen (const char *s, size_t maxlen) +{ + size_t i; + + for (i = 0; i < maxlen; ++i) { + if (s[i] == '\0') { + break; + } + } + return i; +} diff --git a/boot/zcbor/src/zcbor_decode.c b/boot/zcbor/src/zcbor_decode.c index c99fc8385..92f9fe517 100644 --- a/boot/zcbor/src/zcbor_decode.c +++ b/boot/zcbor/src/zcbor_decode.c @@ -1,8 +1,3 @@ -/* - * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 - */ - /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -13,15 +8,19 @@ #include #include #include -#include -#include +#include +#include "zcbor_decode.h" +#include "zcbor_common.h" +#include "zcbor_print.h" /** Return value length from additional value. */ -static uint_fast32_t additional_len(uint8_t additional) +static size_t additional_len(uint8_t additional) { - if (ZCBOR_VALUE_IS_1_BYTE <= additional && additional <= ZCBOR_VALUE_IS_8_BYTES) { + if (additional <= ZCBOR_VALUE_IN_HEADER) { + return 0; + } else if (ZCBOR_VALUE_IS_1_BYTE <= additional && additional <= ZCBOR_VALUE_IS_8_BYTES) { /* 24 => 1 * 25 => 2 * 26 => 4 @@ -29,23 +28,9 @@ static uint_fast32_t additional_len(uint8_t additional) */ return 1U << (additional - ZCBOR_VALUE_IS_1_BYTE); } - return 0; + return 0xF; } -/** Extract the major type, i.e. the first 3 bits of the header byte. */ -#define MAJOR_TYPE(header_byte) ((zcbor_major_type_t)(((header_byte) >> 5) & 0x7)) - -/** Extract the additional info, i.e. the last 5 bits of the header byte. */ -#define ADDITIONAL(header_byte) ((header_byte) & 0x1F) - - -#define FAIL_AND_DECR_IF(expr, err) \ -do {\ - if (expr) { \ - (state->payload)--; \ - ZCBOR_ERR(err); \ - } \ -} while(0) static bool initial_checks(zcbor_state_t *state) { @@ -54,12 +39,13 @@ static bool initial_checks(zcbor_state_t *state) return true; } + static bool type_check(zcbor_state_t *state, zcbor_major_type_t exp_major_type) { if (!initial_checks(state)) { ZCBOR_FAIL(); } - zcbor_major_type_t major_type = MAJOR_TYPE(*state->payload); + zcbor_major_type_t major_type = ZCBOR_MAJOR_TYPE(*state->payload); if (major_type != exp_major_type) { ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE); @@ -67,6 +53,7 @@ static bool type_check(zcbor_state_t *state, zcbor_major_type_t exp_major_type) return true; } + #define INITIAL_CHECKS() \ do {\ if (!initial_checks(state)) { \ @@ -81,11 +68,17 @@ do {\ } \ } while(0) +static void err_restore(zcbor_state_t *state, int err) +{ + state->payload = state->payload_bak; + state->elem_count++; + zcbor_error(state, err); +} + #define ERR_RESTORE(err) \ do { \ - state->payload = state->payload_bak; \ - state->elem_count++; \ - ZCBOR_ERR(err); \ + err_restore(state, err); \ + ZCBOR_FAIL(); \ } while(0) #define FAIL_RESTORE() \ @@ -95,6 +88,21 @@ do { \ ZCBOR_FAIL(); \ } while(0) +#define PRINT_FUNC() zcbor_log("%s ", __func__); + + +static void endian_copy(uint8_t *dst, const uint8_t *src, size_t src_len) +{ +#ifdef ZCBOR_BIG_ENDIAN + memcpy(dst, src, src_len); +#else + for (size_t i = 0; i < src_len; i++) { + dst[i] = src[src_len - 1 - i]; + } +#endif /* ZCBOR_BIG_ENDIAN */ +} + + /** Get a single value. * * @details @p ppayload must point to the header byte. This function will @@ -111,61 +119,55 @@ do { \ * succeeds. If not, they are left unchanged. * * CBOR values are always big-endian, so this function converts from - * big to little-endian if necessary (@ref CONFIG_BIG_ENDIAN). + * big to little-endian if necessary (@ref ZCBOR_BIG_ENDIAN). */ static bool value_extract(zcbor_state_t *state, - void *const result, uint_fast32_t result_len) + void *const result, size_t result_len) { - zcbor_trace(); + zcbor_trace(state, "value_extract"); zcbor_assert_state(result_len != 0, "0-length result not supported.\r\n"); - zcbor_assert_state(result != NULL, NULL); + zcbor_assert_state(result_len <= 8, "result sizes above 8 bytes not supported.\r\n"); + zcbor_assert_state(result != NULL, "result cannot be NULL.\r\n"); INITIAL_CHECKS(); ZCBOR_ERR_IF((state->elem_count == 0), ZCBOR_ERR_LOW_ELEM_COUNT); - uint8_t *u8_result = (uint8_t *)result; - uint8_t additional = ADDITIONAL(*state->payload); + uint8_t additional = ZCBOR_ADDITIONAL(*state->payload); + size_t len = additional_len(additional); + uint8_t *result_offs = (uint8_t *)result + ZCBOR_ECPY_OFFS(result_len, MAX(1, len)); - state->payload_bak = state->payload; - (state->payload)++; + ZCBOR_ERR_IF(additional > ZCBOR_VALUE_IS_8_BYTES, ZCBOR_ERR_ADDITIONAL_INVAL); + ZCBOR_ERR_IF(len > result_len, ZCBOR_ERR_INT_SIZE); + ZCBOR_ERR_IF((state->payload + len + 1) > state->payload_end, + ZCBOR_ERR_NO_PAYLOAD); memset(result, 0, result_len); - if (additional <= ZCBOR_VALUE_IN_HEADER) { -#ifdef CONFIG_BIG_ENDIAN - u8_result[result_len - 1] = additional; -#else - u8_result[0] = additional; -#endif /* CONFIG_BIG_ENDIAN */ - } else { - uint_fast32_t len = additional_len(additional); - - FAIL_AND_DECR_IF(len > result_len, ZCBOR_ERR_INT_SIZE); - FAIL_AND_DECR_IF(len == 0, ZCBOR_ERR_ADDITIONAL_INVAL); // additional_len() did not recognize the additional value. - FAIL_AND_DECR_IF((state->payload + len) > state->payload_end, - ZCBOR_ERR_NO_PAYLOAD); -#ifdef CONFIG_BIG_ENDIAN - memcpy(&u8_result[result_len - len], state->payload, len); -#else - for (uint_fast32_t i = 0; i < len; i++) { - u8_result[i] = (state->payload)[len - i - 1]; - } -#endif /* CONFIG_BIG_ENDIAN */ + if (len == 0) { + *result_offs = additional; + } else { + endian_copy(result_offs, state->payload + 1, len); - (state->payload) += len; +#ifdef ZCBOR_CANONICAL + ZCBOR_ERR_IF((zcbor_header_len_ptr(result, result_len) != (len + 1)), + ZCBOR_ERR_INVALID_VALUE_ENCODING); +#endif } + state->payload_bak = state->payload; + (state->payload) += len + 1; (state->elem_count)--; return true; } -bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) +bool zcbor_int_decode(zcbor_state_t *state, void *result, size_t result_size) { + PRINT_FUNC(); INITIAL_CHECKS(); - zcbor_major_type_t major_type = MAJOR_TYPE(*state->payload); - uint8_t *result_uint8 = (uint8_t *)result_int; - int8_t *result_int8 = (int8_t *)result_int; + zcbor_major_type_t major_type = ZCBOR_MAJOR_TYPE(*state->payload); + uint8_t *result_uint8 = (uint8_t *)result; + int8_t *result_int8 = (int8_t *)result; if (major_type != ZCBOR_MAJOR_TYPE_PINT && major_type != ZCBOR_MAJOR_TYPE_NINT) { @@ -173,14 +175,14 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE); } - if (!value_extract(state, result_int, int_size)) { + if (!value_extract(state, result, result_size)) { ZCBOR_FAIL(); } -#ifdef CONFIG_BIG_ENDIAN +#ifdef ZCBOR_BIG_ENDIAN if (result_int8[0] < 0) { #else - if (result_int8[int_size - 1] < 0) { + if (result_int8[result_size - 1] < 0) { #endif /* Value is too large to fit in a signed integer. */ ERR_RESTORE(ZCBOR_ERR_INT_SIZE); @@ -188,7 +190,7 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) if (major_type == ZCBOR_MAJOR_TYPE_NINT) { /* Convert from CBOR's representation by flipping all bits. */ - for (int i = 0; i < int_size; i++) { + for (unsigned int i = 0; i < result_size; i++) { result_uint8[i] = (uint8_t)~result_uint8[i]; } } @@ -199,29 +201,41 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result) { + PRINT_FUNC(); return zcbor_int_decode(state, result, sizeof(*result)); } bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result) { + PRINT_FUNC(); return zcbor_int_decode(state, result, sizeof(*result)); } -bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result) +bool zcbor_uint_decode(zcbor_state_t *state, void *result, size_t result_size) { + PRINT_FUNC(); INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT); - if (!value_extract(state, result, sizeof(*result))) { + if (!value_extract(state, result, result_size)) { + zcbor_log("uint with size %zu failed.\r\n", result_size); ZCBOR_FAIL(); } return true; } +bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result) +{ + PRINT_FUNC(); + return zcbor_uint_decode(state, result, sizeof(*result)); +} + + bool zcbor_int32_expect_union(zcbor_state_t *state, int32_t result) { + PRINT_FUNC(); if (!zcbor_union_elem_code(state)) { ZCBOR_FAIL(); } @@ -231,6 +245,7 @@ bool zcbor_int32_expect_union(zcbor_state_t *state, int32_t result) bool zcbor_int64_expect_union(zcbor_state_t *state, int64_t result) { + PRINT_FUNC(); if (!zcbor_union_elem_code(state)) { ZCBOR_FAIL(); } @@ -240,6 +255,7 @@ bool zcbor_int64_expect_union(zcbor_state_t *state, int64_t result) bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result) { + PRINT_FUNC(); if (!zcbor_union_elem_code(state)) { ZCBOR_FAIL(); } @@ -249,6 +265,7 @@ bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result) bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result) { + PRINT_FUNC(); if (!zcbor_union_elem_code(state)) { ZCBOR_FAIL(); } @@ -256,72 +273,109 @@ bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result) } -bool zcbor_int32_expect(zcbor_state_t *state, int32_t result) +bool zcbor_int32_expect(zcbor_state_t *state, int32_t expected) { - return zcbor_int64_expect(state, result); + PRINT_FUNC(); + return zcbor_int64_expect(state, expected); +} + + +bool zcbor_int32_pexpect(zcbor_state_t *state, int32_t *expected) +{ + PRINT_FUNC(); + return zcbor_int32_expect(state, *expected); } -bool zcbor_int64_expect(zcbor_state_t *state, int64_t result) +bool zcbor_int64_expect(zcbor_state_t *state, int64_t expected) { - int64_t value; + PRINT_FUNC(); + int64_t actual; - if (!zcbor_int64_decode(state, &value)) { + if (!zcbor_int64_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { - zcbor_print("%" PRIi64 " != %" PRIi64 "\r\n", value, result); + if (actual != expected) { + zcbor_log("%" PRIi64 " != %" PRIi64 "\r\n", actual, expected); ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result) +bool zcbor_int64_pexpect(zcbor_state_t *state, int64_t *expected) { - INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT); + PRINT_FUNC(); + return zcbor_int64_expect(state, *expected); +} - if (!value_extract(state, result, sizeof(*result))) { - ZCBOR_FAIL(); - } - return true; + +bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result) +{ + PRINT_FUNC(); + return zcbor_uint_decode(state, result, sizeof(*result)); } #ifdef ZCBOR_SUPPORTS_SIZE_T bool zcbor_size_decode(zcbor_state_t *state, size_t *result) { - return value_extract(state, result, sizeof(size_t)); + PRINT_FUNC(); + return zcbor_uint_decode(state, result, sizeof(*result)); } #endif -bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t result) +bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t expected) { - return zcbor_uint64_expect(state, result); + PRINT_FUNC(); + return zcbor_uint64_expect(state, expected); } -bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t result) +bool zcbor_uint32_pexpect(zcbor_state_t *state, uint32_t *expected) { - uint64_t value; + PRINT_FUNC(); + return zcbor_uint32_expect(state, *expected); +} + - if (!zcbor_uint64_decode(state, &value)) { +bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t expected) +{ + PRINT_FUNC(); + uint64_t actual; + + if (!zcbor_uint64_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { - zcbor_print("%" PRIu64 " != %" PRIu64 "\r\n", value, result); + if (actual != expected) { + zcbor_log("%" PRIu64 " != %" PRIu64 "\r\n", actual, expected); ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } +bool zcbor_uint64_pexpect(zcbor_state_t *state, uint64_t *expected) +{ + PRINT_FUNC(); + return zcbor_uint64_expect(state, *expected); +} + + #ifdef ZCBOR_SUPPORTS_SIZE_T -bool zcbor_size_expect(zcbor_state_t *state, size_t result) +bool zcbor_size_expect(zcbor_state_t *state, size_t expected) { - return zcbor_uint64_expect(state, result); + PRINT_FUNC(); + return zcbor_uint64_expect(state, expected); +} + + +bool zcbor_size_pexpect(zcbor_state_t *state, size_t *expected) +{ + PRINT_FUNC(); + return zcbor_size_expect(state, *expected); } #endif @@ -339,31 +393,37 @@ static bool str_start_decode(zcbor_state_t *state, return true; } - -static bool str_overflow_check(zcbor_state_t *state, struct zcbor_string *result) +static bool str_start_decode_with_overflow_check(zcbor_state_t *state, + struct zcbor_string *result, zcbor_major_type_t exp_major_type) { - if (result->len > (state->payload_end - state->payload)) { - zcbor_print("error: 0x%zu > 0x%zu\r\n", - result->len, - (state->payload_end - state->payload)); + bool res = str_start_decode(state, result, exp_major_type); + + if (!res) { + ZCBOR_FAIL(); + } + + /* Casting to size_t is safe since str_start_decode() checks that + * payload_end is bigger that payload. */ + if (result->len > (size_t)(state->payload_end - state->payload)) { + zcbor_log("error: 0x%zu > 0x%zu\r\n", + result->len, + (state->payload_end - state->payload)); ERR_RESTORE(ZCBOR_ERR_NO_PAYLOAD); } + return true; } bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result) { + PRINT_FUNC(); struct zcbor_string dummy; if (result == NULL) { result = &dummy; } - if(!str_start_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { - ZCBOR_FAIL(); - } - - if (!str_overflow_check(state, result)) { + if(!str_start_decode_with_overflow_check(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { ZCBOR_FAIL(); } @@ -381,7 +441,7 @@ bool zcbor_bstr_end_decode(zcbor_state_t *state) ZCBOR_ERR_IF(state->payload != state->payload_end, ZCBOR_ERR_PAYLOAD_NOT_CONSUMED); if (!zcbor_process_backup(state, - ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_KEEP_PAYLOAD, ZCBOR_MAX_ELEM_COUNT)) { ZCBOR_FAIL(); } @@ -402,6 +462,7 @@ static bool start_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result, zcbor_major_type_t exp_major_type) { + PRINT_FUNC(); if(!str_start_decode(state, &result->fragment, exp_major_type)) { ZCBOR_FAIL(); } @@ -417,6 +478,7 @@ static bool start_decode_fragment(zcbor_state_t *state, bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) { + PRINT_FUNC(); if (!start_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { ZCBOR_FAIL(); } @@ -437,7 +499,7 @@ void zcbor_next_fragment(zcbor_state_t *state, result->fragment.len = result->total_len - result->offset; partition_fragment(state, result); - zcbor_print("New fragment length %zu\r\n", result->fragment.len); + zcbor_log("New fragment length %zu\r\n", result->fragment.len); state->payload += result->fragment.len; } @@ -453,7 +515,7 @@ void zcbor_bstr_next_fragment(zcbor_state_t *state, result->fragment.len = result->total_len - result->offset; partition_fragment(state, result); - zcbor_print("fragment length %zu\r\n", result->fragment.len); + zcbor_log("fragment length %zu\r\n", result->fragment.len); state->payload_end = state->payload + result->fragment.len; } @@ -467,11 +529,7 @@ bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment) static bool str_decode(zcbor_state_t *state, struct zcbor_string *result, zcbor_major_type_t exp_major_type) { - if (!str_start_decode(state, result, exp_major_type)) { - ZCBOR_FAIL(); - } - - if (!str_overflow_check(state, result)) { + if (!str_start_decode_with_overflow_check(state, result, exp_major_type)) { ZCBOR_FAIL(); } @@ -500,8 +558,7 @@ static bool str_expect(zcbor_state_t *state, struct zcbor_string *result, if (!str_decode(state, &tmp_result, exp_major_type)) { ZCBOR_FAIL(); } - if ((tmp_result.len != result->len) - || memcmp(result->value, tmp_result.value, tmp_result.len)) { + if (!zcbor_compare_strings(&tmp_result, result)) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; @@ -510,56 +567,97 @@ static bool str_expect(zcbor_state_t *state, struct zcbor_string *result, bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result) { + PRINT_FUNC(); return str_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR); } bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) { + PRINT_FUNC(); return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR); } -bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *result) +bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *expected) { - return str_expect(state, result, ZCBOR_MAJOR_TYPE_BSTR); + PRINT_FUNC(); + return str_expect(state, expected, ZCBOR_MAJOR_TYPE_BSTR); } bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result) { + PRINT_FUNC(); return str_decode(state, result, ZCBOR_MAJOR_TYPE_TSTR); } bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) { + PRINT_FUNC(); return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_TSTR); } -bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *result) +bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *expected) +{ + PRINT_FUNC(); + return str_expect(state, expected, ZCBOR_MAJOR_TYPE_TSTR); +} + + +bool zcbor_bstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len) +{ + PRINT_FUNC(); + struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; + + return zcbor_bstr_expect(state, &zs); +} + + +bool zcbor_tstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len) { - return str_expect(state, result, ZCBOR_MAJOR_TYPE_TSTR); + PRINT_FUNC(); + struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; + + return zcbor_tstr_expect(state, &zs); +} + + +bool zcbor_bstr_expect_term(zcbor_state_t *state, char const *string, size_t maxlen) +{ + PRINT_FUNC(); + return zcbor_bstr_expect_ptr(state, string, strnlen(string, maxlen)); +} + + +bool zcbor_tstr_expect_term(zcbor_state_t *state, char const *string, size_t maxlen) +{ + PRINT_FUNC(); + return zcbor_tstr_expect_ptr(state, string, strnlen(string, maxlen)); } static bool list_map_start_decode(zcbor_state_t *state, zcbor_major_type_t exp_major_type) { - uint_fast32_t new_elem_count; + size_t new_elem_count; bool indefinite_length_array = false; INITIAL_CHECKS_WITH_TYPE(exp_major_type); - if (ADDITIONAL(*state->payload) == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { +#ifndef ZCBOR_CANONICAL + if (ZCBOR_ADDITIONAL(*state->payload) == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { /* Indefinite length array. */ new_elem_count = ZCBOR_LARGE_ELEM_COUNT; ZCBOR_ERR_IF(state->elem_count == 0, ZCBOR_ERR_LOW_ELEM_COUNT); indefinite_length_array = true; - state->payload++; + state->payload_bak = state->payload++; state->elem_count--; - } else { + } else +#endif + { if (!value_extract(state, &new_elem_count, sizeof(new_elem_count))) { ZCBOR_FAIL(); } @@ -569,7 +667,7 @@ static bool list_map_start_decode(zcbor_state_t *state, FAIL_RESTORE(); } - state->indefinite_length_array = indefinite_length_array; + state->decode_state.indefinite_length_array = indefinite_length_array; return true; } @@ -577,15 +675,17 @@ static bool list_map_start_decode(zcbor_state_t *state, bool zcbor_list_start_decode(zcbor_state_t *state) { + PRINT_FUNC(); return list_map_start_decode(state, ZCBOR_MAJOR_TYPE_LIST); } bool zcbor_map_start_decode(zcbor_state_t *state) { + PRINT_FUNC(); bool ret = list_map_start_decode(state, ZCBOR_MAJOR_TYPE_MAP); - if (ret && !state->indefinite_length_array) { + if (ret && !state->decode_state.indefinite_length_array) { if (state->elem_count >= (ZCBOR_MAX_ELEM_COUNT / 2)) { /* The new elem_count is too large. */ ERR_RESTORE(ZCBOR_ERR_INT_SIZE); @@ -596,6 +696,272 @@ bool zcbor_map_start_decode(zcbor_state_t *state) } +bool zcbor_array_at_end(zcbor_state_t *state) +{ +#ifdef ZCBOR_CANONICAL + const bool indefinite_length_array = false; +#else + const bool indefinite_length_array = state->decode_state.indefinite_length_array; +#endif + return ((!indefinite_length_array && (state->elem_count == 0)) + || (indefinite_length_array + && (state->payload < state->payload_end) + && (*state->payload == 0xFF))); +} + + +static size_t update_map_elem_count(zcbor_state_t *state, size_t elem_count); +#ifdef ZCBOR_MAP_SMART_SEARCH +static bool allocate_map_flags(zcbor_state_t *state, size_t elem_count); +#endif + + +bool zcbor_unordered_map_start_decode(zcbor_state_t *state) +{ + PRINT_FUNC(); + ZCBOR_FAIL_IF(!zcbor_map_start_decode(state)); + +#ifdef ZCBOR_MAP_SMART_SEARCH + state->decode_state.map_search_elem_state + += zcbor_flags_to_bytes(state->decode_state.map_elem_count); +#else + state->decode_state.map_elems_processed = 0; +#endif + state->decode_state.map_elem_count = 0; + state->decode_state.counting_map_elems = state->decode_state.indefinite_length_array; + + if (!state->decode_state.counting_map_elems) { + size_t old_flags = update_map_elem_count(state, state->elem_count); +#ifdef ZCBOR_MAP_SMART_SEARCH + ZCBOR_FAIL_IF(!allocate_map_flags(state, old_flags)); +#endif + (void)old_flags; + } + + return true; +} + + +/** Return the max (starting) elem_count of the current container. + * + * Should only be used for unordered maps (started with @ref zcbor_unordered_map_start_decode) + */ +static size_t zcbor_current_max_elem_count(zcbor_state_t *state) +{ + return (state->decode_state.indefinite_length_array ? \ + ZCBOR_LARGE_ELEM_COUNT : state->decode_state.map_elem_count * 2); +} + + +static bool map_restart(zcbor_state_t *state) +{ + if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_KEEP_DECODE_STATE, + ZCBOR_MAX_ELEM_COUNT)) { + ZCBOR_FAIL(); + } + + state->elem_count = zcbor_current_max_elem_count(state); + return true; +} + + +__attribute__((used)) +static size_t get_current_index(zcbor_state_t *state, uint32_t index_offset) +{ + /* Subtract mode because for GET, you want the index you are pointing to, while for SET, + * you want the one you just processed. This only comes into play when elem_count is even. */ + return ((zcbor_current_max_elem_count(state) - state->elem_count - index_offset) / 2); +} + + +#ifdef ZCBOR_MAP_SMART_SEARCH +#define FLAG_MODE_GET_CURRENT 0 +#define FLAG_MODE_CLEAR_CURRENT 1 +#define FLAG_MODE_CLEAR_UNUSED 2 + +static bool manipulate_flags(zcbor_state_t *state, uint32_t mode) +{ + const size_t last_index = (state->decode_state.map_elem_count - 1); + size_t index = (mode == FLAG_MODE_CLEAR_UNUSED) ? last_index : get_current_index(state, mode); + + ZCBOR_ERR_IF((index >= state->decode_state.map_elem_count), + ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE); + uint8_t *flag_byte = &state->decode_state.map_search_elem_state[index >> 3]; + uint8_t flag_mask = (uint8_t)(1 << (index & 7)); + + switch(mode) { + case FLAG_MODE_GET_CURRENT: + return (!!(*flag_byte & flag_mask)); + case FLAG_MODE_CLEAR_CURRENT: + *flag_byte &= ~flag_mask; + return true; + case FLAG_MODE_CLEAR_UNUSED: + *flag_byte &= (uint8_t)((flag_mask << 1) - 1); + return true; + } + return false; +} + + +static bool should_try_key(zcbor_state_t *state) +{ + return manipulate_flags(state, FLAG_MODE_GET_CURRENT); +} + + +bool zcbor_elem_processed(zcbor_state_t *state) +{ + return manipulate_flags(state, FLAG_MODE_CLEAR_CURRENT); +} + + +static bool allocate_map_flags(zcbor_state_t *state, size_t old_flags) +{ + size_t new_bytes = zcbor_flags_to_bytes(state->decode_state.map_elem_count); + size_t old_bytes = zcbor_flags_to_bytes(old_flags); + size_t extra_bytes = new_bytes - old_bytes; + const uint8_t *flags_end = state->constant_state->map_search_elem_state_end; + + if (extra_bytes) { + if ((state->decode_state.map_search_elem_state + new_bytes) > flags_end) { + state->decode_state.map_elem_count + = 8 * (size_t)(flags_end - state->decode_state.map_search_elem_state); + ZCBOR_ERR(ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE); + } + + memset(&state->decode_state.map_search_elem_state[new_bytes - extra_bytes], 0xFF, extra_bytes); + } + return true; +} +#else + +static bool should_try_key(zcbor_state_t *state) +{ + return (state->decode_state.map_elems_processed < state->decode_state.map_elem_count); +} + + +bool zcbor_elem_processed(zcbor_state_t *state) +{ + if (should_try_key(state)) { + state->decode_state.map_elems_processed++; + } + return true; +} +#endif + + +static size_t update_map_elem_count(zcbor_state_t *state, size_t elem_count) +{ + size_t old_map_elem_count = state->decode_state.map_elem_count; + + state->decode_state.map_elem_count = MAX(old_map_elem_count, elem_count / 2); + return old_map_elem_count; +} + + +static bool handle_map_end(zcbor_state_t *state) +{ + state->decode_state.counting_map_elems = false; + return map_restart(state); +} + + +static bool try_key(zcbor_state_t *state, void *key_result, zcbor_decoder_t key_decoder) +{ + uint8_t const *payload_bak2 = state->payload; + size_t elem_count_bak = state->elem_count; + + if (!key_decoder(state, (uint8_t *)key_result)) { + state->payload = payload_bak2; + state->elem_count = elem_count_bak; + return false; + } + + zcbor_log("Found element at index %zu.\n", get_current_index(state, 1)); + return true; +} + + +bool zcbor_unordered_map_search(zcbor_decoder_t key_decoder, zcbor_state_t *state, void *key_result) +{ + PRINT_FUNC(); + /* elem_count cannot be odd since the map consists of key-value-pairs. + * This might mean that this function was called while pointing at a value (instead + * of a key). */ + ZCBOR_ERR_IF(state->elem_count & 1, ZCBOR_ERR_MAP_MISALIGNED); + + uint8_t const *payload_bak = state->payload; + size_t elem_count = state->elem_count; + + /* Loop once through all the elements of the map. */ + do { + if (zcbor_array_at_end(state)) { + if (!handle_map_end(state)) { + goto error; + } + continue; /* This continue is needed so the loop stops both if elem_count is + * at the very start or the very end of the map. */ + } + + if (state->decode_state.counting_map_elems) { + size_t m_elem_count = ZCBOR_LARGE_ELEM_COUNT - state->elem_count + 2; + size_t old_flags = update_map_elem_count(state, m_elem_count); +#ifdef ZCBOR_MAP_SMART_SEARCH + ZCBOR_FAIL_IF(!allocate_map_flags(state, old_flags)); +#endif + (void)old_flags; + } + + if (should_try_key(state) && try_key(state, key_result, key_decoder)) { + if (!state->constant_state->manually_process_elem) { + ZCBOR_FAIL_IF(!zcbor_elem_processed(state)); + } + return true; + } + + /* Skip over both the key and the value. */ + if (!zcbor_any_skip(state, NULL) || !zcbor_any_skip(state, NULL)) { + goto error; + } + } while (state->elem_count != elem_count); + + zcbor_error(state, ZCBOR_ERR_ELEM_NOT_FOUND); +error: + state->payload = payload_bak; + state->elem_count = elem_count; + ZCBOR_FAIL(); +} + + +bool zcbor_search_key_bstr_ptr(zcbor_state_t *state, char const *ptr, size_t len) +{ + struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; + + return zcbor_unordered_map_search((zcbor_decoder_t *)zcbor_bstr_expect, state, &zs); +} + + +bool zcbor_search_key_tstr_ptr(zcbor_state_t *state, char const *ptr, size_t len) +{ + struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; + + return zcbor_unordered_map_search((zcbor_decoder_t *)zcbor_tstr_expect, state, &zs); +} + + +bool zcbor_search_key_bstr_term(zcbor_state_t *state, char const *str, size_t maxlen) +{ + return zcbor_search_key_bstr_ptr(state, str, strnlen(str, maxlen)); +} + + +bool zcbor_search_key_tstr_term(zcbor_state_t *state, char const *str, size_t maxlen) +{ + return zcbor_search_key_tstr_ptr(state, str, strnlen(str, maxlen)); +} + + static bool array_end_expect(zcbor_state_t *state) { INITIAL_CHECKS(); @@ -608,17 +974,19 @@ static bool array_end_expect(zcbor_state_t *state) static bool list_map_end_decode(zcbor_state_t *state) { - uint_fast32_t max_elem_count = 0; + size_t max_elem_count = 0; - if (state->indefinite_length_array) { +#ifndef ZCBOR_CANONICAL + if (state->decode_state.indefinite_length_array) { if (!array_end_expect(state)) { ZCBOR_FAIL(); } max_elem_count = ZCBOR_MAX_ELEM_COUNT; - state->indefinite_length_array = false; + state->decode_state.indefinite_length_array = false; } +#endif if (!zcbor_process_backup(state, - ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_KEEP_PAYLOAD, max_elem_count)) { ZCBOR_FAIL(); } @@ -629,20 +997,51 @@ static bool list_map_end_decode(zcbor_state_t *state) bool zcbor_list_end_decode(zcbor_state_t *state) { + PRINT_FUNC(); return list_map_end_decode(state); } bool zcbor_map_end_decode(zcbor_state_t *state) { + PRINT_FUNC(); return list_map_end_decode(state); } +bool zcbor_unordered_map_end_decode(zcbor_state_t *state) +{ + /* Checking zcbor_array_at_end() ensures that check is valid. + * In case the map is at the end, but state->decode_state.counting_map_elems isn't updated.*/ + ZCBOR_ERR_IF(!zcbor_array_at_end(state) && state->decode_state.counting_map_elems, + ZCBOR_ERR_ELEMS_NOT_PROCESSED); + + if (state->decode_state.map_elem_count > 0) { +#ifdef ZCBOR_MAP_SMART_SEARCH + manipulate_flags(state, FLAG_MODE_CLEAR_UNUSED); + + for (size_t i = 0; i < zcbor_flags_to_bytes(state->decode_state.map_elem_count); i++) { + if (state->decode_state.map_search_elem_state[i] != 0) { + zcbor_log("unprocessed element(s) in map: [%zu] = 0x%02x\n", + i, state->decode_state.map_search_elem_state[i]); + ZCBOR_ERR(ZCBOR_ERR_ELEMS_NOT_PROCESSED); + } + } +#else + ZCBOR_ERR_IF(should_try_key(state), ZCBOR_ERR_ELEMS_NOT_PROCESSED); +#endif + } + while (!zcbor_array_at_end(state)) { + zcbor_any_skip(state, NULL); + } + return zcbor_map_end_decode(state); +} + + bool zcbor_list_map_end_force_decode(zcbor_state_t *state) { if (!zcbor_process_backup(state, - ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_KEEP_PAYLOAD, ZCBOR_MAX_ELEM_COUNT)) { ZCBOR_FAIL(); } @@ -651,69 +1050,180 @@ bool zcbor_list_map_end_force_decode(zcbor_state_t *state) } -static bool primx_expect(zcbor_state_t *state, uint8_t result) +bool zcbor_simple_decode(zcbor_state_t *state, uint8_t *result) { - uint32_t value; + PRINT_FUNC(); + PRINT_FUNC(); + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_SIMPLE); + + /* Simple values must be 0-23 (additional is 0-23) or 24-255 (additional is 24). + * Other additional values are not considered simple values. */ + ZCBOR_ERR_IF(ZCBOR_ADDITIONAL(*state->payload) > 24, ZCBOR_ERR_WRONG_TYPE); + + if (!value_extract(state, result, sizeof(*result))) { + ZCBOR_FAIL(); + } + return true; +} + - INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); +bool zcbor_simple_expect(zcbor_state_t *state, uint8_t expected) +{ + PRINT_FUNC(); + uint8_t actual; - if (!value_extract(state, &value, sizeof(value))) { + if (!zcbor_simple_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { + if (actual != expected) { + zcbor_log("simple value %u != %u\r\n", actual, expected); ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } + return true; } +bool zcbor_simple_pexpect(zcbor_state_t *state, uint8_t *expected) +{ + PRINT_FUNC(); + return zcbor_simple_expect(state, *expected); +} + + bool zcbor_nil_expect(zcbor_state_t *state, void *unused) { - if (!primx_expect(state, 22)) { + PRINT_FUNC(); + (void)unused; + return zcbor_simple_expect(state, 22); +} + + +bool zcbor_undefined_expect(zcbor_state_t *state, void *unused) +{ + PRINT_FUNC(); + (void)unused; + return zcbor_simple_expect(state, 23); +} + + +bool zcbor_bool_decode(zcbor_state_t *state, bool *result) +{ + PRINT_FUNC(); + uint8_t value; + + if (!zcbor_simple_decode(state, &value)) { ZCBOR_FAIL(); } + value -= ZCBOR_BOOL_TO_SIMPLE; + if (value > 1) { + ERR_RESTORE(ZCBOR_ERR_WRONG_TYPE); + } + *result = value; + + zcbor_log("boolval: %u\r\n", *result); return true; } -bool zcbor_undefined_expect(zcbor_state_t *state, void *unused) +bool zcbor_bool_expect(zcbor_state_t *state, bool expected) +{ + PRINT_FUNC(); + return zcbor_simple_expect(state, (uint8_t)(!!expected) + ZCBOR_BOOL_TO_SIMPLE); +} + + +bool zcbor_bool_pexpect(zcbor_state_t *state, bool *expected) +{ + PRINT_FUNC(); + return zcbor_bool_expect(state, *expected); +} + + +static bool float_check(zcbor_state_t *state, uint8_t additional_val) +{ + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_SIMPLE); + ZCBOR_ERR_IF(ZCBOR_ADDITIONAL(*state->payload) != additional_val, ZCBOR_ERR_FLOAT_SIZE); + return true; +} + + +bool zcbor_float16_bytes_decode(zcbor_state_t *state, uint16_t *result) { - if (!primx_expect(state, 23)) { + PRINT_FUNC(); + ZCBOR_FAIL_IF(!float_check(state, ZCBOR_VALUE_IS_2_BYTES)); + + if (!value_extract(state, result, sizeof(*result))) { ZCBOR_FAIL(); } + return true; } -bool zcbor_bool_decode(zcbor_state_t *state, bool *result) +bool zcbor_float16_bytes_expect(zcbor_state_t *state, uint16_t expected) { - if (zcbor_bool_expect(state, false)) { - *result = false; - } else if (zcbor_bool_expect(state, true)) { - *result = true; - } else { + PRINT_FUNC(); + uint16_t actual; + + if (!zcbor_float16_bytes_decode(state, &actual)) { + ZCBOR_FAIL(); + } + if (actual != expected) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + + +bool zcbor_float16_bytes_pexpect(zcbor_state_t *state, uint16_t *expected) +{ + PRINT_FUNC(); + return zcbor_float16_bytes_expect(state, *expected); +} + + +bool zcbor_float16_decode(zcbor_state_t *state, float *result) +{ + PRINT_FUNC(); + uint16_t value16; + + if (!zcbor_float16_bytes_decode(state, &value16)) { ZCBOR_FAIL(); } - zcbor_print("boolval: %u\r\n", *result); + *result = zcbor_float16_to_32(value16); return true; } -bool zcbor_bool_expect(zcbor_state_t *state, bool result) +bool zcbor_float16_expect(zcbor_state_t *state, float expected) { - if (!primx_expect(state, (uint8_t)(!!result) + ZCBOR_BOOL_TO_PRIM)) { + PRINT_FUNC(); + float actual; + + if (!zcbor_float16_decode(state, &actual)) { ZCBOR_FAIL(); } + if (actual != expected) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } return true; } +bool zcbor_float16_pexpect(zcbor_state_t *state, float *expected) +{ + PRINT_FUNC(); + return zcbor_float16_expect(state, *expected); +} + + bool zcbor_float32_decode(zcbor_state_t *state, float *result) { - INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); - ZCBOR_ERR_IF(ADDITIONAL(*state->payload) != ZCBOR_VALUE_IS_4_BYTES, ZCBOR_ERR_FLOAT_SIZE); + PRINT_FUNC(); + ZCBOR_FAIL_IF(!float_check(state, ZCBOR_VALUE_IS_4_BYTES)); if (!value_extract(state, result, sizeof(*result))) { ZCBOR_FAIL(); @@ -723,24 +1233,65 @@ bool zcbor_float32_decode(zcbor_state_t *state, float *result) } -bool zcbor_float32_expect(zcbor_state_t *state, float result) +bool zcbor_float32_expect(zcbor_state_t *state, float expected) { - float value; + PRINT_FUNC(); + float actual; - if (!zcbor_float32_decode(state, &value)) { + if (!zcbor_float32_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { + if (actual != expected) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } +bool zcbor_float32_pexpect(zcbor_state_t *state, float *expected) +{ + PRINT_FUNC(); + return zcbor_float32_expect(state, *expected); +} + + +bool zcbor_float16_32_decode(zcbor_state_t *state, float *result) +{ + PRINT_FUNC(); + if (zcbor_float16_decode(state, result)) { + /* Do nothing */ + } else if (!zcbor_float32_decode(state, result)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float16_32_expect(zcbor_state_t *state, float expected) +{ + PRINT_FUNC(); + if (zcbor_float16_expect(state, expected)) { + /* Do nothing */ + } else if (!zcbor_float32_expect(state, expected)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float16_32_pexpect(zcbor_state_t *state, float *expected) +{ + PRINT_FUNC(); + return zcbor_float16_32_expect(state, *expected); +} + + bool zcbor_float64_decode(zcbor_state_t *state, double *result) { - INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); - ZCBOR_ERR_IF(ADDITIONAL(*state->payload) != ZCBOR_VALUE_IS_8_BYTES, ZCBOR_ERR_FLOAT_SIZE); + PRINT_FUNC(); + ZCBOR_FAIL_IF(!float_check(state, ZCBOR_VALUE_IS_8_BYTES)); if (!value_extract(state, result, sizeof(*result))) { ZCBOR_FAIL(); @@ -750,22 +1301,31 @@ bool zcbor_float64_decode(zcbor_state_t *state, double *result) } -bool zcbor_float64_expect(zcbor_state_t *state, double result) +bool zcbor_float64_expect(zcbor_state_t *state, double expected) { - double value; + PRINT_FUNC(); + double actual; - if (!zcbor_float64_decode(state, &value)) { + if (!zcbor_float64_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { + if (actual != expected) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -bool zcbor_float_decode(zcbor_state_t *state, double *result) +bool zcbor_float64_pexpect(zcbor_state_t *state, double *expected) +{ + PRINT_FUNC(); + return zcbor_float64_expect(state, *expected); +} + + +bool zcbor_float32_64_decode(zcbor_state_t *state, double *result) { + PRINT_FUNC(); float float_result; if (zcbor_float32_decode(state, &float_result)) { @@ -778,11 +1338,51 @@ bool zcbor_float_decode(zcbor_state_t *state, double *result) } -bool zcbor_float_expect(zcbor_state_t *state, double result) +bool zcbor_float32_64_expect(zcbor_state_t *state, double expected) +{ + PRINT_FUNC(); + if (zcbor_float64_expect(state, expected)) { + /* Do nothing */ + } else if (!zcbor_float32_expect(state, (float)expected)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float32_64_pexpect(zcbor_state_t *state, double *expected) +{ + PRINT_FUNC(); + return zcbor_float32_64_expect(state, *expected); +} + + +bool zcbor_float_decode(zcbor_state_t *state, double *result) +{ + PRINT_FUNC(); + float float_result; + + if (zcbor_float16_decode(state, &float_result)) { + *result = (double)float_result; + } else if (zcbor_float32_decode(state, &float_result)) { + *result = (double)float_result; + } else if (!zcbor_float64_decode(state, result)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float_expect(zcbor_state_t *state, double expected) { - if (zcbor_float32_expect(state, (float)result)) { + PRINT_FUNC(); + if (zcbor_float16_expect(state, (float)expected)) { + /* Do nothing */ + } else if (zcbor_float32_expect(state, (float)expected)) { /* Do nothing */ - } else if (!zcbor_float64_expect(state, result)) { + } else if (!zcbor_float64_expect(state, expected)) { ZCBOR_FAIL(); } @@ -790,54 +1390,47 @@ bool zcbor_float_expect(zcbor_state_t *state, double result) } +bool zcbor_float_pexpect(zcbor_state_t *state, double *expected) +{ + PRINT_FUNC(); + return zcbor_float_expect(state, *expected); +} + + bool zcbor_any_skip(zcbor_state_t *state, void *result) { + PRINT_FUNC(); zcbor_assert_state(result == NULL, "'any' type cannot be returned, only skipped.\r\n"); + (void)result; INITIAL_CHECKS(); - zcbor_major_type_t major_type = MAJOR_TYPE(*state->payload); - uint8_t additional = ADDITIONAL(*state->payload); - uint_fast32_t value; - uint_fast32_t num_decode; - uint_fast32_t temp_elem_count; - uint_fast32_t elem_count_bak = state->elem_count; - uint8_t const *payload_bak = state->payload; - uint64_t tag_dummy; + zcbor_major_type_t major_type = ZCBOR_MAJOR_TYPE(*state->payload); + uint8_t additional = ZCBOR_ADDITIONAL(*state->payload); + uint64_t value = 0; /* In case of indefinite_length_array. */ + zcbor_state_t state_copy; - payload_bak = state->payload; + memcpy(&state_copy, state, sizeof(zcbor_state_t)); - if (!zcbor_multi_decode(0, ZCBOR_LARGE_ELEM_COUNT, &num_decode, - (zcbor_decoder_t *)zcbor_tag_decode, state, - (void *)&tag_dummy, 0)) { - state->elem_count = elem_count_bak; - state->payload = payload_bak; - ZCBOR_FAIL(); - } - - if ((major_type == ZCBOR_MAJOR_TYPE_MAP) || (major_type == ZCBOR_MAJOR_TYPE_LIST)) { - if (additional == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { - ZCBOR_ERR_IF(state->elem_count == 0, ZCBOR_ERR_LOW_ELEM_COUNT); - state->payload++; - state->elem_count--; - temp_elem_count = state->elem_count; - payload_bak = state->payload; - state->elem_count = ZCBOR_LARGE_ELEM_COUNT; - if (!zcbor_multi_decode(0, ZCBOR_LARGE_ELEM_COUNT, &num_decode, - (zcbor_decoder_t *)zcbor_any_skip, state, - NULL, 0) - || (state->payload >= state->payload_end) - || !(*(state->payload++) == 0xFF)) { - state->elem_count = elem_count_bak; - state->payload = payload_bak; - ZCBOR_FAIL(); - } - state->elem_count = temp_elem_count; - return true; + while (major_type == ZCBOR_MAJOR_TYPE_TAG) { + uint32_t tag_dummy; + + if (!zcbor_tag_decode(&state_copy, &tag_dummy)) { + ZCBOR_FAIL(); } + ZCBOR_ERR_IF(state_copy.payload >= state_copy.payload_end, ZCBOR_ERR_NO_PAYLOAD); + major_type = ZCBOR_MAJOR_TYPE(*state_copy.payload); + additional = ZCBOR_ADDITIONAL(*state_copy.payload); } - if (!value_extract(state, &value, sizeof(value))) { +#ifdef ZCBOR_CANONICAL + const bool indefinite_length_array = false; +#else + const bool indefinite_length_array = ((additional == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) + && ((major_type == ZCBOR_MAJOR_TYPE_LIST) || (major_type == ZCBOR_MAJOR_TYPE_MAP))); +#endif + + if (!indefinite_length_array && !value_extract(&state_copy, &value, sizeof(value))) { /* Can happen because of elem_count (or payload_end) */ ZCBOR_FAIL(); } @@ -845,38 +1438,49 @@ bool zcbor_any_skip(zcbor_state_t *state, void *result) switch (major_type) { case ZCBOR_MAJOR_TYPE_BSTR: case ZCBOR_MAJOR_TYPE_TSTR: - /* 'value' is the length of the BSTR or TSTR */ - if (value > (state->payload_end - state->payload)) { - ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); - } - (state->payload) += value; + /* 'value' is the length of the BSTR or TSTR. + * The subtraction is safe because value_extract() above + * checks that payload_end is greater than payload. */ + ZCBOR_ERR_IF( + value > (uint64_t)(state_copy.payload_end - state_copy.payload), + ZCBOR_ERR_NO_PAYLOAD); + (state_copy.payload) += value; break; case ZCBOR_MAJOR_TYPE_MAP: - value *= 2; /* Because all members have a key. */ - /* Fallthrough */ + ZCBOR_ERR_IF(value > (SIZE_MAX / 2), ZCBOR_ERR_INT_SIZE); + value *= 2; + /* fallthrough */ case ZCBOR_MAJOR_TYPE_LIST: - temp_elem_count = state->elem_count; - state->elem_count = value; - if (!zcbor_multi_decode(value, value, &num_decode, - (zcbor_decoder_t *)zcbor_any_skip, state, - NULL, 0)) { - state->elem_count = elem_count_bak; - state->payload = payload_bak; + if (indefinite_length_array) { + state_copy.payload++; + value = ZCBOR_LARGE_ELEM_COUNT; + } + state_copy.elem_count = (size_t)value; + state_copy.decode_state.indefinite_length_array = indefinite_length_array; + while (!zcbor_array_at_end(&state_copy)) { + if (!zcbor_any_skip(&state_copy, NULL)) { + ZCBOR_FAIL(); + } + } + if (indefinite_length_array && !array_end_expect(&state_copy)) { ZCBOR_FAIL(); } - state->elem_count = temp_elem_count; break; default: /* Do nothing */ break; } + state->payload = state_copy.payload; + state->elem_count--; + return true; } bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result) { + PRINT_FUNC(); INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_TAG); if (!value_extract(state, result, sizeof(*result))) { @@ -887,32 +1491,41 @@ bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result) } -bool zcbor_tag_expect(zcbor_state_t *state, uint32_t result) +bool zcbor_tag_expect(zcbor_state_t *state, uint32_t expected) { - uint32_t tag_val; + PRINT_FUNC(); + uint32_t actual; - if (!zcbor_tag_decode(state, &tag_val)) { + if (!zcbor_tag_decode(state, &actual)) { ZCBOR_FAIL(); } - if (tag_val != result) { + if (actual != expected) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -bool zcbor_multi_decode(uint_fast32_t min_decode, - uint_fast32_t max_decode, - uint_fast32_t *num_decode, +bool zcbor_tag_pexpect(zcbor_state_t *state, uint32_t *expected) +{ + PRINT_FUNC(); + return zcbor_tag_expect(state, *expected); +} + + +bool zcbor_multi_decode(size_t min_decode, + size_t max_decode, + size_t *num_decode, zcbor_decoder_t decoder, zcbor_state_t *state, void *result, - uint_fast32_t result_len) + size_t result_len) { + PRINT_FUNC(); ZCBOR_CHECK_ERROR(); - for (uint_fast32_t i = 0; i < max_decode; i++) { + for (size_t i = 0; i < max_decode; i++) { uint8_t const *payload_bak = state->payload; - uint_fast32_t elem_count_bak = state->elem_count; + size_t elem_count_bak = state->elem_count; if (!decoder(state, (uint8_t *)result + i*result_len)) { @@ -920,33 +1533,35 @@ bool zcbor_multi_decode(uint_fast32_t min_decode, state->payload = payload_bak; state->elem_count = elem_count_bak; ZCBOR_ERR_IF(i < min_decode, ZCBOR_ERR_ITERATIONS); - zcbor_print("Found %" PRIuFAST32 " elements.\r\n", i); + zcbor_log("Found %zu elements.\r\n", i); return true; } } - zcbor_print("Found %" PRIuFAST32 " elements.\r\n", max_decode); + zcbor_log("Found %zu elements.\r\n", max_decode); *num_decode = max_decode; return true; } -bool zcbor_present_decode(uint_fast32_t *present, +bool zcbor_present_decode(bool *present, zcbor_decoder_t decoder, zcbor_state_t *state, void *result) { - uint_fast32_t num_decode; + PRINT_FUNC(); + size_t num_decode = 0; bool retval = zcbor_multi_decode(0, 1, &num_decode, decoder, state, result, 0); zcbor_assert_state(retval, "zcbor_multi_decode should not fail with these parameters.\r\n"); - *present = num_decode; + *present = !!num_decode; return retval; } -void zcbor_new_decode_state(zcbor_state_t *state_array, uint_fast32_t n_states, - const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +void zcbor_new_decode_state(zcbor_state_t *state_array, size_t n_states, + const uint8_t *payload, size_t payload_len, size_t elem_count, + uint8_t *flags, size_t flags_bytes) { - zcbor_new_state(state_array, n_states, payload, payload_len, elem_count); + zcbor_new_state(state_array, n_states, payload, payload_len, elem_count, flags, flags_bytes); } diff --git a/boot/zcbor/src/zcbor_encode.c b/boot/zcbor/src/zcbor_encode.c index 1929cebd5..44411ea35 100644 --- a/boot/zcbor/src/zcbor_encode.c +++ b/boot/zcbor/src/zcbor_encode.c @@ -1,8 +1,3 @@ -/* - * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 - */ - /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -15,12 +10,13 @@ #include #include "zcbor_encode.h" #include "zcbor_common.h" +#include "zcbor_print.h" _Static_assert((sizeof(size_t) == sizeof(void *)), "This code needs size_t to be the same length as pointers."); -static uint8_t log2ceil(uint_fast32_t val) +static uint8_t log2ceil(size_t val) { switch(val) { case 1: return 0; @@ -33,114 +29,74 @@ static uint8_t log2ceil(uint_fast32_t val) case 8: return 3; } - zcbor_print("Should not come here.\r\n"); + zcbor_log("Should not come here.\r\n"); return 0; } -static uint8_t get_additional(uint_fast32_t len, uint8_t value0) + +static uint8_t get_additional(size_t len, uint8_t value0) { return len == 0 ? value0 : (uint8_t)(24 + log2ceil(len)); } + static bool encode_header_byte(zcbor_state_t *state, zcbor_major_type_t major_type, uint8_t additional) { ZCBOR_CHECK_ERROR(); ZCBOR_CHECK_PAYLOAD(); - zcbor_assert_state(additional < 32, NULL); + zcbor_assert_state(additional < 32, "Unsupported additional value: %d\r\n", additional); *(state->payload_mut++) = (uint8_t)((major_type << 5) | (additional & 0x1F)); return true; } -static uint_fast32_t get_encoded_len(const void *const result, uint_fast32_t result_len); - - /** Encode a single value. */ static bool value_encode_len(zcbor_state_t *state, zcbor_major_type_t major_type, - const void *const result, uint_fast32_t result_len) + const void *const result, size_t result_len) { uint8_t *u8_result = (uint8_t *)result; - uint_fast32_t encoded_len = get_encoded_len(result, result_len); - if ((state->payload + 1 + encoded_len) > state->payload_end) { + if ((state->payload + 1 + result_len) > state->payload_end) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } if (!encode_header_byte(state, major_type, - get_additional(encoded_len, u8_result[0]))) { + get_additional(result_len, u8_result[0]))) { ZCBOR_FAIL(); } state->payload_mut--; - zcbor_trace(); + zcbor_trace(state, "value_encode_len"); state->payload_mut++; -#ifdef CONFIG_BIG_ENDIAN - memcpy(state->payload_mut, u8_result, encoded_len); - state->payload_mut += encoded_len; +#ifdef ZCBOR_BIG_ENDIAN + memcpy(state->payload_mut, u8_result, result_len); + state->payload_mut += result_len; #else - for (; encoded_len > 0; encoded_len--) { - *(state->payload_mut++) = u8_result[encoded_len - 1]; + for (; result_len > 0; result_len--) { + *(state->payload_mut++) = u8_result[result_len - 1]; } -#endif /* CONFIG_BIG_ENDIAN */ +#endif /* ZCBOR_BIG_ENDIAN */ state->elem_count++; return true; } -static uint_fast32_t get_result_len(const void *const input, uint_fast32_t max_result_len) -{ - uint8_t *u8_result = (uint8_t *)input; - uint_fast32_t len = max_result_len; - - for (; len > 0; len--) { -#ifdef CONFIG_BIG_ENDIAN - if (u8_result[max_result_len - len] != 0) { -#else - if (u8_result[len - 1] != 0) { -#endif /* CONFIG_BIG_ENDIAN */ - break; - } - } - - /* Round up to nearest power of 2. */ - return len <= 2 ? len : (uint8_t)(1 << log2ceil(len)); -} - - -static const void *get_result(const void *const input, uint_fast32_t max_result_len, - uint_fast32_t result_len) -{ -#ifdef CONFIG_BIG_ENDIAN - return &((uint8_t *)input)[max_result_len - (result_len ? result_len : 1)]; -#else - return input; -#endif -} - - -static uint_fast32_t get_encoded_len(const void *const result, uint_fast32_t result_len) -{ - const uint8_t *u8_result = (const uint8_t *)result; - - if ((result_len == 1) && (u8_result[0] <= ZCBOR_VALUE_IN_HEADER)) { - return 0; - } - return result_len; -} - - static bool value_encode(zcbor_state_t *state, zcbor_major_type_t major_type, - const void *const input, uint_fast32_t max_result_len) + const void *const input, size_t max_result_len) { zcbor_assert_state(max_result_len != 0, "0-length result not supported.\r\n"); - uint_fast32_t result_len = get_result_len(input, max_result_len); - const void *const result = get_result(input, max_result_len, result_len); + size_t result_len = zcbor_header_len_ptr(input, max_result_len) - 1; + const void *result = input; + +#ifdef ZCBOR_BIG_ENDIAN + result = (uint8_t *)input + max_result_len - (result_len ? result_len : 1); +#endif return value_encode_len(state, major_type, result, result_len); } @@ -158,7 +114,7 @@ bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_si ZCBOR_ERR(ZCBOR_ERR_INT_SIZE); } -#ifdef CONFIG_BIG_ENDIAN +#ifdef ZCBOR_BIG_ENDIAN if (input_int8[0] < 0) { #else if (input_int8[int_size - 1] < 0) { @@ -166,7 +122,7 @@ bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_si major_type = ZCBOR_MAJOR_TYPE_NINT; /* Convert to CBOR's representation by flipping all bits. */ - for (int i = 0; i < int_size; i++) { + for (unsigned int i = 0; i < int_size; i++) { input_buf[i] = (uint8_t)~input_uint8[i]; } input = input_buf; @@ -182,53 +138,37 @@ bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_si } -bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input) +bool zcbor_uint_encode(zcbor_state_t *state, const void *input_uint, size_t uint_size) { - return zcbor_int_encode(state, input, sizeof(*input)); + if (!value_encode(state, ZCBOR_MAJOR_TYPE_PINT, input_uint, uint_size)) { + zcbor_log("uint with size %zu failed.\r\n", uint_size); + ZCBOR_FAIL(); + } + return true; } -bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input) +bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input) { return zcbor_int_encode(state, input, sizeof(*input)); } -static bool uint32_encode(zcbor_state_t *state, const uint32_t *input, - zcbor_major_type_t major_type) +bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input) { - if (!value_encode(state, major_type, input, 4)) { - ZCBOR_FAIL(); - } - return true; + return zcbor_int_encode(state, input, sizeof(*input)); } bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input) { - if (!uint32_encode(state, input, ZCBOR_MAJOR_TYPE_PINT)) { - ZCBOR_FAIL(); - } - return true; -} - - -static bool uint64_encode(zcbor_state_t *state, const uint64_t *input, - zcbor_major_type_t major_type) -{ - if (!value_encode(state, major_type, input, 8)) { - ZCBOR_FAIL(); - } - return true; + return zcbor_uint_encode(state, input, sizeof(*input)); } bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input) { - if (!uint64_encode(state, input, ZCBOR_MAJOR_TYPE_PINT)) { - ZCBOR_FAIL(); - } - return true; + return zcbor_uint_encode(state, input, sizeof(*input)); } @@ -246,37 +186,34 @@ bool zcbor_int64_put(zcbor_state_t *state, int64_t input) bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input) { - return zcbor_uint64_put(state, input); + return zcbor_uint_encode(state, &input, sizeof(input)); } bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input) { - if (!uint64_encode(state, &input, ZCBOR_MAJOR_TYPE_PINT)) { - ZCBOR_FAIL(); - } - return true; + return zcbor_uint_encode(state, &input, sizeof(input)); } #ifdef ZCBOR_SUPPORTS_SIZE_T bool zcbor_size_put(zcbor_state_t *state, size_t input) { - return zcbor_uint64_put(state, input); + return zcbor_uint_encode(state, &input, sizeof(input)); } bool zcbor_size_encode(zcbor_state_t *state, const size_t *input) { - return zcbor_size_put(state, *input); + return zcbor_uint_encode(state, input, sizeof(*input)); } #endif static bool str_start_encode(zcbor_state_t *state, const struct zcbor_string *input, zcbor_major_type_t major_type) { - if (input->value && ((get_result_len(&input->len, sizeof(input->len)) - + 1 + input->len + (size_t)state->payload) + if (input->value && ((zcbor_header_len_ptr(&input->len, sizeof(input->len)) + + input->len + (size_t)state->payload) > (size_t)state->payload_end)) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } @@ -288,19 +225,10 @@ static bool str_start_encode(zcbor_state_t *state, } -static bool primitive_put(zcbor_state_t *state, uint32_t input) -{ - if (!uint32_encode(state, &input, ZCBOR_MAJOR_TYPE_PRIM)) { - ZCBOR_FAIL(); - } - return true; -} - - static size_t remaining_str_len(zcbor_state_t *state) { size_t max_len = (size_t)state->payload_end - (size_t)state->payload; - size_t result_len = get_result_len(&max_len, sizeof(max_len)); + size_t result_len = zcbor_header_len_ptr(&max_len, sizeof(max_len)) - 1; return max_len - result_len - 1; } @@ -315,8 +243,7 @@ bool zcbor_bstr_start_encode(zcbor_state_t *state) uint64_t max_len = remaining_str_len(state); /* Encode a dummy header */ - if (!uint64_encode(state, &max_len, - ZCBOR_MAJOR_TYPE_BSTR)) { + if (!value_encode(state, ZCBOR_MAJOR_TYPE_BSTR, &max_len, sizeof(max_len))) { ZCBOR_FAIL(); } return true; @@ -353,7 +280,8 @@ bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result) static bool str_encode(zcbor_state_t *state, const struct zcbor_string *input, zcbor_major_type_t major_type) { - if (input->len > (state->payload_end - state->payload)) { + ZCBOR_CHECK_PAYLOAD(); /* To make the size_t cast below safe. */ + if (input->len > (size_t)(state->payload_end - state->payload)) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } if (!str_start_encode(state, input, major_type)) { @@ -381,7 +309,35 @@ bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input) } -static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num, +bool zcbor_bstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len) +{ + const struct zcbor_string zs = { .value = (const uint8_t *)str, .len = len }; + + return zcbor_bstr_encode(state, &zs); +} + + +bool zcbor_tstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len) +{ + const struct zcbor_string zs = { .value = (const uint8_t *)str, .len = len }; + + return zcbor_tstr_encode(state, &zs); +} + + +bool zcbor_bstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen) +{ + return zcbor_bstr_encode_ptr(state, str, strnlen(str, maxlen)); +} + + +bool zcbor_tstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen) +{ + return zcbor_tstr_encode_ptr(state, str, strnlen(str, maxlen)); +} + + +static bool list_map_start_encode(zcbor_state_t *state, size_t max_num, zcbor_major_type_t major_type) { #ifdef ZCBOR_CANONICAL @@ -395,6 +351,8 @@ static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num, } state->elem_count--; /* Because of dummy header. */ #else + (void)max_num; + if (!encode_header_byte(state, major_type, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { ZCBOR_FAIL(); } @@ -403,54 +361,43 @@ static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num, } -bool zcbor_list_start_encode(zcbor_state_t *state, uint_fast32_t max_num) +bool zcbor_list_start_encode(zcbor_state_t *state, size_t max_num) { return list_map_start_encode(state, max_num, ZCBOR_MAJOR_TYPE_LIST); } -bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num) +bool zcbor_map_start_encode(zcbor_state_t *state, size_t max_num) { return list_map_start_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP); } -#ifdef ZCBOR_CANONICAL -static uint_fast32_t get_encoded_len2(const void *const input, uint_fast32_t max_result_len) -{ - uint_fast32_t result_len = get_result_len(input, max_result_len); - const void *const result = get_result(input, max_result_len, result_len); - - return get_encoded_len(result, result_len); -} -#endif - - -static bool list_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num, +static bool list_map_end_encode(zcbor_state_t *state, size_t max_num, zcbor_major_type_t major_type) { #ifdef ZCBOR_CANONICAL - uint_fast32_t list_count = ((major_type == ZCBOR_MAJOR_TYPE_LIST) ? + size_t list_count = ((major_type == ZCBOR_MAJOR_TYPE_LIST) ? state->elem_count : (state->elem_count / 2)); const uint8_t *payload = state->payload; - uint_fast32_t max_header_len = get_encoded_len2(&max_num, 4); - uint_fast32_t header_len = get_encoded_len2(&list_count, 4); + size_t max_header_len = zcbor_header_len_ptr(&max_num, 4) - 1; + size_t header_len = zcbor_header_len_ptr(&list_count, 4) - 1; if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME, 0xFFFFFFFF)) { ZCBOR_FAIL(); } - zcbor_print("list_count: %" PRIuFAST32 "\r\n", list_count); + zcbor_log("list_count: %zu\r\n", list_count); /** If max_num is smaller than the actual number of encoded elements, * the value_encode() below will corrupt the data if the encoded * header is larger than the previously encoded header. */ if (header_len > max_header_len) { - zcbor_print("max_num too small.\r\n"); + zcbor_log("max_num too small.\r\n"); ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT); } @@ -471,7 +418,9 @@ static bool list_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num, state->payload = payload; } #else - if (!encode_header_byte(state, ZCBOR_MAJOR_TYPE_PRIM, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { + (void)max_num; + (void)major_type; + if (!encode_header_byte(state, ZCBOR_MAJOR_TYPE_SIMPLE, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { ZCBOR_FAIL(); } #endif @@ -479,13 +428,13 @@ static bool list_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num, } -bool zcbor_list_end_encode(zcbor_state_t *state, uint_fast32_t max_num) +bool zcbor_list_end_encode(zcbor_state_t *state, size_t max_num) { return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_LIST); } -bool zcbor_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num) +bool zcbor_map_end_encode(zcbor_state_t *state, size_t max_num) { return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP); } @@ -499,45 +448,56 @@ bool zcbor_list_map_end_force_encode(zcbor_state_t *state) ZCBOR_FAIL(); } #endif + (void)state; return true; } +bool zcbor_simple_encode(zcbor_state_t *state, uint8_t *input) +{ + if (!value_encode(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, sizeof(*input))) { + zcbor_log("Error encoding %u (0x%p)\r\n", *input, input); + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_simple_put(zcbor_state_t *state, uint8_t input) +{ + return value_encode(state, ZCBOR_MAJOR_TYPE_SIMPLE, &input, sizeof(input)); +} + + bool zcbor_nil_put(zcbor_state_t *state, const void *unused) { (void)unused; - return primitive_put(state, 22); + return zcbor_simple_put(state, 22); } bool zcbor_undefined_put(zcbor_state_t *state, const void *unused) { (void)unused; - return primitive_put(state, 23); + return zcbor_simple_put(state, 23); } bool zcbor_bool_encode(zcbor_state_t *state, const bool *input) { - if (!primitive_put(state, (uint32_t)(*input + ZCBOR_BOOL_TO_PRIM))) { - ZCBOR_FAIL(); - } - return true; + return zcbor_bool_put(state, *input); } bool zcbor_bool_put(zcbor_state_t *state, bool input) { - if (!primitive_put(state, (uint32_t)(input + ZCBOR_BOOL_TO_PRIM))) { - ZCBOR_FAIL(); - } - return true; + return zcbor_simple_put(state, (!!input + ZCBOR_BOOL_TO_SIMPLE)); } bool zcbor_float64_encode(zcbor_state_t *state, const double *input) { - if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_PRIM, input, + if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, sizeof(*input))) { ZCBOR_FAIL(); } @@ -554,7 +514,7 @@ bool zcbor_float64_put(zcbor_state_t *state, double input) bool zcbor_float32_encode(zcbor_state_t *state, const float *input) { - if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_PRIM, input, + if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, sizeof(*input))) { ZCBOR_FAIL(); } @@ -569,7 +529,36 @@ bool zcbor_float32_put(zcbor_state_t *state, float input) } -bool zcbor_tag_encode(zcbor_state_t *state, uint32_t tag) +bool zcbor_float16_encode(zcbor_state_t *state, const float *input) +{ + return zcbor_float16_put(state, *input); +} + + +bool zcbor_float16_put(zcbor_state_t *state, float input) +{ + return zcbor_float16_bytes_put(state, zcbor_float32_to_16(input)); +} + + +bool zcbor_float16_bytes_encode(zcbor_state_t *state, const uint16_t *input) +{ + if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, + sizeof(*input))) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float16_bytes_put(zcbor_state_t *state, uint16_t input) +{ + return zcbor_float16_bytes_encode(state, &input); +} + + +bool zcbor_tag_put(zcbor_state_t *state, uint32_t tag) { if (!value_encode(state, ZCBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) { ZCBOR_FAIL(); @@ -580,13 +569,15 @@ bool zcbor_tag_encode(zcbor_state_t *state, uint32_t tag) } -bool zcbor_multi_encode_minmax(uint_fast32_t min_encode, - uint_fast32_t max_encode, - const uint_fast32_t *num_encode, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input, - uint_fast32_t result_len) +bool zcbor_tag_encode(zcbor_state_t *state, uint32_t *tag) +{ + return zcbor_tag_put(state, *tag); +} + + +bool zcbor_multi_encode_minmax(size_t min_encode, size_t max_encode, + const size_t *num_encode, zcbor_encoder_t encoder, + zcbor_state_t *state, const void *input, size_t result_len) { if ((*num_encode >= min_encode) && (*num_encode <= max_encode)) { @@ -596,34 +587,23 @@ bool zcbor_multi_encode_minmax(uint_fast32_t min_encode, } } -bool zcbor_multi_encode(uint_fast32_t num_encode, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input, - uint_fast32_t result_len) + +bool zcbor_multi_encode(const size_t num_encode, zcbor_encoder_t encoder, + zcbor_state_t *state, const void *input, size_t result_len) { ZCBOR_CHECK_ERROR(); - for (uint_fast32_t i = 0; i < num_encode; i++) { + for (size_t i = 0; i < num_encode; i++) { if (!encoder(state, (const uint8_t *)input + i*result_len)) { ZCBOR_FAIL(); } } - zcbor_print("Encoded %" PRIuFAST32 " elements.\n", num_encode); + zcbor_log("Encoded %zu elements.\n", num_encode); return true; } -bool zcbor_present_encode(const uint_fast32_t *present, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input) -{ - return zcbor_multi_encode(!!*present, encoder, state, input, 0); -} - - -void zcbor_new_encode_state(zcbor_state_t *state_array, uint_fast32_t n_states, - uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +void zcbor_new_encode_state(zcbor_state_t *state_array, size_t n_states, + uint8_t *payload, size_t payload_len, size_t elem_count) { - zcbor_new_state(state_array, n_states, payload, payload_len, elem_count); + zcbor_new_state(state_array, n_states, payload, payload_len, elem_count, NULL, 0); } From 0c539f6acb35adb5e29d2c8db0cfd3b325f91d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 10:31:58 +0100 Subject: [PATCH 02/38] [nrf fromtree] zcbor: Add copy notice to all copied files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And update script Signed-off-by: Øyvind Rønningstad (cherry picked from commit a899390056c93ee7bd12b0c76ab63832591800a5) (cherry picked from commit f29720be815b80c6f70c615836005cec8849a59d) --- boot/zcbor/add_zcbor_copy_version.sh | 2 ++ boot/zcbor/include/zcbor_common.h | 5 +++++ boot/zcbor/include/zcbor_decode.h | 5 +++++ boot/zcbor/include/zcbor_encode.h | 5 +++++ boot/zcbor/include/zcbor_print.h | 5 +++++ boot/zcbor/include/zcbor_tags.h | 5 +++++ boot/zcbor/src/zcbor_common.c | 5 +++++ boot/zcbor/src/zcbor_decode.c | 5 +++++ boot/zcbor/src/zcbor_encode.c | 5 +++++ 9 files changed, 42 insertions(+) diff --git a/boot/zcbor/add_zcbor_copy_version.sh b/boot/zcbor/add_zcbor_copy_version.sh index dc49887c0..a88ebf901 100755 --- a/boot/zcbor/add_zcbor_copy_version.sh +++ b/boot/zcbor/add_zcbor_copy_version.sh @@ -20,3 +20,5 @@ add_copy_notice src/zcbor_common.c "copied" add_copy_notice include/zcbor_decode.h "copied" add_copy_notice include/zcbor_encode.h "copied" add_copy_notice include/zcbor_common.h "copied" +add_copy_notice include/zcbor_print.h "copied" +add_copy_notice include/zcbor_tags.h "copied" diff --git a/boot/zcbor/include/zcbor_common.h b/boot/zcbor/include/zcbor_common.h index 879889713..0bf81c9c2 100644 --- a/boot/zcbor/include/zcbor_common.h +++ b/boot/zcbor/include/zcbor_common.h @@ -1,3 +1,8 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * diff --git a/boot/zcbor/include/zcbor_decode.h b/boot/zcbor/include/zcbor_decode.h index 61a6f1763..4cc2c19bd 100644 --- a/boot/zcbor/include/zcbor_decode.h +++ b/boot/zcbor/include/zcbor_decode.h @@ -1,3 +1,8 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * diff --git a/boot/zcbor/include/zcbor_encode.h b/boot/zcbor/include/zcbor_encode.h index 89b0a97bf..68741d147 100644 --- a/boot/zcbor/include/zcbor_encode.h +++ b/boot/zcbor/include/zcbor_encode.h @@ -1,3 +1,8 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * diff --git a/boot/zcbor/include/zcbor_print.h b/boot/zcbor/include/zcbor_print.h index 18f8656c5..22a5637d3 100644 --- a/boot/zcbor/include/zcbor_print.h +++ b/boot/zcbor/include/zcbor_print.h @@ -1,3 +1,8 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.0 + */ + /* * Copyright (c) 2023 Nordic Semiconductor ASA * diff --git a/boot/zcbor/include/zcbor_tags.h b/boot/zcbor/include/zcbor_tags.h index 89148776c..1cf811d9a 100644 --- a/boot/zcbor/include/zcbor_tags.h +++ b/boot/zcbor/include/zcbor_tags.h @@ -1,3 +1,8 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.0 + */ + /* * Copyright (c) 2022 Nordic Semiconductor ASA * diff --git a/boot/zcbor/src/zcbor_common.c b/boot/zcbor/src/zcbor_common.c index 1caf80668..f1a039e52 100644 --- a/boot/zcbor/src/zcbor_common.c +++ b/boot/zcbor/src/zcbor_common.c @@ -1,3 +1,8 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * diff --git a/boot/zcbor/src/zcbor_decode.c b/boot/zcbor/src/zcbor_decode.c index 92f9fe517..5f7e0e15d 100644 --- a/boot/zcbor/src/zcbor_decode.c +++ b/boot/zcbor/src/zcbor_decode.c @@ -1,3 +1,8 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * diff --git a/boot/zcbor/src/zcbor_encode.c b/boot/zcbor/src/zcbor_encode.c index 44411ea35..9859d6818 100644 --- a/boot/zcbor/src/zcbor_encode.c +++ b/boot/zcbor/src/zcbor_encode.c @@ -1,3 +1,8 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * From fc20e9bb80c3acf8b82b4d0921da0f02d3b0b355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 10:43:18 +0100 Subject: [PATCH 03/38] [nrf fromtree] boot_serial: Adapt to API changes in zcbor 0.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New arguments in zcbor_new_state are set to NULL/0 because they are only needed when using the zcbor_unordered_map API. Signed-off-by: Øyvind Rønningstad (cherry picked from commit 63ddb71d51ccba575dc227656a01255cb97fc327) (cherry picked from commit b16b1a945b5de381d6b66b0762b01c9e99d7fb19) --- boot/boot_serial/src/boot_serial.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 5213866ad..9f486a230 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -437,7 +437,7 @@ bs_set(char *buf, int len) #endif zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); struct zcbor_map_decode_key_val image_set_state_decode[] = { ZCBOR_MAP_DECODE_KEY_DECODER("confirm", zcbor_bool_decode, &confirm), @@ -655,7 +655,7 @@ bs_upload(char *buf, int len) #endif zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); struct zcbor_map_decode_key_val image_upload_decode[] = { ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num_tmp), @@ -908,7 +908,7 @@ bs_echo(char *buf, int len) uint32_t rc = MGMT_ERR_EINVAL; zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); if (!zcbor_map_start_decode(zsd)) { goto out; From e5d5708fe33e827abd4e664978b47e31c73638d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Fri, 26 Jan 2024 14:41:53 +0100 Subject: [PATCH 04/38] [nrf fromtree] zcbor: Copy source and header files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit from zcbor 0.8.1 Signed-off-by: Øyvind Rønningstad (cherry picked from commit c8d213a9a100381da81db822fbd6728733459235) (cherry picked from commit ff23755756b3a47b5ec748fed9a040fc93127e0c) --- boot/zcbor/include/zcbor_common.h | 21 ++++++++++++++++++++- boot/zcbor/include/zcbor_decode.h | 2 +- boot/zcbor/include/zcbor_encode.h | 2 +- boot/zcbor/include/zcbor_print.h | 24 ++++++++++++++---------- boot/zcbor/include/zcbor_tags.h | 2 +- boot/zcbor/src/zcbor_common.c | 2 +- boot/zcbor/src/zcbor_decode.c | 2 +- boot/zcbor/src/zcbor_encode.c | 2 +- 8 files changed, 40 insertions(+), 17 deletions(-) diff --git a/boot/zcbor/include/zcbor_common.h b/boot/zcbor/include/zcbor_common.h index 0bf81c9c2..0583ab893 100644 --- a/boot/zcbor/include/zcbor_common.h +++ b/boot/zcbor/include/zcbor_common.h @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.8.0 + * Commit zcbor 0.8.1 */ /* @@ -22,6 +22,23 @@ extern "C" { #endif +#define ZCBOR_STRINGIFY_PRE(x) #x +#define ZCBOR_STRINGIFY(s) ZCBOR_STRINGIFY_PRE(s) + +#define ZCBOR_VERSION_MAJOR 0 +#define ZCBOR_VERSION_MINOR 8 +#define ZCBOR_VERSION_BUGFIX 1 + +/** The version string with dots and not prefix. */ +#define ZCBOR_VERSION_STR ZCBOR_STRINGIFY(ZCBOR_VERSION_MAJOR) \ + "." ZCBOR_STRINGIFY(ZCBOR_VERSION_MINOR) \ + "." ZCBOR_STRINGIFY(ZCBOR_VERSION_BUGFIX) + +/** Monotonically increasing integer representing the version. */ +#define ZCBOR_VERSION ((ZCBOR_VERSION_MAJOR << 24) \ + + (ZCBOR_VERSION_MINOR << 16) \ + + (ZCBOR_VERSION_BUGFIX << 8)) + /** Convenience type that allows pointing to strings directly inside the payload * without the need to copy out. */ @@ -488,6 +505,8 @@ static inline size_t zcbor_flags_to_states(size_t num_flags) #define ZCBOR_FLAG_STATES(n_flags) 0 #endif +size_t strnlen(const char *, size_t); + #ifdef __cplusplus } #endif diff --git a/boot/zcbor/include/zcbor_decode.h b/boot/zcbor/include/zcbor_decode.h index 4cc2c19bd..e5a58d82c 100644 --- a/boot/zcbor/include/zcbor_decode.h +++ b/boot/zcbor/include/zcbor_decode.h @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.8.0 + * Commit zcbor 0.8.1 */ /* diff --git a/boot/zcbor/include/zcbor_encode.h b/boot/zcbor/include/zcbor_encode.h index 68741d147..5139d3ca3 100644 --- a/boot/zcbor/include/zcbor_encode.h +++ b/boot/zcbor/include/zcbor_encode.h @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.8.0 + * Commit zcbor 0.8.1 */ /* diff --git a/boot/zcbor/include/zcbor_print.h b/boot/zcbor/include/zcbor_print.h index 22a5637d3..6ab6d453d 100644 --- a/boot/zcbor/include/zcbor_print.h +++ b/boot/zcbor/include/zcbor_print.h @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.8.0 + * Commit zcbor 0.8.1 */ /* @@ -93,10 +93,12 @@ static void zcbor_print_compare_lines(const uint8_t *str1, const uint8_t *str2, __attribute__((used)) static void zcbor_print_compare_strings(const uint8_t *str1, const uint8_t *str2, uint32_t size) { - for (uint32_t i = 0; i <= size / 16; i++) { - zcbor_do_print("line %d (char %d)\r\n", i, i*16); - zcbor_print_compare_lines(&str1[i*16], &str2[i*16], - MIN(16, (size - i*16))); + const size_t col_width = 16; + + for (size_t i = 0; i <= size / col_width; i++) { + zcbor_do_print("line %zu (char %zu)\r\n", i, i*col_width); + zcbor_print_compare_lines(&str1[i*col_width], &str2[i*col_width], + MIN(col_width, (size - i*col_width))); } zcbor_do_print("\r\n"); } @@ -104,12 +106,14 @@ static void zcbor_print_compare_strings(const uint8_t *str1, const uint8_t *str2 __attribute__((used)) static void zcbor_print_compare_strings_diff(const uint8_t *str1, const uint8_t *str2, uint32_t size) { + const size_t col_width = 16; bool printed = false; - for (uint32_t i = 0; i <= size / 16; i++) { - if (memcmp(&str1[i*16], &str2[i*16], MIN(16, (size - i*16))) != 0) { - zcbor_do_print("line %d (char %d)\r\n", i, i*16); - zcbor_print_compare_lines(&str1[i*16], &str2[i*16], - MIN(16, (size - i*16))); + + for (size_t i = 0; i <= size / col_width; i++) { + if (memcmp(&str1[i*col_width], &str2[i*col_width], MIN(col_width, (size - i*col_width))) != 0) { + zcbor_do_print("line %zu (char %zu)\r\n", i, i*col_width); + zcbor_print_compare_lines(&str1[i*col_width], &str2[i*col_width], + MIN(col_width, (size - i*col_width))); printed = true; } } diff --git a/boot/zcbor/include/zcbor_tags.h b/boot/zcbor/include/zcbor_tags.h index 1cf811d9a..d17e8b348 100644 --- a/boot/zcbor/include/zcbor_tags.h +++ b/boot/zcbor/include/zcbor_tags.h @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.8.0 + * Commit zcbor 0.8.1 */ /* diff --git a/boot/zcbor/src/zcbor_common.c b/boot/zcbor/src/zcbor_common.c index f1a039e52..af93e7ff4 100644 --- a/boot/zcbor/src/zcbor_common.c +++ b/boot/zcbor/src/zcbor_common.c @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.8.0 + * Commit zcbor 0.8.1 */ /* diff --git a/boot/zcbor/src/zcbor_decode.c b/boot/zcbor/src/zcbor_decode.c index 5f7e0e15d..841c34171 100644 --- a/boot/zcbor/src/zcbor_decode.c +++ b/boot/zcbor/src/zcbor_decode.c @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.8.0 + * Commit zcbor 0.8.1 */ /* diff --git a/boot/zcbor/src/zcbor_encode.c b/boot/zcbor/src/zcbor_encode.c index 9859d6818..53d19c01f 100644 --- a/boot/zcbor/src/zcbor_encode.c +++ b/boot/zcbor/src/zcbor_encode.c @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.8.0 + * Commit zcbor 0.8.1 */ /* From 9e03ad4333fa5e9d5f714466571d27558ce49593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Mon, 29 Jan 2024 11:37:45 +0100 Subject: [PATCH 05/38] [nrf fromtree] boot_serial: Adapt to zcbor 0.8.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change one _term to _lit that was missed earlier. Signed-off-by: Øyvind Rønningstad (cherry picked from commit 205d7e5b4194fd8c6e3219771e439048973e4984) (cherry picked from commit 55a0f64dbdbead3b8a9120af6e23f20e3521a37a) --- boot/boot_serial/src/boot_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 9f486a230..988817fc1 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -932,7 +932,7 @@ bs_echo(char *buf, int len) } zcbor_map_start_encode(cbor_state, 10); - zcbor_tstr_put_term(cbor_state, "r"); + zcbor_tstr_put_lit(cbor_state, "r"); if (zcbor_tstr_encode(cbor_state, &value) && zcbor_map_end_encode(cbor_state, 10)) { boot_serial_output(); return; From df01761e611675db3cd1bff183243be4e318d8bc Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Tue, 9 Jan 2024 08:30:58 +0100 Subject: [PATCH 06/38] [nrf fromtree] boot: zephyr: moonlight watchdogs adding WATCHDOG_FEED support for WDT30 and WDT31 Signed-off-by: Mateusz Michalek (cherry picked from commit c3a72e9daf8f94a7c3b0dc91cc19e2bb15b7110a) Signed-off-by: Andrzej Puzdrowski (cherry picked from commit b2b1677503972c55aff0a839b5c53ed5163d2250) --- boot/zephyr/Kconfig | 3 +++ .../include/mcuboot_config/mcuboot_config.h | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 78fe793ed..2dec368eb 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1,5 +1,6 @@ # Copyright (c) 2017-2020 Linaro Limited # Copyright (c) 2020 Arm Limited +# Copyright (c) 2023 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 # @@ -649,6 +650,8 @@ config BOOT_WATCHDOG_FEED imply NRFX_WDT if SOC_FAMILY_NRF imply NRFX_WDT0 if SOC_FAMILY_NRF imply NRFX_WDT1 if SOC_FAMILY_NRF + imply NRFX_WDT30 if SOC_FAMILY_NRF + imply NRFX_WDT31 if SOC_FAMILY_NRF help Enables implementation of MCUBOOT_WATCHDOG_FEED() macro which is used to feed watchdog while doing time consuming operations. diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 04e4c599c..536977135 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -325,9 +325,21 @@ #elif defined(CONFIG_NRFX_WDT0) #define MCUBOOT_WATCHDOG_FEED() \ FEED_WDT_INST(0); -#else /* defined(CONFIG_NRFX_WDT0) && defined(CONFIG_NRFX_WDT1) */ +#elif defined(CONFIG_NRFX_WDT30) && defined(CONFIG_NRFX_WDT31) +#define MCUBOOT_WATCHDOG_FEED() \ + do { \ + FEED_WDT_INST(30); \ + FEED_WDT_INST(31); \ + } while (0) +#elif defined(CONFIG_NRFX_WDT30) +#define MCUBOOT_WATCHDOG_FEED() \ + FEED_WDT_INST(30); +#elif defined(CONFIG_NRFX_WDT31) +#define MCUBOOT_WATCHDOG_FEED() \ + FEED_WDT_INST(31); +#else #error "No NRFX WDT instances enabled" -#endif /* defined(CONFIG_NRFX_WDT0) && defined(CONFIG_NRFX_WDT1) */ +#endif #elif DT_NODE_HAS_STATUS(DT_ALIAS(watchdog0), okay) /* CONFIG_NRFX_WDT */ #include From 27fc8d720f424ad1ce4744a51fde536a30a7bf60 Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Wed, 22 Nov 2023 15:20:52 +0000 Subject: [PATCH 07/38] [nrf fromtree] zephyr: Add NRF54L configuration Adds default Kconfig configuration that allows to build MCUboot for NRF54L. Currently this configuration turns off WDT and FPROTECT, which is TODO to fix. Signed-off-by: Dominik Ermel Signed-off-by: Mateusz Michalek (cherry picked from commit 4b4cc85c67bf5689ce0b35d088ca7f35809b5a82) Signed-off-by: Andrzej Puzdrowski (cherry picked from commit 73e110649932844a6defd0e5c557c4796853d740) --- boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf diff --git a/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf new file mode 100644 index 000000000..59a549113 --- /dev/null +++ b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_BOOT_MAX_IMG_SECTORS=256 + +# Ensure that the qspi driver is disabled by default +CONFIG_NORDIC_QSPI_NOR=n + +# TODO: below are not yet supported and need fixing +CONFIG_FPROTECT=n +CONFIG_BOOT_WATCHDOG_FEED=n From 6a9b75f77d290267e4d79ac9d99c083e3ef797a3 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 15 Feb 2024 17:01:36 +0100 Subject: [PATCH 08/38] [nrf fromlist] zephyr/boards: nrf54l15pdk_nrf54l15_cpuapp config Upstream PR: https://github.com/mcu-tools/mcuboot/pull/1901 Renamed the DK config file to proper name. Signed-off-by: Andrzej Puzdrowski (cherry picked from commit bd1464f69934ff37f91321da397fb1398907c946) (cherry picked from commit 42a1eb615ce1f177a305d539eda9485598d48a65) --- ...15dk_nrf54l15_cpuapp.conf => nrf54l15pdk_nrf54l15_cpuapp.conf} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename boot/zephyr/boards/{nrf54l15dk_nrf54l15_cpuapp.conf => nrf54l15pdk_nrf54l15_cpuapp.conf} (100%) diff --git a/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf b/boot/zephyr/boards/nrf54l15pdk_nrf54l15_cpuapp.conf similarity index 100% rename from boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf rename to boot/zephyr/boards/nrf54l15pdk_nrf54l15_cpuapp.conf From f82a032307f5521a06e74100ca724615a731b29a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 1 Feb 2024 11:59:24 +0000 Subject: [PATCH 09/38] [nrf fromtree] boot: Fix swap-move algorithm failing to validate multi-image In multi image swap validation of images could fail due to headers being incorrectly re-read from storage. Fixes #1768 Signed-off-by: Dominik Ermel (cherry picked from commit 6f7f87384da1e701700b2f436fc49441f693a346) (cherry picked from commit cb64eca4df86554a8da61e23d8fe4469257ff8be) --- boot/bootutil/src/loader.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8bbabbbac..b046d86ab 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -4,6 +4,7 @@ * Copyright (c) 2016-2020 Linaro LTD * Copyright (c) 2016-2019 JUUL Labs * Copyright (c) 2019-2023 Arm Limited + * Copyright (c) 2024 Nordic Semiconductor ASA * * Original license: * @@ -2207,8 +2208,13 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) { /* Attempt to read an image header from each slot. Ensure that image * headers in slots are aligned with headers in boot_data. + * Note: Quite complicated internal logic of boot_read_image_headers + * uses boot state, the last parm, to figure out in which slot which + * header is located; when boot state is not provided, then it + * is assumed that headers are at proper slots (we are not in + * the middle of moving images, etc). */ - rc = boot_read_image_headers(state, false, &bs); + rc = boot_read_image_headers(state, false, NULL); if (rc != 0) { FIH_SET(fih_rc, FIH_FAILURE); goto out; From 4d7e56873401a882867cc7fb2410a16e73eca9a4 Mon Sep 17 00:00:00 2001 From: Thomas Stilwell Date: Fri, 23 Nov 2018 15:37:52 +0100 Subject: [PATCH 10/38] [nrf noup] ci: add downstream-only NCS customizations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Jenkinsfile, .gitlint, and backport workflow files. Signed-off-by: Thomas Stilwell Signed-off-by: Ulrich Myhre Signed-off-by: Chris Bittner Signed-off-by: Martí Bolívar Signed-off-by: Andrzej Puzdrowski Signed-off-by: Johann Fischer Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae (cherry picked from commit 39f179d96df48be823c9a646716a74f281a9d302) --- .github/workflows/backport.yml | 19 ++++++++++++ .gitlint | 57 ++++++++++++++++++++++++++++++++++ Jenkinsfile | 6 ++++ 3 files changed, 82 insertions(+) create mode 100644 .github/workflows/backport.yml create mode 100644 .gitlint create mode 100644 Jenkinsfile diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 000000000..a6f3a2d5d --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,19 @@ +name: Backport +on: + pull_request: + types: + - closed + - labeled + +jobs: + backport: + runs-on: ubuntu-18.04 + name: Backport + steps: + - name: Backport Bot + uses: Gaurav0/backport@v1.0.24 + with: + bot_username: NordicBuilder + bot_token: 151a9b45052f9ee8be5a59963d31ad7b92c3ecb5 + bot_token_key: 67bb1f1f998d546859786a4088917c65415c0ebd + github_token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitlint b/.gitlint new file mode 100644 index 000000000..512813bbb --- /dev/null +++ b/.gitlint @@ -0,0 +1,57 @@ +# All these sections are optional, edit this file as you like. +[general] +ignore=title-trailing-punctuation, T3, title-max-length, T1, body-hard-tab, B3, B1 +# verbosity should be a value between 1 and 3, the commandline -v flags take precedence over this +verbosity = 3 +# By default gitlint will ignore merge commits. Set to 'false' to disable. +ignore-merge-commits=true +# Enable debug mode (prints more output). Disabled by default +debug = false + +# Set the extra-path where gitlint will search for user defined rules +# See http://jorisroovers.github.io/gitlint/user_defined_rules for details +extra-path=../../zephyr/scripts/gitlint + +[title-max-length-no-revert] +line-length=72 + +[body-min-line-count] +min-line-count=1 + +[body-max-line-count] +max-line-count=200 + +[title-starts-with-subsystem] +regex = ^(?!subsys:)(([^:]+):)(\s([^:]+):)*\s(.+)$ + +[title-must-not-contain-word] +# Comma-separated list of words that should not occur in the title. Matching is case +# insensitive. It's fine if the keyword occurs as part of a larger word (so "WIPING" +# will not cause a violation, but "WIP: my title" will. +words=wip + +[title-match-regex] +# python like regex (https://docs.python.org/2/library/re.html) that the +# commit-msg title must be matched to. +# Note that the regex can contradict with other rules if not used correctly +# (e.g. title-must-not-contain-word). +#regex=^US[0-9]* + +[max-line-length-with-exceptions] +# B1 = body-max-line-length +line-length=72 + +[body-min-length] +min-length=3 + +[body-is-missing] +# Whether to ignore this rule on merge commits (which typically only have a title) +# default = True +ignore-merge-commits=false + +[body-changed-file-mention] +# List of files that need to be explicitly mentioned in the body when they are changed +# This is useful for when developers often erroneously edit certain files or git submodules. +# By specifying this rule, developers can only change the file when they explicitly reference +# it in the commit message. +#files=gitlint/rules.py,README.md diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000..8220afe03 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,6 @@ +@Library("CI_LIB") _ + +def pipeline = new ncs.sdk_mcuboot.Main() + +pipeline.run(JOB_NAME) + From 786e351400566f69289eace77f215a6376b851d9 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 10 Oct 2023 15:51:54 +0200 Subject: [PATCH 11/38] [nrf noup] github: Add a commit tags check workflow Use the generic commit-tags action to provide sauce tag checks. Signed-off-by: Carles Cufi (cherry picked from commit d9ed9a66db1909166aa1a74f59754788a05343f5) --- .github/workflows/commit-tags.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/commit-tags.yml diff --git a/.github/workflows/commit-tags.yml b/.github/workflows/commit-tags.yml new file mode 100644 index 000000000..9e0323f94 --- /dev/null +++ b/.github/workflows/commit-tags.yml @@ -0,0 +1,31 @@ +name: Commit tags + +on: pull_request + +jobs: + commit_tags: + runs-on: ubuntu-22.04 + name: Run commit tags checks on patch series (PR) + steps: + - name: Update PATH for west + run: | + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Checkout the code + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: Install python dependencies + run: | + pip3 install setuptools + pip3 install wheel + pip3 install gitlint + + - name: Run the commit tags + uses: nrfconnect/action-commit-tags@main + with: + target: '.' + baserev: origin/${{ github.base_ref }} + revrange: 'none' From 5c94965afb7c8f8d1866ce2079e72f80bc889d1a Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 26 Mar 2019 15:42:38 +0100 Subject: [PATCH 12/38] [nrf noup] zephyr: Remove duplication from cmake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the `add_subdirectory` of nrfxlib it will still check that the nrfxlib is located outside the mcuboot directory. Signed-off-by: Sigvart Hovland Signed-off-by: Andrzej Puzdrowski Signed-off-by: Martí Bolívar Signed-off-by: Emil Obalski Signed-off-by: Andrzej Puzdrowski Signed-off-by: Håkon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit cf90d556d959bddcbddbe5a7a8e25692c9727789) --- boot/zephyr/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index ad4c823f2..9a3a59914 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -41,8 +41,6 @@ if(NOT EXISTS ${NRFXLIB_DIR}) To use the tinycrypt set `CONFIG_BOOT_ECDSA_TINYCRYPT` to y. ------------------------------------------------------------------------") endif() -# Don't include this if we are using west - add_subdirectory(${NRFXLIB_DIR} ${PROJECT_BINARY_DIR}/nrfxlib) endif() zephyr_library_include_directories( From 64740f7c95ca8b7b090086077876670edb95716b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 3 Sep 2021 14:38:54 -0700 Subject: [PATCH 13/38] [nrf noup] zephyr: add 'minimal' configuration files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add prj_minimal.conf, a Kconfig fragment to be used for minimally sized image production. The minimal fragment has been simplified for only external crypto. Move partition sizing into Kconfig to be consistent with the method used by b0. Using this fragment with prj_minimal.conf makes MCUboot < 16kB for all nRF devices (9160 still needs 32kB partition). Ref: NCSDK-6704 Signed-off-by: Stephen Stauts Signed-off-by: Martí Bolívar Signed-off-by: Sebastian Bøe Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 5b6e0b28ba96b47a0eb609a7c38b81020645392e) --- .../nrf5340dk_nrf5340_cpuapp_minimal.conf | 13 ++++++ boot/zephyr/prj_minimal.conf | 41 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf create mode 100644 boot/zephyr/prj_minimal.conf diff --git a/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf b/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf new file mode 100644 index 000000000..dd5468106 --- /dev/null +++ b/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf @@ -0,0 +1,13 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# CC3xx is currently not used for nrf53 +CONFIG_HW_CC3XX=n +CONFIG_NRF_CC3XX_PLATFORM=n + +# Required for kernel operation +CONFIG_CLOCK_CONTROL=y +CONFIG_SYS_CLOCK_EXISTS=y diff --git a/boot/zephyr/prj_minimal.conf b/boot/zephyr/prj_minimal.conf new file mode 100644 index 000000000..1f90e708b --- /dev/null +++ b/boot/zephyr/prj_minimal.conf @@ -0,0 +1,41 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_MAIN_STACK_SIZE=10240 +CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" + +CONFIG_FLASH=y +CONFIG_FPROTECT=y +CONFIG_PM=n + +CONFIG_BOOT_SWAP_SAVE_ENCTLV=n +CONFIG_BOOT_ENCRYPT_IMAGE=n + +CONFIG_BOOT_BOOTSTRAP=n +CONFIG_BOOT_UPGRADE_ONLY=n + +### Minimal Configurations ### +CONFIG_BOOT_USE_MIN_PARTITION_SIZE=y +CONFIG_ASSERT=n +CONFIG_BOOT_BANNER=n +CONFIG_CLOCK_CONTROL=n +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_GPIO=n +CONFIG_KERNEL_MEM_POOL=n +CONFIG_LOG=n +CONFIG_MINIMAL_LIBC_CALLOC=n +CONFIG_MINIMAL_LIBC_MALLOC=n +CONFIG_MINIMAL_LIBC_REALLOCARRAY=n +CONFIG_NCS_SAMPLES_DEFAULTS=n +CONFIG_NO_RUNTIME_CHECKS=y +CONFIG_NRF_RTC_TIMER=n +CONFIG_PRINTK=n +CONFIG_SECURE_BOOT_DEBUG=n +CONFIG_SERIAL=n +CONFIG_SIZE_OPTIMIZATIONS=y +CONFIG_SYS_CLOCK_EXISTS=n +CONFIG_UART_CONSOLE=n From de32681f8b9f6c27243a010752a9230662bf4db4 Mon Sep 17 00:00:00 2001 From: Bernt Johan Damslora Date: Fri, 20 Sep 2019 18:25:41 +0200 Subject: [PATCH 14/38] [nrf noup] boards: add support for Thingy:91 Adds project configurations for the two systems on the Thingy:91 (PCA-20035) board. The bootloader that is factory-programmed on thing91 does not support ECDSA signature type. Hence this commit also sets the signature type to RSA for applications built for Thingy:91. Signed-off-by: Bernt Johan Damslora Signed-off-by: Sigvart Hovland Signed-off-by: Jon Helge Nistad Signed-off-by: Balaji Srinivasan Signed-off-by: Robert Lubos Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Marek Pieta Signed-off-by: Dominik Ermel (cherry picked from commit 74bb73a6ee6ea35d9d1cb5b786c7e468f123f7e1) --- boot/zephyr/boards/thingy91_nrf52840.conf | 34 +++++++++++++++++++++++ boot/zephyr/boards/thingy91_nrf9160.conf | 13 +++++++++ 2 files changed, 47 insertions(+) create mode 100644 boot/zephyr/boards/thingy91_nrf52840.conf create mode 100644 boot/zephyr/boards/thingy91_nrf9160.conf diff --git a/boot/zephyr/boards/thingy91_nrf52840.conf b/boot/zephyr/boards/thingy91_nrf52840.conf new file mode 100644 index 000000000..c0d183401 --- /dev/null +++ b/boot/zephyr/boards/thingy91_nrf52840.conf @@ -0,0 +1,34 @@ +# Disable Zephyr console +CONFIG_LOG=n +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n + +# The build won't fit on the partition allocated for it without size +# optimizations. +CONFIG_SIZE_OPTIMIZATIONS=y +CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x12000 + +# Serial +CONFIG_SERIAL=y +CONFIG_UART_NRFX=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_LINE_CTRL=y + +# MCUboot serial recovery +CONFIG_GPIO=y +CONFIG_MCUBOOT_SERIAL=y +CONFIG_BOOT_SERIAL_CDC_ACM=y + +# Required by USB +CONFIG_MULTITHREADING=y + +# USB +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_PRODUCT="MCUBOOT" +CONFIG_USB_CDC_ACM=y +CONFIG_USB_COMPOSITE_DEVICE=y +CONFIG_USB_MASS_STORAGE=n +CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor" +CONFIG_USB_DEVICE_VID=0x1915 +CONFIG_USB_DEVICE_PID=0x520F diff --git a/boot/zephyr/boards/thingy91_nrf9160.conf b/boot/zephyr/boards/thingy91_nrf9160.conf new file mode 100644 index 000000000..1bf2e424d --- /dev/null +++ b/boot/zephyr/boards/thingy91_nrf9160.conf @@ -0,0 +1,13 @@ +# Disable Zephyr console +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n + +# Disable Flash protection +CONFIG_FPROTECT=n + +# MCUBoot settings +CONFIG_BOOT_MAX_IMG_SECTORS=256 + +# MCUboot serial recovery +CONFIG_MCUBOOT_SERIAL=y From 5cf84236543ce031afe121c0b1111ff548e104d1 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 30 Mar 2021 22:45:17 +0200 Subject: [PATCH 15/38] [nrf noup] loader: work-around for multi-image builds Seems multi-image dependencies are not supported for multi-image in NCS yet. This is a workaround which reverts some lines to restore previous MCUboot behavior, so that Immutable bootloader + MCUBoot type builds will work. Ref. NCSDK-8681 Signed-off-by: Sigvart Hovland Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit e02925a085a107284cb1329742b43859d40afb37) --- boot/bootutil/src/loader.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index b046d86ab..b2ea9ddb0 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1530,7 +1530,7 @@ boot_verify_dependencies(struct boot_loader_state *state) if (rc == 0) { /* All dependencies've been satisfied, continue with next image. */ BOOT_CURR_IMG(state)++; - } else { + } else if (rc == BOOT_EBADIMAGE) { /* Cannot upgrade due to non-met dependencies, so disable all * image upgrades. */ @@ -1539,7 +1539,10 @@ boot_verify_dependencies(struct boot_loader_state *state) BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE; } break; - } + } else { + /* Other error happened, images are inconsistent */ + return rc; + } } return rc; } From 55683e3133b6a801a7bb7feb55d24be81ecccdbb Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Thu, 14 Feb 2019 13:20:34 +0100 Subject: [PATCH 16/38] [nrf noup] boot: Add shared crypto for ECDSA and SHA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add functions for ecdsa_verify_secp256r1 and sha256 to use the shared crypto API * Add Kconfig and CMake variables for selecting shared crypto when using ecdsa * Add custom section to project for placing the API section in the correct location in flash * Add kconfig fragment for using external crypto Signed-off-by: Sigvart Hovland Signed-off-by: Martí Bolívar Signed-off-by: Emil Obalski Signed-off-by: Andrzej Puzdrowski Signed-off-by: Håkon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Trond Einar Snekvik Signed-off-by: Georgios Vasilakis Signed-off-by: Johann Fischer Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 5f71e809d526f568b2b657d9f7f21ccf8e7d2f89) (cherry picked from commit beebb23f8e2d744ef89819e584928377ef6c444a) --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 43 +++++++++++++++++++ boot/bootutil/include/bootutil/crypto/sha.h | 32 ++++++++++++++ boot/zephyr/CMakeLists.txt | 2 + boot/zephyr/external_crypto.conf | 20 +++++++++ .../include/mcuboot_config/mcuboot_config.h | 5 +-- 5 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 boot/zephyr/external_crypto.conf diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index a73388622..5ffb3272d 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -34,6 +34,7 @@ #if (defined(MCUBOOT_USE_TINYCRYPT) + \ defined(MCUBOOT_USE_CC310) + \ + defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \ defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1 #error "One crypto backend must be defined: either CC310/TINYCRYPT/MBED_TLS/PSA_CRYPTO" #endif @@ -70,6 +71,11 @@ #include "bootutil/sign_key.h" #include "common.h" +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + #include + #define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8) +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus extern "C" { #endif @@ -594,6 +600,43 @@ static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) +typedef uintptr_t bootutil_ecdsa_p256_context; + +static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx) +{ + (void)ctx; +} + +static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx) +{ + (void)ctx; +} + +static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, + uint8_t *pk, size_t pk_len, + uint8_t *hash, + uint8_t *sig, size_t sig_len) +{ + (void)ctx; + (void)pk_len; + (void)sig_len; + + /* As described on the compact representation in IETF protocols, + * the first byte of the key defines if the ECC points are + * compressed (0x2 or 0x3) or uncompressed (0x4). + * We only support uncompressed keys. + */ + if (pk[0] != 0x04) + return -1; + + pk++; + + return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, + pk, sig); +} +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/include/bootutil/crypto/sha.h b/boot/bootutil/include/bootutil/crypto/sha.h index 9ce54bee5..28e827fea 100644 --- a/boot/bootutil/include/bootutil/crypto/sha.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -30,6 +30,7 @@ #if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS) + \ defined(MCUBOOT_USE_TINYCRYPT) + \ + defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \ defined(MCUBOOT_USE_CC310)) != 1 #error "One crypto backend must be defined: either CC310/MBED_TLS/TINYCRYPT/PSA_CRYPTO" #endif @@ -206,6 +207,37 @@ static inline int bootutil_sha_finish(bootutil_sha_context *ctx, } #endif /* MCUBOOT_USE_CC310 */ +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + +#include + +typedef bl_sha256_ctx_t bootutil_sha_context; + +static inline void bootutil_sha_init(bootutil_sha_context *ctx) +{ + bl_sha256_init(ctx); +} + +static inline void bootutil_sha_drop(bootutil_sha_context *ctx) +{ + (void)ctx; +} + +static inline int bootutil_sha_update(bootutil_sha_context *ctx, + const void *data, + uint32_t data_len) +{ + return bl_sha256_update(ctx, data, data_len); +} + +static inline int bootutil_sha_finish(bootutil_sha_context *ctx, + uint8_t *output) +{ + bl_sha256_finalize(ctx, output); + return 0; +} +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus } #endif diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 9a3a59914..14a891f34 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -165,6 +165,8 @@ if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) zephyr_library_sources(${NRF_DIR}/cc310_glue.c) zephyr_library_include_directories(${NRF_DIR}) zephyr_link_libraries(nrfxlib_crypto) + elseif(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) + zephyr_include_directories(${BL_CRYPTO_DIR}/../include) endif() # Since here we are not using Zephyr's mbedTLS but rather our own, we need diff --git a/boot/zephyr/external_crypto.conf b/boot/zephyr/external_crypto.conf new file mode 100644 index 000000000..8181ad51c --- /dev/null +++ b/boot/zephyr/external_crypto.conf @@ -0,0 +1,20 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# These configurations should be used when using nrf/samples/bootloader +# as the immutable bootloader (B0), and MCUBoot as the second stage updateable +# bootloader. + +# Set ECDSA as signing mechanism +CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y + +# Use crypto backend from B0 +CONFIG_BOOT_NRF_EXTERNAL_CRYPTO=y +CONFIG_SECURE_BOOT_CRYPTO=y +CONFIG_SB_CRYPTO_CLIENT_ECDSA_SECP256R1=y +CONFIG_SB_CRYPTO_CLIENT_SHA256=y +CONFIG_BL_SHA256_EXT_API_REQUIRED=y +CONFIG_BL_SECP256R1_EXT_API_REQUIRED=y diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 536977135..375088741 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -40,9 +40,8 @@ #define MCUBOOT_USE_TINYCRYPT #elif defined(CONFIG_BOOT_USE_CC310) #define MCUBOOT_USE_CC310 -#ifdef CONFIG_BOOT_USE_NRF_CC310_BL -#define MCUBOOT_USE_NRF_CC310_BL -#endif +#elif defined(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) +#define MCUBOOT_USE_NRF_EXTERNAL_CRYPTO #endif /* Zephyr, regardless of C library used, provides snprintf */ From ba5556128b083ddbaee46ec09fb22c6f743c9205 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 21 Apr 2023 15:45:00 +0000 Subject: [PATCH 17/38] [nrf noup] crypto: ecdsa: Add required signature decoding The CC310 and bl_crypto require decoded signature instead of raw ASN.1 Signed-off-by: Dominik Ermel (cherry picked from commit 685c58eedb98520123d634222c3f38fff1faafe7) --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 5ffb3272d..e62f3d606 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -133,8 +133,6 @@ static int bootutil_import_key(uint8_t **cp, uint8_t *end) } #endif /* (MCUBOOT_USE_TINYCRYPT || MCUBOOT_USE_MBED_TLS || MCUBOOT_USE_CC310) && !MCUBOOT_USE_PSA_CRYPTO */ -#if defined(MCUBOOT_USE_TINYCRYPT) -#ifndef MCUBOOT_ECDSA_NEED_ASN1_SIG /* * cp points to ASN1 string containing an integer. * Verify the tag, and that the length is 32 bytes. Helper function. @@ -184,8 +182,8 @@ static int bootutil_decode_sig(uint8_t signature[NUM_ECC_BYTES * 2], uint8_t *cp } return 0; } -#endif /* not MCUBOOT_ECDSA_NEED_ASN1_SIG */ +#if defined(MCUBOOT_USE_TINYCRYPT) typedef uintptr_t bootutil_ecdsa_context; static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) { @@ -254,8 +252,12 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, { (void)ctx; (void)pk_len; - (void)sig_len; (void)hash_len; + uint8_t dsig[2 * NUM_ECC_BYTES]; + + if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { + return -1; + } /* Only support uncompressed keys. */ if (pk[0] != 0x04) { @@ -263,7 +265,7 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, } pk++; - return cc310_ecdsa_verify_secp256r1(hash, pk, sig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE); + return cc310_ecdsa_verify_secp256r1(hash, pk, dsig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE); } static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, @@ -620,7 +622,11 @@ static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, { (void)ctx; (void)pk_len; - (void)sig_len; + uint8_t dsig[2 * NUM_ECC_BYTES]; + + if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { + return -1; + } /* As described on the compact representation in IETF protocols, * the first byte of the key defines if the ECC points are @@ -633,7 +639,7 @@ static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, pk++; return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, - pk, sig); + pk, dsig); } #endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ From a0c21e290d2618942ea8b340e976a54464d300a9 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 10 Oct 2023 14:05:04 +0200 Subject: [PATCH 18/38] [nrf noup] crypto: ecdsa: Fix shared crypto MCUBoot EXT_ABI After the upmerge using external crypto from NSIB in MCUBoot resulted in build failures. This commit fixes the build failures but also fixes a change in the API call which resulted in `-102` error when calling the verify function. Ref. NCSDK-23994 Signed-off-by: Sigvart Hovland Signed-off-by: Dominik Ermel (cherry picked from commit 40157548d055545f2029c8e669d8b1e96a3cfbc1) --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index e62f3d606..949ec82bf 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -73,7 +73,7 @@ #if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) #include - #define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (4 * 8) + #define NUM_ECC_BYTES (256 / 8) #endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ #ifdef __cplusplus @@ -81,7 +81,8 @@ extern "C" { #endif #if (defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS) || \ - defined(MCUBOOT_USE_CC310)) && !defined(MCUBOOT_USE_PSA_CRYPTO) + defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)) \ + && !defined(MCUBOOT_USE_PSA_CRYPTO) /* * Declaring these like this adds NULL termination. */ @@ -603,43 +604,45 @@ static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) -typedef uintptr_t bootutil_ecdsa_p256_context; - -static inline void bootutil_ecdsa_p256_init(bootutil_ecdsa_p256_context *ctx) +typedef uintptr_t bootutil_ecdsa_context; +static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) { (void)ctx; } -static inline void bootutil_ecdsa_p256_drop(bootutil_ecdsa_p256_context *ctx) +static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx) { (void)ctx; } -static inline int bootutil_ecdsa_p256_verify(bootutil_ecdsa_p256_context *ctx, - uint8_t *pk, size_t pk_len, - uint8_t *hash, - uint8_t *sig, size_t sig_len) +static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, + uint8_t *pk, size_t pk_len, + uint8_t *hash, size_t hash_len, + uint8_t *sig, size_t sig_len) { (void)ctx; (void)pk_len; + (void)hash_len; uint8_t dsig[2 * NUM_ECC_BYTES]; if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { return -1; } - /* As described on the compact representation in IETF protocols, - * the first byte of the key defines if the ECC points are - * compressed (0x2 or 0x3) or uncompressed (0x4). - * We only support uncompressed keys. - */ - if (pk[0] != 0x04) - return -1; + /* Only support uncompressed keys. */ + if (pk[0] != 0x04) { + return -1; + } + pk++; - pk++; + return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, pk, dsig); +} - return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, - pk, dsig); +static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, + uint8_t **cp,uint8_t *end) +{ + (void)ctx; + return bootutil_import_key(cp, end); } #endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ From fcd7281e6ffd386d5f28b1af62ece96b9945b2ab Mon Sep 17 00:00:00 2001 From: Georgios Vasilakis Date: Mon, 8 Nov 2021 22:58:59 +0100 Subject: [PATCH 19/38] [nrf noup] zephyr: Set at least provide EXT_API -This sets the provide EXT_API to be at least optional when the external_crypto is being used. Ref: NCSDK-12021 Signed-off-by: Georgios Vasilakis Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit c8e7fbde8c38094f99fc39a629d06ec4a83c0fed) --- boot/zephyr/external_crypto.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/external_crypto.conf b/boot/zephyr/external_crypto.conf index 8181ad51c..c362f000a 100644 --- a/boot/zephyr/external_crypto.conf +++ b/boot/zephyr/external_crypto.conf @@ -18,3 +18,4 @@ CONFIG_SB_CRYPTO_CLIENT_ECDSA_SECP256R1=y CONFIG_SB_CRYPTO_CLIENT_SHA256=y CONFIG_BL_SHA256_EXT_API_REQUIRED=y CONFIG_BL_SECP256R1_EXT_API_REQUIRED=y +CONFIG_EXT_API_PROVIDE_EXT_API_ATLEAST_OPTIONAL=y From a01d30a9906ee0b874f48c8f12f05185cc4e4a8e Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Mon, 21 Mar 2022 13:44:27 +0100 Subject: [PATCH 20/38] [nrf noup] zephyr: Restore default RTC user channel count The default value of CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT for nRF52 SOCs has been changed from 0 to 3, but it makes MCUBoot get stuck on erasing flash pages when swapping two images. Restore the previous value until the RTC issue is resolved (see NCSDK-14427) Signed-off-by: Damian Krolik Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 9fa2c07df1fcfcc1d85e7b270731259940c8f06b) --- boot/zephyr/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 851c133ec..58cb2ae35 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -35,3 +35,4 @@ CONFIG_MCUBOOT_LOG_LEVEL_INF=y CONFIG_CBPRINTF_NANO=y ### Use the minimal C library to reduce flash usage CONFIG_MINIMAL_LIBC=y +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 From 80016fd841cdd2710cbcd6471202739b00593dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B8e?= Date: Wed, 12 Dec 2018 08:59:47 +0100 Subject: [PATCH 21/38] [nrf noup] treewide: add NCS partition manager support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partition Manager is an nRF Connect SDK component which uses yaml files to resolve flash partition placement with a holistic view of the device. This component's MCUboot portions began life as upstream mcuboot PR#430. This added support for being built as a sub image from the downstream Nordic patch set for a zephyr multi image build system (mcuboot 430 was combined with effor submitted to upstream zephyr as PR#13672, which was ultimately reworked after being rejected for mainline at the ELCE 2019 conference in Lyon). It has since evolved over time. This is the version that will go into NCS v1.3. It features: - page size aligned partitions for all partitions used by mcuboot. - image swaps without scratch partitions Add support for configurations where there exists two primary slots but only one secondary slot, which is shared. These two primary slots are the regular application and B1. B1 can be either S0 or S1 depending on the state of the device. Decide where an upgrade should be stored by looking at the vector table. Provide update candidates for both s0 and s1. These candidates must be signed with mcuboot after being signed by b0. Additional notes: - we make update.hex without trailer data This is needed for serial recovery to work using hex files. Prior to this the update.hex got TLV data at the end of the partition, which caused many blank pages to be included, which made it hard to use in a serial recovery scheme. Instead, make update.hex without TLV data at the end, and provide a new file test_update.hex which contains the TLV data, and can be directly flashed to test the upgrade procedure. - we use a function for signing the application as future-proofing for when other components must be signed as well - this includes an update to single image applications that enables support for partition manager; when single image DFU is used, a scratch partition is not needed. - In NCS, image 1 primary slot is the upgrade bank for mcuboot (IE S0 or S1 depending on the active slot). It is not required that this slot contains any valid data. - The nRF boards all have a single flash page size, and partition manager deals with the size of the update partitions and so on, so we must skip a boot_slots_compatible() check to avoid getting an error. - There is no need to verify the target when using partition manager. - We lock mcuboot using fprotect before jumping, to enable the secure boot property of the system. - Call fw_info_ext_api_provide() before booting if EXT_API_PROVIDE EXT_API is enabled. This is relevant only when the immutable bootloader has booted mcuboot. Signed-off-by: Håkon Øye Amundsen Signed-off-by: Øyvind Rønningstad Signed-off-by: Sebastian Bøe Signed-off-by: Sigvart Hovland Signed-off-by: Martí Bolívar Signed-off-by: Torsten Rasmussen Signed-off-by: Andrzej Głąbek Signed-off-by: Robert Lubos Signed-off-by: Andrzej Puzdrowski Signed-off-by: Emil Obalski Signed-off-by: Pawel Dunaj Signed-off-by: Ioannis Glaropoulos Signed-off-by: Johann Fischer Signed-off-by: Vidar Berg Signed-off-by: Draus, Sebastian Signed-off-by: Trond Einar Snekvik Signed-off-by: Jamie McCrae Signed-off-by: Joakim Andersson Signed-off-by: Georgios Vasilakis Signed-off-by: Dominik Ermel (cherry picked from commit 71fe2df3211ffc0cd497f830348d7d4c8f53f8e8) --- boot/bootutil/src/loader.c | 95 ++++++++++++++++++++++--- boot/bootutil/src/swap_move.c | 13 ++++ boot/bootutil/src/swap_scratch.c | 13 ++++ boot/zephyr/CMakeLists.txt | 7 ++ boot/zephyr/Kconfig | 2 + boot/zephyr/include/sysflash/sysflash.h | 48 +++++++++++++ boot/zephyr/include/target.h | 4 ++ boot/zephyr/main.c | 45 ++++++++++++ boot/zephyr/pm.yml | 74 +++++++++++++++++++ boot/zephyr/prj.conf | 1 + ext/nrf/cc310_glue.h | 2 +- zephyr/module.yml | 3 +- 12 files changed, 296 insertions(+), 11 deletions(-) create mode 100644 boot/zephyr/pm.yml diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index b2ea9ddb0..a7b388438 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -109,6 +109,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all, * * Failure to read any headers is a fatal error. */ +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. The primary slot of the second image + * (image 1) will not contain a valid image header until an upgrade + * of mcuboot has happened (filling S1 with the new version). + */ + if (BOOT_CURR_IMG(state) == 1 && i == 0) { + continue; + } +#endif /* PM_S1_ADDRESS */ if (i > 0 && !require_all) { return 0; } else { @@ -822,7 +831,24 @@ boot_validate_slot(struct boot_loader_state *state, int slot, goto out; } - if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) { + uint32_t min_addr, max_addr; + +#ifdef PM_CPUNET_APP_ADDRESS + /* The primary slot for the network core is emulated in RAM. + * Its flash_area hasn't got relevant boundaries. + * Therfore need to override its boundaries for the check. + */ + if (BOOT_CURR_IMG(state) == 1) { + min_addr = PM_CPUNET_APP_ADDRESS; + max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE; + } else +#endif + { + min_addr = pri_fa->fa_off; + max_addr = pri_fa->fa_off + pri_fa->fa_size; + } + + if (reset_value < min_addr || reset_value> (max_addr)) { BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot"); BOOT_LOG_ERR("Erasing image from secondary slot"); @@ -905,6 +931,42 @@ boot_validated_swap_type(struct boot_loader_state *state, { int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other + * B1 slot S0 or S1) share the same secondary slot, we need to check + * whether the update candidate in the secondary slot is intended for + * image 0 or image 1 primary by looking at the address of the reset + * vector. Note that there are good reasons for not using img_num from + * the swap info. + */ + const struct flash_area *secondary_fa = + BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); + struct image_header *hdr = + (struct image_header *)secondary_fa->fa_off; + + if (hdr->ih_magic == IMAGE_MAGIC) { + const struct flash_area *primary_fa; + uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; + uint32_t *vtable = (uint32_t *)(vtable_addr); + uint32_t reset_addr = vtable[1]; + int rc = flash_area_open( + flash_area_id_from_multi_image_slot( + BOOT_CURR_IMG(state), + BOOT_PRIMARY_SLOT), + &primary_fa); + + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } + /* Get start and end of primary slot for current image */ + if (reset_addr < primary_fa->fa_off || + reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { + /* The image in the secondary slot is not intended for this image + */ + return BOOT_SWAP_TYPE_NONE; + } + } +#endif swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -2230,15 +2292,25 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT - FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL); - /* Check for all possible values is redundant in normal operation it - * is meant to prevent FI attack. +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. Image 1 primary is the currently + * executing MCUBoot image, and is therefore already validated by NSIB and + * does not need to also be validated by MCUBoot. */ - if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS) || - FIH_EQ(fih_rc, FIH_FAILURE) || - FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) { - FIH_SET(fih_rc, FIH_FAILURE); - goto out; + bool image_validated_by_nsib = BOOT_CURR_IMG(state) == 1; + if (!image_validated_by_nsib) +#endif + { + FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL); + /* Check for all possible values is redundant in normal operation it + * is meant to prevent FI attack. + */ + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS) || + FIH_EQ(fih_rc, FIH_FAILURE) || + FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } } #else /* Even if we're not re-validating the primary slot, we could be booting @@ -2255,11 +2327,16 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */ +#ifdef PM_S1_ADDRESS + if (!image_validated_by_nsib) +#endif + { rc = boot_update_hw_rollback_protection(state); if (rc != 0) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } + } rc = boot_add_shared_data(state, BOOT_PRIMARY_SLOT); if (rc != 0) { diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index 61246b9e5..cd5016391 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -237,6 +237,18 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz) int boot_slots_compatible(struct boot_loader_state *state) { +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. In this case, image 1 primary points to the other + * B1 slot (ie S0 or S1), and image 0 primary points to the app. + * With this configuration, image 0 and image 1 share the secondary slot. + * Hence, the primary slot of image 1 will be *smaller* than image 1's + * secondary slot. This is not allowed in upstream mcuboot, so we need + * this patch to allow it. Also, all of these checks are redundant when + * partition manager is in use, and since we have the same sector size + * in all of our flash. + */ + return 1; +#else size_t num_sectors_pri; size_t num_sectors_sec; size_t sector_sz_pri = 0; @@ -273,6 +285,7 @@ boot_slots_compatible(struct boot_loader_state *state) } return 1; +#endif /* PM_S1_ADDRESS */ } #define BOOT_LOG_SWAP_STATE(area, state) \ diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index 66cbdce5f..a32eb8d87 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -170,6 +170,18 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz) int boot_slots_compatible(struct boot_loader_state *state) { +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. In this case, image 1 primary points to the other + * B1 slot (ie S0 or S1), and image 0 primary points to the app. + * With this configuration, image 0 and image 1 share the secondary slot. + * Hence, the primary slot of image 1 will be *smaller* than image 1's + * secondary slot. This is not allowed in upstream mcuboot, so we need + * this patch to allow it. Also, all of these checks are redundant when + * partition manager is in use, and since we have the same sector size + * in all of our flash. + */ + return 1; +#else size_t num_sectors_primary; size_t num_sectors_secondary; size_t sz0, sz1; @@ -255,6 +267,7 @@ boot_slots_compatible(struct boot_loader_state *state) } return 1; +#endif /* PM_S1_ADDRESS */ } #define BOOT_LOG_SWAP_STATE(area, state) \ diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 14a891f34..467eb9be1 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -290,6 +290,13 @@ if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") endif() message("MCUBoot bootloader key file: ${KEY_FILE}") + set_property( + GLOBAL + PROPERTY + KEY_FILE + ${KEY_FILE} + ) + set(GENERATED_PUBKEY ${ZEPHYR_BINARY_DIR}/autogen-pubkey.c) add_custom_command( OUTPUT ${GENERATED_PUBKEY} diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2dec368eb..f69790e74 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -9,6 +9,8 @@ mainmenu "MCUboot configuration" comment "MCUboot-specific configuration options" +source "$(ZEPHYR_NRF_MODULE_DIR)/modules/mcuboot/boot/zephyr/Kconfig" + # Hidden option to mark a project as MCUboot config MCUBOOT default y diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 646f1122f..e22f9b776 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -7,6 +7,52 @@ #ifndef __SYSFLASH_H__ #define __SYSFLASH_H__ +#if USE_PARTITION_MANAGER +#include +#include + +#ifndef CONFIG_SINGLE_APPLICATION_SLOT + +#if (MCUBOOT_IMAGE_NUMBER == 1) + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID + +#elif (MCUBOOT_IMAGE_NUMBER == 2) + +extern uint32_t _image_1_primary_slot_id[]; + +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + (uint32_t)_image_1_primary_slot_id : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + 255 ) +#endif +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID + +#else /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID +/* NOTE: Scratch parition is not used by single image DFU but some of + * functions in common files reference it, so the definitions has been + * provided to allow compilation of common units. + */ +#define FLASH_AREA_IMAGE_SCRATCH 0 + +#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#else + +#include #include #include #include @@ -57,4 +103,6 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #endif /* CONFIG_SINGLE_APPLICATION_SLOT */ +#endif /* USE_PARTITION_MANAGER */ + #endif /* __SYSFLASH_H__ */ diff --git a/boot/zephyr/include/target.h b/boot/zephyr/include/target.h index 61dfd9322..513693511 100644 --- a/boot/zephyr/include/target.h +++ b/boot/zephyr/include/target.h @@ -8,6 +8,8 @@ #ifndef H_TARGETS_TARGET_ #define H_TARGETS_TARGET_ +#ifndef USE_PARTITION_MANAGER + #if defined(MCUBOOT_TARGET_CONFIG) /* * Target-specific definitions are permitted in legacy cases that @@ -45,4 +47,6 @@ #error "Target support is incomplete; cannot build mcuboot." #endif +#endif /* ifndef USE_PARTITION_MANAGER */ + #endif /* H_TARGETS_TARGET_ */ diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 7b3702475..898f501b9 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -64,6 +64,10 @@ #endif /* CONFIG_SOC_FAMILY_ESP32 */ +#ifdef CONFIG_FW_INFO +#include +#endif + #ifdef CONFIG_MCUBOOT_SERIAL #include "boot_serial/boot_serial.h" #include "serial_adapter/serial_adapter.h" @@ -132,6 +136,11 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); * !defined(ZEPHYR_LOG_MODE_MINIMAL) */ +#if USE_PARTITION_MANAGER && CONFIG_FPROTECT +#include +#include +#endif + #ifdef CONFIG_SOC_FAMILY_NRF #include @@ -239,6 +248,19 @@ static void do_boot(struct boot_rsp *rsp) /* Disable the USB to prevent it from firing interrupts */ usb_disable(); #endif + +#if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) + bool provided = fw_info_ext_api_provide(fw_info_find((uint32_t)vt), true); + +#ifdef PM_S0_ADDRESS + /* Only fail if the immutable bootloader is present. */ + if (!provided) { + BOOT_LOG_ERR("Failed to provide EXT_APIs\n"); + return; + } +#endif +#endif + #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_nvic(); /* cleanup NVIC registers */ @@ -681,7 +703,30 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND); +#if USE_PARTITION_MANAGER && CONFIG_FPROTECT + +#ifdef PM_S1_ADDRESS +/* MCUBoot is stored in either S0 or S1, protect both */ +#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_S0_ADDRESS) +#define PROTECT_ADDR PM_S0_ADDRESS +#else +/* There is only one instance of MCUBoot */ +#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_MCUBOOT_ADDRESS) +#define PROTECT_ADDR PM_MCUBOOT_ADDRESS +#endif + + rc = fprotect_area(PROTECT_ADDR, PROTECT_SIZE); + + if (rc != 0) { + BOOT_LOG_ERR("Protect mcuboot flash failed, cancel startup."); + while (1) + ; + } + +#endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */ + ZEPHYR_BOOT_LOG_STOP(); + do_boot(&rsp); mcuboot_status_change(MCUBOOT_STATUS_BOOT_FAILED); diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml new file mode 100644 index 000000000..0c3a59154 --- /dev/null +++ b/boot/zephyr/pm.yml @@ -0,0 +1,74 @@ +#include + +mcuboot: + size: CONFIG_PM_PARTITION_SIZE_MCUBOOT + placement: + before: [mcuboot_primary] + +mcuboot_primary_app: + # All images to be placed in MCUboot's slot 0 should be placed in this + # partition + span: [app] + +mcuboot_primary: + span: [mcuboot_pad, mcuboot_primary_app] + +# Partition for secondary slot is not created if building in single application +# slot configuration. +#if !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_BOOT_DIRECT_XIP) +mcuboot_secondary: + share_size: [mcuboot_primary] +#if defined(CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY) + region: external_flash + placement: + align: {start: 4} +#else + placement: + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} + align_next: CONFIG_FPROTECT_BLOCK_SIZE # Ensure that the next partition does not interfere with this image + after: mcuboot_primary +#endif /* CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY */ + +#endif /* !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_BOOT_DIRECT_XIP) */ + +#if CONFIG_BOOT_DIRECT_XIP + +# Direct XIP is enabled, reserve area for metadata (padding) and name the +# partition so that its clear that it is not the secondary slot, but the direct +# XIP alternative. + +mcuboot_secondary_pad: + share_size: mcuboot_pad + placement: + after: mcuboot_primary + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} + +mcuboot_secondary_app: + share_size: mcuboot_primary_app + placement: + after: mcuboot_secondary_pad + +mcuboot_secondary: + span: [mcuboot_secondary_pad, mcuboot_secondary_app] + +#endif /* CONFIG_BOOT_DIRECT_XIP */ + +#if CONFIG_BOOT_SWAP_USING_SCRATCH +mcuboot_scratch: + size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_SCRATCH + placement: + after: app + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} +#endif /* CONFIG_BOOT_SWAP_USING_SCRATCH */ + +# Padding placed before image to boot. This reserves space for the MCUboot image header +# and it ensures that the boot image gets linked with the correct address offset in flash. +mcuboot_pad: + # MCUboot pad must be placed before the primary application partition. + # The primary application partition includes the secure firmware if present. + size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_PAD + placement: + before: [mcuboot_primary_app] +#ifdef CONFIG_FPROTECT + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} +#endif diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 58cb2ae35..23b5f3b93 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -19,6 +19,7 @@ CONFIG_BOOT_BOOTSTRAP=n # CONFIG_TINYCRYPT_SHA256 is not set CONFIG_FLASH=y +CONFIG_FPROTECT=y ### Various Zephyr boards enable features that we don't want. # CONFIG_BT is not set diff --git a/ext/nrf/cc310_glue.h b/ext/nrf/cc310_glue.h index ed3ed5c00..22eb94911 100644 --- a/ext/nrf/cc310_glue.h +++ b/ext/nrf/cc310_glue.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include /* diff --git a/zephyr/module.yml b/zephyr/module.yml index c4293e387..797b0fa10 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -1,4 +1,5 @@ samples: - boot/zephyr build: - cmake: ./boot/bootutil/zephyr + cmake-ext: True + kconfig-ext: True From 20095871947ddd4516a0b0e3fe32b72363ab872e Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Thu, 27 Aug 2020 14:29:31 +0200 Subject: [PATCH 22/38] [nrf noup] boot: nrf53-specific customizations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add network core bootloader implementation Enables network core updates of nrf53 using MCUBoot by identifying images through their start addresses. Also implements the control and transfer using the PCD module. - Add support for multi image DFU using partition manager. - Add check for netcore addr if NSIB is enabled so netcore updates works - boot: zephyr: move thingy53_nrf5340_cpuapp.conf downstream Moved the board configuration for Thingy:53 Application Core to the nRF Connect SDK MCUboot downstream repository. The configuration file contains references to the Kconfig modules that are only available in the nRF Connect SDK. The current configuration is set up to work in the nRF Connect SDK environment and cannot be used upstream. - pm: enable ram flash partition using common flag This patch makes mcuboot_primary_1 ram-flash partition selectable using CONFIG_NRF53_MCUBOOT_PRIMARY_1_RAM_FLASH property. This is needed since CONFIG_NRF53_MULTI_IMAGE_UPDATE become not only configuration which requires that partition. - MCUBoot configures USB CDC by its own. There is no need for BOARD_SERIAL_BACKEND_CDC_ACM option to configure anything which is later overwritten anyway. Jira: NCSDK-18596 Signed-off-by: Andrzej Puzdrowski Signed-off-by: Emil Obalski Signed-off-by: Håkon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Jamie McCrae Signed-off-by: Johann Fischer Signed-off-by: Kamil Piszczek Signed-off-by: Ole Sæther Signed-off-by: Sigvart Hovland Signed-off-by: Simon Iversen Signed-off-by: Torsten Rasmussen Signed-off-by: Trond Einar Snekvik Signed-off-by: Mateusz Kapala Signed-off-by: Dominik Ermel (cherry picked from commit 2bbd3b115b34a68908d6e8cde057292de276c552) (cherry picked from commit 0098451eb6c511a1ba72602e43dbbaf3c1707390) --- boot/bootutil/src/loader.c | 96 ++++++++++++++----- .../boards/thingy53_nrf5340_cpuapp.conf | 73 ++++++++++++++ boot/zephyr/include/sysflash/sysflash.h | 23 +++++ boot/zephyr/main.c | 7 ++ boot/zephyr/pm.yml | 13 +++ 5 files changed, 186 insertions(+), 26 deletions(-) create mode 100644 boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index a7b388438..bf1c5cd35 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -49,6 +49,10 @@ #include "bootutil/boot_hooks.h" #include "bootutil/mcuboot_status.h" +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) +#include +#endif + #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -931,7 +935,15 @@ boot_validated_swap_type(struct boot_loader_state *state, { int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); -#ifdef PM_S1_ADDRESS + bool upgrade_valid = false; + +#if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) + const struct flash_area *secondary_fa = + BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); + struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; + uint32_t vtable_addr = 0; + uint32_t *vtable = 0; + uint32_t reset_addr = 0; /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other * B1 slot S0 or S1) share the same secondary slot, we need to check * whether the update candidate in the secondary slot is intended for @@ -939,34 +951,36 @@ boot_validated_swap_type(struct boot_loader_state *state, * vector. Note that there are good reasons for not using img_num from * the swap info. */ - const struct flash_area *secondary_fa = - BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); - struct image_header *hdr = - (struct image_header *)secondary_fa->fa_off; if (hdr->ih_magic == IMAGE_MAGIC) { - const struct flash_area *primary_fa; - uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; - uint32_t *vtable = (uint32_t *)(vtable_addr); - uint32_t reset_addr = vtable[1]; - int rc = flash_area_open( - flash_area_id_from_multi_image_slot( - BOOT_CURR_IMG(state), - BOOT_PRIMARY_SLOT), - &primary_fa); - - if (rc != 0) { - return BOOT_SWAP_TYPE_FAIL; - } - /* Get start and end of primary slot for current image */ - if (reset_addr < primary_fa->fa_off || - reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { - /* The image in the secondary slot is not intended for this image - */ - return BOOT_SWAP_TYPE_NONE; - } - } + vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; + vtable = (uint32_t *)(vtable_addr); + reset_addr = vtable[1]; +#ifdef PM_S1_ADDRESS +#ifdef PM_CPUNET_B0N_ADDRESS + if(reset_addr < PM_CPUNET_B0N_ADDRESS) #endif + { + const struct flash_area *primary_fa; + int rc = flash_area_open(flash_area_id_from_multi_image_slot( + BOOT_CURR_IMG(state), + BOOT_PRIMARY_SLOT), + &primary_fa); + + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } + /* Get start and end of primary slot for current image */ + if (reset_addr < primary_fa->fa_off || + reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { + /* The image in the secondary slot is not intended for this image + */ + return BOOT_SWAP_TYPE_NONE; + } + } +#endif /* PM_S1_ADDRESS */ + } +#endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -980,7 +994,37 @@ boot_validated_swap_type(struct boot_loader_state *state, } else { swap_type = BOOT_SWAP_TYPE_FAIL; } + } else { + upgrade_valid = true; + } + +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) + /* If the update is valid, and it targets the network core: perform the + * update and indicate to the caller of this function that no update is + * available + */ + if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) { + uint32_t fw_size = hdr->ih_img_size; + + BOOT_LOG_INF("Starting network core update"); + int rc = pcd_network_core_update(vtable, fw_size); + + if (rc != 0) { + swap_type = BOOT_SWAP_TYPE_FAIL; + } else { + BOOT_LOG_INF("Done updating network core"); +#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) + /* swap_erase_trailer_sectors is undefined if upgrade only + * method is used. There is no need to erase sectors, because + * the image cannot be reverted. + */ + rc = swap_erase_trailer_sectors(state, + secondary_fa); +#endif + swap_type = BOOT_SWAP_TYPE_NONE; + } } +#endif /* CONFIG_SOC_NRF5340_CPUAPP */ } return swap_type; diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf new file mode 100644 index 000000000..7d3bc0bec --- /dev/null +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -0,0 +1,73 @@ +CONFIG_SIZE_OPTIMIZATIONS=y + +CONFIG_SYSTEM_CLOCK_NO_WAIT=y +CONFIG_PM=n + +CONFIG_MAIN_STACK_SIZE=10240 +CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" + +CONFIG_BOOT_MAX_IMG_SECTORS=2048 +CONFIG_BOOT_SIGNATURE_TYPE_RSA=y + +# Flash +CONFIG_FLASH=y +CONFIG_BOOT_ERASE_PROGRESSIVELY=y +CONFIG_SOC_FLASH_NRF_EMULATE_ONE_BYTE_WRITE_ACCESS=y +CONFIG_FPROTECT=y + +# Serial +CONFIG_SERIAL=y +CONFIG_UART_LINE_CTRL=y + +# MCUBoot serial +CONFIG_GPIO=y +CONFIG_MCUBOOT_SERIAL=y +CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y +CONFIG_BOOT_SERIAL_CDC_ACM=y + +# Required by QSPI +CONFIG_NORDIC_QSPI_NOR=y +CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 +CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16 + +# Required by USB and QSPI +CONFIG_MULTITHREADING=y + +# USB +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n +CONFIG_USB_DEVICE_REMOTE_WAKEUP=n +CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor ASA" +CONFIG_USB_DEVICE_PRODUCT="Bootloader Thingy:53" +CONFIG_USB_DEVICE_VID=0x1915 +CONFIG_USB_DEVICE_PID=0x5300 +CONFIG_USB_CDC_ACM=y + +# Decrease memory footprint +CONFIG_CBPRINTF_NANO=y +CONFIG_TIMESLICING=n +CONFIG_BOOT_BANNER=n +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n +CONFIG_USE_SEGGER_RTT=n +CONFIG_LOG=n +CONFIG_ERRNO=n +CONFIG_PRINTK=n +CONFIG_RESET_ON_FATAL_ERROR=n +CONFIG_SPI=n +CONFIG_I2C=n +CONFIG_UART_NRFX=n + +# The following configurations are required to support simultaneous multi image update +CONFIG_PCD_APP=y +CONFIG_UPDATEABLE_IMAGE_NUMBER=2 +CONFIG_BOOT_UPGRADE_ONLY=y +# The network core cannot access external flash directly. The flash simulator must be used to +# provide a memory region that is used to forward the new firmware to the network core. +CONFIG_FLASH_SIMULATOR=y +CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y +CONFIG_FLASH_SIMULATOR_STATS=n + +# Enable custom command to erase settings partition. +CONFIG_ENABLE_MGMT_PERUSER=y +CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE=y diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index e22f9b776..d6a74f370 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -20,6 +20,11 @@ #elif (MCUBOOT_IMAGE_NUMBER == 2) +/* If B0 is present then two bootloaders are present, and we must use + * a single secondary slot for both primary slots. + */ +#ifdef PM_B0_ADDRESS + extern uint32_t _image_1_primary_slot_id[]; #define FLASH_AREA_IMAGE_PRIMARY(x) \ @@ -35,6 +40,24 @@ extern uint32_t _image_1_primary_slot_id[]; (x == 1) ? \ PM_MCUBOOT_SECONDARY_ID: \ 255 ) +#else + +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) + +#endif /* PM_B0_ADDRESS */ + #endif #define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 898f501b9..f2d0425c2 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -94,6 +94,10 @@ const struct boot_uart_funcs boot_funcs = { #include #endif +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) +#include +#endif + /* CONFIG_LOG_MINIMAL is the legacy Kconfig property, * replaced by CONFIG_LOG_MODE_MINIMAL. */ @@ -723,6 +727,9 @@ int main(void) ; } +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) + pcd_lock_ram(); +#endif #endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */ ZEPHYR_BOOT_LOG_STOP(); diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml index 0c3a59154..125b8813c 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -72,3 +72,16 @@ mcuboot_pad: #ifdef CONFIG_FPROTECT align: {start: CONFIG_FPROTECT_BLOCK_SIZE} #endif + +#if (CONFIG_NRF53_MCUBOOT_PRIMARY_1_RAM_FLASH) +mcuboot_primary_1: + region: ram_flash + size: CONFIG_NRF53_RAM_FLASH_SIZE +#endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ + +#if (CONFIG_NRF53_MULTI_IMAGE_UPDATE) +mcuboot_secondary_1: + region: external_flash + size: CONFIG_NRF53_RAM_FLASH_SIZE + +#endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ From 1b0aa58267e39a052622f7eaf55195b7ff1d69e7 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 27 Feb 2020 12:48:56 +0100 Subject: [PATCH 23/38] [nrf noup] zephyr: clean peripherals state before boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do some cleanup of nRF peripherals. This is necessary since Zephyr doesn't have any driver deinitialization functionality, and we'd like to leave peripherals in a more predictable state before booting the Zephyr image. This should be re-worked when the zephyr driver model allows us to deinitialize devices cleanly before jumping to the chain-loaded image. Signed-off-by: Andrzej Puzdrowski Signed-off-by: Robert Lubos Signed-off-by: Torsten Rasmussen Signed-off-by: Øyvind Rønningstad Signed-off-by: Martí Bolívar Signed-off-by: Håkon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Johann Fischer Signed-off-by: Trond Einar Snekvik Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 4c8e0413044684474e9eda646e073f8cf0855be6) --- boot/zephyr/CMakeLists.txt | 6 +++ boot/zephyr/include/nrf_cleanup.h | 19 +++++++ boot/zephyr/main.c | 8 ++- boot/zephyr/nrf_cleanup.c | 83 +++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 boot/zephyr/include/nrf_cleanup.h create mode 100644 boot/zephyr/nrf_cleanup.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 467eb9be1..0cf0ade1f 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -357,3 +357,9 @@ zephyr_library_sources( ${BOOT_DIR}/zephyr/arm_cleanup.c ) endif() + +if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL) +zephyr_library_sources( + ${BOOT_DIR}/zephyr/nrf_cleanup.c +) +endif() diff --git a/boot/zephyr/include/nrf_cleanup.h b/boot/zephyr/include/nrf_cleanup.h new file mode 100644 index 000000000..6b04cedfe --- /dev/null +++ b/boot/zephyr/include/nrf_cleanup.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef H_NRF_CLEANUP_ +#define H_NRF_CLEANUP_ + +/** + * Perform cleanup on some peripheral resources used by MCUBoot prior chainload + * the application. + * + * This function disables all RTC instances and UARTE instances. + * It Disables their interrupts signals as well. + */ +void nrf_cleanup_peripheral(void); + +#endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index f2d0425c2..b6b039b89 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -145,6 +145,10 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL +#include +#endif + #ifdef CONFIG_SOC_FAMILY_NRF #include @@ -264,7 +268,9 @@ static void do_boot(struct boot_rsp *rsp) } #endif #endif - +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL + nrf_cleanup_peripheral(); +#endif #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_nvic(); /* cleanup NVIC registers */ diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c new file mode 100644 index 000000000..5bab26b24 --- /dev/null +++ b/boot/zephyr/nrf_cleanup.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#if defined(NRF_UARTE0) || defined(NRF_UARTE1) + #include +#endif +#if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) + #include +#endif +#if defined(NRF_PPI) + #include +#endif +#if defined(NRF_DPPIC) + #include +#endif + +#include + +#define NRF_UARTE_SUBSCRIBE_CONF_OFFS offsetof(NRF_UARTE_Type, SUBSCRIBE_STARTRX) +#define NRF_UARTE_SUBSCRIBE_CONF_SIZE (offsetof(NRF_UARTE_Type, EVENTS_CTS) -\ + NRF_UARTE_SUBSCRIBE_CONF_OFFS) + +#define NRF_UARTE_PUBLISH_CONF_OFFS offsetof(NRF_UARTE_Type, PUBLISH_CTS) +#define NRF_UARTE_PUBLISH_CONF_SIZE (offsetof(NRF_UARTE_Type, SHORTS) -\ + NRF_UARTE_PUBLISH_CONF_OFFS) + +#if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) +static inline void nrf_cleanup_rtc(NRF_RTC_Type * rtc_reg) +{ + nrf_rtc_task_trigger(rtc_reg, NRF_RTC_TASK_STOP); + nrf_rtc_event_disable(rtc_reg, 0xFFFFFFFF); + nrf_rtc_int_disable(rtc_reg, 0xFFFFFFFF); +} +#endif + +static void nrf_cleanup_clock(void) +{ + nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); +} + +void nrf_cleanup_peripheral(void) +{ +#if defined(NRF_RTC0) + nrf_cleanup_rtc(NRF_RTC0); +#endif +#if defined(NRF_RTC1) + nrf_cleanup_rtc(NRF_RTC1); +#endif +#if defined(NRF_RTC2) + nrf_cleanup_rtc(NRF_RTC2); +#endif +#if defined(NRF_UARTE0) + nrf_uarte_disable(NRF_UARTE0); + nrf_uarte_int_disable(NRF_UARTE0, 0xFFFFFFFF); +#if defined(NRF_DPPIC) + /* Clear all SUBSCRIBE configurations. */ + memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); + /* Clear all PUBLISH configurations. */ + memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); +#endif +#endif +#if defined(NRF_UARTE1) + nrf_uarte_disable(NRF_UARTE1); + nrf_uarte_int_disable(NRF_UARTE1, 0xFFFFFFFF); +#if defined(NRF_DPPIC) + /* Clear all SUBSCRIBE configurations. */ + memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); + /* Clear all PUBLISH configurations. */ + memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); +#endif +#endif +#if defined(NRF_PPI) + nrf_ppi_channels_disable_all(NRF_PPI); +#endif +#if defined(NRF_DPPIC) + nrf_dppi_channels_disable_all(NRF_DPPIC); +#endif + nrf_cleanup_clock(); +} From 83bc352b963efde2b5bba2d28a24a9ec7275c625 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Fri, 6 Jan 2023 12:24:48 +0100 Subject: [PATCH 24/38] [nrf noup] zephyr: Clean up non-secure RAM if enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To ensure that MCUBoot does not leak keys or other material through memory to non-secure side we clear the memory before jumping to the next image. Signed-off-by: Sigvart Hovland Signed-off-by: Dominik Ermel Signed-off-by: Ole Sæther (cherry picked from commit b8a544de583be183d09efe435791bf73a66a95f0) (cherry picked from commit 7f2386f06d402a7968dd77513fdfee30020f0d5e) --- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/include/nrf_cleanup.h | 5 +++++ boot/zephyr/main.c | 5 ++++- boot/zephyr/nrf_cleanup.c | 13 +++++++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 0cf0ade1f..154442399 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -358,7 +358,7 @@ zephyr_library_sources( ) endif() -if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL) +if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL OR CONFIG_MCUBOOT_CLEANUP_NONSECURE_RAM) zephyr_library_sources( ${BOOT_DIR}/zephyr/nrf_cleanup.c ) diff --git a/boot/zephyr/include/nrf_cleanup.h b/boot/zephyr/include/nrf_cleanup.h index 6b04cedfe..9e87e13f5 100644 --- a/boot/zephyr/include/nrf_cleanup.h +++ b/boot/zephyr/include/nrf_cleanup.h @@ -16,4 +16,9 @@ */ void nrf_cleanup_peripheral(void); +/** + * Perform cleanup of non-secure RAM that may have been used by MCUBoot. + */ +void nrf_cleanup_ns_ram(void); + #endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index b6b039b89..5bc8b1c7e 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -145,7 +145,7 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif -#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL || CONFIG_MCUBOOT_NRF_CLEANUP_NONSECURE_RAM #include #endif @@ -271,6 +271,9 @@ static void do_boot(struct boot_rsp *rsp) #if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL nrf_cleanup_peripheral(); #endif +#if CONFIG_MCUBOOT_NRF_CLEANUP_NONSECURE_RAM && defined(PM_SRAM_NONSECURE_NAME) + nrf_cleanup_ns_ram(); +#endif #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_nvic(); /* cleanup NVIC registers */ diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 5bab26b24..2165159ea 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -20,6 +20,10 @@ #include +#if USE_PARTITION_MANAGER +#include +#endif + #define NRF_UARTE_SUBSCRIBE_CONF_OFFS offsetof(NRF_UARTE_Type, SUBSCRIBE_STARTRX) #define NRF_UARTE_SUBSCRIBE_CONF_SIZE (offsetof(NRF_UARTE_Type, EVENTS_CTS) -\ NRF_UARTE_SUBSCRIBE_CONF_OFFS) @@ -81,3 +85,12 @@ void nrf_cleanup_peripheral(void) #endif nrf_cleanup_clock(); } + +#if USE_PARTITION_MANAGER \ + && defined(CONFIG_ARM_TRUSTZONE_M) \ + && defined(PM_SRAM_NONSECURE_NAME) +void nrf_cleanup_ns_ram(void) +{ + memset((void *) PM_SRAM_NONSECURE_ADDRESS, 0, PM_SRAM_NONSECURE_SIZE); +} +#endif From 5bdac092c6eb4a4e0a275fc9ea262046a3282f4a Mon Sep 17 00:00:00 2001 From: Christian Taedcke Date: Thu, 10 Feb 2022 15:37:49 +0100 Subject: [PATCH 25/38] [nrf noup] loader: Fix reading reset addr to support ext flash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When mcuboot_secondary is on external flash, the image header cannot dircetly be accessed via secondary_fa->fa_off. Instead the provided function boot_img_hdr() is used now. Additionally a similar issue is present when trying to read the address of the reset handler. For this flash_area_read() is used now. With this patch is possible to have the update partiton mcuboot_secondary on external flash and update a updatable bootloader (mcuboot) in s0 and/or s1. Signed-off-by: Christian Taedcke Signed-off-by: Ole Sæther Signed-off-by: Sigvart Hovland Signed-off-by: Dominik Ermel (cherry picked from commit 9403865b1fb2d7fd74f0600d0d24a997eb258dce) --- boot/bootutil/src/loader.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index bf1c5cd35..8351a953f 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -940,10 +940,9 @@ boot_validated_swap_type(struct boot_loader_state *state, #if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); - struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; - uint32_t vtable_addr = 0; - uint32_t *vtable = 0; + struct image_header *hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); uint32_t reset_addr = 0; + int rc = 0; /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other * B1 slot S0 or S1) share the same secondary slot, we need to check * whether the update candidate in the secondary slot is intended for @@ -953,16 +952,19 @@ boot_validated_swap_type(struct boot_loader_state *state, */ if (hdr->ih_magic == IMAGE_MAGIC) { - vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; - vtable = (uint32_t *)(vtable_addr); - reset_addr = vtable[1]; + rc = flash_area_read(secondary_fa, hdr->ih_hdr_size + + sizeof(uint32_t), &reset_addr, + sizeof(reset_addr)); + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } #ifdef PM_S1_ADDRESS #ifdef PM_CPUNET_B0N_ADDRESS if(reset_addr < PM_CPUNET_B0N_ADDRESS) #endif { const struct flash_area *primary_fa; - int rc = flash_area_open(flash_area_id_from_multi_image_slot( + rc = flash_area_open(flash_area_id_from_multi_image_slot( BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT), &primary_fa); @@ -998,16 +1000,19 @@ boot_validated_swap_type(struct boot_loader_state *state, upgrade_valid = true; } -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) \ + && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) /* If the update is valid, and it targets the network core: perform the * update and indicate to the caller of this function that no update is * available */ if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) { + struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; + uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; + uint32_t *net_core_fw_addr = (uint32_t *)(vtable_addr); uint32_t fw_size = hdr->ih_img_size; - BOOT_LOG_INF("Starting network core update"); - int rc = pcd_network_core_update(vtable, fw_size); + rc = pcd_network_core_update(net_core_fw_addr, fw_size); if (rc != 0) { swap_type = BOOT_SWAP_TYPE_FAIL; From d9d380408fd6efc9823955fc1b929c286c743684 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Jul 2023 08:42:49 +0100 Subject: [PATCH 26/38] [nrf noup] zephyr: Fix path variables Fixes path variables to use the proper Zephyr module variables Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit be3e7c6aa86a37598e4c292f42b88b323d2d6408) --- boot/zephyr/CMakeLists.txt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 154442399..ce1c88d33 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -26,21 +26,20 @@ assert_exists(FIAT_DIR) # Path to mbed-tls' asn1 parser library. set(MBEDTLS_ASN1_DIR "${MCUBOOT_DIR}/ext/mbedtls-asn1") assert_exists(MBEDTLS_ASN1_DIR) -set(NRF_DIR "${MCUBOOT_DIR}/ext/nrf") +set(MCUBOOT_NRF_EXT_DIR "${MCUBOOT_DIR}/ext/nrf") if(CONFIG_BOOT_USE_NRF_CC310_BL) -set(NRFXLIB_DIR ${ZEPHYR_BASE}/../nrfxlib) -if(NOT EXISTS ${NRFXLIB_DIR}) - message(FATAL_ERROR " + if(NOT EXISTS ${ZEPHYR_NRFXLIB_MODULE_DIR}) + message(FATAL_ERROR " ------------------------------------------------------------------------ - No such file or directory: ${NRFXLIB_DIR} + No such file or directory: ${ZEPHYR_NRFXLIB_MODULE_DIR} The current configuration enables nRF CC310 crypto accelerator hardware with the `CONFIG_BOOT_USE_NRF_CC310_BL` option. Please follow `ext/nrf/README.md` guide to fix your setup or use tinycrypt instead of the HW accelerator. To use the tinycrypt set `CONFIG_BOOT_ECDSA_TINYCRYPT` to y. ------------------------------------------------------------------------") -endif() + endif() endif() zephyr_library_include_directories( @@ -162,8 +161,8 @@ if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) ${TINYCRYPT_DIR}/source/utils.c ) elseif(CONFIG_BOOT_USE_NRF_CC310_BL) - zephyr_library_sources(${NRF_DIR}/cc310_glue.c) - zephyr_library_include_directories(${NRF_DIR}) + zephyr_library_sources(${MCUBOOT_NRF_EXT_DIR}/cc310_glue.c) + zephyr_library_include_directories(${MCUBOOT_NRF_EXT_DIR}) zephyr_link_libraries(nrfxlib_crypto) elseif(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) zephyr_include_directories(${BL_CRYPTO_DIR}/../include) From 6024d0a97a546e9bc845de6c52684a261e681a21 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 31 Aug 2023 08:58:31 +0100 Subject: [PATCH 27/38] [nrf noup] loader: Fix missing PCD define check Fixes a missing PCD define check, an image might have the network core partition layout set but if PCD support is not enabled then it should not assume that PCD support is part of mcuboot. Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 5932630e32930e34865dcd260e742225ceadb269) --- boot/bootutil/src/loader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8351a953f..4bd001ba3 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1001,7 +1001,7 @@ boot_validated_swap_type(struct boot_loader_state *state, } #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) \ - && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) && defined(CONFIG_PCD_APP) /* If the update is valid, and it targets the network core: perform the * update and indicate to the caller of this function that no update is * available @@ -1029,7 +1029,8 @@ boot_validated_swap_type(struct boot_loader_state *state, swap_type = BOOT_SWAP_TYPE_NONE; } } -#endif /* CONFIG_SOC_NRF5340_CPUAPP */ +#endif /* CONFIG_SOC_NRF5340_CPUAPP && PM_CPUNET_B0N_ADDRESS && + !CONFIG_NRF53_MULTI_IMAGE_UPDATE && CONFIG_PCD_APP */ } return swap_type; From b4464ad3a00a699fb0097e362ac03b30671fdda4 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Wed, 31 May 2023 14:41:13 +0200 Subject: [PATCH 28/38] [nrf noup] boot: Add support for NSIB and multi-image This adds support for using both NSIB and the multi-image configuration in MCUboot. Before this was not possible due to upgradable bootloader support through NSIB was using the `UPDATEABLE_IMAGE_NUMBER` configuration to update the updateable bootloader. In this commit we change from using `FLASH_AREA_IMAGE_PRIMARY` to get the flash area ID to using the bootloader state where we set the flash area ID of the free updatable bootloader slot if the image is intended for this slot. Ref. NCSDK-19223 Ref. NCSDK-23305 Signed-off-by: Sigvart Hovland Signed-off-by: Dominik Ermel (cherry picked from commit 03af90f48c7b9c888642b6e7c1c565d2ae721cd4) (cherry picked from commit 0d436749a2f2e9e5784a09de2f8a7946e80f0310) --- boot/bootutil/src/loader.c | 44 +++++++++++++++++++------ boot/zephyr/include/sysflash/sysflash.h | 19 +++++++++-- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 4bd001ba3..8dd27714a 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -845,6 +845,11 @@ boot_validate_slot(struct boot_loader_state *state, int slot, if (BOOT_CURR_IMG(state) == 1) { min_addr = PM_CPUNET_APP_ADDRESS; max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE; +#ifdef PM_S1_ADDRESS + } else if (BOOT_CURR_IMG(state) == 0) { + min_addr = PM_S0_ADDRESS; + max_addr = pri_fa->fa_off + pri_fa->fa_size; +#endif } else #endif { @@ -965,18 +970,37 @@ boot_validated_swap_type(struct boot_loader_state *state, { const struct flash_area *primary_fa; rc = flash_area_open(flash_area_id_from_multi_image_slot( - BOOT_CURR_IMG(state), - BOOT_PRIMARY_SLOT), - &primary_fa); - + BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT), + &primary_fa); if (rc != 0) { return BOOT_SWAP_TYPE_FAIL; } - /* Get start and end of primary slot for current image */ - if (reset_addr < primary_fa->fa_off || - reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { - /* The image in the secondary slot is not intended for this image - */ + + /* Check start and end of primary slot for current image */ + if (reset_addr < primary_fa->fa_off) { +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + const struct flash_area *nsib_fa; + + /* NSIB upgrade slot */ + rc = flash_area_open((uint32_t)_image_1_primary_slot_id, + &nsib_fa); + + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } + + /* Image is placed before Primary and within the NSIB slot */ + if (reset_addr > nsib_fa->fa_off + && reset_addr < (nsib_fa->fa_off + nsib_fa->fa_size)) { + /* Set primary to be NSIB upgrade slot */ + BOOT_IMG_AREA(state, 0) = nsib_fa; + } +#else + return BOOT_SWAP_TYPE_NONE; +#endif + + } else if (reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { + /* The image in the secondary slot is not intended for any */ return BOOT_SWAP_TYPE_NONE; } } @@ -1240,7 +1264,7 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) BOOT_LOG_INF("Image %d upgrade secondary slot -> primary slot", image_index); BOOT_LOG_INF("Erasing the primary slot"); - rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), + rc = flash_area_open(flash_area_get_id(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)), &fap_primary_slot); assert (rc == 0); diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index d6a74f370..da21832a9 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -23,9 +23,24 @@ /* If B0 is present then two bootloaders are present, and we must use * a single secondary slot for both primary slots. */ -#ifdef PM_B0_ADDRESS - +#if defined(PM_B0_ADDRESS) extern uint32_t _image_1_primary_slot_id[]; +#endif +#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) +#elif defined(PM_B0_ADDRESS) #define FLASH_AREA_IMAGE_PRIMARY(x) \ ((x == 0) ? \ From 418b6fe501c8cf0a067168a136ff845b8b363242 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 10 Aug 2023 17:32:48 +0000 Subject: [PATCH 29/38] [nrf noup] sysflash: Move partition manager definitions to pm_sysflash.h Making sysflash.h and pm_sysflash.h more readable. Signed-off-by: Dominik Ermel (cherry picked from commit c3b33eb4b3510b251a0712bc65f6749b5ecf4346) --- boot/zephyr/include/sysflash/pm_sysflash.h | 92 ++++++++++++++++++++++ boot/zephyr/include/sysflash/sysflash.h | 90 ++------------------- 2 files changed, 97 insertions(+), 85 deletions(-) create mode 100644 boot/zephyr/include/sysflash/pm_sysflash.h diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h new file mode 100644 index 000000000..377291e8b --- /dev/null +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef __PM_SYSFLASH_H__ +#define __PM_SYSFLASH_H__ +/* Blocking the __SYSFLASH_H__ */ +#define __SYSFLASH_H__ + +#include +#include + +#ifndef CONFIG_SINGLE_APPLICATION_SLOT + +#if (MCUBOOT_IMAGE_NUMBER == 1) + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID + +#elif (MCUBOOT_IMAGE_NUMBER == 2) + +/* If B0 is present then two bootloaders are present, and we must use + * a single secondary slot for both primary slots. + */ +#if defined(PM_B0_ADDRESS) +extern uint32_t _image_1_primary_slot_id[]; +#endif +#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) +#elif defined(PM_B0_ADDRESS) + +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + (uint32_t)_image_1_primary_slot_id : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + 255 ) +#else + +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) + +#endif /* PM_B0_ADDRESS */ + +#endif +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID + +#else /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID +/* NOTE: Scratch parition is not used by single image DFU but some of + * functions in common files reference it, so the definitions has been + * provided to allow compilation of common units. + */ +#define FLASH_AREA_IMAGE_SCRATCH 0 + +#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#endif /* __PM_SYSFLASH_H__ */ diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index da21832a9..501c0b2e5 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -4,93 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __SYSFLASH_H__ -#define __SYSFLASH_H__ - #if USE_PARTITION_MANAGER -#include -#include - -#ifndef CONFIG_SINGLE_APPLICATION_SLOT - -#if (MCUBOOT_IMAGE_NUMBER == 1) - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID - -#elif (MCUBOOT_IMAGE_NUMBER == 2) - -/* If B0 is present then two bootloaders are present, and we must use - * a single secondary slot for both primary slots. - */ -#if defined(PM_B0_ADDRESS) -extern uint32_t _image_1_primary_slot_id[]; -#endif -#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) -#elif defined(PM_B0_ADDRESS) - -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - (uint32_t)_image_1_primary_slot_id : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - 255 ) -#else - -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) - -#endif /* PM_B0_ADDRESS */ - +/* Blocking the rest of the file */ +#define __SYSFLASH_H__ +#include #endif -#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID - -#else /* CONFIG_SINGLE_APPLICATION_SLOT */ -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID -/* NOTE: Scratch parition is not used by single image DFU but some of - * functions in common files reference it, so the definitions has been - * provided to allow compilation of common units. - */ -#define FLASH_AREA_IMAGE_SCRATCH 0 - -#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ - -#else +#ifndef __SYSFLASH_H__ +#define __SYSFLASH_H__ -#include #include #include #include @@ -141,6 +63,4 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #endif /* CONFIG_SINGLE_APPLICATION_SLOT */ -#endif /* USE_PARTITION_MANAGER */ - #endif /* __SYSFLASH_H__ */ From 7b87633282e9d0bad957af56992022848fb02723 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 11 Aug 2023 12:29:13 +0000 Subject: [PATCH 30/38] [nrf noup] sysflash: Add support for three images The commit modifies pm_sysflash.h to add support for three application images. Ref. NCSDK-19223 Signed-off-by: Dominik Ermel Signed-off-by: Sigvart Hovland (cherry picked from commit 77c7e253dc0dd81db87bc315c1ee2775ef873561) (cherry picked from commit d700515040d6d39b1101b6a344728623e2a56192) --- boot/zephyr/include/sysflash/pm_sysflash.h | 82 ++++++++++++---------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index 377291e8b..db60ddd03 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -11,37 +11,19 @@ #include #include +#include #ifndef CONFIG_SINGLE_APPLICATION_SLOT -#if (MCUBOOT_IMAGE_NUMBER == 1) - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID - -#elif (MCUBOOT_IMAGE_NUMBER == 2) - +#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) /* If B0 is present then two bootloaders are present, and we must use * a single secondary slot for both primary slots. */ -#if defined(PM_B0_ADDRESS) extern uint32_t _image_1_primary_slot_id[]; -#endif -#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) +#endif /* (MCUBOOT_IMAGE_NUMBER == 2 && defined(PM_B0_ADDRESS) */ -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) -#elif defined(PM_B0_ADDRESS) +#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ + !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) #define FLASH_AREA_IMAGE_PRIMARY(x) \ ((x == 0) ? \ @@ -56,26 +38,52 @@ extern uint32_t _image_1_primary_slot_id[]; (x == 1) ? \ PM_MCUBOOT_SECONDARY_ID: \ 255 ) + +#else /* MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ + * !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + */ + +/* Each pair of slots is separated by , and there is no terminating character */ +#define FLASH_AREA_IMAGE_0_SLOTS PM_MCUBOOT_PRIMARY_ID, PM_MCUBOOT_SECONDARY_ID +#define FLASH_AREA_IMAGE_1_SLOTS PM_MCUBOOT_PRIMARY_1_ID, PM_MCUBOOT_SECONDARY_1_ID +#define FLASH_AREA_IMAGE_2_SLOTS PM_MCUBOOT_PRIMARY_2_ID, PM_MCUBOOT_SECONDARY_2_ID + +#if (MCUBOOT_IMAGE_NUMBER == 1) +#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS +#elif (MCUBOOT_IMAGE_NUMBER == 2) +#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS, \ + FLASH_AREA_IMAGE_1_SLOTS +#elif (MCUBOOT_IMAGE_NUMBER == 3) +#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS, \ + FLASH_AREA_IMAGE_1_SLOTS, \ + FLASH_AREA_IMAGE_2_SLOTS #else +#error Unsupported number of images +#endif -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) +static inline uint32_t __flash_area_ids_for_slot(int img, int slot) +{ + static const int all_slots[] = { + ALL_AVAILABLE_SLOTS + }; + return all_slots[img * 2 + slot]; +}; -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) +#undef FLASH_AREA_IMAGE_0_SLOTS +#undef FLASH_AREA_IMAGE_1_SLOTS +#undef FLASH_AREA_IMAGE_2_SLOTS +#undef ALL_AVAILABLE_SLOTS -#endif /* PM_B0_ADDRESS */ +#define FLASH_AREA_IMAGE_PRIMARY(x) __flash_area_ids_for_slot(x, 0) +#define FLASH_AREA_IMAGE_SECONDARY(x) __flash_area_ids_for_slot(x, 1) +#if !defined(CONFIG_BOOT_SWAP_USING_MOVE) +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID #endif -#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID + +#endif /* MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ + * !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + */ #else /* CONFIG_SINGLE_APPLICATION_SLOT */ From 8e373ccbbb896ff83587abd38c94a2ddf17687a6 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 22 Sep 2023 21:31:08 +0000 Subject: [PATCH 31/38] [nrf noup] loader: Do not check reset vector for XIP image The XIP image, 2, does not have reset vector. Signed-off-by: Dominik Ermel (cherry picked from commit 30181d80583e38336df98690d9c2a0dc1373afad) --- boot/bootutil/src/loader.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8dd27714a..6892770f5 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -823,6 +823,16 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * overwriting an application written to the incorrect slot. * This feature is only supported by ARM platforms. */ +#if MCUBOOT_IMAGE_NUMBER >= 3 + /* Currently the MCUboot can be configured for up to 3 image, where image number 2 is + * designated for XIP, where it is the second part of image stored in slots of image + * 0. This part of image is not bootable, as the XIP setup is done by the app in + * image 0 slot, and it does not carry the reset vector. + */ + if (area_id == FLASH_AREA_IMAGE_SECONDARY(2)) { + goto out; + } +#endif if (area_id == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) { const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT); struct image_header *secondary_hdr = boot_img_hdr(state, slot); From 90a91e08fedfea3b238ffe5489904d4fc19fb711 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 18 Sep 2023 13:47:00 +0100 Subject: [PATCH 32/38] [nrf noup] zephyr: Add RAM flash configuration to cache for sysbuild Puts the flash simulation configurtion into cache variables that can be used by other applications and CMake code to know specifics on the simulated flash details Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit c19337f808b9459a4ae6904bb3e6f2a0eff11b38) --- boot/zephyr/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index ce1c88d33..4b840d9d2 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -362,3 +362,14 @@ zephyr_library_sources( ${BOOT_DIR}/zephyr/nrf_cleanup.c ) endif() + +if(SYSBUILD AND CONFIG_PCD_APP) + # Sysbuild requires details of the RAM flash device are stored to the cache of MCUboot so + # that they can be read when running partition manager + dt_nodelabel(ram_flash_dev NODELABEL flash_sim0) + dt_reg_addr(ram_flash_addr PATH ${ram_flash_dev}) + dt_reg_size(ram_flash_size PATH ${ram_flash_dev}) + + set(RAM_FLASH_ADDR "${ram_flash_addr}" CACHE STRING "" FORCE) + set(RAM_FLASH_SIZE "${ram_flash_size}" CACHE STRING "" FORCE) +endif() From 4b36f9f28ed1daae217b8b8c5ba353b2b691c09e Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 17 Oct 2023 11:28:09 +0200 Subject: [PATCH 33/38] [nrf noup] zephyr: Boot even if EXT_ABI is not provided This removes the `return;` to ensure that the application is booted even if EXT_ABI is not provided to the application because it does not include `FW_INFO`. Added a bit more description to the error messages when FW_INFO is not found and EXT_ABI is not able to be provided to the next image. Ref. NCSDK-24132 Signed-off-by: Sigvart Hovland Signed-off-by: Dominik Ermel (cherry picked from commit e6e72a005aff6a45aea570e36ec985ec7480ad68) --- boot/zephyr/main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 5bc8b1c7e..d601eae0a 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -258,13 +258,16 @@ static void do_boot(struct boot_rsp *rsp) #endif #if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) - bool provided = fw_info_ext_api_provide(fw_info_find((uint32_t)vt), true); + const struct fw_info *firmware_info = fw_info_find((uint32_t) vt); + bool provided = fw_info_ext_api_provide(firmware_info, true); #ifdef PM_S0_ADDRESS /* Only fail if the immutable bootloader is present. */ if (!provided) { - BOOT_LOG_ERR("Failed to provide EXT_APIs\n"); - return; + if (firmware_info == NULL) { + BOOT_LOG_WRN("Unable to find firmware info structure in %p", vt); + } + BOOT_LOG_ERR("Failed to provide EXT_APIs to %p", vt); } #endif #endif From c5aadd71007d0da1b4a2ee392fd58ea06e7bf7a5 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Wed, 27 Sep 2023 15:18:04 +0200 Subject: [PATCH 34/38] =?UTF-8?q?[nrf=20noup]=C2=A0loader:=20Add=20firmwar?= =?UTF-8?q?e=20version=20check=20downgrade=20prevention?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For nRF53, the only existing version number metadata is stored in the `firmware_info` structure in the network core. This utilizes PCD to read out the version number and compares it against the version number found in the secondary slot for the network core. Ref. NCSDK-21379 Signed-off-by: Sigvart Hovland Signed-off-by: Dominik Ermel (cherry picked from commit 4441695f31bcc566297595d822f76c0d6e45d13f) --- boot/bootutil/src/loader.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 6892770f5..3367e79ac 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -51,6 +51,10 @@ #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) #include +#ifdef CONFIG_PCD_READ_NETCORE_APP_VERSION +#include +int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); +#endif #endif #ifdef MCUBOOT_ENC_IMAGES @@ -782,9 +786,21 @@ boot_validate_slot(struct boot_loader_state *state, int slot, #if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION) if (slot != BOOT_PRIMARY_SLOT) { /* Check if version of secondary slot is sufficient */ - rc = boot_version_cmp( - &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, - &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); + +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) \ + && defined(CONFIG_PCD_APP) && defined(CONFIG_PCD_READ_NETCORE_APP_VERSION) + if (BOOT_CURR_IMG(state) == 1) { + rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SECONDARY_SLOT)); + } else { + rc = boot_version_cmp( + &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, + &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); + } +#else + rc = boot_version_cmp( + &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, + &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); +#endif if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) { BOOT_LOG_ERR("insufficient version in secondary slot"); flash_area_erase(fap, 0, flash_area_get_size(fap)); From ed3a0c2dbe3d52565a8316cfd82ee58c28650415 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 15 Feb 2024 16:47:25 +0100 Subject: [PATCH 35/38] [nrf noup] loader: introduced cleanup of unusable secondary slot Added procedure which clean-up content of all the secondary slot which contains valid header but couldn't be assigned to any of supported primary images. This behavior is needed when configuration allows to use one secondary slot for collecting image for multiple primary slots. Signed-off-by: Andrzej Puzdrowski --- boot/bootutil/src/loader.c | 90 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 3367e79ac..ccf3def36 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -951,6 +951,87 @@ boot_update_security_counter(uint8_t image_index, int slot, } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ +#if defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ +(defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP)) + +#define SEC_SLOT_VIRGIN 0 +#define SEC_SLOT_TOUCHED 1 +#define SEC_SLOT_ASSIGNED 2 + +#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ + !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +/* This configuration is peculiar - the one physical secondary slot is + * mocking two logical secondary + */ +#define SEC_SLOT_PHYSICAL_CNT 1 +#else +#define SEC_SLOT_PHYSICAL_CNT MCUBOOT_IMAGE_NUMBER +#endif + +static uint8_t sec_slot_assignmnet[SEC_SLOT_PHYSICAL_CNT] = {0}; + +static inline void sec_slot_touch(struct boot_loader_state *state) +{ + uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); + + if (SEC_SLOT_VIRGIN == sec_slot_assignmnet[idx]) { + sec_slot_assignmnet[idx] = SEC_SLOT_TOUCHED; + } +} + +static inline void sec_slot_mark_assigned(struct boot_loader_state *state) +{ + uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); + + sec_slot_assignmnet[idx] = SEC_SLOT_ASSIGNED; +} + +/** + * Cleanu up all secondary slot which couldn't be assigned to any primary slot. + * + * This function erases content of each secondary slot which contains valid + * header but couldn't be assigned to any of supported primary images. + * + * This function is supposed to be called after boot_validated_swap_type() + * iterates over all the images in context_boot_go(). + */ +static void sec_slot_cleanup_if_unusable(void) +{ + uint8_t idx; + + for (idx = 0; idx < SEC_SLOT_PHYSICAL_CNT; idx++) { + if (SEC_SLOT_TOUCHED == sec_slot_assignmnet[idx]) { + const struct flash_area *secondary_fa; + int rc; + + rc = flash_area_open(flash_area_id_from_multi_image_slot(idx, BOOT_SECONDARY_SLOT), + &secondary_fa); + if (!rc) { + rc = flash_area_erase(secondary_fa, 0, secondary_fa->fa_size); + if (!rc) { + BOOT_LOG_ERR("Cleaned-up secondary slot of %d. image.", idx); + } + } + + if (rc) { + BOOT_LOG_ERR("Can not cleanup secondary slot of %d. image.", idx); + } + } + } +} +#else +static inline void sec_slot_touch(struct boot_loader_state *state) +{ +} +static inline void sec_slot_mark_assigned(struct boot_loader_state *state) +{ +} +static inline void sec_slot_cleanup_if_unusable(void) +{ +} +#endif /* defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ + defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) */ + #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) /** * Determines which swap operation to perform, if any. If it is determined @@ -989,6 +1070,9 @@ boot_validated_swap_type(struct boot_loader_state *state, if (rc != 0) { return BOOT_SWAP_TYPE_FAIL; } + + sec_slot_touch(state); + #ifdef PM_S1_ADDRESS #ifdef PM_CPUNET_B0N_ADDRESS if(reset_addr < PM_CPUNET_B0N_ADDRESS) @@ -1023,6 +1107,7 @@ boot_validated_swap_type(struct boot_loader_state *state, } #else return BOOT_SWAP_TYPE_NONE; + #endif } else if (reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { @@ -1031,7 +1116,9 @@ boot_validated_swap_type(struct boot_loader_state *state, } } #endif /* PM_S1_ADDRESS */ + sec_slot_mark_assigned(state); } + #endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); @@ -2256,6 +2343,9 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } + /* cleanup secondary slots which were recognized unusable*/ + sec_slot_cleanup_if_unusable(); + #if (BOOT_IMAGE_NUMBER > 1) if (has_upgrade) { /* Iterate over all the images and verify whether the image dependencies From 8bb85670472789ccd89c74745d68772159e1e280 Mon Sep 17 00:00:00 2001 From: Nikodem Kastelik Date: Mon, 9 Oct 2023 09:55:57 +0200 Subject: [PATCH 36/38] [nrf noup] boards: thingy53: disable GPIO ISR support Change disables GPIO interrupt support in Zephyr GPIO driver, which is not obligatory for MCUboot. This is needed to reduce memory footprint. Signed-off-by: Nikodem Kastelik Signed-off-by: Dominik Ermel (cherry picked from commit 69805fa4d4193e53951cf5bfaceef23848e45897) --- boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index 7d3bc0bec..e10656678 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -21,6 +21,7 @@ CONFIG_UART_LINE_CTRL=y # MCUBoot serial CONFIG_GPIO=y +CONFIG_GPIO_NRFX_INTERRUPT=n CONFIG_MCUBOOT_SERIAL=y CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y CONFIG_BOOT_SERIAL_CDC_ACM=y From 3c2f2ff12bc20625cd65730b6036d061de4da5f7 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Fri, 8 Dec 2023 13:18:12 +0100 Subject: [PATCH 37/38] [nrf noup] boards: thingy91x: add board config This patch adds board configuration for the Thingy:91 X. Signed-off-by: Maximilian Deubel (cherry picked from commit a9d5fa76a6840f8934b2aaaf51e290f91eb3f991) --- .../boards/thingy91x_nrf5340_cpuapp.conf | 54 +++++++++++++++++++ boot/zephyr/boards/thingy91x_nrf9151.conf | 8 +++ 2 files changed, 62 insertions(+) create mode 100644 boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf create mode 100644 boot/zephyr/boards/thingy91x_nrf9151.conf diff --git a/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf new file mode 100644 index 000000000..72dfa7fca --- /dev/null +++ b/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf @@ -0,0 +1,54 @@ +# MCUBoot settings +CONFIG_BOOT_MAX_IMG_SECTORS=110 + +# MCUboot serial recovery +CONFIG_MCUBOOT_SERIAL=y + +# Disable Zephyr console +CONFIG_LOG=n +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n + +# Serial +CONFIG_SERIAL=y +CONFIG_UART_NRFX=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_LINE_CTRL=y + +# MCUboot serial recovery +CONFIG_GPIO=y +CONFIG_MCUBOOT_SERIAL=y +CONFIG_BOOT_SERIAL_CDC_ACM=y + +# Required by USB +CONFIG_MULTITHREADING=y + +# USB +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_PRODUCT="MCUBOOT" +CONFIG_USB_CDC_ACM=y +CONFIG_USB_COMPOSITE_DEVICE=y +CONFIG_USB_MASS_STORAGE=n +CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor" +CONFIG_USB_DEVICE_VID=0x1915 +CONFIG_USB_DEVICE_PID=0x520F + +CONFIG_BOOT_SERIAL_BOOT_MODE=y + +CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x13E00 + +# The following configurations are required to support simultaneous multi image update +CONFIG_PCD_APP=y +CONFIG_UPDATEABLE_IMAGE_NUMBER=2 +CONFIG_BOOT_UPGRADE_ONLY=y +# The network core cannot access external flash directly. The flash simulator must be used to +# provide a memory region that is used to forward the new firmware to the network core. +CONFIG_FLASH_SIMULATOR=y +CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y +CONFIG_FLASH_SIMULATOR_STATS=n + +CONFIG_BOOT_IMAGE_ACCESS_HOOKS=y +CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y + +CONFIG_NRF53_RECOVERY_NETWORK_CORE=y diff --git a/boot/zephyr/boards/thingy91x_nrf9151.conf b/boot/zephyr/boards/thingy91x_nrf9151.conf new file mode 100644 index 000000000..33cd3301c --- /dev/null +++ b/boot/zephyr/boards/thingy91x_nrf9151.conf @@ -0,0 +1,8 @@ +# MCUBoot settings +CONFIG_BOOT_MAX_IMG_SECTORS=512 + +CONFIG_SPI=y +CONFIG_SPI_NOR=y +CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 +CONFIG_SPI_NOR_SFDP_DEVICETREE=y +CONFIG_MULTITHREADING=y From f6870686200ad902b924b45dfbb6127cdbaef07f Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 5 Mar 2024 18:44:13 +0100 Subject: [PATCH 38/38] [nrf noup] boot/zephyr/nrf_cleanup: cleanup uarte pins Added procedure which does configure UARTE pins to the default states. This allows to reduce power consumption if pin is floating. clean-up UARTE only if its driver was enabled Signed-off-by: Andrzej Puzdrowski --- boot/zephyr/nrf_cleanup.c | 51 +++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 2165159ea..312a521f3 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -7,6 +7,7 @@ #include #if defined(NRF_UARTE0) || defined(NRF_UARTE1) #include + #include #endif #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) #include @@ -46,6 +47,34 @@ static void nrf_cleanup_clock(void) nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); } +#if (defined(NRF_UARTE0) || defined(NRF_UARTE1)) && defined(CONFIG_UART_NRFX_UARTE) +static void uninit_used_uarte(NRF_UARTE_Type *p_reg) +{ + uint32_t pin[4]; + + nrf_uarte_disable(p_reg); + nrf_uarte_int_disable(p_reg, 0xFFFFFFFF); + + pin[0] = nrf_uarte_tx_pin_get(p_reg); + pin[1] = nrf_uarte_rx_pin_get(p_reg); + pin[2] = nrf_uarte_rts_pin_get(p_reg); + pin[3] = nrf_uarte_cts_pin_get(p_reg); + + for (int i = 0; i < 4; i++) { + if (pin[i] != NRF_UARTE_PSEL_DISCONNECTED) { + nrf_gpio_cfg_default(pin[i]); + } + } + + #if defined(NRF_DPPIC) + /* Clear all SUBSCRIBE configurations. */ + memset((uint8_t *)p_reg + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); + /* Clear all PUBLISH configurations. */ + memset((uint8_t *)p_reg + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); + #endif +} +#endif + void nrf_cleanup_peripheral(void) { #if defined(NRF_RTC0) @@ -57,25 +86,11 @@ void nrf_cleanup_peripheral(void) #if defined(NRF_RTC2) nrf_cleanup_rtc(NRF_RTC2); #endif -#if defined(NRF_UARTE0) - nrf_uarte_disable(NRF_UARTE0); - nrf_uarte_int_disable(NRF_UARTE0, 0xFFFFFFFF); -#if defined(NRF_DPPIC) - /* Clear all SUBSCRIBE configurations. */ - memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); - /* Clear all PUBLISH configurations. */ - memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); -#endif -#endif -#if defined(NRF_UARTE1) - nrf_uarte_disable(NRF_UARTE1); - nrf_uarte_int_disable(NRF_UARTE1, 0xFFFFFFFF); -#if defined(NRF_DPPIC) - /* Clear all SUBSCRIBE configurations. */ - memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); - /* Clear all PUBLISH configurations. */ - memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); +#if defined(NRF_UARTE0) && defined(CONFIG_UART_NRFX_UARTE) + uninit_used_uarte(NRF_UARTE0); #endif +#if defined(NRF_UARTE1) && defined(CONFIG_UART_NRFX_UARTE) + uninit_used_uarte(NRF_UARTE1); #endif #if defined(NRF_PPI) nrf_ppi_channels_disable_all(NRF_PPI);