blob: d064d8b7b28cf11c1ea161524f77948cf0531e2f [file] [log] [blame]
Almir Okato14763b12021-11-25 00:45:26 -03001/*
Almir Okatodb2024e2023-08-24 15:40:26 -03002 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
Almir Okato14763b12021-11-25 00:45:26 -03003 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <strings.h>
8#include "bootloader_flash_priv.h"
9#include "bootloader_random.h"
10#include "esp_image_format.h"
11#include "esp_flash_encrypt.h"
12#include "esp_flash_partitions.h"
13#include "esp_secure_boot.h"
14#include "esp_efuse.h"
15#include "esp_efuse_table.h"
16#include "esp_log.h"
17#include "hal/wdt_hal.h"
Almir Okatodb2024e2023-08-24 15:40:26 -030018#include "hal/efuse_hal.h"
Almir Okatob365e232022-03-08 01:35:54 -030019#include "soc/soc_caps.h"
Almir Okatodb2024e2023-08-24 15:40:26 -030020#ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
21#include "soc/sensitive_reg.h"
22#endif
Almir Okato14763b12021-11-25 00:45:26 -030023
24#include "esp_mcuboot_image.h"
25
26#if CONFIG_IDF_TARGET_ESP32
27#define CRYPT_CNT ESP_EFUSE_FLASH_CRYPT_CNT
28#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT
29#else
30#define CRYPT_CNT ESP_EFUSE_SPI_BOOT_CRYPT_CNT
31#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT
32#endif
33
Almir Okatodb2024e2023-08-24 15:40:26 -030034#define FLASH_ENC_CNT_MAX (CRYPT_CNT[0]->bit_count)
35
Almir Okato14763b12021-11-25 00:45:26 -030036/* This file implements FLASH ENCRYPTION related APIs to perform
37 * various operations such as programming necessary flash encryption
38 * eFuses, detect whether flash encryption is enabled (by reading eFuse)
39 * and if required encrypt the partitions in flash memory
40 */
41
42static const char *TAG = "flash_encrypt";
43
44/* Static functions for stages of flash encryption */
Almir Okato14763b12021-11-25 00:45:26 -030045static esp_err_t encrypt_bootloader(void);
46static esp_err_t encrypt_primary_slot(void);
Almir Okatodb2024e2023-08-24 15:40:26 -030047static size_t get_flash_encrypt_cnt_value(void);
Almir Okato14763b12021-11-25 00:45:26 -030048
Almir Okato54ef4842023-03-07 17:56:53 -030049/**
50 * This former inlined function must not be defined in the header file anymore.
51 * As it depends on efuse component, any use of it outside of `bootloader_support`,
52 * would require the caller component to include `efuse` as part of its `REQUIRES` or
53 * `PRIV_REQUIRES` entries.
54 * Attribute IRAM_ATTR must be specified for the app build.
55 */
56bool IRAM_ATTR esp_flash_encryption_enabled(void)
57{
Almir Okato54ef4842023-03-07 17:56:53 -030058#ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
Almir Okatodb2024e2023-08-24 15:40:26 -030059 return efuse_hal_flash_encryption_enabled();
Almir Okato54ef4842023-03-07 17:56:53 -030060#else
Almir Okatodb2024e2023-08-24 15:40:26 -030061 uint32_t flash_crypt_cnt = 0;
Almir Okato54ef4842023-03-07 17:56:53 -030062#if CONFIG_IDF_TARGET_ESP32
63 esp_efuse_read_field_blob(ESP_EFUSE_FLASH_CRYPT_CNT, &flash_crypt_cnt, ESP_EFUSE_FLASH_CRYPT_CNT[0]->bit_count);
64#else
65 esp_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, ESP_EFUSE_SPI_BOOT_CRYPT_CNT[0]->bit_count);
66#endif
Almir Okato54ef4842023-03-07 17:56:53 -030067 /* __builtin_parity is in flash, so we calculate parity inline */
68 bool enabled = false;
69 while (flash_crypt_cnt) {
70 if (flash_crypt_cnt & 1) {
71 enabled = !enabled;
72 }
73 flash_crypt_cnt >>= 1;
74 }
75 return enabled;
Almir Okatodb2024e2023-08-24 15:40:26 -030076#endif // CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
Almir Okato54ef4842023-03-07 17:56:53 -030077}
78
Almir Okatodb2024e2023-08-24 15:40:26 -030079static size_t get_flash_encrypt_cnt_value(void)
Almir Okato14763b12021-11-25 00:45:26 -030080{
81 size_t flash_crypt_cnt = 0;
82 esp_efuse_read_field_cnt(CRYPT_CNT, &flash_crypt_cnt);
Almir Okatodb2024e2023-08-24 15:40:26 -030083 return flash_crypt_cnt;
84}
85
86bool esp_flash_encrypt_initialized_once(void)
87{
88 return get_flash_encrypt_cnt_value() != 0;
89}
90
91bool esp_flash_encrypt_is_write_protected(bool print_error)
92{
93 if (esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT)) {
94 if (print_error) {
95 ESP_LOGE(TAG, "Flash Encryption cannot be enabled (CRYPT_CNT (%d) is write protected)", get_flash_encrypt_cnt_value());
96 }
97 return true;
98 }
99 return false;
100}
101
102bool esp_flash_encrypt_state(void)
103{
104 size_t flash_crypt_cnt = get_flash_encrypt_cnt_value();
105 bool flash_crypt_wr_dis = esp_flash_encrypt_is_write_protected(false);
Almir Okato14763b12021-11-25 00:45:26 -0300106
107 ESP_LOGV(TAG, "CRYPT_CNT %d, write protection %d", flash_crypt_cnt, flash_crypt_wr_dis);
108
109 if (flash_crypt_cnt % 2 == 1) {
110 /* Flash is already encrypted */
Almir Okatodb2024e2023-08-24 15:40:26 -0300111 int left = (FLASH_ENC_CNT_MAX - flash_crypt_cnt) / 2;
Almir Okato14763b12021-11-25 00:45:26 -0300112 if (flash_crypt_wr_dis) {
113 left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */
114 }
115 ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left);
Almir Okatodb2024e2023-08-24 15:40:26 -0300116 return true;
117 }
118 return false;
119}
120
121esp_err_t esp_flash_encrypt_check_and_update(void)
122{
123 bool flash_encryption_enabled = esp_flash_encrypt_state();
124 if (!flash_encryption_enabled) {
Almir Okato14763b12021-11-25 00:45:26 -0300125#ifndef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
Almir Okatodb2024e2023-08-24 15:40:26 -0300126 if (esp_flash_encrypt_is_write_protected(true)) {
127 return ESP_FAIL;
128 }
129
130 esp_err_t err = esp_flash_encrypt_init();
131 if (err != ESP_OK) {
132 ESP_LOGE(TAG, "Initialization of Flash encryption key failed (%d)", err);
133 return err;
134 }
135
136 err = esp_flash_encrypt_contents();
137 if (err != ESP_OK) {
138 ESP_LOGE(TAG, "Encryption flash contents failed (%d)", err);
139 return err;
140 }
141
142 err = esp_flash_encrypt_enable();
143 if (err != ESP_OK) {
144 ESP_LOGE(TAG, "Enabling of Flash encryption failed (%d)", err);
145 return err;
146 }
Almir Okato14763b12021-11-25 00:45:26 -0300147#else
148 ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED "
149 "is set, refusing to boot.");
150 return ESP_ERR_INVALID_STATE;
151#endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
152 }
Almir Okatodb2024e2023-08-24 15:40:26 -0300153 return ESP_OK;
Almir Okato14763b12021-11-25 00:45:26 -0300154}
155
156static esp_err_t check_and_generate_encryption_keys(void)
157{
158 size_t key_size = 32;
159#ifdef CONFIG_IDF_TARGET_ESP32
160 enum { BLOCKS_NEEDED = 1 };
161 esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
162 ESP_EFUSE_KEY_PURPOSE_FLASH_ENCRYPTION,
163 };
164 esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_ENCRYPT_FLASH);
165 if (coding_scheme != EFUSE_CODING_SCHEME_NONE && coding_scheme != EFUSE_CODING_SCHEME_3_4) {
166 ESP_LOGE(TAG, "Unknown/unsupported CODING_SCHEME value 0x%x", coding_scheme);
167 return ESP_ERR_NOT_SUPPORTED;
168 }
169 if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
170 key_size = 24;
171 }
172#else
173#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES256
174 enum { BLOCKS_NEEDED = 2 };
175 esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
176 ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1,
177 ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2,
178 };
179 if (esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, NULL)) {
180 ESP_LOGE(TAG, "XTS_AES_128_KEY is already in use, XTS_AES_256_KEY_1/2 can not be used");
181 return ESP_ERR_INVALID_STATE;
182 }
183#else
Almir Okatodb2024e2023-08-24 15:40:26 -0300184#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES128_DERIVED
185 enum { BLOCKS_NEEDED = 1 };
186 esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
187 ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS,
188 };
189 key_size = 16;
190#else
Almir Okato14763b12021-11-25 00:45:26 -0300191 enum { BLOCKS_NEEDED = 1 };
192 esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
193 ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
194 };
Almir Okatodb2024e2023-08-24 15:40:26 -0300195#endif // CONFIG_SECURE_FLASH_ENCRYPTION_AES128_DERIVED
Almir Okato14763b12021-11-25 00:45:26 -0300196#endif // CONFIG_SECURE_FLASH_ENCRYPTION_AES256
197#endif // CONFIG_IDF_TARGET_ESP32
198
199 /* Initialize all efuse block entries to invalid (max) value */
200 esp_efuse_block_t blocks[BLOCKS_NEEDED] = {[0 ... BLOCKS_NEEDED-1] = EFUSE_BLK_KEY_MAX};
201 bool has_key = true;
202 for (unsigned i = 0; i < BLOCKS_NEEDED; i++) {
203 bool tmp_has_key = esp_efuse_find_purpose(purposes[i], &blocks[i]);
204 if (tmp_has_key) { // For ESP32: esp_efuse_find_purpose() always returns True, need to check whether the key block is used or not.
205 tmp_has_key &= !esp_efuse_key_block_unused(blocks[i]);
206 }
207 if (i == 1 && tmp_has_key != has_key) {
208 ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set.");
209 return ESP_ERR_INVALID_STATE;
210 }
211 has_key &= tmp_has_key;
212 }
213
214 if (!has_key) {
215 /* Generate key */
216 uint8_t keys[BLOCKS_NEEDED][32] = { 0 };
217 ESP_LOGI(TAG, "Generating new flash encryption key...");
218 for (unsigned i = 0; i < BLOCKS_NEEDED; ++i) {
219 bootloader_fill_random(keys[i], key_size);
220 }
221 ESP_LOGD(TAG, "Key generation complete");
222
223 esp_err_t err = esp_efuse_write_keys(purposes, keys, BLOCKS_NEEDED);
224 if (err != ESP_OK) {
225 if (err == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
226 ESP_LOGE(TAG, "Not enough free efuse key blocks (need %d) to continue", BLOCKS_NEEDED);
227 } else {
228 ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", err);
229 }
230 return err;
231 }
232 } else {
233 for (unsigned i = 0; i < BLOCKS_NEEDED; i++) {
234 if (!esp_efuse_get_key_dis_write(blocks[i])
235 || !esp_efuse_get_key_dis_read(blocks[i])
236 || !esp_efuse_get_keypurpose_dis_write(blocks[i])) { // For ESP32: no keypurpose, it returns always True.
237 ESP_LOGE(TAG, "Invalid key state, check read&write protection for key and keypurpose(if exists)");
238 return ESP_ERR_INVALID_STATE;
239 }
240 }
241 ESP_LOGI(TAG, "Using pre-loaded flash encryption key in efuse");
242 }
243 return ESP_OK;
244}
245
Almir Okatodb2024e2023-08-24 15:40:26 -0300246esp_err_t esp_flash_encrypt_init(void)
Almir Okato14763b12021-11-25 00:45:26 -0300247{
Almir Okatodb2024e2023-08-24 15:40:26 -0300248 if (esp_flash_encryption_enabled() || esp_flash_encrypt_initialized_once()) {
249 return ESP_OK;
250 }
251
252 /* Very first flash encryption pass: generate keys, etc. */
253
Almir Okato14763b12021-11-25 00:45:26 -0300254 esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
255
256 /* Before first flash encryption pass, need to initialise key & crypto config */
257 esp_err_t err = check_and_generate_encryption_keys();
258 if (err != ESP_OK) {
259 esp_efuse_batch_write_cancel();
260 return err;
261 }
262
263 err = esp_flash_encryption_enable_secure_features();
264 if (err != ESP_OK) {
265 esp_efuse_batch_write_cancel();
266 return err;
267 }
268
Almir Okato14763b12021-11-25 00:45:26 -0300269 err = esp_efuse_batch_write_commit();
270 if (err != ESP_OK) {
271 ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
272 return err;
273 }
274
275 return ESP_OK;
276}
277
278/* Encrypt all flash data that should be encrypted */
Almir Okatodb2024e2023-08-24 15:40:26 -0300279esp_err_t esp_flash_encrypt_contents(void)
Almir Okato14763b12021-11-25 00:45:26 -0300280{
281 esp_err_t err;
282
Almir Okatodb2024e2023-08-24 15:40:26 -0300283#ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
284 REG_WRITE(SENSITIVE_XTS_AES_KEY_UPDATE_REG, 1);
285#endif
Almir Okato14763b12021-11-25 00:45:26 -0300286
287 err = encrypt_bootloader();
288 if (err != ESP_OK) {
289 return err;
290 }
291
292 /* If the primary slot executable application is not encrypted,
293 * then encrypt it
294 */
295 err = encrypt_primary_slot();
296 if (err != ESP_OK) {
297 return err;
298 }
299
300 /* Unconditionally encrypts remaining regions
301 * This will need changes when implementing multi-slot support
302 */
303 ESP_LOGI(TAG, "Encrypting remaining flash...");
Almir Okatoa1d641d2022-02-21 19:31:46 -0300304 uint32_t region_addr = CONFIG_ESP_IMAGE0_SECONDARY_START_ADDRESS;
Almir Okato14763b12021-11-25 00:45:26 -0300305 size_t region_size = CONFIG_ESP_APPLICATION_SIZE;
306 err = esp_flash_encrypt_region(region_addr, region_size);
307 if (err != ESP_OK) {
308 return err;
309 }
310 region_addr = CONFIG_ESP_SCRATCH_OFFSET;
311 region_size = CONFIG_ESP_SCRATCH_SIZE;
312 err = esp_flash_encrypt_region(region_addr, region_size);
313 if (err != ESP_OK) {
314 return err;
315 }
316
Almir Okatoa1d641d2022-02-21 19:31:46 -0300317#if defined(CONFIG_ESP_IMAGE_NUMBER) && (CONFIG_ESP_IMAGE_NUMBER == 2)
318 region_addr = CONFIG_ESP_IMAGE1_PRIMARY_START_ADDRESS;
319 region_size = CONFIG_ESP_APPLICATION_SIZE;
320 err = esp_flash_encrypt_region(region_addr, region_size);
321 if (err != ESP_OK) {
322 return err;
323 }
324 region_addr = CONFIG_ESP_IMAGE1_SECONDARY_START_ADDRESS;
325 region_size = CONFIG_ESP_APPLICATION_SIZE;
326 err = esp_flash_encrypt_region(region_addr, region_size);
327 if (err != ESP_OK) {
328 return err;
329 }
330#endif
331
Almir Okato14763b12021-11-25 00:45:26 -0300332 ESP_LOGI(TAG, "Flash encryption completed");
333
334 return ESP_OK;
335}
336
Almir Okatodb2024e2023-08-24 15:40:26 -0300337esp_err_t esp_flash_encrypt_enable(void)
338{
339 esp_err_t err = ESP_OK;
340 if (!esp_flash_encryption_enabled()) {
341
342 if (esp_flash_encrypt_is_write_protected(true)) {
343 return ESP_FAIL;
344 }
345
346 size_t flash_crypt_cnt = get_flash_encrypt_cnt_value();
347
348#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
349 // Go straight to max, permanently enabled
350 ESP_LOGI(TAG, "Setting CRYPT_CNT for permanent encryption");
351 size_t new_flash_crypt_cnt = FLASH_ENC_CNT_MAX - flash_crypt_cnt;
352#else
353 /* Set least significant 0-bit in flash_crypt_cnt */
354 size_t new_flash_crypt_cnt = 1;
355#endif
356 ESP_LOGD(TAG, "CRYPT_CNT %d -> %d", flash_crypt_cnt, new_flash_crypt_cnt);
357 err = esp_efuse_write_field_cnt(CRYPT_CNT, new_flash_crypt_cnt);
358
359#if defined(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE) && defined(CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED)
360 // For AES128_DERIVED, FE key is 16 bytes and XTS_KEY_LENGTH_256 is 0.
361 // It is important to protect XTS_KEY_LENGTH_256 from further changing it to 1. Set write protection for this bit.
362 // Burning WR_DIS_CRYPT_CNT, blocks further changing of eFuses: DOWNLOAD_DIS_MANUAL_ENCRYPT, SPI_BOOT_CRYPT_CNT, [XTS_KEY_LENGTH_256], SECURE_BOOT_EN.
363 esp_efuse_write_field_bit(WR_DIS_CRYPT_CNT);
364#endif
365 }
366
367 ESP_LOGI(TAG, "Flash encryption completed");
368
369#ifdef CONFIG_EFUSE_VIRTUAL
370 ESP_LOGW(TAG, "Flash encryption not really completed. Must disable virtual efuses");
371#endif
372
373 return err;
374}
375
Almir Okato14763b12021-11-25 00:45:26 -0300376static esp_err_t encrypt_bootloader(void)
377{
378 esp_err_t err;
379 uint32_t image_length;
380 /* Check for plaintext bootloader (verification will fail if it's already encrypted) */
381 if (esp_image_verify_bootloader(&image_length) == ESP_OK) {
382 ESP_LOGI(TAG, "Encrypting bootloader...");
383
384 err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, CONFIG_ESP_BOOTLOADER_SIZE);
385 if (err != ESP_OK) {
386 ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
387 return err;
388 }
389 ESP_LOGI(TAG, "Bootloader encrypted successfully");
390 } else {
391 ESP_LOGW(TAG, "No valid bootloader was found");
392 return ESP_ERR_NOT_FOUND;
393 }
394
395 return ESP_OK;
396}
397
398static esp_err_t verify_img_header(uint32_t addr, const esp_image_load_header_t *image, bool silent)
399{
400 esp_err_t err = ESP_OK;
401
402 if (image->header_magic != ESP_LOAD_HEADER_MAGIC) {
403 if (!silent) {
404 ESP_LOGE(TAG, "image at 0x%x has invalid magic byte",
405 addr);
406 }
407 err = ESP_ERR_IMAGE_INVALID;
408 }
409
410 return err;
411}
412
413static esp_err_t encrypt_primary_slot(void)
414{
415 esp_err_t err;
416
417 esp_image_load_header_t img_header;
418
419 /* Check if the slot is plaintext or encrypted, 0x20 offset is for skipping
420 * MCUboot header
421 */
Almir Okatoa1d641d2022-02-21 19:31:46 -0300422 err = bootloader_flash_read(CONFIG_ESP_IMAGE0_PRIMARY_START_ADDRESS + 0x20,
Almir Okato14763b12021-11-25 00:45:26 -0300423 &img_header, sizeof(esp_image_load_header_t), true);
424 if (err != ESP_OK) {
425 ESP_LOGE(TAG, "Failed to read slot img header");
426 return err;
427 } else {
Almir Okatoa1d641d2022-02-21 19:31:46 -0300428 err = verify_img_header(CONFIG_ESP_IMAGE0_PRIMARY_START_ADDRESS,
Almir Okato14763b12021-11-25 00:45:26 -0300429 &img_header, true);
430 }
431
432 if (err == ESP_OK) {
433 ESP_LOGI(TAG, "Encrypting primary slot...");
434
Almir Okatoa1d641d2022-02-21 19:31:46 -0300435 err = esp_flash_encrypt_region(CONFIG_ESP_IMAGE0_PRIMARY_START_ADDRESS,
Almir Okato14763b12021-11-25 00:45:26 -0300436 CONFIG_ESP_APPLICATION_SIZE);
437 if (err != ESP_OK) {
438 ESP_LOGE(TAG, "Failed to encrypt slot in place: 0x%x", err);
439 return err;
440 }
441 } else {
442 ESP_LOGW(TAG, "Slot already encrypted or no valid image was found");
443 }
444
445 return ESP_OK;
446}
447
448esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
449{
450 esp_err_t err;
451 uint32_t buf[FLASH_SECTOR_SIZE / sizeof(uint32_t)];
452
453 if (src_addr % FLASH_SECTOR_SIZE != 0) {
454 ESP_LOGE(TAG, "esp_flash_encrypt_region bad src_addr 0x%x", src_addr);
455 return ESP_FAIL;
456 }
457
Almir Okato54ef4842023-03-07 17:56:53 -0300458 wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
Almir Okato14763b12021-11-25 00:45:26 -0300459 for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
460 wdt_hal_write_protect_disable(&rtc_wdt_ctx);
461 wdt_hal_feed(&rtc_wdt_ctx);
462 wdt_hal_write_protect_enable(&rtc_wdt_ctx);
463 uint32_t sec_start = i + src_addr;
464 err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, true);
465 if (err != ESP_OK) {
466 goto flash_failed;
467 }
468 err = bootloader_flash_erase_sector(sec_start / FLASH_SECTOR_SIZE);
469 if (err != ESP_OK) {
470 goto flash_failed;
471 }
472 err = bootloader_flash_write(sec_start, buf, FLASH_SECTOR_SIZE, true);
473 if (err != ESP_OK) {
474 goto flash_failed;
475 }
476 }
477 return ESP_OK;
478
479flash_failed:
480 ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
481 return err;
482}