驱动函数需要修改一个文件rt_fota.c,添加内部flash操作相关文件,删除外部flash操作相关文件,移植过程注意事项及其它外设移植细节参见 移植完整版RT-Thread到GD32F4XX(详细) 中关于bootloader及flash移植相关内容,移植完成后使用及验证方法同stm32
原开源项目位于https://gitee.com/spunky_973/rt-fota,只适配了stm32f4系列,未实现hash校验;本博客所做改动仅为适配GD32F4XX系列,及添加了hash校验(已提交PR),同时修改片外升级为片内升级,进一步缩小bootloader大小,开源地址为https://gitee.com/yangfei_addoil/rt-fota-gd32
//添加hash校验 通过RT_FOTA_USE_HASH进行开启关闭
//hash fnv1a
#define FNV_SEED 0x811c9dc5
#define DATA_LEN 355232
int rt_fota_check_hash(const char *part_name);
static uint32_t fnv1a_r(uint8_t oneByte, uint32_t hash)
{
return ((oneByte ^ hash) * 0x1000193);
}
static uint32_t calc(uint8_t * data, uint32_t hash, long len)
{
for (int i = 0; i < len; i++)
{
hash = fnv1a_r(data[i], hash);
}
return hash;
}
#ifdef RT_FOTA_USE_HASH
/**
* @brief check hash value
* @note
* @param part_name: flash name
*
* @retval rt_fota_err_t
* @author yangFei
* @date 20220620
* @note similar to rt_fota_upgrade,add before rt_fota_upgrade of rt_fota_thread_entry
*/
int rt_fota_check_hash(const char *part_name)
{
uint32_t hash_value = 0;
int fota_err = RT_FOTA_NO_ERR;
const struct fal_partition *part;
rt_fota_part_head_t part_head = RT_NULL;
tiny_aes_context *aes_ctx = RT_NULL;
rt_uint8_t *aes_iv = RT_NULL;
rt_uint8_t *crypt_buf = RT_NULL;
int fw_raw_pos = 0;
int fw_raw_len = 0;
rt_uint32_t total_copy_size = 0;
rt_uint8_t block_hdr_buf[RT_FOTA_BLOCK_HEADER_SIZE];
rt_uint32_t block_hdr_pos = RT_FOTA_ALGO_BUFF_SIZE;
rt_uint32_t block_size = 0;
rt_uint32_t dcprs_size = 0;
qlz_state_decompress *dcprs_state = RT_NULL;
rt_uint8_t *cmprs_buff = RT_NULL;
rt_uint8_t *dcprs_buff = RT_NULL;
rt_uint32_t padding_size = 0;
if (part_name == RT_NULL)
{
LOG_D("Invaild paramenter input!");
fota_err = RT_FOTA_GENERAL_ERR;
goto __exit_check_hash;
}
part = fal_partition_find(part_name);
if (part == RT_NULL)
{
LOG_D("check hash partition[%s] not found.", part_name);
fota_err = RT_FOTA_GENERAL_ERR;
goto __exit_check_hash;
}
/* Application partition erase */
fota_err = rt_fota_erase_app_part();
if (fota_err != RT_FOTA_NO_ERR)
{
goto __exit_check_hash;
}
/* rt_fota_erase_app_part() has check fota_part_head vaild already */
part_head = &fota_part_head;
crypt_buf = rt_malloc(RT_FOTA_ALGO_BUFF_SIZE);
if (crypt_buf == RT_NULL)
{
LOG_D("Not enough memory for firmware buffer.");
fota_err = RT_FOTA_NO_MEM_ERR;
goto __exit_check_hash;
}
/* AES256 algorithm enable */
if ((part_head->fota_algo & RT_FOTA_CRYPT_STAT_MASK) == RT_FOTA_CRYPT_ALGO_AES256)
{
aes_ctx = rt_malloc(sizeof(tiny_aes_context));
aes_iv = rt_malloc(rt_strlen(RT_FOTA_ALGO_AES_IV) + 1);
if (aes_ctx == RT_NULL || aes_iv == RT_NULL)
{
LOG_D("Not enough memory for firmware hash verify.");
fota_err = RT_FOTA_NO_MEM_ERR;
goto __exit_check_hash;
}
rt_memset(aes_iv, 0x0, rt_strlen(RT_FOTA_ALGO_AES_IV) + 1);
rt_memcpy(aes_iv, RT_FOTA_ALGO_AES_IV, rt_strlen(RT_FOTA_ALGO_AES_IV));
tiny_aes_setkey_dec(aes_ctx, (rt_uint8_t *)RT_FOTA_ALGO_AES_KEY, 256);
}
else if ((part_head->fota_algo & RT_FOTA_CRYPT_STAT_MASK) == RT_FOTA_CRYPT_ALGO_XOR)
{
LOG_I("Not surpport XOR.");
fota_err = RT_FOTA_GENERAL_ERR;
goto __exit_check_hash;
}
/* If enable fastlz compress function */
if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) == RT_FOTA_CMPRS_ALGO_FASTLZ)
{
cmprs_buff = rt_malloc(RT_FOTA_CMPRS_BUFFER_SIZE + RT_FOTA_FASTLZ_BUFFER_PADDING);
dcprs_buff = rt_malloc(RT_FOTA_CMPRS_BUFFER_SIZE);
if (cmprs_buff == RT_NULL || dcprs_buff == RT_NULL)
{
LOG_D("Not enough memory for firmware hash verify.");
fota_err = RT_FOTA_NO_MEM_ERR;
goto __exit_check_hash;
}
padding_size = RT_FOTA_FASTLZ_BUFFER_PADDING;
}
else if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) == RT_FOTA_CMPRS_ALGO_QUICKLZ)
{
cmprs_buff = rt_malloc(RT_FOTA_CMPRS_BUFFER_SIZE + RT_FOTA_QUICKLZ_BUFFER_PADDING);
dcprs_buff = rt_malloc(RT_FOTA_CMPRS_BUFFER_SIZE);
dcprs_state = rt_malloc(sizeof(qlz_state_decompress));
if (cmprs_buff == RT_NULL || dcprs_buff == RT_NULL || dcprs_state == RT_NULL)
{
LOG_D("Not enough memory for firmware hash verify.");
fota_err = RT_FOTA_NO_MEM_ERR;
goto __exit_check_hash;
}
padding_size = RT_FOTA_QUICKLZ_BUFFER_PADDING;
rt_memset(dcprs_state, 0x0, sizeof(qlz_state_decompress));
}
else if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) == RT_FOTA_CMPRS_ALGO_GZIP)
{
LOG_I("Not surpport GZIP.");
fota_err = RT_FOTA_GENERAL_ERR;
goto __exit_check_hash;
}
while (fw_raw_pos < part_head->com_size)
{
if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) != RT_FOTA_CRYPT_ALGO_NONE)
{
if (block_hdr_pos >= RT_FOTA_ALGO_BUFF_SIZE)
{
fw_raw_len = rt_fota_read_part(part, fw_raw_pos, aes_ctx, aes_iv, crypt_buf, RT_FOTA_ALGO_BUFF_SIZE);
if (fw_raw_len < 0)
{
LOG_D("AES256 algorithm failed.");
fota_err = RT_FOTA_PART_READ_ERR;
goto __exit_check_hash;
}
fw_raw_pos += fw_raw_len;
rt_memcpy(block_hdr_buf, crypt_buf, RT_FOTA_BLOCK_HEADER_SIZE);
block_size = block_hdr_buf[0] * (1 << 24) + block_hdr_buf[1] * (1 << 16) + block_hdr_buf[2] * (1 << 8) + block_hdr_buf[3];
rt_memset(cmprs_buff, 0x0, RT_FOTA_CMPRS_BUFFER_SIZE + padding_size);
rt_memcpy(cmprs_buff, &crypt_buf[RT_FOTA_BLOCK_HEADER_SIZE], block_size);
block_hdr_pos = RT_FOTA_BLOCK_HEADER_SIZE + block_size;
}
else
{
rt_uint8_t hdr_tmp_pos = 0;
while (block_hdr_pos < RT_FOTA_ALGO_BUFF_SIZE)
{
if (hdr_tmp_pos < RT_FOTA_BLOCK_HEADER_SIZE)
{
block_hdr_buf[hdr_tmp_pos++] = crypt_buf[block_hdr_pos++];
}
else
{
block_size = block_hdr_buf[0] * (1 << 24) + block_hdr_buf[1] * (1 << 16) + block_hdr_buf[2] * (1 << 8) + block_hdr_buf[3];
rt_memset(cmprs_buff, 0x0, RT_FOTA_CMPRS_BUFFER_SIZE + padding_size);
if (block_size > (RT_FOTA_ALGO_BUFF_SIZE - block_hdr_pos))
{
rt_memcpy(cmprs_buff, &crypt_buf[block_hdr_pos], (RT_FOTA_ALGO_BUFF_SIZE - block_hdr_pos));
fw_raw_len = rt_fota_read_part(part, fw_raw_pos, aes_ctx, aes_iv, crypt_buf, RT_FOTA_ALGO_BUFF_SIZE);
if (fw_raw_len < 0)
{
LOG_D("AES256 algorithm failed.");
fota_err = RT_FOTA_PART_READ_ERR;
goto __exit_check_hash;
}
fw_raw_pos += fw_raw_len;
rt_memcpy(&cmprs_buff[RT_FOTA_ALGO_BUFF_SIZE - block_hdr_pos], &crypt_buf[0], (block_size + block_hdr_pos) - RT_FOTA_ALGO_BUFF_SIZE);
block_hdr_pos = (block_size + block_hdr_pos) - RT_FOTA_ALGO_BUFF_SIZE;
}
else
{
rt_memcpy(cmprs_buff, &crypt_buf[block_hdr_pos], block_size);
block_hdr_pos = block_hdr_pos + block_size;
}
break;
}
}
if (hdr_tmp_pos < RT_FOTA_BLOCK_HEADER_SIZE)
{
fw_raw_len = rt_fota_read_part(part, fw_raw_pos, aes_ctx, aes_iv, crypt_buf, RT_FOTA_ALGO_BUFF_SIZE);
if (fw_raw_len < 0)
{
LOG_D("AES256 algorithm failed.");
fota_err = RT_FOTA_PART_READ_ERR;
goto __exit_check_hash;
}
fw_raw_pos += fw_raw_len;
block_hdr_pos = 0;
while (hdr_tmp_pos < RT_FOTA_BLOCK_HEADER_SIZE)
{
block_hdr_buf[hdr_tmp_pos++] = crypt_buf[block_hdr_pos++];
}
block_size = block_hdr_buf[0] * (1 << 24) + block_hdr_buf[1] * (1 << 16) + block_hdr_buf[2] * (1 << 8) + block_hdr_buf[3];
rt_memset(cmprs_buff, 0x0, RT_FOTA_CMPRS_BUFFER_SIZE + padding_size);
rt_memcpy(cmprs_buff, &crypt_buf[block_hdr_pos], block_size);
block_hdr_pos = (block_hdr_pos + block_size) % RT_FOTA_ALGO_BUFF_SIZE;
}
}
rt_memset(dcprs_buff, 0x0, RT_FOTA_CMPRS_BUFFER_SIZE);
if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) == RT_FOTA_CMPRS_ALGO_FASTLZ)
{
dcprs_size = fastlz_decompress((const void *)&cmprs_buff[0], block_size, &dcprs_buff[0], RT_FOTA_CMPRS_BUFFER_SIZE);
}
else if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) == RT_FOTA_CMPRS_ALGO_QUICKLZ)
{
dcprs_size = qlz_decompress((const char *)&cmprs_buff[0], &dcprs_buff[0], dcprs_state);
}
if (dcprs_size <= 0)
{
LOG_D("Decompress failed: %d.", dcprs_size);
fota_err = RT_FOTA_GENERAL_ERR;
goto __exit_check_hash;
}
if(total_copy_size == 0)
{
hash_value = calc(dcprs_buff, FNV_SEED, dcprs_size);
}
else
{
hash_value = calc(dcprs_buff, hash_value, dcprs_size);
}
total_copy_size += dcprs_size;
rt_kprintf("#");
}
/* no compress option */
else
{
fw_raw_len = rt_fota_read_part(part, fw_raw_pos, aes_ctx, aes_iv, crypt_buf, RT_FOTA_ALGO_BUFF_SIZE);
if (fw_raw_len < 0)
{
LOG_D("AES256 algorithm failed.");
fota_err = RT_FOTA_PART_READ_ERR;
goto __exit_check_hash;
}
fw_raw_pos += fw_raw_len;
if(total_copy_size == 0)
{
hash_value = calc(crypt_buf, FNV_SEED, fw_raw_len);
}
else if((total_copy_size / 1024) == (part_head->raw_size / 1024))
{
hash_value = calc(crypt_buf, hash_value, (part_head->raw_size - total_copy_size));
}
else
{
hash_value = calc(crypt_buf, hash_value, fw_raw_len);
}
total_copy_size += fw_raw_len;
rt_kprintf("#");
}
}
/* it has compress option */
if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) != RT_FOTA_CRYPT_ALGO_NONE)
{
while (total_copy_size < part_head->raw_size)
{
if ((block_hdr_pos < fw_raw_len) && ((fw_raw_len - block_hdr_pos) > RT_FOTA_BLOCK_HEADER_SIZE))
{
rt_memcpy(block_hdr_buf, &crypt_buf[block_hdr_pos], RT_FOTA_BLOCK_HEADER_SIZE);
block_size = block_hdr_buf[0] * (1 << 24) + block_hdr_buf[1] * (1 << 16) + block_hdr_buf[2] * (1 << 8) + block_hdr_buf[3];
if ((fw_raw_len - block_hdr_pos - RT_FOTA_BLOCK_HEADER_SIZE) >= block_size)
{
rt_memset(cmprs_buff, 0x0, RT_FOTA_CMPRS_BUFFER_SIZE + padding_size);
rt_memcpy(cmprs_buff, &crypt_buf[block_hdr_pos + RT_FOTA_BLOCK_HEADER_SIZE], block_size);
rt_memset(dcprs_buff, 0x0, RT_FOTA_CMPRS_BUFFER_SIZE);
block_hdr_pos += (block_size + RT_FOTA_BLOCK_HEADER_SIZE);
if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) == RT_FOTA_CMPRS_ALGO_FASTLZ)
{
dcprs_size = fastlz_decompress((const void *)&cmprs_buff[0], block_size, &dcprs_buff[0], RT_FOTA_CMPRS_BUFFER_SIZE);
}
else if ((part_head->fota_algo & RT_FOTA_CMPRS_STAT_MASK) == RT_FOTA_CMPRS_ALGO_QUICKLZ)
{
dcprs_size = qlz_decompress((const char *)&cmprs_buff[0], &dcprs_buff[0], dcprs_state);
}
if (dcprs_size <= 0)
{
LOG_D("Decompress failed: %d.", dcprs_size);
fota_err = RT_FOTA_GENERAL_ERR;
goto __exit_check_hash;
}
hash_value = calc(dcprs_buff, hash_value, dcprs_size);
total_copy_size += dcprs_size;
rt_kprintf("#");
}
else
{
break;
}
}
else
{
break;
}
}
}
rt_kprintf("\r\n");
#ifdef RT_FOTA_USE_HASH
/* add hash cal */
if(hash_value != part_head->hash_val)
{
rt_kprintf("hash value check failed.");
fota_err = RT_FOTA_GENERAL_ERR;
goto __exit_check_hash;
}
rt_kprintf("hash value check sucess.\r\n");
#endif
if (total_copy_size < part_head->raw_size)
{
LOG_D("Decompress check failed.");
fota_err = RT_FOTA_GENERAL_ERR;
}
__exit_check_hash:
if (aes_ctx)
rt_free(aes_ctx);
if (aes_iv)
rt_free(aes_iv);
if (crypt_buf)
rt_free(crypt_buf);
if (cmprs_buff)
rt_free(cmprs_buff);
if (dcprs_buff)
rt_free(dcprs_buff);
if (dcprs_state)
rt_free(dcprs_state);
if (fota_err == RT_FOTA_NO_ERR)
{
rt_kprintf("check success, total %d bytes.", total_copy_size);
}
return fota_err;
}
#endif
见https://gitee.com/yangfei_addoil/rt-fota-gd32