548 lines
14 KiB
C
548 lines
14 KiB
C
/*
|
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
* Copyright (c) 2020 Cypress Semiconductor Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you 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.
|
|
*/
|
|
/*******************************************************************************/
|
|
|
|
#ifdef MCUBOOT_HAVE_ASSERT_H
|
|
#include "mcuboot_config/mcuboot_assert.h"
|
|
#else
|
|
#include <assert.h>
|
|
#endif
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
|
|
#include "mcuboot_config/mcuboot_config.h"
|
|
#include "flash_map_backend/flash_map_backend.h"
|
|
#include <sysflash/sysflash.h>
|
|
|
|
#include "bootutil/bootutil_log.h"
|
|
|
|
#include "cy_pdl.h"
|
|
|
|
#ifdef CY_BOOT_USE_EXTERNAL_FLASH
|
|
#include "cy_smif_psoc6.h"
|
|
#endif
|
|
/*
|
|
* For now, we only support one flash device.
|
|
*
|
|
* Pick a random device ID for it that's unlikely to collide with
|
|
* anything "real".
|
|
*/
|
|
#define FLASH_DEVICE_ID 111
|
|
#define FLASH_MAP_ENTRY_MAGIC 0xd00dbeef
|
|
|
|
#define FLASH_AREA_IMAGE_SECTOR_SIZE FLASH_AREA_IMAGE_SCRATCH_SIZE
|
|
|
|
#ifndef CY_BOOTLOADER_START_ADDRESS
|
|
#define CY_BOOTLOADER_START_ADDRESS (0x10000000)
|
|
#endif
|
|
|
|
#ifndef CY_BOOT_INTERNAL_FLASH_ERASE_VALUE
|
|
/* This is the value of internal flash bytes after an erase */
|
|
#define CY_BOOT_INTERNAL_FLASH_ERASE_VALUE (0x00)
|
|
#endif
|
|
|
|
#ifndef CY_BOOT_EXTERNAL_FLASH_ERASE_VALUE
|
|
/* This is the value of external flash bytes after an erase */
|
|
#define CY_BOOT_EXTERNAL_FLASH_ERASE_VALUE (0xff)
|
|
#endif
|
|
|
|
#ifdef CY_FLASH_MAP_EXT_DESC
|
|
/* Nothing to be there when external FlashMap Descriptors are used */
|
|
#else
|
|
static struct flash_area bootloader =
|
|
{
|
|
.fa_id = FLASH_AREA_BOOTLOADER,
|
|
.fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
|
|
.fa_off = CY_BOOTLOADER_START_ADDRESS,
|
|
.fa_size = CY_BOOT_BOOTLOADER_SIZE
|
|
};
|
|
|
|
static struct flash_area primary_1 =
|
|
{
|
|
.fa_id = FLASH_AREA_IMAGE_PRIMARY(0),
|
|
.fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
|
|
.fa_off = CY_FLASH_BASE + CY_BOOT_BOOTLOADER_SIZE,
|
|
.fa_size = CY_BOOT_PRIMARY_1_SIZE
|
|
};
|
|
|
|
#ifndef CY_BOOT_USE_EXTERNAL_FLASH
|
|
static struct flash_area secondary_1 =
|
|
{
|
|
.fa_id = FLASH_AREA_IMAGE_SECONDARY(0),
|
|
.fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
|
|
.fa_off = CY_FLASH_BASE +\
|
|
CY_BOOT_BOOTLOADER_SIZE +\
|
|
CY_BOOT_PRIMARY_1_SIZE,
|
|
.fa_size = CY_BOOT_SECONDARY_1_SIZE
|
|
};
|
|
#else
|
|
static struct flash_area secondary_1 =
|
|
{
|
|
.fa_id = FLASH_AREA_IMAGE_SECONDARY(0),
|
|
.fa_device_id = FLASH_DEVICE_EXTERNAL_FLASH(CY_BOOT_EXTERNAL_DEVICE_INDEX),
|
|
.fa_off = CY_SMIF_BASE_MEM_OFFSET,
|
|
.fa_size = CY_BOOT_SECONDARY_1_SIZE
|
|
};
|
|
#endif
|
|
#if (MCUBOOT_IMAGE_NUMBER == 2) /* if dual-image */
|
|
static struct flash_area primary_2 =
|
|
{
|
|
.fa_id = FLASH_AREA_IMAGE_PRIMARY(1),
|
|
.fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
|
|
.fa_off = CY_FLASH_BASE +\
|
|
CY_BOOT_BOOTLOADER_SIZE +\
|
|
CY_BOOT_PRIMARY_1_SIZE +\
|
|
CY_BOOT_SECONDARY_1_SIZE,
|
|
.fa_size = CY_BOOT_PRIMARY_2_SIZE
|
|
};
|
|
|
|
static struct flash_area secondary_2 =
|
|
{
|
|
.fa_id = FLASH_AREA_IMAGE_SECONDARY(1),
|
|
/* it is for external flash memory
|
|
.fa_device_id = FLASH_DEVICE_EXTERNAL_FLASH(CY_BOOT_EXTERNAL_DEVICE_INDEX), */
|
|
#ifndef CY_BOOT_USE_EXTERNAL_FLASH
|
|
.fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
|
|
.fa_off = CY_FLASH_BASE +\
|
|
CY_BOOT_BOOTLOADER_SIZE +\
|
|
CY_BOOT_PRIMARY_1_SIZE +\
|
|
CY_BOOT_SECONDARY_1_SIZE +\
|
|
CY_BOOT_PRIMARY_2_SIZE,
|
|
#else
|
|
.fa_device_id = FLASH_DEVICE_EXTERNAL_FLASH(CY_BOOT_EXTERNAL_DEVICE_INDEX),
|
|
.fa_off = CY_SMIF_BASE_MEM_OFFSET + 0x40000,
|
|
#endif
|
|
.fa_size = CY_BOOT_SECONDARY_2_SIZE
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef MCUBOOT_SWAP_USING_SCRATCH
|
|
static struct flash_area scratch =
|
|
{
|
|
.fa_id = FLASH_AREA_IMAGE_SCRATCH,
|
|
.fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
|
|
#if (MCUBOOT_IMAGE_NUMBER == 1) /* if single-image */
|
|
.fa_off = CY_FLASH_BASE +\
|
|
CY_BOOT_BOOTLOADER_SIZE +\
|
|
CY_BOOT_PRIMARY_1_SIZE +\
|
|
CY_BOOT_SECONDARY_1_SIZE,
|
|
#elif (MCUBOOT_IMAGE_NUMBER == 2) /* if dual-image */
|
|
.fa_off = CY_FLASH_BASE +\
|
|
CY_BOOT_BOOTLOADER_SIZE +\
|
|
CY_BOOT_PRIMARY_1_SIZE +\
|
|
CY_BOOT_SECONDARY_1_SIZE +\
|
|
CY_BOOT_PRIMARY_2_SIZE +\
|
|
CY_BOOT_SECONDARY_2_SIZE,
|
|
#endif
|
|
.fa_size = CY_BOOT_SCRATCH_SIZE
|
|
};
|
|
#endif
|
|
|
|
#ifdef CY_FLASH_MAP_EXT_DESC
|
|
/* Use external Flash Map Descriptors */
|
|
extern struct flash_area *boot_area_descs[];
|
|
#else
|
|
struct flash_area *boot_area_descs[] =
|
|
{
|
|
&bootloader,
|
|
&primary_1,
|
|
&secondary_1,
|
|
#if (MCUBOOT_IMAGE_NUMBER == 2) /* if dual-image */
|
|
&primary_2,
|
|
&secondary_2,
|
|
#endif
|
|
#ifdef MCUBOOT_SWAP_USING_SCRATCH
|
|
&scratch,
|
|
#endif
|
|
NULL
|
|
};
|
|
#endif
|
|
|
|
/* Returns device flash start based on supported fa_id */
|
|
int flash_device_base(uint8_t fd_id, uintptr_t *ret)
|
|
{
|
|
if (fd_id != FLASH_DEVICE_INTERNAL_FLASH) {
|
|
BOOT_LOG_ERR("invalid flash ID %d; expected %d",
|
|
fd_id, FLASH_DEVICE_INTERNAL_FLASH);
|
|
return -1;
|
|
}
|
|
*ret = CY_FLASH_BASE;
|
|
return 0;
|
|
}
|
|
|
|
/* Opens the area for use. id is one of the `fa_id`s */
|
|
int flash_area_open(uint8_t id, const struct flash_area **fa)
|
|
{
|
|
int ret = -1;
|
|
uint32_t i = 0;
|
|
|
|
while(NULL != boot_area_descs[i])
|
|
{
|
|
if(id == boot_area_descs[i]->fa_id)
|
|
{
|
|
*fa = boot_area_descs[i];
|
|
ret = 0;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void flash_area_close(const struct flash_area *fa)
|
|
{
|
|
(void)fa;/* Nothing to do there */
|
|
}
|
|
|
|
/*
|
|
* Reads `len` bytes of flash memory at `off` to the buffer at `dst`
|
|
*/
|
|
int flash_area_read(const struct flash_area *fa, uint32_t off, void *dst,
|
|
uint32_t len)
|
|
{
|
|
int rc = 0;
|
|
size_t addr;
|
|
|
|
/* check if requested offset not less then flash area (fa) start */
|
|
assert(off < fa->fa_off);
|
|
assert(off + len < fa->fa_off);
|
|
/* convert to absolute address inside a device*/
|
|
addr = fa->fa_off + off;
|
|
|
|
if (fa->fa_device_id == FLASH_DEVICE_INTERNAL_FLASH)
|
|
{
|
|
/* flash read by simple memory copying */
|
|
memcpy((void *)dst, (const void*)addr, (size_t)len);
|
|
}
|
|
#ifdef CY_BOOT_USE_EXTERNAL_FLASH
|
|
else if ((fa->fa_device_id & FLASH_DEVICE_EXTERNAL_FLAG) == FLASH_DEVICE_EXTERNAL_FLAG)
|
|
{
|
|
rc = psoc6_smif_read(fa, addr, dst, len);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* incorrect/non-existing flash device id */
|
|
rc = -1;
|
|
}
|
|
|
|
if (rc != 0) {
|
|
BOOT_LOG_ERR("Flash area read error, rc = %d", (int)rc);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Writes `len` bytes of flash memory at `off` from the buffer at `src`
|
|
*/
|
|
int flash_area_write(const struct flash_area *fa, uint32_t off,
|
|
const void *src, uint32_t len)
|
|
{
|
|
cy_en_flashdrv_status_t rc = CY_FLASH_DRV_SUCCESS;
|
|
size_t write_start_addr;
|
|
size_t write_end_addr;
|
|
const uint32_t * row_ptr = NULL;
|
|
|
|
assert(off < fa->fa_off);
|
|
assert(off + len < fa->fa_off);
|
|
|
|
/* convert to absolute address inside a device */
|
|
write_start_addr = fa->fa_off + off;
|
|
write_end_addr = fa->fa_off + off + len;
|
|
|
|
if (fa->fa_device_id == FLASH_DEVICE_INTERNAL_FLASH)
|
|
{
|
|
uint32_t row_number = 0;
|
|
uint32_t row_addr = 0;
|
|
|
|
assert(!(len % CY_FLASH_SIZEOF_ROW));
|
|
assert(!(write_start_addr % CY_FLASH_SIZEOF_ROW));
|
|
|
|
row_number = (write_end_addr - write_start_addr) / CY_FLASH_SIZEOF_ROW;
|
|
row_addr = write_start_addr;
|
|
|
|
row_ptr = (uint32_t *) src;
|
|
|
|
for (uint32_t i = 0; i < row_number; i++)
|
|
{
|
|
rc = Cy_Flash_WriteRow(row_addr, row_ptr);
|
|
|
|
row_addr += (uint32_t) CY_FLASH_SIZEOF_ROW;
|
|
row_ptr = row_ptr + CY_FLASH_SIZEOF_ROW / 4;
|
|
}
|
|
}
|
|
#ifdef CY_BOOT_USE_EXTERNAL_FLASH
|
|
else if ((fa->fa_device_id & FLASH_DEVICE_EXTERNAL_FLAG) == FLASH_DEVICE_EXTERNAL_FLAG)
|
|
{
|
|
rc = psoc6_smif_write(fa, write_start_addr, src, len);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* incorrect/non-existing flash device id */
|
|
rc = -1;
|
|
}
|
|
|
|
return (int) rc;
|
|
}
|
|
|
|
/*< Erases `len` bytes of flash memory at `off` */
|
|
int flash_area_erase(const struct flash_area *fa, uint32_t off, uint32_t len)
|
|
{
|
|
cy_en_flashdrv_status_t rc = CY_FLASH_DRV_SUCCESS;
|
|
size_t erase_start_addr;
|
|
size_t erase_end_addr;
|
|
|
|
assert(off < fa->fa_off);
|
|
assert(off + len < fa->fa_off);
|
|
assert(!(len % CY_FLASH_SIZEOF_ROW));
|
|
|
|
/* convert to absolute address inside a device*/
|
|
erase_start_addr = fa->fa_off + off;
|
|
erase_end_addr = fa->fa_off + off + len;
|
|
|
|
if (fa->fa_device_id == FLASH_DEVICE_INTERNAL_FLASH)
|
|
{
|
|
int row_number = 0;
|
|
uint32_t row_addr = 0;
|
|
|
|
row_number = (erase_end_addr - erase_start_addr) / CY_FLASH_SIZEOF_ROW;
|
|
|
|
while (row_number != 0)
|
|
{
|
|
row_number--;
|
|
row_addr = erase_start_addr + row_number * (uint32_t) CY_FLASH_SIZEOF_ROW;
|
|
rc = Cy_Flash_EraseRow(row_addr);
|
|
}
|
|
}
|
|
#ifdef CY_BOOT_USE_EXTERNAL_FLASH
|
|
else if ((fa->fa_device_id & FLASH_DEVICE_EXTERNAL_FLAG) == FLASH_DEVICE_EXTERNAL_FLAG)
|
|
{
|
|
rc = psoc6_smif_erase(erase_start_addr, len);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* incorrect/non-existing flash device id */
|
|
rc = -1;
|
|
}
|
|
return (int) rc;
|
|
}
|
|
|
|
/*< Returns this `flash_area`s alignment */
|
|
uint32_t flash_area_align(const struct flash_area *fa)
|
|
{
|
|
int ret = -1;
|
|
if (fa->fa_device_id == FLASH_DEVICE_INTERNAL_FLASH)
|
|
{
|
|
ret = CY_FLASH_ALIGN;
|
|
}
|
|
#ifdef CY_BOOT_USE_EXTERNAL_FLASH
|
|
else if ((fa->fa_device_id & FLASH_DEVICE_EXTERNAL_FLAG) == FLASH_DEVICE_EXTERNAL_FLAG)
|
|
{
|
|
return qspi_get_prog_size();
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* incorrect/non-existing flash device id */
|
|
ret = -1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
|
|
/*< Initializes an array of flash_area elements for the slot's sectors */
|
|
int flash_area_to_sectors(int idx, int *cnt, struct flash_area *fa)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (fa->fa_device_id == FLASH_DEVICE_INTERNAL_FLASH)
|
|
{
|
|
(void)idx;
|
|
(void)cnt;
|
|
rc = 0;
|
|
}
|
|
#ifdef CY_BOOT_USE_EXTERNAL_FLASH
|
|
else if ((fa->fa_device_id & FLASH_DEVICE_EXTERNAL_FLAG) == FLASH_DEVICE_EXTERNAL_FLAG)
|
|
{
|
|
(void)idx;
|
|
(void)cnt;
|
|
rc = 0;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* incorrect/non-existing flash device id */
|
|
rc = -1;
|
|
}
|
|
return rc;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* This depends on the mappings defined in sysflash.h.
|
|
* MCUBoot uses continuous numbering for the primary slot, the secondary slot,
|
|
* and the scratch while zephyr might number it differently.
|
|
*/
|
|
int flash_area_id_from_multi_image_slot(int image_index, int slot)
|
|
{
|
|
switch (slot) {
|
|
case 0: return FLASH_AREA_IMAGE_PRIMARY(image_index);
|
|
case 1: return FLASH_AREA_IMAGE_SECONDARY(image_index);
|
|
case 2: return FLASH_AREA_IMAGE_SCRATCH;
|
|
}
|
|
|
|
return -1; /* flash_area_open will fail on that */
|
|
}
|
|
|
|
int flash_area_id_from_image_slot(int slot)
|
|
{
|
|
return flash_area_id_from_multi_image_slot(0, slot);
|
|
}
|
|
|
|
int flash_area_id_to_multi_image_slot(int image_index, int area_id)
|
|
{
|
|
if (area_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
|
|
return 0;
|
|
}
|
|
if (area_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
|
|
return 1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
uint8_t flash_area_erased_val(const struct flash_area *fap)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (fap->fa_device_id == FLASH_DEVICE_INTERNAL_FLASH)
|
|
{
|
|
ret = CY_BOOT_INTERNAL_FLASH_ERASE_VALUE;
|
|
}
|
|
#ifdef CY_BOOT_USE_EXTERNAL_FLASH
|
|
else if ((fap->fa_device_id & FLASH_DEVICE_EXTERNAL_FLAG) == FLASH_DEVICE_EXTERNAL_FLAG)
|
|
{
|
|
ret = CY_BOOT_EXTERNAL_FLASH_ERASE_VALUE;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
assert(false) ;
|
|
}
|
|
|
|
return ret ;
|
|
}
|
|
|
|
int flash_area_read_is_empty(const struct flash_area *fa, uint32_t off,
|
|
void *dst, uint32_t len)
|
|
{
|
|
uint8_t *mem_dest;
|
|
int rc;
|
|
|
|
mem_dest = (uint8_t *)dst;
|
|
rc = flash_area_read(fa, off, dst, len);
|
|
if (rc) {
|
|
return -1;
|
|
}
|
|
|
|
for (uint8_t i = 0; i < len; i++) {
|
|
if (mem_dest[i] != flash_area_erased_val(fa)) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
|
|
int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
|
|
{
|
|
int rc = 0;
|
|
uint32_t i = 0;
|
|
struct flash_area *fa = NULL;
|
|
|
|
while(NULL != boot_area_descs[i])
|
|
{
|
|
if(idx == boot_area_descs[i]->fa_id)
|
|
{
|
|
fa = boot_area_descs[i];
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if(NULL != boot_area_descs[i])
|
|
{
|
|
size_t sector_size = 0;
|
|
|
|
if(fa->fa_device_id == FLASH_DEVICE_INTERNAL_FLASH)
|
|
{
|
|
sector_size = CY_FLASH_SIZEOF_ROW;
|
|
}
|
|
#ifdef CY_BOOT_USE_EXTERNAL_FLASH
|
|
else if((fa->fa_device_id & FLASH_DEVICE_EXTERNAL_FLAG) == FLASH_DEVICE_EXTERNAL_FLAG)
|
|
{
|
|
/* implement for SMIF */
|
|
/* lets assume they are equal */
|
|
sector_size = CY_FLASH_SIZEOF_ROW;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
rc = -1;
|
|
}
|
|
|
|
if(0 == rc)
|
|
{
|
|
uint32_t addr = 0;
|
|
size_t sectors_n = 0;
|
|
|
|
sectors_n = (fa->fa_size + (sector_size - 1)) / sector_size;
|
|
assert(sectors_n <= *cnt);
|
|
|
|
addr = fa->fa_off;
|
|
for(i = 0; i < sectors_n; i++)
|
|
{
|
|
ret[i].fs_size = sector_size ;
|
|
ret[i].fs_off = addr ;
|
|
addr += sector_size ;
|
|
}
|
|
|
|
*cnt = sectors_n;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
#endif
|