Skip to content

Instantly share code, notes, and snippets.

@igrr
Created July 10, 2023 17:18
Show Gist options
  • Save igrr/ef5a3ad9f5fbf835f06c88b6b36defcc to your computer and use it in GitHub Desktop.
Save igrr/ef5a3ad9f5fbf835f06c88b6b36defcc to your computer and use it in GitHub Desktop.
Copy a function into PSRAM on ESP32-S3 and execute it
/*
* 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