Explorar o código

nvs, spi_flash: handle case when source data is in DROM

Ivan Grokhotkov %!s(int64=9) %!d(string=hai) anos
pai
achega
0b265dc2a7

+ 24 - 1
components/nvs_flash/src/nvs_page.cpp

@@ -114,7 +114,30 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size)
     assert(mFirstUsedEntry != INVALID_ENTRY);
     assert(mFirstUsedEntry != INVALID_ENTRY);
     const uint16_t count = size / ENTRY_SIZE;
     const uint16_t count = size / ENTRY_SIZE;
     
     
-    auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), data, size);
+    const uint8_t* buf = data;
+    
+#ifdef ESP_PLATFORM
+    /* On the ESP32, data can come from DROM, which is not accessible by spi_flash_write
+     * function. To work around this, we copy the data to heap if it came from DROM.
+     * Hopefully this won't happen very often in practice. For data from DRAM, we should
+     * still be able to write it to flash directly.
+     * TODO: figure out how to make this platform-specific check nicer (probably by introducing
+     * a platform-specific flash layer).
+     */
+    if ((uint32_t) data < 0x3ff00000) {
+        buf = (uint8_t*) malloc(size);
+        if (!buf) {
+            return ESP_ERR_NO_MEM;
+        }
+        memcpy((void*)buf, data, size);
+    }
+#endif //ESP_PLATFORM
+    auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), buf, size);
+#ifdef ESP_PLATFORM
+    if (buf != data) {
+        free((void*)buf);
+    }
+#endif //ESP_PLATFORM
     if (rc != ESP_OK) {
     if (rc != ESP_OK) {
         mState = PageState::INVALID;
         mState = PageState::INVALID;
         return rc;
         return rc;

+ 6 - 0
components/spi_flash/flash_ops.c

@@ -135,6 +135,12 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const void *src, size_t si
     if (size % 4 != 0) {
     if (size % 4 != 0) {
         return ESP_ERR_INVALID_SIZE;
         return ESP_ERR_INVALID_SIZE;
     }
     }
+    if ((uint32_t) src < 0x3ff00000) {
+        // if source address is in DROM, we won't be able to read it
+        // from within SPIWrite
+        // TODO: consider buffering source data using heap and writing it anyway?
+        return ESP_ERR_INVALID_ARG;
+    }
     // Out of bound writes are checked in ROM code, but we can give better
     // Out of bound writes are checked in ROM code, but we can give better
     // error code here
     // error code here
     if (dest_addr + size > g_rom_flashchip.chip_size) {
     if (dest_addr + size > g_rom_flashchip.chip_size) {

+ 2 - 0
components/spi_flash/include/esp_spi_flash.h

@@ -76,6 +76,8 @@ esp_err_t spi_flash_erase_range(size_t start_address, size_t size);
  *
  *
  * @note Address in flash, dest, has to be 4-byte aligned.
  * @note Address in flash, dest, has to be 4-byte aligned.
  *       This is a temporary limitation which will be removed.
  *       This is a temporary limitation which will be removed.
+ * @note If source address is in DROM, this function will return
+ *       ESP_ERR_INVALID_ARG.
  *
  *
  * @param  dest  destination address in Flash
  * @param  dest  destination address in Flash
  * @param  src   pointer to the source buffer
  * @param  src   pointer to the source buffer