mcuboot - Initial migration.
diff --git a/boot_serial/include/boot_serial/boot_serial.h b/boot_serial/include/boot_serial/boot_serial.h
new file mode 100644
index 0000000..b93c28f
--- /dev/null
+++ b/boot_serial/include/boot_serial/boot_serial.h
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __BOOT_SERIAL_H__
+#define __BOOT_SERIAL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Start processing newtmgr commands for uploading image0 over serial.
+ *
+ * Open console serial port and wait for download command.
+ */
+void boot_serial_start(int max_input);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*  __BOOT_SERIAL_H__ */
diff --git a/boot_serial/pkg.yml b/boot_serial/pkg.yml
new file mode 100644
index 0000000..5913877
--- /dev/null
+++ b/boot_serial/pkg.yml
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: boot/boot_serial
+pkg.description: The boot_serial library is used when downloading image over serial port.
+pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+    - boot
+    - bootloader
+
+pkg.deps:
+    - hw/hal
+    - kernel/os
+    - boot/bootutil
+    - encoding/tinycbor
+    - encoding/cborattr
+    - encoding/base64
+    - sys/flash_map
+    - util/crc
+
+pkg.req_apis:
+    - console
diff --git a/boot_serial/src/boot_serial.c b/boot_serial/src/boot_serial.c
new file mode 100644
index 0000000..ac935c1
--- /dev/null
+++ b/boot_serial/src/boot_serial.c
@@ -0,0 +1,445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <assert.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "sysflash/sysflash.h"
+
+#include <bsp/bsp.h>
+
+#include <flash_map/flash_map.h>
+#include <hal/hal_flash.h>
+#include <hal/hal_system.h>
+
+#include <os/endian.h>
+#include <os/os.h>
+#include <os/os_malloc.h>
+#include <os/os_cputime.h>
+
+#include <console/console.h>
+
+#include <tinycbor/cbor.h>
+#include <tinycbor/cbor_buf_reader.h>
+#include <cborattr/cborattr.h>
+#include <base64/base64.h>
+#include <crc/crc16.h>
+
+#include <bootutil/image.h>
+
+#include "boot_serial/boot_serial.h"
+#include "boot_serial_priv.h"
+
+#define BOOT_SERIAL_OUT_MAX	48
+
+static uint32_t curr_off;
+static uint32_t img_size;
+static struct nmgr_hdr *bs_hdr;
+
+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 CborEncoder bs_root;
+static CborEncoder bs_rsp;
+
+int
+bs_cbor_writer(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+    memcpy(&bs_obuf[cew->bytes_written], data, len);
+    cew->bytes_written += len;
+
+    return 0;
+}
+
+/*
+ * Looks for 'name' from NULL-terminated json data in buf.
+ * Returns pointer to first character of value for that name.
+ * Returns NULL if 'name' is not found.
+ */
+char *
+bs_find_val(char *buf, char *name)
+{
+    char *ptr;
+
+    ptr = strstr(buf, name);
+    if (!ptr) {
+        return NULL;
+    }
+    ptr += strlen(name);
+
+    while (*ptr != '\0') {
+        if (*ptr != ':' && !isspace(*ptr)) {
+            break;
+        }
+        ++ptr;
+    }
+    if (*ptr == '\0') {
+        ptr = NULL;
+    }
+    return ptr;
+}
+
+/*
+ * List images.
+ */
+static void
+bs_list(char *buf, int len)
+{
+    CborEncoder images;
+    CborEncoder image;
+    struct image_header hdr;
+    uint8_t tmpbuf[64];
+    int i, area_id;
+    const struct flash_area *fap;
+
+    cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
+    cbor_encode_text_stringz(&bs_rsp, "images");
+    cbor_encoder_create_array(&bs_rsp, &images, CborIndefiniteLength);
+    for (i = 0; i < 2; i++) {
+        area_id = flash_area_id_from_image_slot(i);
+        if (flash_area_open(area_id, &fap)) {
+            continue;
+        }
+
+        flash_area_read(fap, 0, &hdr, sizeof(hdr));
+
+        if (hdr.ih_magic != IMAGE_MAGIC ||
+          bootutil_img_validate(&hdr, fap, tmpbuf, sizeof(tmpbuf),
+                                NULL, 0, NULL)) {
+            flash_area_close(fap);
+            continue;
+        }
+        flash_area_close(fap);
+
+        cbor_encoder_create_map(&images, &image, CborIndefiniteLength);
+        cbor_encode_text_stringz(&image, "slot");
+        cbor_encode_int(&image, i);
+        cbor_encode_text_stringz(&image, "version");
+
+        len = snprintf((char *)tmpbuf, sizeof(tmpbuf),
+          "%u.%u.%u.%u", hdr.ih_ver.iv_major, hdr.ih_ver.iv_minor,
+          hdr.ih_ver.iv_revision, (unsigned int)hdr.ih_ver.iv_build_num);
+        cbor_encode_text_stringz(&image, (char *)tmpbuf);
+        cbor_encoder_close_container(&images, &image);
+    }
+    cbor_encoder_close_container(&bs_rsp, &images);
+    cbor_encoder_close_container(&bs_root, &bs_rsp);
+    boot_serial_output();
+}
+
+/*
+ * Image upload request.
+ */
+static void
+bs_upload(char *buf, int len)
+{
+    CborParser parser;
+    struct cbor_buf_reader reader;
+    struct CborValue value;
+    uint8_t img_data[400];
+    long long unsigned int off = UINT_MAX;
+    size_t img_blen = 0;
+    long long unsigned int data_len = UINT_MAX;
+    const struct cbor_attr_t attr[4] = {
+        [0] = {
+            .attribute = "data",
+            .type = CborAttrByteStringType,
+            .addr.bytestring.data = img_data,
+            .addr.bytestring.len = &img_blen,
+            .len = sizeof(img_data)
+        },
+        [1] = {
+            .attribute = "off",
+            .type = CborAttrUnsignedIntegerType,
+            .addr.uinteger = &off,
+            .nodefault = true
+        },
+        [2] = {
+            .attribute = "len",
+            .type = CborAttrUnsignedIntegerType,
+            .addr.uinteger = &data_len,
+            .nodefault = true
+        }
+    };
+    const struct flash_area *fap = NULL;
+    int rc;
+
+    memset(img_data, 0, sizeof(img_data));
+    cbor_buf_reader_init(&reader, (uint8_t *)buf, len);
+    cbor_parser_init(&reader.r, 0, &parser, &value);
+    rc = cbor_read_object(&value, attr);
+    if (rc || off == UINT_MAX) {
+        rc = MGMT_ERR_EINVAL;
+        goto out;
+    }
+
+
+    rc = flash_area_open(flash_area_id_from_image_slot(0), &fap);
+    if (rc) {
+        rc = MGMT_ERR_EINVAL;
+        goto out;
+    }
+
+    if (off == 0) {
+        curr_off = 0;
+        if (data_len > fap->fa_size) {
+            rc = MGMT_ERR_EINVAL;
+            goto out;
+        }
+        rc = flash_area_erase(fap, 0, fap->fa_size);
+        if (rc) {
+            rc = MGMT_ERR_EINVAL;
+            goto out;
+        }
+        img_size = data_len;
+    }
+    if (off != curr_off) {
+        rc = 0;
+        goto out;
+    }
+    rc = flash_area_write(fap, curr_off, img_data, img_blen);
+    if (rc) {
+        rc = MGMT_ERR_EINVAL;
+        goto out;
+    }
+    curr_off += img_blen;
+
+out:
+    cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
+    cbor_encode_text_stringz(&bs_rsp, "rc");
+    cbor_encode_int(&bs_rsp, rc);
+    if (rc == 0) {
+        cbor_encode_text_stringz(&bs_rsp, "off");
+        cbor_encode_uint(&bs_rsp, curr_off);
+    }
+    cbor_encoder_close_container(&bs_root, &bs_rsp);
+
+    boot_serial_output();
+    flash_area_close(fap);
+}
+
+/*
+ * Console echo control. Send empty response, don't do anything.
+ */
+static void
+bs_echo_ctl(char *buf, int len)
+{
+    boot_serial_output();
+}
+
+/*
+ * Reset, and (presumably) boot to newly uploaded image. Flush console
+ * before restarting.
+ */
+static int
+bs_reset(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);
+
+    boot_serial_output();
+    os_cputime_delay_usecs(250000);
+    hal_system_reset();
+}
+
+/*
+ * Parse incoming line of input from console.
+ * Expect newtmgr protocol with serial transport.
+ */
+void
+boot_serial_input(char *buf, int len)
+{
+    struct nmgr_hdr *hdr;
+
+    hdr = (struct nmgr_hdr *)buf;
+    if (len < sizeof(*hdr) ||
+      (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
+      (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
+        return;
+    }
+    bs_hdr = hdr;
+    hdr->nh_group = ntohs(hdr->nh_group);
+
+    buf += sizeof(*hdr);
+    len -= sizeof(*hdr);
+
+    bs_writer.bytes_written = 0;
+    cbor_encoder_init(&bs_root, &bs_writer, 0);
+
+    /*
+     * Limited support for commands.
+     */
+    if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
+        switch (hdr->nh_id) {
+        case IMGMGR_NMGR_OP_STATE:
+            bs_list(buf, len);
+            break;
+        case IMGMGR_NMGR_OP_UPLOAD:
+            bs_upload(buf, len);
+            break;
+        default:
+            break;
+        }
+    } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
+        switch (hdr->nh_id) {
+        case NMGR_ID_CONS_ECHO_CTRL:
+            bs_echo_ctl(buf, len);
+            break;
+        case NMGR_ID_RESET:
+            bs_reset(buf, len);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+static void
+boot_serial_output(void)
+{
+    char *data;
+    int len;
+    uint16_t crc;
+    uint16_t totlen;
+    char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
+    char buf[BOOT_SERIAL_OUT_MAX];
+    char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
+
+    data = bs_obuf;
+    len = bs_writer.bytes_written;
+
+    bs_hdr->nh_op++;
+    bs_hdr->nh_flags = NMGR_F_CBOR_RSP_COMPLETE;
+    bs_hdr->nh_len = htons(len);
+    bs_hdr->nh_group = htons(bs_hdr->nh_group);
+
+    crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
+    crc = crc16_ccitt(crc, data, len);
+    crc = htons(crc);
+
+    console_write(pkt_start, sizeof(pkt_start));
+
+    totlen = len + sizeof(*bs_hdr) + sizeof(crc);
+    totlen = htons(totlen);
+
+    memcpy(buf, &totlen, sizeof(totlen));
+    totlen = sizeof(totlen);
+    memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
+    totlen += sizeof(*bs_hdr);
+    memcpy(&buf[totlen], data, len);
+    totlen += len;
+    memcpy(&buf[totlen], &crc, sizeof(crc));
+    totlen += sizeof(crc);
+    totlen = base64_encode(buf, totlen, encoded_buf, 1);
+    console_write(encoded_buf, totlen);
+    console_write("\n", 1);
+}
+
+/*
+ * Returns 1 if full packet has been received.
+ */
+static int
+boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
+{
+    int rc;
+    uint16_t crc;
+    uint16_t len;
+
+    if (*out_off + base64_decode_len(in) >= maxout) {
+        return -1;
+    }
+    rc = base64_decode(in, &out[*out_off]);
+    if (rc < 0) {
+        return -1;
+    }
+    *out_off += rc;
+
+    if (*out_off > sizeof(uint16_t)) {
+        len = ntohs(*(uint16_t *)out);
+
+        len = min(len, *out_off - sizeof(uint16_t));
+        out += sizeof(uint16_t);
+        crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
+        if (crc || len <= sizeof(crc)) {
+            return 0;
+        }
+        *out_off -= sizeof(crc);
+        out[*out_off] = '\0';
+
+        return 1;
+    }
+    return 0;
+}
+
+/*
+ * Task which waits reading console, expecting to get image over
+ * serial port.
+ */
+void
+boot_serial_start(int max_input)
+{
+    int rc;
+    int off;
+    char *buf;
+    char *dec;
+    int dec_off;
+    int full_line;
+
+    rc = console_init(NULL);
+    assert(rc == 0);
+    console_echo(0);
+
+    buf = os_malloc(max_input);
+    dec = os_malloc(max_input);
+    assert(buf && dec);
+
+    off = 0;
+    while (1) {
+        rc = console_read(buf + off, max_input - off, &full_line);
+        if (rc <= 0 && !full_line) {
+            continue;
+        }
+        off += rc;
+        if (!full_line) {
+            continue;
+        }
+        if (buf[0] == SHELL_NLIP_PKT_START1 &&
+          buf[1] == SHELL_NLIP_PKT_START2) {
+            dec_off = 0;
+            rc = boot_serial_in_dec(&buf[2], off - 2, dec, &dec_off, max_input);
+        } else if (buf[0] == SHELL_NLIP_DATA_START1 &&
+          buf[1] == SHELL_NLIP_DATA_START2) {
+            rc = boot_serial_in_dec(&buf[2], off - 2, dec, &dec_off, max_input);
+        }
+        if (rc == 1) {
+            boot_serial_input(&dec[2], dec_off - 2);
+        }
+        off = 0;
+    }
+}
diff --git a/boot_serial/src/boot_serial_priv.h b/boot_serial/src/boot_serial_priv.h
new file mode 100644
index 0000000..146aa6a
--- /dev/null
+++ b/boot_serial/src/boot_serial_priv.h
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __BOOTUTIL_SERIAL_PRIV_H__
+#define __BOOTUTIL_SERIAL_PRIV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * From shell.h
+ */
+#define SHELL_NLIP_PKT_START1   6
+#define SHELL_NLIP_PKT_START2   9
+
+#define SHELL_NLIP_DATA_START1  4
+#define SHELL_NLIP_DATA_START2  20
+
+/*
+ * From newtmgr.h
+ */
+#define MGMT_ERR_EINVAL         3
+
+#define NMGR_OP_READ            0
+#define NMGR_OP_WRITE           2
+
+#define NMGR_F_CBOR_RSP_COMPLETE 0x01
+
+#define MGMT_GROUP_ID_DEFAULT   0
+#define MGMT_GROUP_ID_IMAGE     1
+
+#define NMGR_ID_CONS_ECHO_CTRL  1
+#define NMGR_ID_RESET           5
+
+struct nmgr_hdr {
+    uint8_t  nh_op;             /* NMGR_OP_XXX */
+    uint8_t  nh_flags;
+    uint16_t nh_len;            /* length of the payload */
+    uint16_t nh_group;          /* NMGR_GROUP_XXX */
+    uint8_t  nh_seq;            /* sequence number */
+    uint8_t  nh_id;             /* message ID within group */
+};
+
+/*
+ * From imgmgr.h
+ */
+#define IMGMGR_NMGR_OP_STATE            0
+#define IMGMGR_NMGR_OP_UPLOAD           1
+
+
+void boot_serial_input(char *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*  __BOOTUTIL_SERIAL_PRIV_H__ */
diff --git a/boot_serial/test/pkg.yml b/boot_serial/test/pkg.yml
new file mode 100644
index 0000000..6b4b52b
--- /dev/null
+++ b/boot_serial/test/pkg.yml
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+pkg.name: boot/boot_serial/test
+pkg.type: unittest
+pkg.description: "Boot serial unit tests."
+pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - boot/boot_serial
+    - test/testutil
+
+pkg.deps.SELFTEST:
+    - sys/console/stub
diff --git a/boot_serial/test/src/boot_test.c b/boot_serial/test/src/boot_test.c
new file mode 100644
index 0000000..94efbd6
--- /dev/null
+++ b/boot_serial/test/src/boot_test.c
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "syscfg/syscfg.h"
+#include "sysflash/sysflash.h"
+#include "os/endian.h"
+#include "base64/base64.h"
+#include "crc/crc16.h"
+#include "testutil/testutil.h"
+#include "hal/hal_flash.h"
+#include "flash_map/flash_map.h"
+
+#include "boot_serial_priv.h"
+
+TEST_CASE_DECL(boot_serial_setup)
+TEST_CASE_DECL(boot_serial_empty_msg)
+TEST_CASE_DECL(boot_serial_empty_img_msg)
+TEST_CASE_DECL(boot_serial_img_msg)
+TEST_CASE_DECL(boot_serial_upload_bigger_image)
+
+void
+tx_msg(void *src, int len)
+{
+    boot_serial_input(src, len);
+}
+
+TEST_SUITE(boot_serial_suite)
+{
+    boot_serial_setup();
+    boot_serial_empty_msg();
+    boot_serial_empty_img_msg();
+    boot_serial_img_msg();
+    boot_serial_upload_bigger_image();
+}
+
+int
+boot_serial_test(void)
+{
+    boot_serial_suite();
+    return tu_any_failed;
+}
+
+#if MYNEWT_VAL(SELFTEST)
+int
+main(void)
+{
+    ts_config.ts_print_results = 1;
+    tu_init();
+
+    boot_serial_test();
+
+    return tu_any_failed;
+}
+#endif
diff --git a/boot_serial/test/src/boot_test.h b/boot_serial/test/src/boot_test.h
new file mode 100644
index 0000000..b517a04
--- /dev/null
+++ b/boot_serial/test/src/boot_test.h
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef _BOOT_TEST_H
+#define _BOOT_TEST_H
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "syscfg/syscfg.h"
+#include "sysflash/sysflash.h"
+#include "os/endian.h"
+#include "base64/base64.h"
+#include "crc/crc16.h"
+#include "testutil/testutil.h"
+#include "hal/hal_flash.h"
+#include "flash_map/flash_map.h"
+
+#include "boot_serial_priv.h"
+
+#ifdef __cplusplus
+#extern "C" {
+#endif
+
+void tx_msg(void *src, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BOOT_TEST_H */
diff --git a/boot_serial/test/src/testcases/boot_serial_empty_img_msg.c b/boot_serial/test/src/testcases/boot_serial_empty_img_msg.c
new file mode 100644
index 0000000..ff69324
--- /dev/null
+++ b/boot_serial/test/src/testcases/boot_serial_empty_img_msg.c
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "boot_test.h"
+
+TEST_CASE(boot_serial_empty_img_msg)
+{
+    char buf[sizeof(struct nmgr_hdr) + 32];
+    struct nmgr_hdr *hdr;
+
+    hdr = (struct nmgr_hdr *)buf;
+    memset(hdr, 0, sizeof(*hdr));
+    hdr->nh_op = NMGR_OP_WRITE;
+    hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
+    hdr->nh_id = IMGMGR_NMGR_OP_UPLOAD;
+    hdr->nh_len = htons(2);
+    strcpy((char *)(hdr + 1), "{}");
+
+    tx_msg(buf, sizeof(*hdr) + 2);
+}
diff --git a/boot_serial/test/src/testcases/boot_serial_empty_msg.c b/boot_serial/test/src/testcases/boot_serial_empty_msg.c
new file mode 100644
index 0000000..a4bd470
--- /dev/null
+++ b/boot_serial/test/src/testcases/boot_serial_empty_msg.c
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "boot_test.h"
+
+TEST_CASE(boot_serial_empty_msg)
+{
+    char buf[4];
+    struct nmgr_hdr hdr;
+
+    boot_serial_input(buf, 0);
+
+    tx_msg(buf, 0);
+
+    strcpy(buf, "--");
+    tx_msg(buf, 2);
+
+    memset(&hdr, 0, sizeof(hdr));
+    tx_msg(&hdr, sizeof(hdr));
+
+    hdr.nh_op = NMGR_OP_WRITE;
+
+    tx_msg(&hdr, sizeof(hdr));
+}
diff --git a/boot_serial/test/src/testcases/boot_serial_img_msg.c b/boot_serial/test/src/testcases/boot_serial_img_msg.c
new file mode 100644
index 0000000..c978650
--- /dev/null
+++ b/boot_serial/test/src/testcases/boot_serial_img_msg.c
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "boot_test.h"
+
+TEST_CASE(boot_serial_img_msg)
+{
+    char img[16];
+    char enc_img[BASE64_ENCODE_SIZE(sizeof(img)) + 1];
+    char buf[sizeof(struct nmgr_hdr) + sizeof(enc_img) + 32];
+    int len;
+    int rc;
+    struct nmgr_hdr *hdr;
+    const struct flash_area *fap;
+
+    /* 00000000  a3 64 64 61 74 61 58 10  |.ddataX.|
+     * 00000008  a5 a5 a5 a5 a5 a5 a5 a5  |........|
+     * 00000010  a5 a5 a5 a5 a5 a5 a5 a5  |........|
+     * 00000018  63 6c 65 6e 1a 00 01 14  |clen....|
+     * 00000020  e8 63 6f 66 66 00        |.coff.|
+     */
+    static const uint8_t payload[] = { 
+        0xa3, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x10,
+        /* 16 bytes of image data starts here. */
+        0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+        0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+        0x63, 0x6c, 0x65, 0x6e, 0x1a, 0x00, 0x01, 0x14,
+        0xe8, 0x63, 0x6f, 0x66, 0x66, 0x00,
+    };
+
+    memset(img, 0xa5, sizeof(img));
+
+    hdr = (struct nmgr_hdr *)buf;
+    memset(hdr, 0, sizeof(*hdr));
+    hdr->nh_op = NMGR_OP_WRITE;
+    hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
+    hdr->nh_id = IMGMGR_NMGR_OP_UPLOAD;
+
+    memcpy(hdr + 1, payload, sizeof payload);
+    hdr->nh_len = htons(sizeof payload);
+
+    len = sizeof(*hdr) + sizeof payload;
+    tx_msg(buf, len);
+
+    /*
+     * Validate contents inside image 0 slot
+     */
+    rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
+    assert(rc == 0);
+
+    rc = flash_area_read(fap, 0, enc_img, sizeof(img));
+    assert(rc == 0);
+    assert(!memcmp(enc_img, img, sizeof(img)));
+}
diff --git a/boot_serial/test/src/testcases/boot_serial_setup.c b/boot_serial/test/src/testcases/boot_serial_setup.c
new file mode 100644
index 0000000..791e845
--- /dev/null
+++ b/boot_serial/test/src/testcases/boot_serial_setup.c
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "boot_test.h"
+
+TEST_CASE(boot_serial_setup)
+{
+
+}
diff --git a/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c b/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c
new file mode 100644
index 0000000..9f326b8
--- /dev/null
+++ b/boot_serial/test/src/testcases/boot_serial_upload_bigger_image.c
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <tinycbor/cborconstants_p.h>
+
+#include "boot_test.h"
+
+TEST_CASE(boot_serial_upload_bigger_image)
+{
+    char img[256];
+    char enc_img[64];
+    char buf[sizeof(struct nmgr_hdr) + 128];
+    int len;
+    int off;
+    int rc;
+    struct nmgr_hdr *hdr;
+    const struct flash_area *fap;
+    int i;
+
+    const int payload_off = sizeof *hdr;
+    const int img_data_off = payload_off + 8;
+
+    /* 00000000  a3 64 64 61 74 61 58 20  |.ddataX.|
+     * 00000008  00 00 00 00 00 00 00 00  |........|
+     * 00000010  00 00 00 00 00 00 00 00  |........|
+     * 00000018  00 00 00 00 00 00 00 00  |........|
+     * 00000020  00 00 00 00 00 00 00 00  |........|
+     * 00000028  63 6c 65 6e 1a 00 01 14  |clen....|
+     * 00000030  e8 63 6f 66 66 00        |.coff.|
+     */
+    static const uint8_t payload_first[] = {
+        0xa3, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x20,
+        /* 32 bytes of image data starts here. */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x63, 0x6c, 0x65, 0x6e, 0x1a, 0x00, 0x01, 0x14,
+        0xe8, 0x63, 0x6f, 0x66, 0x66, 0x00,
+    };
+
+    /* 00000000  a3 64 64 61 74 61 58 20  |.ddataX.|
+     * 00000008  00 00 00 00 00 00 00 00  |........|
+     * 00000010  00 00 00 00 00 00 00 00  |........|
+     * 00000018  00 00 00 00 00 00 00 00  |........|
+     * 00000020  00 00 00 00 00 00 00 00  |........|
+     * 00000028  63 6f 66 66 00 00        |coff..|
+     */
+    static const uint8_t payload_next[] = {
+        0xa2, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x20,
+        /* 32 bytes of image data starts here. */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x63, 0x6f, 0x66, 0x66,
+        /* 2 bytes of offset value starts here. */
+        0x00, 0x00
+    };
+
+    for (i = 0; i < sizeof(img); i++) {
+        img[i] = i;
+    }
+
+    for (off = 0; off < sizeof(img); off += 32) {
+        hdr = (struct nmgr_hdr *)buf;
+        memset(hdr, 0, sizeof(*hdr));
+        hdr->nh_op = NMGR_OP_WRITE;
+        hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
+        hdr->nh_id = IMGMGR_NMGR_OP_UPLOAD;
+
+        if (off) {
+            memcpy(buf + payload_off, payload_next, sizeof payload_next);
+            len = sizeof payload_next;
+            buf[payload_off + len - 2] = Value8Bit;
+            buf[payload_off + len - 1] = off;
+        } else {
+            memcpy(buf + payload_off, payload_first, sizeof payload_first);
+            len = sizeof payload_first;
+        }
+        memcpy(buf + img_data_off, img + off, 32);
+        hdr->nh_len = htons(len);
+
+        len = sizeof(*hdr) + len;
+
+        tx_msg(buf, len);
+    }
+
+    /*
+     * Validate contents inside image 0 slot
+     */
+    rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
+    assert(rc == 0);
+
+    for (off = 0; off < sizeof(img); off += sizeof(enc_img)) {
+        rc = flash_area_read(fap, off, enc_img, sizeof(enc_img));
+        assert(rc == 0);
+        assert(!memcmp(enc_img, &img[off], sizeof(enc_img)));
+    }
+}
diff --git a/boot_serial/test/syscfg.yml b/boot_serial/test/syscfg.yml
new file mode 100644
index 0000000..c982db5
--- /dev/null
+++ b/boot_serial/test/syscfg.yml
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Package: boot/boot_serial/test
+
+syscfg.vals: