| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include <stddef.h>
- #include <bootloader_flash_priv.h>
- #include <esp_log.h>
- #include <esp_flash_encrypt.h>
- #include "sdkconfig.h"
- #include "soc/soc_caps.h"
- #if CONFIG_IDF_TARGET_ESP32
- # include "soc/spi_struct.h"
- # include "soc/spi_reg.h"
- /* SPI flash controller */
- # define SPIFLASH SPI1
- #else
- # include "soc/spi_mem_struct.h"
- # include "soc/spi_mem_reg.h"
- /* SPI flash controller */
- # define SPIFLASH SPIMEM1
- #endif
- #if CONFIG_IDF_TARGET_ESP32S2
- #include "esp32s2/rom/spi_flash.h"
- #elif CONFIG_IDF_TARGET_ESP32S3
- #include "esp32s3/rom/spi_flash.h"
- #elif CONFIG_IDF_TARGET_ESP32C3
- #include "esp32c3/rom/spi_flash.h"
- #endif
- #ifndef BOOTLOADER_BUILD
- /* Normal app version maps to esp_spi_flash.h operations...
- */
- static const char *TAG = "bootloader_mmap";
- static spi_flash_mmap_handle_t map;
- uint32_t bootloader_mmap_get_free_pages(void)
- {
- return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
- }
- const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
- {
- if (map) {
- ESP_LOGE(TAG, "tried to bootloader_mmap twice");
- return NULL; /* existing mapping in use... */
- }
- const void *result = NULL;
- uint32_t src_page = src_addr & ~(SPI_FLASH_MMU_PAGE_SIZE - 1);
- size += (src_addr - src_page);
- esp_err_t err = spi_flash_mmap(src_page, size, SPI_FLASH_MMAP_DATA, &result, &map);
- if (err != ESP_OK) {
- ESP_LOGE(TAG, "spi_flash_mmap failed: 0x%x", err);
- return NULL;
- }
- return (void *)((intptr_t)result + (src_addr - src_page));
- }
- void bootloader_munmap(const void *mapping)
- {
- if (mapping && map) {
- spi_flash_munmap(map);
- }
- map = 0;
- }
- esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size, bool allow_decrypt)
- {
- if (allow_decrypt && esp_flash_encryption_enabled()) {
- return spi_flash_read_encrypted(src, dest, size);
- } else {
- return spi_flash_read(src, dest, size);
- }
- }
- esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
- {
- if (write_encrypted) {
- #if CONFIG_IDF_TARGET_ESP32
- return spi_flash_write_encrypted(dest_addr, src, size);
- #else
- return esp_rom_spiflash_write_encrypted(dest_addr, src, size);
- #endif
- } else {
- return spi_flash_write(dest_addr, src, size);
- }
- }
- esp_err_t bootloader_flash_erase_sector(size_t sector)
- {
- return spi_flash_erase_sector(sector);
- }
- esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
- {
- return spi_flash_erase_range(start_addr, size);
- }
- #else
- /* Bootloader version, uses ROM functions only */
- #if CONFIG_IDF_TARGET_ESP32
- #include "esp32/rom/spi_flash.h"
- #include "esp32/rom/cache.h"
- #elif CONFIG_IDF_TARGET_ESP32S2
- #include "esp32s2/rom/spi_flash.h"
- #include "esp32s2/rom/cache.h"
- #include "soc/cache_memory.h"
- #elif CONFIG_IDF_TARGET_ESP32S3
- #include "esp32s3/rom/spi_flash.h"
- #include "esp32s3/rom/cache.h"
- #include "soc/cache_memory.h"
- #elif CONFIG_IDF_TARGET_ESP32C3
- #include "esp32c3/rom/spi_flash.h"
- #include "esp32c3/rom/cache.h"
- #include "soc/cache_memory.h"
- #endif
- static const char *TAG = "bootloader_flash";
- #if CONFIG_IDF_TARGET_ESP32
- /* Use first 50 blocks in MMU for bootloader_mmap,
- 50th block for bootloader_flash_read
- */
- #define MMU_BLOCK0_VADDR SOC_DROM_LOW
- #define MMU_SIZE (0x320000)
- #define MMU_BLOCK50_VADDR (MMU_BLOCK0_VADDR + MMU_SIZE)
- #define FLASH_READ_VADDR MMU_BLOCK50_VADDR
- #else // !CONFIG_IDF_TARGET_ESP32
- /* Use first 63 blocks in MMU for bootloader_mmap,
- 63th block for bootloader_flash_read
- */
- #define MMU_BLOCK0_VADDR SOC_DROM_LOW
- #define MMU_SIZE (0x3f0000)
- #define MMU_BLOCK63_VADDR (MMU_BLOCK0_VADDR + MMU_SIZE)
- #define FLASH_READ_VADDR MMU_BLOCK63_VADDR
- #endif
- #define MMU_FREE_PAGES (MMU_SIZE / FLASH_BLOCK_SIZE)
- static bool mapped;
- // Current bootloader mapping (ab)used for bootloader_read()
- static uint32_t current_read_mapping = UINT32_MAX;
- uint32_t bootloader_mmap_get_free_pages(void)
- {
- /**
- * Allow mapping up to 50 of the 51 available MMU blocks (last one used for reads)
- * Since, bootloader_mmap function below assumes it to be 0x320000 (50 pages), we can safely do this.
- */
- return MMU_FREE_PAGES;
- }
- const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
- {
- if (mapped) {
- ESP_LOGE(TAG, "tried to bootloader_mmap twice");
- return NULL; /* can't map twice */
- }
- if (size > MMU_SIZE) {
- ESP_LOGE(TAG, "bootloader_mmap excess size %x", size);
- return NULL;
- }
- uint32_t src_addr_aligned = src_addr & MMU_FLASH_MASK;
- uint32_t count = bootloader_cache_pages_to_map(size, src_addr);
- #if CONFIG_IDF_TARGET_ESP32
- Cache_Read_Disable(0);
- Cache_Flush(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- uint32_t autoload = Cache_Suspend_ICache();
- Cache_Invalidate_ICache_All();
- #elif CONFIG_IDF_TARGET_ESP32S3
- uint32_t autoload = Cache_Suspend_DCache();
- Cache_Invalidate_DCache_All();
- #elif CONFIG_IDF_TARGET_ESP32C3
- uint32_t autoload = Cache_Suspend_ICache();
- Cache_Invalidate_ICache_All();
- #endif
- ESP_LOGD(TAG, "mmu set paddr=%08x count=%d size=%x src_addr=%x src_addr_aligned=%x",
- src_addr & MMU_FLASH_MASK, count, size, src_addr, src_addr_aligned );
- #if CONFIG_IDF_TARGET_ESP32
- int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count);
- #elif CONFIG_IDF_TARGET_ESP32S2
- int e = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count, 0);
- #else // S3, C3
- int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK0_VADDR, src_addr_aligned, 64, count, 0);
- #endif
- if (e != 0) {
- ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d\n", e);
- #if CONFIG_IDF_TARGET_ESP32
- Cache_Read_Enable(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- Cache_Resume_ICache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32S3
- Cache_Resume_DCache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32C3
- Cache_Resume_ICache(autoload);
- #endif
- return NULL;
- }
- #if CONFIG_IDF_TARGET_ESP32
- Cache_Read_Enable(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- Cache_Resume_ICache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32S3
- Cache_Resume_DCache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32C3
- Cache_Resume_ICache(autoload);
- #endif
- mapped = true;
- return (void *)(MMU_BLOCK0_VADDR + (src_addr - src_addr_aligned));
- }
- void bootloader_munmap(const void *mapping)
- {
- if (mapped) {
- #if CONFIG_IDF_TARGET_ESP32
- /* Full MMU reset */
- Cache_Read_Disable(0);
- Cache_Flush(0);
- mmu_init(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- //TODO, save the autoload value.
- Cache_Suspend_ICache();
- Cache_Invalidate_ICache_All();
- Cache_MMU_Init();
- #elif CONFIG_IDF_TARGET_ESP32S3
- Cache_Suspend_DCache();
- Cache_Invalidate_DCache_All();
- Cache_MMU_Init();
- #elif CONFIG_IDF_TARGET_ESP32C3
- //TODO, save the autoload value.
- Cache_Suspend_ICache();
- Cache_Invalidate_ICache_All();
- Cache_MMU_Init();
- #endif
- mapped = false;
- current_read_mapping = UINT32_MAX;
- }
- }
- static esp_err_t spi_to_esp_err(esp_rom_spiflash_result_t r)
- {
- switch (r) {
- case ESP_ROM_SPIFLASH_RESULT_OK:
- return ESP_OK;
- case ESP_ROM_SPIFLASH_RESULT_ERR:
- return ESP_ERR_FLASH_OP_FAIL;
- case ESP_ROM_SPIFLASH_RESULT_TIMEOUT:
- return ESP_ERR_FLASH_OP_TIMEOUT;
- default:
- return ESP_FAIL;
- }
- }
- static esp_err_t bootloader_flash_read_no_decrypt(size_t src_addr, void *dest, size_t size)
- {
- #if CONFIG_IDF_TARGET_ESP32
- Cache_Read_Disable(0);
- Cache_Flush(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- uint32_t autoload = Cache_Suspend_ICache();
- #elif CONFIG_IDF_TARGET_ESP32S3
- uint32_t autoload = Cache_Suspend_DCache();
- #elif CONFIG_IDF_TARGET_ESP32C3
- uint32_t autoload = Cache_Suspend_ICache();
- #endif
- esp_rom_spiflash_result_t r = esp_rom_spiflash_read(src_addr, dest, size);
- #if CONFIG_IDF_TARGET_ESP32
- Cache_Read_Enable(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- Cache_Resume_ICache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32S3
- Cache_Resume_DCache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32C3
- Cache_Resume_ICache(autoload);
- #endif
- return spi_to_esp_err(r);
- }
- static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest, size_t size)
- {
- uint32_t *dest_words = (uint32_t *)dest;
- for (size_t word = 0; word < size / 4; word++) {
- uint32_t word_src = src_addr + word * 4; /* Read this offset from flash */
- uint32_t map_at = word_src & MMU_FLASH_MASK; /* Map this 64KB block from flash */
- uint32_t *map_ptr;
- if (map_at != current_read_mapping) {
- /* Move the 64KB mmu mapping window to fit map_at */
- #if CONFIG_IDF_TARGET_ESP32
- Cache_Read_Disable(0);
- Cache_Flush(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- uint32_t autoload = Cache_Suspend_ICache();
- Cache_Invalidate_ICache_All();
- #elif CONFIG_IDF_TARGET_ESP32S3
- uint32_t autoload = Cache_Suspend_DCache();
- Cache_Invalidate_DCache_All();
- #elif CONFIG_IDF_TARGET_ESP32C3
- uint32_t autoload = Cache_Suspend_ICache();
- Cache_Invalidate_ICache_All();
- #endif
- ESP_LOGD(TAG, "mmu set block paddr=0x%08x (was 0x%08x)", map_at, current_read_mapping);
- #if CONFIG_IDF_TARGET_ESP32
- int e = cache_flash_mmu_set(0, 0, FLASH_READ_VADDR, map_at, 64, 1);
- #elif CONFIG_IDF_TARGET_ESP32S2
- int e = Cache_Ibus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
- #elif CONFIG_IDF_TARGET_ESP32S3
- int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
- #elif CONFIG_IDF_TARGET_ESP32C3
- int e = Cache_Dbus_MMU_Set(MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0);
- #endif
- if (e != 0) {
- ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d\n", e);
- #if CONFIG_IDF_TARGET_ESP32
- Cache_Read_Enable(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- Cache_Resume_ICache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32S3
- Cache_Resume_DCache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32C3
- Cache_Resume_ICache(autoload);
- #endif
- return ESP_FAIL;
- }
- current_read_mapping = map_at;
- #if CONFIG_IDF_TARGET_ESP32
- Cache_Read_Enable(0);
- #elif CONFIG_IDF_TARGET_ESP32S2
- Cache_Resume_ICache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32S3
- Cache_Resume_DCache(autoload);
- #elif CONFIG_IDF_TARGET_ESP32C3
- Cache_Resume_ICache(autoload);
- #endif
- }
- map_ptr = (uint32_t *)(FLASH_READ_VADDR + (word_src - map_at));
- dest_words[word] = *map_ptr;
- }
- return ESP_OK;
- }
- esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt)
- {
- if (src_addr & 3) {
- ESP_LOGE(TAG, "bootloader_flash_read src_addr 0x%x not 4-byte aligned", src_addr);
- return ESP_FAIL;
- }
- if (size & 3) {
- ESP_LOGE(TAG, "bootloader_flash_read size 0x%x not 4-byte aligned", size);
- return ESP_FAIL;
- }
- if ((intptr_t)dest & 3) {
- ESP_LOGE(TAG, "bootloader_flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest);
- return ESP_FAIL;
- }
- if (allow_decrypt) {
- return bootloader_flash_read_allow_decrypt(src_addr, dest, size);
- } else {
- return bootloader_flash_read_no_decrypt(src_addr, dest, size);
- }
- }
- esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
- {
- esp_err_t err;
- size_t alignment = write_encrypted ? 32 : 4;
- if ((dest_addr % alignment) != 0) {
- ESP_LOGE(TAG, "bootloader_flash_write dest_addr 0x%x not %d-byte aligned", dest_addr, alignment);
- return ESP_FAIL;
- }
- if ((size % alignment) != 0) {
- ESP_LOGE(TAG, "bootloader_flash_write size 0x%x not %d-byte aligned", size, alignment);
- return ESP_FAIL;
- }
- if (((intptr_t)src % 4) != 0) {
- ESP_LOGE(TAG, "bootloader_flash_write src 0x%x not 4 byte aligned", (intptr_t)src);
- return ESP_FAIL;
- }
- err = spi_to_esp_err(esp_rom_spiflash_unlock());
- if (err != ESP_OK) {
- return err;
- }
- if (write_encrypted) {
- return spi_to_esp_err(esp_rom_spiflash_write_encrypted(dest_addr, src, size));
- } else {
- return spi_to_esp_err(esp_rom_spiflash_write(dest_addr, src, size));
- }
- }
- esp_err_t bootloader_flash_erase_sector(size_t sector)
- {
- return spi_to_esp_err(esp_rom_spiflash_erase_sector(sector));
- }
- esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
- {
- if (start_addr % FLASH_SECTOR_SIZE != 0) {
- return ESP_ERR_INVALID_ARG;
- }
- if (size % FLASH_SECTOR_SIZE != 0) {
- return ESP_ERR_INVALID_SIZE;
- }
- size_t start = start_addr / FLASH_SECTOR_SIZE;
- size_t end = start + size / FLASH_SECTOR_SIZE;
- const size_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE;
- esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK;
- for (size_t sector = start; sector != end && rc == ESP_ROM_SPIFLASH_RESULT_OK; ) {
- 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;
- } else {
- rc = esp_rom_spiflash_erase_sector(sector);
- ++sector;
- }
- }
- return spi_to_esp_err(rc);
- }
- #endif
- #ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here
- extern uint8_t g_rom_spiflash_dummy_len_plus[];
- #endif
- uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
- {
- uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
- #if CONFIG_IDF_TARGET_ESP32
- SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
- #else
- SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
- #endif
- SPIFLASH.user.usr_dummy = 0;
- SPIFLASH.user.usr_addr = 0;
- SPIFLASH.user.usr_command = 1;
- SPIFLASH.user2.usr_command_bitlen = 7;
- SPIFLASH.user2.usr_command_value = command;
- SPIFLASH.user.usr_miso = miso_len > 0;
- #if CONFIG_IDF_TARGET_ESP32
- SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
- #else
- SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
- #endif
- SPIFLASH.user.usr_mosi = mosi_len > 0;
- #if CONFIG_IDF_TARGET_ESP32
- SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
- #else
- SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0;
- #endif
- SPIFLASH.data_buf[0] = mosi_data;
- if (g_rom_spiflash_dummy_len_plus[1]) {
- /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */
- if (miso_len > 0) {
- SPIFLASH.user.usr_dummy = 1;
- SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1;
- } else {
- SPIFLASH.user.usr_dummy = 0;
- SPIFLASH.user1.usr_dummy_cyclelen = 0;
- }
- }
- SPIFLASH.cmd.usr = 1;
- while (SPIFLASH.cmd.usr != 0) {
- }
- SPIFLASH.ctrl.val = old_ctrl_reg;
- return SPIFLASH.data_buf[0];
- }
- void bootloader_enable_wp(void)
- {
- bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
- }
- #if SOC_CACHE_SUPPORT_WRAP
- esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
- {
- uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val;
- uint32_t reg_bkp_usr = SPIFLASH.user.val;
- SPIFLASH.user.fwrite_dio = 0;
- SPIFLASH.user.fwrite_dual = 0;
- SPIFLASH.user.fwrite_qio = 1;
- SPIFLASH.user.fwrite_quad = 0;
- SPIFLASH.ctrl.fcmd_dual = 0;
- SPIFLASH.ctrl.fcmd_quad = 0;
- SPIFLASH.user.usr_dummy = 0;
- SPIFLASH.user.usr_addr = 1;
- SPIFLASH.user.usr_command = 1;
- SPIFLASH.user2.usr_command_bitlen = 7;
- SPIFLASH.user2.usr_command_value = CMD_WRAP;
- SPIFLASH.user1.usr_addr_bitlen = 23;
- SPIFLASH.addr = 0;
- SPIFLASH.user.usr_miso = 0;
- SPIFLASH.user.usr_mosi = 1;
- SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7;
- SPIFLASH.data_buf[0] = (uint32_t) mode << 4;;
- SPIFLASH.cmd.usr = 1;
- while(SPIFLASH.cmd.usr != 0)
- { }
- SPIFLASH.ctrl.val = reg_bkp_ctrl;
- SPIFLASH.user.val = reg_bkp_usr;
- return ESP_OK;
- }
- #endif //SOC_CACHE_SUPPORT_WRAP
|