From cd82f8bf7ad31fd602f81ab5c676de7666f1abdd Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 20 Nov 2023 09:18:27 +0100 Subject: [PATCH 01/70] boot: zephyr: add support for lpcxpresso55s28 Add default configuration for lpcxpresso55s28. Signed-off-by: Andrej Butok --- boot/zephyr/boards/lpcxpresso55s28.conf | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 boot/zephyr/boards/lpcxpresso55s28.conf diff --git a/boot/zephyr/boards/lpcxpresso55s28.conf b/boot/zephyr/boards/lpcxpresso55s28.conf new file mode 100644 index 000000000..fbe7b6723 --- /dev/null +++ b/boot/zephyr/boards/lpcxpresso55s28.conf @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +#LPC does not support the MCUBoot swap mode. +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_BOOT_MAX_IMG_SECTORS=512 From 47b34362552835621bc289d53d2127691088cb7c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 21 Nov 2023 10:38:41 +0000 Subject: [PATCH 02/70] zephyr: kconfig: Prevent MBEDTLS selection when tinycrypt is used Prevents an issue which occurs when the MCUboot configuration is changed which then selects multiple conflicting symbols Signed-off-by: Jamie McCrae --- boot/zephyr/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 78fe793ed..183bb500e 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -30,6 +30,7 @@ config BOOT_USE_TINYCRYPT # When building for ECDSA, we use our own copy of mbedTLS, so the # Zephyr one must not be enabled or the MBEDTLS_CONFIG_FILE macros # will collide. + select MBEDTLS_PROMPTLESS help Use TinyCrypt for crypto primitives. From 3f0b89d680ee1bc7bfeee1dd8055986c3dd9c278 Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Mon, 27 Nov 2023 14:45:57 +0100 Subject: [PATCH 03/70] boot: zephyr: add support for mimxrt101x_evk Add default configuration for mimxrt1010_evk and mimxrt1015_evk. Signed-off-by: Andrej Butok --- boot/zephyr/boards/mimxrt1010_evk.conf | 4 ++++ boot/zephyr/boards/mimxrt1015_evk.conf | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 boot/zephyr/boards/mimxrt1010_evk.conf create mode 100644 boot/zephyr/boards/mimxrt1015_evk.conf diff --git a/boot/zephyr/boards/mimxrt1010_evk.conf b/boot/zephyr/boards/mimxrt1010_evk.conf new file mode 100644 index 000000000..e7737afde --- /dev/null +++ b/boot/zephyr/boards/mimxrt1010_evk.conf @@ -0,0 +1,4 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOOT_MAX_IMG_SECTORS=2048 diff --git a/boot/zephyr/boards/mimxrt1015_evk.conf b/boot/zephyr/boards/mimxrt1015_evk.conf new file mode 100644 index 000000000..e7737afde --- /dev/null +++ b/boot/zephyr/boards/mimxrt1015_evk.conf @@ -0,0 +1,4 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOOT_MAX_IMG_SECTORS=2048 From 5e6cffbf4a8774dd9911a4abed6f8f24ea760786 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 24 Nov 2023 08:27:23 +0000 Subject: [PATCH 04/70] boot: boot_serial: Fix single slot encrypted image list Fixes an issue whereby MCUboot is configured in single application slot mode with serial recovery with encryption and an encrypted image has been loaded, if valid this will have been decrypted, so should not be treated as encrypted Signed-off-by: Jamie McCrae --- boot/boot_serial/src/boot_serial.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 5213866ad..bc07e2d60 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -294,10 +294,12 @@ bs_list(char *buf, int len) if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) { #if defined(MCUBOOT_ENC_IMAGES) +#if !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) if (IS_ENCRYPTED(&hdr) && MUST_DECRYPT(fap, image_index, &hdr)) { FIH_CALL(boot_image_validate_encrypted, fih_rc, fap, &hdr, tmpbuf, sizeof(tmpbuf)); } else { +#endif if (IS_ENCRYPTED(&hdr)) { /* * There is an image present which has an encrypted flag set but is @@ -310,7 +312,7 @@ bs_list(char *buf, int len) FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, &hdr, fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL); -#if defined(MCUBOOT_ENC_IMAGES) +#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) } #endif } From 433b8480f760bdf40381e7543e358185a1006a2b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 16 Aug 2023 07:33:24 +0100 Subject: [PATCH 05/70] zephyr: Move IO functions out of main to separate file Moves IO functions into a separate file to allow reuse Signed-off-by: Jamie McCrae --- boot/zephyr/CMakeLists.txt | 1 + boot/zephyr/include/io/io.h | 78 +++++++++++++++ boot/zephyr/io.c | 190 ++++++++++++++++++++++++++++++++++++ boot/zephyr/main.c | 164 ++----------------------------- 4 files changed, 275 insertions(+), 158 deletions(-) create mode 100644 boot/zephyr/include/io/io.h create mode 100644 boot/zephyr/io.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index ad4c823f2..3ce4235cb 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -56,6 +56,7 @@ endif() # Zephyr port-specific sources. zephyr_library_sources( main.c + io.c flash_map_extended.c os.c keys.c diff --git a/boot/zephyr/include/io/io.h b/boot/zephyr/include/io/io.h new file mode 100644 index 000000000..332eefbd8 --- /dev/null +++ b/boot/zephyr/include/io/io.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * Copyright (c) 2020 Arm Limited + * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef H_IO_ +#define H_IO_ + +#include + +#ifdef CONFIG_SOC_FAMILY_NRF +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Initialises the configured LED. + */ +void io_led_init(void); + +/* + * Checks if GPIO is set in the required way to remain in serial recovery mode + * + * @retval false for normal boot, true for serial recovery boot + */ +bool io_detect_pin(void); + +/* + * Checks if board was reset using reset pin and if device should stay in + * serial recovery mode + * + * @retval false for normal boot, true for serial recovery boot + */ +bool io_detect_pin_reset(void); + +/* + * Checks board boot mode via retention subsystem and if device should stay in + * serial recovery mode + * + * @retval false for normal boot, true for serial recovery boot + */ +bool io_detect_boot_mode(void); + +#ifdef CONFIG_SOC_FAMILY_NRF +static inline bool io_boot_skip_serial_recovery() +{ + uint32_t rr = nrfx_reset_reason_get(); + + return !(rr == 0 || (rr & NRFX_RESET_REASON_RESETPIN_MASK)); +} +#else +static inline bool io_boot_skip_serial_recovery() +{ + return false; +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/boot/zephyr/io.c b/boot/zephyr/io.c new file mode 100644 index 000000000..6d3b01ef5 --- /dev/null +++ b/boot/zephyr/io.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * Copyright (c) 2020 Arm Limited + * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "target.h" + +#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) +#include +#endif + +#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) +#include +#endif + +/* Validate serial recovery configuration */ +#ifdef CONFIG_MCUBOOT_SERIAL +#if !defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) && \ + !defined(CONFIG_BOOT_SERIAL_WAIT_FOR_DFU) && \ + !defined(CONFIG_BOOT_SERIAL_BOOT_MODE) && \ + !defined(CONFIG_BOOT_SERIAL_NO_APPLICATION) && \ + !defined(CONFIG_BOOT_SERIAL_PIN_RESET) +#error "Serial recovery selected without an entrance mode set" +#endif +#endif + +#ifdef CONFIG_MCUBOOT_INDICATION_LED + +/* + * The led0 devicetree alias is optional. If present, we'll use it + * to turn on the LED whenever the button is pressed. + */ +#if DT_NODE_EXISTS(DT_ALIAS(mcuboot_led0)) +#define LED0_NODE DT_ALIAS(mcuboot_led0) +#elif DT_NODE_EXISTS(DT_ALIAS(bootloader_led0)) +#warning "bootloader-led0 alias is deprecated; use mcuboot-led0 instead" +#define LED0_NODE DT_ALIAS(bootloader_led0) +#endif + +#if DT_NODE_HAS_STATUS(LED0_NODE, okay) && DT_NODE_HAS_PROP(LED0_NODE, gpios) +static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios); +#else +/* A build error here means your board isn't set up to drive an LED. */ +#error "Unsupported board: led0 devicetree alias is not defined" +#endif + +void io_led_init(void) +{ + if (!device_is_ready(led0.port)) { + BOOT_LOG_ERR("Didn't find LED device referred by the LED0_NODE\n"); + return; + } + + gpio_pin_configure_dt(&led0, GPIO_OUTPUT); + gpio_pin_set_dt(&led0, 0); +} +#endif /* CONFIG_MCUBOOT_INDICATION_LED */ + +#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) + +#if defined(CONFIG_MCUBOOT_SERIAL) +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY +#else +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY +#endif + +#define BUTTON_0_NODE DT_ALIAS(mcuboot_button0) + +#if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios) +static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios); +#else +#error "Serial recovery/USB DFU button must be declared in device tree as 'mcuboot_button0'" +#endif + +bool io_detect_pin(void) +{ + int rc; + int pin_active; + + if (!device_is_ready(button0.port)) { + __ASSERT(false, "GPIO device is not ready.\n"); + return false; + } + + rc = gpio_pin_configure_dt(&button0, GPIO_INPUT); + __ASSERT(rc == 0, "Failed to initialize boot detect pin.\n"); + + rc = gpio_pin_get_dt(&button0); + pin_active = rc; + + __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); + + if (pin_active) { + if (BUTTON_0_DETECT_DELAY > 0) { +#ifdef CONFIG_MULTITHREADING + k_sleep(K_MSEC(50)); +#else + k_busy_wait(50000); +#endif + + /* Get the uptime for debounce purposes. */ + int64_t timestamp = k_uptime_get(); + + for(;;) { + rc = gpio_pin_get_dt(&button0); + pin_active = rc; + __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); + + /* Get delta from when this started */ + uint32_t delta = k_uptime_get() - timestamp; + + /* If not pressed OR if pressed > debounce period, stop. */ + if (delta >= BUTTON_0_DETECT_DELAY || !pin_active) { + break; + } + + /* Delay 1 ms */ +#ifdef CONFIG_MULTITHREADING + k_sleep(K_MSEC(1)); +#else + k_busy_wait(1000); +#endif + } + } + } + + return (bool)pin_active; +} +#endif + +#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) +bool io_detect_pin_reset(void) +{ + uint32_t reset_cause; + int rc; + + rc = hwinfo_get_reset_cause(&reset_cause); + + if (rc == 0 && reset_cause == RESET_PIN) { + (void)hwinfo_clear_reset_cause(); + return true; + } + + return false; +} +#endif + +#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) +bool io_detect_boot_mode(void) +{ + int32_t boot_mode; + + boot_mode = bootmode_check(BOOT_MODE_TYPE_BOOTLOADER); + + if (boot_mode == 1) { + /* Boot mode to stay in bootloader, clear status and enter serial + * recovery mode + */ + bootmode_clear(); + + return true; + } + + return false; +} +#endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 7b3702475..abd2fe6eb 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -31,6 +31,7 @@ #include #endif +#include "io/io.h" #include "target.h" #include "bootutil/bootutil_log.h" @@ -74,10 +75,6 @@ const struct boot_uart_funcs boot_funcs = { }; #endif -#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE -#include -#endif - #if defined(CONFIG_BOOT_USB_DFU_WAIT) || defined(CONFIG_BOOT_USB_DFU_GPIO) #include #endif @@ -86,10 +83,6 @@ const struct boot_uart_funcs boot_funcs = { #include #endif -#ifdef CONFIG_BOOT_SERIAL_PIN_RESET -#include -#endif - /* CONFIG_LOG_MINIMAL is the legacy Kconfig property, * replaced by CONFIG_LOG_MODE_MINIMAL. */ @@ -132,67 +125,8 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); * !defined(ZEPHYR_LOG_MODE_MINIMAL) */ -#ifdef CONFIG_SOC_FAMILY_NRF -#include - -static inline bool boot_skip_serial_recovery() -{ - uint32_t rr = nrfx_reset_reason_get(); - - return !(rr == 0 || (rr & NRFX_RESET_REASON_RESETPIN_MASK)); -} -#else -static inline bool boot_skip_serial_recovery() -{ - return false; -} -#endif - BOOT_LOG_MODULE_REGISTER(mcuboot); -/* Validate serial recovery configuration */ -#ifdef CONFIG_MCUBOOT_SERIAL -#if !defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) && \ - !defined(CONFIG_BOOT_SERIAL_WAIT_FOR_DFU) && \ - !defined(CONFIG_BOOT_SERIAL_BOOT_MODE) && \ - !defined(CONFIG_BOOT_SERIAL_NO_APPLICATION) && \ - !defined(CONFIG_BOOT_SERIAL_PIN_RESET) -#error "Serial recovery selected without an entrance mode set" -#endif -#endif - -#ifdef CONFIG_MCUBOOT_INDICATION_LED - -/* - * The led0 devicetree alias is optional. If present, we'll use it - * to turn on the LED whenever the button is pressed. - */ -#if DT_NODE_EXISTS(DT_ALIAS(mcuboot_led0)) -#define LED0_NODE DT_ALIAS(mcuboot_led0) -#elif DT_NODE_EXISTS(DT_ALIAS(bootloader_led0)) -#warning "bootloader-led0 alias is deprecated; use mcuboot-led0 instead" -#define LED0_NODE DT_ALIAS(bootloader_led0) -#endif - -#if DT_NODE_HAS_STATUS(LED0_NODE, okay) && DT_NODE_HAS_PROP(LED0_NODE, gpios) -static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios); -#else -/* A build error here means your board isn't set up to drive an LED. */ -#error "Unsupported board: led0 devicetree alias is not defined" -#endif - -void led_init(void) -{ - if (!device_is_ready(led0.port)) { - BOOT_LOG_ERR("Didn't find LED device referred by the LED0_NODE\n"); - return; - } - - gpio_pin_configure_dt(&led0, GPIO_OUTPUT); - gpio_pin_set_dt(&led0, 0); -} -#endif /* CONFIG_MCUBOOT_INDICATION_LED */ - void os_heap_init(void); #if defined(CONFIG_ARM) @@ -437,78 +371,6 @@ void zephyr_boot_log_stop(void) * !defined(CONFIG_LOG_PROCESS_THREAD) && !defined(ZEPHYR_LOG_MODE_MINIMAL) */ -#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) - -#ifdef CONFIG_MCUBOOT_SERIAL -#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY -#else -#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY -#endif - -#define BUTTON_0_NODE DT_ALIAS(mcuboot_button0) - -#if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios) -static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios); -#else -#error "Serial recovery/USB DFU button must be declared in device tree as 'mcuboot_button0'" -#endif - -static bool detect_pin(void) -{ - int rc; - int pin_active; - - if (!device_is_ready(button0.port)) { - __ASSERT(false, "GPIO device is not ready.\n"); - return false; - } - - rc = gpio_pin_configure_dt(&button0, GPIO_INPUT); - __ASSERT(rc == 0, "Failed to initialize boot detect pin.\n"); - - rc = gpio_pin_get_dt(&button0); - pin_active = rc; - - __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); - - if (pin_active) { - if (BUTTON_0_DETECT_DELAY > 0) { -#ifdef CONFIG_MULTITHREADING - k_sleep(K_MSEC(50)); -#else - k_busy_wait(50000); -#endif - - /* Get the uptime for debounce purposes. */ - int64_t timestamp = k_uptime_get(); - - for(;;) { - rc = gpio_pin_get_dt(&button0); - pin_active = rc; - __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); - - /* Get delta from when this started */ - uint32_t delta = k_uptime_get() - timestamp; - - /* If not pressed OR if pressed > debounce period, stop. */ - if (delta >= BUTTON_0_DETECT_DELAY || !pin_active) { - break; - } - - /* Delay 1 ms */ -#ifdef CONFIG_MULTITHREADING - k_sleep(K_MSEC(1)); -#else - k_busy_wait(1000); -#endif - } - } - } - - return (bool)pin_active; -} -#endif - #ifdef CONFIG_MCUBOOT_SERIAL static void boot_serial_enter() { @@ -534,14 +396,6 @@ int main(void) int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); -#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE - int32_t boot_mode; -#endif - -#ifdef CONFIG_BOOT_SERIAL_PIN_RESET - uint32_t reset_cause; -#endif - MCUBOOT_WATCHDOG_SETUP(); MCUBOOT_WATCHDOG_FEED(); @@ -565,23 +419,20 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_STARTUP); #ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO - if (detect_pin() && - !boot_skip_serial_recovery()) { + if (io_detect_pin() && + !io_boot_skip_serial_recovery()) { boot_serial_enter(); } #endif #ifdef CONFIG_BOOT_SERIAL_PIN_RESET - rc = hwinfo_get_reset_cause(&reset_cause); - - if (rc == 0 && reset_cause == RESET_PIN) { - (void)hwinfo_clear_reset_cause(); + if (io_detect_pin_reset()) { boot_serial_enter(); } #endif #if defined(CONFIG_BOOT_USB_DFU_GPIO) - if (detect_pin()) { + if (io_detect_pin()) { #ifdef CONFIG_MCUBOOT_INDICATION_LED gpio_pin_set_dt(&led0, 1); #endif @@ -631,13 +482,10 @@ int main(void) FIH_CALL(boot_go, fih_rc, &rsp); #ifdef CONFIG_BOOT_SERIAL_BOOT_MODE - boot_mode = bootmode_check(BOOT_MODE_TYPE_BOOTLOADER); - - if (boot_mode == 1) { + if (io_detect_boot_mode()) { /* Boot mode to stay in bootloader, clear status and enter serial * recovery mode */ - bootmode_clear(); boot_serial_enter(); } #endif From 215345f76abd2377000148652247fa36ca16e200 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 16 Aug 2023 07:37:18 +0100 Subject: [PATCH 06/70] zephyr: Add firmware loader MCUboot operation style Adds a new operation style in which the secondary slot has an image which is used to update the primary image only. Signed-off-by: Jamie McCrae --- boot/bootutil/include/bootutil/boot_status.h | 3 +- boot/bootutil/src/boot_record.c | 2 + boot/bootutil/src/bootutil_misc.c | 3 +- boot/bootutil/src/bootutil_priv.h | 8 +- boot/zephyr/CMakeLists.txt | 5 + boot/zephyr/Kconfig | 14 ++ boot/zephyr/Kconfig.firmware_loader | 47 +++++ boot/zephyr/Kconfig.serial_recovery | 1 + boot/zephyr/firmware_loader.c | 194 ++++++++++++++++++ .../include/mcuboot_config/mcuboot_config.h | 4 + boot/zephyr/io.c | 23 ++- 11 files changed, 294 insertions(+), 10 deletions(-) create mode 100644 boot/zephyr/Kconfig.firmware_loader create mode 100644 boot/zephyr/firmware_loader.c diff --git a/boot/bootutil/include/bootutil/boot_status.h b/boot/bootutil/include/bootutil/boot_status.h index 149e45e87..8ec0619aa 100644 --- a/boot/bootutil/include/bootutil/boot_status.h +++ b/boot/bootutil/include/bootutil/boot_status.h @@ -122,7 +122,8 @@ enum mcuboot_mode { MCUBOOT_MODE_SWAP_USING_MOVE, MCUBOOT_MODE_DIRECT_XIP, MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT, - MCUBOOT_MODE_RAM_LOAD + MCUBOOT_MODE_RAM_LOAD, + MCUBOOT_MODE_FIRMWARE_LOADER }; enum mcuboot_signature_type { diff --git a/boot/bootutil/src/boot_record.c b/boot/bootutil/src/boot_record.c index 5e4e25d4b..64a36d7c1 100644 --- a/boot/bootutil/src/boot_record.c +++ b/boot/bootutil/src/boot_record.c @@ -250,6 +250,8 @@ int boot_save_shared_data(const struct image_header *hdr, const struct flash_are #endif #elif defined(MCUBOOT_RAM_LOAD) uint8_t mode = MCUBOOT_MODE_RAM_LOAD; +#elif defined(MCUBOOT_FIRMWARE_LOADER) + uint8_t mode = MCUBOOT_MODE_FIRMWARE_LOADER; #else #error "Unknown mcuboot operating mode" #endif diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 0caad7ff1..87b863507 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -333,7 +333,8 @@ boot_write_enc_key(const struct flash_area *fap, uint8_t slot, uint32_t bootutil_max_image_size(const struct flash_area *fap) { -#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT) +#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \ + defined(MCUBOOT_FIRMWARE_LOADER) return boot_status_off(fap); #elif defined(MCUBOOT_SWAP_USING_MOVE) struct flash_sector sector; diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 059bfcd1f..32f996e78 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -57,15 +57,17 @@ struct flash_area; #if (defined(MCUBOOT_OVERWRITE_ONLY) + \ defined(MCUBOOT_SWAP_USING_MOVE) + \ defined(MCUBOOT_DIRECT_XIP) + \ - defined(MCUBOOT_RAM_LOAD)) > 1 -#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD" + defined(MCUBOOT_RAM_LOAD) + \ + defined(MCUBOOT_FIRMWARE_LOADER)) > 1 +#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP, MCUBOOT_RAM_LOAD or MCUBOOT_FIRMWARE_LOADER" #endif #if !defined(MCUBOOT_OVERWRITE_ONLY) && \ !defined(MCUBOOT_SWAP_USING_MOVE) && \ !defined(MCUBOOT_DIRECT_XIP) && \ !defined(MCUBOOT_RAM_LOAD) && \ - !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) + !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) && \ + !defined(MCUBOOT_FIRMWARE_LOADER) #define MCUBOOT_SWAP_USING_SCRATCH 1 #endif diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 3ce4235cb..1356f4e69 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -131,6 +131,11 @@ zephyr_library_sources( ${BOOT_DIR}/zephyr/single_loader.c ) zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) +elseif(CONFIG_BOOT_FIRMWARE_LOADER) +zephyr_library_sources( + ${BOOT_DIR}/zephyr/firmware_loader.c + ) +zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) else() zephyr_library_sources( ${BOOT_DIR}/bootutil/src/loader.c diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 183bb500e..a67126a0b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -256,6 +256,18 @@ config BOOT_RAM_LOAD The address that the image is copied to is specified using the load-addr argument to the imgtool.py script which writes it to the image header. +config BOOT_FIRMWARE_LOADER + bool "Firmware loader" + help + If y, mcuboot will have a single application slot, and the secondary + slot will be for a non-upgradeable firmware loaded image (e.g. for + loading firmware via Bluetooth). The main application will boot by + default unless there is an error with it or the boot mode has been + forced to the firmware loader. + + Note: The firmware loader image must be signed with the same signing + key as the primary image. + endchoice # Workaround for not being able to have commas in macro arguments @@ -582,6 +594,8 @@ config MCUBOOT_INDICATION_LED rsource "Kconfig.serial_recovery" +rsource "Kconfig.firmware_loader" + config BOOT_INTR_VEC_RELOC bool "Relocate the interrupt vector to the application" default n diff --git a/boot/zephyr/Kconfig.firmware_loader b/boot/zephyr/Kconfig.firmware_loader new file mode 100644 index 000000000..1ba223949 --- /dev/null +++ b/boot/zephyr/Kconfig.firmware_loader @@ -0,0 +1,47 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +if BOOT_FIRMWARE_LOADER + +menu "Firmware loader entrance methods" + +menuconfig BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO + bool "GPIO" + depends on GPIO + help + Use a GPIO to enter firmware loader mode. + +config BOOT_FIRMWARE_LOADER_DETECT_DELAY + int "Serial detect pin detection delay time [ms]" + default 0 + depends on BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO + help + Used to prevent the bootloader from loading on button press. + Useful for powering on when using the same button as + the one used to place the device in bootloader mode. + +config BOOT_FIRMWARE_LOADER_BOOT_MODE + bool "Check boot mode via retention subsystem" + depends on RETENTION_BOOT_MODE + help + Allows for entering firmware loader mode by using Zephyr's boot mode + retention system (i.e. an application must set the boot mode to stay + in firmware loader mode and reboot the module). + +config BOOT_FIRMWARE_LOADER_NO_APPLICATION + bool "Stay in bootloader if no application" + help + Allows for entering firmware loader mode if there is no bootable + application that the bootloader can jump to. + +config BOOT_FIRMWARE_LOADER_PIN_RESET + bool "Check for device reset by pin" + select HWINFO + help + Checks if the module reset was caused by the reset pin and will + remain in bootloader firmware loader mode if it was. + +endmenu + +endif diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery index c73baddf0..74bced750 100644 --- a/boot/zephyr/Kconfig.serial_recovery +++ b/boot/zephyr/Kconfig.serial_recovery @@ -13,6 +13,7 @@ menuconfig MCUBOOT_SERIAL select BASE64 select CRC select ZCBOR + depends on !BOOT_FIRMWARE_LOADER help If y, enables a serial-port based update mode. This allows MCUboot itself to load update images into flash over a UART. diff --git a/boot/zephyr/firmware_loader.c b/boot/zephyr/firmware_loader.c new file mode 100644 index 000000000..38b121cd4 --- /dev/null +++ b/boot/zephyr/firmware_loader.c @@ -0,0 +1,194 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2020 Arm Limited + * Copyright (c) 2020-2023 Nordic Semiconductor ASA + */ + +#include +#include +#include +#include +#include "bootutil/image.h" +#include "bootutil_priv.h" +#include "bootutil/bootutil_log.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/fault_injection_hardening.h" + +#include "io/io.h" +#include "mcuboot_config/mcuboot_config.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +/* Variables passed outside of unit via poiters. */ +static const struct flash_area *_fa_p; +static struct image_header _hdr = { 0 }; + +#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) || defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) +/** + * Validate hash of a primary boot image. + * + * @param[in] fa_p flash area pointer + * @param[in] hdr boot image header pointer + * + * @return FIH_SUCCESS on success, error code otherwise + */ +fih_ret +boot_image_validate(const struct flash_area *fa_p, + struct image_header *hdr) +{ + static uint8_t tmpbuf[BOOT_TMPBUF_SZ]; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + /* NOTE: The first argument to boot_image_validate, for enc_state pointer, + * is allowed to be NULL only because the single image loader compiles + * with BOOT_IMAGE_NUMBER == 1, which excludes the code that uses + * the pointer from compilation. + */ + /* Validate hash */ + if (IS_ENCRYPTED(hdr)) + { + /* Clear the encrypted flag we didn't supply a key + * This flag could be set if there was a decryption in place + * was performed. We will try to validate the image, and if still + * encrypted the validation will fail, and go in panic mode + */ + hdr->ih_flags &= ~(ENCRYPTIONFLAGS); + } + FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, hdr, fa_p, tmpbuf, + BOOT_TMPBUF_SZ, NULL, 0, NULL); + + FIH_RET(fih_rc); +} +#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT || MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE*/ + +inline static fih_ret +boot_image_validate_once(const struct flash_area *fa_p, + struct image_header *hdr) +{ + static struct boot_swap_state state; + int rc; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + memset(&state, 0, sizeof(struct boot_swap_state)); + rc = boot_read_swap_state(fa_p, &state); + if (rc != 0) + FIH_RET(FIH_FAILURE); + if (state.magic != BOOT_MAGIC_GOOD + || state.image_ok != BOOT_FLAG_SET) { + /* At least validate the image once */ + FIH_CALL(boot_image_validate, fih_rc, fa_p, hdr); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + FIH_RET(FIH_FAILURE); + } + if (state.magic != BOOT_MAGIC_GOOD) { + rc = boot_write_magic(fa_p); + if (rc != 0) + FIH_RET(FIH_FAILURE); + } + rc = boot_write_image_ok(fa_p); + if (rc != 0) + FIH_RET(FIH_FAILURE); + } + FIH_RET(FIH_SUCCESS); +} + +/** + * Validates that an image in a slot is OK to boot. + * + * @param[in] slot Slot number to check + * @param[out] rsp Parameters for booting image, on success + * + * @return FIH_SUCCESS on success; non-zero on failure. + */ +static fih_ret validate_image_slot(int slot, struct boot_rsp *rsp) +{ + int rc = -1; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + rc = flash_area_open(slot, &_fa_p); + assert(rc == 0); + + rc = boot_image_load_header(_fa_p, &_hdr); + if (rc != 0) { + goto other; + } + +#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT + FIH_CALL(boot_image_validate, fih_rc, _fa_p, &_hdr); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + goto other; + } +#elif defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) + FIH_CALL(boot_image_validate_once, fih_rc, _fa_p, &_hdr); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + goto other; + } +#else + fih_rc = FIH_SUCCESS; +#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */ + + rsp->br_flash_dev_id = flash_area_get_device_id(_fa_p); + rsp->br_image_off = flash_area_get_off(_fa_p); + rsp->br_hdr = &_hdr; + +other: + flash_area_close(_fa_p); + + FIH_RET(fih_rc); +} + +/** + * Gather information on image and prepare for booting. Will boot from main + * image if none of the enabled entrance modes for the firmware loader are set, + * otherwise will boot the firmware loader. Note: firmware loader must be a + * valid signed image with the same signing key as the application image. + * + * @param[out] rsp Parameters for booting image, on success + * + * @return FIH_SUCCESS on success; non-zero on failure. + */ +fih_ret +boot_go(struct boot_rsp *rsp) +{ + bool boot_firmware_loader = false; + FIH_DECLARE(fih_rc, FIH_FAILURE); + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO + if (io_detect_pin() && + !io_boot_skip_serial_recovery()) { + boot_firmware_loader = true; + } +#endif + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET + if (io_detect_pin_reset()) { + boot_firmware_loader = true; + } +#endif + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE + if (io_detect_boot_mode()) { + boot_firmware_loader = true; + } +#endif + + /* Check if firmware loader button is pressed. TODO: check all entrance methods */ + if (boot_firmware_loader == true) { + FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp); + + if (FIH_EQ(fih_rc, FIH_SUCCESS)) { + FIH_RET(fih_rc); + } + } + + FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_PRIMARY(0), rsp); + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_NO_APPLICATION + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp); + } +#endif + + FIH_RET(fih_rc); +} diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 04e4c599c..a9c52bdaf 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -88,6 +88,10 @@ #define IMAGE_EXECUTABLE_RAM_SIZE CONFIG_BOOT_IMAGE_EXECUTABLE_RAM_SIZE #endif +#ifdef CONFIG_BOOT_FIRMWARE_LOADER +#define MCUBOOT_FIRMWARE_LOADER +#endif + #ifdef CONFIG_UPDATEABLE_IMAGE_NUMBER #define MCUBOOT_IMAGE_NUMBER CONFIG_UPDATEABLE_IMAGE_NUMBER #else diff --git a/boot/zephyr/io.c b/boot/zephyr/io.c index 6d3b01ef5..fc1966d7f 100644 --- a/boot/zephyr/io.c +++ b/boot/zephyr/io.c @@ -29,11 +29,11 @@ #include "target.h" -#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) +#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) #include #endif -#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) +#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) || defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) #include #endif @@ -48,6 +48,16 @@ #endif #endif +/* Validate firmware loader configuration */ +#ifdef CONFIG_BOOT_FIRMWARE_LOADER +#if !defined(CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_NO_APPLICATION) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) +#error "Firmware loader selected without an entrance mode set" +#endif +#endif + #ifdef CONFIG_MCUBOOT_INDICATION_LED /* @@ -80,10 +90,13 @@ void io_led_init(void) } #endif /* CONFIG_MCUBOOT_INDICATION_LED */ -#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) +#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) || \ + defined(CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) #if defined(CONFIG_MCUBOOT_SERIAL) #define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY +#elif defined(CONFIG_BOOT_FIRMWARE_LOADER) +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_FIRMWARE_LOADER_DETECT_DELAY #else #define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY #endif @@ -152,7 +165,7 @@ bool io_detect_pin(void) } #endif -#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) +#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) bool io_detect_pin_reset(void) { uint32_t reset_cause; @@ -169,7 +182,7 @@ bool io_detect_pin_reset(void) } #endif -#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) +#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) || defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) bool io_detect_boot_mode(void) { int32_t boot_mode; From 05d11942774fc15b90af101232ec5305051216ec Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 16 Aug 2023 07:39:37 +0100 Subject: [PATCH 07/70] docs: release: Add note on firmware loader mode Adds a note on the new firmware loader operation type Signed-off-by: Jamie McCrae --- docs/release-notes.d/zephyr-firmware-loader.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs/release-notes.d/zephyr-firmware-loader.md diff --git a/docs/release-notes.d/zephyr-firmware-loader.md b/docs/release-notes.d/zephyr-firmware-loader.md new file mode 100644 index 000000000..8f6acf455 --- /dev/null +++ b/docs/release-notes.d/zephyr-firmware-loader.md @@ -0,0 +1,4 @@ +- Added firmware loader configuration type support for Zephyr, this + allows for a single application slot and firmware loader image in + the secondary slot which is used to update the primary image + (loading it in any way it sees fit e.g. via Bluetooth). From ab99fe28122aea665161c4762567b56cc67762d5 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 19 Nov 2023 11:04:39 +0100 Subject: [PATCH 08/70] scripts: add missing pyyaml dependency `pyyaml` is a dependency introduced in `imgtool dumpinfo` Signed-off-by: Samuel Tardieu --- scripts/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 244692809..79883b6da 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -2,3 +2,4 @@ cryptography>=2.6 intelhex click cbor2 +pyyaml From c43a20fd193dc445faa9b7f0d2ed77759a6aca8f Mon Sep 17 00:00:00 2001 From: Andrej Butok Date: Tue, 5 Dec 2023 13:30:54 +0100 Subject: [PATCH 09/70] boot: zephyr: add support for mimxrt1040_evk Add default configuration for mimxrt1040_evk. Signed-off-by: Andrej Butok --- boot/zephyr/boards/mimxrt1040_evk.conf | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 boot/zephyr/boards/mimxrt1040_evk.conf diff --git a/boot/zephyr/boards/mimxrt1040_evk.conf b/boot/zephyr/boards/mimxrt1040_evk.conf new file mode 100644 index 000000000..35f90d455 --- /dev/null +++ b/boot/zephyr/boards/mimxrt1040_evk.conf @@ -0,0 +1,4 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOOT_MAX_IMG_SECTORS=1024 From d99154f441191fc8b13a5ca506c2887466d7ceea Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Tue, 5 Dec 2023 13:41:59 +0100 Subject: [PATCH 10/70] zephyr: rename 'led_init()' to 'io_led_init()' This fixes below warning when building with 'MCUBOOT_INDICATION_LED' enabled: mcuboot/boot/zephyr/main.c:410:5: warning: implicit declaration of function 'led_init'; did you mean 'io_led_init'? [-Wimplicit-function-declaration] 410 | led_init(); | ^~~~~~~~ | io_led_init Fixes: 433b8480 ("zephyr: Move IO functions out of main to separate file") Signed-off-by: Piotr Dymacz --- boot/zephyr/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index abd2fe6eb..91c9b9b9d 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -407,7 +407,7 @@ int main(void) #ifdef CONFIG_MCUBOOT_INDICATION_LED /* LED init */ - led_init(); + io_led_init(); #endif os_heap_init(); From 8c6c67016acf0e312c5933b926bb3ce6b434dfe0 Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Tue, 5 Dec 2023 14:05:38 +0100 Subject: [PATCH 11/70] zephyr: io: include 'bootutil_log.h' and declare log module membership This fixes below error when building with 'MCUBOOT_INDICATION_LED' and 'LOG' enabled: In file included from zephyr/include/zephyr/logging/log.h:11, from zephyr/include/zephyr/usb/usb_device.h:43, from bootloader/mcuboot/boot/zephyr/io.c:26: mcuboot/boot/zephyr/io.c: In function 'io_led_init': zephyr/include/zephyr/logging/log_core.h:151:20: error: '__log_level' undeclared (first use in this function) 151 | (_level <= __log_level) && \ | ^~~~~~~~~~~ Fixes: 433b8480 ("zephyr: Move IO functions out of main to separate file") Signed-off-by: Piotr Dymacz --- boot/zephyr/io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/io.c b/boot/zephyr/io.c index fc1966d7f..e6d54d3c7 100644 --- a/boot/zephyr/io.c +++ b/boot/zephyr/io.c @@ -28,6 +28,7 @@ #include #include "target.h" +#include "bootutil/bootutil_log.h" #if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) #include @@ -78,6 +79,8 @@ static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios); #error "Unsupported board: led0 devicetree alias is not defined" #endif +BOOT_LOG_MODULE_DECLARE(mcuboot); + void io_led_init(void) { if (!device_is_ready(led0.port)) { From 2a74a2b580035e767f4a4ead2b7c8b9253872276 Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Tue, 5 Dec 2023 14:26:22 +0100 Subject: [PATCH 12/70] zephyr: io: add 'io_led_set()' The static declaration of 'led0' was moved to 'io.c' which broke building with the 'MCUBOOT_INDICATION_LED' enabled: mcuboot/boot/zephyr/main.c:380:22: error: 'led0' undeclared (first use in this function) 380 | gpio_pin_set_dt(&led0, 1); | ^~~~ This adds simple function 'io_led_set()' for changing LED's value. Fixes: 433b8480 ("zephyr: Move IO functions out of main to separate file") Signed-off-by: Piotr Dymacz --- boot/zephyr/include/io/io.h | 5 +++++ boot/zephyr/io.c | 5 +++++ boot/zephyr/main.c | 8 ++++---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/boot/zephyr/include/io/io.h b/boot/zephyr/include/io/io.h index 332eefbd8..145530bb8 100644 --- a/boot/zephyr/include/io/io.h +++ b/boot/zephyr/include/io/io.h @@ -34,6 +34,11 @@ extern "C" { */ void io_led_init(void); +/* + * Sets value of the configured LED. + */ +void io_led_set(int value); + /* * Checks if GPIO is set in the required way to remain in serial recovery mode * diff --git a/boot/zephyr/io.c b/boot/zephyr/io.c index e6d54d3c7..309f1ab94 100644 --- a/boot/zephyr/io.c +++ b/boot/zephyr/io.c @@ -91,6 +91,11 @@ void io_led_init(void) gpio_pin_configure_dt(&led0, GPIO_OUTPUT); gpio_pin_set_dt(&led0, 0); } + +void io_led_set(int value) +{ + gpio_pin_set_dt(&led0, value); +} #endif /* CONFIG_MCUBOOT_INDICATION_LED */ #if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) || \ diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 91c9b9b9d..c6a0f74ae 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -377,7 +377,7 @@ static void boot_serial_enter() int rc; #ifdef CONFIG_MCUBOOT_INDICATION_LED - gpio_pin_set_dt(&led0, 1); + io_led_set(1); #endif mcuboot_status_change(MCUBOOT_STATUS_SERIAL_DFU_ENTERED); @@ -434,7 +434,7 @@ int main(void) #if defined(CONFIG_BOOT_USB_DFU_GPIO) if (io_detect_pin()) { #ifdef CONFIG_MCUBOOT_INDICATION_LED - gpio_pin_set_dt(&led0, 1); + io_led_set(1); #endif mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_ENTERED); @@ -475,7 +475,7 @@ int main(void) uint32_t start = k_uptime_get_32(); #ifdef CONFIG_MCUBOOT_INDICATION_LED - gpio_pin_set_dt(&led0, 1); + io_led_set(1); #endif #endif @@ -499,7 +499,7 @@ int main(void) boot_serial_check_start(&boot_funcs,timeout_in_ms); #ifdef CONFIG_MCUBOOT_INDICATION_LED - gpio_pin_set_dt(&led0, 0); + io_led_set(0); #endif #endif From a88e229346204c09b6292f49e4481627254946e7 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Dec 2023 09:40:51 +0000 Subject: [PATCH 13/70] zephyr: sysflash: Fix if condition for zephyr applications Fixes an issue when sysflash is included by zephyr (non-mcuboot) applications Signed-off-by: Jamie McCrae --- boot/zephyr/include/sysflash/sysflash.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 646f1122f..890e69d98 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -12,7 +12,7 @@ #include #include -#ifndef CONFIG_SINGLE_APPLICATION_SLOT +#if !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP) /* Each pair of slots is separated by , and there is no terminating character */ #define FLASH_AREA_IMAGE_0_SLOTS slot0_partition, slot1_partition @@ -50,7 +50,7 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #define FLASH_AREA_IMAGE_SCRATCH FIXED_PARTITION_ID(scratch_partition) #endif -#else /* CONFIG_SINGLE_APPLICATION_SLOT */ +#else /* !CONFIG_SINGLE_APPLICATION_SLOT && !CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP */ #define FLASH_AREA_IMAGE_PRIMARY(x) FIXED_PARTITION_ID(slot0_partition) #define FLASH_AREA_IMAGE_SECONDARY(x) FIXED_PARTITION_ID(slot0_partition) From 212997395ed34ff1721f5f4461b800e81abeb68d Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Dec 2023 09:41:55 +0000 Subject: [PATCH 14/70] zephyr: firmware/single_loader: Fix compile warning Fixes an issue of an unused function calling an undefined function Signed-off-by: Jamie McCrae --- boot/zephyr/firmware_loader.c | 2 ++ boot/zephyr/single_loader.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/boot/zephyr/firmware_loader.c b/boot/zephyr/firmware_loader.c index 38b121cd4..11b461c41 100644 --- a/boot/zephyr/firmware_loader.c +++ b/boot/zephyr/firmware_loader.c @@ -62,6 +62,7 @@ boot_image_validate(const struct flash_area *fa_p, } #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT || MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE*/ +#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) inline static fih_ret boot_image_validate_once(const struct flash_area *fa_p, struct image_header *hdr) @@ -92,6 +93,7 @@ boot_image_validate_once(const struct flash_area *fa_p, } FIH_RET(FIH_SUCCESS); } +#endif /** * Validates that an image in a slot is OK to boot. diff --git a/boot/zephyr/single_loader.c b/boot/zephyr/single_loader.c index 5d1e76fcf..75374d2db 100644 --- a/boot/zephyr/single_loader.c +++ b/boot/zephyr/single_loader.c @@ -58,6 +58,7 @@ boot_image_validate(const struct flash_area *fa_p, } #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT || MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE*/ +#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) inline static fih_ret boot_image_validate_once(const struct flash_area *fa_p, struct image_header *hdr) @@ -88,6 +89,7 @@ boot_image_validate_once(const struct flash_area *fa_p, } FIH_RET(FIH_SUCCESS); } +#endif /** * Gather information on image and prepare for booting. From 26d6423b00fa74bb17be2a89fd1406c7e9ba4914 Mon Sep 17 00:00:00 2001 From: YuLong Yao Date: Sat, 23 Sep 2023 16:03:17 +0800 Subject: [PATCH 15/70] boot: zephyr: esp32: zephyr port Add support for ESP32xx_luatos_core targets to build as Zephyr application. This target is simular to esp32 devkitm, copy conf file from esp32xx_devkitm Signed-off-by: YuLong Yao --- boot/zephyr/boards/esp32c3_luatos_core.conf | 20 ++++++++++++++++++++ boot/zephyr/boards/esp32s3_luatos_core.conf | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 boot/zephyr/boards/esp32c3_luatos_core.conf create mode 100644 boot/zephyr/boards/esp32s3_luatos_core.conf diff --git a/boot/zephyr/boards/esp32c3_luatos_core.conf b/boot/zephyr/boards/esp32c3_luatos_core.conf new file mode 100644 index 000000000..56298cd4f --- /dev/null +++ b/boot/zephyr/boards/esp32c3_luatos_core.conf @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOOT_MAX_IMG_SECTORS=512 +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_BOOT_VALIDATE_SLOT0=n +CONFIG_BOOT_SIGNATURE_TYPE_NONE=y +CONFIG_BOOT_BANNER=n + +CONFIG_UART_CONSOLE=n +CONFIG_CONSOLE=n +CONFIG_SERIAL=n + +CONFIG_MCUBOOT_LOG_LEVEL_OFF=y +CONFIG_LOG_DEFAULT_LEVEL=0 +CONFIG_DEBUG=n + +CONFIG_XIP=n +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/esp32s3_luatos_core.conf b/boot/zephyr/boards/esp32s3_luatos_core.conf new file mode 100644 index 000000000..b2b405922 --- /dev/null +++ b/boot/zephyr/boards/esp32s3_luatos_core.conf @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOOT_MAX_IMG_SECTORS=512 +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_BOOT_VALIDATE_SLOT0=n +CONFIG_BOOT_SIGNATURE_TYPE_NONE=y +CONFIG_BOOT_BANNER=n + +CONFIG_UART_CONSOLE=n +CONFIG_CONSOLE=n +CONFIG_SERIAL=n + +CONFIG_MCUBOOT_LOG_LEVEL_OFF=y +CONFIG_LOG_DEFAULT_LEVEL=0 +CONFIG_DEBUG=n + +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y From 4c7942e58c5458ce3c4e50d3169e0f865910fe87 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 30 Oct 2023 11:59:57 +0000 Subject: [PATCH 16/70] zephyr: Add estimated image footer size to cache in sysbuild Adds MCUboot's estimated overhead footer size to the application's cache when using sysbuild, this allows that information to be propagated to applications which can use the information to reduce the available size for an application, preventing the MCUboot error of image too large to swap. Signed-off-by: Jamie McCrae --- boot/zephyr/CMakeLists.txt | 128 ++++++++++++++++++++++++++++ boot/zephyr/sysbuild/CMakeLists.txt | 40 +++++++++ zephyr/module.yml | 1 + 3 files changed, 169 insertions(+) create mode 100644 boot/zephyr/sysbuild/CMakeLists.txt diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 1356f4e69..78eb653e7 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -1,6 +1,7 @@ # CMakeLists.txt for building mcuboot as a Zephyr project # # Copyright (c) 2017 Open Source Foundries Limited +# Copyright (c) 2023 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -356,3 +357,130 @@ zephyr_library_sources( ${BOOT_DIR}/zephyr/arm_cleanup.c ) endif() + +if(SYSBUILD) + function(align_up num align result) + math(EXPR out "(((${num}) + ((${align}) - 1)) & ~((${align}) - 1))") + set(${result} "${out}" PARENT_SCOPE) + endfunction() + + function(dt_get_parent node) + string(FIND "${${node}}" "/" pos REVERSE) + + if(pos EQUAL -1) + message(ERROR "Unable to get parent of node: ${${node}}") + endif() + + string(SUBSTRING "${${node}}" 0 ${pos} ${node}) + set(${node} "${${node}}" PARENT_SCOPE) + endfunction() + + if(CONFIG_SINGLE_APPLICATION_SLOT OR CONFIG_BOOT_FIRMWARE_LOADER OR CONFIG_BOOT_SWAP_USING_SCRATCH OR CONFIG_BOOT_SWAP_USING_MOVE OR CONFIG_BOOT_UPGRADE_ONLY OR CONFIG_BOOT_DIRECT_XIP OR CONFIG_BOOT_RAM_LOAD) + # TODO: RAM LOAD support + dt_nodelabel(slot0_flash NODELABEL "slot0_partition") + dt_get_parent(slot0_flash) + dt_get_parent(slot0_flash) + + if(NOT CONFIG_SINGLE_APPLICATION_SLOT) + dt_nodelabel(slot1_flash NODELABEL "slot1_partition") + dt_get_parent(slot1_flash) + dt_get_parent(slot1_flash) + + if(NOT "${slot0_flash}" STREQUAL "${slot1_flash}") + # Check both slots for the one with the largest write/erase block size + dt_prop(erase_size_slot0 PATH "${slot0_flash}" PROPERTY "erase-block-size") + dt_prop(write_size_slot0 PATH "${slot0_flash}" PROPERTY "write-block-size") + dt_prop(erase_size_slot1 PATH "${slot1_flash}" PROPERTY "erase-block-size") + dt_prop(write_size_slot1 PATH "${slot1_flash}" PROPERTY "write-block-size") + + if(${erase_size_slot0} GREATER ${erase_size_slot1}) + set(erase_size ${erase_size_slot0}) + else() + set(erase_size ${erase_size_slot1}) + endif() + + if(${write_size_slot0} GREATER ${write_size_slot1}) + set(write_size ${write_size_slot0}) + else() + set(write_size ${write_size_slot1}) + endif() + else() + dt_prop(erase_size PATH "${slot0_flash}" PROPERTY "erase-block-size") + dt_prop(write_size PATH "${slot0_flash}" PROPERTY "write-block-size") + endif() + else() + dt_prop(erase_size PATH "${slot0_flash}" PROPERTY "erase-block-size") + dt_prop(write_size PATH "${slot0_flash}" PROPERTY "write-block-size") + endif() + + if(write_size LESS 8) + set(write_size 8) + endif() + + set(key_size 0) + + # Boot trailer magic size + set(boot_magic_size 16) + + # Estimates for trailer TLV data size, this was taken from hello world builds for nrf52840dk + if(CONFIG_BOOT_SIGNATURE_TYPE_RSA) + if(CONFIG_BOOT_SIGNATURE_TYPE_RSA_LEN EQUAL 3072) + set(boot_tlv_estimate 464) + else() + set(boot_tlv_estimate 336) + endif() + elseif(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) + set(boot_tlv_estimate 150) + elseif(CONFIG_BOOT_SIGNATURE_TYPE_ED25519) + set(boot_tlv_estimate 144) + else() + set(boot_tlv_estimate 40) + endif() + + if(CONFIG_BOOT_ENCRYPT_RSA OR CONFIG_BOOT_ENCRYPT_EC256 OR CONFIG_BOOT_ENCRYPT_X25519) + # 128-bit AES key size + set(boot_enc_key_size 16) + + if(CONFIG_BOOT_SWAP_SAVE_ENCTLV) + if(CONFIG_BOOT_ENCRYPT_RSA) + set(key_size 256) + elseif(CONFIG_BOOT_ENCRYPT_EC256) + math(EXPR key_size "65 + 32 + ${boot_enc_key_size}") + elseif(CONFIG_BOOT_ENCRYPT_X25519) + math(EXPR key_size "32 + 32 + ${boot_enc_key_size}") + endif() + else() + set(key_size "${boot_enc_key_size}") + endif() + + align_up(${key_size} ${write_size} key_size) + math(EXPR key_size "${key_size} * 2") + endif() + + align_up(${boot_magic_size} ${write_size} boot_magic_size) + + if(CONFIG_SINGLE_APPLICATION_SLOT OR CONFIG_BOOT_FIRMWARE_LOADER) + set(boot_swap_data_size 0) + else() + math(EXPR boot_swap_data_size "${write_size} * 4") + endif() + + if(CONFIG_BOOT_SWAP_USING_SCRATCH OR CONFIG_BOOT_SWAP_USING_MOVE) + math(EXPR boot_status_data_size "${CONFIG_BOOT_MAX_IMG_SECTORS} * (3 * ${write_size})") + else() + set(boot_status_data_size 0) + endif() + + math(EXPR required_size "${key_size} + ${boot_magic_size} + ${boot_swap_data_size} + ${boot_status_data_size} + ${boot_tlv_estimate}") + + align_up(${required_size} ${erase_size} required_size) + + if(CONFIG_BOOT_SWAP_USING_MOVE) + math(EXPR required_size "${required_size} + ${erase_size}") + endif() + else() + set(required_size 0) + endif() + + set(mcuboot_image_footer_size ${required_size} CACHE INTERNAL "Estimated MCUboot image trailer size" FORCE) +endif() diff --git a/boot/zephyr/sysbuild/CMakeLists.txt b/boot/zephyr/sysbuild/CMakeLists.txt new file mode 100644 index 000000000..adcd74437 --- /dev/null +++ b/boot/zephyr/sysbuild/CMakeLists.txt @@ -0,0 +1,40 @@ +function(mathup num align result) + math(EXPR out "(((${num}) + ((${align}) - 1)) & ~((${align}) - 1))") + set(${result} "${out}" PARENT_SCOPE) +endfunction() + +function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_image_cmake) + cmake_parse_arguments(POST_IMAGE_CMAKE "" "IMAGE" "IMAGES" ${ARGN}) + + if(NOT "${POST_IMAGE_CMAKE_IMAGE}" STREQUAL "mcuboot") + return() + endif() + + set_property( + DIRECTORY APPEND PROPERTY + CMAKE_CONFIGURE_DEPENDS + ${CMAKE_BINARY_DIR}/mcuboot/CMakeCache.txt + ${CMAKE_BINARY_DIR}/mcuboot/zephyr/.config + ) +endfunction(${SYSBUILD_CURRENT_MODULE_NAME}_pre_image_cmake) + +function(${SYSBUILD_CURRENT_MODULE_NAME}_post_image_cmake) + cmake_parse_arguments(POST_IMAGE_CMAKE "" "IMAGE" "IMAGES" ${ARGN}) + + if(NOT "${POST_IMAGE_CMAKE_IMAGE}" STREQUAL "mcuboot") + return() + endif() + + foreach(image ${IMAGES}) + set(app_type) + get_property(app_type TARGET ${image} PROPERTY APP_TYPE) + + if("${app_type}" STREQUAL "MAIN") + sysbuild_get(mcuboot_image_footer_size IMAGE mcuboot CACHE) + math(EXPR mcuboot_image_footer_size "${mcuboot_image_footer_size}" OUTPUT_FORMAT HEXADECIMAL) + + set_property(TARGET ${image} APPEND_STRING PROPERTY CONFIG "CONFIG_ROM_END_OFFSET=${mcuboot_image_footer_size}\n") + return() + endif() + endforeach() +endfunction(${SYSBUILD_CURRENT_MODULE_NAME}_post_image_cmake) diff --git a/zephyr/module.yml b/zephyr/module.yml index c4293e387..014a21956 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -2,3 +2,4 @@ samples: - boot/zephyr build: cmake: ./boot/bootutil/zephyr + sysbuild-cmake: boot/zephyr/sysbuild From e9131ee8b8ab9306d8f6ad410fd1e3d8a820ce10 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 31 Oct 2023 09:54:35 +0000 Subject: [PATCH 17/70] zephyr: kconfig: Make saving encrypt TLVs depending on encryption Prevents enabling the option to save encrypted TLVs if encryption support is not enabled, as it is required to make use of this functionality. Signed-off-by: Jamie McCrae --- boot/zephyr/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a67126a0b..2cfd7b86c 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -306,6 +306,7 @@ config BOOT_BOOTSTRAP config BOOT_SWAP_SAVE_ENCTLV bool "Save encrypted key TLVs instead of plaintext keys in swap metadata" default n + depends on BOOT_ENCRYPT_IMAGE help If y, instead of saving the encrypted image keys in plaintext in the swap resume metadata, save the encrypted image TLVs. This should be used From 12e2b6398b8a268b43ee9f9efa492be99250fb8c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 12 Dec 2023 15:11:12 +0000 Subject: [PATCH 18/70] docs: release: Add release notes Adds release notes for various recent changes Signed-off-by: Jamie McCrae --- docs/release-notes.d/boot-serial-echo.md | 5 ++++- docs/release-notes.d/zephyr-encryption-single.md | 3 +++ docs/release-notes.d/zephyr-estimated-sysbuild.mc | 1 + docs/release-notes.d/zephyr-mass-erase.md | 1 + docs/release-notes.d/zephyr-mbedtls-kconfig.md | 1 + docs/release-notes.d/zephyr-usb.md | 9 +++++++-- 6 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 docs/release-notes.d/zephyr-encryption-single.md create mode 100644 docs/release-notes.d/zephyr-estimated-sysbuild.mc create mode 100644 docs/release-notes.d/zephyr-mass-erase.md create mode 100644 docs/release-notes.d/zephyr-mbedtls-kconfig.md diff --git a/docs/release-notes.d/boot-serial-echo.md b/docs/release-notes.d/boot-serial-echo.md index 2667f733c..6116f0567 100644 --- a/docs/release-notes.d/boot-serial-echo.md +++ b/docs/release-notes.d/boot-serial-echo.md @@ -1 +1,4 @@ -- Boot serial: Add response to echo command if support is not enabled, previously the command would have been accepted but no response indicating that the command is not supported would have been sent. +- Boot serial: Add response to echo command if support is not + enabled, previously the command would have been accepted but no + response indicating that the command is not supported would have + been sent. diff --git a/docs/release-notes.d/zephyr-encryption-single.md b/docs/release-notes.d/zephyr-encryption-single.md new file mode 100644 index 000000000..78767db20 --- /dev/null +++ b/docs/release-notes.d/zephyr-encryption-single.md @@ -0,0 +1,3 @@ +- Zephyr: Fix issue with single application slot mode, serial + recovery and encryption whereby an encrypted image is loaded + and being wrongly treated as encrypted after decryption. diff --git a/docs/release-notes.d/zephyr-estimated-sysbuild.mc b/docs/release-notes.d/zephyr-estimated-sysbuild.mc new file mode 100644 index 000000000..8b42c2612 --- /dev/null +++ b/docs/release-notes.d/zephyr-estimated-sysbuild.mc @@ -0,0 +1 @@ +- Zephyr: Add estimated image footer size to cache in sysbuild. diff --git a/docs/release-notes.d/zephyr-mass-erase.md b/docs/release-notes.d/zephyr-mass-erase.md new file mode 100644 index 000000000..7834ee289 --- /dev/null +++ b/docs/release-notes.d/zephyr-mass-erase.md @@ -0,0 +1 @@ +- Zephyr: Remove deprecated ZEPHYR_TRY_MASS_ERASE Kconfig option. diff --git a/docs/release-notes.d/zephyr-mbedtls-kconfig.md b/docs/release-notes.d/zephyr-mbedtls-kconfig.md new file mode 100644 index 000000000..d7914cbbb --- /dev/null +++ b/docs/release-notes.d/zephyr-mbedtls-kconfig.md @@ -0,0 +1 @@ +- Zephyr: Prevent MBEDTLS Kconfig selection when tinycrypt is used. diff --git a/docs/release-notes.d/zephyr-usb.md b/docs/release-notes.d/zephyr-usb.md index 7154f58ea..139de7cc8 100644 --- a/docs/release-notes.d/zephyr-usb.md +++ b/docs/release-notes.d/zephyr-usb.md @@ -1,2 +1,7 @@ -- Zephyr: Add USB CDC serial recovery check that now causes a build failure if console is enabled and device is the same as the USB CDC device. -- Zephyr: Add USB CDC serial recovery check that now causes a build failure if the main thread priority is below 0 (cooperative thread), this would prevent USB CDC from working as the driver would not have been able to fire callbacks. +- Zephyr: Add USB CDC serial recovery check that now causes a build + failure if console is enabled and device is the same as the USB + CDC device. +- Zephyr: Add USB CDC serial recovery check that now causes a build + failure if the main thread priority is below 0 (cooperative + thread), this would prevent USB CDC from working as the driver + would not have been able to fire callbacks. From 8cee3550955bb88ed84b6cfa1e1549a416042cbd Mon Sep 17 00:00:00 2001 From: Xudong Zheng <7pkvm5aw@slicealias.com> Date: Tue, 26 Dec 2023 21:28:38 -0500 Subject: [PATCH 19/70] zephyr: kconfig: make MBEDTLS_PROMPTLESS depend on MBEDTLS This addresses compilation error when MBEDTLS module is not present. Signed-off-by: Xudong Zheng <7pkvm5aw@slicealias.com> --- boot/zephyr/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2cfd7b86c..baa807c56 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -30,7 +30,7 @@ config BOOT_USE_TINYCRYPT # When building for ECDSA, we use our own copy of mbedTLS, so the # Zephyr one must not be enabled or the MBEDTLS_CONFIG_FILE macros # will collide. - select MBEDTLS_PROMPTLESS + select MBEDTLS_PROMPTLESS if ZEPHYR_MBEDTLS_MODULE help Use TinyCrypt for crypto primitives. From db9a7f5822b9473ae0d623029f2d816f9a915667 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 18 Dec 2023 13:45:27 +0000 Subject: [PATCH 20/70] boot: zephyr: cmake: Fix issue with missing dts entries Fixes an issue whereby a device might not have a write or erase entry for the flash controller in devicetree. In the case whereby the other slot has this information, use that instead. In the case whereby neither slot has this information, use default values and show a warning to the user Signed-off-by: Jamie McCrae --- boot/zephyr/CMakeLists.txt | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 78eb653e7..580954fc4 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -393,15 +393,27 @@ if(SYSBUILD) dt_prop(erase_size_slot1 PATH "${slot1_flash}" PROPERTY "erase-block-size") dt_prop(write_size_slot1 PATH "${slot1_flash}" PROPERTY "write-block-size") - if(${erase_size_slot0} GREATER ${erase_size_slot1}) + if(DEFINED erase_size_slot0 AND DEFINED erase_size_slot1) + if(${erase_size_slot0} GREATER ${erase_size_slot1}) + set(erase_size ${erase_size_slot0}) + else() + set(erase_size ${erase_size_slot1}) + endif() + elseif(DEFINED erase_size_slot0) set(erase_size ${erase_size_slot0}) - else() + elseif(DEFINED erase_size_slot1) set(erase_size ${erase_size_slot1}) endif() - if(${write_size_slot0} GREATER ${write_size_slot1}) + if(DEFINED write_size_slot0 AND DEFINED write_size_slot1) + if(${write_size_slot0} GREATER ${write_size_slot1}) + set(write_size ${write_size_slot0}) + else() + set(write_size ${write_size_slot1}) + endif() + elseif(DEFINED write_size_slot0) set(write_size ${write_size_slot0}) - else() + elseif(DEFINED write_size_slot1) set(write_size ${write_size_slot1}) endif() else() @@ -413,7 +425,15 @@ if(SYSBUILD) dt_prop(write_size PATH "${slot0_flash}" PROPERTY "write-block-size") endif() - if(write_size LESS 8) + if(NOT DEFINED erase_size) + message(WARNING "Unable to determine erase size of slot0 or slot1 partition, setting to 1 (this is probably wrong)") + set(erase_size 1) + endif() + + if(NOT DEFINED write_size) + message(WARNING "Unable to determine write size of slot0 or slot1 partition, setting to 8 (this is probably wrong)") + set(write_size 8) + elseif(write_size LESS 8) set(write_size 8) endif() From 35e9931c781a896d47506c67b300e0f8f61de4d0 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 3 Jan 2024 07:37:55 +0000 Subject: [PATCH 21/70] bootutil: Add debug logging for boot status write Adds debug level logging which shows the offset of where a sector swap status write is occurring at Signed-off-by: Jamie McCrae --- boot/bootutil/src/loader.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8bbabbbac..9a771a07a 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -470,6 +470,10 @@ boot_write_status(const struct boot_loader_state *state, struct boot_status *bs) memset(buf, erased_val, BOOT_MAX_ALIGN); buf[0] = bs->state; + BOOT_LOG_DBG("writing swap status; fa_id=%d off=0x%lx (0x%lx)", + flash_area_get_id(fap), (unsigned long)off, + (unsigned long)flash_area_get_off(fap) + off); + rc = flash_area_write(fap, off, buf, align); if (rc != 0) { rc = BOOT_EFLASH; From 4d75fc8e07556e624e6a2d21d082dc39c6ab8acb Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 3 Jan 2024 07:39:46 +0000 Subject: [PATCH 22/70] bootutil: Fix compatible sector checking Fixes an issue whereby slot sizes were checked but the check was not done properly. This also adds debug log messages to show the sector configuration including if slot sizes are not optimal Signed-off-by: Jamie McCrae --- boot/bootutil/src/swap_move.c | 56 ++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index 61246b9e5..111e82f05 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -234,6 +234,28 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz) return off; } +static int app_max_sectors(struct boot_loader_state *state) +{ + uint32_t sz = 0; + uint32_t sector_sz; + uint32_t trailer_sz; + uint32_t first_trailer_idx; + + sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0); + trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); + first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1; + + while (1) { + sz += sector_sz; + if (sz >= trailer_sz) { + break; + } + first_trailer_idx--; + } + + return first_trailer_idx; +} + int boot_slots_compatible(struct boot_loader_state *state) { @@ -242,20 +264,31 @@ boot_slots_compatible(struct boot_loader_state *state) size_t sector_sz_pri = 0; size_t sector_sz_sec = 0; size_t i; + size_t num_usable_sectors_pri; num_sectors_pri = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT); num_sectors_sec = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT); + num_usable_sectors_pri = app_max_sectors(state); + if ((num_sectors_pri != num_sectors_sec) && - (num_sectors_pri != (num_sectors_sec + 1))) { + (num_sectors_pri != (num_sectors_sec + 1)) && + (num_usable_sectors_pri != (num_sectors_sec + 1))) { BOOT_LOG_WRN("Cannot upgrade: not a compatible amount of sectors"); + BOOT_LOG_DBG("slot0 sectors: %d, slot1 sectors: %d, usable slot0 sectors: %d", + (int)num_sectors_pri, (int)num_sectors_sec, + (int)(num_usable_sectors_pri - 1)); return 0; - } - - if (num_sectors_pri > BOOT_MAX_IMG_SECTORS) { + } else if (num_sectors_pri > BOOT_MAX_IMG_SECTORS) { BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed"); return 0; } + if (num_usable_sectors_pri != (num_sectors_sec + 1)) { + BOOT_LOG_DBG("Non-optimal sector distribution, slot0 has %d usable sectors (%d assigned) " + "but slot1 has %d assigned", (int)(num_usable_sectors_pri - 1), + (int)num_sectors_pri, (int)num_sectors_sec); + } + for (i = 0; i < num_sectors_sec; i++) { sector_sz_pri = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i); sector_sz_sec = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, i); @@ -544,24 +577,11 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs, int app_max_size(struct boot_loader_state *state) { - uint32_t sz = 0; uint32_t sector_sz; - uint32_t trailer_sz; - uint32_t first_trailer_idx; sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0); - trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); - first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1; - - while (1) { - sz += sector_sz; - if (sz >= trailer_sz) { - break; - } - first_trailer_idx--; - } - return (first_trailer_idx * sector_sz); + return (app_max_sectors(state) * sector_sz); } #endif From b994ba2ce29425587957dcbb6c96d4e1872b5737 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 3 Jan 2024 07:43:49 +0000 Subject: [PATCH 23/70] docs: release: Add release notes on changes Adds release notes on bootutil changes Signed-off-by: Jamie McCrae --- docs/release-notes.d/bootutil-sector.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/release-notes.d/bootutil-sector.md diff --git a/docs/release-notes.d/bootutil-sector.md b/docs/release-notes.d/bootutil-sector.md new file mode 100644 index 000000000..be1186de0 --- /dev/null +++ b/docs/release-notes.d/bootutil-sector.md @@ -0,0 +1,7 @@ +- bootutil: Fixed issue with comparing sector sizes for + compatibility, this now also checks against the number of usable + sectors (which is the slot size minus the swap status and moved + up by one sector). +- bootutil: Added debug logging to show write location of swap status + and details on sectors including if slot sizes are not optimal for + a given board. From c3a72e9daf8f94a7c3b0dc91cc19e2bb15b7110a Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Tue, 9 Jan 2024 08:30:58 +0100 Subject: [PATCH 24/70] boot: zephyr: moonlight watchdogs adding WATCHDOG_FEED support for WDT30 and WDT31 Signed-off-by: Mateusz Michalek --- 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 baa807c56..908b793cf 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 # @@ -665,6 +666,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 a9c52bdaf..8f5d17bf5 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -329,9 +329,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 ad5f0ac1b2e3ce3fca4e746b492d453e578b9dc1 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 25/70] 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 --- 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 a899390056c93ee7bd12b0c76ab63832591800a5 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 26/70] 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 --- 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 63ddb71d51ccba575dc227656a01255cb97fc327 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 27/70] 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 --- 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 bc07e2d60..fe79d3dac 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -439,7 +439,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), @@ -657,7 +657,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), @@ -910,7 +910,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 f09e205b1e4a8d2bc3f50dffa7960d6ccd14df59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 10:54:45 +0100 Subject: [PATCH 28/70] zcbor: Make changes to zcbor code to satisfy mynewt compile options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit printf format type and bit-casting between uint and float. Signed-off-by: Øyvind Rønningstad --- boot/zcbor/include/zcbor_print.h | 20 ++++++++++---------- boot/zcbor/src/zcbor_common.c | 13 ++++++++++--- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/boot/zcbor/include/zcbor_print.h b/boot/zcbor/include/zcbor_print.h index 22a5637d3..ef3bc1d73 100644 --- a/boot/zcbor/include/zcbor_print.h +++ b/boot/zcbor/include/zcbor_print.h @@ -73,17 +73,17 @@ do { \ #endif __attribute__((used)) -static void zcbor_print_compare_lines(const uint8_t *str1, const uint8_t *str2, uint32_t size) +static void zcbor_print_compare_lines(const uint8_t *str1, const uint8_t *str2, size_t size) { - for (uint32_t j = 0; j < size; j++) { + for (size_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++) { + for (size_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++) { + for (size_t j = 0; j < size; j++) { zcbor_do_print("%x ", str1[j] != str2[j]); } zcbor_do_print("\r\n"); @@ -91,10 +91,10 @@ 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) +static void zcbor_print_compare_strings(const uint8_t *str1, const uint8_t *str2, size_t size) { - for (uint32_t i = 0; i <= size / 16; i++) { - zcbor_do_print("line %d (char %d)\r\n", i, i*16); + for (size_t i = 0; i <= size / 16; i++) { + zcbor_do_print("line %zu (char %zu)\r\n", i, i*16); zcbor_print_compare_lines(&str1[i*16], &str2[i*16], MIN(16, (size - i*16))); } @@ -102,12 +102,12 @@ 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) +static void zcbor_print_compare_strings_diff(const uint8_t *str1, const uint8_t *str2, size_t size) { bool printed = false; - for (uint32_t i = 0; i <= size / 16; i++) { + for (size_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_do_print("line %zu (char %zu)\r\n", i, i*16); zcbor_print_compare_lines(&str1[i*16], &str2[i*16], MIN(16, (size - i*16))); printed = true; diff --git a/boot/zcbor/src/zcbor_common.c b/boot/zcbor/src/zcbor_common.c index f1a039e52..a7c9ee7be 100644 --- a/boot/zcbor/src/zcbor_common.c +++ b/boot/zcbor/src/zcbor_common.c @@ -355,14 +355,19 @@ float zcbor_float16_to_32(uint16_t input) : (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; + float result; + + memcpy(&result, &value32, sizeof(result)); + return result; } } uint16_t zcbor_float32_to_16(float input) { - uint32_t value32 = *(uint32_t *)&input; + uint32_t value32; + + memcpy(&value32, &input, sizeof(value32)); uint32_t sign = value32 >> F32_SIGN_OFFS; uint32_t expo = (value32 >> F32_EXPO_OFFS) & F32_EXPO_MSK; @@ -370,8 +375,10 @@ uint16_t zcbor_float32_to_16(float input) uint16_t value16 = (uint16_t)(sign << F16_SIGN_OFFS); + uint32_t abs_value32 = value32 & ~(1 << F32_SIGN_OFFS); float abs_input; - *(uint32_t *)&abs_input = value32 & ~(1 << F32_SIGN_OFFS); + + memcpy(&abs_input, &abs_value32, sizeof(abs_input)); if (abs_input <= (F16_MIN / 2)) { /* 0 or too small for float16. Round down to 0. value16 is already correct. */ From c8d213a9a100381da81db822fbd6728733459235 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 29/70] 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 --- 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 | 15 ++++----------- boot/zcbor/src/zcbor_decode.c | 2 +- boot/zcbor/src/zcbor_encode.c | 2 +- 8 files changed, 43 insertions(+), 27 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 ef3bc1d73..fc1966715 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, size_t size) { - for (size_t i = 0; i <= size / 16; i++) { - zcbor_do_print("line %zu (char %zu)\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, size_t size) { + const size_t col_width = 16; bool printed = false; - for (size_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 %zu (char %zu)\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 a7c9ee7be..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 */ /* @@ -355,19 +355,14 @@ float zcbor_float16_to_32(uint16_t input) : (expo + (F32_BIAS - F16_BIAS)); uint32_t value32 = (sign << F32_SIGN_OFFS) | (new_expo << F32_EXPO_OFFS) | (mantissa << (F32_EXPO_OFFS - F16_EXPO_OFFS)); - float result; - - memcpy(&result, &value32, sizeof(result)); - return result; + return *(float *)&value32; } } uint16_t zcbor_float32_to_16(float input) { - uint32_t value32; - - memcpy(&value32, &input, sizeof(value32)); + uint32_t value32 = *(uint32_t *)&input; uint32_t sign = value32 >> F32_SIGN_OFFS; uint32_t expo = (value32 >> F32_EXPO_OFFS) & F32_EXPO_MSK; @@ -375,10 +370,8 @@ uint16_t zcbor_float32_to_16(float input) uint16_t value16 = (uint16_t)(sign << F16_SIGN_OFFS); - uint32_t abs_value32 = value32 & ~(1 << F32_SIGN_OFFS); float abs_input; - - memcpy(&abs_input, &abs_value32, sizeof(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. */ 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 cf882ef3b56643053b3a825ac446ff92e55fd945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Wed, 10 Jan 2024 10:54:45 +0100 Subject: [PATCH 30/70] zcbor: Make changes to zcbor code to satisfy mynewt compile options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bit-casting between uint and float. Signed-off-by: Øyvind Rønningstad --- boot/zcbor/src/zcbor_common.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/boot/zcbor/src/zcbor_common.c b/boot/zcbor/src/zcbor_common.c index af93e7ff4..3697983aa 100644 --- a/boot/zcbor/src/zcbor_common.c +++ b/boot/zcbor/src/zcbor_common.c @@ -355,14 +355,19 @@ float zcbor_float16_to_32(uint16_t input) : (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; + float result; + + memcpy(&result, &value32, sizeof(result)); + return result; } } uint16_t zcbor_float32_to_16(float input) { - uint32_t value32 = *(uint32_t *)&input; + uint32_t value32; + + memcpy(&value32, &input, sizeof(value32)); uint32_t sign = value32 >> F32_SIGN_OFFS; uint32_t expo = (value32 >> F32_EXPO_OFFS) & F32_EXPO_MSK; @@ -370,8 +375,10 @@ uint16_t zcbor_float32_to_16(float input) uint16_t value16 = (uint16_t)(sign << F16_SIGN_OFFS); + uint32_t abs_value32 = value32 & ~(1 << F32_SIGN_OFFS); float abs_input; - *(uint32_t *)&abs_input = value32 & ~(1 << F32_SIGN_OFFS); + + memcpy(&abs_input, &abs_value32, sizeof(abs_input)); if (abs_input <= (F16_MIN / 2)) { /* 0 or too small for float16. Round down to 0. value16 is already correct. */ From 205d7e5b4194fd8c6e3219771e439048973e4984 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 31/70] 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 --- 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 fe79d3dac..b631e150f 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -934,7 +934,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 a4eda30f5b0cfd0cf15512be9dcd559239dbfc91 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 29 Jan 2024 11:00:25 +0000 Subject: [PATCH 32/70] zephyr: Add estimated size of update trailer to sysbuild Adds a new field which is set to the estimated size of the upgrade slot data, this is used to know how much space should be reserved in an update image to determine if an update will fit or not Signed-off-by: Jamie McCrae --- boot/zephyr/CMakeLists.txt | 11 ++++++++++- boot/zephyr/sysbuild/CMakeLists.txt | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 580954fc4..9156ad23d 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -492,15 +492,24 @@ if(SYSBUILD) endif() math(EXPR required_size "${key_size} + ${boot_magic_size} + ${boot_swap_data_size} + ${boot_status_data_size} + ${boot_tlv_estimate}") - align_up(${required_size} ${erase_size} required_size) + if(CONFIG_SINGLE_APPLICATION_SLOT OR CONFIG_BOOT_FIRMWARE_LOADER) + set(required_upgrade_size "0") + else() + math(EXPR required_upgrade_size "${boot_magic_size} + ${boot_swap_data_size} + ${boot_status_data_size}") + align_up(${required_upgrade_size} ${erase_size} required_upgrade_size) + endif() + if(CONFIG_BOOT_SWAP_USING_MOVE) math(EXPR required_size "${required_size} + ${erase_size}") + math(EXPR required_upgrade_size "${required_upgrade_size} + ${erase_size}") endif() else() set(required_size 0) + set(required_upgrade_size 0) endif() set(mcuboot_image_footer_size ${required_size} CACHE INTERNAL "Estimated MCUboot image trailer size" FORCE) + set(mcuboot_image_upgrade_footer_size ${required_upgrade_size} CACHE INTERNAL "Estimated MCUboot update image trailer size" FORCE) endif() diff --git a/boot/zephyr/sysbuild/CMakeLists.txt b/boot/zephyr/sysbuild/CMakeLists.txt index adcd74437..a39f4c490 100644 --- a/boot/zephyr/sysbuild/CMakeLists.txt +++ b/boot/zephyr/sysbuild/CMakeLists.txt @@ -31,9 +31,12 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_post_image_cmake) if("${app_type}" STREQUAL "MAIN") sysbuild_get(mcuboot_image_footer_size IMAGE mcuboot CACHE) + sysbuild_get(mcuboot_image_upgrade_footer_size IMAGE mcuboot CACHE) math(EXPR mcuboot_image_footer_size "${mcuboot_image_footer_size}" OUTPUT_FORMAT HEXADECIMAL) + math(EXPR mcuboot_image_upgrade_footer_size "${mcuboot_image_upgrade_footer_size}" OUTPUT_FORMAT HEXADECIMAL) set_property(TARGET ${image} APPEND_STRING PROPERTY CONFIG "CONFIG_ROM_END_OFFSET=${mcuboot_image_footer_size}\n") + set_property(TARGET ${image} APPEND_STRING PROPERTY CONFIG "CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE=${mcuboot_image_upgrade_footer_size}\n") return() endif() endforeach() From f44f042630fd79f216db2c1691294cf0d623753d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 33/70] Revert "[nrf noup] boards: thingy53: disable GPIO ISR support" This reverts commit 8bb85670472789ccd89c74745d68772159e1e280. Signed-off-by: Robert Lubos --- boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index e10656678..7d3bc0bec 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -21,7 +21,6 @@ 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 c56303f3fa0b977a9fdf8cf45b448806d3e11acb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 34/70] Revert "[nrf noup] loader: introduced cleanup of unusable secondary slot" This reverts commit ed3a0c2dbe3d52565a8316cfd82ee58c28650415. Signed-off-by: Robert Lubos --- boot/bootutil/src/loader.c | 90 -------------------------------------- 1 file changed, 90 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index ccf3def36..3367e79ac 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -951,87 +951,6 @@ 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 @@ -1070,9 +989,6 @@ 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) @@ -1107,7 +1023,6 @@ 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)) { @@ -1116,9 +1031,7 @@ 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)); @@ -2343,9 +2256,6 @@ 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 5f9c2d5ce000eb2d73d2715cc149e7a1c7b987eb Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 35/70] =?UTF-8?q?Revert=20"[nrf=20noup]=C2=A0loader:=20Add?= =?UTF-8?q?=20firmware=20version=20check=20downgrade=20prevention"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit c5aadd71007d0da1b4a2ee392fd58ea06e7bf7a5. Signed-off-by: Robert Lubos --- boot/bootutil/src/loader.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 3367e79ac..6892770f5 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -51,10 +51,6 @@ #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 @@ -786,21 +782,9 @@ 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 */ - -#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 + rc = boot_version_cmp( + &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, + &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); 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 50962cb329fdc725d62e06ce83f785051f56723f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 36/70] Revert "[nrf noup] zephyr: Boot even if EXT_ABI is not provided" This reverts commit 4b36f9f28ed1daae217b8b8c5ba353b2b691c09e. Signed-off-by: Robert Lubos --- boot/zephyr/main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index d601eae0a..5bc8b1c7e 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -258,16 +258,13 @@ static void do_boot(struct boot_rsp *rsp) #endif #if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) - const struct fw_info *firmware_info = fw_info_find((uint32_t) vt); - bool provided = fw_info_ext_api_provide(firmware_info, true); + 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) { - 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); + BOOT_LOG_ERR("Failed to provide EXT_APIs\n"); + return; } #endif #endif From ba7dd6febeb780803e610d85563670cab290afa8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 37/70] Revert "[nrf noup] zephyr: Add RAM flash configuration to cache for sysbuild" This reverts commit 90a91e08fedfea3b238ffe5489904d4fc19fb711. Signed-off-by: Robert Lubos --- boot/zephyr/CMakeLists.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 4b840d9d2..ce1c88d33 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -362,14 +362,3 @@ 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 fa880e631d4e96d4f7f028d7f2760ef670ce6d63 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 38/70] Revert "[nrf noup] loader: Do not check reset vector for XIP image" This reverts commit 8e373ccbbb896ff83587abd38c94a2ddf17687a6. Signed-off-by: Robert Lubos --- boot/bootutil/src/loader.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 6892770f5..8dd27714a 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -823,16 +823,6 @@ 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 08439d899c427618b6f22c9303ff0e1c8e7e450b Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 39/70] Revert "[nrf noup] sysflash: Add support for three images" This reverts commit 7b87633282e9d0bad957af56992022848fb02723. Signed-off-by: Robert Lubos --- boot/zephyr/include/sysflash/pm_sysflash.h | 82 ++++++++++------------ 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index db60ddd03..377291e8b 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -11,19 +11,37 @@ #include #include -#include #ifndef CONFIG_SINGLE_APPLICATION_SLOT -#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) +#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 /* (MCUBOOT_IMAGE_NUMBER == 2 && defined(PM_B0_ADDRESS) */ +#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 ) -#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ - !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#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) ? \ @@ -38,52 +56,26 @@ 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 -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_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_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 +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) -#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) +#endif /* PM_B0_ADDRESS */ -#if !defined(CONFIG_BOOT_SWAP_USING_MOVE) -#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID #endif - -#endif /* MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ - * !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) - */ +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID #else /* CONFIG_SINGLE_APPLICATION_SLOT */ From 761738c927969ba0340bceb811965bdeb3a3684f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 40/70] Revert "[nrf noup] sysflash: Move partition manager definitions to pm_sysflash.h" This reverts commit 418b6fe501c8cf0a067168a136ff845b8b363242. Signed-off-by: Robert Lubos --- boot/zephyr/include/sysflash/pm_sysflash.h | 92 ---------------------- boot/zephyr/include/sysflash/sysflash.h | 90 +++++++++++++++++++-- 2 files changed, 85 insertions(+), 97 deletions(-) delete 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 deleted file mode 100644 index 377291e8b..000000000 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 501c0b2e5..da21832a9 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -4,15 +4,93 @@ * SPDX-License-Identifier: Apache-2.0 */ -#if USE_PARTITION_MANAGER -/* Blocking the rest of the file */ +#ifndef __SYSFLASH_H__ #define __SYSFLASH_H__ -#include + +#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 ) -#ifndef __SYSFLASH_H__ -#define __SYSFLASH_H__ +#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 */ + +#else + +#include #include #include #include @@ -63,4 +141,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__ */ From 97e049be31b1c79f54738ba274d61bd6e0677ead Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 41/70] Revert "[nrf noup] boot: Add support for NSIB and multi-image" This reverts commit b4464ad3a00a699fb0097e362ac03b30671fdda4. Signed-off-by: Robert Lubos --- boot/bootutil/src/loader.c | 44 ++++++------------------- boot/zephyr/include/sysflash/sysflash.h | 19 ++--------- 2 files changed, 12 insertions(+), 51 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8dd27714a..4bd001ba3 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -845,11 +845,6 @@ 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 { @@ -970,37 +965,18 @@ 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; } - - /* 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 */ + /* 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; } } @@ -1264,7 +1240,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_get_id(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)), + rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap_primary_slot); assert (rc == 0); diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index da21832a9..d6a74f370 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -23,24 +23,9 @@ /* 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 ) +#ifdef 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) +extern uint32_t _image_1_primary_slot_id[]; #define FLASH_AREA_IMAGE_PRIMARY(x) \ ((x == 0) ? \ From 3aafd780af2d927f49e268a948531231ed7bbdcc Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 42/70] Revert "[nrf noup] loader: Fix missing PCD define check" This reverts commit 6024d0a97a546e9bc845de6c52684a261e681a21. Signed-off-by: Robert Lubos --- boot/bootutil/src/loader.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 4bd001ba3..8351a953f 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_PCD_APP) + && !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 @@ -1029,8 +1029,7 @@ boot_validated_swap_type(struct boot_loader_state *state, swap_type = BOOT_SWAP_TYPE_NONE; } } -#endif /* CONFIG_SOC_NRF5340_CPUAPP && PM_CPUNET_B0N_ADDRESS && - !CONFIG_NRF53_MULTI_IMAGE_UPDATE && CONFIG_PCD_APP */ +#endif /* CONFIG_SOC_NRF5340_CPUAPP */ } return swap_type; From 69006ec0e1a6be01868b6ff80f34870977f5d498 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 43/70] Revert "[nrf noup] zephyr: Fix path variables" This reverts commit d9d380408fd6efc9823955fc1b929c286c743684. Signed-off-by: Robert Lubos --- boot/zephyr/CMakeLists.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index ce1c88d33..154442399 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -26,20 +26,21 @@ 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(MCUBOOT_NRF_EXT_DIR "${MCUBOOT_DIR}/ext/nrf") +set(NRF_DIR "${MCUBOOT_DIR}/ext/nrf") if(CONFIG_BOOT_USE_NRF_CC310_BL) - if(NOT EXISTS ${ZEPHYR_NRFXLIB_MODULE_DIR}) - message(FATAL_ERROR " +set(NRFXLIB_DIR ${ZEPHYR_BASE}/../nrfxlib) +if(NOT EXISTS ${NRFXLIB_DIR}) + message(FATAL_ERROR " ------------------------------------------------------------------------ - No such file or directory: ${ZEPHYR_NRFXLIB_MODULE_DIR} + No such file or directory: ${NRFXLIB_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( @@ -161,8 +162,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(${MCUBOOT_NRF_EXT_DIR}/cc310_glue.c) - zephyr_library_include_directories(${MCUBOOT_NRF_EXT_DIR}) + 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) From 4fa8d28ac27dd156b41af422cd9002e0484de7d6 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 44/70] Revert "[nrf noup] loader: Fix reading reset addr to support ext flash" This reverts commit 5bdac092c6eb4a4e0a275fc9ea262046a3282f4a. Signed-off-by: Robert Lubos --- boot/bootutil/src/loader.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8351a953f..bf1c5cd35 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -940,9 +940,10 @@ 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 = boot_img_hdr(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; - 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 @@ -952,19 +953,16 @@ boot_validated_swap_type(struct boot_loader_state *state, */ if (hdr->ih_magic == IMAGE_MAGIC) { - 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; - } + 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; - rc = flash_area_open(flash_area_id_from_multi_image_slot( + int rc = flash_area_open(flash_area_id_from_multi_image_slot( BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT), &primary_fa); @@ -1000,19 +998,16 @@ boot_validated_swap_type(struct boot_loader_state *state, upgrade_valid = true; } -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) \ - && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#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) { - 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"); - rc = pcd_network_core_update(net_core_fw_addr, fw_size); + int rc = pcd_network_core_update(vtable, fw_size); if (rc != 0) { swap_type = BOOT_SWAP_TYPE_FAIL; From 959ddb9177164381f65ca93f98424378f710f6b6 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 45/70] Revert "[nrf noup] zephyr: Clean up non-secure RAM if enabled" This reverts commit 83bc352b963efde2b5bba2d28a24a9ec7275c625. Signed-off-by: Robert Lubos --- 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, 2 insertions(+), 23 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 154442399..0cf0ade1f 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 OR CONFIG_MCUBOOT_CLEANUP_NONSECURE_RAM) +if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL) 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 9e87e13f5..6b04cedfe 100644 --- a/boot/zephyr/include/nrf_cleanup.h +++ b/boot/zephyr/include/nrf_cleanup.h @@ -16,9 +16,4 @@ */ 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 5bc8b1c7e..b6b039b89 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 || CONFIG_MCUBOOT_NRF_CLEANUP_NONSECURE_RAM +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL #include #endif @@ -271,9 +271,6 @@ 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 2165159ea..5bab26b24 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -20,10 +20,6 @@ #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) @@ -85,12 +81,3 @@ 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 666eaed4d8e7c1ffefccfab17b6b726b149da935 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 46/70] Revert "[nrf noup] zephyr: clean peripherals state before boot" This reverts commit 1b0aa58267e39a052622f7eaf55195b7ff1d69e7. Signed-off-by: Robert Lubos --- 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, 1 insertion(+), 115 deletions(-) delete mode 100644 boot/zephyr/include/nrf_cleanup.h delete mode 100644 boot/zephyr/nrf_cleanup.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 0cf0ade1f..467eb9be1 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -357,9 +357,3 @@ 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 deleted file mode 100644 index 6b04cedfe..000000000 --- a/boot/zephyr/include/nrf_cleanup.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 b6b039b89..f2d0425c2 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -145,10 +145,6 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif -#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL -#include -#endif - #ifdef CONFIG_SOC_FAMILY_NRF #include @@ -268,9 +264,7 @@ 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 deleted file mode 100644 index 5bab26b24..000000000 --- a/boot/zephyr/nrf_cleanup.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 ed6a9579b42c932980f5388cf21ea3a8aad2d135 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 47/70] Revert "[nrf noup] boot: nrf53-specific customizations" This reverts commit 20095871947ddd4516a0b0e3fe32b72363ab872e. Signed-off-by: Robert Lubos --- 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, 26 insertions(+), 186 deletions(-) delete mode 100644 boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index bf1c5cd35..a7b388438 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -49,10 +49,6 @@ #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 @@ -935,15 +931,7 @@ boot_validated_swap_type(struct boot_loader_state *state, { int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); - 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; +#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 @@ -951,36 +939,34 @@ 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) { - 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 */ + 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 /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ +#endif swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -994,37 +980,7 @@ 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 deleted file mode 100644 index 7d3bc0bec..000000000 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ /dev/null @@ -1,73 +0,0 @@ -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 d6a74f370..e22f9b776 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -20,11 +20,6 @@ #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) \ @@ -40,24 +35,6 @@ 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 f2d0425c2..898f501b9 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -94,10 +94,6 @@ 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. */ @@ -727,9 +723,6 @@ 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 125b8813c..0c3a59154 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -72,16 +72,3 @@ 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 710ca469ca469ac16e8feea212fa106f47f423e7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 48/70] Revert "[nrf noup] treewide: add NCS partition manager support" This reverts commit 80016fd841cdd2710cbcd6471202739b00593dff. Signed-off-by: Robert Lubos --- 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, 11 insertions(+), 296 deletions(-) delete mode 100644 boot/zephyr/pm.yml diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index a7b388438..b2ea9ddb0 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -109,15 +109,6 @@ 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 { @@ -831,24 +822,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, goto out; } - 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)) { + if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) { BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot"); BOOT_LOG_ERR("Erasing image from secondary slot"); @@ -931,42 +905,6 @@ 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)) { @@ -2292,25 +2230,15 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT -#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. + 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. */ - 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; - } + 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 @@ -2327,16 +2255,11 @@ 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 cd5016391..61246b9e5 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -237,18 +237,6 @@ 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; @@ -285,7 +273,6 @@ 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 a32eb8d87..66cbdce5f 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -170,18 +170,6 @@ 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; @@ -267,7 +255,6 @@ 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 467eb9be1..14a891f34 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -290,13 +290,6 @@ 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 f69790e74..2dec368eb 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -9,8 +9,6 @@ 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 e22f9b776..646f1122f 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -7,52 +7,6 @@ #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 @@ -103,6 +57,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__ */ diff --git a/boot/zephyr/include/target.h b/boot/zephyr/include/target.h index 513693511..61dfd9322 100644 --- a/boot/zephyr/include/target.h +++ b/boot/zephyr/include/target.h @@ -8,8 +8,6 @@ #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 @@ -47,6 +45,4 @@ #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 898f501b9..7b3702475 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -64,10 +64,6 @@ #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" @@ -136,11 +132,6 @@ 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 @@ -248,19 +239,6 @@ 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 */ @@ -703,30 +681,7 @@ 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 deleted file mode 100644 index 0c3a59154..000000000 --- a/boot/zephyr/pm.yml +++ /dev/null @@ -1,74 +0,0 @@ -#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 23b5f3b93..58cb2ae35 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -19,7 +19,6 @@ 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 22eb94911..ed3ed5c00 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 797b0fa10..c4293e387 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -1,5 +1,4 @@ samples: - boot/zephyr build: - cmake-ext: True - kconfig-ext: True + cmake: ./boot/bootutil/zephyr From 57e0fc733d9ef30831adc7581244066a5bb1122d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 49/70] Revert "[nrf fromtree] boot: zephyr: moonlight watchdogs" This reverts commit df01761e611675db3cd1bff183243be4e318d8bc. Signed-off-by: Robert Lubos --- boot/zephyr/Kconfig | 3 --- .../include/mcuboot_config/mcuboot_config.h | 16 ++-------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2dec368eb..78fe793ed 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1,6 +1,5 @@ # Copyright (c) 2017-2020 Linaro Limited # Copyright (c) 2020 Arm Limited -# Copyright (c) 2023 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 # @@ -650,8 +649,6 @@ 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 375088741..0cf2e6060 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -324,21 +324,9 @@ #elif defined(CONFIG_NRFX_WDT0) #define MCUBOOT_WATCHDOG_FEED() \ FEED_WDT_INST(0); -#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 +#else /* defined(CONFIG_NRFX_WDT0) && defined(CONFIG_NRFX_WDT1) */ #error "No NRFX WDT instances enabled" -#endif +#endif /* defined(CONFIG_NRFX_WDT0) && defined(CONFIG_NRFX_WDT1) */ #elif DT_NODE_HAS_STATUS(DT_ALIAS(watchdog0), okay) /* CONFIG_NRFX_WDT */ #include From b2e6ef5bbe91c6fa15c0cb81be75e0e9a8dc65b8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 50/70] Revert "[nrf fromtree] boot_serial: Adapt to zcbor 0.8.x" This reverts commit 9e03ad4333fa5e9d5f714466571d27558ce49593. Signed-off-by: Robert Lubos --- 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 988817fc1..9f486a230 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_lit(cbor_state, "r"); + zcbor_tstr_put_term(cbor_state, "r"); if (zcbor_tstr_encode(cbor_state, &value) && zcbor_map_end_encode(cbor_state, 10)) { boot_serial_output(); return; From 4e40746c868d49930ccbeae0a72f6a052a4d79b8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 51/70] Revert "[nrf fromtree] zcbor: Copy source and header files" This reverts commit e5d5708fe33e827abd4e664978b47e31c73638d3. Signed-off-by: Robert Lubos --- 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, 17 insertions(+), 40 deletions(-) diff --git a/boot/zcbor/include/zcbor_common.h b/boot/zcbor/include/zcbor_common.h index 0583ab893..0bf81c9c2 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.1 + * Commit zcbor 0.8.0 */ /* @@ -22,23 +22,6 @@ 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. */ @@ -505,8 +488,6 @@ 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 e5a58d82c..4cc2c19bd 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.1 + * Commit zcbor 0.8.0 */ /* diff --git a/boot/zcbor/include/zcbor_encode.h b/boot/zcbor/include/zcbor_encode.h index 5139d3ca3..68741d147 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.1 + * Commit zcbor 0.8.0 */ /* diff --git a/boot/zcbor/include/zcbor_print.h b/boot/zcbor/include/zcbor_print.h index 6ab6d453d..22a5637d3 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.1 + * Commit zcbor 0.8.0 */ /* @@ -93,12 +93,10 @@ 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) { - 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))); + 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"); } @@ -106,14 +104,12 @@ 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 (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))); + 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; } } diff --git a/boot/zcbor/include/zcbor_tags.h b/boot/zcbor/include/zcbor_tags.h index d17e8b348..1cf811d9a 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.1 + * Commit zcbor 0.8.0 */ /* diff --git a/boot/zcbor/src/zcbor_common.c b/boot/zcbor/src/zcbor_common.c index af93e7ff4..f1a039e52 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.1 + * Commit zcbor 0.8.0 */ /* diff --git a/boot/zcbor/src/zcbor_decode.c b/boot/zcbor/src/zcbor_decode.c index 841c34171..5f7e0e15d 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.1 + * Commit zcbor 0.8.0 */ /* diff --git a/boot/zcbor/src/zcbor_encode.c b/boot/zcbor/src/zcbor_encode.c index 53d19c01f..9859d6818 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.1 + * Commit zcbor 0.8.0 */ /* From 3885aab1c6b29ca81afac6feabf7d4f29d0c91a7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 52/70] Revert "[nrf fromtree] boot_serial: Adapt to API changes in zcbor 0.8.0" This reverts commit fc20e9bb80c3acf8b82b4d0921da0f02d3b0b355. Signed-off-by: Robert Lubos --- 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 9f486a230..5213866ad 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, NULL, 0); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); 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, NULL, 0); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); 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, NULL, 0); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); if (!zcbor_map_start_decode(zsd)) { goto out; From d490bed4e1248ba474b22d8756db6553a1506578 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 53/70] Revert "[nrf fromtree] zcbor: Add copy notice to all copied files" This reverts commit 0c539f6acb35adb5e29d2c8db0cfd3b325f91d1e. Signed-off-by: Robert Lubos --- 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 deletions(-) diff --git a/boot/zcbor/add_zcbor_copy_version.sh b/boot/zcbor/add_zcbor_copy_version.sh index a88ebf901..dc49887c0 100755 --- a/boot/zcbor/add_zcbor_copy_version.sh +++ b/boot/zcbor/add_zcbor_copy_version.sh @@ -20,5 +20,3 @@ 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 0bf81c9c2..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.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 4cc2c19bd..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.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 68741d147..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.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 22a5637d3..18f8656c5 100644 --- a/boot/zcbor/include/zcbor_print.h +++ b/boot/zcbor/include/zcbor_print.h @@ -1,8 +1,3 @@ -/* - * 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 1cf811d9a..89148776c 100644 --- a/boot/zcbor/include/zcbor_tags.h +++ b/boot/zcbor/include/zcbor_tags.h @@ -1,8 +1,3 @@ -/* - * 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 f1a039e52..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.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 5f7e0e15d..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.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 9859d6818..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.8.0 - */ - /* * Copyright (c) 2020 Nordic Semiconductor ASA * From a8c984423c218ce23f77febe75effd9dbc8a9c60 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 11 Mar 2024 14:04:33 +0100 Subject: [PATCH 54/70] Revert "[nrf fromtree] zcbor: Copy source and header files" This reverts commit b137da69b7aff537494e6ed562775d6e1a606dc7. Signed-off-by: Robert Lubos --- 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, 971 insertions(+), 2079 deletions(-) create mode 100644 boot/zcbor/include/zcbor_debug.h delete mode 100644 boot/zcbor/include/zcbor_print.h delete 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 879889713..f44ded6ad 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.7.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -10,8 +15,6 @@ #include #include #include -#include -#include "zcbor_tags.h" #ifdef __cplusplus extern "C" { @@ -40,25 +43,54 @@ 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 -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#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 MAX -#define MAX(a, b) (((a) < (b)) ? (b) : (a)) +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #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. @@ -70,7 +102,6 @@ struct zcbor_string_fragment { struct zcbor_state_constant; -/** The zcbor_state_t structure is used for both encoding and decoding. */ typedef struct { union { uint8_t *payload_mut; @@ -79,59 +110,31 @@ union { processed. */ }; uint8_t const *payload_bak; /**< Temporary backup of payload. */ - 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. */ + 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. */ uint8_t const *payload_end; /**< The end of the payload. This will be checked against payload before processing each element. */ - 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; + 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. */ 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; - size_t current_backup; - size_t num_backups; + uint_fast32_t current_backup; + uint_fast32_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 }; @@ -149,42 +152,27 @@ 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_SIMPLE = 7, ///! Simple values and floats + 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_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_log("ZCBOR_FAIL "); \ - zcbor_trace_file(state); \ + zcbor_trace(); \ 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) @@ -192,7 +180,6 @@ do { \ #define ZCBOR_ERR_IF(expr, err) \ do {\ if (expr) { \ - zcbor_log("ZCBOR_ERR_IF(" #expr ", %d) ", err); \ ZCBOR_ERR(err); \ } \ } while(0) @@ -218,12 +205,11 @@ 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_SIMPLE ((uint8_t)20) ///! In CBOR, false/true have the values 20/21 +#define ZCBOR_BOOL_TO_PRIM ((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_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_FLAG_TRANSFER_PAYLOAD 4UL ///! Keep the pre-restore payload after restoring. #define ZCBOR_SUCCESS 0 #define ZCBOR_ERR_NO_BACKUP_MEM 1 @@ -240,30 +226,47 @@ 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. */ -#define ZCBOR_MAX_ELEM_COUNT SIZE_MAX +#ifdef UINT_FAST32_MAX +#define ZCBOR_MAX_ELEM_COUNT UINT_FAST32_MAX +#else +#define ZCBOR_MAX_ELEM_COUNT ((uint_fast32_t)(-1L)) +#endif /** Initial value for elem_count for when it just needs to be large. */ -#define ZCBOR_LARGE_ELEM_COUNT (ZCBOR_MAX_ELEM_COUNT - 15) +#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 +}; /** Take a backup of the current state. Overwrite the current elem_count. */ -bool zcbor_new_backup(zcbor_state_t *state, size_t new_elem_count); +bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_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, size_t max_elem_count); +bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, uint_fast32_t max_elem_count); /** Convenience function for starting encoding/decoding of a union. * @@ -291,30 +294,17 @@ 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, 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. + * 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. */ -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); +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); #ifdef ZCBOR_STOP_ON_ERROR -/** 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 - */ +/** Check stored error and fail if present, but only if stop_on_error is true. */ 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 @@ -365,9 +355,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 @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. + * 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. * * @param[inout] state The current state, will be updated with * the new payload pointer. @@ -392,7 +382,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, - size_t num_fragments); + uint_fast32_t num_fragments); /** Assemble the fragments into a single string. * @@ -411,77 +401,7 @@ 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, - 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 + uint_fast32_t num_fragments, uint8_t *result, size_t *result_len); #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_debug.h b/boot/zcbor/include/zcbor_debug.h new file mode 100644 index 000000000..5f9b4778f --- /dev/null +++ b/boot/zcbor/include/zcbor_debug.h @@ -0,0 +1,69 @@ +/* + * 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 61a6f1763..53ce94db4 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.7.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -23,222 +28,213 @@ extern "C" { */ -/** 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. +/** The following applies to all single-value decode functions that don't have docs. * - * 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 + * @param[inout] state The current state of the decoding. + * @param[out] result Where to place the decoded value. * * @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. */ -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. + +/** 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. * * @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. */ -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. */ +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); /** 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 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); +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 }; -/** Decode and consume a list/map header. + 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. * - * The contents of the list can be decoded via subsequent function calls. + * @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); + +/** Decode and consume a bstr header. + * + * 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_list_end_decode / @ref zcbor_map_end_decode when done - * decoding the contents of the list/map + * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. * * @retval true Header decoded correctly * @retval false Header decoded incorrectly, or backup failed. */ -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_start_decode(zcbor_state_t *state, struct zcbor_string *result); + +/** Finalize decoding a CBOR-encoded bstr. + * + * Restore element count from backup. */ -bool zcbor_unordered_map_search(zcbor_decoder_t key_decoder, zcbor_state_t *state, void *key_result); +bool zcbor_bstr_end_decode(zcbor_state_t *state); -/** Find a specific bstr/tstr key as part of a map with unknown element order. +/** 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. * - * 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. + * This consumes the remaining payload as long as it belongs to the string. */ -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))) +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); -/** (Optional) Call this function to mark an (unordered map) element as processed. +/** Extract the next fragment of a string. * - * @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. + * 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. * - * By default, this function increments the internal count @ref map_elems_processed. + * 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. * - * 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. + * 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. * - * @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. + * 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. */ -bool zcbor_elem_processed(zcbor_state_t *state); +bool zcbor_list_start_decode(zcbor_state_t *state); +bool zcbor_map_start_decode(zcbor_state_t *state); /** Finalize decoding a list/map * @@ -248,33 +244,13 @@ bool zcbor_elem_processed(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. @@ -317,8 +293,6 @@ bool zcbor_any_skip(zcbor_state_t *state, void *unused); * 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 @@ -328,9 +302,9 @@ bool zcbor_any_skip(zcbor_state_t *state, void *unused); * @retval false If @p decoder failed before having decoded @p min_decode * values. */ -bool zcbor_multi_decode(size_t min_decode, size_t max_decode, size_t *num_decode, +bool zcbor_multi_decode(uint_fast32_t min_decode, uint_fast32_t max_decode, uint_fast32_t *num_decode, zcbor_decoder_t decoder, zcbor_state_t *state, void *result, - size_t result_len); + uint_fast32_t result_len); /** Attempt to decode a value that might not be present in the data. * @@ -343,102 +317,31 @@ bool zcbor_multi_decode(size_t min_decode, size_t max_decode, size_t *num_decode * * @return Should always return true. */ -bool zcbor_present_decode(bool *present, +bool zcbor_present_decode(uint_fast32_t *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); -/** Supplementary string (bstr/tstr) decoding functions: */ - -/** Consume and expect a bstr/tstr with the value of the provided char/uint8_t array. - * - * @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. - * - * 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. - */ -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. +/** Convenience macro for declaring and initializing a state with backups. * - * 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. + * This gives you a state variable named @p name. The variable functions like + * a pointer. * - * Use this function to extract all but the first fragment of a CBOR-encoded - * bstr. + * @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). */ -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); +#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) #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_encode.h b/boot/zcbor/include/zcbor_encode.h index 89b0a97bf..40bcccfe1 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.7.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -16,7 +21,6 @@ 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, @@ -24,72 +28,130 @@ extern "C" { */ -/** 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); +/** 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); -/** Convenience macro for declaring and initializing an encoding state with backups. +/** Encode a pint/nint from a pointer. * - * This gives you a state variable named @p name. The variable functions like - * 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[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[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. */ -#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) +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 }; -/** The following applies to all _put and _encode functions listed directly below. + return zcbor_tstr_encode(state, &zs); +} + +/** Encode a string literal as a bstr/tstr. * - * 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. + * @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) + +/** Encode null-terminated string as a bstr/tstr. * - * @param[inout] state The current state of the encoding. - * @param[in] input The value to encode. + * @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. * - * @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 */ + * @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. + */ +#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); + +/** 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. + * + * @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 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. + * + * Restore element count from backup. + */ +bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); /** Encode a list/map header. * @@ -107,8 +169,8 @@ bool zcbor_float64_encode(zcbor_state_t *state, const double *input); /* IEEE754 * call. * Only used when ZCBOR_CANONICAL is defined. */ -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); +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); /** Encode the end of a list/map. Do some checks and deallocate backup. * @@ -127,8 +189,8 @@ bool zcbor_map_start_encode(zcbor_state_t *state, size_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, size_t max_num); -bool zcbor_map_end_encode(zcbor_state_t *state, size_t max_num); +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_map_end_force_encode(zcbor_state_t *state); /** Encode 0 or more elements with the same type and constraints. @@ -179,59 +241,49 @@ 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(size_t num_encode, zcbor_encoder_t encoder, - zcbor_state_t *state, const void *input, size_t result_len); +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); /** 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(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); - +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); -/* Supplementary string (bstr/tstr) encoding functions: */ - -/** Encode a char/uint8_t pointer as a bstr/tstr. - * - * @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. - * - * 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. +/** Runs @p encoder on @p state and @p input if @p present is true. * - * @param[inout] state The current state of the encoding. - * - * @retval true Header encoded correctly - * @retval false Header encoded incorrectly, or backup failed. + * Calls @ref zcbor_multi_encode under the hood. */ -bool zcbor_bstr_start_encode(zcbor_state_t *state); +bool zcbor_present_encode(const uint_fast32_t *present, + zcbor_encoder_t encoder, + zcbor_state_t *state, + const void *input); -/** Finalize encoding a CBOR-encoded bstr. +/** 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); + +/** Convenience macro for declaring and initializing a state with backups. * - * This writes the final size of the bstr to the header. - * Restore element count from backup. + * 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). */ -bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); +#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) #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_print.h b/boot/zcbor/include/zcbor_print.h deleted file mode 100644 index 18f8656c5..000000000 --- a/boot/zcbor/include/zcbor_print.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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 deleted file mode 100644 index 89148776c..000000000 --- a/boot/zcbor/include/zcbor_tags.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 1caf80668..e7a5e3aee 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.7.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -9,7 +14,6 @@ #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."); @@ -17,7 +21,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, size_t new_elem_count) +bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count) { ZCBOR_CHECK_ERROR(); @@ -32,41 +36,39 @@ bool zcbor_new_backup(zcbor_state_t *state, size_t new_elem_count) /* use the backup at current_backup - 1, since otherwise, the 0th * backup would be unused. */ - size_t i = (state->constant_state->current_backup) - 1; + uint_fast32_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, - size_t max_elem_count) + uint_fast32_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_log("No backups available.\r\n"); + zcbor_print("No backups available.\r\n"); ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_ACTIVE); } - /* use the backup at current_backup - 1, since otherwise, the - * 0th backup would be unused. */ - size_t i = state->constant_state->current_backup - 1; - - zcbor_log("Process backup (level %zu, flags 0x%x)\n", i, flags); - if (flags & ZCBOR_FLAG_RESTORE) { - if (!(flags & ZCBOR_FLAG_KEEP_PAYLOAD)) { + /* 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; + + if (!(flags & ZCBOR_FLAG_TRANSFER_PAYLOAD)) { if (state->constant_state->backup_list[i].payload_moved) { - zcbor_log("Payload pointer out of date.\r\n"); - ZCBOR_ERR(ZCBOR_ERR_PAYLOAD_OUTDATED); + zcbor_print("Payload pointer out of date.\r\n"); + ZCBOR_FAIL(); } } memcpy(state, &state->constant_state->backup_list[i], @@ -77,19 +79,14 @@ bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, state->constant_state->current_backup--; } - 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); + if (elem_count > max_elem_count) { + zcbor_print("elem_count: %" PRIuFAST32 " (expected max %" PRIuFAST32 ")\r\n", + elem_count, max_elem_count); ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT); } - 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; + if (flags & ZCBOR_FLAG_TRANSFER_PAYLOAD) { + state->payload = payload; } return true; @@ -98,7 +95,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 (unsigned int i = 0; i < state->constant_state->current_backup; i++) { + for (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; } @@ -131,26 +128,17 @@ bool zcbor_union_end_code(zcbor_state_t *state) return true; } -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) +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) { 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; } @@ -162,10 +150,6 @@ void zcbor_new_state(zcbor_state_t *state_array, size_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]; @@ -183,7 +167,7 @@ void zcbor_update_state(zcbor_state_t *state, bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, - size_t num_fragments) + uint_fast32_t num_fragments) { size_t total_len = 0; @@ -191,7 +175,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, return false; } - for (size_t i = 0; i < num_fragments; i++) { + for (uint_fast32_t i = 0; i < num_fragments; i++) { if (fragments[i].offset != total_len) { return false; } @@ -212,7 +196,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, } if (num_fragments && (fragments[0].total_len == ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH)) { - for (size_t i = 0; i < num_fragments; i++) { + for (uint_fast32_t i = 0; i < num_fragments; i++) { fragments[i].total_len = total_len; } } @@ -221,7 +205,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, } bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, - size_t num_fragments, uint8_t *result, size_t *result_len) + uint_fast32_t num_fragments, uint8_t *result, size_t *result_len) { size_t total_len = 0; @@ -229,7 +213,7 @@ bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, return false; } - for (size_t i = 0; i < num_fragments; i++) { + for (uint_fast32_t i = 0; i < num_fragments; i++) { if ((total_len > *result_len) || (fragments[i].fragment.len > (*result_len - total_len))) { return false; @@ -242,189 +226,3 @@ 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 92f9fe517..c99fc8385 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.7.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -8,19 +13,15 @@ #include #include #include -#include -#include "zcbor_decode.h" -#include "zcbor_common.h" -#include "zcbor_print.h" +#include +#include /** Return value length from additional value. */ -static size_t additional_len(uint8_t additional) +static uint_fast32_t additional_len(uint8_t additional) { - if (additional <= ZCBOR_VALUE_IN_HEADER) { - return 0; - } else if (ZCBOR_VALUE_IS_1_BYTE <= additional && additional <= ZCBOR_VALUE_IS_8_BYTES) { + if (ZCBOR_VALUE_IS_1_BYTE <= additional && additional <= ZCBOR_VALUE_IS_8_BYTES) { /* 24 => 1 * 25 => 2 * 26 => 4 @@ -28,9 +29,23 @@ static size_t additional_len(uint8_t additional) */ return 1U << (additional - ZCBOR_VALUE_IS_1_BYTE); } - return 0xF; + return 0; } +/** 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) { @@ -39,13 +54,12 @@ 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 = ZCBOR_MAJOR_TYPE(*state->payload); + zcbor_major_type_t major_type = MAJOR_TYPE(*state->payload); if (major_type != exp_major_type) { ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE); @@ -53,7 +67,6 @@ 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)) { \ @@ -68,17 +81,11 @@ 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 { \ - err_restore(state, err); \ - ZCBOR_FAIL(); \ + state->payload = state->payload_bak; \ + state->elem_count++; \ + ZCBOR_ERR(err); \ } while(0) #define FAIL_RESTORE() \ @@ -88,21 +95,6 @@ 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 @@ -119,55 +111,61 @@ static void endian_copy(uint8_t *dst, const uint8_t *src, size_t src_len) * 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 ZCBOR_BIG_ENDIAN). + * big to little-endian if necessary (@ref CONFIG_BIG_ENDIAN). */ static bool value_extract(zcbor_state_t *state, - void *const result, size_t result_len) + void *const result, uint_fast32_t result_len) { - zcbor_trace(state, "value_extract"); + zcbor_trace(); zcbor_assert_state(result_len != 0, "0-length result not supported.\r\n"); - 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"); + zcbor_assert_state(result != NULL, NULL); INITIAL_CHECKS(); ZCBOR_ERR_IF((state->elem_count == 0), ZCBOR_ERR_LOW_ELEM_COUNT); - 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)); + uint8_t *u8_result = (uint8_t *)result; + uint8_t additional = ADDITIONAL(*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); + state->payload_bak = state->payload; + (state->payload)++; memset(result, 0, result_len); - - if (len == 0) { - *result_offs = additional; + 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 { - endian_copy(result_offs, state->payload + 1, len); + uint_fast32_t len = additional_len(additional); -#ifdef ZCBOR_CANONICAL - ZCBOR_ERR_IF((zcbor_header_len_ptr(result, result_len) != (len + 1)), - ZCBOR_ERR_INVALID_VALUE_ENCODING); -#endif + 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 */ + + (state->payload) += len; } - state->payload_bak = state->payload; - (state->payload) += len + 1; (state->elem_count)--; return true; } -bool zcbor_int_decode(zcbor_state_t *state, void *result, size_t result_size) +bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) { - PRINT_FUNC(); INITIAL_CHECKS(); - 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; + 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; if (major_type != ZCBOR_MAJOR_TYPE_PINT && major_type != ZCBOR_MAJOR_TYPE_NINT) { @@ -175,14 +173,14 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result, size_t result_size) ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE); } - if (!value_extract(state, result, result_size)) { + if (!value_extract(state, result_int, int_size)) { ZCBOR_FAIL(); } -#ifdef ZCBOR_BIG_ENDIAN +#ifdef CONFIG_BIG_ENDIAN if (result_int8[0] < 0) { #else - if (result_int8[result_size - 1] < 0) { + if (result_int8[int_size - 1] < 0) { #endif /* Value is too large to fit in a signed integer. */ ERR_RESTORE(ZCBOR_ERR_INT_SIZE); @@ -190,7 +188,7 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result, size_t result_size) if (major_type == ZCBOR_MAJOR_TYPE_NINT) { /* Convert from CBOR's representation by flipping all bits. */ - for (unsigned int i = 0; i < result_size; i++) { + for (int i = 0; i < int_size; i++) { result_uint8[i] = (uint8_t)~result_uint8[i]; } } @@ -201,41 +199,29 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result, size_t result_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_uint_decode(zcbor_state_t *state, void *result, size_t result_size) +bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result) { - PRINT_FUNC(); INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT); - if (!value_extract(state, result, result_size)) { - zcbor_log("uint with size %zu failed.\r\n", result_size); + if (!value_extract(state, result, sizeof(*result))) { 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(); } @@ -245,7 +231,6 @@ 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(); } @@ -255,7 +240,6 @@ 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(); } @@ -265,7 +249,6 @@ 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(); } @@ -273,109 +256,72 @@ bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result) } -bool zcbor_int32_expect(zcbor_state_t *state, int32_t expected) +bool zcbor_int32_expect(zcbor_state_t *state, int32_t 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); + return zcbor_int64_expect(state, result); } -bool zcbor_int64_expect(zcbor_state_t *state, int64_t expected) +bool zcbor_int64_expect(zcbor_state_t *state, int64_t result) { - PRINT_FUNC(); - int64_t actual; + int64_t value; - if (!zcbor_int64_decode(state, &actual)) { + if (!zcbor_int64_decode(state, &value)) { ZCBOR_FAIL(); } - if (actual != expected) { - zcbor_log("%" PRIi64 " != %" PRIi64 "\r\n", actual, expected); + if (value != result) { + zcbor_print("%" PRIi64 " != %" PRIi64 "\r\n", value, result); ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -bool zcbor_int64_pexpect(zcbor_state_t *state, int64_t *expected) -{ - PRINT_FUNC(); - return zcbor_int64_expect(state, *expected); -} - - bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result) { - PRINT_FUNC(); - return zcbor_uint_decode(state, result, sizeof(*result)); + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT); + + if (!value_extract(state, result, sizeof(*result))) { + ZCBOR_FAIL(); + } + return true; } #ifdef ZCBOR_SUPPORTS_SIZE_T bool zcbor_size_decode(zcbor_state_t *state, size_t *result) { - PRINT_FUNC(); - return zcbor_uint_decode(state, result, sizeof(*result)); + return value_extract(state, result, sizeof(size_t)); } #endif -bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t expected) -{ - PRINT_FUNC(); - return zcbor_uint64_expect(state, expected); -} - - -bool zcbor_uint32_pexpect(zcbor_state_t *state, uint32_t *expected) +bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t result) { - PRINT_FUNC(); - return zcbor_uint32_expect(state, *expected); + return zcbor_uint64_expect(state, result); } -bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t expected) +bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t result) { - PRINT_FUNC(); - uint64_t actual; + uint64_t value; - if (!zcbor_uint64_decode(state, &actual)) { + if (!zcbor_uint64_decode(state, &value)) { ZCBOR_FAIL(); } - if (actual != expected) { - zcbor_log("%" PRIu64 " != %" PRIu64 "\r\n", actual, expected); + if (value != result) { + zcbor_print("%" PRIu64 " != %" PRIu64 "\r\n", value, result); 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 expected) -{ - PRINT_FUNC(); - return zcbor_uint64_expect(state, expected); -} - - -bool zcbor_size_pexpect(zcbor_state_t *state, size_t *expected) +bool zcbor_size_expect(zcbor_state_t *state, size_t result) { - PRINT_FUNC(); - return zcbor_size_expect(state, *expected); + return zcbor_uint64_expect(state, result); } #endif @@ -393,37 +339,31 @@ static bool str_start_decode(zcbor_state_t *state, return true; } -static bool str_start_decode_with_overflow_check(zcbor_state_t *state, - struct zcbor_string *result, zcbor_major_type_t exp_major_type) -{ - 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)); +static bool str_overflow_check(zcbor_state_t *state, struct zcbor_string *result) +{ + if (result->len > (state->payload_end - state->payload)) { + zcbor_print("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_with_overflow_check(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { + if(!str_start_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { + ZCBOR_FAIL(); + } + + if (!str_overflow_check(state, result)) { ZCBOR_FAIL(); } @@ -441,7 +381,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_KEEP_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, ZCBOR_MAX_ELEM_COUNT)) { ZCBOR_FAIL(); } @@ -462,7 +402,6 @@ 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(); } @@ -478,7 +417,6 @@ 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(); } @@ -499,7 +437,7 @@ void zcbor_next_fragment(zcbor_state_t *state, result->fragment.len = result->total_len - result->offset; partition_fragment(state, result); - zcbor_log("New fragment length %zu\r\n", result->fragment.len); + zcbor_print("New fragment length %zu\r\n", result->fragment.len); state->payload += result->fragment.len; } @@ -515,7 +453,7 @@ void zcbor_bstr_next_fragment(zcbor_state_t *state, result->fragment.len = result->total_len - result->offset; partition_fragment(state, result); - zcbor_log("fragment length %zu\r\n", result->fragment.len); + zcbor_print("fragment length %zu\r\n", result->fragment.len); state->payload_end = state->payload + result->fragment.len; } @@ -529,7 +467,11 @@ 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_with_overflow_check(state, result, exp_major_type)) { + if (!str_start_decode(state, result, exp_major_type)) { + ZCBOR_FAIL(); + } + + if (!str_overflow_check(state, result)) { ZCBOR_FAIL(); } @@ -558,7 +500,8 @@ static bool str_expect(zcbor_state_t *state, struct zcbor_string *result, if (!str_decode(state, &tmp_result, exp_major_type)) { ZCBOR_FAIL(); } - if (!zcbor_compare_strings(&tmp_result, result)) { + if ((tmp_result.len != result->len) + || memcmp(result->value, tmp_result.value, tmp_result.len)) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; @@ -567,97 +510,56 @@ 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 *expected) +bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *result) { - PRINT_FUNC(); - return str_expect(state, expected, ZCBOR_MAJOR_TYPE_BSTR); + return str_expect(state, result, 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 *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) +bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *result) { - 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)); + return str_expect(state, result, ZCBOR_MAJOR_TYPE_TSTR); } static bool list_map_start_decode(zcbor_state_t *state, zcbor_major_type_t exp_major_type) { - size_t new_elem_count; + uint_fast32_t new_elem_count; bool indefinite_length_array = false; INITIAL_CHECKS_WITH_TYPE(exp_major_type); -#ifndef ZCBOR_CANONICAL - if (ZCBOR_ADDITIONAL(*state->payload) == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { + if (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_bak = state->payload++; + state->payload++; state->elem_count--; - } else -#endif - { + } else { if (!value_extract(state, &new_elem_count, sizeof(new_elem_count))) { ZCBOR_FAIL(); } @@ -667,7 +569,7 @@ static bool list_map_start_decode(zcbor_state_t *state, FAIL_RESTORE(); } - state->decode_state.indefinite_length_array = indefinite_length_array; + state->indefinite_length_array = indefinite_length_array; return true; } @@ -675,17 +577,15 @@ 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->decode_state.indefinite_length_array) { + if (ret && !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); @@ -696,272 +596,6 @@ 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(); @@ -974,19 +608,17 @@ static bool array_end_expect(zcbor_state_t *state) static bool list_map_end_decode(zcbor_state_t *state) { - size_t max_elem_count = 0; + uint_fast32_t max_elem_count = 0; -#ifndef ZCBOR_CANONICAL - if (state->decode_state.indefinite_length_array) { + if (state->indefinite_length_array) { if (!array_end_expect(state)) { ZCBOR_FAIL(); } max_elem_count = ZCBOR_MAX_ELEM_COUNT; - state->decode_state.indefinite_length_array = false; + state->indefinite_length_array = false; } -#endif if (!zcbor_process_backup(state, - ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_KEEP_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, max_elem_count)) { ZCBOR_FAIL(); } @@ -997,51 +629,20 @@ 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_KEEP_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, ZCBOR_MAX_ELEM_COUNT)) { ZCBOR_FAIL(); } @@ -1050,180 +651,69 @@ bool zcbor_list_map_end_force_decode(zcbor_state_t *state) } -bool zcbor_simple_decode(zcbor_state_t *state, uint8_t *result) +static bool primx_expect(zcbor_state_t *state, uint8_t result) { - 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; -} - + uint32_t value; -bool zcbor_simple_expect(zcbor_state_t *state, uint8_t expected) -{ - PRINT_FUNC(); - uint8_t actual; + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); - if (!zcbor_simple_decode(state, &actual)) { + if (!value_extract(state, &value, sizeof(value))) { ZCBOR_FAIL(); } - if (actual != expected) { - zcbor_log("simple value %u != %u\r\n", actual, expected); + if (value != result) { 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) { - 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)) { + if (!primx_expect(state, 22)) { 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_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) -{ - 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_float16_bytes_expect(zcbor_state_t *state, uint16_t expected) +bool zcbor_undefined_expect(zcbor_state_t *state, void *unused) { - PRINT_FUNC(); - uint16_t actual; - - if (!zcbor_float16_bytes_decode(state, &actual)) { + if (!primx_expect(state, 23)) { 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) +bool zcbor_bool_decode(zcbor_state_t *state, bool *result) { - PRINT_FUNC(); - uint16_t value16; - - if (!zcbor_float16_bytes_decode(state, &value16)) { + if (zcbor_bool_expect(state, false)) { + *result = false; + } else if (zcbor_bool_expect(state, true)) { + *result = true; + } else { ZCBOR_FAIL(); } - *result = zcbor_float16_to_32(value16); + zcbor_print("boolval: %u\r\n", *result); return true; } -bool zcbor_float16_expect(zcbor_state_t *state, float expected) +bool zcbor_bool_expect(zcbor_state_t *state, bool result) { - PRINT_FUNC(); - float actual; - - if (!zcbor_float16_decode(state, &actual)) { + if (!primx_expect(state, (uint8_t)(!!result) + ZCBOR_BOOL_TO_PRIM)) { 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) { - PRINT_FUNC(); - ZCBOR_FAIL_IF(!float_check(state, ZCBOR_VALUE_IS_4_BYTES)); + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); + ZCBOR_ERR_IF(ADDITIONAL(*state->payload) != ZCBOR_VALUE_IS_4_BYTES, ZCBOR_ERR_FLOAT_SIZE); if (!value_extract(state, result, sizeof(*result))) { ZCBOR_FAIL(); @@ -1233,65 +723,24 @@ bool zcbor_float32_decode(zcbor_state_t *state, float *result) } -bool zcbor_float32_expect(zcbor_state_t *state, float expected) +bool zcbor_float32_expect(zcbor_state_t *state, float result) { - PRINT_FUNC(); - float actual; + float value; - if (!zcbor_float32_decode(state, &actual)) { + if (!zcbor_float32_decode(state, &value)) { ZCBOR_FAIL(); } - if (actual != expected) { + if (value != result) { 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) { - PRINT_FUNC(); - ZCBOR_FAIL_IF(!float_check(state, ZCBOR_VALUE_IS_8_BYTES)); + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); + ZCBOR_ERR_IF(ADDITIONAL(*state->payload) != ZCBOR_VALUE_IS_8_BYTES, ZCBOR_ERR_FLOAT_SIZE); if (!value_extract(state, result, sizeof(*result))) { ZCBOR_FAIL(); @@ -1301,71 +750,25 @@ bool zcbor_float64_decode(zcbor_state_t *state, double *result) } -bool zcbor_float64_expect(zcbor_state_t *state, double expected) +bool zcbor_float64_expect(zcbor_state_t *state, double result) { - PRINT_FUNC(); - double actual; + double value; - if (!zcbor_float64_decode(state, &actual)) { + if (!zcbor_float64_decode(state, &value)) { ZCBOR_FAIL(); } - if (actual != expected) { + if (value != result) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -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)) { - *result = (double)float_result; - } else if (!zcbor_float64_decode(state, result)) { - ZCBOR_FAIL(); - } - - return true; -} - - -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)) { + if (zcbor_float32_decode(state, &float_result)) { *result = (double)float_result; } else if (!zcbor_float64_decode(state, result)) { ZCBOR_FAIL(); @@ -1375,14 +778,11 @@ bool zcbor_float_decode(zcbor_state_t *state, double *result) } -bool zcbor_float_expect(zcbor_state_t *state, double expected) +bool zcbor_float_expect(zcbor_state_t *state, double result) { - PRINT_FUNC(); - if (zcbor_float16_expect(state, (float)expected)) { - /* Do nothing */ - } else if (zcbor_float32_expect(state, (float)expected)) { + if (zcbor_float32_expect(state, (float)result)) { /* Do nothing */ - } else if (!zcbor_float64_expect(state, expected)) { + } else if (!zcbor_float64_expect(state, result)) { ZCBOR_FAIL(); } @@ -1390,47 +790,54 @@ bool zcbor_float_expect(zcbor_state_t *state, double expected) } -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 = 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; - - memcpy(&state_copy, state, sizeof(zcbor_state_t)); + 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; - while (major_type == ZCBOR_MAJOR_TYPE_TAG) { - uint32_t tag_dummy; + payload_bak = state->payload; - if (!zcbor_tag_decode(&state_copy, &tag_dummy)) { - ZCBOR_FAIL(); + 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; } - 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); } -#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))) { + if (!value_extract(state, &value, sizeof(value))) { /* Can happen because of elem_count (or payload_end) */ ZCBOR_FAIL(); } @@ -1438,49 +845,38 @@ 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. - * 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; + /* '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; break; case ZCBOR_MAJOR_TYPE_MAP: - ZCBOR_ERR_IF(value > (SIZE_MAX / 2), ZCBOR_ERR_INT_SIZE); - value *= 2; - /* fallthrough */ + value *= 2; /* Because all members have a key. */ + /* Fallthrough */ case ZCBOR_MAJOR_TYPE_LIST: - 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)) { + 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; 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))) { @@ -1491,41 +887,32 @@ bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result) } -bool zcbor_tag_expect(zcbor_state_t *state, uint32_t expected) +bool zcbor_tag_expect(zcbor_state_t *state, uint32_t result) { - PRINT_FUNC(); - uint32_t actual; + uint32_t tag_val; - if (!zcbor_tag_decode(state, &actual)) { + if (!zcbor_tag_decode(state, &tag_val)) { ZCBOR_FAIL(); } - if (actual != expected) { + if (tag_val != result) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -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, +bool zcbor_multi_decode(uint_fast32_t min_decode, + uint_fast32_t max_decode, + uint_fast32_t *num_decode, zcbor_decoder_t decoder, zcbor_state_t *state, void *result, - size_t result_len) + uint_fast32_t result_len) { - PRINT_FUNC(); ZCBOR_CHECK_ERROR(); - for (size_t i = 0; i < max_decode; i++) { + for (uint_fast32_t i = 0; i < max_decode; i++) { uint8_t const *payload_bak = state->payload; - size_t elem_count_bak = state->elem_count; + uint_fast32_t elem_count_bak = state->elem_count; if (!decoder(state, (uint8_t *)result + i*result_len)) { @@ -1533,35 +920,33 @@ bool zcbor_multi_decode(size_t min_decode, state->payload = payload_bak; state->elem_count = elem_count_bak; ZCBOR_ERR_IF(i < min_decode, ZCBOR_ERR_ITERATIONS); - zcbor_log("Found %zu elements.\r\n", i); + zcbor_print("Found %" PRIuFAST32 " elements.\r\n", i); return true; } } - zcbor_log("Found %zu elements.\r\n", max_decode); + zcbor_print("Found %" PRIuFAST32 " elements.\r\n", max_decode); *num_decode = max_decode; return true; } -bool zcbor_present_decode(bool *present, +bool zcbor_present_decode(uint_fast32_t *present, zcbor_decoder_t decoder, zcbor_state_t *state, void *result) { - PRINT_FUNC(); - size_t num_decode = 0; + uint_fast32_t num_decode; 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, size_t n_states, - const uint8_t *payload, size_t payload_len, size_t elem_count, - uint8_t *flags, size_t flags_bytes) +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) { - zcbor_new_state(state_array, n_states, payload, payload_len, elem_count, flags, flags_bytes); + zcbor_new_state(state_array, n_states, payload, payload_len, elem_count); } diff --git a/boot/zcbor/src/zcbor_encode.c b/boot/zcbor/src/zcbor_encode.c index 44411ea35..1929cebd5 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.7.0 + */ + /* * Copyright (c) 2020 Nordic Semiconductor ASA * @@ -10,13 +15,12 @@ #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(size_t val) +static uint8_t log2ceil(uint_fast32_t val) { switch(val) { case 1: return 0; @@ -29,74 +33,114 @@ static uint8_t log2ceil(size_t val) case 8: return 3; } - zcbor_log("Should not come here.\r\n"); + zcbor_print("Should not come here.\r\n"); return 0; } - -static uint8_t get_additional(size_t len, uint8_t value0) +static uint8_t get_additional(uint_fast32_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, "Unsupported additional value: %d\r\n", additional); + zcbor_assert_state(additional < 32, NULL); *(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, size_t result_len) + const void *const result, uint_fast32_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 + result_len) > state->payload_end) { + if ((state->payload + 1 + encoded_len) > state->payload_end) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } if (!encode_header_byte(state, major_type, - get_additional(result_len, u8_result[0]))) { + get_additional(encoded_len, u8_result[0]))) { ZCBOR_FAIL(); } state->payload_mut--; - zcbor_trace(state, "value_encode_len"); + zcbor_trace(); state->payload_mut++; -#ifdef ZCBOR_BIG_ENDIAN - memcpy(state->payload_mut, u8_result, result_len); - state->payload_mut += result_len; +#ifdef CONFIG_BIG_ENDIAN + memcpy(state->payload_mut, u8_result, encoded_len); + state->payload_mut += encoded_len; #else - for (; result_len > 0; result_len--) { - *(state->payload_mut++) = u8_result[result_len - 1]; + for (; encoded_len > 0; encoded_len--) { + *(state->payload_mut++) = u8_result[encoded_len - 1]; } -#endif /* ZCBOR_BIG_ENDIAN */ +#endif /* CONFIG_BIG_ENDIAN */ state->elem_count++; return true; } -static bool value_encode(zcbor_state_t *state, zcbor_major_type_t major_type, - const void *const input, size_t max_result_len) +static uint_fast32_t get_result_len(const void *const input, uint_fast32_t max_result_len) { - zcbor_assert_state(max_result_len != 0, "0-length result not supported.\r\n"); + uint8_t *u8_result = (uint8_t *)input; + uint_fast32_t len = max_result_len; - size_t result_len = zcbor_header_len_ptr(input, max_result_len) - 1; - const void *result = input; + 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)); +} -#ifdef ZCBOR_BIG_ENDIAN - result = (uint8_t *)input + max_result_len - (result_len ? result_len : 1); + +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) +{ + 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); return value_encode_len(state, major_type, result, result_len); } @@ -114,7 +158,7 @@ bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_si ZCBOR_ERR(ZCBOR_ERR_INT_SIZE); } -#ifdef ZCBOR_BIG_ENDIAN +#ifdef CONFIG_BIG_ENDIAN if (input_int8[0] < 0) { #else if (input_int8[int_size - 1] < 0) { @@ -122,7 +166,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 (unsigned int i = 0; i < int_size; i++) { + for (int i = 0; i < int_size; i++) { input_buf[i] = (uint8_t)~input_uint8[i]; } input = input_buf; @@ -138,37 +182,53 @@ bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_si } -bool zcbor_uint_encode(zcbor_state_t *state, const void *input_uint, size_t uint_size) +bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *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; + return zcbor_int_encode(state, input, sizeof(*input)); } -bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input) +bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input) { return zcbor_int_encode(state, input, sizeof(*input)); } -bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input) +static bool uint32_encode(zcbor_state_t *state, const uint32_t *input, + zcbor_major_type_t major_type) { - return zcbor_int_encode(state, input, sizeof(*input)); + if (!value_encode(state, major_type, input, 4)) { + ZCBOR_FAIL(); + } + return true; } bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input) { - return zcbor_uint_encode(state, input, sizeof(*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; } bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input) { - return zcbor_uint_encode(state, input, sizeof(*input)); + if (!uint64_encode(state, input, ZCBOR_MAJOR_TYPE_PINT)) { + ZCBOR_FAIL(); + } + return true; } @@ -186,34 +246,37 @@ bool zcbor_int64_put(zcbor_state_t *state, int64_t input) bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input) { - return zcbor_uint_encode(state, &input, sizeof(input)); + return zcbor_uint64_put(state, input); } bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input) { - return zcbor_uint_encode(state, &input, sizeof(input)); + if (!uint64_encode(state, &input, ZCBOR_MAJOR_TYPE_PINT)) { + ZCBOR_FAIL(); + } + return true; } #ifdef ZCBOR_SUPPORTS_SIZE_T bool zcbor_size_put(zcbor_state_t *state, size_t input) { - return zcbor_uint_encode(state, &input, sizeof(input)); + return zcbor_uint64_put(state, input); } bool zcbor_size_encode(zcbor_state_t *state, const size_t *input) { - return zcbor_uint_encode(state, input, sizeof(*input)); + return zcbor_size_put(state, *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 && ((zcbor_header_len_ptr(&input->len, sizeof(input->len)) - + input->len + (size_t)state->payload) + if (input->value && ((get_result_len(&input->len, sizeof(input->len)) + + 1 + input->len + (size_t)state->payload) > (size_t)state->payload_end)) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } @@ -225,10 +288,19 @@ 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 = zcbor_header_len_ptr(&max_len, sizeof(max_len)) - 1; + size_t result_len = get_result_len(&max_len, sizeof(max_len)); return max_len - result_len - 1; } @@ -243,7 +315,8 @@ bool zcbor_bstr_start_encode(zcbor_state_t *state) uint64_t max_len = remaining_str_len(state); /* Encode a dummy header */ - if (!value_encode(state, ZCBOR_MAJOR_TYPE_BSTR, &max_len, sizeof(max_len))) { + if (!uint64_encode(state, &max_len, + ZCBOR_MAJOR_TYPE_BSTR)) { ZCBOR_FAIL(); } return true; @@ -280,8 +353,7 @@ 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) { - ZCBOR_CHECK_PAYLOAD(); /* To make the size_t cast below safe. */ - if (input->len > (size_t)(state->payload_end - state->payload)) { + if (input->len > (state->payload_end - state->payload)) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } if (!str_start_encode(state, input, major_type)) { @@ -309,35 +381,7 @@ bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input) } -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, +static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num, zcbor_major_type_t major_type) { #ifdef ZCBOR_CANONICAL @@ -351,8 +395,6 @@ static bool list_map_start_encode(zcbor_state_t *state, size_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(); } @@ -361,43 +403,54 @@ static bool list_map_start_encode(zcbor_state_t *state, size_t max_num, } -bool zcbor_list_start_encode(zcbor_state_t *state, size_t max_num) +bool zcbor_list_start_encode(zcbor_state_t *state, uint_fast32_t max_num) { return list_map_start_encode(state, max_num, ZCBOR_MAJOR_TYPE_LIST); } -bool zcbor_map_start_encode(zcbor_state_t *state, size_t max_num) +bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num) { return list_map_start_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP); } -static bool list_map_end_encode(zcbor_state_t *state, size_t max_num, +#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, zcbor_major_type_t major_type) { #ifdef ZCBOR_CANONICAL - size_t list_count = ((major_type == ZCBOR_MAJOR_TYPE_LIST) ? + uint_fast32_t list_count = ((major_type == ZCBOR_MAJOR_TYPE_LIST) ? state->elem_count : (state->elem_count / 2)); const uint8_t *payload = state->payload; - 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; + uint_fast32_t max_header_len = get_encoded_len2(&max_num, 4); + uint_fast32_t header_len = get_encoded_len2(&list_count, 4); if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME, 0xFFFFFFFF)) { ZCBOR_FAIL(); } - zcbor_log("list_count: %zu\r\n", list_count); + zcbor_print("list_count: %" PRIuFAST32 "\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_log("max_num too small.\r\n"); + zcbor_print("max_num too small.\r\n"); ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT); } @@ -418,9 +471,7 @@ static bool list_map_end_encode(zcbor_state_t *state, size_t max_num, state->payload = payload; } #else - (void)max_num; - (void)major_type; - if (!encode_header_byte(state, ZCBOR_MAJOR_TYPE_SIMPLE, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { + if (!encode_header_byte(state, ZCBOR_MAJOR_TYPE_PRIM, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { ZCBOR_FAIL(); } #endif @@ -428,13 +479,13 @@ static bool list_map_end_encode(zcbor_state_t *state, size_t max_num, } -bool zcbor_list_end_encode(zcbor_state_t *state, size_t max_num) +bool zcbor_list_end_encode(zcbor_state_t *state, uint_fast32_t max_num) { return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_LIST); } -bool zcbor_map_end_encode(zcbor_state_t *state, size_t max_num) +bool zcbor_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num) { return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP); } @@ -448,56 +499,45 @@ 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 zcbor_simple_put(state, 22); + return primitive_put(state, 22); } bool zcbor_undefined_put(zcbor_state_t *state, const void *unused) { (void)unused; - return zcbor_simple_put(state, 23); + return primitive_put(state, 23); } bool zcbor_bool_encode(zcbor_state_t *state, const bool *input) { - return zcbor_bool_put(state, *input); + if (!primitive_put(state, (uint32_t)(*input + ZCBOR_BOOL_TO_PRIM))) { + ZCBOR_FAIL(); + } + return true; } bool zcbor_bool_put(zcbor_state_t *state, bool input) { - return zcbor_simple_put(state, (!!input + ZCBOR_BOOL_TO_SIMPLE)); + if (!primitive_put(state, (uint32_t)(input + ZCBOR_BOOL_TO_PRIM))) { + ZCBOR_FAIL(); + } + return true; } bool zcbor_float64_encode(zcbor_state_t *state, const double *input) { - if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, + if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_PRIM, input, sizeof(*input))) { ZCBOR_FAIL(); } @@ -514,7 +554,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_SIMPLE, input, + if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_PRIM, input, sizeof(*input))) { ZCBOR_FAIL(); } @@ -529,36 +569,7 @@ bool zcbor_float32_put(zcbor_state_t *state, float input) } -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) +bool zcbor_tag_encode(zcbor_state_t *state, uint32_t tag) { if (!value_encode(state, ZCBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) { ZCBOR_FAIL(); @@ -569,15 +580,13 @@ bool zcbor_tag_put(zcbor_state_t *state, uint32_t tag) } -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) +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) { if ((*num_encode >= min_encode) && (*num_encode <= max_encode)) { @@ -587,23 +596,34 @@ bool zcbor_multi_encode_minmax(size_t min_encode, size_t max_encode, } } - -bool zcbor_multi_encode(const size_t num_encode, zcbor_encoder_t encoder, - zcbor_state_t *state, const void *input, size_t result_len) +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) { ZCBOR_CHECK_ERROR(); - for (size_t i = 0; i < num_encode; i++) { + for (uint_fast32_t i = 0; i < num_encode; i++) { if (!encoder(state, (const uint8_t *)input + i*result_len)) { ZCBOR_FAIL(); } } - zcbor_log("Encoded %zu elements.\n", num_encode); + zcbor_print("Encoded %" PRIuFAST32 " elements.\n", num_encode); return true; } -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) +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) { - zcbor_new_state(state_array, n_states, payload, payload_len, elem_count, NULL, 0); + zcbor_new_state(state_array, n_states, payload, payload_len, elem_count); } From 518617a4921c66e637073753370974743127412c 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 55/70] [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) (cherry picked from commit 80016fd841cdd2710cbcd6471202739b00593dff) Signed-off-by: Robert Lubos --- 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 d53406ddd..acf03533a 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 { @@ -826,7 +835,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"); @@ -909,6 +935,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)) { @@ -2234,15 +2296,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 @@ -2259,11 +2331,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 111e82f05..5e6723bb6 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -259,6 +259,18 @@ static int app_max_sectors(struct boot_loader_state *state) 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; @@ -306,6 +318,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 c85e0bc66..1f8fa6699 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -297,6 +297,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 908b793cf..143a8d343 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 890e69d98..2ec4fc7e2 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 c6a0f74ae..4efeb7e2e 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -65,6 +65,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" @@ -125,6 +129,11 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); * !defined(ZEPHYR_LOG_MODE_MINIMAL) */ +#if USE_PARTITION_MANAGER && CONFIG_FPROTECT +#include +#include +#endif + BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -173,6 +182,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 */ @@ -529,7 +551,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 014a21956..9360dbf70 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -1,5 +1,6 @@ samples: - boot/zephyr build: - cmake: ./boot/bootutil/zephyr + cmake-ext: True + kconfig-ext: True sysbuild-cmake: boot/zephyr/sysbuild From 42e43d04e0b2327ac0722b070a3b2fa11f17fa34 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Thu, 27 Aug 2020 14:29:31 +0200 Subject: [PATCH 56/70] [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) (cherry picked from commit 20095871947ddd4516a0b0e3fe32b72363ab872e) Signed-off-by: Robert Lubos --- 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 acf03533a..a3abbaed5 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 @@ -935,7 +939,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 @@ -943,34 +955,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)) { @@ -984,7 +998,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 2ec4fc7e2..78c5ead1c 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 4efeb7e2e..eeba79393 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -87,6 +87,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. */ @@ -571,6 +575,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 3b2a5baea3a31a399508f338ccf2e0696939451a Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 27 Feb 2020 12:48:56 +0100 Subject: [PATCH 57/70] [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) (cherry picked from commit 1b0aa58267e39a052622f7eaf55195b7ff1d69e7) --- 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 1f8fa6699..a4eb548d0 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -520,3 +520,9 @@ if(SYSBUILD) set(mcuboot_image_footer_size ${required_size} CACHE INTERNAL "Estimated MCUboot image trailer size" FORCE) set(mcuboot_image_upgrade_footer_size ${required_upgrade_size} CACHE INTERNAL "Estimated MCUboot update image trailer size" FORCE) 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 eeba79393..da9f16c9b 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -138,6 +138,10 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL +#include +#endif + BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -198,7 +202,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 047d463df16e048e4f85283bf57b7228c62ff17b Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Fri, 6 Jan 2023 12:24:48 +0100 Subject: [PATCH 58/70] [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) (cherry picked from commit 83bc352b963efde2b5bba2d28a24a9ec7275c625) Signed-off-by: Robert Lubos --- 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 a4eb548d0..3fa47f5c5 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -521,7 +521,7 @@ if(SYSBUILD) set(mcuboot_image_upgrade_footer_size ${required_upgrade_size} CACHE INTERNAL "Estimated MCUboot update image trailer size" FORCE) 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 da9f16c9b..bafbfe683 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -138,7 +138,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 @@ -205,6 +205,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 2dac63a3ecd987c056351e09bdb240c3af37ecfe Mon Sep 17 00:00:00 2001 From: Christian Taedcke Date: Thu, 10 Feb 2022 15:37:49 +0100 Subject: [PATCH 59/70] [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) (cherry picked from commit 5bdac092c6eb4a4e0a275fc9ea262046a3282f4a) Signed-off-by: Robert Lubos --- 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 a3abbaed5..9eeefbdce 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -944,10 +944,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 @@ -957,16 +956,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); @@ -1002,16 +1004,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 c28fa1d8c6d4d5a73b08394f0e96f7cb2f3e3d8f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Jul 2023 08:42:49 +0100 Subject: [PATCH 60/70] [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) (cherry picked from commit d9d380408fd6efc9823955fc1b929c286c743684) Signed-off-by: Robert Lubos --- 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 3fa47f5c5..8e1930db4 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -27,21 +27,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( @@ -169,8 +168,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 f577000c9d4dfc2f3efdf40a938f37567a89f12e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 31 Aug 2023 08:58:31 +0100 Subject: [PATCH 61/70] [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) (cherry picked from commit 6024d0a97a546e9bc845de6c52684a261e681a21) Signed-off-by: Robert Lubos --- 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 9eeefbdce..58f400fb0 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1005,7 +1005,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 @@ -1033,7 +1033,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 22ed9fbb3980b1464c1ba2846a9f0b8ea487fb79 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Wed, 31 May 2023 14:41:13 +0200 Subject: [PATCH 62/70] [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) (cherry picked from commit b4464ad3a00a699fb0097e362ac03b30671fdda4) Signed-off-by: Robert Lubos --- 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 58f400fb0..957289264 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -849,6 +849,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 { @@ -969,18 +974,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; } } @@ -1244,7 +1268,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 78c5ead1c..fb5aa4782 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 f013888a19ae24c83c40f48af69c1161deba6bb7 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 10 Aug 2023 17:32:48 +0000 Subject: [PATCH 63/70] [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) (cherry picked from commit 418b6fe501c8cf0a067168a136ff845b8b363242) Signed-off-by: Robert Lubos --- 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 fb5aa4782..6db393b00 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 d3f55fe0facd7582710a4a5851b0f227769c1d6e Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 11 Aug 2023 12:29:13 +0000 Subject: [PATCH 64/70] [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) (cherry picked from commit 7b87633282e9d0bad957af56992022848fb02723) Signed-off-by: Robert Lubos --- 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 d798de3f27589d640a750d98aca4e91affbf927b Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 22 Sep 2023 21:31:08 +0000 Subject: [PATCH 65/70] [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) (cherry picked from commit 8e373ccbbb896ff83587abd38c94a2ddf17687a6) Signed-off-by: Robert Lubos --- 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 957289264..d73dce753 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -827,6 +827,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 af27205c904fa5eee91eb3a9cec3a1eea939b4aa Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 18 Sep 2023 13:47:00 +0100 Subject: [PATCH 66/70] [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) (cherry picked from commit 90a91e08fedfea3b238ffe5489904d4fc19fb711) Signed-off-by: Robert Lubos --- boot/zephyr/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 8e1930db4..a41b61ef5 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -525,3 +525,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 41cc274e70465192a973b28ca9463c22e3ae9e82 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 17 Oct 2023 11:28:09 +0200 Subject: [PATCH 67/70] [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) (cherry picked from commit 4b36f9f28ed1daae217b8b8c5ba353b2b691c09e) Signed-off-by: Robert Lubos --- 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 bafbfe683..0785590e0 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -192,13 +192,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 8e91ec1b9ea30ba0ca201bf8fb8cdf173f1188e7 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Wed, 27 Sep 2023 15:18:04 +0200 Subject: [PATCH 68/70] =?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) (cherry picked from commit c5aadd71007d0da1b4a2ee392fd58ea06e7bf7a5) Signed-off-by: Robert Lubos --- 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 d73dce753..40048e933 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 @@ -786,9 +790,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 3b0eac81098959eb6ee063b82bd1a542d93bfdf4 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 15 Feb 2024 16:47:25 +0100 Subject: [PATCH 69/70] [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 (cherry picked from commit ed3a0c2dbe3d52565a8316cfd82ee58c28650415) Signed-off-by: Robert Lubos --- 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 40048e933..4224bd9b2 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -955,6 +955,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 @@ -993,6 +1074,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) @@ -1027,6 +1111,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)) { @@ -1035,7 +1120,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)); @@ -2260,6 +2347,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 86af2de75205ec5f2c846a2393934360de22fde4 Mon Sep 17 00:00:00 2001 From: Nikodem Kastelik Date: Mon, 9 Oct 2023 09:55:57 +0200 Subject: [PATCH 70/70] [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) (cherry picked from commit 8bb85670472789ccd89c74745d68772159e1e280) Signed-off-by: Robert Lubos --- 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