719 lines
19 KiB
C
719 lines
19 KiB
C
|
|
/*********************************************************************
|
||
|
|
* @file mbr.c
|
||
|
|
* @brief
|
||
|
|
* @version 1.0
|
||
|
|
* @date 16 July 2016
|
||
|
|
* @author luwei
|
||
|
|
*
|
||
|
|
* @addtogroup mbr
|
||
|
|
* @ingroup
|
||
|
|
* @details
|
||
|
|
*
|
||
|
|
* @note
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*********************************************************************
|
||
|
|
* INCLUDES
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "om.h"
|
||
|
|
#include "mbr.h"
|
||
|
|
#include "om_driver.h"
|
||
|
|
|
||
|
|
/*********************************************************************
|
||
|
|
* MACROS
|
||
|
|
*/
|
||
|
|
#define TAG "[mbr]"
|
||
|
|
|
||
|
|
#define SECTOR_NIL 0xFF // uint8_t
|
||
|
|
|
||
|
|
/*********************************************************************
|
||
|
|
* LOCAL VARIABLES
|
||
|
|
*/
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
uint8_t sector_no_mas;
|
||
|
|
uint8_t sector_no_bak;
|
||
|
|
uint8_t probed;
|
||
|
|
} mbr_info_t;
|
||
|
|
|
||
|
|
static mbr_info_t m_mbr_info = {SECTOR_NIL, SECTOR_NIL, 0};
|
||
|
|
|
||
|
|
/********************************************************************
|
||
|
|
* LOCAL FUNCTIONS
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr sf sector verify
|
||
|
|
*
|
||
|
|
* @param[in] sector_n sector n
|
||
|
|
* @param[in] offset offset
|
||
|
|
* @param[in] data data
|
||
|
|
* @param[in] length length
|
||
|
|
*
|
||
|
|
* @return
|
||
|
|
**/
|
||
|
|
static bool mbr_sf_sector_is_ok(uint32_t sector_n, uint32_t offset, const void *data, uint32_t length)
|
||
|
|
{
|
||
|
|
__ALIGNED(8)
|
||
|
|
uint8_t vbuffer[64];
|
||
|
|
uint32_t voffset, vleft, vlength;
|
||
|
|
|
||
|
|
for (voffset = 0; voffset < length; voffset += vlength)
|
||
|
|
{
|
||
|
|
vleft = length - voffset;
|
||
|
|
vlength = vleft < sizeof(vbuffer) ? vleft : sizeof(vbuffer);
|
||
|
|
|
||
|
|
drv_sfs_read_sector_n(sector_n, offset + voffset, vbuffer, vlength);
|
||
|
|
|
||
|
|
if (memcmp((uint8_t *)data + voffset, vbuffer, vlength) != 0)
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr sf read sector
|
||
|
|
*
|
||
|
|
* @param[in] sector_n sector n
|
||
|
|
* @param[in] offset offset
|
||
|
|
* @param[in] data data
|
||
|
|
* @param[in] length length
|
||
|
|
**/
|
||
|
|
static void mbr_sf_read_sector_verify(uint32_t sector_n, uint32_t offset, void *data, uint32_t length)
|
||
|
|
{
|
||
|
|
do
|
||
|
|
{
|
||
|
|
drv_sfs_read_sector_n(sector_n, offset, data, length);
|
||
|
|
} while (!mbr_sf_sector_is_ok(sector_n, offset, data, length));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr sf erase write sector verify
|
||
|
|
*
|
||
|
|
* @param[in] sector_n sector n
|
||
|
|
* @param[in] offset offset
|
||
|
|
* @param[in] data data
|
||
|
|
* @param[in] length length
|
||
|
|
**/
|
||
|
|
static void mbr_sf_erase_write_sector_verify(uint32_t sector_n, uint32_t offset, const void *data, uint32_t length)
|
||
|
|
{
|
||
|
|
do
|
||
|
|
{
|
||
|
|
drv_sfs_erase_sector_n(sector_n);
|
||
|
|
drv_sfs_write_sector_n(sector_n, offset, data, length);
|
||
|
|
} while (!mbr_sf_sector_is_ok(sector_n, offset, data, length));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr sf write sector noverify
|
||
|
|
*
|
||
|
|
* @param[in] sector_n sector n
|
||
|
|
* @param[in] offset offset
|
||
|
|
* @param[in] data data
|
||
|
|
* @param[in] length length
|
||
|
|
**/
|
||
|
|
static void mbr_sf_write_sector_noverify(uint32_t sector_n, uint32_t offset, const void *data, uint32_t length)
|
||
|
|
{
|
||
|
|
drv_sfs_write_sector_n(sector_n, offset, data, length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*********************************************************************
|
||
|
|
* PUBLIC FUNCTIONS
|
||
|
|
*/
|
||
|
|
|
||
|
|
int mbr_validate_app(uint32_t addr, uint32_t len)
|
||
|
|
{
|
||
|
|
return 0; /* always ok, do validation after decrypted */
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr_get_security(), read option bytes and encryption key in iflash or xflash
|
||
|
|
*
|
||
|
|
* @return errno
|
||
|
|
**/
|
||
|
|
int mbr_get_security(uint32_t *p_option_bytes, uint8_t *p_key)
|
||
|
|
{
|
||
|
|
if (!drv_sfs_is_present())
|
||
|
|
{
|
||
|
|
// For OTP Burn
|
||
|
|
*p_option_bytes = 0xFFFFFFFF;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (p_option_bytes != NULL) {
|
||
|
|
DRV_SF_IFLASH_ENCRYPT_DISABLE();
|
||
|
|
mbr_sf_read_sector_verify(OPT_SECTOR_START, OPT_BYTES_OFFSET, p_option_bytes, sizeof(uint32_t));
|
||
|
|
DRV_SF_IFLASH_ENCRYPT_RESTORE();
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr_set_security(), program option bytes and encryption key in iflash or xflash
|
||
|
|
*
|
||
|
|
* @return errno
|
||
|
|
**/
|
||
|
|
int mbr_set_security(uint32_t option_bytes, uint8_t *p_key)
|
||
|
|
{
|
||
|
|
/* swap write */
|
||
|
|
__ALIGNED(8)
|
||
|
|
uint8_t buf[DRV_SF_SECTOR_SIZE];
|
||
|
|
|
||
|
|
if (!drv_sfs_is_present())
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
// disable encrypt
|
||
|
|
DRV_SF_IFLASH_ENCRYPT_DISABLE();
|
||
|
|
|
||
|
|
mbr_sf_read_sector_verify(OPT_SECTOR_START, 0, buf, DRV_SF_SECTOR_SIZE);
|
||
|
|
|
||
|
|
// new option bytes
|
||
|
|
*(uint32_t *)(&buf[OPT_BYTES_OFFSET]) = option_bytes;
|
||
|
|
|
||
|
|
// write
|
||
|
|
mbr_sf_erase_write_sector_verify(OPT_SECTOR_START, 0, buf, DRV_SF_SECTOR_SIZE);
|
||
|
|
|
||
|
|
// restore encrypt
|
||
|
|
DRV_SF_IFLASH_ENCRYPT_RESTORE();
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr set security option with mask
|
||
|
|
*
|
||
|
|
* @param[in] option_mask option bytes
|
||
|
|
*
|
||
|
|
* @return errno
|
||
|
|
**/
|
||
|
|
int mbr_set_security_option_with_mask(uint32_t option_mask, uint32_t option_value, uint32_t *new_option)
|
||
|
|
{
|
||
|
|
uint32_t option_bytes;
|
||
|
|
int error = mbr_get_security(&option_bytes, NULL);
|
||
|
|
if (error >= 0)
|
||
|
|
{
|
||
|
|
option_bytes = (option_bytes & ~option_mask) | option_value;
|
||
|
|
error = mbr_set_security(option_bytes, NULL);
|
||
|
|
if (error >= 0)
|
||
|
|
error = mbr_get_security(new_option, NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
return error;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr_probe(), probe mbr data and its swap during boot or isp
|
||
|
|
*
|
||
|
|
* @return errno or 0 if mbr is valid
|
||
|
|
**/
|
||
|
|
int mbr_probe(bool create_if_fail)
|
||
|
|
{
|
||
|
|
uint8_t i, sector_no;
|
||
|
|
uint16_t sigs[2];
|
||
|
|
|
||
|
|
sector_no = MBR_SECTOR_START;
|
||
|
|
for (i = 0; i < 2; i++)
|
||
|
|
{
|
||
|
|
mbr_sf_read_sector_verify(sector_no + i, DOS_PART_MAGIC_OFFSET, &sigs[i], sizeof(uint16_t));
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((sigs[0] != MBR_SIGNATURE) && (sigs[1] != MBR_SIGNATURE))
|
||
|
|
{
|
||
|
|
if (create_if_fail)
|
||
|
|
{
|
||
|
|
sigs[0] = MBR_SIGNATURE;
|
||
|
|
mbr_sf_erase_write_sector_verify(sector_no, DOS_PART_MAGIC_OFFSET, &sigs[0], sizeof(uint16_t));
|
||
|
|
m_mbr_info.sector_no_mas = sector_no;
|
||
|
|
m_mbr_info.sector_no_bak = sector_no + 1;
|
||
|
|
m_mbr_info.probed = 1;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_mbr_info.probed = 0;
|
||
|
|
}
|
||
|
|
return -ENXIO;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (sigs[0] == MBR_SIGNATURE)
|
||
|
|
{
|
||
|
|
m_mbr_info.sector_no_mas = sector_no;
|
||
|
|
m_mbr_info.sector_no_bak = sector_no + 1;
|
||
|
|
m_mbr_info.probed = 1;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (sigs[1] == MBR_SIGNATURE)
|
||
|
|
{
|
||
|
|
m_mbr_info.sector_no_mas = sector_no + 1;
|
||
|
|
m_mbr_info.sector_no_bak = sector_no;
|
||
|
|
m_mbr_info.probed = 1;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return -ENODEV;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr_read_part(), get the specific partition's location, len and crc
|
||
|
|
* @note don't switch chip select, but use the current flash
|
||
|
|
*
|
||
|
|
* @return errno or 0 if found
|
||
|
|
**/
|
||
|
|
int mbr_read_part(int img_type, uint32_t *p_addr, uint32_t *p_len, uint16_t *p_crc)
|
||
|
|
{
|
||
|
|
mbr_part_t part;
|
||
|
|
int data_off;
|
||
|
|
int idx;
|
||
|
|
|
||
|
|
if (!m_mbr_info.probed)
|
||
|
|
{
|
||
|
|
mbr_probe(false /*create_if_fail*/);
|
||
|
|
if (SECTOR_NIL == m_mbr_info.sector_no_mas)
|
||
|
|
return -ENODEV;
|
||
|
|
}
|
||
|
|
if ((uint8_t)img_type & PART_TYPE_MASK_HS)
|
||
|
|
idx = img_type - PART_TYPE_APP;
|
||
|
|
else
|
||
|
|
idx = img_type;
|
||
|
|
if (idx >= MBR_PART_NUM)
|
||
|
|
return -EINVAL;
|
||
|
|
|
||
|
|
data_off = DOS_PART_TBL_OFFSET + idx * sizeof(mbr_part_t);
|
||
|
|
|
||
|
|
mbr_sf_read_sector_verify(m_mbr_info.sector_no_mas, data_off, &part, sizeof(mbr_part_t));
|
||
|
|
|
||
|
|
if (part.partitionType == img_type)
|
||
|
|
{
|
||
|
|
if (p_addr)
|
||
|
|
*p_addr = part.firstLBA << DRV_SF_SECTOR_SHIFT;
|
||
|
|
if (p_len)
|
||
|
|
*p_len = part.lengthLBA;
|
||
|
|
if (p_crc)
|
||
|
|
*p_crc = part.crc16;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return -ENOENT;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr_alloc_part(), allocate a partition during ISP
|
||
|
|
* @note don't switch chip select, but use the current flash
|
||
|
|
*
|
||
|
|
* @return errno or 0 if success
|
||
|
|
**/
|
||
|
|
int mbr_alloc_part(int img_type, uint32_t *p_addr, uint32_t len)
|
||
|
|
{
|
||
|
|
uint32_t cfg_addr, addr;
|
||
|
|
|
||
|
|
if (!m_mbr_info.probed)
|
||
|
|
{
|
||
|
|
mbr_probe(true /*create_if_fail*/);
|
||
|
|
if (SECTOR_NIL == m_mbr_info.sector_no_mas)
|
||
|
|
return -ENODEV;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* cfg partition's address in default: don't occupy the last sector */
|
||
|
|
cfg_addr = drv_sfs_capacity() - DRV_SF_SECTOR_SIZE * (2 + 1 /*cfg's swap*/ + 1 /*trace id*/);
|
||
|
|
|
||
|
|
if (PART_TYPE_APP == img_type)
|
||
|
|
{
|
||
|
|
/* app partition's address in default */
|
||
|
|
addr = APP_SECTOR_START * DRV_SF_SECTOR_SIZE;
|
||
|
|
if ((addr + len) > cfg_addr)
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
#ifdef CONFIG_PATCH_PACKAGE_ON_FLASH
|
||
|
|
else if (PART_TYPE_PATCH == img_type)
|
||
|
|
{
|
||
|
|
/* put near to cfg partition and align to sector */
|
||
|
|
addr = cfg_addr - len;
|
||
|
|
addr = addr & ~(DRV_SF_SECTOR_SIZE - 1);
|
||
|
|
|
||
|
|
/* check collision with the existing app partition */
|
||
|
|
{
|
||
|
|
uint32_t app_addr, app_len;
|
||
|
|
int err;
|
||
|
|
err = mbr_read_part(PART_TYPE_APP, &app_addr, &app_len, NULL);
|
||
|
|
if ((err >= 0) && (addr < (app_addr + app_len)))
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
else if (PART_TYPE_CFG == img_type)
|
||
|
|
{
|
||
|
|
addr = cfg_addr;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (p_addr)
|
||
|
|
*p_addr = addr;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr_write_part(), write a partition during ISP
|
||
|
|
* @note don't switch chip select, but use the current flash
|
||
|
|
*
|
||
|
|
* @return errno or 0 if success
|
||
|
|
**/
|
||
|
|
int mbr_write_part(int img_type, uint32_t addr, uint32_t len, uint16_t crc)
|
||
|
|
{
|
||
|
|
mbr_part_t part;
|
||
|
|
int idx, data_off;
|
||
|
|
uint32_t invalid_mbr_part_magic = 0;
|
||
|
|
|
||
|
|
if (!m_mbr_info.probed)
|
||
|
|
{
|
||
|
|
mbr_probe(true /*create_if_fail*/);
|
||
|
|
if (SECTOR_NIL == m_mbr_info.sector_no_mas)
|
||
|
|
return -ENODEV;
|
||
|
|
}
|
||
|
|
if ((uint8_t)img_type & PART_TYPE_MASK_HS)
|
||
|
|
idx = img_type - PART_TYPE_APP;
|
||
|
|
else
|
||
|
|
idx = img_type;
|
||
|
|
if (idx >= MBR_PART_NUM)
|
||
|
|
return -EINVAL;
|
||
|
|
|
||
|
|
data_off = DOS_PART_TBL_OFFSET + idx * sizeof(mbr_part_t);
|
||
|
|
|
||
|
|
// make sure write is ok
|
||
|
|
while (1)
|
||
|
|
{
|
||
|
|
mbr_sf_read_sector_verify(m_mbr_info.sector_no_mas, data_off, &part, sizeof(mbr_part_t));
|
||
|
|
|
||
|
|
if ((part.partitionType == img_type) &&
|
||
|
|
(part.crc16 == crc) &&
|
||
|
|
(part.firstLBA == (addr >> DRV_SF_SECTOR_SHIFT)) &&
|
||
|
|
(part.lengthLBA == len))
|
||
|
|
{
|
||
|
|
/* same with the existing */
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
/* swap write */
|
||
|
|
__ALIGNED(8)
|
||
|
|
uint8_t buf[512];
|
||
|
|
/* Backup */
|
||
|
|
mbr_sf_read_sector_verify(m_mbr_info.sector_no_mas, 0, buf, sizeof(buf));
|
||
|
|
mbr_sf_erase_write_sector_verify(m_mbr_info.sector_no_bak, 0, buf, sizeof(buf));
|
||
|
|
/* Destroy used section magic code */
|
||
|
|
mbr_sf_write_sector_noverify(m_mbr_info.sector_no_mas, DOS_PART_MAGIC_OFFSET, &invalid_mbr_part_magic, sizeof(uint16_t));
|
||
|
|
/* Fresh new */
|
||
|
|
part.partitionType = img_type;
|
||
|
|
part.crc16 = crc;
|
||
|
|
part.firstLBA = addr >> DRV_SF_SECTOR_SHIFT;
|
||
|
|
part.lengthLBA = len;
|
||
|
|
memcpy(buf + data_off, &part, sizeof(mbr_part_t));
|
||
|
|
mbr_sf_erase_write_sector_verify(m_mbr_info.sector_no_mas, 0, buf, sizeof(buf));
|
||
|
|
/* Destroy backup section magic code */
|
||
|
|
mbr_sf_write_sector_noverify(m_mbr_info.sector_no_bak, DOS_PART_MAGIC_OFFSET, &invalid_mbr_part_magic, sizeof(uint16_t));
|
||
|
|
/* ok */
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int mbr_write_clock(uint8_t clock, uint8_t width, uint8_t delay)
|
||
|
|
{
|
||
|
|
int data_off;
|
||
|
|
uint32_t old;
|
||
|
|
uint32_t new = (delay << 16u) | (width << 8u) | (clock << 0u); // FIXME: endian
|
||
|
|
uint32_t invalid_mbr_part_magic = 0;
|
||
|
|
|
||
|
|
data_off = FLASH_CLOCK_OFFSET;
|
||
|
|
|
||
|
|
// make sure write is ok
|
||
|
|
while (1)
|
||
|
|
{
|
||
|
|
mbr_sf_read_sector_verify(m_mbr_info.sector_no_mas, data_off, &old, FLASH_SETTINGS_SIZE);
|
||
|
|
old &= 0xFFFFFF;
|
||
|
|
|
||
|
|
if (old == new)
|
||
|
|
{
|
||
|
|
/* same with the existing */
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
/* swap write */
|
||
|
|
__ALIGNED(8)
|
||
|
|
uint8_t buf[512];
|
||
|
|
/* Backup */
|
||
|
|
mbr_sf_read_sector_verify(m_mbr_info.sector_no_mas, 0, buf, sizeof(buf));
|
||
|
|
mbr_sf_erase_write_sector_verify(m_mbr_info.sector_no_bak, 0, buf, sizeof(buf));
|
||
|
|
/* Destroy used section magic code */
|
||
|
|
mbr_sf_write_sector_noverify(m_mbr_info.sector_no_mas, DOS_PART_MAGIC_OFFSET, &invalid_mbr_part_magic, sizeof(uint16_t));
|
||
|
|
/* Fresh new */
|
||
|
|
memcpy(buf + data_off, &new, FLASH_SETTINGS_SIZE);
|
||
|
|
mbr_sf_erase_write_sector_verify(m_mbr_info.sector_no_mas, 0, buf, sizeof(buf));
|
||
|
|
/* Destroy backup section magic code */
|
||
|
|
mbr_sf_write_sector_noverify(m_mbr_info.sector_no_bak, DOS_PART_MAGIC_OFFSET, &invalid_mbr_part_magic, sizeof(uint16_t));
|
||
|
|
/* ok */
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void mbr_boost_clock(void)
|
||
|
|
{
|
||
|
|
uint8_t settings[FLASH_SETTINGS_SIZE];
|
||
|
|
uint32_t freq_hz;
|
||
|
|
drv_sf_width_t width;
|
||
|
|
uint8_t delay;
|
||
|
|
|
||
|
|
mbr_sf_read_sector_verify(m_mbr_info.sector_no_mas, FLASH_CLOCK_OFFSET, &settings, FLASH_SETTINGS_SIZE);
|
||
|
|
|
||
|
|
if (settings[0] != 0xFF && settings[1] != 0xFF && settings[2] != 0xFF)
|
||
|
|
{
|
||
|
|
freq_hz = settings[0] * 1000000;
|
||
|
|
width = settings[1] ? (drv_sf_width_t)settings[1] : DRV_SF_WIDTH_1LINE;
|
||
|
|
delay = settings[2];
|
||
|
|
drv_sfs_config(freq_hz, width, delay);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void mbr_restore_clock(void)
|
||
|
|
{
|
||
|
|
drv_sfs_config(DRV_SFS_CLK_FREQ_HZ_DEF, DRV_SF_WIDTH_1LINE, DRV_SF_DELAY_DEFAULT);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief mbr_get_app(), get the address and length of app partition during boot
|
||
|
|
* @note don't toggle the pins of xflash, unless there is no app in iflash
|
||
|
|
* @note if partition is valid, it will boost flash at new clock and data width.
|
||
|
|
*
|
||
|
|
* @param[in] p_addr the pointer to the address of app partition in byte
|
||
|
|
* @param[in] p_len the pointer to the length of app partition in byte
|
||
|
|
*
|
||
|
|
* @return errno or chip select
|
||
|
|
**/
|
||
|
|
int mbr_get_app(uint32_t *p_addr, uint32_t *p_len, uint16_t *p_crc)
|
||
|
|
{
|
||
|
|
int err;
|
||
|
|
uint32_t addr, len;
|
||
|
|
uint8_t mbr_in_iflash = 0;
|
||
|
|
|
||
|
|
err = drv_sfs_probe(DRV_SFS_IFLASH, DRV_SFS_CLK_FREQ_HZ_DEF);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
/* iflash is present */
|
||
|
|
err = mbr_probe(false /*create_if_fail*/);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
mbr_in_iflash = 1;
|
||
|
|
/* try app with iflash's MBR */
|
||
|
|
err = mbr_read_part(PART_TYPE_APP, &addr, &len, p_crc);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
/* try improve clock and data width */
|
||
|
|
mbr_boost_clock();
|
||
|
|
err = mbr_validate_app(addr, len);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
err = DRV_SFS_IFLASH;
|
||
|
|
goto ret_ok;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
err = drv_sfs_probe(DRV_SFS_XFLASH, DRV_SFS_CLK_FREQ_HZ_DEF);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
/* xflash is present */
|
||
|
|
err = mbr_probe(false /*create_if_fail*/);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
/* try app with xflash's MBR */
|
||
|
|
err = mbr_read_part(PART_TYPE_APP, &addr, &len, p_crc);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
/* try improve clock and data width */
|
||
|
|
mbr_boost_clock();
|
||
|
|
err = mbr_validate_app(addr, len);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
err = DRV_SFS_XFLASH;
|
||
|
|
goto ret_ok;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* restore to the flash in case of patch in iflash */
|
||
|
|
if (mbr_in_iflash)
|
||
|
|
drv_sfs_select(DRV_SFS_IFLASH);
|
||
|
|
return -ENOEXEC;
|
||
|
|
|
||
|
|
ret_ok:
|
||
|
|
if (p_addr)
|
||
|
|
*p_addr = addr;
|
||
|
|
if (p_len)
|
||
|
|
*p_len = len;
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef CONFIG_PATCH_PACKAGE_ON_FLASH
|
||
|
|
/**
|
||
|
|
* @brief mbr_get_patch(), get the address and length of patch partition during boot
|
||
|
|
* @note don't toggle the pins of xflash, unless there is no patch in iflash
|
||
|
|
* @note don't boost flash at new clock and data width.
|
||
|
|
*
|
||
|
|
* @param[in] p_addr the pointer to the address of patch partition in byte
|
||
|
|
* @param[in] p_len the pointer to the length of patch partition in byte
|
||
|
|
*
|
||
|
|
* @return errno or chip select
|
||
|
|
**/
|
||
|
|
int mbr_get_patch(uint32_t *p_addr, uint32_t *p_len, uint16_t *p_crc)
|
||
|
|
{
|
||
|
|
int err;
|
||
|
|
uint32_t addr, len;
|
||
|
|
uint8_t mbr_in_iflash = 0;
|
||
|
|
|
||
|
|
err = drv_sfs_probe(DRV_SFS_IFLASH, DRV_SFS_CLK_FREQ_HZ_DEF);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
/* iflash is present */
|
||
|
|
err = mbr_probe(false /*create_if_fail*/);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
mbr_in_iflash = 1;
|
||
|
|
/* try patch with iflash's MBR */
|
||
|
|
err = mbr_read_part(PART_TYPE_PATCH, &addr, &len, p_crc);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
err = DRV_SFS_IFLASH;
|
||
|
|
goto ret_ok;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/* don't toggle xflash's pins if app in iflash */
|
||
|
|
if (mbr_in_iflash)
|
||
|
|
return -ENOEXEC;
|
||
|
|
|
||
|
|
err = drv_sfs_probe(DRV_SFS_XFLASH, DRV_SFS_CLK_FREQ_HZ_DEF);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
/* xflash is present */
|
||
|
|
err = mbr_probe(false /*create_if_fail*/);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
/* try patch with xflash's MBR */
|
||
|
|
err = mbr_read_part(PART_TYPE_PATCH, &addr, &len, p_crc);
|
||
|
|
if (err >= 0)
|
||
|
|
{
|
||
|
|
err = DRV_SFS_XFLASH;
|
||
|
|
goto ret_ok;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* restore to the flash in case of cfg in iflash */
|
||
|
|
if (mbr_in_iflash)
|
||
|
|
drv_sfs_select(DRV_SFS_IFLASH);
|
||
|
|
return -ENOEXEC;
|
||
|
|
|
||
|
|
ret_ok:
|
||
|
|
if (p_addr)
|
||
|
|
*p_addr = addr;
|
||
|
|
if (p_len)
|
||
|
|
*p_len = len;
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if 0
|
||
|
|
/**
|
||
|
|
* @brief get cpft address and length
|
||
|
|
*
|
||
|
|
* @param[out] p_addr cpft base address
|
||
|
|
* @param[out] p_len cpft length
|
||
|
|
*
|
||
|
|
* @return errno or 0 success
|
||
|
|
**/
|
||
|
|
int mbr_get_cpft(uint32_t *p_addr, uint32_t *p_len)
|
||
|
|
{
|
||
|
|
uint32_t capacity = drv_sfs_capacity();
|
||
|
|
|
||
|
|
if(capacity == 0)
|
||
|
|
return -ENOEXEC;
|
||
|
|
|
||
|
|
if(p_len)
|
||
|
|
*p_len = DRV_SF_SECTOR_SIZE;
|
||
|
|
if(p_addr)
|
||
|
|
*p_addr = capacity - DRV_SF_SECTOR_SIZE;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief get free space address and length
|
||
|
|
*
|
||
|
|
* @param[out] p_addr free space address
|
||
|
|
* @param[out] p_len freee space length
|
||
|
|
*
|
||
|
|
* @return errno or 0 success
|
||
|
|
**/
|
||
|
|
int mbr_get_free_area(uint32_t *p_addr, uint32_t *p_len)
|
||
|
|
{
|
||
|
|
int err;
|
||
|
|
uint32_t app_base, app_len;
|
||
|
|
uint32_t patch_base, patch_len;
|
||
|
|
uint32_t free_base, free_limit, free_len;
|
||
|
|
uint32_t sector_mask;
|
||
|
|
uint16_t crc;
|
||
|
|
int capacity = drv_sfs_capacity();
|
||
|
|
|
||
|
|
if(capacity == 0)
|
||
|
|
return -ENOEXEC;
|
||
|
|
|
||
|
|
err = mbr_read_part(PART_TYPE_APP, &app_base, &app_len, &crc);
|
||
|
|
if(err)
|
||
|
|
free_base = APP_SECTOR_START<<DRV_SF_SECTOR_SHIFT;
|
||
|
|
else
|
||
|
|
free_base = app_base + app_len;
|
||
|
|
|
||
|
|
err = mbr_read_part(PART_TYPE_PATCH, &patch_base, &patch_len, &crc);
|
||
|
|
if(err)
|
||
|
|
{
|
||
|
|
uint32_t cfg_base, cfg_len;
|
||
|
|
err = mbr_read_part(PART_TYPE_CFG, &cfg_base, &cfg_len, &crc);
|
||
|
|
if(err)
|
||
|
|
{
|
||
|
|
uint32_t cpft_base, cpft_len;
|
||
|
|
err = mbr_get_cpft(&cpft_base, &cpft_len);
|
||
|
|
if(err)
|
||
|
|
free_limit = capacity;
|
||
|
|
else
|
||
|
|
free_limit = cpft_base;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
free_limit = cfg_base;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
free_limit = patch_base;
|
||
|
|
}
|
||
|
|
free_len = free_limit - free_base;
|
||
|
|
|
||
|
|
sector_mask = DRV_SF_SECTOR_SIZE - 1;
|
||
|
|
|
||
|
|
*p_addr = (free_base + sector_mask) & ~sector_mask;
|
||
|
|
*p_len = free_len & ~sector_mask;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
#endif
|