999 lines
29 KiB
C
999 lines
29 KiB
C
// Copyright 2020-2021 Beken
|
|
//
|
|
// Licensed 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 <stdlib.h>
|
|
#include <string.h>
|
|
#include <os/mem.h>
|
|
#include <driver/flash.h>
|
|
#include <driver/flash_partition.h>
|
|
#include "flash_driver.h"
|
|
#include "flash_hal.h"
|
|
|
|
#if CONFIG_OVERRIDE_FLASH_PARTITION
|
|
#include "vendor_flash_partition.h"
|
|
#endif
|
|
|
|
#if (CONFIG_SOC_BK7236XX) || (CONFIG_SOC_BK7239XX)
|
|
#include "partitions_gen.h"
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
//#if (CONFIG_PSA_MBEDTLS) || (CONFIG_MBEDTLS_ACCELERATOR) || (CONFIG_MBEDTLS)
|
|
//#include "mbedtls/aes.h"
|
|
//#endif
|
|
|
|
#define TAG "partition"
|
|
|
|
#define NVS_KEY_SIZE 32 // AES-256
|
|
#define DATAUNIT_SIZE 32
|
|
|
|
#define PARTITION_AMOUNT 50
|
|
|
|
#define FLASH_PHYSICAL_ADDR_UNIT_SIZE 34
|
|
#define FLASH_LOGICAL_ADDR_UNIT_SIZE 32
|
|
|
|
#define FLASH_PHY_ADDR_VALID(addr) (((addr) % FLASH_PHYSICAL_ADDR_UNIT_SIZE) < FLASH_LOGICAL_ADDR_UNIT_SIZE)
|
|
#define FLASH_PHY_2_LOGICAL(addr) ((((addr) / FLASH_PHYSICAL_ADDR_UNIT_SIZE) * FLASH_LOGICAL_ADDR_UNIT_SIZE) + ((addr) % FLASH_PHYSICAL_ADDR_UNIT_SIZE))
|
|
#define FLASH_LOGICAL_2_PHY(addr) ((((addr) / FLASH_LOGICAL_ADDR_UNIT_SIZE) * FLASH_PHYSICAL_ADDR_UNIT_SIZE) + ((addr) % FLASH_LOGICAL_ADDR_UNIT_SIZE))
|
|
|
|
#define SOC_FLASH_BASE_ADDR 0x02000000
|
|
#define FLASH_LOGICAL_BASE_ADDR SOC_FLASH_BASE_ADDR
|
|
|
|
#if CONFIG_TFM_READ_FLASH_NSC
|
|
#if (CONFIG_TFM_FWU)
|
|
#include "tfm_flash_nsc.h"
|
|
#endif
|
|
|
|
#if CONFIG_NVS_ENCRYPTION
|
|
/**/
|
|
#else
|
|
char eky[4 * NVS_KEY_SIZE + 1] = {
|
|
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,
|
|
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
|
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
|
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
|
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
|
|
};
|
|
|
|
#endif
|
|
|
|
uint32_t flash_partition_get_index(const bk_logic_partition_t *partition_ptr);
|
|
|
|
#endif
|
|
|
|
enum {
|
|
PARTITION_PRIMARY_ALL = 0,
|
|
PARTITION_SECONDARY_ALL,
|
|
PARTITION_OTA,
|
|
PARTITION_PARTITION,
|
|
PARTITION_SPE,
|
|
PARTITION_TFM_NS,
|
|
PARTITION_NSPE,
|
|
PARTITION_OTP_NV,
|
|
PARTITION_PS,
|
|
PARTITION_ITS,
|
|
PARTITION_CNT,
|
|
};
|
|
|
|
const char *s_partition_name[PARTITION_CNT] = {
|
|
// "sys_rf",
|
|
// "sys_net",
|
|
// "easyflash",
|
|
// "primary_tfm_s",
|
|
// "primary_cpu0_app",
|
|
// "ota",
|
|
// "user_config"
|
|
"primary_all",
|
|
"secondary_all",
|
|
"ota",
|
|
"partition",
|
|
"primary_tfm_s",
|
|
"primary_tfm_ns",
|
|
"primary_cpu0_app",
|
|
"sys_otp_nv",
|
|
"sys_ps",
|
|
"sys_its"
|
|
};
|
|
#if (CONFIG_TFM_READ_FLASH_NSC)
|
|
#define PARTITION_PARTITION_PHY_OFFSET CONFIG_PARTITION_PHY_PARTITION_OFFSET
|
|
#define PARTITION_PPC_OFFSET 0x400
|
|
#define PARTITION_NAME_LEN 20
|
|
#define PARTITION_ENTRY_LEN 32
|
|
#define PARTITION_OFFSET_OFFSET 22
|
|
#define PARTITION_SIZE_OFFSET 26
|
|
#define PARTITION_FLAGS_OFFSET 30
|
|
|
|
typedef struct {
|
|
uint32_t phy_offset;
|
|
uint32_t phy_size;
|
|
uint32_t phy_flags;
|
|
} partition_config_t;
|
|
|
|
typedef struct {
|
|
bk_partition_t partition;
|
|
const char *name;
|
|
} partition_map_t;
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
uint32_t offset;
|
|
uint32_t size;
|
|
} partition_info_t;
|
|
|
|
const partition_info_t partition_map_by_gen[] = PARTITION_MAP;
|
|
|
|
bk_logic_partition_t logic_partitions[sizeof(partition_map_by_gen) / sizeof(partition_map_by_gen[0])];
|
|
static int is_initialized = 0;
|
|
|
|
static struct {
|
|
char name[PARTITION_NAME_LEN + 1];
|
|
uint32_t phy_flags;
|
|
} cachedPartitions[PARTITION_AMOUNT];
|
|
|
|
|
|
|
|
const partition_map_t partition_map[] = {
|
|
{BK_PARTITION_BOOTLOADER, "bl2"},
|
|
{BK_PARTITION_APPLICATION, "primary_cpu0_app"},
|
|
{BK_PARTITION_OTA, "ota"},
|
|
{BK_PARTITION_APPLICATION1, "primary_cpu0_app1"},
|
|
{BK_PARTITION_MATTER_FLASH, "matter"},
|
|
{BK_PARTITION_RF_FIRMWARE, "sys_rf"},
|
|
{BK_PARTITION_NET_PARAM, "sys_net"},
|
|
{BK_PARTITION_USR_CONFIG, "user_config"},
|
|
{BK_PARTITION_OTA_FINA_EXECUTIVE, "ota2"},
|
|
{BK_PARTITION_APPLICATION2, "primary_cpu0_app2"},
|
|
{BK_PARTITION_EASYFLASH, "easyflash"},
|
|
{BK_PARTITION_NVS, "nvs"},
|
|
{BK_PARTITION_NVS_KEY, "nvs_key"},
|
|
{BK_PARTITION_WIZ_MFR, "wiz_mfr"},
|
|
};
|
|
|
|
const size_t partition_map_size = sizeof(partition_map) / sizeof(partition_map[0]);
|
|
|
|
#endif
|
|
|
|
#if CONFIG_FLASH_ORIGIN_API
|
|
#define PAR_OPT_READ_POS (0)
|
|
#define PAR_OPT_WRITE_POS (1)
|
|
|
|
#define PAR_OPT_READ_DIS (0x0u << PAR_OPT_READ_POS)
|
|
#define PAR_OPT_READ_EN (0x1u << PAR_OPT_READ_POS)
|
|
#define PAR_OPT_WRITE_DIS (0x0u << PAR_OPT_WRITE_POS)
|
|
#define PAR_OPT_WRITE_EN (0x1u << PAR_OPT_WRITE_POS)
|
|
#endif
|
|
|
|
#define PARTITION_IRAM __attribute__((section(".iram")))
|
|
|
|
/// TODO: use bk_flash_partitions name for all, every soc can define self config at:
|
|
/// middleware/boards/bk7256/vnd_flash/vnd_flash.c
|
|
/// Custom can override bk_flash_partitions in project, For example:
|
|
/// projects/customization/bk7256_config2/main/vendor_flash.c
|
|
/* Logic partition on flash devices */
|
|
#if (CONFIG_SOC_BK7256XX)
|
|
#if CONFIG_OVERRIDE_FLASH_PARTITION
|
|
extern const bk_logic_partition_t bk_flash_partitions[BK_PARTITION_MAX_USER];
|
|
#else
|
|
extern const bk_logic_partition_t bk_flash_partitions[BK_PARTITION_MAX];
|
|
#endif
|
|
#elif (CONFIG_SOC_BK7236XX) || (CONFIG_SOC_BK7239XX)
|
|
#if CONFIG_OVERRIDE_FLASH_PARTITION
|
|
extern const bk_logic_partition_t bk_flash_partitions[BK_PARTITION_MAX_USER];
|
|
#else
|
|
extern const bk_logic_partition_t bk_flash_partitions[BK_PARTITION_MAX];
|
|
#endif
|
|
#else
|
|
#include "partitions.h"
|
|
static const bk_logic_partition_t bk_flash_partitions[BK_PARTITION_MAX] = {
|
|
[BK_PARTITION_BOOTLOADER] =
|
|
{
|
|
.partition_owner = BK_FLASH_EMBEDDED,
|
|
.partition_description = "Bootloader",
|
|
.partition_start_addr = 0x00000000,
|
|
.partition_length = 0x0F000,
|
|
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
|
|
},
|
|
[BK_PARTITION_APPLICATION] =
|
|
{
|
|
.partition_owner = BK_FLASH_EMBEDDED,
|
|
.partition_description = "Primary Application",
|
|
.partition_start_addr = 0x11000,
|
|
#if CONFIG_SUPPORT_MATTER || CONFIG_FLASH_SIZE_4M
|
|
.partition_length = 0x1A9000,
|
|
#else
|
|
.partition_length = 0x143000,
|
|
#endif
|
|
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
|
|
},
|
|
[BK_PARTITION_OTA] =
|
|
{
|
|
.partition_owner = BK_FLASH_EMBEDDED,
|
|
.partition_description = "ota",
|
|
#if CONFIG_FLASH_SIZE_4M
|
|
.partition_start_addr = 0x1BA000,
|
|
.partition_length = 0x1A9000, //1700KB
|
|
#elif CONFIG_SUPPORT_MATTER
|
|
.partition_start_addr = 0x1BA000,
|
|
.partition_length = 0x11000, //68KB
|
|
#else
|
|
.partition_start_addr = 0x132000,
|
|
.partition_length = 0xAE000, //696KB
|
|
#endif
|
|
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
|
|
},
|
|
#if CONFIG_SUPPORT_MATTER
|
|
[BK_PARTITION_MATTER_FLASH] =
|
|
{
|
|
.partition_owner = BK_FLASH_EMBEDDED,
|
|
.partition_description = "Matter",
|
|
#if CONFIG_FLASH_SIZE_4M
|
|
.partition_start_addr = 0x363000,
|
|
#else
|
|
partition_start_addr = 0x1CB000,
|
|
#endif
|
|
.partition_length = 0x15000, //84KB
|
|
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
|
|
},
|
|
#endif
|
|
[BK_PARTITION_RF_FIRMWARE] =
|
|
{
|
|
.partition_owner = BK_FLASH_EMBEDDED,
|
|
.partition_description = "RF Firmware",
|
|
#if (CONFIG_FLASH_SIZE_4M)
|
|
.partition_start_addr = 0x3FE000,
|
|
#else
|
|
.partition_start_addr = CONFIG_SYS_RF_PHY_PARTITION_OFFSET,// for rf related info
|
|
#endif
|
|
.partition_length = CONFIG_SYS_RF_PHY_PARTITION_SIZE,
|
|
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
|
|
},
|
|
[BK_PARTITION_NET_PARAM] =
|
|
{
|
|
.partition_owner = BK_FLASH_EMBEDDED,
|
|
.partition_description = "NET info",
|
|
#if (CONFIG_FLASH_SIZE_4M)
|
|
.partition_start_addr = 0x3FF000,
|
|
#else
|
|
.partition_start_addr = CONFIG_SYS_NET_PHY_PARTITION_OFFSET,// for net related info
|
|
#endif
|
|
.partition_length = CONFIG_SYS_NET_PHY_PARTITION_SIZE,
|
|
.partition_options = PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS,
|
|
},
|
|
};
|
|
#endif
|
|
|
|
|
|
static bool flash_partition_is_valid(bk_partition_t partition)
|
|
{
|
|
if ((partition >= BK_PARTITION_BOOTLOADER)
|
|
&& (partition < ARRAY_SIZE(bk_flash_partitions))) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static int is_alpha(char c)
|
|
{
|
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
|
|
}
|
|
|
|
static uint32_t piece_address(uint8_t *array,uint32_t index)
|
|
{
|
|
return ((uint32_t)(array[index]) << 24 | (uint32_t)(array[index+1]) << 16 | (uint32_t)(array[index+2]) << 8 | (uint32_t)((array[index+3])));
|
|
}
|
|
|
|
static uint16_t short_address(uint8_t *array,uint16_t index)
|
|
{
|
|
return ((uint16_t)(array[index]) << 8 | (uint16_t)(array[index+1]));
|
|
}
|
|
|
|
int toHex(char ch) {
|
|
if (ch >= '0' && ch <= '9') {
|
|
return ch - '0';
|
|
} else if (ch >= 'a' && ch <= 'f') {
|
|
return ch - 'a' + 10;
|
|
} else if (ch >= 'A' && ch <= 'F') {
|
|
return ch - 'A' + 10;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint8_t toHexByte(const char* c) {
|
|
return 16 * toHex(c[0]) + toHex(c[1]);
|
|
}
|
|
|
|
void toHexStream(const char* src, uint8_t* dest, uint32_t* dest_len) {
|
|
uint32_t cnt = 0;
|
|
const char* p = src;
|
|
while (*p != '\0' && *(p + 1) != '\0') {
|
|
dest[cnt++] = toHexByte(p);
|
|
p += 2;
|
|
}
|
|
*dest_len = cnt;
|
|
}
|
|
|
|
void generate_iv(uint8_t *iv, size_t unit_num) {
|
|
memset(iv, 0, 16);
|
|
for (int k = 0; k < 16 && k < DATAUNIT_SIZE; k++) {
|
|
if (8 * k >= 32) continue;
|
|
iv[15 - k] = (unit_num >> (8 * k)) & 0xFF;
|
|
}
|
|
for (int j = 0; j < 8; j++) {
|
|
u8 temp = iv[j];
|
|
iv[j] = iv[15 - j];
|
|
iv[15 - j] = temp;
|
|
}
|
|
}
|
|
|
|
|
|
#if CONFIG_TFM_READ_FLASH_NSC
|
|
|
|
void initialize_logic_partitions() {
|
|
if (is_initialized) return;
|
|
|
|
for (size_t i = 0; i < sizeof(partition_map_by_gen) / sizeof(partition_map_by_gen[0]); ++i) {
|
|
logic_partitions[i].partition_owner = BK_FLASH_EMBEDDED;
|
|
logic_partitions[i].partition_description = partition_map_by_gen[i].name;
|
|
logic_partitions[i].partition_start_addr = partition_map_by_gen[i].offset;
|
|
logic_partitions[i].partition_length = partition_map_by_gen[i].size;
|
|
logic_partitions[i].partition_options = PAR_OPT_EXECUTE_DIS | PAR_OPT_READ_EN | PAR_OPT_WRITE_DIS;
|
|
}
|
|
|
|
is_initialized = 1;
|
|
}
|
|
|
|
static void get_partition_name(bk_partition_t partition, char *name, size_t name_len) {
|
|
for (size_t i = 0; i < sizeof(partition_map) / sizeof(partition_map[0]); ++i) {
|
|
if (partition_map[i].partition == partition) {
|
|
strncpy(name, partition_map[i].name, name_len - 1);
|
|
name[name_len - 1] = '\0';
|
|
return;
|
|
}
|
|
}
|
|
strncpy(name, "unknown", name_len - 1);
|
|
name[name_len - 1] = '\0';
|
|
}
|
|
|
|
bk_logic_partition_t * get_partition_info(bk_partition_t partition) {
|
|
const char *label = NULL;
|
|
|
|
for (size_t i = 0; i < sizeof(partition_map) / sizeof(partition_map[0]); ++i) {
|
|
if (partition_map[i].partition == partition) {
|
|
label = partition_map[i].name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (label) {
|
|
return get_partition_info_by_name(label);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bk_logic_partition_t * get_partition_info_by_name(const char *label) {
|
|
if (!is_initialized) {
|
|
initialize_logic_partitions();
|
|
}
|
|
|
|
for (size_t i = 0; i < sizeof(partition_map_by_gen) / sizeof(partition_map_by_gen[0]); ++i) {
|
|
if (strcmp(partition_map_by_gen[i].name, label) == 0) {
|
|
return &logic_partitions[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t get_partition_index(const bk_logic_partition_t* partition) {
|
|
uint32_t iRet = 0;
|
|
for (size_t i = 0; i < partition_map_size; ++i) {
|
|
if (strcmp(partition->partition_description,partition_map[i].name) == 0) {
|
|
iRet = i;
|
|
break;
|
|
}
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
static bool partitionIsEncrypt(bk_logic_partition_t *partition_info)
|
|
{
|
|
static bool isInitialized = false;
|
|
|
|
if (!isInitialized) {
|
|
uint8_t* buf = (uint8_t*)malloc(PARTITION_ENTRY_LEN * sizeof(uint8_t));
|
|
if (buf == NULL) {
|
|
BK_LOGE(TAG, "memory malloc fails.\r\n");
|
|
return false;
|
|
}
|
|
|
|
uint32_t partition_start = PARTITION_PARTITION_PHY_OFFSET + PARTITION_PPC_OFFSET;
|
|
|
|
for (uint32_t i = 0; i < PARTITION_AMOUNT; ++i) {
|
|
#if (CONFIG_TFM_FWU)
|
|
psa_flash_read_bytes(partition_start + PARTITION_ENTRY_LEN * i, buf, PARTITION_ENTRY_LEN);
|
|
#else
|
|
bk_flash_read_bytes(partition_start + PARTITION_ENTRY_LEN * i, buf, PARTITION_ENTRY_LEN);
|
|
#endif
|
|
|
|
if (is_alpha(buf[0]) == 0) {
|
|
break;
|
|
}
|
|
|
|
int j;
|
|
for (j = 0; j < PARTITION_NAME_LEN; ++j) {
|
|
if (buf[j] == 0xFF) {
|
|
break;
|
|
}
|
|
cachedPartitions[i].name[j] = buf[j];
|
|
}
|
|
cachedPartitions[i].name[j] = '\0';
|
|
|
|
cachedPartitions[i].phy_flags = short_address(buf, PARTITION_FLAGS_OFFSET);
|
|
}
|
|
|
|
free(buf);
|
|
isInitialized = true;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < PARTITION_AMOUNT; ++i) {
|
|
if (strcmp(partition_info->partition_description, cachedPartitions[i].name) == 0) {
|
|
return (cachedPartitions[i].phy_flags & 1) != 0;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
|
|
static bk_logic_partition_t * flash_partition_get_info_by_addr(uint32_t addr)
|
|
{
|
|
const bk_logic_partition_t *pt;
|
|
|
|
for(int i = 0; i < ARRAY_SIZE(bk_flash_partitions); i++)
|
|
{
|
|
pt = &bk_flash_partitions[i];
|
|
|
|
if(addr < pt->partition_start_addr)
|
|
continue;
|
|
if(addr >= (pt->partition_start_addr + pt->partition_length))
|
|
continue;
|
|
|
|
return (bk_logic_partition_t *)pt;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bk_logic_partition_t *bk_flash_partition_get_info(bk_partition_t partition)
|
|
{
|
|
bk_logic_partition_t *pt = NULL;
|
|
|
|
BK_ASSERT(BK_PARTITION_BOOTLOADER < BK_PARTITION_MAX);
|
|
|
|
if (flash_partition_is_valid(partition)) {
|
|
#if (CONFIG_SOC_BK7256XX)
|
|
pt = (bk_logic_partition_t *)&bk_flash_partitions[partition];
|
|
#elif (CONFIG_SOC_BK7236XX) || (CONFIG_SOC_BK7239XX)
|
|
#if CONFIG_TFM_READ_FLASH_NSC
|
|
pt = get_partition_info(partition);
|
|
#else
|
|
pt = (bk_logic_partition_t *)&bk_flash_partitions[partition];
|
|
#endif
|
|
#else
|
|
pt = (bk_logic_partition_t *)&bk_flash_partitions[partition];
|
|
#endif
|
|
}
|
|
return pt;
|
|
}
|
|
|
|
static bk_err_t flash_partition_addr_check(bk_logic_partition_t *partition_info, uint32_t offset, uint32_t size)
|
|
{
|
|
#if (CONFIG_FLASH_PARTITION_CHECK_VALID)
|
|
if ( (offset >= partition_info->partition_length)
|
|
|| (size > partition_info->partition_length)
|
|
|| (offset + size > partition_info->partition_length) )
|
|
{
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
#endif
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
/*********************************************
|
|
* this function MUST reside in the flash.
|
|
* it will use itself address to check partition write permission.
|
|
*/
|
|
static bk_err_t flash_partition_write_perm_check(bk_logic_partition_t *partition_info)
|
|
{
|
|
#if (CONFIG_FLASH_PARTITION_CHECK_VALID)
|
|
if((partition_info->partition_options & PAR_OPT_WRITE_EN) == 0)
|
|
return BK_FAIL;
|
|
|
|
// flash ctrl only can read/write 16MB.
|
|
uint32_t fun_flash_logical_addr = ((uint32_t)flash_partition_write_perm_check) & (FLASH_MAX_SIZE - 1) ;
|
|
uint32_t fun_flash_phy_addr = FLASH_LOGICAL_2_PHY(fun_flash_logical_addr);
|
|
|
|
if(fun_flash_phy_addr < partition_info->partition_start_addr)
|
|
{
|
|
return BK_OK; // not write current running partition.
|
|
}
|
|
|
|
if(fun_flash_phy_addr > (partition_info->partition_start_addr + partition_info->partition_length))
|
|
{
|
|
return BK_OK; // not write current running partition.
|
|
}
|
|
|
|
return BK_FAIL; // not permit to write current running partition.
|
|
#else
|
|
return BK_OK;
|
|
#endif
|
|
|
|
}
|
|
|
|
static bk_err_t bk_flash_partition_erase_internal(bk_logic_partition_t *partition_info, uint32_t offset, uint32_t size)
|
|
{
|
|
if (size == 0)
|
|
return BK_OK;
|
|
|
|
uint32_t erase_addr = 0;
|
|
uint32_t start_sector, end_sector = 0;
|
|
|
|
start_sector = offset >> FLASH_SECTOR_SIZE_OFFSET; /* offset / FLASH_SECTOR_SIZE */
|
|
end_sector = (offset + size - 1) >> FLASH_SECTOR_SIZE_OFFSET;
|
|
|
|
for (uint32_t i = start_sector; i <= end_sector; i++) {
|
|
erase_addr = partition_info->partition_start_addr + (i << FLASH_SECTOR_SIZE_OFFSET);
|
|
|
|
bk_flash_erase_sector(erase_addr);
|
|
}
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_flash_partition_erase(bk_partition_t partition, uint32_t offset, uint32_t size)
|
|
{
|
|
bk_logic_partition_t *partition_info = bk_flash_partition_get_info(partition);
|
|
|
|
if (partition_info == NULL) {
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
if (flash_partition_addr_check(partition_info, offset, size) != BK_OK )
|
|
{
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
if (flash_partition_write_perm_check(partition_info) != BK_OK )
|
|
{
|
|
return BK_FAIL;
|
|
}
|
|
|
|
|
|
return bk_flash_partition_erase_internal(partition_info, offset, size);
|
|
}
|
|
|
|
static bk_err_t bk_flash_partition_write_internal(bk_logic_partition_t *partition_info, const uint8_t *buffer, uint32_t offset, uint32_t buffer_len)
|
|
{
|
|
BK_RETURN_ON_NULL(buffer);
|
|
|
|
uint32_t start_addr;
|
|
|
|
start_addr = partition_info->partition_start_addr + offset;
|
|
if ((offset + buffer_len) > partition_info->partition_length) {
|
|
FLASH_LOGE("partition overlap. offset(%d),len(%d)\r\n", offset, buffer_len);
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
|
|
#if (CONFIG_TFM_READ_FLASH_NSC)
|
|
uint8_t *dest_hex = os_malloc(buffer_len);
|
|
if (dest_hex == NULL) {
|
|
FLASH_LOGW("%s malloc failed\r\n", __func__);
|
|
return BK_ERR_NO_MEM;
|
|
}
|
|
|
|
os_memcpy(dest_hex, buffer, buffer_len);
|
|
|
|
if (partitionIsEncrypt(partition_info)) {
|
|
uint8_t eky_hex[2 * NVS_KEY_SIZE];
|
|
uint8_t ptxt_hex[32], ctxt_hex[32], TweakValue[16];
|
|
bk_err_t ret = BK_FAIL;
|
|
|
|
mbedtls_aes_xts_context ectx[1];
|
|
mbedtls_aes_xts_init(ectx);
|
|
|
|
#if CONFIG_NVS_ENCRYPTION
|
|
#else
|
|
uint32_t byteArrayLen = 0;
|
|
toHexStream(eky, eky_hex, &byteArrayLen);
|
|
#endif // CONFIG_NVS_ENCRYPTION
|
|
|
|
mbedtls_aes_xts_setkey_enc(ectx, eky_hex, 2 * NVS_KEY_SIZE * 8);
|
|
|
|
for (size_t i = 0; i < buffer_len; i += DATAUNIT_SIZE) {
|
|
os_memset(TweakValue, 0, 16);
|
|
os_memset(ptxt_hex, 0xff, 32);
|
|
|
|
generate_iv(TweakValue, (i + offset) / DATAUNIT_SIZE);
|
|
|
|
const uint8_t* tab_addr = &buffer[i];
|
|
|
|
if ((i + DATAUNIT_SIZE) < buffer_len)
|
|
os_memcpy(ptxt_hex, tab_addr, DATAUNIT_SIZE);
|
|
else {
|
|
// last copy
|
|
uint32_t len = buffer_len - i;
|
|
os_memcpy(ptxt_hex, tab_addr, len);
|
|
}
|
|
|
|
ret = mbedtls_aes_crypt_xts(ectx, MBEDTLS_AES_ENCRYPT, 32, TweakValue, ptxt_hex, ctxt_hex);
|
|
if (ret != BK_OK) {
|
|
mbedtls_aes_xts_free(ectx);
|
|
BK_LOGE(TAG, "Failed to mbedtls_aes_crypt_xts_encrypt: [0x%02X]", ret);
|
|
return ret;
|
|
}
|
|
|
|
if ((i + DATAUNIT_SIZE) < buffer_len)
|
|
os_memcpy(&dest_hex[i], ctxt_hex, DATAUNIT_SIZE);
|
|
else {
|
|
// last copy
|
|
uint32_t len = buffer_len - i;
|
|
os_memcpy(&dest_hex[i], ctxt_hex, len);
|
|
}
|
|
}
|
|
mbedtls_aes_xts_free(ectx);
|
|
}
|
|
#endif
|
|
|
|
if ((offset + buffer_len) <= partition_info->partition_length) {
|
|
#if (CONFIG_TFM_READ_FLASH_NSC)
|
|
bk_flash_write_bytes(start_addr, dest_hex, buffer_len);
|
|
#else
|
|
bk_flash_write_bytes(start_addr, buffer, buffer_len);
|
|
#endif
|
|
}
|
|
|
|
#if (CONFIG_TFM_READ_FLASH_NSC)
|
|
if (dest_hex) {
|
|
os_free(dest_hex);
|
|
dest_hex = NULL;
|
|
}
|
|
#endif
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_flash_partition_write(bk_partition_t partition, const uint8_t *buffer, uint32_t offset, uint32_t buffer_len)
|
|
{
|
|
bk_logic_partition_t *partition_info = bk_flash_partition_get_info(partition);
|
|
if (NULL == partition_info) {
|
|
FLASH_LOGW("%s partition not found\r\n", __func__);
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
if (flash_partition_addr_check(partition_info, offset, buffer_len) != BK_OK )
|
|
{
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
if (flash_partition_write_perm_check(partition_info) != BK_OK )
|
|
{
|
|
return BK_FAIL;
|
|
}
|
|
|
|
return bk_flash_partition_write_internal(partition_info, buffer, offset, buffer_len);
|
|
}
|
|
|
|
static bk_err_t bk_flash_partition_read_internal(bk_logic_partition_t *partition_info, uint8_t *out_buffer, uint32_t offset, uint32_t buffer_len)
|
|
{
|
|
BK_RETURN_ON_NULL(out_buffer);
|
|
|
|
uint32_t start_addr;
|
|
|
|
start_addr = partition_info->partition_start_addr + offset;
|
|
if ((offset + buffer_len) > partition_info->partition_length) {
|
|
FLASH_LOGE("partition overlap. offset(%d),len(%d)\r\n", offset, buffer_len);
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
|
|
bk_flash_read_bytes(start_addr, out_buffer, buffer_len);
|
|
|
|
#if (CONFIG_TFM_READ_FLASH_NSC)
|
|
if (partitionIsEncrypt(partition_info)) {
|
|
uint8_t eky_hex[2 * NVS_KEY_SIZE];
|
|
uint8_t ptxt_hex[32], ctxt_hex[32], TweakValue[16];
|
|
bk_err_t ret = BK_FAIL;
|
|
|
|
mbedtls_aes_xts_context dctx[1];
|
|
|
|
uint8_t* dest_hex = os_malloc(buffer_len);
|
|
if (dest_hex == NULL) {
|
|
FLASH_LOGW("%s malloc failed\r\n", __func__);
|
|
return BK_ERR_NO_MEM;
|
|
}
|
|
|
|
os_memset(dest_hex, 0xff, buffer_len);
|
|
mbedtls_aes_xts_init(dctx);
|
|
|
|
#if CONFIG_NVS_ENCRYPTION
|
|
#else
|
|
uint32_t byteArrayLen = 0;
|
|
toHexStream(eky, eky_hex, &byteArrayLen);
|
|
#endif // CONFIG_NVS_ENCRYPTION
|
|
|
|
mbedtls_aes_xts_setkey_dec(dctx, eky_hex, 2 * NVS_KEY_SIZE * 8);
|
|
|
|
for (size_t i = 0; i < buffer_len; i += DATAUNIT_SIZE) {
|
|
os_memset(TweakValue, 0, 16);
|
|
generate_iv(TweakValue, (i + offset) / DATAUNIT_SIZE);
|
|
|
|
uint8_t* tab_addr = &out_buffer[i];
|
|
|
|
if ((i + DATAUNIT_SIZE) < buffer_len)
|
|
os_memcpy(ctxt_hex, tab_addr, DATAUNIT_SIZE);
|
|
else {
|
|
// last copy
|
|
uint32_t len = buffer_len - i;
|
|
os_memcpy(ctxt_hex, tab_addr, len);
|
|
}
|
|
|
|
ret = mbedtls_aes_crypt_xts(dctx, MBEDTLS_AES_DECRYPT, 32, TweakValue, ctxt_hex, ptxt_hex);
|
|
if (ret != BK_OK) {
|
|
mbedtls_aes_xts_free(dctx);
|
|
BK_LOGE(TAG, "Failed to mbedtls_aes_crypt_xts_decrypt: [0x%02X]", ret);
|
|
return ret;
|
|
}
|
|
|
|
if ((i + DATAUNIT_SIZE) < buffer_len)
|
|
os_memcpy(&dest_hex[i], ptxt_hex, DATAUNIT_SIZE);
|
|
else {
|
|
// last copy
|
|
uint32_t len = buffer_len - i;
|
|
os_memcpy(&dest_hex[i], ptxt_hex, len);
|
|
}
|
|
}
|
|
mbedtls_aes_xts_free(dctx);
|
|
|
|
os_memset(out_buffer, 0xff, buffer_len);
|
|
os_memcpy(out_buffer, dest_hex, buffer_len);
|
|
|
|
if (dest_hex) {
|
|
os_free(dest_hex);
|
|
dest_hex = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_flash_partition_read(bk_partition_t partition, uint8_t *out_buffer, uint32_t offset, uint32_t buffer_len)
|
|
{
|
|
bk_logic_partition_t *partition_info = bk_flash_partition_get_info(partition);
|
|
if (NULL == partition_info) {
|
|
FLASH_LOGW("%s partition not found\r\n", __func__);
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
if (flash_partition_addr_check(partition_info, offset, buffer_len) != BK_OK )
|
|
{
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
|
|
uint32_t aligned_offset = offset & ~0x1F;
|
|
uint32_t aligned_end = (offset + buffer_len + 31) & ~0x1F;
|
|
|
|
uint32_t aligned_length = aligned_end - aligned_offset;
|
|
uint8_t *aligned_buffer = (uint8_t *)malloc(aligned_length);
|
|
if (aligned_buffer == NULL) {
|
|
return BK_ERR_NO_MEM;
|
|
}
|
|
|
|
bk_err_t read_status = bk_flash_partition_read_internal(partition_info, aligned_buffer, aligned_offset, aligned_length);
|
|
|
|
if (read_status != BK_OK) {
|
|
free(aligned_buffer);
|
|
return read_status;
|
|
}
|
|
memcpy(out_buffer, aligned_buffer + (offset - aligned_offset), buffer_len);
|
|
free(aligned_buffer);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
#if CONFIG_TFM_READ_FLASH_NSC
|
|
bk_err_t bk_flash_partition_erase_all(const char *label)
|
|
{
|
|
bk_logic_partition_t *partition_info = get_partition_info_by_name(label);
|
|
if (partition_info == NULL) {
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
if (flash_partition_write_perm_check(partition_info) != BK_OK )
|
|
{
|
|
return BK_FAIL;
|
|
}
|
|
|
|
return bk_flash_partition_erase_internal(partition_info, 0, partition_info->partition_length);
|
|
}
|
|
|
|
bk_err_t bk_flash_partition_erase_by_name(const char* label, uint32_t offset, uint32_t size)
|
|
{
|
|
bk_logic_partition_t *partition_info = get_partition_info_by_name(label);
|
|
if (partition_info == NULL) {
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
if (flash_partition_addr_check(partition_info, offset, size) != BK_OK )
|
|
{
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
if (flash_partition_write_perm_check(partition_info) != BK_OK )
|
|
{
|
|
return BK_FAIL;
|
|
}
|
|
|
|
return bk_flash_partition_erase_internal(partition_info, offset, size);
|
|
}
|
|
|
|
bk_err_t bk_flash_partition_write_by_name(const char *label, const uint8_t *buffer, uint32_t offset, uint32_t buffer_len)
|
|
{
|
|
bk_logic_partition_t *partition_info = get_partition_info_by_name(label);
|
|
|
|
if (NULL == partition_info) {
|
|
FLASH_LOGW("%s partition not found\r\n", __func__);
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
if (flash_partition_addr_check(partition_info, offset, buffer_len) != BK_OK )
|
|
{
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
if (flash_partition_write_perm_check(partition_info) != BK_OK )
|
|
{
|
|
return BK_FAIL;
|
|
}
|
|
|
|
return bk_flash_partition_write_internal(partition_info, buffer, offset, buffer_len);
|
|
}
|
|
|
|
bk_err_t bk_flash_partition_read_by_name(const char *label, uint8_t *out_buffer, uint32_t offset, uint32_t buffer_len)
|
|
{
|
|
bk_logic_partition_t *partition_info = get_partition_info_by_name(label);
|
|
|
|
if (NULL == partition_info) {
|
|
FLASH_LOGW("%s partition not found\r\n", __func__);
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
if (flash_partition_addr_check(partition_info, offset, buffer_len) != BK_OK )
|
|
{
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
|
|
uint32_t aligned_offset = offset & ~0x1F;
|
|
uint32_t aligned_end = (offset + buffer_len + 31) & ~0x1F;
|
|
|
|
uint32_t aligned_length = aligned_end - aligned_offset;
|
|
uint8_t *aligned_buffer = (uint8_t *)malloc(aligned_length);
|
|
if (aligned_buffer == NULL) {
|
|
return BK_ERR_NO_MEM;
|
|
}
|
|
|
|
bk_err_t read_status = bk_flash_partition_read_internal(partition_info, aligned_buffer, aligned_offset, aligned_length);
|
|
|
|
if (read_status != BK_OK) {
|
|
free(aligned_buffer);
|
|
return read_status;
|
|
}
|
|
memcpy(out_buffer, aligned_buffer + (offset - aligned_offset), buffer_len);
|
|
free(aligned_buffer);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
extern void * bk_memcpy_4w(void *dst, const void *src, unsigned int size);
|
|
|
|
#if CONFIG_FLASH_CBUS_RW
|
|
bk_err_t bk_flash_partition_read_cbus(bk_partition_t partition, uint8_t *out_buffer, uint32_t offset, uint32_t buffer_len)
|
|
{
|
|
BK_RETURN_ON_NULL(out_buffer);
|
|
|
|
uint32_t in_ptr;
|
|
uint32_t start_addr, flash_base;
|
|
bk_logic_partition_t *partition_info;
|
|
|
|
partition_info = bk_flash_partition_get_info(partition);
|
|
if (NULL == partition_info) {
|
|
FLASH_LOGW("%s partiion not found\r\n", __func__);
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
|
|
flash_base = FLASH_LOGICAL_BASE_ADDR;
|
|
start_addr = partition_info->partition_start_addr;
|
|
if(!FLASH_PHY_ADDR_VALID(start_addr))
|
|
return BK_FAIL;
|
|
|
|
int ret = flash_partition_addr_check(partition_info, FLASH_LOGICAL_2_PHY(offset), FLASH_LOGICAL_2_PHY(buffer_len));
|
|
|
|
if(ret != BK_OK)
|
|
return ret;
|
|
|
|
in_ptr = flash_base + FLASH_PHY_2_LOGICAL(start_addr) + offset;
|
|
|
|
memcpy(out_buffer, (void *)in_ptr, buffer_len);
|
|
|
|
return BK_OK;
|
|
}
|
|
|
|
bk_err_t bk_flash_partition_write_cbus(bk_partition_t partition, const uint8_t *buffer, uint32_t offset, uint32_t buffer_len)
|
|
{
|
|
BK_RETURN_ON_NULL(buffer);
|
|
|
|
uint32_t wr_ptr;
|
|
uint32_t start_addr, flash_base;
|
|
bk_logic_partition_t *partition_info;
|
|
|
|
GLOBAL_INT_DECLARATION();
|
|
FLASH_LOGI("bk_flash_partition_write_enhanced:0x%x\r\n", buffer_len);
|
|
partition_info = bk_flash_partition_get_info(partition);
|
|
if (NULL == partition_info) {
|
|
FLASH_LOGW("%s partition not found\r\n", __func__);
|
|
return BK_ERR_FLASH_PARTITION_NOT_FOUND;
|
|
}
|
|
|
|
flash_base = SOC_FLASH_DATA_BASE;
|
|
start_addr = partition_info->partition_start_addr;
|
|
wr_ptr = flash_base + FLASH_PHY_2_LOGICAL(start_addr) + offset;
|
|
if((offset + buffer_len) > partition_info->partition_length) {
|
|
FLASH_LOGE("partition overlap. offset(%d),len(%d)\r\n", offset, buffer_len);
|
|
return BK_ERR_FLASH_ADDR_OUT_OF_RANGE;
|
|
}
|
|
|
|
GLOBAL_INT_DISABLE();
|
|
|
|
flash_protect_type_t partition_type = bk_flash_get_protect_type();
|
|
bk_flash_set_protect_type(FLASH_PROTECT_NONE);
|
|
if((offset + buffer_len) <= partition_info->partition_length) {
|
|
bk_memcpy_4w((void *)wr_ptr, buffer, buffer_len);
|
|
}
|
|
bk_flash_set_protect_type(partition_type);
|
|
|
|
GLOBAL_INT_RESTORE();
|
|
|
|
return BK_OK;
|
|
}
|
|
#endif
|
|
|
|
bk_err_t bk_flash_partition_write_perm_check_by_addr(uint32_t addr, uint32_t size, uint32_t magic_code)
|
|
{
|
|
if(magic_code != FLASH_API_MAGIC_CODE)
|
|
return BK_FAIL;
|
|
|
|
bk_logic_partition_t *partition_info = flash_partition_get_info_by_addr(addr);
|
|
|
|
if (NULL == partition_info) {
|
|
return BK_FAIL;
|
|
}
|
|
|
|
uint32_t offset = addr - partition_info->partition_start_addr;
|
|
|
|
bk_err_t ret_val = flash_partition_addr_check(partition_info, offset, size);
|
|
|
|
if(ret_val != BK_OK)
|
|
return ret_val;
|
|
|
|
return flash_partition_write_perm_check(partition_info);
|
|
}
|
|
|