storage/flash_map: Separate layout and integrity functions
The commit separates conditionally compiled API calls to separate C files and moves conditional compilation to CMakeLists.txt. Inline helpers have been moved to flash_map_priv.h. Signed-off-by: Dominik Ermel <dominik.ermel@nordicsemi.no>
This commit is contained in:
parent
51e8db228b
commit
5f0dff61be
5 changed files with 244 additions and 196 deletions
|
@ -3,4 +3,5 @@
|
|||
zephyr_sources(flash_map.c)
|
||||
zephyr_sources_ifndef(CONFIG_FLASH_MAP_CUSTOM flash_map_default.c)
|
||||
zephyr_sources_ifdef(CONFIG_FLASH_MAP_SHELL flash_map_shell.c)
|
||||
|
||||
zephyr_sources_ifdef(CONFIG_FLASH_PAGE_LAYOUT flash_map_layout.c)
|
||||
zephyr_sources_ifdef(CONFIG_FLASH_AREA_CHECK_INTEGRITY flash_map_integrity.c)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2017-2021 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
* Copyright (c) 2017 Linaro Ltd
|
||||
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
|
||||
|
@ -12,42 +12,11 @@
|
|||
#include <sys/types.h>
|
||||
#include <device.h>
|
||||
#include <storage/flash_map.h>
|
||||
#include "flash_map_priv.h"
|
||||
#include <drivers/flash.h>
|
||||
#include <soc.h>
|
||||
#include <init.h>
|
||||
|
||||
#if defined(CONFIG_FLASH_AREA_CHECK_INTEGRITY)
|
||||
#include <tinycrypt/constants.h>
|
||||
#include <tinycrypt/sha256.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||
struct layout_data {
|
||||
uint32_t area_idx;
|
||||
uint32_t area_off;
|
||||
uint32_t area_len;
|
||||
void *ret; /* struct flash_area* or struct flash_sector* */
|
||||
uint32_t ret_idx;
|
||||
uint32_t ret_len;
|
||||
int status;
|
||||
};
|
||||
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
|
||||
|
||||
extern const struct flash_area *flash_map;
|
||||
extern const int flash_map_entries;
|
||||
|
||||
static struct flash_area const *get_flash_area_from_id(int idx)
|
||||
{
|
||||
for (int i = 0; i < flash_map_entries; i++) {
|
||||
if (flash_map[i].fa_id == idx) {
|
||||
return &flash_map[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void flash_area_foreach(flash_area_cb_t user_cb, void *user_data)
|
||||
{
|
||||
for (int i = 0; i < flash_map_entries; i++) {
|
||||
|
@ -77,111 +46,6 @@ void flash_area_close(const struct flash_area *fa)
|
|||
/* nothing to do for now */
|
||||
}
|
||||
|
||||
static inline bool is_in_flash_area_bounds(const struct flash_area *fa,
|
||||
off_t off, size_t len)
|
||||
{
|
||||
return (off >= 0) && ((off + len) <= fa->fa_size);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||
/*
|
||||
* Check if a flash_page_foreach() callback should exit early, due to
|
||||
* one of the following conditions:
|
||||
*
|
||||
* - The flash page described by "info" is before the area of interest
|
||||
* described in "data"
|
||||
* - The flash page is after the end of the area
|
||||
* - There are too many flash pages on the device to fit in the array
|
||||
* held in data->ret. In this case, data->status is set to -ENOMEM.
|
||||
*
|
||||
* The value to return to flash_page_foreach() is stored in
|
||||
* "bail_value" if the callback should exit early.
|
||||
*/
|
||||
static bool should_bail(const struct flash_pages_info *info,
|
||||
struct layout_data *data,
|
||||
bool *bail_value)
|
||||
{
|
||||
if (info->start_offset < data->area_off) {
|
||||
*bail_value = true;
|
||||
return true;
|
||||
} else if (info->start_offset >= data->area_off + data->area_len) {
|
||||
*bail_value = false;
|
||||
return true;
|
||||
} else if (data->ret_idx >= data->ret_len) {
|
||||
data->status = -ENOMEM;
|
||||
*bail_value = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic page layout discovery routine. This is kept separate to
|
||||
* support both the deprecated flash_area_to_sectors() and the current
|
||||
* flash_area_get_sectors(). A lot of this can be inlined once
|
||||
* flash_area_to_sectors() is removed.
|
||||
*/
|
||||
static int flash_area_layout(int idx, uint32_t *cnt, void *ret,
|
||||
flash_page_cb cb, struct layout_data *cb_data)
|
||||
{
|
||||
const struct device *flash_dev;
|
||||
const struct flash_area *fa;
|
||||
int rc = flash_area_open(idx, &fa);
|
||||
|
||||
if (rc < 0 || fa == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cb_data->area_idx = idx;
|
||||
cb_data->area_off = fa->fa_off;
|
||||
cb_data->area_len = fa->fa_size;
|
||||
|
||||
cb_data->ret = ret;
|
||||
cb_data->ret_idx = 0U;
|
||||
cb_data->ret_len = *cnt;
|
||||
cb_data->status = 0;
|
||||
|
||||
flash_dev = device_get_binding(fa->fa_dev_name);
|
||||
flash_area_close(fa);
|
||||
if (flash_dev == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
flash_page_foreach(flash_dev, cb, cb_data);
|
||||
|
||||
if (cb_data->status == 0) {
|
||||
*cnt = cb_data->ret_idx;
|
||||
}
|
||||
|
||||
return cb_data->status;
|
||||
}
|
||||
|
||||
static bool get_sectors_cb(const struct flash_pages_info *info, void *datav)
|
||||
{
|
||||
struct layout_data *data = datav;
|
||||
struct flash_sector *ret = data->ret;
|
||||
bool bail;
|
||||
|
||||
if (should_bail(info, data, &bail)) {
|
||||
return bail;
|
||||
}
|
||||
|
||||
ret[data->ret_idx].fs_off = info->start_offset - data->area_off;
|
||||
ret[data->ret_idx].fs_size = info->size;
|
||||
data->ret_idx++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
|
||||
{
|
||||
struct layout_data data;
|
||||
|
||||
return flash_area_layout(idx, cnt, ret, get_sectors_cb, &data);
|
||||
}
|
||||
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
|
||||
|
||||
int flash_area_read(const struct flash_area *fa, off_t off, void *dst,
|
||||
size_t len)
|
||||
{
|
||||
|
@ -260,60 +124,3 @@ uint8_t flash_area_erased_val(const struct flash_area *fa)
|
|||
|
||||
return param->erase_value;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FLASH_AREA_CHECK_INTEGRITY)
|
||||
int flash_area_check_int_sha256(const struct flash_area *fa,
|
||||
const struct flash_area_check *fac)
|
||||
{
|
||||
unsigned char hash[TC_SHA256_DIGEST_SIZE];
|
||||
struct tc_sha256_state_struct sha;
|
||||
const struct device *dev;
|
||||
int to_read;
|
||||
int pos;
|
||||
int rc;
|
||||
|
||||
if (fa == NULL || fac == NULL || fac->match == NULL ||
|
||||
fac->rbuf == NULL || fac->clen == 0 || fac->rblen == 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!is_in_flash_area_bounds(fa, fac->off, fac->clen)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tc_sha256_init(&sha) != TC_CRYPTO_SUCCESS) {
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
dev = device_get_binding(fa->fa_dev_name);
|
||||
to_read = fac->rblen;
|
||||
|
||||
for (pos = 0; pos < fac->clen; pos += to_read) {
|
||||
if (pos + to_read > fac->clen) {
|
||||
to_read = fac->clen - pos;
|
||||
}
|
||||
|
||||
rc = flash_read(dev, (fa->fa_off + fac->off + pos),
|
||||
fac->rbuf, to_read);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (tc_sha256_update(&sha,
|
||||
fac->rbuf,
|
||||
to_read) != TC_CRYPTO_SUCCESS) {
|
||||
return -ESRCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (tc_sha256_final(hash, &sha) != TC_CRYPTO_SUCCESS) {
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
if (memcmp(hash, fac->match, TC_SHA256_DIGEST_SIZE)) {
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_FLASH_AREA_CHECK_INTEGRITY */
|
||||
|
|
77
subsys/storage/flash_map/flash_map_integrity.c
Normal file
77
subsys/storage/flash_map/flash_map_integrity.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2021 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
* Copyright (c) 2017 Linaro Ltd
|
||||
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <device.h>
|
||||
#include <storage/flash_map.h>
|
||||
#include "flash_map_priv.h"
|
||||
#include <drivers/flash.h>
|
||||
#include <soc.h>
|
||||
#include <init.h>
|
||||
|
||||
#include <tinycrypt/constants.h>
|
||||
#include <tinycrypt/sha256.h>
|
||||
#include <string.h>
|
||||
|
||||
int flash_area_check_int_sha256(const struct flash_area *fa,
|
||||
const struct flash_area_check *fac)
|
||||
{
|
||||
unsigned char hash[TC_SHA256_DIGEST_SIZE];
|
||||
struct tc_sha256_state_struct sha;
|
||||
const struct device *dev;
|
||||
int to_read;
|
||||
int pos;
|
||||
int rc;
|
||||
|
||||
if (fa == NULL || fac == NULL || fac->match == NULL ||
|
||||
fac->rbuf == NULL || fac->clen == 0 || fac->rblen == 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!is_in_flash_area_bounds(fa, fac->off, fac->clen)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tc_sha256_init(&sha) != TC_CRYPTO_SUCCESS) {
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
dev = device_get_binding(fa->fa_dev_name);
|
||||
to_read = fac->rblen;
|
||||
|
||||
for (pos = 0; pos < fac->clen; pos += to_read) {
|
||||
if (pos + to_read > fac->clen) {
|
||||
to_read = fac->clen - pos;
|
||||
}
|
||||
|
||||
rc = flash_read(dev, (fa->fa_off + fac->off + pos),
|
||||
fac->rbuf, to_read);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (tc_sha256_update(&sha,
|
||||
fac->rbuf,
|
||||
to_read) != TC_CRYPTO_SUCCESS) {
|
||||
return -ESRCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (tc_sha256_final(hash, &sha) != TC_CRYPTO_SUCCESS) {
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
if (memcmp(hash, fac->match, TC_SHA256_DIGEST_SIZE)) {
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
124
subsys/storage/flash_map/flash_map_layout.c
Normal file
124
subsys/storage/flash_map/flash_map_layout.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2021 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
* Copyright (c) 2017 Linaro Ltd
|
||||
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <device.h>
|
||||
#include <storage/flash_map.h>
|
||||
#include <drivers/flash.h>
|
||||
#include <soc.h>
|
||||
#include <init.h>
|
||||
|
||||
struct layout_data {
|
||||
uint32_t area_idx;
|
||||
uint32_t area_off;
|
||||
uint32_t area_len;
|
||||
void *ret; /* struct flash_area* or struct flash_sector* */
|
||||
uint32_t ret_idx;
|
||||
uint32_t ret_len;
|
||||
int status;
|
||||
};
|
||||
|
||||
/*
|
||||
* Check if a flash_page_foreach() callback should exit early, due to
|
||||
* one of the following conditions:
|
||||
*
|
||||
* - The flash page described by "info" is before the area of interest
|
||||
* described in "data"
|
||||
* - The flash page is after the end of the area
|
||||
* - There are too many flash pages on the device to fit in the array
|
||||
* held in data->ret. In this case, data->status is set to -ENOMEM.
|
||||
*
|
||||
* The value to return to flash_page_foreach() is stored in
|
||||
* "bail_value" if the callback should exit early.
|
||||
*/
|
||||
static bool should_bail(const struct flash_pages_info *info,
|
||||
struct layout_data *data,
|
||||
bool *bail_value)
|
||||
{
|
||||
if (info->start_offset < data->area_off) {
|
||||
*bail_value = true;
|
||||
return true;
|
||||
} else if (info->start_offset >= data->area_off + data->area_len) {
|
||||
*bail_value = false;
|
||||
return true;
|
||||
} else if (data->ret_idx >= data->ret_len) {
|
||||
data->status = -ENOMEM;
|
||||
*bail_value = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic page layout discovery routine. This is kept separate to
|
||||
* support both the deprecated flash_area_to_sectors() and the current
|
||||
* flash_area_get_sectors(). A lot of this can be inlined once
|
||||
* flash_area_to_sectors() is removed.
|
||||
*/
|
||||
static int flash_area_layout(int idx, uint32_t *cnt, void *ret,
|
||||
flash_page_cb cb, struct layout_data *cb_data)
|
||||
{
|
||||
const struct device *flash_dev;
|
||||
const struct flash_area *fa;
|
||||
int rc = flash_area_open(idx, &fa);
|
||||
|
||||
if (rc < 0 || fa == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cb_data->area_idx = idx;
|
||||
cb_data->area_off = fa->fa_off;
|
||||
cb_data->area_len = fa->fa_size;
|
||||
|
||||
cb_data->ret = ret;
|
||||
cb_data->ret_idx = 0U;
|
||||
cb_data->ret_len = *cnt;
|
||||
cb_data->status = 0;
|
||||
|
||||
flash_dev = device_get_binding(fa->fa_dev_name);
|
||||
flash_area_close(fa);
|
||||
if (flash_dev == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
flash_page_foreach(flash_dev, cb, cb_data);
|
||||
|
||||
if (cb_data->status == 0) {
|
||||
*cnt = cb_data->ret_idx;
|
||||
}
|
||||
|
||||
return cb_data->status;
|
||||
}
|
||||
|
||||
static bool get_sectors_cb(const struct flash_pages_info *info, void *datav)
|
||||
{
|
||||
struct layout_data *data = datav;
|
||||
struct flash_sector *ret = data->ret;
|
||||
bool bail;
|
||||
|
||||
if (should_bail(info, data, &bail)) {
|
||||
return bail;
|
||||
}
|
||||
|
||||
ret[data->ret_idx].fs_off = info->start_offset - data->area_off;
|
||||
ret[data->ret_idx].fs_size = info->size;
|
||||
data->ret_idx++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
|
||||
{
|
||||
struct layout_data data;
|
||||
|
||||
return flash_area_layout(idx, cnt, ret, get_sectors_cb, &data);
|
||||
}
|
39
subsys/storage/flash_map/flash_map_priv.h
Normal file
39
subsys/storage/flash_map/flash_map_priv.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2021 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
* Copyright (c) 2017 Linaro Ltd
|
||||
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SUBSYS_STORAGE_FLASH_MAP_PRIV_H_
|
||||
#define ZEPHYR_SUBSYS_STORAGE_FLASH_MAP_PRIV_H_
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <device.h>
|
||||
|
||||
extern const struct flash_area *flash_map;
|
||||
extern const int flash_map_entries;
|
||||
|
||||
static inline struct flash_area const *get_flash_area_from_id(int idx)
|
||||
{
|
||||
for (int i = 0; i < flash_map_entries; i++) {
|
||||
if (flash_map[i].fa_id == idx) {
|
||||
return &flash_map[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static inline bool is_in_flash_area_bounds(const struct flash_area *fa,
|
||||
off_t off, size_t len)
|
||||
{
|
||||
return (off >= 0) && ((off + len) <= fa->fa_size);
|
||||
}
|
||||
|
||||
#endif /* ZEPHYR_SUBSYS_STORAGE_FLASH_MAP_PRIV_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue