Infineon: Add cyw20829 platform, shared slot feature, json memory map, psoc6 xip

Based in 1.8.0 release of MCUBoot library

This commit adds CYW20829 Infineon platform support with following capabilities:
1. Overwrite and swap upgrade mode support
2. Multi-image with up to 4 images
3. Hardware security counter is supported for CYW20829 platform

Add XIP support for PSOC6 platform - place BOOT slot in external memory and execute it in place using SMIF in XIP mode

and some new features for Infineon devices.

1. Shared upgrade slot feature - use one shared area for upgrade slots of multiple images
2. Memory map defined using JSON file - define memory regions for bootloader and user app in conventional way using JSON file
diff --git a/boot/boot_serial/pkg.yml b/boot/boot_serial/pkg.yml
index f1431c7..19f9a32 100644
--- a/boot/boot_serial/pkg.yml
+++ b/boot/boot_serial/pkg.yml
@@ -28,7 +28,6 @@
 pkg.deps:
     - "@apache-mynewt-core/hw/hal"
     - "@apache-mynewt-core/kernel/os"
-    - "@apache-mynewt-core/encoding/tinycbor"
     - "@apache-mynewt-core/encoding/base64"
     - "@mcuboot/boot/mynewt/flash_map_backend"
     - "@mcuboot/boot/mynewt/boot_uart"
diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c
index d0f0eb0..914167e 100644
--- a/boot/boot_serial/src/boot_serial.c
+++ b/boot/boot_serial/src/boot_serial.c
@@ -25,6 +25,7 @@
 #include "sysflash/sysflash.h"
 
 #include "bootutil/bootutil_log.h"
+#include "cbor_encode.h"
 
 #ifdef __ZEPHYR__
 #include <power/reboot.h>
@@ -33,8 +34,6 @@
 #include <drivers/flash.h>
 #include <sys/crc.h>
 #include <sys/base64.h>
-#include <tinycbor/cbor.h>
-#include <tinycbor/cbor_buf_reader.h>
 #else
 #include <bsp/bsp.h>
 #include <hal/hal_system.h>
@@ -42,7 +41,6 @@
 #include <os/os_cputime.h>
 #include <crc/crc16.h>
 #include <base64/base64.h>
-#include <tinycbor/cbor.h>
 #endif /* __ZEPHYR__ */
 
 #include <flash_map_backend/flash_map_backend.h>
@@ -56,16 +54,21 @@
 #include "boot_serial/boot_serial.h"
 #include "boot_serial_priv.h"
 
-#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
+#ifdef MCUBOOT_ERASE_PROGRESSIVELY
 #include "bootutil_priv.h"
 #endif
 
 #include "serial_recovery_cbor.h"
+#include "bootutil/boot_hooks.h"
 
-MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
+BOOT_LOG_MODULE_DECLARE(mcuboot);
+
+#ifndef BOOT_IMAGE_NUMBER
+#define BOOT_IMAGE_NUMBER MCUBOOT_IMAGE_NUMBER
+#endif
 
 #define BOOT_SERIAL_INPUT_MAX   512
-#define BOOT_SERIAL_OUT_MAX     128
+#define BOOT_SERIAL_OUT_MAX     (128 * MCUBOOT_IMAGE_NUMBER)
 
 #ifdef __ZEPHYR__
 /* base64 lib encodes data to null-terminated string */
@@ -78,10 +81,6 @@
 #define htons(x) sys_cpu_to_be16(x)
 #endif
 
-#ifndef BOOT_IMAGE_NUMBER
-#define BOOT_IMAGE_NUMBER MCUBOOT_IMAGE_NUMBER
-#endif
-
 #if (BOOT_IMAGE_NUMBER > 1)
 #define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
 #else
@@ -97,28 +96,28 @@
 
 static char bs_obuf[BOOT_SERIAL_OUT_MAX];
 
-static int bs_cbor_writer(struct cbor_encoder_writer *, const char *data,
-  int len);
 static void boot_serial_output(void);
 
