123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- /*
- * Copyright (c) 2019 Actions Semiconductor Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @file
- * @brief OTA SDCARD backend interface
- */
- #include <kernel.h>
- #include <string.h>
- #include <drivers/flash.h>
- #include <partition/partition.h>
- #include <mem_manager.h>
- #include <ota_backend.h>
- #include <ota_backend_temp_part.h>
- #include <os_common_api.h>
- #include <drivers/mmc/sd.h>
- #ifdef CONFIG_OTA_LZMA
- #include <minlzma.h>
- #endif
- #ifdef CONFIG_WATCHDOG
- #include <watchdog_hal.h>
- #endif
- enum ota_backend_temp_type {
- OTA_BACKEND_SPINOR,
- OTA_BACKEND_SD,
- OTA_BACKEND_NAND,
- };
- #define OTA_BACKEND_SD_SECTOR_SIZE (512)
- #define CONFIG_MMC_SDCARD_DEV_NAME "sd"
- #define CONFIG_SPINAND_DEV_NAME "spinand"
- struct ota_backend_temp_part {
- struct ota_backend backend;
- const struct device *dev;
- const char *dev_name;
- uint32_t offset;
- int size;
- int type; // refer to enum ota_backend_temp_type
- int lzma; // lzma compress flag
- };
- #define IMAGE_MAGIC0 0x48544341
- #define IMAGE_MAGIC1 0x41435448
- typedef struct image_head {
- uint32_t ih_magic0;
- uint32_t ih_magic1; //
- uint32_t ih_load_addr; /*load addr, include header*/
- uint8_t ih_name[8]; //
- uint32_t ih_entry;
- uint32_t ih_img_size;
- uint32_t ih_img_chksum; /*if not sign, use check sum??ih_img_size not include header */
- uint32_t ih_hdr_chksum; /* include header. */
- uint16_t ih_hdr_size; /* Size of image header (bytes). */
- uint16_t ih_ptlv_size; /* Size of protected TLV area (bytes). */
- uint16_t ih_tlv_size; /*tlv size*/
- uint16_t ih_version;
- uint32_t ih_flags;
- uint8_t ih_ext_ictype[7];
- uint8_t ih_storage_type; // mbrec
- }image_head_t;
- #if CONFIG_PSRAM_SIZE >= 4096
- #define LZMA_IN_MAX (1536*1024)
- #define LZMA_OUT_MAX (2048*1024)
- #elif CONFIG_PSRAM_SIZE >= 1024
- #define LZMA_IN_MAX (256*1024)
- #define LZMA_OUT_MAX (256*1024)
- #else
- #define LZMA_IN_MAX (32*1024)
- #define LZMA_OUT_MAX (32*1024)
- #endif
- static uint8_t __in_section_unique(noinit) lzma_inbuf[LZMA_IN_MAX];
- static uint8_t __in_section_unique(noinit) lzma_outbuf[LZMA_OUT_MAX];
- static uint32_t lzma_inoff = 0;
- static uint32_t lzma_outoff = 0xffffffff;
- static int temp_part_read_flash(struct ota_backend_temp_part *ob_tp, int offset, uint8_t *buf, int size)
- {
- int err = 0;
- uint32_t offs = ob_tp->offset + offset;
- uint32_t head, count, left;
- uint8_t *buffer = NULL;
-
- SYS_LOG_DBG("dev %s: offset 0x%x, size 0x%x, buf %p",
- ob_tp->dev_name, offset, size, buf);
- if ((offset + size) > ob_tp->size) {
- SYS_LOG_ERR("offs 0x%x size 0x%x is too big, max size 0x%x",
- offset, size, ob_tp->size);
- return -EINVAL;
- }
- if (ob_tp->type == OTA_BACKEND_SD || ob_tp->type == OTA_BACKEND_NAND) {
- head = ROUND_UP(offs, OTA_BACKEND_SD_SECTOR_SIZE) - offs;
- size = (size > head) ? (size - head): 0;
- count = size / OTA_BACKEND_SD_SECTOR_SIZE;
- left = size % OTA_BACKEND_SD_SECTOR_SIZE;
- offs /= OTA_BACKEND_SD_SECTOR_SIZE;
- if (head || left) {
- buffer = (uint8_t *)mem_malloc(OTA_BACKEND_SD_SECTOR_SIZE);
- if (!buffer) {
- SYS_LOG_ERR("can not malloc %d size", OTA_BACKEND_SD_SECTOR_SIZE);
- return -ENOMEM;
- }
- }
- if (head && !err) {
- err = flash_read(ob_tp->dev, offs<<9, buffer, 1<<9);
- if (err) {
- SYS_LOG_ERR("read error %d, offs 0x%x, count %d",
- err, offs, count);
- err = -EIO;
- }
- memcpy(buf, buffer + OTA_BACKEND_SD_SECTOR_SIZE - head, head);
- buf += head;
- offs += 1;
- }
- if (count && !err) {
- err = flash_read(ob_tp->dev, offs<<9, buf, count<<9);
- if (err) {
- SYS_LOG_ERR("read error %d, offs 0x%x, count %d",
- err, offs, count);
- err = -EIO;
- }
- buf += (count * OTA_BACKEND_SD_SECTOR_SIZE);
- offs += count;
- }
- if (left && !err) {
- err = flash_read(ob_tp->dev, offs<<9, buffer, 1<<9);
- if (err) {
- SYS_LOG_ERR("read error %d, offs 0x%x, count %d",
- err, offs, count);
- err = -EIO;
- }
- memcpy(buf, buffer, left);
- }
- if (buffer) {
- mem_free(buffer);
- }
- } else {
- err = flash_read(ob_tp->dev, offs, buf, size);
- if (err) {
- SYS_LOG_ERR("read error %d, offs 0x%x, buf %p, size 0x%x",
- err, offset, buf, size);
- return -EIO;
- }
- }
- return err;
- }
- static int temp_part_read_lzma(struct ota_backend_temp_part *ob_tp, int offset, uint8_t *buf, int size)
- {
- int err, ret;
- uint32_t out_off, out_size;
- lzma_head_t *plzma_h = (lzma_head_t *)lzma_inbuf;
- // read first part from lzma buffer
- if ((offset >= lzma_outoff) && (offset < (lzma_outoff + LZMA_OUT_MAX))) {
- if ((offset + size) > (lzma_outoff + LZMA_OUT_MAX)) {
- out_size = lzma_outoff + LZMA_OUT_MAX - offset;
- memcpy(buf, lzma_outbuf+offset-lzma_outoff, out_size);
- buf += out_size;
- offset += out_size;
- size -= out_size;
- }
- }
- // check size
- if (size <= 0) {
- return 0;
- }
- // check offset
- if ((offset < lzma_outoff) || (offset >= (lzma_outoff + LZMA_OUT_MAX))) {
- // init lzma block
- if (offset < lzma_outoff) {
- lzma_inoff = 0;
- out_off = 0;
- } else {
- out_off = lzma_outoff;
- }
- // search lzma block
- while (1) {
- // read lzma header
- err = temp_part_read_flash(ob_tp, lzma_inoff, (uint8_t*)plzma_h, sizeof(lzma_head_t));
- if (err) {
- return -1;
- }
- // check lzma magic
- if (plzma_h->ih_magic != LZMA_MAGIC) {
- SYS_LOG_ERR("lzma error magic: 0x%x", plzma_h->ih_magic);
- return -1;
- }
- // check out offset
- if ((offset >= out_off) && (offset < (out_off + LZMA_OUT_MAX))) {
- break;
- }
- // next lzma block
- lzma_inoff += plzma_h->ih_hdr_size + plzma_h->ih_img_size;
- out_off += plzma_h->ih_org_size;
- }
- // check lzma buffer size
- if (plzma_h->ih_org_size > LZMA_OUT_MAX) {
- SYS_LOG_ERR("lzma buffer too small! size 0x%x", LZMA_OUT_MAX);
- return -1;
- }
- // read lzma img
- err = temp_part_read_flash(ob_tp, lzma_inoff, lzma_inbuf, plzma_h->ih_hdr_size+plzma_h->ih_img_size);
- if (err) {
- return -1;
- }
- #ifdef CONFIG_WATCHDOG
- watchdog_clear();
- #endif
- // lzma decompress
- out_size = LZMA_OUT_MAX;
- #ifdef CONFIG_OTA_LZMA
- ret = XzDecode(lzma_inbuf+plzma_h->ih_hdr_size, plzma_h->ih_img_size, lzma_outbuf, &out_size);
- #else
- ret = 0;
- #endif
- if (ret == 0) {
- SYS_LOG_ERR("XzDecode error! size 0x%x", out_size);
- return -2;
- }
- // check origin size
- if (out_size != plzma_h->ih_org_size) {
- SYS_LOG_ERR("XzDecode out_size mismatch! 0x%x", out_size);
- return -3;
- }
- lzma_outoff = out_off;
- SYS_LOG_INF("XzDecode 0x%x ok! 0x%x -> 0x%x", out_off, plzma_h->ih_img_size, plzma_h->ih_org_size);
- }
- // read last part from lzma buffer
- memcpy(buf, lzma_outbuf+offset-lzma_outoff, size);
- return 0;
- }
- static int ota_backend_temp_part_prepare(struct ota_backend_temp_part *ob_tp)
- {
- int err;
- uint32_t inner_offset = 0;
- image_head_t *pimg_h = (image_head_t *)lzma_inbuf;
- lzma_head_t *plzma_h = (lzma_head_t *)lzma_inbuf;
- // init lzma flag
- ob_tp->lzma = 0;
- // read image header
- err = temp_part_read_flash(ob_tp, 0, (uint8_t*)pimg_h, sizeof(image_head_t));
- if (err) {
- return -1;
- }
- // check ota_app
- if ((pimg_h->ih_magic0 == IMAGE_MAGIC0) && (pimg_h->ih_magic1 == IMAGE_MAGIC1)) {
- inner_offset = pimg_h->ih_hdr_size + pimg_h->ih_img_size;
- inner_offset = (inner_offset + OTA_BACKEND_SD_SECTOR_SIZE - 1) & ~(OTA_BACKEND_SD_SECTOR_SIZE - 1);
- SYS_LOG_INF("found app! temp inner offset: 0x%x", inner_offset);
- }
-
- // update temp offset and size
- if (inner_offset > 0) {
- ob_tp->offset += inner_offset;
- ob_tp->size -= inner_offset;
- }
- // read lzma header
- err = temp_part_read_flash(ob_tp, 0, (uint8_t*)plzma_h, sizeof(lzma_head_t));
- if (err) {
- return -1;
- }
- // check lzma header
- if (plzma_h->ih_magic == LZMA_MAGIC) {
- // set lzma flag
- ob_tp->lzma = 1;
- SYS_LOG_INF("found lzma!");
- }
- return 0;
- }
- int ota_backend_temp_part_read(struct ota_backend *backend, int offset, uint8_t *buf, int size)
- {
- struct ota_backend_temp_part *ob_tp = CONTAINER_OF(backend,
- struct ota_backend_temp_part, backend);
- int err = 0;
- // check lzma flag
- if (ob_tp->lzma) {
- err = temp_part_read_lzma(ob_tp, offset, buf, size);
- } else {
- err = temp_part_read_flash(ob_tp, offset, buf, size);
- }
- return err;
- }
- int ota_backend_temp_part_open(struct ota_backend *backend)
- {
- #if CONFIG_LOG
- struct ota_backend_temp_part *backend_temp_part = CONTAINER_OF(backend,
- struct ota_backend_temp_part, backend);
- SYS_LOG_INF("dev %s: open: type %d", backend_temp_part->dev_name, backend->type);
- #endif
- return 0;
- }
- int ota_backend_temp_part_close(struct ota_backend *backend)
- {
- #if CONFIG_LOG
- struct ota_backend_temp_part *backend_temp_part = CONTAINER_OF(backend,
- struct ota_backend_temp_part, backend);
- SYS_LOG_INF("dev %s: close: type %d", backend_temp_part->dev_name, backend->type);
- #endif
- return 0;
- }
- void ota_backend_temp_part_exit(struct ota_backend *backend)
- {
- struct ota_backend_temp_part *backend_temp_part = CONTAINER_OF(backend,
- struct ota_backend_temp_part, backend);
- SYS_LOG_INF("dev %s: exit: type %d", backend_temp_part->dev_name, backend->type);
- mem_free(backend_temp_part);
- }
- const struct ota_backend_api ota_backend_api_temp_part = {
- .init = (void *)ota_backend_temp_part_init,
- .exit = ota_backend_temp_part_exit,
- .open = ota_backend_temp_part_open,
- .close = ota_backend_temp_part_close,
- .read = ota_backend_temp_part_read,
- };
- struct ota_backend *ota_backend_temp_part_init(ota_backend_notify_cb_t cb,
- struct ota_backend_temp_part_init_param *param)
- {
- struct ota_backend_temp_part *backend_temp_part;
- const struct partition_entry *temp_part;
- const struct device *temp_part_dev;
- SYS_LOG_INF("init backend %s\n", param->dev_name);
- temp_part_dev = device_get_binding(param->dev_name);
- if (!temp_part_dev) {
- SYS_LOG_ERR("cannot found temp part device %s", param->dev_name);
- return NULL;
- }
- temp_part = partition_get_temp_part();
- if (temp_part == NULL) {
- SYS_LOG_ERR("cannot found temp partition to store ota fw");
- return NULL;
- }
- SYS_LOG_INF("temp partition offset 0x%x, size 0x%x\n",
- temp_part->offset, temp_part->size);
- backend_temp_part = mem_malloc(sizeof(struct ota_backend_temp_part));
- if (!backend_temp_part) {
- SYS_LOG_ERR("malloc failed");
- return NULL;
- }
- memset(backend_temp_part, 0x0, sizeof(struct ota_backend_temp_part));
- backend_temp_part->dev = temp_part_dev;
- backend_temp_part->dev_name = param->dev_name;
- backend_temp_part->offset = temp_part->offset;
- backend_temp_part->size = temp_part->size;
- if (!strcmp(param->dev_name, CONFIG_MMC_SDCARD_DEV_NAME)) {
- backend_temp_part->type = OTA_BACKEND_SD;
- #ifdef CONFIG_MMC
- if (sd_card_storage_init(backend_temp_part->dev)) {
- SYS_LOG_ERR("init sd device error");
- return NULL;
- }
- #endif
- } else if (!strcmp(param->dev_name, CONFIG_SPINAND_DEV_NAME)) {
- backend_temp_part->type = OTA_BACKEND_NAND;
- } else {
- backend_temp_part->type = OTA_BACKEND_SPINOR;
- }
- ota_backend_temp_part_prepare(backend_temp_part);
-
- ota_backend_init(&backend_temp_part->backend, OTA_BACKEND_TYPE_TEMP_PART,
- (struct ota_backend_api *)&ota_backend_api_temp_part, cb);
- /* spinor backend detected, notify app */
- cb(&backend_temp_part->backend, OTA_BACKEND_UPGRADE_STATE, 1);
- return &backend_temp_part->backend;
- }
|