Merge branch 'fix/jpeg_enc_encrypt' into 'master'

fix(jpeg): Jpeg can encode and decode in encryption situation

Closes IDF-15061

See merge request espressif/esp-idf!50063
This commit is contained in:
C.S.M
2026-07-07 13:36:20 +08:00
18 changed files with 236 additions and 25 deletions
+15
View File
@@ -23,6 +23,7 @@
#include "esp_log.h"
#include "esp_check.h"
#include "hal/jpeg_periph.h"
#include "esp_psram.h"
#if JPEG_USE_RETENTION_LINK
#include "esp_private/sleep_retention.h"
#endif
@@ -257,3 +258,17 @@ esp_err_t jpeg_check_intr_priority(jpeg_codec_handle_t jpeg_codec, int intr_prio
ESP_RETURN_ON_FALSE(!intr_priority_conflict, ESP_ERR_INVALID_STATE, TAG, "intr_priority conflict, already is %d but attempt to %d", jpeg_codec->intr_priority, intr_priority);
return ret;
}
bool jpeg_check_dma2d_buffer(const void *buffer)
{
#if CONFIG_SECURE_FLASH_ENC_ENABLED
// jpeg cannot handle encrypted data.
if (esp_ptr_external_ram(buffer) && !esp_psram_ptr_is_no_enc(buffer)) {
return false;
}
if (esp_ptr_in_drom(buffer)) {
return false;
}
#endif
return true;
}
+18 -7
View File
@@ -17,6 +17,7 @@
#include "hal/cache_ll.h"
#include "hal/cache_hal.h"
#include "hal/jpeg_defs.h"
#include "hal/hal_utils.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
@@ -287,6 +288,10 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_
ESP_RETURN_ON_FALSE(_check_buffer_alignment(decode_outbuf, outbuf_size, outbuf_cache_line_size), ESP_ERR_INVALID_ARG, TAG,
"jpeg decode decode_outbuf or out_buffer size is not aligned, please use jpeg_alloc_decoder_mem to malloc your buffer");
// both the bitstream and output buffer are accessed by the 2D-DMA
ESP_RETURN_ON_FALSE(jpeg_check_dma2d_buffer(bit_stream) && jpeg_check_dma2d_buffer(decode_outbuf), ESP_ERR_INVALID_ARG, TAG,
"jpeg decode buffer is not 16-byte aligned or not in unencrypted PSRAM, please use jpeg_alloc_decoder_mem to malloc your buffer");
esp_err_t ret = ESP_OK;
#if CONFIG_PM_ENABLE
@@ -435,15 +440,21 @@ void *jpeg_alloc_decoder_mem(size_t size, const jpeg_decode_memory_alloc_cfg_t *
FOr input buffer(for decoder is PSRAM write to 2DDMA), no restriction for any align (both cache writeback and requirement from 2DDMA).
*/
size_t cache_align = 0;
size_t buffer_align = 0;
esp_cache_get_alignment(MALLOC_CAP_SPIRAM, &cache_align);
if (mem_cfg->buffer_direction == JPEG_DEC_ALLOC_OUTPUT_BUFFER) {
size = ESP_ALIGN_UP(size, cache_align);
*allocated_size = size;
return heap_caps_aligned_calloc(cache_align, 1, size, MALLOC_CAP_SPIRAM);
} else {
*allocated_size = size;
return heap_caps_calloc(1, size, MALLOC_CAP_SPIRAM);
buffer_align = MAX(cache_align, JPEG_DMA2D_BUFFER_ALIGN);
size = ESP_ALIGN_UP(size, buffer_align);
*allocated_size = size;
// To simplify the logic, we always use the LCM of cache and 2D-DMA alignment to satisfy both requirements
void *buffer = heap_caps_aligned_calloc(buffer_align, 1, size, JPEG_SPIRAM_ALLOC_CAPS);
if (buffer == NULL) {
#if CONFIG_SPIRAM_ENC_EXEMPT
ESP_LOGE(TAG, "no mem for %zu bytes decode buffer in unencrypted PSRAM, please enlarge CONFIG_SPIRAM_ENC_EXEMPT_SIZE", size);
#else
ESP_LOGE(TAG, "no mem for %zu bytes decode buffer", size);
#endif
}
return buffer;
}
/****************************************************************
+16 -7
View File
@@ -19,6 +19,7 @@
#include "hal/jpeg_ll.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "hal/hal_utils.h"
#include "esp_private/dma2d.h"
#include "jpeg_private.h"
#include "driver/jpeg_encode.h"
@@ -175,6 +176,8 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_
ESP_RETURN_ON_FALSE(bit_stream, ESP_ERR_INVALID_ARG, TAG, "jpeg encode output buffer is null");
ESP_RETURN_ON_FALSE(out_size, ESP_ERR_INVALID_ARG, TAG, "jpeg encode picture out_size is null");
ESP_RETURN_ON_FALSE(((uintptr_t)bit_stream % cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA)) == 0, ESP_ERR_INVALID_ARG, TAG, "jpeg encode bit stream is not aligned, please use jpeg_alloc_encoder_mem to malloc your buffer");
// both the input picture and output bitstream are accessed by the 2D-DMA
ESP_RETURN_ON_FALSE(jpeg_check_dma2d_buffer(encode_inbuf) && jpeg_check_dma2d_buffer(bit_stream), ESP_ERR_INVALID_ARG, TAG, "jpeg encode buffer is not 16-byte aligned or not in unencrypted PSRAM, please use jpeg_alloc_encoder_mem to malloc your buffer");
esp_err_t ret = ESP_OK;
@@ -401,15 +404,21 @@ void *jpeg_alloc_encoder_mem(size_t size, const jpeg_encode_memory_alloc_cfg_t *
For input buffer(for decoder is PSRAM write to 2DDMA), no restriction for any align (both cache writeback and requirement from 2DDMA).
*/
size_t cache_align = 0;
size_t buffer_align = 0;
esp_cache_get_alignment(MALLOC_CAP_SPIRAM, &cache_align);
if (mem_cfg->buffer_direction == JPEG_ENC_ALLOC_OUTPUT_BUFFER) {
size = ESP_ALIGN_UP(size, cache_align);
*allocated_size = size;
return heap_caps_aligned_calloc(cache_align, 1, size, MALLOC_CAP_SPIRAM);
} else {
*allocated_size = size;
return heap_caps_calloc(1, size, MALLOC_CAP_SPIRAM);
buffer_align = MAX(cache_align, JPEG_DMA2D_BUFFER_ALIGN);
size = ESP_ALIGN_UP(size, buffer_align);
*allocated_size = size;
// To simplify the logic, we always use the LCM of cache and 2D-DMA alignment to satisfy both requirements
void *buffer = heap_caps_aligned_calloc(buffer_align, 1, size, JPEG_SPIRAM_ALLOC_CAPS);
if (buffer == NULL) {
#if CONFIG_SPIRAM_ENC_EXEMPT
ESP_LOGE(TAG, "no mem for %zu bytes encode buffer in unencrypted PSRAM, please enlarge CONFIG_SPIRAM_ENC_EXEMPT_SIZE", size);
#else
ESP_LOGE(TAG, "no mem for %zu bytes encode buffer", size);
#endif
}
return buffer;
}
/****************************************************************
+24
View File
@@ -31,6 +31,18 @@ extern "C" {
// JPEG encoder and decoder shares same interrupt ID.
#define JPEG_INTR_ALLOC_FLAG (ESP_INTR_FLAG_SHARED)
// Buffers fed to the 2D-DMA must be at least 16-byte aligned.
#define JPEG_DMA2D_BUFFER_ALIGN 16
// The JPEG codec cannot work with encrypted buffer, because it deals with macro block. When an
// unencrypted PSRAM region is reserved (CONFIG_SPIRAM_ENC_EXEMPT), codec buffers
// must come from it; otherwise use normal PSRAM.
#if CONFIG_SPIRAM_ENC_EXEMPT
#define JPEG_SPIRAM_ALLOC_CAPS (MALLOC_CAP_SPIRAM_NO_ENC)
#else
#define JPEG_SPIRAM_ALLOC_CAPS (MALLOC_CAP_SPIRAM)
#endif
// Use retention link only when the target supports sleep retention and PM is enabled
#define JPEG_USE_RETENTION_LINK (CONFIG_PM_ENABLE && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
@@ -250,6 +262,18 @@ esp_err_t jpeg_isr_deregister(jpeg_codec_handle_t jpeg_codec, jpeg_isr_handler_t
*/
esp_err_t jpeg_check_intr_priority(jpeg_codec_handle_t jpeg_codec, int intr_priority);
/**
* @brief Validate a user buffer that will be accessed by the 2D-DMA
*
* The buffer must be 16-byte aligned. When CONFIG_SPIRAM_ENC_EXEMPT is enabled,
* a PSRAM buffer must reside in the unencrypted carve-out, since the 2D-DMA
* cannot access encrypted PSRAM. Internal RAM buffers are always accepted.
*
* @param buffer Buffer pointer provided by the user
* @return true if the buffer can be used by the 2D-DMA, false otherwise
*/
bool jpeg_check_dma2d_buffer(const void *buffer);
/**
* @brief Create sleep retention link
*
@@ -19,6 +19,7 @@
#include "freertos/FreeRTOS.h"
#include "esp_heap_caps_init.h"
#include "esp_psram.h"
#include "esp_macros.h"
#include "esp_mmu_map.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
@@ -288,7 +289,7 @@ static void s_psram_mapping(uint32_t psram_available_size, uint32_t start_page)
{
esp_err_t ret = ESP_FAIL;
#if CONFIG_SPIRAM_ENC_EXEMPT
size_t enc_exempt_size = ALIGN_UP_BY((size_t)CONFIG_SPIRAM_ENC_EXEMPT_SIZE * 1024, MMU_PAGE_SIZE);
size_t enc_exempt_size = ESP_ALIGN_UP((size_t)CONFIG_SPIRAM_ENC_EXEMPT_SIZE * 1024, MMU_PAGE_SIZE);
if (enc_exempt_size >= psram_available_size) {
ESP_EARLY_LOGE(TAG, "SPIRAM_ENC_EXEMPT_SIZE (%dKB) >= available PSRAM (%dKB); disabling carve-out",
(int)(enc_exempt_size / 1024), (int)(psram_available_size / 1024));
@@ -587,6 +587,24 @@ static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t e
return mmu_ll_laddr_to_vaddr(laddr, type, (mmu_id == MMU_LL_FLASH_MMU_ID) ? MMU_TARGET_FLASH0 : MMU_TARGET_PSRAM0);
}
/**
* Write a PSRAM MMU entry without the SENSITIVE bit, used only for the
* carved-out unencrypted region (see CONFIG_SPIRAM_ENC_EXEMPT).
*
* No anti-FI check: the SENSITIVE bit is intentionally clear, and an FI flip
* that sets it would force decryption of plaintext data (garbage, fails safe).
*/
__attribute__((always_inline)) static inline void mmu_ll_write_entry_no_enc(uint32_t mmu_id, uint32_t entry_id, uint32_t mmu_val)
{
HAL_ASSERT(mmu_id == MMU_LL_PSRAM_MMU_ID);
mmu_val |= SOC_MMU_PSRAM_VALID;
mmu_val |= SOC_MMU_ACCESS_PSRAM;
REG_WRITE(SPI_MEM_S_MMU_ITEM_INDEX_REG, entry_id);
REG_WRITE(SPI_MEM_S_MMU_ITEM_CONTENT_REG, mmu_val);
}
#ifdef __cplusplus
}
#endif
@@ -1255,6 +1255,10 @@ config SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX
int
default 64
config SOC_PSRAM_ENCRYPTION_PAGE_CONFIGURABLE
bool
default y
config SOC_RECOVERY_BOOTLOADER_SUPPORTED
bool
default y
@@ -467,6 +467,9 @@
#define SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND 1
#define SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX (64)
/*-------------------------- PSRAM Encryption CAPS----------------------------*/
#define SOC_PSRAM_ENCRYPTION_PAGE_CONFIGURABLE 1 /* PSRAM encryption can be configured on a MMU page basis */
/*------------------------Bootloader CAPS---------------------------------*/
/* Support Recovery Bootloader */
#define SOC_RECOVERY_BOOTLOADER_SUPPORTED (1)