-static struct cbor_encoder_writer bs_writer = {
-    .write = bs_cbor_writer
+static cbor_state_backups_t dummy_backups;
+static cbor_state_t cbor_state = {
+    .backups = &dummy_backups
 };
-static CborEncoder bs_root;
-static CborEncoder bs_rsp;
 
-int
-bs_cbor_writer(struct cbor_encoder_writer *cew, const char *data, int len)
-{
-    if (cew->bytes_written + len > sizeof(bs_obuf)) {
-        return CborErrorOutOfMemory;
-    }
-
-    memcpy(&bs_obuf[cew->bytes_written], data, len);
-    cew->bytes_written += len;
-
-    return 0;
-}
+/**
+ * Function that processes MGMT_GROUP_ID_PERUSER mcumgr group and may be
+ * used to process any groups that have not been processed by generic boot
+ * serial implementation.
+ *
+ * @param[in] hdr -- the decoded header of mcumgr message;
+ * @param[in] buffer -- buffer with first mcumgr message;
+ * @param[in] len -- length of of data in buffer;
+ * @param[out] *cs -- object with encoded response.
+ *
+ * @return 0 on success; non-0 error code otherwise.
+ */
+extern int bs_peruser_system_specific(const struct nmgr_hdr *hdr,
+                                      const char *buffer,
+                                      int len, cbor_state_t *cs);
 
 /*
  * Convert version into string without use of snprintf().
@@ -172,17 +171,15 @@
 static void
 bs_list(char *buf, int len)
 {
-    CborEncoder images;
-    CborEncoder image;
     struct image_header hdr;
     uint8_t tmpbuf[64];
-    int slot, area_id;
+    uint32_t slot, area_id;
     const struct flash_area *fap;
     uint8_t image_index;
 
-    cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
-    cbor_encode_text_stringz(&bs_rsp, "images");
-    cbor_encoder_create_array(&bs_rsp, &images, CborIndefiniteLength);
+    map_start_encode(&cbor_state, 1);
+    tstrx_put(&cbor_state, "images");
+    list_start_encode(&cbor_state, 5);
     image_index = 0;
     IMAGES_ITER(image_index) {
         for (slot = 0; slot < 2; slot++) {
@@ -191,34 +188,51 @@
                 continue;
             }
 
-            flash_area_read(fap, 0, &hdr, sizeof(hdr));
-
-            if (hdr.ih_magic != IMAGE_MAGIC ||
-              bootutil_img_validate(NULL, 0, &hdr, fap, tmpbuf, sizeof(tmpbuf),
-                                    NULL, 0, NULL)) {
-                flash_area_close(fap);
-                continue;
+            int rc = BOOT_HOOK_CALL(boot_read_image_header_hook,
+                                    BOOT_HOOK_REGULAR, image_index, slot, &hdr);
+            if (rc == BOOT_HOOK_REGULAR)
+            {
+                flash_area_read(fap, 0, &hdr, sizeof(hdr));
             }
+
+            fih_int fih_rc = FIH_FAILURE;
+
+            if (hdr.ih_magic == IMAGE_MAGIC)
+            {
+                BOOT_HOOK_CALL_FIH(boot_image_check_hook,
+                                   fih_int_encode(BOOT_HOOK_REGULAR),
+                                   fih_rc, image_index, slot);
+                if (fih_eq(fih_rc, BOOT_HOOK_REGULAR))
+                {
+                    FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, &hdr, fap, tmpbuf, sizeof(tmpbuf),
+                                    NULL, 0, NULL);
+                }
+            }
+
             flash_area_close(fap);
 
-            cbor_encoder_create_map(&images, &image, CborIndefiniteLength);
+            if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+                continue;
+            }
+
+            map_start_encode(&cbor_state, 20);
 
 #if (BOOT_IMAGE_NUMBER > 1)
-            cbor_encode_text_stringz(&image, "image");
-            cbor_encode_int(&image, image_index);
+            tstrx_put(&cbor_state, "image");
+            uintx32_put(&cbor_state, image_index);
 #endif
 
-            cbor_encode_text_stringz(&image, "slot");
-            cbor_encode_int(&image, slot);
-            cbor_encode_text_stringz(&image, "version");
+            tstrx_put(&cbor_state, "slot");
+            uintx32_put(&cbor_state, slot);
+            tstrx_put(&cbor_state, "version");
 
             bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
-            cbor_encode_text_stringz(&image, (char *)tmpbuf);
-            cbor_encoder_close_container(&images, &image);
+            tstrx_put_term(&cbor_state, (char *)tmpbuf);
+            map_end_encode(&cbor_state, 20);
         }
     }
-    cbor_encoder_close_container(&bs_rsp, &images);
-    cbor_encoder_close_container(&bs_root, &bs_rsp);
+    list_end_encode(&cbor_state, 5);
+    map_end_encode(&cbor_state, 1);
     boot_serial_output();
 }
 
@@ -229,15 +243,15 @@
 bs_upload(char *buf, int len)
 {
     const uint8_t *img_data = NULL;
-    long long int off = UINT_MAX;
+    long long int off = UINT64_MAX;
     size_t img_blen = 0;
     uint8_t rem_bytes;
-    long long int data_len = UINT_MAX;
+    long long int data_len = UINT64_MAX;
     int img_num;
     size_t slen;
     const struct flash_area *fap = NULL;
     int rc;
-#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
+#ifdef MCUBOOT_ERASE_PROGRESSIVELY
     static off_t off_last = -1;
     struct flash_sector sector;
 #endif
@@ -254,13 +268,16 @@
      * }
      */
 
-    Upload_t upload;
-    if (!cbor_decode_Upload((const uint8_t *)buf, len, &upload)) {
+    struct Upload upload;
+    uint32_t decoded_len;
+    bool result = cbor_decode_Upload((const uint8_t *)buf, len, &upload, &decoded_len);
+
+    if (!result || (len != decoded_len)) {
         goto out_invalid_data;
     }
 
     for (int i = 0; i < upload._Upload_members_count; i++) {
-        _Member_t *member = &upload._Upload_members[i];
+        struct Member_ *member = &upload._Upload_members[i];
         switch(member->_Member_choice) {
             case _Member_image:
                 img_num = member->_Member_image;
@@ -283,14 +300,18 @@
         }
     }
 
-    if (off == UINT_MAX || img_data == NULL) {
+    if (off == UINT64_MAX || img_data == NULL) {
         /*
          * Offset must be set in every block.
          */
         goto out_invalid_data;
     }
 
+#if !defined(MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD)
     rc = flash_area_open(flash_area_id_from_multi_image_slot(img_num, 0), &fap);
+#else
+    rc = flash_area_open(flash_area_id_from_direct_image(img_num), &fap);
+#endif
     if (rc) {
         rc = MGMT_ERR_EINVAL;
         goto out;
@@ -298,11 +319,11 @@
 
     if (off == 0) {
         curr_off = 0;
-        if (data_len > fap->fa_size) {
+        if (data_len > flash_area_get_size(fap)) {
             goto out_invalid_data;
         }
-#ifndef CONFIG_BOOT_ERASE_PROGRESSIVELY
-        rc = flash_area_erase(fap, 0, fap->fa_size);
+#ifndef MCUBOOT_ERASE_PROGRESSIVELY
+        rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
         if (rc) {
             goto out_invalid_data;
         }
@@ -326,16 +347,17 @@
         rem_bytes = 0;
     }
 
-#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
+#ifdef MCUBOOT_ERASE_PROGRESSIVELY
     rc = flash_area_sector_from_off(curr_off + img_blen, &sector);
     if (rc) {
         BOOT_LOG_ERR("Unable to determine flash sector size");
         goto out;
     }
-    if (off_last != sector.fs_off) {
-        off_last = sector.fs_off;
-        BOOT_LOG_INF("Erasing sector at offset 0x%x", sector.fs_off);
-        rc = flash_area_erase(fap, sector.fs_off, sector.fs_size);
+    if (off_last != flash_sector_get_off(&sector)) {
+        off_last = flash_sector_get_off(&sector);
+        BOOT_LOG_INF("Erasing sector at offset 0x%x", flash_sector_get_off(&sector));
+        rc = flash_area_erase(fap, flash_sector_get_off(&sector),
+                              flash_sector_get_size(&sector));
         if (rc) {
             BOOT_LOG_ERR("Error %d while erasing sector", rc);
             goto out;
@@ -372,8 +394,8 @@
 
     if (rc == 0) {
         curr_off += img_blen;
-#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
         if (curr_off == img_size) {
+#ifdef MCUBOOT_ERASE_PROGRESSIVELY
             /* get the last sector offset */
             rc = flash_area_sector_from_off(boot_status_off(fap), &sector);
             if (rc) {
@@ -383,16 +405,24 @@
             }
             /* Assure that sector for image trailer was erased. */
             /* Check whether it was erased during previous upload. */
-            if (off_last < sector.fs_off) {
-                BOOT_LOG_INF("Erasing sector at offset 0x%x", sector.fs_off);
-                rc = flash_area_erase(fap, sector.fs_off, sector.fs_size);
+            if (off_last < flash_sector_get_off(&sector)) {
+                BOOT_LOG_INF("Erasing sector at offset 0x%x",
+                             flash_sector_get_off(&sector));
+                rc = flash_area_erase(fap, flash_sector_get_off(&sector),
+                                      flash_sector_get_size(&sector));
                 if (rc) {
                     BOOT_LOG_ERR("Error %d while erasing sector", rc);
                     goto out;
                 }
             }
-        }
 #endif
+            rc = BOOT_HOOK_CALL(boot_serial_uploaded_hook, 0, img_num, fap,
+                                img_size);
+            if (rc) {
+                BOOT_LOG_ERR("Error %d post upload hook", rc);
+                goto out;
+            }
+        }
     } else {
     out_invalid_data:
         rc = MGMT_ERR_EINVAL;
@@ -400,14 +430,14 @@
 
 out:
     BOOT_LOG_INF("RX: 0x%x", rc);
-    cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
-    cbor_encode_text_stringz(&bs_rsp, "rc");
-    cbor_encode_int(&bs_rsp, rc);
+    map_start_encode(&cbor_state, 10);
+    tstrx_put(&cbor_state, "rc");
+    uintx32_put(&cbor_state, rc);
     if (rc == 0) {
-        cbor_encode_text_stringz(&bs_rsp, "off");
-        cbor_encode_uint(&bs_rsp, curr_off);
+        tstrx_put(&cbor_state, "off");
+        uintx32_put(&cbor_state, curr_off);
     }
-    cbor_encoder_close_container(&bs_root, &bs_rsp);
+    map_end_encode(&cbor_state, 10);
 
     boot_serial_output();
     flash_area_close(fap);
@@ -419,10 +449,10 @@
 static void
 bs_empty_rsp(char *buf, int len)
 {
-    cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
-    cbor_encode_text_stringz(&bs_rsp, "rc");
-    cbor_encode_int(&bs_rsp, 0);
-    cbor_encoder_close_container(&bs_root, &bs_rsp);
+    map_start_encode(&cbor_state, 10);
+    tstrx_put(&cbor_state, "rc");
+    uintx32_put(&cbor_state, 0);
+    map_end_encode(&cbor_state, 10);
     boot_serial_output();
 }
 
@@ -436,7 +466,11 @@
     bs_empty_rsp(buf, len);
 
 #ifdef __ZEPHYR__
+#ifdef CONFIG_MULTITHREADING
     k_sleep(K_MSEC(250));
+#else
+    k_busy_wait(250000);
+#endif
     sys_reboot(SYS_REBOOT_COLD);
 #else
     os_cputime_delay_usecs(250000);
@@ -465,8 +499,9 @@
     buf += sizeof(*hdr);
     len -= sizeof(*hdr);
 
-    bs_writer.bytes_written = 0;
-    cbor_encoder_init(&bs_root, &bs_writer, 0);
+    cbor_state.payload_mut = (uint8_t *)bs_obuf;
+    cbor_state.payload_end = (const uint8_t *)bs_obuf
+                             + sizeof(bs_obuf);
 
     /*
      * Limited support for commands.
@@ -494,6 +529,10 @@
         default:
             break;
         }
+    } else if (MCUBOOT_PERUSER_MGMT_GROUP_ENABLED == 1) {
+        if (bs_peruser_system_specific(hdr, buf, len, &cbor_state) == 0) {
+            boot_serial_output();
+        }
     }
 }
 
@@ -509,7 +548,7 @@
     char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
 
     data = bs_obuf;
-    len = bs_writer.bytes_written;
+    len = (uint32_t)cbor_state.payload_mut - (uint32_t)bs_obuf;
 
     bs_hdr->nh_op++;
     bs_hdr->nh_flags = 0;
@@ -624,6 +663,7 @@
 
     off = 0;
     while (1) {
+        MCUBOOT_CPU_IDLE();
         rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
         if (rc <= 0 && !full_line) {
             continue;
diff --git a/boot/boot_serial/src/boot_serial_priv.h b/boot/boot_serial/src/boot_serial_priv.h
index 9275f3f..5e0211c 100644
--- a/boot/boot_serial/src/boot_serial_priv.h
+++ b/boot/boot_serial/src/boot_serial_priv.h
@@ -36,13 +36,17 @@
 /*
  * From newtmgr.h
  */
+#define MGMT_ERR_OK             0
+#define MGMT_ERR_EUNKNOWN       2
 #define MGMT_ERR_EINVAL         3
+#define MGMT_ERR_ENOTSUP        8
 
 #define NMGR_OP_READ            0
 #define NMGR_OP_WRITE           2
 
 #define MGMT_GROUP_ID_DEFAULT   0
 #define MGMT_GROUP_ID_IMAGE     1
+#define MGMT_GROUP_ID_PERUSER  64
 
 #define NMGR_ID_CONS_ECHO_CTRL  1
 #define NMGR_ID_RESET           5
@@ -65,6 +69,19 @@
 void boot_serial_input(char *buf, int len);
 extern const struct boot_uart_funcs *boot_uf;
 
+/**
+ * @brief Selects direct image to upload according to the "image"
+ * parameter of the mcumgr update frame.
+ *
+ * @param[in] image_id  the value of the "image" parameter of the
+ *                      mcumgr update frame to be translated.
+ *
+ * @return flash area ID for the image if defined;
+ *         -EINVAL when flash area for given image number has not been
+ *         defined.
+ */
+extern int flash_area_id_from_direct_image(int image_id);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boot/boot_serial/src/cbor_common.c b/boot/boot_serial/src/cbor_common.c
new file mode 100644
index 0000000..8a4cd9c
--- /dev/null
+++ b/boot/boot_serial/src/cbor_common.c
@@ -0,0 +1,125 @@
+/*
+ * This file has been copied from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "cbor_common.h"
+
+_Static_assert((sizeof(size_t) == sizeof(void *)),
+	"This code needs size_t to be the same length as pointers.");
+
+bool new_backup(cbor_state_t *state, uint32_t new_elem_count)
+{
+	if ((state->backups->current_backup + 1)
+		>= state->backups->num_backups) {
+		FAIL();
+	}
+
+	uint32_t i = ++(state->backups->current_backup);
+	memcpy(&state->backups->backup_list[i], state,
+		sizeof(cbor_state_t));
+
+	state->elem_count = new_elem_count;
+
+	return true;
+}
+
+
+bool restore_backup(cbor_state_t *state, uint32_t flags,
+		uint32_t max_elem_count)
+{
+	const uint8_t *payload = state->payload;
+	const uint32_t elem_count = state->elem_count;
+
+	if (state->backups->current_backup == 0) {
+		FAIL();
+	}
+
+	if (flags & FLAG_RESTORE) {
+		uint32_t i = state->backups->current_backup;
+
+		memcpy(state, &state->backups->backup_list[i],
+			sizeof(cbor_state_t));
+	}
+
+	if (flags & FLAG_DISCARD) {
+		state->backups->current_backup--;
+	}
+
+	if (elem_count > max_elem_count) {
+		cbor_print("elem_count: %d (expected max %d)\r\n",
+			elem_count, max_elem_count);
+		FAIL();
+	}
+
+	if (flags & FLAG_TRANSFER_PAYLOAD) {
+		state->payload = payload;
+	}
+
+	return true;
+}
+
+
+bool union_start_code(cbor_state_t *state)
+{
+	if (!new_backup(state, state->elem_count)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+bool union_elem_code(cbor_state_t *state)
+{
+	if (!restore_backup(state, FLAG_RESTORE, state->elem_count)) {
+		FAIL();
+	}
+	return true;
+}
+
+bool union_end_code(cbor_state_t *state)
+{
+	if (!restore_backup(state, FLAG_DISCARD, state->elem_count)) {
+		FAIL();
+	}
+	return true;
+}
+
+bool entry_function(const uint8_t *payload, uint32_t payload_len,
+		const void *struct_ptr, uint32_t *payload_len_out,
+		cbor_encoder_t func, uint32_t elem_count, uint32_t num_backups)
+{
+	cbor_state_t state = {
+		.payload = payload,
+		.payload_end = payload + payload_len,
+		.elem_count = elem_count,
+	};
+
+	cbor_state_t state_backups[num_backups + 1];
+
+	cbor_state_backups_t backups = {
+		.backup_list = state_backups,
+		.current_backup = 0,
+		.num_backups = num_backups + 1,
+	};
+
+	state.backups = &backups;
+
+	bool result = func(&state, struct_ptr);
+
+	if (result && (payload_len_out != NULL)) {
+		*payload_len_out = MIN(payload_len,
+				(size_t)state.payload - (size_t)payload);
+	}
+	return result;
+}
diff --git a/boot/boot_serial/src/cbor_common.h b/boot/boot_serial/src/cbor_common.h
new file mode 100644
index 0000000..e652908
--- /dev/null
+++ b/boot/boot_serial/src/cbor_common.h
@@ -0,0 +1,145 @@
+/*
+ * This file has been copied from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef CBOR_COMMON_H__
+#define CBOR_COMMON_H__
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+
+/** Convenience type that allows pointing to strings directly inside the payload
+ *  without the need to copy out.
+ */
+typedef struct
+{
+	const uint8_t *value;
+	uint32_t len;
+} cbor_string_type_t;
+
+#ifdef CDDL_CBOR_VERBOSE
+#include <sys/printk.h>
+#define cbor_trace() (printk("bytes left: %d, byte: 0x%x, elem_count: 0x%zx, %s:%d\n",\
+	(uint32_t)state->payload_end - (uint32_t)state->payload, *state->payload, state->elem_count,\
+	__FILE__, __LINE__))
+#define cbor_assert(expr, ...) \
+do { \
+	if (!(expr)) { \
+		printk("ASSERTION \n  \"" #expr \
+			"\"\nfailed at %s:%d with message:\n  ", \
+			__FILE__, __LINE__); \
+		printk(__VA_ARGS__);\
+		return false; \
+	} \
+} while(0)
+#define cbor_print(...) printk(__VA_ARGS__)
+#else
+#define cbor_trace() ((void)state)
+#define cbor_assert(...)
+#define cbor_print(...)
+#endif
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+
+struct cbor_state_backups_s;
+
+typedef struct cbor_state_backups_s cbor_state_backups_t;
+
+typedef struct{
+union {
+	uint8_t *payload_mut;
+	uint8_t const *payload; /**< The current place in the payload. Will be
+	                             updated when an element is correctly
+	                             processed. */
+};
+	uint8_t const *payload_bak; /**< Temporary backup of payload. */
+	uint32_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. */
+	cbor_state_backups_t *backups;
+} cbor_state_t;
+
+struct cbor_state_backups_s{
+	cbor_state_t *backup_list;
+	uint32_t current_backup;
+	uint32_t num_backups;
+};
+
+/** Function pointer type used with multi_decode.
+ *
+ * This type is compatible with all decoding functions here and in the generated
+ * code, except for multi_decode.
+ */
+typedef bool(cbor_encoder_t)(cbor_state_t *, const void *);
+typedef bool(cbor_decoder_t)(cbor_state_t *, void *);
+
+/** Enumeration representing the major types available in CBOR.
+ *
+ * The major type is represented in the 3 first bits of the header byte.
+ */
+typedef enum
+{
+	CBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer
+	CBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer
+	CBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String
+	CBOR_MAJOR_TYPE_TSTR = 3, ///! Text String
+	CBOR_MAJOR_TYPE_LIST = 4, ///! List
+	CBOR_MAJOR_TYPE_MAP  = 5, ///! Map
+	CBOR_MAJOR_TYPE_TAG  = 6, ///! Semantic Tag
+	CBOR_MAJOR_TYPE_PRIM = 7, ///! Primitive Type
+} cbor_major_type_t;
+
+/** Shorthand macro to check if a result is within min/max constraints.
+ */
+#define PTR_VALUE_IN_RANGE(type, res, min, max) \
+		(((min == NULL) || (*(type *)res >= *(type *)min)) \
+		&& ((max == NULL) || (*(type *)res <= *(type *)max)))
+
+#define FAIL() \
+do {\
+	cbor_trace(); \
+	return false; \
+} while(0)
+
+
+#define VALUE_IN_HEADER 23 /**! For values below this, the value is encoded
+                                directly in the header. */
+
+#define BOOL_TO_PRIM 20 ///! In CBOR, false/true have the values 20/21
+
+#define FLAG_RESTORE 1UL
+#define FLAG_DISCARD 2UL
+#define FLAG_TRANSFER_PAYLOAD 4UL
+
+bool new_backup(cbor_state_t *state, uint32_t new_elem_count);
+
+bool restore_backup(cbor_state_t *state, uint32_t flags,
+		uint32_t max_elem_count);
+
+bool union_start_code(cbor_state_t *state);
+
+bool union_elem_code(cbor_state_t *state);
+
+bool union_end_code(cbor_state_t *state);
+
+bool entry_function(const uint8_t *payload, uint32_t payload_len,
+		const void *struct_ptr, uint32_t *payload_len_out,
+		cbor_encoder_t func, uint32_t elem_count, uint32_t num_backups);
+
+#endif /* CBOR_COMMON_H__ */
diff --git a/boot/boot_serial/src/cbor_decode.c b/boot/boot_serial/src/cbor_decode.c
index 9d27bbb..9707729 100644
--- a/boot/boot_serial/src/cbor_decode.c
+++ b/boot/boot_serial/src/cbor_decode.c
@@ -1,6 +1,6 @@
 /*
- * This file has been copied from the cddl_gen submodule.
- * Commit 9d911cf0c7c9f13b5a9fdd5ed6c1012df21e5576
+ * This file has been copied from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
  */
 
 /*
@@ -14,22 +14,8 @@
 #include <stddef.h>
 #include <string.h>
 #include "cbor_decode.h"
+#include "cbor_common.h"
 
-/** Enumeration representing the major types available in CBOR.
- *
- * The major type is represented in the 3 first bits of the header byte.
- */
-typedef enum
-{
-	CBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer
-	CBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer
-	CBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String
-	CBOR_MAJOR_TYPE_TSTR = 3, ///! Text String
-	CBOR_MAJOR_TYPE_LIST = 4, ///! List
-	CBOR_MAJOR_TYPE_MAP  = 5, ///! Map
-	CBOR_MAJOR_TYPE_TAG  = 6, ///! Semantic Tag
-	CBOR_MAJOR_TYPE_PRIM = 7, ///! Primitive Type
-} cbor_major_type_t;
 
 /** Return value length from additional value.
  */
@@ -52,122 +38,126 @@
 /** Extract the additional info, i.e. the last 5 bits of the header byte. */
 #define ADDITIONAL(header_byte) ((header_byte) & 0x1F)
 
-/** Shorthand macro to check if a result is within min/max constraints.
- */
-#define PTR_VALUE_IN_RANGE(type, p_res, p_min, p_max) \
-		(((p_min == NULL) || (*(type *)p_res >= *(type *)p_min)) \
-		&& ((p_max == NULL) || (*(type *)p_res <= *(type *)p_max)))
-
-#define FAIL() \
-do {\
-	cbor_decode_trace(); \
-	return false; \
-} while(0)
 
 #define FAIL_AND_DECR_IF(expr) \
 do {\
 	if (expr) { \
-		(p_state->p_payload)--; \
+		(state->payload)--; \
 		FAIL(); \
 	} \
 } while(0)
 
-#define VALUE_IN_HEADER 23 /**! For values below this, the value is encoded
-                                directly in the header. */
+#define FAIL_IF(expr) \
+do {\
+	if (expr) { \
+		FAIL(); \
+	} \
+} while(0)
 
-#define BOOL_TO_PRIM 20 ///! In CBOR, false/true have the values 20/21
+
+#define FAIL_RESTORE() \
+	state->payload = state->payload_bak; \
+	state->elem_count++; \
+	FAIL()
 
 /** Get a single value.
  *
- * @details @p pp_payload must point to the header byte. This function will
+ * @details @p ppayload must point to the header byte. This function will
  *          retrieve the value (either from within the additional info, or from
  *          the subsequent bytes) and return it in the result. The result can
  *          have arbitrary length.
  *
  *          The function will also validate
  *           - Min/max constraints on the value.
- *           - That @p pp_payload doesn't overrun past @p p_payload_end.
- *           - That @p p_elem_count has not been exhausted.
+ *           - That @p payload doesn't overrun past @p payload_end.
+ *           - That @p elem_count has not been exhausted.
  *
- *          @p pp_payload and @p p_elem_count are updated if the function
+ *          @p ppayload and @p elem_count are updated if the function
  *          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).
  */
-static bool value_extract(cbor_decode_state_t * p_state,
-		void * const p_result, size_t result_len)
+static bool value_extract(cbor_state_t *state,
+		void *const result, uint32_t result_len)
 {
-	cbor_decode_trace();
-	cbor_decode_assert(result_len != 0, "0-length result not supported.\n");
+	cbor_trace();
+	cbor_assert(result_len != 0, "0-length result not supported.\n");
+	cbor_assert(result != NULL, NULL);
 
-	FAIL_AND_DECR_IF(p_state->elem_count == 0);
-	FAIL_AND_DECR_IF(p_state->p_payload >= p_state->p_payload_end);
+	FAIL_IF((state->elem_count == 0) \
+		|| (state->payload >= state->payload_end));
 
-	uint8_t *p_u8_result  = (uint8_t *)p_result;
-	uint8_t additional = ADDITIONAL(*p_state->p_payload);
+	uint8_t *u8_result  = (uint8_t *)result;
+	uint8_t additional = ADDITIONAL(*state->payload);
 
-	(p_state->p_payload)++;
+	state->payload_bak = state->payload;
+	(state->payload)++;
 
-	memset(p_result, 0, result_len);
+	memset(result, 0, result_len);
 	if (additional <= VALUE_IN_HEADER) {
 #ifdef CONFIG_BIG_ENDIAN
-		p_u8_result[result_len - 1] = additional;
+		u8_result[result_len - 1] = additional;
 #else
-		p_u8_result[0] = additional;
+		u8_result[0] = additional;
 #endif /* CONFIG_BIG_ENDIAN */
 	} else {
 		uint32_t len = additional_len(additional);
 
 		FAIL_AND_DECR_IF(len > result_len);
-		FAIL_AND_DECR_IF((p_state->p_payload + len)
-				> p_state->p_payload_end);
+		FAIL_AND_DECR_IF((state->payload + len)
+				> state->payload_end);
 
 #ifdef CONFIG_BIG_ENDIAN
-		memcpy(&p_u8_result[result_len - len], p_state->p_payload, len);
+		memcpy(&u8_result[result_len - len], state->payload, len);
 #else
 		for (uint32_t i = 0; i < len; i++) {
-			p_u8_result[i] = (p_state->p_payload)[len - i - 1];
+			u8_result[i] = (state->payload)[len - i - 1];
 		}
 #endif /* CONFIG_BIG_ENDIAN */
 
-		(p_state->p_payload) += len;
+		(state->payload) += len;
 	}
 
-	(p_state->elem_count)--;
+	(state->elem_count)--;
 	return true;
 }
 
 
-static bool int32_decode(cbor_decode_state_t * p_state,
-		int32_t *p_result, void *p_min_value, void *p_max_value)
+static bool int32_decode(cbor_state_t *state, int32_t *result)
 {
-	uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
+	uint32_t uint_result;
+	int32_t int_result;
 
-	if (!value_extract(p_state, p_result, 4)) {
+	if (!value_extract(state, &uint_result, 4)) {
 		FAIL();
 	}
-	if (*p_result < 0) {
+
+	cbor_print("uintval: %u\r\n", uint_result);
+	if (uint_result >= (1 << (8*sizeof(uint_result)-1))) {
 		/* Value is too large to fit in a signed integer. */
-		FAIL();
+		FAIL_RESTORE();
 	}
 
 	if (major_type == CBOR_MAJOR_TYPE_NINT) {
-		// Convert from CBOR's representation.
-		*p_result = 1 - *p_result;
+		/* Convert from CBOR's representation. */
+		int_result = -1 - uint_result;
+	} else {
+		int_result = uint_result;
 	}
-	if (!PTR_VALUE_IN_RANGE(int32_t, p_result, p_min_value, p_max_value)) {
-		FAIL();
-	}
-	cbor_decode_print("val: %d\r\n", *p_result);
+
+	cbor_print("val: %d\r\n", int_result);
+	*result = int_result;
 	return true;
 }
 
 
-bool intx32_decode(cbor_decode_state_t * p_state,
-		int32_t *p_result, void *p_min_value, void *p_max_value)
+bool intx32_decode(cbor_state_t *state, int32_t *result)
 {
-	uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
 
 	if (major_type != CBOR_MAJOR_TYPE_PINT
 		&& major_type != CBOR_MAJOR_TYPE_NINT) {
@@ -175,203 +165,384 @@
 		FAIL();
 	}
 
-	if (!int32_decode(p_state,
-				p_result, p_min_value,
-				p_max_value)){
+	if (!int32_decode(state, result)) {
 		FAIL();
 	}
 	return true;
 }
 
-
-static bool uint32_decode(cbor_decode_state_t * p_state,
-		void *p_result, void *p_min_value, void *p_max_value)
+bool intx32_expect(cbor_state_t *state, int32_t result)
 {
-	if (!value_extract(p_state, p_result, 4)) {
+	int32_t value;
+
+	if (!intx32_decode(state, &value)) {
 		FAIL();
 	}
 
-	if (!PTR_VALUE_IN_RANGE(uint32_t, p_result, p_min_value, p_max_value)) {
-		FAIL();
+	if (value != result) {
+		cbor_print("%d != %d\r\n", value, result);
+		FAIL_RESTORE();
 	}
-	cbor_decode_print("val: %u\r\n", *(uint32_t *)p_result);
 	return true;
 }
 
 
-bool uintx32_decode(cbor_decode_state_t * p_state,
-		uint32_t *p_result, void *p_min_value, void *p_max_value)
+static bool uint32_decode(cbor_state_t *state, uint32_t *result)
 {
-	uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+	if (!value_extract(state, result, 4)) {
+		FAIL();
+	}
+
+	return true;
+}
+
+
+bool uintx32_decode(cbor_state_t *state, uint32_t *result)
+{
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
 
 	if (major_type != CBOR_MAJOR_TYPE_PINT) {
 		/* Value to be read doesn't have the right type. */
 		FAIL();
 	}
-	if (!uint32_decode(p_state, p_result, p_min_value, p_max_value)){
+	if (!uint32_decode(state, result)) {
 		FAIL();
 	}
 	return true;
 }
 
-
-static bool size_decode(cbor_decode_state_t * p_state,
-		size_t *p_result, size_t *p_min_value, size_t *p_max_value)
+bool uintx32_expect(cbor_state_t *state, uint32_t result)
 {
-	_Static_assert((sizeof(size_t) == sizeof(uint32_t)),
-			"This code needs size_t to be 4 bytes long.");
-	return uint32_decode(p_state,
-			p_result, p_min_value, p_max_value);
+	uint32_t value;
+
+	if (!uintx32_decode(state, &value)) {
+		FAIL();
+	}
+	if (value != result) {
+		cbor_print("%u != %u\r\n", value, result);
+		FAIL_RESTORE();
+	}
+	return true;
+}
+
+bool uintx32_expect_union(cbor_state_t *state, uint32_t result)
+{
+	union_elem_code(state);
+	return uintx32_expect(state, result);
 }
 
 
-bool strx_start_decode(cbor_decode_state_t * p_state,
-		cbor_string_type_t *p_result, void *p_min_len, void *p_max_len)
+static bool strx_start_decode(cbor_state_t *state,
+		cbor_string_type_t *result, cbor_major_type_t exp_major_type)
 {
-	uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
-	cbor_string_type_t *p_str_result = (cbor_string_type_t *)p_result;
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
 
-	if (major_type != CBOR_MAJOR_TYPE_BSTR
-		&& major_type != CBOR_MAJOR_TYPE_TSTR) {
-		/* Value to be read doesn't have the right type. */
+	if (major_type != exp_major_type) {
 		FAIL();
 	}
-	if (!size_decode(p_state,
-			&p_str_result->len, (size_t *)p_min_len,
-			(size_t *)p_max_len)) {
+
+	if (!uint32_decode(state, &result->len)) {
 		FAIL();
 	}
-	p_str_result->value = p_state->p_payload;
+
+	if (result->len > (state->payload_end - state->payload)) {
+		cbor_print("error: 0x%x > 0x%x\r\n",
+		(uint32_t)result->len,
+		(uint32_t)(state->payload_end - state->payload));
+		FAIL_RESTORE();
+	}
+
+	result->value = state->payload;
+	return true;
+}
+
+bool bstrx_cbor_start_decode(cbor_state_t *state, cbor_string_type_t *result)
+{
+	if(!strx_start_decode(state, result, CBOR_MAJOR_TYPE_BSTR)) {
+		FAIL();
+	}
+
+	if (!new_backup(state, 0xFFFFFFFF)) {
+		FAIL_RESTORE();
+	}
+
+	/* Overflow is checked in strx_start_decode() */
+	state->payload_end = result->value + result->len;
+	return true;
+}
+
+bool bstrx_cbor_end_decode(cbor_state_t *state)
+{
+	if (state->payload != state->payload_end) {
+		FAIL();
+	}
+	if (!restore_backup(state,
+			FLAG_RESTORE | FLAG_DISCARD | FLAG_TRANSFER_PAYLOAD,
+			0xFFFFFFFF)) {
+		FAIL();
+	}
+
 	return true;
 }
 
 
-bool strx_decode(cbor_decode_state_t * p_state,
-		cbor_string_type_t *p_result, void *p_min_len, void *p_max_len)
+bool strx_decode(cbor_state_t *state, cbor_string_type_t *result,
+		cbor_major_type_t exp_major_type)
 {
-	if (!strx_start_decode(p_state, p_result,
-				p_min_len, p_max_len)) {
-		return false;
+	if (!strx_start_decode(state, result, exp_major_type)) {
+		FAIL();
 	}
-	(p_state->p_payload) += p_result->len;
+
+	/* Overflow is checked in strx_start_decode() */
+	(state->payload) += result->len;
 	return true;
 }
 
 
-bool list_start_decode(cbor_decode_state_t * p_state,
-		size_t *p_result, size_t min_num, size_t max_num)
+bool strx_expect(cbor_state_t *state, cbor_string_type_t *result,
+		cbor_major_type_t exp_major_type)
 {
-	uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+	cbor_string_type_t tmp_result;
 
-	*p_result = p_state->elem_count;
-
-	if (major_type != CBOR_MAJOR_TYPE_LIST
-		&& major_type != CBOR_MAJOR_TYPE_MAP) {
+	if (!strx_decode(state, &tmp_result, exp_major_type)) {
 		FAIL();
 	}
-	if (!uint32_decode(p_state,
-			p_result, &min_num, &max_num)) {
-		FAIL();
+	if ((tmp_result.len != result->len)
+			|| memcmp(result->value, tmp_result.value, tmp_result.len)) {
+		FAIL_RESTORE();
 	}
-	size_t tmp = *p_result;
-	*p_result = p_state->elem_count;
-	p_state->elem_count = major_type == CBOR_MAJOR_TYPE_MAP ? tmp * 2 : tmp;
 	return true;
 }
 
 
-bool primx_decode(cbor_decode_state_t * p_state,
-		uint8_t *p_result, void *p_min_result, void *p_max_result)
+bool bstrx_decode(cbor_state_t *state, cbor_string_type_t *result)
 {
-	uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
-	uint32_t val;
+	return strx_decode(state, result, CBOR_MAJOR_TYPE_BSTR);
+}
+
+
+bool bstrx_expect(cbor_state_t *state, cbor_string_type_t *result)
+{
+	return strx_expect(state, result, CBOR_MAJOR_TYPE_BSTR);
+}
+
+
+bool tstrx_decode(cbor_state_t *state, cbor_string_type_t *result)
+{
+	return strx_decode(state, result, CBOR_MAJOR_TYPE_TSTR);
+}
+
+
+bool tstrx_expect(cbor_state_t *state, cbor_string_type_t *result)
+{
+	return strx_expect(state, result, CBOR_MAJOR_TYPE_TSTR);
+}
+
+
+static bool list_map_start_decode(cbor_state_t *state,
+		cbor_major_type_t exp_major_type)
+{
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
+	uint32_t new_elem_count;
+
+	if (major_type != exp_major_type) {
+		FAIL();
+	}
+
+	if (!uint32_decode(state, &new_elem_count)) {
+		FAIL();
+	}
+
+	if (!new_backup(state, new_elem_count)) {
+		FAIL_RESTORE();
+	}
+
+	return true;
+}
+
+
+bool list_start_decode(cbor_state_t *state)
+{
+	return list_map_start_decode(state, CBOR_MAJOR_TYPE_LIST);
+}
+
+
+bool map_start_decode(cbor_state_t *state)
+{
+	bool ret = list_map_start_decode(state, CBOR_MAJOR_TYPE_MAP);
+
+	if (ret) {
+		state->elem_count *= 2;
+	}
+	return ret;
+}
+
+
+bool list_map_end_decode(cbor_state_t *state)
+{
+	if (!restore_backup(state,
+			FLAG_RESTORE | FLAG_DISCARD | FLAG_TRANSFER_PAYLOAD,
+			0)) {
+		FAIL();
+	}
+
+	return true;
+}
+
+
+bool list_end_decode(cbor_state_t *state)
+{
+	return list_map_end_decode(state);
+}
+
+
+bool map_end_decode(cbor_state_t *state)
+{
+	return list_map_end_decode(state);
+}
+
+
+static bool primx_decode(cbor_state_t *state, uint32_t *result)
+{
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
 
 	if (major_type != CBOR_MAJOR_TYPE_PRIM) {
 		/* Value to be read doesn't have the right type. */
 		FAIL();
 	}
-	if (!uint32_decode(p_state,
-			&val, p_min_result, p_max_result)) {
+	if (!uint32_decode(state, result)) {
 		FAIL();
 	}
-	if (p_result != NULL) {
-		*p_result = val;
+	if (*result > 0xFF) {
+		FAIL_RESTORE();
+	}
+	return true;
+}
+
+static bool primx_expect(cbor_state_t *state, uint32_t result)
+{
+	uint32_t value;
+
+	if (!primx_decode(state, &value)) {
+		FAIL();
+	}
+	if (value != result) {
+		FAIL_RESTORE();
 	}
 	return true;
 }
 
 
-bool boolx_decode(cbor_decode_state_t * p_state,
-		bool *p_result, void *p_min_result, void *p_max_result)
+bool nilx_expect(cbor_state_t *state, void *result)
 {
-	uint8_t min_result = *(uint8_t *)p_min_result + BOOL_TO_PRIM;
-	uint8_t max_result = *(uint8_t *)p_max_result + BOOL_TO_PRIM;
-
-	if (!primx_decode(p_state,
-			(uint8_t *)p_result, &min_result, &max_result)) {
+	if (!primx_expect(state, 22)) {
 		FAIL();
 	}
-	(*p_result) -= BOOL_TO_PRIM;
 	return true;
 }
 
 
-bool double_decode(cbor_decode_state_t * p_state,
-		double *p_result, void *p_min_result, void *p_max_result)
+bool boolx_decode(cbor_state_t *state, bool *result)
 {
-	uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+	uint32_t tmp_result;
+
+	if (!primx_decode(state, &tmp_result)) {
+		FAIL();
+	}
+	(*result) = tmp_result - BOOL_TO_PRIM;
+
+	cbor_print("boolval: %u\r\n", *result);
+	return true;
+}
+
+
+bool boolx_expect(cbor_state_t *state, bool result)
+{
+	bool value;
+
+	if (!boolx_decode(state, &value)) {
+		FAIL();
+	}
+	if (value != result) {
+		FAIL_RESTORE();
+	}
+	return true;
+}
+
+
+bool double_decode(cbor_state_t *state, double *result)
+{
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
 
 	if (major_type != CBOR_MAJOR_TYPE_PRIM) {
 		/* Value to be read doesn't have the right type. */
 		FAIL();
 	}
-	if (!value_extract(p_state, p_result,
-			sizeof(*p_result))) {
-		FAIL();
-	}
-
-	if (!PTR_VALUE_IN_RANGE(double, p_result, p_min_result, p_max_result)) {
+	if (!value_extract(state, result,
+			sizeof(*result))) {
 		FAIL();
 	}
 	return true;
 }
 
 
-bool any_decode(cbor_decode_state_t * p_state,
-		void *p_result, void *p_min_result, void *p_max_result)
+bool double_expect(cbor_state_t *state, double *result)
 {
-	cbor_decode_assert(p_result == NULL,
+	double value;
+
+	if (!double_decode(state, &value)) {
+		FAIL();
+	}
+	if (value != *result) {
+		FAIL_RESTORE();
+	}
+	return true;
+}
+
+
+bool any_decode(cbor_state_t *state, void *result)
+{
+	cbor_assert(result == NULL,
 			"'any' type cannot be returned, only skipped.\n");
 
-	uint8_t major_type = MAJOR_TYPE(*p_state->p_payload);
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
 	uint32_t value;
-	size_t num_decode;
-	void *p_null_result = NULL;
-	size_t temp_elem_count;
+	uint32_t num_decode;
+	void *null_result = NULL;
+	uint32_t temp_elem_count;
+	uint8_t const *payload_bak;
 
-	if (!value_extract(p_state, &value, sizeof(value))) {
-		/* Can happen because of p_elem_count (or p_payload_end) */
+	if (!value_extract(state, &value, sizeof(value))) {
+		/* Can happen because of elem_count (or payload_end) */
 		FAIL();
 	}
 
 	switch (major_type) {
 		case CBOR_MAJOR_TYPE_BSTR:
 		case CBOR_MAJOR_TYPE_TSTR:
-			(p_state->p_payload) += value;
+			(state->payload) += value;
 			break;
 		case CBOR_MAJOR_TYPE_MAP:
 			value *= 2; /* Because all members have a key. */
 			/* Fallthrough */
 		case CBOR_MAJOR_TYPE_LIST:
-			temp_elem_count = p_state->elem_count;
-			p_state->elem_count = value;
-			if (!multi_decode(value, value, &num_decode, any_decode,
-					p_state,
-					&p_null_result,	NULL, NULL, 0)) {
-				p_state->elem_count = temp_elem_count;
+			temp_elem_count = state->elem_count;
+			payload_bak = state->payload;
+			state->elem_count = value;
+			if (!multi_decode(value, value, &num_decode,
+					(void *)any_decode, state,
+					&null_result, 0)) {
+				state->elem_count = temp_elem_count;
+				state->payload = payload_bak;
 				FAIL();
 			}
-			p_state->elem_count = temp_elem_count;
+			state->elem_count = temp_elem_count;
 			break;
 		default:
 			/* Do nothing */
@@ -382,36 +553,77 @@
 }
 
 
-bool multi_decode(size_t min_decode,
-		size_t max_decode,
-		size_t *p_num_decode,
-		decoder_t decoder,
-		cbor_decode_state_t * p_state,
-		void *p_result,
-		void *p_min_result,
-		void *p_max_result,
-		size_t result_len)
+bool tag_decode(cbor_state_t *state, uint32_t *result)
 {
-	for (size_t i = 0; i < max_decode; i++) {
-		uint8_t const *p_payload_bak = p_state->p_payload;
-		size_t elem_count_bak = p_state->elem_count;
+	FAIL_IF(state->payload >= state->payload_end);
+	uint8_t major_type = MAJOR_TYPE(*state->payload);
 
-		if (!decoder(p_state,
-				(uint8_t *)p_result + i*result_len,
-				p_min_result,
-				p_max_result)) {
-			*p_num_decode = i;
-			p_state->p_payload = p_payload_bak;
-			p_state->elem_count = elem_count_bak;
+	if (major_type != CBOR_MAJOR_TYPE_TAG) {
+		/* Value to be read doesn't have the right type. */
+		FAIL();
+	}
+	if (!uint32_decode(state, result)) {
+		FAIL();
+	}
+	state->elem_count++;
+	return true;
+}
+
+
+bool tag_expect(cbor_state_t *state, uint32_t result)
+{
+	uint32_t tag_val;
+
+	if (!tag_decode(state, &tag_val)) {
+		FAIL();
+	}
+	if (tag_val != result) {
+		FAIL_RESTORE();
+	}
+	return true;
+}
+
+
+bool multi_decode(uint32_t min_decode,
+		uint32_t max_decode,
+		uint32_t *num_decode,
+		cbor_decoder_t decoder,
+		cbor_state_t *state,
+		void *result,
+		uint32_t result_len)
+{
+	for (uint32_t i = 0; i < max_decode; i++) {
+		uint8_t const *payload_bak = state->payload;
+		uint32_t elem_count_bak = state->elem_count;
+
+		if (!decoder(state,
+				(uint8_t *)result + i*result_len)) {
+			*num_decode = i;
+			state->payload = payload_bak;
+			state->elem_count = elem_count_bak;
 			if (i < min_decode) {
 				FAIL();
 			} else {
-				cbor_decode_print("Found %zu elements.\n", i);
+				cbor_print("Found %zu elements.\n", i);
 			}
 			return true;
 		}
 	}
-	cbor_decode_print("Found %zu elements.\n", max_decode);
-	*p_num_decode = max_decode;
+	cbor_print("Found %zu elements.\n", max_decode);
+	*num_decode = max_decode;
 	return true;
 }
+
+
+bool present_decode(uint32_t *present,
+		cbor_decoder_t decoder,
+		cbor_state_t *state,
+		void *result)
+{
+	uint32_t num_decode;
+	bool retval = multi_decode(0, 1, &num_decode, decoder, state, result, 0);
+	if (retval) {
+		*present = num_decode;
+	}
+	return retval;
+}
diff --git a/boot/boot_serial/src/cbor_decode.h b/boot/boot_serial/src/cbor_decode.h
index cd466cd..5bdc800 100644
--- a/boot/boot_serial/src/cbor_decode.h
+++ b/boot/boot_serial/src/cbor_decode.h
@@ -1,6 +1,6 @@
 /*
- * This file has been copied from the cddl_gen submodule.
- * Commit 9d911cf0c7c9f13b5a9fdd5ed6c1012df21e5576
+ * This file has been copied from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
  */
 
 /*
@@ -9,35 +9,33 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-#ifndef CDDL_CBOR_H__
-#define CDDL_CBOR_H__
+#ifndef CBOR_DECODE_H__
+#define CBOR_DECODE_H__
 #include <stdint.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include "cbor_common.h"
 
 /** The cbor_decode library provides functions for decoding CBOR data elements.
  *
  * This library is primarily meant to be called from code generated by
- * $CDDL_GEN_BASE/scripts/cddl_gen.py
+ * $CDDL_GEN_BASE/cddl_gen/cddl_gen.py script, or its equivalent cddl_gen
+ * command line executable.
  *
  * Some details to notice about this library:
- *  - Integers are all 32 bits (uint32_t and size_t). This means that CBOR's
- *    64 bit values are not supported. This applies to integer types, as well as
- *    lengths for other types.
+ *  - Integers are all 32 bits (uint32_t). This means that CBOR's 64 bit values
+ *    are not supported, even when the code is running on a 64 bit architecture.
+ *    This applies to integer types, as well as lengths for other types.
  *  - Strings are kept in the container type cbor_string_type_t, which is a
  *    pointer and a length.
  *  - When a function returns false, it only means that decoding that particular
  *    value failed. If a value is allowed to take multiple different values,
- *    another decoding function can be called if the first fails. All functions
- *    are designed to reset pp_payload and p_elem_count to their original values
- *    if they return false.
+ *    another decoding function can be called if the first fails.
  *  - There is some type casting going on under the hood to make the code
- *    generator friendly. See especially the decoder_t type which is compatible
+ *    generator friendly. See especially the processor_t type which is compatible
  *    with all functions except multi_decode, but the compiler doesn't "know"
  *    this because they are defined with different pointer types. It also means
  *    any usage of multi_decode must be made with care for function types.
- *  - This library has no function for semantic tags.
- *  - This library doesn't distinguish lists from maps.
  *
  *
  * CBOR's format is described well on Wikipedia
@@ -54,7 +52,11 @@
  *
  * The available major types can be seen in @ref cbor_major_type_t.
  *
- * PINT, NINT, TAG, and PRIM elements have no payload, only Value.
+ * For all types, Values 0-23 are encoded directly in the "Additional info",
+ * meaning that the "Value" field is 0 bytes long. If "Additional info" is 24,
+ * 25, 26, or 27, the "Value" field is 1, 2, 4, or 8 bytes long, respectively.
+ *
+ * Major types PINT, NINT, TAG, and PRIM elements have no payload, only Value.
  * PINT: Interpret the Value as a positive integer.
  * NINT: Interpret the Value as a positive integer, then multiply by -1 and
  *       subtract 1.
@@ -65,7 +67,7 @@
  *       21: "true"
  *       22: "null"
  *       23: "undefined"
- *       >256: Interpret as IEEE 754 float with given precision
+ *       >=0x10000: Interpret as IEEE 754 float with given precision
  *
  * For BSTR, TSTR, LIST, and MAP, the Value describes the length of the payload.
  * For BSTR and TSTR, the length is in bytes, for LIST, the length is in number
@@ -74,148 +76,105 @@
  * For LIST and MAP, sub elements are regular CBOR elements with their own
  * Header, Value and Payload. LISTs and MAPs can be recursively encoded.
  *
- * For all types, Values 0-23 are encoded directly in the "Additional info",
- * meaning that the "Value" field is 0 bytes long. If "Additional info" is 24,
- * 25, 26, or 27, the "Value" field is 1, 2, 4, or 8 bytes long, respectively.
- *
  * The additional info means slightly different things for different major
  * types.
  */
 
-
-/** Convenience type that allows pointing to strings directly inside the payload
- *  without the need to copy out.
- */
-typedef struct
-{
-	const uint8_t *value;
-	size_t len;
-} cbor_string_type_t;
-
-#ifdef CDDL_CBOR_VERBOSE
-#include <sys/printk.h>
-#define cbor_decode_trace() (printk("p_state->p_payload: 0x%x, "\
-	"*p_state->p_payload: 0x%x, p_state->elem_count: 0x%zx, %s:%d\n",\
-	(uint32_t)p_state->p_payload, *p_state->p_payload, p_state->elem_count,\
-	__FILE__, __LINE__))
-#define cbor_decode_assert(expr, ...) \
-do { \
-	if (!(expr)) { \
-		printk("ASSERTION \n  \"" #expr \
-			"\"\nfailed at %s:%d with message:\n  ", \
-			__FILE__, __LINE__); \
-		printk(__VA_ARGS__);\
-		return false; \
-	} \
-} while(0)
-#define cbor_decode_print(...) printk(__VA_ARGS__)
-#else
-#define cbor_decode_trace()
-#define cbor_decode_assert(...)
-#define cbor_decode_print(...)
-#endif
-
-typedef struct {
-	uint8_t const *p_payload;
-	uint8_t const *p_payload_end;
-	size_t elem_count;
-} cbor_decode_state_t;
-
-/** Function pointer type used with multi_decode.
- *
- * This type is compatible with all decoding functions here and in the generated
- * code, except for multi_decode.
- */
-typedef bool(decoder_t)(cbor_decode_state_t *, void *, void *, void *);
-
 /** Decode a PINT/NINT into a int32_t.
  *
- * @param[inout] pp_payload     The current place in the payload. Will be
- *                              updated if the element is correctly decoded.
- * @param[in]    p_payload_end  The end of the payload. This will be checked
- *                              against pp_payload before decoding.
- * @param[inout] p_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 decoding
- *                              decremented if the element is correctly decoded.
- * @param[out]   p_result       Where to place the decoded value.
- * @param[in]    p_min_value    The minimum acceptable value. This is checked
- *                              after decoding, and if the decoded value is
- *                              outside the range, the decoding will fail.
- *                              A NULL value here means there is no restriction.
- * @param[in]    p_max_value    The maximum acceptable value. This is checked
- *                              after decoding, and if the decoded value is
- *                              outside the range, the decoding will fail.
- *                              A NULL value here means there is no restriction.
+ * @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, the value was not within the
- *                acceptable range, or the value was larger than can fit in the
- *                result variable.
+ *                element count was exhausted, or the value was larger than can
+ *                fit in the result variable.
  */
-bool intx32_decode(cbor_decode_state_t * p_state, int32_t *p_result, void *p_min_value, void *p_max_value);
+bool intx32_decode(cbor_state_t *state, int32_t *result);
 
-/** Decode a PINT into a uint32_t.
+/** Expect a PINT/NINT with a certain value. Uses intx32_decode internally.
  *
- * @details See @ref intx32_decode for information about parameters and return
- *          values.
+ * @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 intx32_decode failed or the result doesn't have the
+ *                expected value.
  */
-bool uintx32_decode(cbor_decode_state_t * p_state, uint32_t *p_result, void *p_min_value, void *p_max_value);
+bool intx32_expect(cbor_state_t *state, int32_t result);
 
-/** Decode a BSTR or TSTR, but leave pp_payload pointing at the payload.
- *
- * @details See @ref intx32_decode for information about parameters and return
- *          values. For strings, the value refers to the length of the string.
- */
-bool strx_start_decode(cbor_decode_state_t * p_state, cbor_string_type_t *p_result, void *p_min_len, void *p_max_len);
+/** Decode a PINT. */
+bool uintx32_decode(cbor_state_t *state, uint32_t *result);
+bool uintx32_expect(cbor_state_t *state, uint32_t result);
+bool uintx32_expect_union(cbor_state_t *state, uint32_t result);
 
-/** Decode a BSTR or TSTR, and move pp_payload to after the payload.
+/** Decode and consume a BSTR header.
  *
- * @details See @ref intx32_decode for information about parameters and return
- *          values. For strings, the value refers to the length of the string.
+ * The rest of the string can be decoded as CBOR.
+ * A state backup is created to keep track of the element count.
+ *
+ * @retval true   Header decoded correctly
+ * @retval false  Header decoded incorrectly, or backup failed.
  */
-bool strx_decode(cbor_decode_state_t * p_state, cbor_string_type_t *p_result, void *p_min_len, void *p_max_len);
+bool bstrx_cbor_start_decode(cbor_state_t *state, cbor_string_type_t *result);
 
-/** Decode a LIST or MAP, but leave pp_payload pointing at the payload.
+/** Finalize decoding a CBOR-encoded bstr.
  *
- * @details See @ref intx32_decode for information about parameters and return
- *          values. For lists and maps, the value refers to the number of
- *          elements.
+ * Restore element count from backup.
  */
-bool list_start_decode(cbor_decode_state_t * p_state, size_t *p_result, size_t min_num, size_t max_num);
+bool bstrx_cbor_end_decode(cbor_state_t *state);
 
-/** Decode a primitive value.
- *
- * @details See @ref intx32_decode for information about parameters and return
- *          values.
- */
-bool primx_decode(cbor_decode_state_t * p_state, uint8_t *p_result, void *p_min_result, void *p_max_result);
+/** Decode and consume a BSTR */
+bool bstrx_decode(cbor_state_t *state, cbor_string_type_t *result);
+bool bstrx_expect(cbor_state_t *state, cbor_string_type_t *result);
 
-/** Decode a boolean primitive value.
- *
- * @details See @ref intx32_decode for information about parameters and return
- *          values. The result is translated internally from the primitive
- *          values for true/false (20/21) to 0/1.
- */
-bool boolx_decode(cbor_decode_state_t * p_state, bool *p_result, void *p_min_result, void *p_max_result);
+/** Decode and consume a TSTR */
+bool tstrx_decode(cbor_state_t *state, cbor_string_type_t *result);
+bool tstrx_expect(cbor_state_t *state, cbor_string_type_t *result);
 
-/** Decode a float
+/** Decode and consume a LIST header.
  *
- * @warning This function has not been tested, and likely doesn't work.
+ * The contents of the list can be decoded via subsequent function calls.
+ * A state backup is created to keep track of the element count.
  *
- * @details See @ref intx32_decode for information about parameters and return
- *          values.
+ * @retval true   Header decoded correctly
+ * @retval false  Header decoded incorrectly, or backup failed.
  */
-bool float_decode(cbor_decode_state_t * p_state, double *p_result, void *p_min_result, void *p_max_result);
+bool list_start_decode(cbor_state_t *state);
 
-/** Skip a single element, regardless of type and value.
+/** Decode and consume a MAP header. */
+bool map_start_decode(cbor_state_t *state);
+
+/** Finalize decoding a LIST
  *
- * @details See @ref intx32_decode for information about parameters and return
- *          values. @p p_result, @p p_min_result, and @p p_max_result must be
- *          NULL.
+ * Check that the list had the correct number of elements, and restore previous
+ * element count from backup.
+ *
+ * @retval true   Everything ok.
+ * @retval false  Element count not correct.
  */
-bool any_decode(cbor_decode_state_t * p_state, void *p_result, void *p_min_result, void *p_max_result);
+bool list_end_decode(cbor_state_t *state);
+
+/** Finalize decoding a MAP */
+bool map_end_decode(cbor_state_t *state);
+
+/** Decode a "nil" primitive value. */
+bool nilx_expect(cbor_state_t *state, void *result);
+
+/** Decode a boolean primitive value. */
+bool boolx_decode(cbor_state_t *state, bool *result);
+bool boolx_expect(cbor_state_t *state, bool result);
+
+/** Decode a float */
+bool float_decode(cbor_state_t *state, double *result);
+bool float_expect(cbor_state_t *state, double *result);
+
+/** Skip a single element, regardless of type and value. */
+bool any_decode(cbor_state_t *state, void *result);
+
+/** Decode a tag. */
+bool tag_decode(cbor_state_t *state, uint32_t *result);
+bool tag_expect(cbor_state_t *state, uint32_t result);
 
 /** Decode 0 or more elements with the same type and constraints.
  *
@@ -224,46 +183,52 @@
  *          with length 8, that could be done with:
  *
  *          @code{c}
- *              size_t elem_count = 5;
  *              uint32_t int_min = 0;
  *              uint32_t int_max = 100;
- *              size_t bstr_size = 8;
+ *              uint32_t bstr_size = 8;
  *              uint32_t ints[3];
  *              cbor_string_type_t bstrs[2];
+ *              bool res;
  *
- *              list_start_decode(pp_payload, p_payload_end, &parent_elem_count,
- *                                &elem_count, NULL, NULL);
- *              multi_decode(3, 3, &num_decode, uintx32_decode, pp_payload,
- *                           p_payload_end, ints, &int_min, &int_max, 4);
- *              multi_decode(0, 2, &num_decode, strx_decode, pp_payload,
- *                           p_payload_end, bstrs, &bstr_size, &bstr_size,
+ *              res = list_start_encode(state, 3, 5);
+ *              // check res
+ *              res = multi_encode(3, 3, &num_encode, uintx32_encode, state,
+ *                           ints, &int_min, &int_max, 4);
+ *              // check res
+ *              res = multi_encode(0, 2, &num_encode, strx_encode, state,
+ *                           bstrs, &bstr_size, &bstr_size,
  *                           sizeof(cbor_string_type_t));
+ *              // check res
+ *              res = list_end_encode(state, 3, 5);
+ *              // check res
  *          @endcode
  *
- *          See @ref intx32_decode for information about the undocumented
- *          parameters.
- *
  * @param[in]  min_decode    The minimum acceptable number of elements.
  * @param[in]  max_decode    The maximum acceptable number of elements.
- * @param[out] p_num_decode  The actual number of elements.
+ * @param[out] num_decode    The actual number of elements.
  * @param[in]  decoder       The decoder function to call under the hood. This
  *                           function will be called with the provided arguments
  *                           repeatedly until the function fails (returns false)
  *                           or until it has been called @p max_decode times.
- *                           p_result is moved @p result_len bytes for each call
- *                           to @p decoder, i.e. @p p_result refers to an array
+ *                           result is moved @p result_len bytes for each call
+ *                           to @p decoder, i.e. @p result refers to an array
  *                           of result variables.
- * @param[out] p_result      Where to place the decoded values. Must be an array
+ * @param[out] result      Where to place the decoded values. Must be an array
  *                           of length at least @p max_decode.
  * @param[in]  result_len    The length of the result variables. Must be the
- *                           length expected by the @p decoder.
+ *                           length matching the elements of @p result.
  *
  * @retval true   If at least @p min_decode variables were correctly decoded.
  * @retval false  If @p decoder failed before having decoded @p min_decode
  *                values.
  */
-bool multi_decode(size_t min_decode, size_t max_decode, size_t *p_num_decode,
-		decoder_t decoder, cbor_decode_state_t * p_state, void *p_result, void *p_min_result, void *p_max_result,
-		size_t result_len);
+bool multi_decode(uint32_t min_decode, uint32_t max_decode, uint32_t *num_decode,
+		cbor_decoder_t decoder, cbor_state_t *state, void *result,
+		uint32_t result_len);
 
-#endif
+bool present_decode(uint32_t *present,
+		cbor_decoder_t decoder,
+		cbor_state_t *state,
+		void *result);
+
+#endif /* CBOR_DECODE_H__ */
diff --git a/boot/boot_serial/src/cbor_encode.c b/boot/boot_serial/src/cbor_encode.c
new file mode 100644
index 0000000..d12dc94
--- /dev/null
+++ b/boot/boot_serial/src/cbor_encode.c
@@ -0,0 +1,466 @@
+/*
+ * This file has been copied from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include "cbor_encode.h"
+#include "cbor_common.h"
+
+_Static_assert((sizeof(size_t) == sizeof(void *)),
+	"This code needs size_t to be the same length as pointers.");
+
+uint8_t get_additional(uint32_t len, uint8_t value0)
+{
+	switch(len) {
+		case 0: return value0;
+		case 1: return 24;
+		case 2: return 25;
+		case 3: return 25;
+		case 4: return 26;
+		case 5: return 26;
+		case 6: return 26;
+		case 7: return 26;
+		case 8: return 27;
+	}
+
+	cbor_assert(false, NULL);
+	return 0;
+}
+
+static bool encode_header_byte(cbor_state_t *state,
+	cbor_major_type_t major_type, uint8_t additional)
+{
+	if ((state->payload + 1) > state->payload_end) {
+		FAIL();
+	}
+
+	cbor_assert(additional < 32, NULL);
+
+	*(state->payload_mut++) = (major_type << 5) | (additional & 0x1F);
+	return true;
+}
+
+/** Encode a single value.
+ */
+static bool value_encode_len(cbor_state_t *state, cbor_major_type_t major_type,
+		const void *const input, uint32_t result_len)
+{
+	uint8_t *u8_result  = (uint8_t *)input;
+
+	if ((state->payload + 1 + result_len) > state->payload_end) {
+		FAIL();
+	}
+
+	if (!encode_header_byte(state, major_type,
+				get_additional(result_len, u8_result[0]))) {
+		FAIL();
+	}
+	state->payload_mut--;
+	cbor_trace();
+	state->payload_mut++;
+
+#ifdef CONFIG_BIG_ENDIAN
+	memcpy(state->payload_mut, u8_result, result_len);
+	state->payload_mut += result_len;
+#else
+	for (; result_len > 0; result_len--) {
+		*(state->payload_mut++) = u8_result[result_len - 1];
+	}
+#endif
+
+	state->elem_count++;
+	return true;
+}
+
+
+static uint32_t get_result_len(const void *const input, uint32_t max_result_len)
+{
+	uint8_t *u8_result  = (uint8_t *)input;
+	size_t i;
+
+	for (i = 0; i < max_result_len; i++) {
+#ifdef CONFIG_BIG_ENDIAN
+		size_t idx = i;
+#else
+		size_t idx = max_result_len - 1 - i;
+#endif
+		if (u8_result[idx] != 0) {
+			break;
+		}
+	}
+	max_result_len -= i;
+
+	/* According to specification result length can be encoded on 1, 2, 4
+	 * or 8 bytes.
+	 */
+	cbor_assert(max_result_len <= 8, "Up to 8 bytes can be used to encode length.\n");
+	size_t encode_byte_cnt = 1;
+
+	for (size_t i = 0; i <= 3; i++) {
+		if (max_result_len <= encode_byte_cnt) {
+			max_result_len = encode_byte_cnt;
+			break;
+		}
+
+		encode_byte_cnt *= 2;
+	}
+
+	if ((max_result_len == 1) && (u8_result[0] <= VALUE_IN_HEADER)) {
+		max_result_len = 0;
+	}
+
+	return max_result_len;
+}
+
+
+static bool value_encode(cbor_state_t *state, cbor_major_type_t major_type,
+		const void *const input, uint32_t max_result_len)
+{
+	cbor_assert(max_result_len != 0, "0-length result not supported.\n");
+	return value_encode_len(state, major_type, input,
+				get_result_len(input, max_result_len));
+}
+
+
+bool intx32_put(cbor_state_t *state, int32_t input)
+{
+	cbor_major_type_t major_type;
+
+	if (input < 0) {
+		major_type = CBOR_MAJOR_TYPE_NINT;
+		/* Convert from CBOR's representation. */
+		input = -1 - input;
+	} else {
+		major_type = CBOR_MAJOR_TYPE_PINT;
+		input = input;
+	}
+
+	if (!value_encode(state, major_type, &input, 4)) {
+		FAIL();
+	}
+
+	return true;
+}
+
+bool intx32_encode(cbor_state_t *state, const int32_t *input)
+{
+	return intx32_put(state, *input);
+}
+
+
+static bool uint32_encode(cbor_state_t *state, const uint32_t *input,
+		cbor_major_type_t major_type)
+{
+	if (!value_encode(state, major_type, input, 4)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+bool uintx32_encode(cbor_state_t *state, const uint32_t *input)
+{
+	if (!uint32_encode(state, input, CBOR_MAJOR_TYPE_PINT)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+bool uintx32_put(cbor_state_t *state, uint32_t input)
+{
+	if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PINT)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+static bool strx_start_encode(cbor_state_t *state,
+		const cbor_string_type_t *input, cbor_major_type_t major_type)
+{
+	if (input->value && ((get_result_len(&input->len, sizeof(input->len))
+			+ 1 + input->len + (size_t)state->payload)
+			> (size_t)state->payload_end)) {
+		FAIL();
+	}
+	if (!uint32_encode(state, &input->len, major_type)) {
+		FAIL();
+	}
+
+	return true;
+}
+
+
+static bool primx_encode(cbor_state_t *state, uint32_t input)
+{
+	if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PRIM)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+static uint32_t remaining_str_len(cbor_state_t *state)
+{
+	uint32_t max_len = (size_t)state->payload_end - (size_t)state->payload;
+	uint32_t result_len = get_result_len(&max_len, sizeof(uint32_t));
+	return max_len - result_len - 1;
+}
+
+
+bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result)
+{
+	if (!new_backup(state, 0)) {
+		FAIL();
+	}
+
+	uint32_t max_len = remaining_str_len(state);
+
+	/* Encode a dummy header */
+	if (!uint32_encode(state, &max_len,
+			CBOR_MAJOR_TYPE_BSTR)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+bool bstrx_cbor_end_encode(cbor_state_t *state)
+{
+	const uint8_t *payload = state->payload;
+
+	if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
+		FAIL();
+	}
+	cbor_string_type_t value;
+
+	value.value = state->payload_end - remaining_str_len(state);
+	value.len = (size_t)payload - (size_t)value.value;
+
+	/* Reencode header of list now that we know the number of elements. */
+	if (!bstrx_encode(state, &value)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+static bool strx_encode(cbor_state_t *state,
+		const cbor_string_type_t *input, cbor_major_type_t major_type)
+{
+	if (!strx_start_encode(state, input, major_type)) {
+		FAIL();
+	}
+	if (input->len > (state->payload_end - state->payload)) {
+		FAIL();
+	}
+	if (state->payload_mut != input->value) {
+		memmove(state->payload_mut, input->value, input->len);
+	}
+	state->payload += input->len;
+	return true;
+}
+
+
+bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
+{
+	return strx_encode(state, input, CBOR_MAJOR_TYPE_BSTR);
+}
+
+
+bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
+{
+	return strx_encode(state, input, CBOR_MAJOR_TYPE_TSTR);
+}
+
+
+static bool list_map_start_encode(cbor_state_t *state, uint32_t max_num,
+		cbor_major_type_t major_type)
+{
+#ifdef CDDL_CBOR_CANONICAL
+	if (!new_backup(state, 0)) {
+		FAIL();
+	}
+
+	/* Encode dummy header with max number of elements. */
+	if (!uint32_encode(state, &max_num, major_type)) {
+		FAIL();
+	}
+	state->elem_count--; /* Because of dummy header. */
+#else
+	if (!encode_header_byte(state, major_type, 31)) {
+		FAIL();
+	}
+#endif
+	return true;
+}
+
+
+bool list_start_encode(cbor_state_t *state, uint32_t max_num)
+{
+	return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
+}
+
+
+bool map_start_encode(cbor_state_t *state, uint32_t max_num)
+{
+	return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
+}
+
+
+bool list_map_end_encode(cbor_state_t *state, uint32_t max_num,
+			cbor_major_type_t major_type)
+{
+#ifdef CDDL_CBOR_CANONICAL
+	uint32_t list_count = ((major_type == CBOR_MAJOR_TYPE_LIST) ?
+					state->elem_count
+					: (state->elem_count / 2));
+
+	const uint8_t *payload = state->payload;
+	uint32_t max_header_len = get_result_len(&max_num, 4);
+	uint32_t header_len = get_result_len(&list_count, 4);
+
+	if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
+		FAIL();
+	}
+
+	cbor_print("list_count: %d\r\n", list_count);
+
+	/* Reencode header of list now that we know the number of elements. */
+	if (!(uint32_encode(state, &list_count, major_type))) {
+		FAIL();
+	}
+
+	if (max_header_len != header_len) {
+		const uint8_t *start = state->payload + max_header_len - header_len;
+		uint32_t body_size = payload - start;
+		memmove(state->payload_mut,
+			state->payload + max_header_len - header_len,
+			body_size);
+		/* Reset payload pointer to end of list */
+		state->payload += body_size;
+	} else {
+		/* Reset payload pointer to end of list */
+		state->payload = payload;
+	}
+#else
+	if (!encode_header_byte(state, CBOR_MAJOR_TYPE_PRIM, 31)) {
+		FAIL();
+	}
+#endif
+	return true;
+}
+
+
+bool list_end_encode(cbor_state_t *state, uint32_t max_num)
+{
+	return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
+}
+
+
+bool map_end_encode(cbor_state_t *state, uint32_t max_num)
+{
+	return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
+}
+
+
+bool nilx_put(cbor_state_t *state, const void *input)
+{
+	(void)input;
+	return primx_encode(state, 22);
+}
+
+
+bool boolx_encode(cbor_state_t *state, const bool *input)
+{
+	if (!primx_encode(state, *input + BOOL_TO_PRIM)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+bool boolx_put(cbor_state_t *state, bool input)
+{
+	if (!primx_encode(state, input + BOOL_TO_PRIM)) {
+		FAIL();
+	}
+	return true;
+}
+
+
+bool double_encode(cbor_state_t *state, double *input)
+{
+	if (!value_encode(state, CBOR_MAJOR_TYPE_PRIM, input,
+			sizeof(*input))) {
+		FAIL();
+	}
+
+	return true;
+}
+
+
+bool double_put(cbor_state_t *state, double input)
+{
+	return double_encode(state, &input);
+}
+
+
+bool any_encode(cbor_state_t *state, void *input)
+{
+	return nilx_put(state, input);
+}
+
+
+bool tag_encode(cbor_state_t *state, uint32_t tag)
+{
+	if (!value_encode(state, CBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) {
+		FAIL();
+	}
+	state->elem_count--;
+
+	return true;
+}
+
+
+bool multi_encode(uint32_t min_encode,
+		uint32_t max_encode,
+		const uint32_t *num_encode,
+		cbor_encoder_t encoder,
+		cbor_state_t *state,
+		const void *input,
+		uint32_t result_len)
+{
+	if (!PTR_VALUE_IN_RANGE(uint32_t, num_encode, NULL, &max_encode)) {
+		FAIL();
+	}
+	for (uint32_t i = 0; i < *num_encode; i++) {
+		if (!encoder(state, (const uint8_t *)input + i*result_len)) {
+			FAIL();
+		}
+	}
+	cbor_print("Found %zu elements.\n", *num_encode);
+	return true;
+}
+
+
+bool present_encode(const uint32_t *present,
+		cbor_encoder_t encoder,
+		cbor_state_t *state,
+		const void *input)
+{
+	uint32_t num_encode = *present;
+	bool retval = multi_encode(0, 1, &num_encode, encoder, state, input, 0);
+	return retval;
+}
diff --git a/boot/boot_serial/src/cbor_encode.h b/boot/boot_serial/src/cbor_encode.h
new file mode 100644
index 0000000..4c53d45
--- /dev/null
+++ b/boot/boot_serial/src/cbor_encode.h
@@ -0,0 +1,150 @@
+/*
+ * This file has been copied from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
+ */
+
+/*
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef CBOR_ENCODE_H__
+#define CBOR_ENCODE_H__
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "cbor_common.h"
+
+
+/** Encode a PINT/NINT into a int32_t.
+ *
+ * @param[inout] state        The current state of the decoding.
+ * @param[out]   result       Where to place the encoded value.
+ *
+ * @retval true   Everything is ok.
+ * @retval false  If the payload is exhausted.
+ */
+bool intx32_encode(cbor_state_t *state, const int32_t *input);
+bool intx32_put(cbor_state_t *state, int32_t result);
+
+/** Encode a PINT into a uint32_t. */
+bool uintx32_encode(cbor_state_t *state, const uint32_t *result);
+bool uintx32_put(cbor_state_t *state, uint32_t result);
+
+/** 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.
+ *
+ * @retval true   Header encoded correctly
+ * @retval false  Header encoded incorrectly, or backup failed.
+ */
+bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result);
+
+/** Finalize encoding a CBOR-encoded BSTR.
+ *
+ * Restore element count from backup.
+ */
+bool bstrx_cbor_end_encode(cbor_state_t *state);
+
+/** Encode a BSTR, */
+bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *result);
+
+/** Encode a TSTR. */
+bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *result);
+
+#define tstrx_put(state, string) \
+	tstrx_encode(state, &(cbor_string_type_t){.value = (const uint8_t *)string, .len = (sizeof(string) - 1)})
+
+#define tstrx_put_term(state, string) \
+	tstrx_encode(state, &(cbor_string_type_t){.value = (const uint8_t *)string, .len = strlen((const char *)string)})
+
+/** Encode a LIST header.
+ *
+ * The contents of the list can be decoded via subsequent function calls.
+ * A state backup is created to keep track of the element count.
+ */
+bool list_start_encode(cbor_state_t *state, uint32_t max_num);
+
+/** Encode a MAP header. */
+bool map_start_encode(cbor_state_t *state, uint32_t max_num);
+
+/** Encode end of a LIST. Do some checks and deallocate backup. */
+bool list_end_encode(cbor_state_t *state, uint32_t max_num);
+
+/** Encode end of a MAP. Do some checks and deallocate backup. */
+bool map_end_encode(cbor_state_t *state, uint32_t max_num);
+
+/** Encode a "nil" primitive value. result should be NULL. */
+bool nilx_put(cbor_state_t *state, const void *result);
+
+/** Encode a boolean primitive value. */
+bool boolx_encode(cbor_state_t *state, const bool *result);
+bool boolx_put(cbor_state_t *state, bool result);
+
+/** Encode a float */
+bool float_encode(cbor_state_t *state, double *result);
+bool float_put(cbor_state_t *state, double result);
+
+/** Dummy encode "any": Encode a "nil". input should be NULL. */
+bool any_encode(cbor_state_t *state, void *input);
+
+/** Encode a tag. */
+bool tag_encode(cbor_state_t *state, uint32_t tag);
+
+/** Encode 0 or more elements with the same type and constraints.
+ *
+ * @details This must not necessarily encode all elements in a list. E.g. if
+ *          the list contains 3 INTS between 0 and 100 followed by 0 to 2 BSTRs
+ *          with length 8, that could be done with:
+ *
+ *          @code{c}
+ *              uint32_t int_min = 0;
+ *              uint32_t int_max = 100;
+ *              uint32_t bstr_size = 8;
+ *              uint32_t ints[3];
+ *              cbor_string_type_t bstrs[2] = <initialize here>;
+ *              bool res;
+ *
+ *              res = list_start_encode(state, 5);
+ *              // check res
+ *              res = multi_encode(3, 3, &num_encode, uintx32_encode, state,
+ *                           ints, 4);
+ *              // check res
+ *              res = multi_encode(0, 2, &num_encode, strx_encode, state,
+ *                           bstrs, sizeof(cbor_string_type_t));
+ *              // check res
+ *              res = list_end_encode(state, 5);
+ *              // check res
+ *          @endcode
+ *
+ * @param[in]  min_encode    The minimum acceptable number of elements.
+ * @param[in]  max_encode    The maximum acceptable number of elements.
+ * @param[in]  num_encode    The actual number of elements.
+ * @param[in]  encoder       The encoder function to call under the hood. This
+ *                           function will be called with the provided arguments
+ *                           repeatedly until the function fails (returns false)
+ *                           or until it has been called @p max_encode times.
+ *                           result is moved @p result_len bytes for each call
+ *                           to @p encoder, i.e. @p result refers to an array
+ *                           of result variables.
+ * @param[in]  input         Source of the encoded values. Must be an array
+ *                           of length at least @p max_encode.
+ * @param[in]  result_len    The length of the result variables. Must be the
+ *                           length of the elements in result.
+ *
+ * @retval true   If at least @p min_encode variables were correctly encoded.
+ * @retval false  If @p encoder failed before having encoded @p min_encode
+ *                values.
+ */
+bool multi_encode(uint32_t min_encode, uint32_t max_encode, const uint32_t *num_encode,
+		cbor_encoder_t encoder, cbor_state_t *state, const void *input,
+		uint32_t result_len);
+
+bool present_encode(const uint32_t *present,
+		cbor_encoder_t encoder,
+		cbor_state_t *state,
+		const void *input);
+
+#endif /* CBOR_ENCODE_H__ */
diff --git a/boot/boot_serial/src/regenerate_serial_recovery_cbor.sh b/boot/boot_serial/src/regenerate_serial_recovery_cbor.sh
index 79cb6e9..08d1220 100755
--- a/boot/boot_serial/src/regenerate_serial_recovery_cbor.sh
+++ b/boot/boot_serial/src/regenerate_serial_recovery_cbor.sh
@@ -1,19 +1,19 @@
 #!/bin/bash
 
 if [ "$1" == "--help" ] || [ "$1" == "" ]; then
-	echo "Regenerate serial_recovery_cbor.c|h if the cddl_gen submodule is updated."
+	echo "Regenerate serial_recovery_cbor.c|h if the cddl-gen submodule is updated."
 	echo "Usage: $0 <copyright>"
-	echo "  e.g. $0 \"2020 Nordic Semiconductor ASA\""
+	echo "  e.g. $0 \"2021 Nordic Semiconductor ASA\""
 	exit -1
 fi
 
 add_copy_notice() {
 echo "$(printf '/*
- * This file has been %s from the cddl_gen submodule.
+ * This file has been %s from the cddl-gen submodule.
  * Commit %s
  */
 
-' "$2" "$(git -C ../../../ext/cddl_gen rev-parse HEAD)"; cat $1;)" > $1
+' "$2" "$(git -C ../../../ext/cddl-gen rev-parse HEAD)"; cat $1;)" > $1
 }
 
 echo "Copying cbor_decode.c|h"
@@ -22,11 +22,15 @@
 	add_copy_notice $2 "copied"
 }
 
-copy_with_copy_notice ../../../ext/cddl_gen/src/cbor_decode.c cbor_decode.c
-copy_with_copy_notice ../../../ext/cddl_gen/include/cbor_decode.h cbor_decode.h cbor_decode.h
+copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_decode.c cbor_decode.c
+copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_encode.c cbor_encode.c
+copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_common.c cbor_common.c
+copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_decode.h cbor_decode.h
+copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_encode.h cbor_encode.h
+copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_common.h cbor_common.h
 
 echo "Generating serial_recovery_cbor.c|h"
-python3 ../../../ext/cddl_gen/scripts/cddl_gen.py -i serial_recovery.cddl -t Upload --oc serial_recovery_cbor.c --oh serial_recovery_cbor.h --time-header
+python3 ../../../ext/cddl-gen/cddl_gen/cddl_gen.py -c serial_recovery.cddl code -d -t Upload --oc serial_recovery_cbor.c --oh serial_recovery_cbor.h --time-header
 
 add_copyright() {
 echo "$(printf '/*
@@ -42,3 +46,4 @@
 add_copyright serial_recovery_cbor.h "$1"
 add_copy_notice serial_recovery_cbor.c "generated"
 add_copy_notice serial_recovery_cbor.h "generated"
+add_copy_notice types_serial_recovery_cbor.h "generated"
diff --git a/boot/boot_serial/src/serial_recovery_cbor.c b/boot/boot_serial/src/serial_recovery_cbor.c
index 45634ef..2561b70 100644
--- a/boot/boot_serial/src/serial_recovery_cbor.c
+++ b/boot/boot_serial/src/serial_recovery_cbor.c
@@ -1,16 +1,18 @@
 /*
- * This file has been generated from the cddl_gen submodule.
- * Commit 9d911cf0c7c9f13b5a9fdd5ed6c1012df21e5576
+ * This file has been generated from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
  */
 
 /*
- * Copyright (c) 2020 Nordic Semiconductor ASA
+ * Copyright (c) 2021 Nordic Semiconductor ASA
  *
  * SPDX-License-Identifier: Apache-2.0
  */
 
-/* Generated with cddl_gen.py (https://github.com/oyvindronningstad/cddl_gen)
- * at: 2020-05-13 12:19:04
+/*
+ * Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen)
+ * at: 2021-08-02 17:09:42
+ * Generated with a default_max_qty of 3
  */
 
 #include <stdint.h>
@@ -20,65 +22,73 @@
 #include "cbor_decode.h"
 #include "serial_recovery_cbor.h"
 
+#if DEFAULT_MAX_QTY != 3
+#error "The type file was generated with a different default_max_qty than this file"
+#endif
+
 
 static bool decode_Member(
-		cbor_decode_state_t *p_state, void * p_result, void * p_min_value,
-		void * p_max_value)
+		cbor_state_t *state, struct Member_ *result)
 {
-	cbor_decode_print("decode_Member\n");
-	uint8_t const * p_payload_bak;
-	size_t elem_count_bak;
-	_Member_t* p_type_result = (_Member_t*)p_result;
+	cbor_print("%s\n", __func__);
+	cbor_string_type_t tmp_str;
+	bool int_res;
 
-	bool result = (((p_payload_bak = p_state->p_payload) && ((elem_count_bak = p_state->elem_count) || 1) && ((((strx_decode(p_state, &((*p_type_result)._Member_image_key), NULL, NULL))&& !memcmp("image", (*p_type_result)._Member_image_key.value, (*p_type_result)._Member_image_key.len)
-	&& (intx32_decode(p_state, &((*p_type_result)._Member_image), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_image) || 1))
-	|| ((p_state->p_payload = p_payload_bak) && ((p_state->elem_count = elem_count_bak) || 1) && (((strx_decode(p_state, &((*p_type_result)._Member_data_key), NULL, NULL))&& !memcmp("data", (*p_type_result)._Member_data_key.value, (*p_type_result)._Member_data_key.len)
-	&& (strx_decode(p_state, &((*p_type_result)._Member_data), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_data) || 1)))
-	|| ((p_state->p_payload = p_payload_bak) && ((p_state->elem_count = elem_count_bak) || 1) && (((strx_decode(p_state, &((*p_type_result)._Member_len_key), NULL, NULL))&& !memcmp("len", (*p_type_result)._Member_len_key.value, (*p_type_result)._Member_len_key.len)
-	&& (intx32_decode(p_state, &((*p_type_result)._Member_len), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_len) || 1)))
-	|| ((p_state->p_payload = p_payload_bak) && ((p_state->elem_count = elem_count_bak) || 1) && (((strx_decode(p_state, &((*p_type_result)._Member_off_key), NULL, NULL))&& !memcmp("off", (*p_type_result)._Member_off_key.value, (*p_type_result)._Member_off_key.len)
-	&& (intx32_decode(p_state, &((*p_type_result)._Member_off), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_off) || 1)))
-	|| ((p_state->p_payload = p_payload_bak) && ((p_state->elem_count = elem_count_bak) || 1) && (((strx_decode(p_state, &((*p_type_result)._Member_sha_key), NULL, NULL))&& !memcmp("sha", (*p_type_result)._Member_sha_key.value, (*p_type_result)._Member_sha_key.len)
-	&& (strx_decode(p_state, &((*p_type_result)._Member_sha), NULL, NULL))) && (((*p_type_result)._Member_choice = _Member_sha) || 1))))));
+	bool tmp_result = (((union_start_code(state) && (int_res = (((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"image",
+    tmp_str.len = sizeof("image") - 1, &tmp_str)))))
+	&& (intx32_decode(state, (&(*result)._Member_image)))) && (((*result)._Member_choice = _Member_image) || 1))
+	|| (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"data",
+    tmp_str.len = sizeof("data") - 1, &tmp_str)))))
+	&& (bstrx_decode(state, (&(*result)._Member_data)))) && (((*result)._Member_choice = _Member_data) || 1)))
+	|| (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"len",
+    tmp_str.len = sizeof("len") - 1, &tmp_str)))))
+	&& (intx32_decode(state, (&(*result)._Member_len)))) && (((*result)._Member_choice = _Member_len) || 1)))
+	|| (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"off",
+    tmp_str.len = sizeof("off") - 1, &tmp_str)))))
+	&& (intx32_decode(state, (&(*result)._Member_off)))) && (((*result)._Member_choice = _Member_off) || 1)))
+	|| (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"sha",
+    tmp_str.len = sizeof("sha") - 1, &tmp_str)))))
+	&& (bstrx_decode(state, (&(*result)._Member_sha)))) && (((*result)._Member_choice = _Member_sha) || 1)))), union_end_code(state), int_res))));
 
-	if (!result)
-	{
-		cbor_decode_trace();
-	}
+	if (!tmp_result)
+		cbor_trace();
 
-	return result;
+	return tmp_result;
 }
 
 static bool decode_Upload(
-		cbor_decode_state_t *p_state, void * p_result, void * p_min_value,
-		void * p_max_value)
+		cbor_state_t *state, struct Upload *result)
 {
-	cbor_decode_print("decode_Upload\n");
-	size_t temp_elem_counts[2];
-	size_t *p_temp_elem_count = temp_elem_counts;
-	Upload_t* p_type_result = (Upload_t*)p_result;
+	cbor_print("%s\n", __func__);
+	bool int_res;
 
-	bool result = (((list_start_decode(p_state, &(*(p_temp_elem_count++)), 1, 5))
-	&& multi_decode(1, 5, &(*p_type_result)._Upload_members_count, (void*)decode_Member, p_state, &((*p_type_result)._Upload_members), NULL, NULL, sizeof(_Member_t))
-	&& ((p_state->elem_count = *(--p_temp_elem_count)) || 1)));
+	bool tmp_result = (((map_start_decode(state) && (int_res = (multi_decode(1, 5, &(*result)._Upload_members_count, (void *)decode_Member, state, (&(*result)._Upload_members), sizeof(struct Member_))), ((map_end_decode(state)) && int_res)))));
 
-	if (!result)
-	{
-		cbor_decode_trace();
-	}
+	if (!tmp_result)
+		cbor_trace();
 
-	p_state->elem_count = temp_elem_counts[0];
-	return result;
+	return tmp_result;
 }
 
 
