-
-
Save utzig/0e69b459e76b7e82e4f9a4d4fd796193 to your computer and use it in GitHub Desktop.
MCUBoot flash_map layer for ChibiOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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