diff --git a/src/fs/flash.c b/src/fs/flash.c index 53f739e..4d9361b 100644 --- a/src/fs/flash.c +++ b/src/fs/flash.c @@ -82,15 +82,16 @@ static size_t flash_record_size(uintptr_t base) { return 2 * sizeof(uintptr_t) + sizeof(uint16_t) + flash_record_length_size(base) + flash_record_payload_size(base); } -static uintptr_t allocate_free_addr(uint32_t size, bool persistent) { +static uintptr_t allocate_free_addr(uint32_t size, bool persistent, uintptr_t *publish_at) { size_t length_size = size >= FLASH_FILE_EXTENDED_LENGTH ? FLASH_FILE_EXTENDED_LENGTH_SIZE : FLASH_FILE_LEGACY_LENGTH_SIZE; size_t overhead = 2 * sizeof(uintptr_t) + sizeof(uint16_t) + length_size; size_t real_size = 0; uintptr_t next_base = 0x0, endp = end_data_pool, startp = start_data_pool; - if (size > SIZE_MAX - overhead) { + if (!publish_at || size > SIZE_MAX - overhead) { return 0x0; } + *publish_at = 0x0; real_size = overhead + size; if (persistent) { endp = end_rom_pool; @@ -121,12 +122,17 @@ static uintptr_t allocate_free_addr(uint32_t size, bool persistent) { } if (gap_reusable && potential_addr >= gap_start && potential_addr >= startp) { - flash_program_uintptr(potential_addr, next_base); - flash_program_uintptr(potential_addr + sizeof(uintptr_t), base); - if (next_base != 0x0) { - flash_program_uintptr(next_base + sizeof(uintptr_t), potential_addr); + int r = flash_program_uintptr(potential_addr, next_base); + if (r == PICOKEYS_OK) { + r = flash_program_uintptr(potential_addr + sizeof(uintptr_t), base); } - flash_program_uintptr(base, potential_addr); + if (r == PICOKEYS_OK && next_base != 0x0) { + r = flash_program_uintptr(next_base + sizeof(uintptr_t), potential_addr); + } + if (r != PICOKEYS_OK) { + return 0x0; + } + *publish_at = base; return potential_addr; } if (next_base == 0x0) { @@ -205,7 +211,8 @@ static int flash_write_data_to_file_internal(file_t *file, const_byte_array_t da file_t old_file = *file; bool replacing = old_file.data != NULL; - uintptr_t new_addr = allocate_free_addr(new_size, (file_get_type(file) & FILE_PERSISTENT) == FILE_PERSISTENT); + uintptr_t publish_at = 0x0; + uintptr_t new_addr = allocate_free_addr(new_size, (file_get_type(file) & FILE_PERSISTENT) == FILE_PERSISTENT, &publish_at); if (new_addr == 0x0) { return PICOKEYS_ERR_NO_MEMORY; } @@ -235,9 +242,13 @@ static int flash_write_data_to_file_internal(file_t *file, const_byte_array_t da if (r == PICOKEYS_OK && partial && replacing && write_end < old_size) { r = copy_file_range(&old_file, write_end, payload + write_end, old_size - write_end); } - if (r == PICOKEYS_OK && 2 * sizeof(uintptr_t) + sizeof(uint16_t) + length_size + new_size > FLASH_SECTOR_SIZE && !flash_commit_sync(5000u)) { + /* Publish only after the record is complete; across sectors the record must be durable first. */ + if (r == PICOKEYS_OK && (publish_at & ~(uintptr_t)(FLASH_SECTOR_SIZE - 1)) != (new_addr & ~(uintptr_t)(FLASH_SECTOR_SIZE - 1)) && !flash_commit_sync(5000u)) { r = PICOKEYS_ERR_MEMORY_FATAL; } + if (r == PICOKEYS_OK) { + r = flash_program_uintptr(publish_at, new_addr); + } if (r != PICOKEYS_OK) { flash_clear_file(&new_file); return r;