-bool cbor_decode_Upload(const uint8_t * p_payload, size_t payload_len, Upload_t * p_result)
-{
-	cbor_decode_state_t state = {
-		.p_payload = p_payload,
-		.p_payload_end = p_payload + payload_len,
-		.elem_count = 1
-	};
 
-	return decode_Upload(&state, p_result, NULL, NULL);
+__attribute__((unused)) static bool type_test_decode_Upload(
+		struct Upload *result)
+{
+	/* This function should not be called, it is present only to test that
+	 * the types of the function and struct match, since this information
+	 * is lost with the casts in the entry function.
+	 */
+	return decode_Upload(NULL, result);
+}
+
+
+bool cbor_decode_Upload(
+		const uint8_t *payload, uint32_t payload_len,
+		struct Upload *result,
+		uint32_t *payload_len_out)
+{
+	return entry_function(payload, payload_len, (const void *)result,
+		payload_len_out, (void *)decode_Upload,
+		1, 2);
 }
diff --git a/boot/boot_serial/src/serial_recovery_cbor.h b/boot/boot_serial/src/serial_recovery_cbor.h
index aa14f5c..f167d9b 100644
--- a/boot/boot_serial/src/serial_recovery_cbor.h
+++ b/boot/boot_serial/src/serial_recovery_cbor.h
@@ -1,16 +1,18 @@
 /*
- * This file has been generated from the cddl_gen submodule.
- * Commit 9d911cf0c7c9f13b5a9fdd5ed6c1012df21e5576
+ * This file has been generated from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
  */
 
 /*
- * Copyright (c) 2020 Nordic Semiconductor ASA
+ * Copyright (c) 2021 Nordic Semiconductor ASA
  *
  * SPDX-License-Identifier: Apache-2.0
  */
 
-/* Generated with cddl_gen.py (https://github.com/oyvindronningstad/cddl_gen)
- * at: 2020-05-13 12:19:04
+/*
+ * Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen)
+ * at: 2021-08-02 17:09:42
+ * Generated with a default_max_qty of 3
  */
 
 #ifndef SERIAL_RECOVERY_CBOR_H__
@@ -21,45 +23,17 @@
 #include <stddef.h>
 #include <string.h>
 #include "cbor_decode.h"
+#include "types_serial_recovery_cbor.h"
+
+#if DEFAULT_MAX_QTY != 3
+#error "The type file was generated with a different default_max_qty than this file"
+#endif
 
 
-typedef struct {
-	union {
-		struct {
-			cbor_string_type_t _Member_image_key;
-			int32_t _Member_image;
-		};
-		struct {
-			cbor_string_type_t _Member_data_key;
-			cbor_string_type_t _Member_data;
-		};
-		struct {
-			cbor_string_type_t _Member_len_key;
-			int32_t _Member_len;
-		};
-		struct {
-			cbor_string_type_t _Member_off_key;
-			int32_t _Member_off;
-		};
-		struct {
-			cbor_string_type_t _Member_sha_key;
-			cbor_string_type_t _Member_sha;
-		};
-	};
-	enum {
-		_Member_image,
-		_Member_data,
-		_Member_len,
-		_Member_off,
-		_Member_sha,
-	} _Member_choice;
-} _Member_t;
+bool cbor_decode_Upload(
+		const uint8_t *payload, uint32_t payload_len,
+		struct Upload *result,
+		uint32_t *payload_len_out);
 
-typedef struct {
-	_Member_t _Upload_members[5];
-	size_t _Upload_members_count;
-} Upload_t;
 
-bool cbor_decode_Upload(const uint8_t * p_payload, size_t payload_len, Upload_t * p_result);
-
-#endif // SERIAL_RECOVERY_CBOR_H__
+#endif /* SERIAL_RECOVERY_CBOR_H__ */
diff --git a/boot/boot_serial/src/types_serial_recovery_cbor.h b/boot/boot_serial/src/types_serial_recovery_cbor.h
new file mode 100644
index 0000000..8856017
--- /dev/null
+++ b/boot/boot_serial/src/types_serial_recovery_cbor.h
@@ -0,0 +1,56 @@
+/*
+ * This file has been generated from the cddl-gen submodule.
+ * Commit 9f77837f9950da1633d22abf6181a830521a6688
+ */
+
+/*
+ * Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen)
+ * at: 2021-08-02 17:09:42
+ * Generated with a default_max_qty of 3
+ */
+
+#ifndef TYPES_SERIAL_RECOVERY_CBOR_H__
+#define TYPES_SERIAL_RECOVERY_CBOR_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include "cbor_decode.h"
+
+#define DEFAULT_MAX_QTY 3
+
+struct Member_ {
+ 	union {
+		struct {
+			int32_t _Member_image;
+		};
+		struct {
+			cbor_string_type_t _Member_data;
+		};
+		struct {
+			int32_t _Member_len;
+		};
+		struct {
+			int32_t _Member_off;
+		};
+		struct {
+			cbor_string_type_t _Member_sha;
+		};
+	};
+	enum {
+		_Member_image,
+		_Member_data,
+		_Member_len,
+		_Member_off,
+		_Member_sha,
+	} _Member_choice;
+};
+
+struct Upload {
+ 	struct Member_ _Upload_members[5];
+	uint32_t _Upload_members_count;
+};
+
+
+#endif /* TYPES_SERIAL_RECOVERY_CBOR_H__ */
diff --git a/boot/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c b/boot/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c
index 53a7199..83ba50a 100644
--- a/boot/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c
+++ b/boot/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c
@@ -18,7 +18,6 @@
  */
 
 #include <flash_map_backend/flash_map_backend.h>
-#include <tinycbor/cborconstants_p.h>
 
 #include "boot_test.h"