Skip to content

Instantly share code, notes, and snippets.

@utzig
Forked from aport/flash_map.c
Created July 2, 2020 12:16
Show Gist options
  • Save utzig/0e69b459e76b7e82e4f9a4d4fd796193 to your computer and use it in GitHub Desktop.
Save utzig/0e69b459e76b7e82e4f9a4d4fd796193 to your computer and use it in GitHub Desktop.
MCUBoot flash_map layer for ChibiOS
#include <hal.h>
#include <flash_map_backend/flash_map_backend.h>
#include <bootconf.h>
/* License this file however you want, feel free to do anything */
/*
* This depends on a file bootconf.h which contains the following information:
* BOOT_CONFIG_FLASH_DRIVER The EFL driver (usually just &EFLD1)
* BOOT_AREA_BOOTLOADER_SIZE The size in bytes of the bootloader partition
* BOOT_AREA_IMAGE0_OFFSET Offset to the start of Slot 1 Image 0
* BOOT_AREA_IMAGE_SIZE Size of an image slot partition
* BOOT_AREA_IMAGE1_OFFSET Offset to the start of Slot 1 Image 1
*/
/*
* Note: This code has only been used/tested with MCUBOOT_OVERWRITE_ONLY
* and a single image slot.
* Dual image slots and swap with a scratch partition will require modifications.
*/
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
static BaseFlash *flash = (BaseFlash *)BOOT_CONFIG_FLASH_DRIVER;
static const struct flash_area flash_map[] = {
/* Bootloader */
{
.fa_id = 0U,
.fa_device_id = 0U,
.fa_off = 0U,
.fa_size = BOOT_AREA_BOOTLOADER_SIZE,
},
/* Slot 0 */
{
.fa_id = 1U,
.fa_device_id = 0U,
.fa_off = BOOT_AREA_IMAGE0_OFFSET,
.fa_size = BOOT_AREA_IMAGE_SIZE,
},
/* Slot 1 */
{
.fa_id = 2U,
.fa_device_id = 0U,
.fa_off = BOOT_AREA_IMAGE1_OFFSET,
.fa_size = BOOT_AREA_IMAGE_SIZE,
},
};
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
static flash_sector_t get_sector(uint32_t offset) {
const flash_descriptor_t *desc;
flash_sector_t sect = 0U;
uint32_t length = offset;
desc = flashGetDescriptor(flash);
while (sect < desc->sectors_count) {
if ((offset >= desc->sectors[sect].offset) &&
(length < desc->sectors[sect].size)) {
break;
}
length -= desc->sectors[sect].size;
++sect;
}
return sect;
}
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/** 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) {
size_t i;
for (i = 0U; i < (sizeof(flash_map) / sizeof(flash_map[0])); i++) {
if (flash_map[i].fa_id == id) {
*fa = &flash_map[i];
return 0;
}
}
return -1;
}
void flash_area_close(const struct flash_area *fa) {
(void)fa;
}
/** 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) {
flash_error_t err;
err = flashRead(flash, fa->fa_off + off, len, dst);
if (err != FLASH_NO_ERROR) {
return -1;
}
return 0;
}
/** 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) {
flash_error_t err;
err = flashProgram(flash, fa->fa_off + off, len, src);
if (err != FLASH_NO_ERROR) {
return -1;
}
return 0;
}
/** Erases `len` bytes of flash memory at `off` */
int flash_area_erase(const struct flash_area *fa, uint32_t off, uint32_t len) {
flash_sector_t sector;
flash_sector_t end;
sector = get_sector(fa->fa_off + off);
end = get_sector(fa->fa_off + off + len - 1U);
while (sector <= end) {
flash_error_t err;
err = flashStartEraseSector(flash, sector);
if (err != FLASH_NO_ERROR) {
return -1;
}
err = flashWaitErase(flash);
if (err != FLASH_NO_ERROR) {
return -1;
}
err = flashVerifyErase(flash, sector);
if (err != FLASH_NO_ERROR) {
return -1;
}
++sector;
}
return 0;
}
/** Returns this `flash_area`s alignment */
uint8_t flash_area_align(const struct flash_area *fa) {
(void)fa;
return (uint8_t)8U;
}
/** What is value is read from erased flash bytes. */
uint8_t flash_area_erased_val(const struct flash_area *fa) {
(void)fa;
return (uint8_t)0xFFU;
}
/** Reads len bytes from off, and checks if the read data is erased. Returns
1 if empty (that is containing erased value), 0 if not-empty, and -1 on
failure. */
int flash_area_read_is_empty(const struct flash_area *fa,
uint32_t off,
void *dst,
uint32_t len) {
uint8_t i;
uint8_t *b;
int ret;
ret = flash_area_read(fa, off, dst, len);
if (ret) {
return -1;
}
b = (uint8_t *)dst;
for (i = 0; i < len; i++) {
if (b[i] != (uint8_t)0xFFU) {
return 0;
}
}
return 1;
}
/** Given flash area ID, return info about sectors within the area. */
int flash_area_get_sectors(int fa_id,
uint32_t *count,
struct flash_sector *sectors) {
const struct flash_area *fa;
const flash_descriptor_t *desc;
if (flash_area_open(fa_id, &fa)) {
return -1;
}
if (*count < 1) {
return -1;
}
/* Get range of flash sectors from [beg,end) */
flash_sector_t beg = get_sector(fa->fa_off);
flash_sector_t end = get_sector(fa->fa_off + fa->fa_size - 1U) + 1U;
/* Make sure the caller can hold the number of sectors */
if (*count < (end - beg)) {
return -1;
}
*count = 0;
desc = flashGetDescriptor(flash);
do {
uint32_t size;
uint32_t offs;
if (desc->sectors_size != 0U) {
offs = desc->sectors_size * (*count);
size = desc->sectors_size;
}
else {
offs = desc->sectors[beg].offset;
size = desc->sectors[beg].size;
}
sectors[*count].fs_off = offs;
sectors[*count].fs_size = size;
++(*count);
++beg;
} while (beg < end);
return 0;
}
/** Returns the `fa_id` for slot, where slot is 0 (primary) or 1 (secondary).
`image_index` (0 or 1) is the index of the image. Image index is
relevant only when multi-image support support is enabled */
int flash_area_id_from_multi_image_slot(int image_index, int slot) {
int area;
switch (slot) {
case 0:
area = FLASH_AREA_IMAGE_PRIMARY(image_index);
break;
case 1:
area = FLASH_AREA_IMAGE_SECONDARY(image_index);
break;
#if !defined(MCUBOOT_OVERWRITE_ONLY)
case 2:
area = FLASH_AREA_IMAGE_SCRATCH;
break;
#endif
default:
return -1;
}
return area;
}
/** Returns the slot (0 for primary or 1 for secondary), for the supplied
`image_index` and `area_id`. `area_id` is unique and is represented by
`fa_id` in the `flash_area` struct. */
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;
}
int flash_area_id_from_image_slot(int slot) {
return flash_area_id_from_multi_image_slot(0, slot);
}
int flash_area_id_to_image_slot(int area_id) {
return flash_area_id_to_multi_image_slot(0, area_id);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment