Skip to content

Commit c72c990

Browse files
committed
suit: Move IPUC initialization to the first op
Change flash_ipuc driver, so the memory is not initialized inside the constructor, but on the first operation done through flash API. Add an additional API that allows to filter out uninitialized IPUCs in the SUIT cache RW implementation, so the logic there will not read the memory contents that are erased upon the first IPUC flash API usage. Ref: NCSDK-32192 Signed-off-by: Tomasz Chyrowicz <[email protected]>
1 parent f85af7b commit c72c990

File tree

7 files changed

+625
-193
lines changed

7 files changed

+625
-193
lines changed

drivers/flash/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ if FLASH_IPUC
1515

1616
config FLASH_IPUC_COUNT
1717
int "Number of available flash IPUC drivers"
18-
default 1
18+
default 4
1919

2020
module = FLASH_IPUC
2121
module-str = Flash over SUIT IPUC

drivers/flash/flash_ipuc/flash_ipuc.c

Lines changed: 111 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,19 @@ struct ipuc_context {
4040
uintptr_t address;
4141
size_t size;
4242
bool read_access;
43+
bool setup_pending;
44+
#ifdef CONFIG_FLASH_PAGE_LAYOUT
45+
struct flash_pages_layout pages_layout;
46+
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
4347
};
4448

4549
#define DEFINE_NRF_IPUC_DATA(x, _) \
4650
static struct ipuc_context ipuc_context_data_##x = { \
4751
.component_id = {NULL, 0}, \
4852
.address = 0, \
4953
.size = 0, \
54+
.setup_pending = false, \
55+
.pages_layout = {0}, \
5056
}
5157

5258
#define DEFINE_NRF_IPUC(x, _) \
@@ -109,6 +115,18 @@ static int nrf_ipuc_write(const struct device *dev, off_t offset, const void *da
109115
return -ENOMEM;
110116
}
111117

118+
if (ctx->setup_pending) {
119+
LOG_DBG("setup: %p:%zu", (void *)ctx->address, ctx->size);
120+
121+
plat_ret = suit_ipuc_write_setup(&ctx->component_id, NULL, NULL);
122+
if (plat_ret != SUIT_PLAT_SUCCESS) {
123+
LOG_ERR("Failed to setup IPUC for writing: %d", plat_ret);
124+
return -EIO;
125+
}
126+
127+
ctx->setup_pending = false;
128+
}
129+
112130
LOG_DBG("write: %p:%zu", (void *)offset, len);
113131

114132
if (len == 0) {
@@ -182,10 +200,11 @@ static int nrf_ipuc_write(const struct device *dev, off_t offset, const void *da
182200

183201
static int nrf_ipuc_erase(const struct device *dev, off_t offset, size_t size)
184202
{
185-
static const uint8_t erase_block[WRITE_BLOCK_SIZE] __ALIGNED(CACHE_ALIGNMENT) = {
186-
ERASE_VALUE};
203+
const uint8_t erase_block[WRITE_BLOCK_SIZE] __ALIGNED(CACHE_ALIGNMENT) = {
204+
[0 ... WRITE_BLOCK_SIZE - 1] = ERASE_VALUE};
187205
suit_plat_err_t plat_ret = SUIT_PLAT_SUCCESS;
188206
struct ipuc_context *ctx = NULL;
207+
size_t bytes_erased = 0;
189208

190209
if (dev == NULL) {
191210
return -EINVAL;
@@ -209,17 +228,48 @@ static int nrf_ipuc_erase(const struct device *dev, off_t offset, size_t size)
209228
return -EIO;
210229
}
211230

231+
if (ctx->setup_pending) {
232+
/* Any write sets up the IPUC, which erases the whole area, so we may return here
233+
* immediately.
234+
*/
235+
return 0;
236+
}
237+
212238
LOG_DBG("erase: %p:%zu", (void *)offset, size);
213239

240+
if (size == ctx->size) {
241+
/* Optimize: Use write_setup() to erase the whole area with a single SSF IPC call.
242+
*/
243+
LOG_DBG("setup: %p:%zu", (void *)ctx->address, ctx->size);
244+
245+
plat_ret = suit_ipuc_write_setup(&ctx->component_id, NULL, NULL);
246+
if (plat_ret != SUIT_PLAT_SUCCESS) {
247+
LOG_ERR("Failed to erase IPUC through write setup: %d", plat_ret);
248+
return -EIO;
249+
}
250+
251+
return 0;
252+
}
253+
214254
while (size > 0) {
255+
bytes_erased = MIN(sizeof(erase_block), size);
215256
plat_ret = suit_ipuc_write(&ctx->component_id, offset, (uintptr_t)erase_block,
216-
sizeof(erase_block), false);
257+
bytes_erased, false);
217258
if (plat_ret != SUIT_PLAT_SUCCESS) {
259+
LOG_ERR("Failed to erase IPUC (%p:%zu): %d",
260+
(void *)(ctx->address + offset), bytes_erased, plat_ret);
218261
return -EIO;
219262
}
220263

221-
offset += sizeof(erase_block);
222-
size -= sizeof(erase_block);
264+
offset += bytes_erased;
265+
size -= bytes_erased;
266+
267+
/* The erase operation generates a lot of SSF requests.
268+
* It is necessary to give some time SDFW, so it is able to feed the watchdog.
269+
*/
270+
if ((offset % 0x10000 == 0) && (size > 0)) {
271+
k_sleep(K_MSEC(2));
272+
}
223273
}
224274

225275
return 0;
@@ -241,11 +291,31 @@ static const struct flash_parameters *nrf_ipuc_get_parameters(const struct devic
241291
return &parameters;
242292
}
243293

294+
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
295+
static void nrf_ipuc_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
296+
size_t *layout_size)
297+
{
298+
struct ipuc_context *ctx = NULL;
299+
300+
if (dev == NULL) {
301+
return;
302+
}
303+
304+
ctx = (struct ipuc_context *)dev->data;
305+
306+
*layout = &ctx->pages_layout;
307+
*layout_size = 1;
308+
}
309+
#endif
310+
244311
static const struct flash_driver_api nrf_ipuc_api = {
245312
.read = nrf_ipuc_read,
246313
.write = nrf_ipuc_write,
247314
.erase = nrf_ipuc_erase,
248315
.get_parameters = nrf_ipuc_get_parameters,
316+
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
317+
.page_layout = nrf_ipuc_page_layout,
318+
#endif
249319
};
250320

251321
static bool read_access_check(suit_manifest_role_t role)
@@ -338,7 +408,7 @@ static struct device *flash_component_ipuc(struct zcbor_string *component_id,
338408

339409
dev = get_free_dev();
340410
if (dev == NULL) {
341-
LOG_ERR("Maximum number of IPUCs reached");
411+
LOG_WRN("Unable to allocate new component IPUC device - no free instances");
342412
return NULL;
343413
}
344414

@@ -371,13 +441,6 @@ static struct device *flash_component_ipuc(struct zcbor_string *component_id,
371441
continue;
372442
}
373443

374-
plat_err = suit_ipuc_write_setup(&ctx->component_id, encryption_info,
375-
compression_info);
376-
if (plat_err != SUIT_PLAT_SUCCESS) {
377-
LOG_ERR("Failed to setup IPUC %d write: %d", i, plat_err);
378-
break;
379-
}
380-
381444
LOG_INF("IPUC for address range (0x%lx, 0x%x) created", ctx->address,
382445
ctx->size);
383446
}
@@ -388,6 +451,12 @@ static struct device *flash_component_ipuc(struct zcbor_string *component_id,
388451
ctx->read_access = false;
389452
}
390453

454+
ctx->setup_pending = true;
455+
#ifdef CONFIG_FLASH_PAGE_LAYOUT
456+
ctx->pages_layout.pages_count = 1;
457+
ctx->pages_layout.pages_size = ctx->size;
458+
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
459+
391460
return dev;
392461
}
393462

