Created
July 10, 2023 17:18
-
-
Save igrr/ef5a3ad9f5fbf835f06c88b6b36defcc to your computer and use it in GitHub Desktop.
Copy a function into PSRAM on ESP32-S3 and execute it
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD | |
* | |
* SPDX-License-Identifier: Apache-2.0 | |
*/ | |
#include <stdio.h> | |
#include <string.h> | |
#include "esp_err.h" | |
#include "esp_log.h" | |
#include "esp_check.h" | |
#include "esp_heap_caps.h" | |
#include "esp_mmu_map.h" | |
#include "esp_cache.h" | |
static const char *TAG = "example"; | |
int test_func(void) | |
{ | |
return 42; | |
} | |
void app_main(void) | |
{ | |
// 1. Allocate a buffer in PSRAM from heap | |
const size_t heap_buf_size = 0x10000; | |
void *heap_buf = heap_caps_malloc(heap_buf_size, MALLOC_CAP_SPIRAM); | |
// 2. Find the physical address of this buffer | |
esp_paddr_t psram_buf_paddr = 0; | |
mmu_target_t out_target; | |
ESP_ERROR_CHECK(esp_mmu_vaddr_to_paddr(heap_buf, &psram_buf_paddr, &out_target)); | |
// 3. Map the same physical pages to instruction bus | |
const size_t low_paddr = psram_buf_paddr & ~(CONFIG_MMU_PAGE_SIZE - 1); // round down to page boundary | |
const size_t high_paddr = (psram_buf_paddr + heap_buf_size + CONFIG_MMU_PAGE_SIZE - 1) & ~(CONFIG_MMU_PAGE_SIZE - 1); // round up to page boundary | |
const size_t map_size = high_paddr - low_paddr; | |
void *mmap_ptr = NULL; | |
ESP_ERROR_CHECK(esp_mmu_map(0, map_size, MMU_TARGET_PSRAM0, MMU_MEM_CAP_EXEC, 0, &mmap_ptr)); | |
esp_mmu_map_dump_mapped_blocks(stdout); | |
// 4. Adjust the mapped pointer to point to the beginning of the buffer | |
void *exec_buf = mmap_ptr + (psram_buf_paddr - low_paddr); | |
ESP_LOGI(TAG, "heap_buf: %p, paddr:0x%08x...0x%08x, exec_buf: %p", heap_buf, low_paddr, high_paddr, exec_buf); | |
// 5. Write "test_func" code to the buffer via the heap pointer | |
size_t code_size = 32; // just a small function | |
memcpy(heap_buf, &test_func, code_size); | |
// 6. Write back the cache, so that the update data is visible on the instruction bus | |
ESP_ERROR_CHECK(esp_cache_msync(heap_buf, code_size, 0)); | |
// 7. Sanity check: compare the contents of the heap buffer and the mapped buffer | |
if (memcmp(heap_buf, exec_buf, code_size) != 0) { | |
ESP_LOGE(TAG, "Heap buffer and mapped buffer do not match"); | |
return; | |
} | |
// 8. Call the function via the psram pointer | |
int result = ((int (*)(void))exec_buf)(); | |
ESP_LOGI(TAG, "Function call result: %d", result); | |
// 9. Clean up | |
ESP_ERROR_CHECK(esp_mmu_unmap(mmap_ptr)); | |
heap_caps_free(heap_buf); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment