#include "sdkconfig.h" #include #include "cli.h" #include #include "driver/flash.h" #include "modules/ota.h" #if CONFIG_SECURITY_OTA #include "_ota.h" #endif #include "utils_httpc.h" #include "modules/wifi.h" #include #include "partitions.h" #include "CheckSumUtils.h" #include "security_ota.h" #include #include #define OTA_MAGIC_WORD "\x42\x4B\x37\x32\x33\x36\x35\x38" #define MANIFEST_SIZE (4 * 1024) extern void vPortEnableTimerInterrupt( void ); extern void vPortDisableTimerInterrupt( void ); static ota_parse_t ota_parse = {0}; #define TAG "ota" #if (CONFIG_TFM_FWU) #if CONFIG_INT_WDT #include #include #endif #include "sys_ctrl/sys_driver.h" void wdt_init(void); static uint32_t ota_image_flag = 0; const ota_partition_info_t s_ota_partition_info[] = { {CONFIG_PRIMARY_MANIFEST_PHY_PARTITION_OFFSET, CONFIG_PRIMARY_MANIFEST_PHY_PARTITION_SIZE, FWU_IMAGE_TYPE_PRIMARY_MANIFEST}, {CONFIG_SECONDARY_MANIFEST_PHY_PARTITION_OFFSET, CONFIG_SECONDARY_MANIFEST_PHY_PARTITION_SIZE, FWU_IMAGE_TYPE_SECONDARY_MANIFEST}, {CONFIG_PRIMARY_BL2_PHY_PARTITION_OFFSET, CONFIG_PRIMARY_BL2_PHY_PARTITION_SIZE, FWU_IMAGE_TYPE_PRIMARY_BL2}, {CONFIG_SECONDARY_BL2_PHY_PARTITION_OFFSET, CONFIG_SECONDARY_BL2_PHY_PARTITION_SIZE, FWU_IMAGE_TYPE_SECONDARY_BL2}, #if CONFIG_DIRECT_XIP {CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET, CONFIG_PRIMARY_ALL_PHY_PARTITION_SIZE, FWU_IMAGE_TYPE_FULL}, #endif #if CONFIG_OTA_OVERWRITE {CONFIG_OTA_PHY_PARTITION_OFFSET, CONFIG_OTA_PHY_PARTITION_SIZE, FWU_IMAGE_TYPE_FULL}, #endif {CONFIG_SECONDARY_ALL_PHY_PARTITION_OFFSET, CONFIG_SECONDARY_ALL_PHY_PARTITION_SIZE, FWU_IMAGE_TYPE_FULL} }; static void security_ota_dump_partition_info(void) { BK_LOGI(TAG, "%8s %8s %8s\r\n", "offset", "size", "fwu_id"); for (uint32_t partition_id = 0; partition_id < sizeof(s_ota_partition_info)/sizeof(ota_partition_info_t); partition_id++) { const ota_partition_info_t *p = &s_ota_partition_info[partition_id]; BK_LOGI(TAG, "%8x %8x %-6d\r\n", p->partition_offset, p->partition_size, p->fwu_image_id); } } static const ota_partition_info_t* security_ota_get_partition_info(void) { uint32_t flash_offset; if (ota_parse.phase != OTA_PARSE_IMG || ota_parse.index >= ota_parse.ota_header.image_num) { return NULL; } flash_offset = ota_parse.ota_image_header[ota_parse.index].flash_offset; for (uint32_t partition_id = 0; partition_id < sizeof(s_ota_partition_info)/sizeof(ota_partition_info_t); partition_id++) { if (flash_offset == s_ota_partition_info[partition_id].partition_offset) { return &s_ota_partition_info[partition_id]; } } return NULL; } static uint32_t security_ota_get_fwu_image_id(void) { const ota_partition_info_t *partition_info = security_ota_get_partition_info(); if (!partition_info) { return FWU_IMAGE_TYPE_INVALID; } //TODO for BL2, update image_id per boot_flag return partition_info->fwu_image_id; } static psa_image_id_t security_ota_fwu2psa_image_id(uint32_t fwu_image_id) { return (psa_image_id_t)FWU_CALCULATE_IMAGE_ID(FWU_IMAGE_ID_SLOT_STAGE, fwu_image_id, 0); } int bk_ota_check(psa_image_id_t ota_image) { psa_status_t status; psa_image_id_t dependency_uuid; psa_image_version_t dependency_version; psa_image_info_t info; #if CONFIG_INT_WDT bk_wdt_stop(); bk_task_wdt_stop(); #endif status = psa_fwu_query(ota_image, &info); if (status != PSA_SUCCESS) { BK_LOGE(TAG, "query status %d\r\n", status); goto _ret_fail; } if (info.state != PSA_IMAGE_CANDIDATE) { BK_LOGE(TAG, "info state %d\r\n", info.state); goto _ret_fail; } status = psa_fwu_install(ota_image, &dependency_uuid, &dependency_version); if (status != PSA_SUCCESS_REBOOT) { BK_LOGE(TAG, "install fail %d\r\n", status); goto _ret_fail; } status = psa_fwu_query(ota_image, &info); if (status != PSA_SUCCESS) { BK_LOGE(TAG, "query fail %d\r\n", status); goto _ret_fail; } if (info.state != PSA_IMAGE_REBOOT_NEEDED) { BK_LOGE(TAG, "info fail %d\r\n", info.state); goto _ret_fail; } #if CONFIG_INT_WDT bk_wdt_start(CONFIG_INT_WDT_PERIOD_MS); #endif return 0; _ret_fail: #if CONFIG_INT_WDT wdt_init(); #endif return -1; } void bk_ota_set_flag(uint32_t flag) { ota_image_flag |= flag; } uint32_t bk_ota_get_flag(void) { return ota_image_flag; } void bk_ota_clear_flag(void) { ota_image_flag = 0; } void bk_ota_accept_image(void) { int32_t ns_interface_lock_init(void); psa_image_id_t psa_image_id = (psa_image_id_t)FWU_CALCULATE_IMAGE_ID(FWU_IMAGE_ID_SLOT_ACTIVE, FWU_IMAGE_TYPE_FULL, 0); BK_LOGI(TAG, "accept image\r\n"); ns_interface_lock_init(); psa_fwu_accept(psa_image_id); } #endif // (CONFIG_TFM_FWU) static int security_ota_parse_header(uint8_t **data, int *len); static int security_ota_parse_image_header(uint8_t **data, int *len); static int security_ota_parse_header(uint8_t **data, int *len) { uint32_t data_len, offset; uint8_t *tmp; if (*len == 0) return 0; if (ota_parse.offset == 0) { BK_LOGI(TAG, "downloading OTA global header...\r\n"); } tmp = (uint8_t *)&ota_parse.ota_header; data_len = sizeof(ota_header_t) - ota_parse.offset; if (*len < data_len) { os_memcpy(tmp + ota_parse.offset, *data, *len); ota_parse.offset += *len; return 0; } else { os_memcpy(tmp + ota_parse.offset, *data, data_len); *data += data_len; *len -= data_len; //check global header magic code! if(os_memcmp(OTA_MAGIC_WORD,tmp,8) != 0){ BK_LOGE(TAG, "magic error\r\n"); return BK_ERR_OTA_HDR_MAGIC; } /*calculate global header crc*/ offset = sizeof(ota_parse.ota_header.magic) + sizeof(ota_parse.ota_header.crc); tmp += offset; CRC32_Update(&ota_parse.ota_crc, tmp, sizeof(ota_header_t) - offset); /*to next parse*/ ota_parse.phase = OTA_PARSE_IMG_HEADER; ota_parse.offset = 0; if (ota_parse.ota_image_header) { os_free(ota_parse.ota_image_header); } offset = ota_parse.ota_header.image_num * sizeof(ota_image_header_t); ota_parse.ota_image_header = (ota_image_header_t *)os_malloc(offset); if (!ota_parse.ota_image_header) { BK_LOGE(TAG, "ota parse image header: oom\r\n"); return BK_ERR_OTA_OOM; } BK_LOGI(TAG, "crc %x, version %x, header_len %x, image_num %x\r\n", ota_parse.ota_header.crc, ota_parse.ota_header.version, ota_parse.ota_header.header_len, ota_parse.ota_header.image_num); } return 0; } static int security_ota_parse_image_header(uint8_t **data, int *len) { int i; uint32_t data_len, offset, crc_control; uint8_t *tmp; if (*len == 0) return 0; if (ota_parse.offset == 0) { BK_LOGI(TAG, "downloading OTA image header...\r\n"); } tmp = (uint8_t *)ota_parse.ota_image_header; data_len = ota_parse.ota_header.image_num * sizeof(ota_image_header_t) - ota_parse.offset; if (*len < data_len) { os_memcpy(tmp + ota_parse.offset, *data, *len); ota_parse.offset += *len; return 0; } else { os_memcpy(tmp + ota_parse.offset, *data, data_len); *data += data_len; *len -= data_len; /*calculate header crc*/ offset = ota_parse.ota_header.image_num * sizeof(ota_image_header_t); CRC32_Update(&ota_parse.ota_crc, tmp, offset); //TODO check image CRC! CRC32_Final(&ota_parse.ota_crc,&crc_control); if(crc_control != ota_parse.ota_header.crc){ BK_LOGE(TAG, "crc error\r\n"); return BK_ERR_OTA_IMG_HDR_CRC; } /*to next parse*/ ota_parse.phase = OTA_PARSE_IMG; ota_parse.offset = 0; for (i = 0; i < ota_parse.ota_header.image_num; i++) { BK_LOGI(TAG, "image[%d], image_len=%x, image_offset=%x, flash_offset=%x\r\n", i, ota_parse.ota_image_header[i].image_len, ota_parse.ota_image_header[i].image_offset, ota_parse.ota_image_header[i].flash_offset); } } return 0; } uint32_t get_http_flash_wr_buf_max(void); static void security_ota_write_flash(uint8_t **data, uint32_t len, uint32_t psa_image_id) { uint32_t copy_len; uint32_t data_idx = 0; uint32_t http_flash_wr_buf_max = get_http_flash_wr_buf_max(); while(data_idx < len){ copy_len = min(len-(data_idx),http_flash_wr_buf_max - bk_http_ptr->wr_last_len); os_memcpy(bk_http_ptr->wr_buf + bk_http_ptr->wr_last_len, *data + data_idx, copy_len); data_idx += copy_len; bk_http_ptr->wr_last_len += copy_len; if(bk_http_ptr->wr_last_len >= http_flash_wr_buf_max){ #if CONFIG_TFM_FWU psa_fwu_write(psa_image_id, ota_parse.write_offset, (const void *)bk_http_ptr->wr_buf, http_flash_wr_buf_max); #else extern void bk_flash_xip_update(uint32_t off, const void *src, uint32_t len); bk_flash_xip_update(ota_parse.write_offset, (const void *)bk_http_ptr->wr_buf, http_flash_wr_buf_max); #endif ota_parse.write_offset += http_flash_wr_buf_max; bk_http_ptr->wr_last_len = 0; } } } static int security_ota_handle_image(uint8_t **data, int *len) { uint32_t image_crc; vPortDisableTimerInterrupt(); do { bk_wdt_feed(); if (ota_parse.offset == 0) { BK_LOGI(TAG, "downloading OTA image%d, expected data len=%x...\r\n", ota_parse.index, ota_parse.ota_image_header[ota_parse.index].image_len); ota_parse.percent = 0; CRC32_Init(&ota_parse.ota_crc); } #if CONFIG_TFM_FWU uint32_t fwu_image_id = security_ota_get_fwu_image_id(); if (fwu_image_id == FWU_IMAGE_TYPE_INVALID) { if (*len) { BK_LOGE(TAG, "Invalid image ID, parse index=%d, parse offset=%x, len=%d, total_rx_len=%x\r\n", ota_parse.index, ota_parse.offset, *len, ota_parse.total_rx_len); vPortEnableTimerInterrupt(); return BK_ERR_OTA_IMG_ID; } vPortEnableTimerInterrupt(); return BK_OK; } bk_ota_set_flag(BIT(fwu_image_id)); psa_image_id_t psa_image_id = security_ota_fwu2psa_image_id(fwu_image_id); #else uint32_t psa_image_id = 0; #endif uint32_t image_len = ota_parse.ota_image_header[ota_parse.index].image_len; uint32_t data_len = image_len - ota_parse.offset; if (ota_parse.offset >= (image_len/10 + image_len*ota_parse.percent/100)) { ota_parse.percent += 10; if (ota_parse.percent < 100) { BK_LOGI(TAG, "download %d%%\r\n", ota_parse.percent); } } if (*len < data_len) { security_ota_write_flash(data, *len, psa_image_id); CRC32_Update(&ota_parse.ota_crc,*data,*len); ota_parse.offset += *len; *len = 0; } else { security_ota_write_flash(data, *len, psa_image_id); uint32_t align_len = (((bk_http_ptr->wr_last_len) + ((32) - 1)) & ~((32) - 1)); // align_up 32 memset(bk_http_ptr->wr_buf + bk_http_ptr->wr_last_len,0xFF,align_len - bk_http_ptr->wr_last_len); #if CONFIG_TFM_FWU psa_fwu_write(psa_image_id, ota_parse.write_offset, (const void *)bk_http_ptr->wr_buf, align_len); #else extern void bk_flash_xip_update(uint32_t off, const void *src, uint32_t len); bk_flash_xip_update(ota_parse.write_offset, (const void *)bk_http_ptr->wr_buf, align_len); #endif bk_http_ptr->wr_last_len = 0; CRC32_Update(&ota_parse.ota_crc,*data,*len); *data += data_len; *len = 0; BK_LOGI(TAG, "downloaded OTA image%d\r\n", ota_parse.index); //check image CRC, then we can abort quickly! CRC32_Final(&ota_parse.ota_crc,&image_crc); if(image_crc != ota_parse.ota_image_header[ota_parse.index].checksum){ BK_LOGE(TAG, "image crc error!\r\n"); vPortEnableTimerInterrupt(); return BK_ERR_OTA_IMG_CRC; } /*to next image*/ BK_LOGI(TAG, "\r\n"); ota_parse.index++; ota_parse.offset = 0; ota_parse.write_offset = 0; } } while(*len); vPortEnableTimerInterrupt(); return BK_OK; } int security_ota_parse_data(char *data, int len) { int ret = 0; ota_parse.total_rx_len += len; if (ota_parse.phase == OTA_PARSE_HEADER) { ret = security_ota_parse_header((uint8_t **)&data, &len); if (ret != BK_OK) return ret; } if (ota_parse.phase == OTA_PARSE_IMG_HEADER) { ret = security_ota_parse_image_header((uint8_t **)&data, &len); if (ret != BK_OK) return ret; } if (ota_parse.phase == OTA_PARSE_IMG) { if (len == 0) return 0; ret = security_ota_handle_image((uint8_t **)&data, &len); if (ret != BK_OK) return ret; } return BK_OK; } void security_ota_init(void) { if (ota_parse.phase != OTA_PARSE_HEADER) { BK_LOGI(TAG, "abort previous OTA\r\n"); #if CONFIG_TFM_FWU psa_image_id_t id = security_ota_fwu2psa_image_id(FWU_IMAGE_TYPE_FULL); psa_fwu_abort(id); #endif } bk_flash_set_protect_type(FLASH_PROTECT_NONE); #if CONFIG_TFM_FWU security_ota_dump_partition_info(); bk_ota_clear_flag(); #else extern void bk_flash_xip_erase(void); bk_flash_xip_erase(); #endif os_memset(&ota_parse, 0, sizeof(ota_parse_t)); CRC32_Init(&ota_parse.ota_crc); if (!bk_http_ptr->wr_buf) { bk_http_ptr->wr_buf = (uint8_t*)os_malloc(4096 * sizeof(char)); } bk_http_ptr->wr_last_len = 0; } int security_ota_deinit(void) { if (ota_parse.ota_image_header) { os_free(ota_parse.ota_image_header); ota_parse.ota_image_header = NULL; } os_free(bk_http_ptr->wr_buf); bk_http_ptr->wr_buf = NULL; return 0; } int security_ota_finish(void) { #if (CONFIG_TFM_FWU) int ret; psa_image_id_t psa_image_id = 0; uint8_t fwu_image_id = 0; uint32_t ota_flags = bk_ota_get_flag(); while (ota_flags) { if (ota_flags & 1) { #if CONFIG_DIRECT_XIP /*when run in B cannot read A,so don't check A*/ BK_LOGI(TAG, "reboot\r\n"); psa_fwu_request_reboot(); #endif BK_LOGI(TAG, "checking fwu image%d...\r\n", fwu_image_id); psa_image_id = (psa_image_id_t)FWU_CALCULATE_IMAGE_ID(FWU_IMAGE_ID_SLOT_STAGE, fwu_image_id, 0); ret = bk_ota_check(psa_image_id); if (ret != BK_OK) { BK_LOGI(TAG, "check fwu image%d failed\r\n", fwu_image_id); return BK_FAIL; } else { BK_LOGI(TAG, "check fwu image%d success\r\n", fwu_image_id); } } ota_flags >>= 1; fwu_image_id++; } BK_LOGI(TAG, "reboot\r\n"); psa_fwu_request_reboot(); #else // CONFIG_TFM_FWU #if CONFIG_DIRECT_XIP extern uint32_t flash_get_excute_enable(); uint32_t update_id = (flash_get_excute_enable() ^ 1); uint32_t fa_addr; if (update_id == 0) { fa_addr = CONFIG_PRIMARY_ALL_PHY_PARTITION_OFFSET; } else { fa_addr = CONFIG_SECONDARY_ALL_PHY_PARTITION_OFFSET; } uint32_t fa_size = CONFIG_PRIMARY_ALL_PHY_PARTITION_SIZE; uint32_t copy_done_offset = CEIL_ALIGN_34(fa_addr + fa_size - 4096) + 32; uint32_t status = XIP_SET; const uint8_t * value = (const uint8_t *)&(status); bk_flash_write_bytes(copy_done_offset,value,sizeof(value)); #endif // CONFIG_DIRECT_XIP bk_reboot_ex(RESET_SOURCE_OTA_REBOOT); #endif /* CONFIG_TFM_FWU*/ return BK_OK; }