esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) { CHECK_WRITE_ADDRESS(start_addr, size); if (start_addr % SPI_FLASH_SEC_SIZE != 0) { return ESP_ERR_INVALID_ARG; } if (size % SPI_FLASH_SEC_SIZE != 0) { return ESP_ERR_INVALID_SIZE; } if (size + start_addr > spi_flash_get_chip_size()) { return ESP_ERR_INVALID_SIZE; } size_t start = start_addr / SPI_FLASH_SEC_SIZE; size_t end = start + size / SPI_FLASH_SEC_SIZE; const size_t sectors_per_block = BLOCK_ERASE_SIZE / SPI_FLASH_SEC_SIZE; COUNTER_START(); esp_rom_spiflash_result_t rc; rc = spi_flash_unlock(); if (rc == ESP_ROM_SPIFLASH_RESULT_OK) { for (size_t sector = start; sector != end && rc == ESP_ROM_SPIFLASH_RESULT_OK; ) { spi_flash_guard_start(); if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) { rc = esp_rom_spiflash_erase_block(sector / sectors_per_block); sector += sectors_per_block; COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE); } else { rc = esp_rom_spiflash_erase_sector(sector); ++sector; COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE); } spi_flash_guard_end(); } } COUNTER_STOP(erase); return spi_flash_translate_rc(rc); }
void save_flash(int flash_address, char buffer[MAX_DEVICES][MAX_LENGTH], u8 max_lines, u8 spi_wp_toggle) { int i = 0; int k = 0; int j, ret; char cbfs_formatted_list[MAX_DEVICES * MAX_LENGTH]; u32 nvram_pos; // compact the table into the expected packed list for (j = 0; j < max_lines; j++) { for (k = 0; k < MAX_LENGTH; k++) { cbfs_formatted_list[i++] = buffer[j][k]; if (buffer[j][k] == NEWLINE ) break; } } cbfs_formatted_list[i++] = NUL; // try to unlock the flash if it is locked if (spi_flash_is_locked(flash_device)) { spi_flash_unlock(flash_device); if (spi_flash_is_locked(flash_device)) { printf("Flash is write protected. Exiting...\n"); return; } } printf("Erasing Flash size 0x%x @ 0x%x\n", FLASH_SIZE_CHUNK, flash_address); ret = spi_flash_erase(flash_device, flash_address, FLASH_SIZE_CHUNK); if (ret) { printf("Erase failed, ret: %d\n", ret); return; } printf("Writing %d bytes @ 0x%x\n", i, flash_address); // write first 512 bytes for (nvram_pos = 0; nvram_pos < (i & 0xFFFC); nvram_pos += 4) { ret = spi_flash_write(flash_device, nvram_pos + flash_address, sizeof(u32), (u32 *)(cbfs_formatted_list + nvram_pos)); if (ret) { printf("Write failed, ret: %d\n", ret); return; } } // write remaining filler characters in one run ret = spi_flash_write(flash_device, nvram_pos + flash_address, sizeof(i % 4), (u32 *)(cbfs_formatted_list + nvram_pos)); if (ret) { printf("Write failed, ret: %d\n", ret); return; } if (spi_wp_toggle) { printf("Enabling flash write protect...\n"); spi_flash_lock(flash_device); } spi_wp_toggle = spi_flash_is_locked(flash_device); printf("Done\n"); }
inline int unlock_flash(void) { return spi_flash_unlock(flash_device); }
esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size) { CHECK_WRITE_ADDRESS(dest_addr, size); const uint8_t *ssrc = (const uint8_t *)src; if ((dest_addr % 16) != 0) { return ESP_ERR_INVALID_ARG; } if ((size % 16) != 0) { return ESP_ERR_INVALID_SIZE; } COUNTER_START(); esp_rom_spiflash_result_t rc; rc = spi_flash_unlock(); if (rc == ESP_ROM_SPIFLASH_RESULT_OK) { /* esp_rom_spiflash_write_encrypted encrypts data in RAM as it writes, so copy to a temporary buffer - 32 bytes at a time. Each call to esp_rom_spiflash_write_encrypted takes a 32 byte "row" of data to encrypt, and each row is two 16 byte AES blocks that share a key (as derived from flash address). */ uint8_t encrypt_buf[32] __attribute__((aligned(4))); uint32_t row_size; for (size_t i = 0; i < size; i += row_size) { uint32_t row_addr = dest_addr + i; if (i == 0 && (row_addr % 32) != 0) { /* writing to second block of a 32 byte row */ row_size = 16; row_addr -= 16; /* copy to second block in buffer */ memcpy(encrypt_buf + 16, ssrc + i, 16); /* decrypt the first block from flash, will reencrypt to same bytes */ spi_flash_read_encrypted(row_addr, encrypt_buf, 16); } else if (size - i == 16) { /* 16 bytes left, is first block of a 32 byte row */ row_size = 16; /* copy to first block in buffer */ memcpy(encrypt_buf, ssrc + i, 16); /* decrypt the second block from flash, will reencrypt to same bytes */ spi_flash_read_encrypted(row_addr + 16, encrypt_buf + 16, 16); } else { /* Writing a full 32 byte row (2 blocks) */ row_size = 32; memcpy(encrypt_buf, ssrc + i, 32); } spi_flash_guard_start(); rc = esp_rom_spiflash_write_encrypted(row_addr, (uint32_t *)encrypt_buf, 32); spi_flash_guard_end(); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { break; } } bzero(encrypt_buf, sizeof(encrypt_buf)); } COUNTER_ADD_BYTES(write, size); COUNTER_STOP(write); spi_flash_guard_op_lock(); spi_flash_mark_modified_region(dest_addr, size); spi_flash_guard_op_unlock(); return spi_flash_translate_rc(rc); }
esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) { CHECK_WRITE_ADDRESS(dst, size); // Out of bound writes are checked in ROM code, but we can give better // error code here if (dst + size > g_rom_flashchip.chip_size) { return ESP_ERR_INVALID_SIZE; } if (size == 0) { return ESP_OK; } esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK; COUNTER_START(); const uint8_t *srcc = (const uint8_t *) srcv; /* * Large operations are split into (up to) 3 parts: * - Left padding: 4 bytes up to the first 4-byte aligned destination offset. * - Middle part * - Right padding: 4 bytes from the last 4-byte aligned offset covered. */ size_t left_off = dst & ~3U; size_t left_size = MIN(((dst + 3) & ~3U) - dst, size); size_t mid_off = left_size; size_t mid_size = (size - left_size) & ~3U; size_t right_off = left_size + mid_size; size_t right_size = size - mid_size - left_size; rc = spi_flash_unlock(); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } if (left_size > 0) { uint32_t t = 0xffffffff; memcpy(((uint8_t *) &t) + (dst - left_off), srcc, left_size); spi_flash_guard_start(); rc = spi_flash_write_inner(left_off, &t, 4); spi_flash_guard_end(); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } COUNTER_ADD_BYTES(write, 4); } if (mid_size > 0) { /* If src buffer is 4-byte aligned as well and is not in a region that requires cache access to be enabled, we * can write directly without buffering in RAM. */ #ifdef ESP_PLATFORM bool direct_write = esp_ptr_internal(srcc) && esp_ptr_byte_accessible(srcc) && ((uintptr_t) srcc + mid_off) % 4 == 0; #else bool direct_write = true; #endif while(mid_size > 0 && rc == ESP_ROM_SPIFLASH_RESULT_OK) { uint32_t write_buf[8]; uint32_t write_size = MIN(mid_size, MAX_WRITE_CHUNK); const uint8_t *write_src = srcc + mid_off; if (!direct_write) { write_size = MIN(write_size, sizeof(write_buf)); memcpy(write_buf, write_src, write_size); write_src = (const uint8_t *)write_buf; } spi_flash_guard_start(); rc = spi_flash_write_inner(dst + mid_off, (const uint32_t *) write_src, write_size); spi_flash_guard_end(); COUNTER_ADD_BYTES(write, write_size); mid_size -= write_size; mid_off += write_size; } if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } } if (right_size > 0) { uint32_t t = 0xffffffff; memcpy(&t, srcc + right_off, right_size); spi_flash_guard_start(); rc = spi_flash_write_inner(dst + right_off, &t, 4); spi_flash_guard_end(); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { goto out; } COUNTER_ADD_BYTES(write, 4); } out: COUNTER_STOP(write); spi_flash_guard_op_lock(); spi_flash_mark_modified_region(dst, size); spi_flash_guard_op_unlock(); return spi_flash_translate_rc(rc); }