@@ -431,8 +500,15 @@ static struct device *flash_cache_ipuc(uintptr_t min_address, uintptr_t *ipuc_ad
431500
size_t i_max = 0;
432501
uintptr_t range_addr;
433502

503+
if ((ipuc_address == NULL) || (ipuc_size == NULL)) {
504+
LOG_WRN("Invalid input arguments: (0x%lx, 0x%lx)", (uintptr_t)ipuc_address,
505+
(uintptr_t)ipuc_size);
506+
return NULL;
507+
}
508+
434509
dev = get_free_dev();
435-
if ((dev == NULL) || (ipuc_address == NULL) || (ipuc_size == NULL)) {
510+
if (dev == NULL) {
511+
LOG_WRN("Unable to allocate new cache IPUC device - no free instances");
436512
return NULL;
437513
}
438514

@@ -497,16 +573,15 @@ static struct device *flash_cache_ipuc(uintptr_t min_address, uintptr_t *ipuc_ad
497573
}
498574

499575
if (!dry_run) {
500-
plat_err = suit_ipuc_write_setup(&ctx->component_id, NULL, NULL);
501-
if (plat_err != SUIT_PLAT_SUCCESS) {
502-
flash_ipuc_release(dev);
503-
return NULL;
504-
}
505-
506576
LOG_INF("Cache IPUC at idx %d for address range (0x%lx, 0x%x) created", i_max,
507577
ctx->address, ctx->size);
508578
}
509579

580+
ctx->setup_pending = true;
581+
#ifdef CONFIG_FLASH_PAGE_LAYOUT
582+
ctx->pages_layout.pages_count = 1;
583+
ctx->pages_layout.pages_size = ctx->size;
584+
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
510585
*ipuc_address = ctx->address;
511586
*ipuc_size = ctx->size;
512587

@@ -559,3 +634,19 @@ struct device *flash_ipuc_find(uintptr_t address, size_t size, uintptr_t *ipuc_a
559634

560635
return NULL;
561636
}
637+
638+
bool flash_ipuc_setup_pending(const struct device *dev)
639+
{
640+
struct ipuc_context *ctx;
641+
642+
if (dev == NULL) {
643+
return false;
644+
}
645+
646+
ctx = (struct ipuc_context *)dev->data;
647+
if (ctx->component_id.value != NULL) {
648+
return ctx->setup_pending;
649+
}
650+
651+
return false;
652+
}

include/drivers/flash/flash_ipuc.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ bool flash_cache_ipuc_check(uintptr_t min_address, uintptr_t *ipuc_address, size
8989
struct device *flash_ipuc_find(uintptr_t address, size_t size, uintptr_t *ipuc_address,
9090
size_t *ipuc_size);
9191

92+
/**
93+
* @brief Check if IPUC device was not initialized over SSF.
94+
*
95+
* @param[in] dev Reference to the IPUC device to release.
96+
*/
97+
bool flash_ipuc_setup_pending(const struct device *dev);
98+
9299
#ifdef __cplusplus
93100
}
94101
#endif

subsys/suit/cache/src/suit_dfu_cache_helpers.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,11 @@ static bool is_cache_ipuc_uninitialized(struct dfu_cache_pool *cache_pool)
2929
{
3030
uintptr_t ipuc_address;
3131
size_t ipuc_size;
32-
bool ipuc_possible =
33-
flash_cache_ipuc_check((uintptr_t)cache_pool->address, &ipuc_address, &ipuc_size);
32+
struct device *ipuc_dev = flash_ipuc_find((uintptr_t)cache_pool->address, cache_pool->size,
33+
&ipuc_address, &ipuc_size);
3434

35-
if (ipuc_possible) {
36-
if (flash_ipuc_find((uintptr_t)cache_pool->address, cache_pool->size, &ipuc_address,
37-
&ipuc_size) == NULL) {
38-
return true;
39-
}
35+
if ((ipuc_dev != NULL) && (flash_ipuc_setup_pending(ipuc_dev))) {
36+
return true;
4037
}
4138

4239
return false;

0 commit comments

Comments
 (0)