xtensa/esp32: Tasks use PSRAM as stack can do SPI flash read/write/erase/map/unmap

This commit is contained in:
Dong Heng 2023-02-24 10:36:20 +08:00 committed by Alan Carvalho de Assis
parent d1113110f3
commit 663b4c4f34
3 changed files with 363 additions and 76 deletions

View File

@ -1811,6 +1811,16 @@ config ESP32_SPIFLASH_DEBUG
Enable this option, read and write of SPI Flash
will show input arguments and result.
config ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
bool "Support PSRAM As Task Stack"
default n
depends on ESP32_SPIRAM
select SCHED_LPWORK
---help---
Enable this option, Tasks which use PSRAM as stack
can do SPI Flash read/write/erase/map/unmap.
Otherwise, it may cause exception.
if ESP32_APP_FORMAT_LEGACY
comment "Partition Table Configuration"

View File

@ -103,6 +103,19 @@
#define PRO_IRAM0_FIRST_PAGE ((SOC_IRAM_LOW - SOC_DRAM_HIGH) /\
(SPI_FLASH_MMU_PAGE_SIZE + IROM0_PAGES_START))
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
/* SPI flash work operation code */
enum spiflash_op_code_e
{
SPIFLASH_OP_CODE_WRITE = 0,
SPIFLASH_OP_CODE_READ,
SPIFLASH_OP_CODE_ERASE,
SPIFLASH_OP_CODE_ENCRYPT_READ,
SPIFLASH_OP_CODE_ENCRYPT_WRITE
};
#endif
/****************************************************************************
* Private Types
****************************************************************************/
@ -170,6 +183,27 @@ struct spiflash_cachestate_s
uint32_t val[CONFIG_SMP_NCPUS];
};
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
/* SPI flash work operation arguments */
struct spiflash_work_arg
{
enum spiflash_op_code_e op_code;
struct
{
struct esp32_spiflash_s *priv;
uint32_t addr;
uint8_t *buffer;
uint32_t size;
} op_arg;
volatile int ret;
sem_t sem;
};
#endif
/****************************************************************************
* ROM function prototypes
****************************************************************************/
@ -217,6 +251,19 @@ static int IRAM_ATTR esp32_writedata(struct esp32_spiflash_s *priv,
static int IRAM_ATTR esp32_readdata(struct esp32_spiflash_s *priv,
uint32_t addr,
uint8_t *buffer, uint32_t size);
static int IRAM_ATTR esp32_readdata_encrypted(struct esp32_spiflash_s *priv,
uint32_t addr,
uint8_t *buffer,
uint32_t size);
static int IRAM_ATTR esp32_writedata_encrypted(struct esp32_spiflash_s *priv,
uint32_t addr,
const uint8_t *buffer,
uint32_t size);
static int esp32_writeblk_encrypted(struct esp32_spiflash_s *priv,
uint32_t offset,
const uint8_t *buffer,
uint32_t nbytes);
#if 0
static int esp32_read_highstatus(struct esp32_spiflash_s *priv,
uint32_t *status);
@ -226,6 +273,10 @@ static int esp32_write_status(struct esp32_spiflash_s *priv,
uint32_t status);
#endif
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
static void esp32_spiflash_work(void *p);
#endif
/* MTD driver methods */
static int esp32_erase(struct mtd_dev_s *dev, off_t startblock,
@ -307,6 +358,9 @@ static struct esp32_spiflash_s g_esp32_spiflash1_encrypt =
/* Enxusre exculisve access to the driver */
static mutex_t g_lock = NXMUTEX_INITIALIZER;
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
static struct work_s g_work;
#endif
/****************************************************************************
* Private Functions
@ -460,6 +514,26 @@ static inline void IRAM_ATTR
leave_critical_section(state->flags);
}
/****************************************************************************
* Name: stack_is_psram
*
* Description:
* Check if current task's stack space is in PSRAM
*
* Returned Value:
* true if it is in PSRAM or false if not.
*
****************************************************************************/
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
static inline bool IRAM_ATTR stack_is_psram(void)
{
void *sp = (void *)up_getsp();
return esp32_ptr_extram(sp);
}
#endif
/****************************************************************************
* Name: spiflash_pagecached
*
@ -1094,7 +1168,7 @@ static int IRAM_ATTR esp32_writedata(struct esp32_spiflash_s *priv,
}
/****************************************************************************
* Name: esp32_writedata
* Name: esp32_writedata_encrypted
*
* Description:
* Write plaintext data to SPI Flash at designated address by SPI Flash
@ -1470,6 +1544,219 @@ static int IRAM_ATTR esp32_readdata_encrypted(
return OK;
}
/****************************************************************************
* Name: esp32_writeblk_encrypted
*
* Description:
* Write plaintext block data to SPI Flash at designated address by SPI
* Flash hardware encryption, and written data in SPI Flash is ciphertext.
*
* Input Parameters:
* priv - ESP32 SPI Flash private data
* offset - target address
* buffer - data buffer pointer
* nbytes - data number
*
* Returned Value:
* 0 if success or a negative value if fail.
*
****************************************************************************/
static int esp32_writeblk_encrypted(struct esp32_spiflash_s *priv,
uint32_t offset,
const uint8_t *buffer,
uint32_t nbytes)
{
uint8_t *wbuf;
uint8_t *rbuf;
off_t addr;
ssize_t n;
uint8_t tmp_buf[SPI_FLASH_ENCRYPT_UNIT_SIZE];
size_t wbytes = 0;
int ret = 0;
while (nbytes > 0)
{
if ((offset % SPI_FLASH_ENCRYPT_UNIT_SIZE) != 0)
{
wbuf = tmp_buf;
rbuf = tmp_buf;
addr = offset - SPI_FLASH_ENCRYPT_MIN_SIZE;
n = SPI_FLASH_ENCRYPT_MIN_SIZE;
ret = esp32_readdata_encrypted(priv, addr, rbuf, n);
if (ret < 0)
{
ferr("esp32_readdata_encrypted failed ret=%d\n", ret);
break;
}
memcpy(wbuf + n, buffer, n);
}
else if ((nbytes % SPI_FLASH_ENCRYPT_UNIT_SIZE) != 0)
{
wbuf = tmp_buf;
if ((offset % SPI_FLASH_ENCRYPT_UNIT_SIZE) != 0)
{
rbuf = tmp_buf;
addr = offset - SPI_FLASH_ENCRYPT_MIN_SIZE;
}
else
{
rbuf = tmp_buf + SPI_FLASH_ENCRYPT_MIN_SIZE;
addr = offset;
}
n = SPI_FLASH_ENCRYPT_MIN_SIZE;
ret = esp32_readdata_encrypted(priv, addr, rbuf, n);
if (ret < 0)
{
ferr("esp32_readdata_encrypted failed ret=%d\n", ret);
break;
}
if ((offset % SPI_FLASH_ENCRYPT_UNIT_SIZE) != 0)
{
memcpy(wbuf + n, buffer, n);
}
else
{
memcpy(wbuf, buffer, n);
}
}
else
{
n = SPI_FLASH_ENCRYPT_UNIT_SIZE;
wbuf = (uint8_t *)buffer;
addr = offset;
}
ret = esp32_writedata_encrypted(priv, addr, wbuf,
SPI_FLASH_ENCRYPT_UNIT_SIZE);
if (ret < 0)
{
ferr("esp32_writedata_encrypted failed ret=%d\n", ret);
break;
}
offset += n;
nbytes -= n;
buffer += n;
wbytes += n;
}
return wbytes;
}
/****************************************************************************
* Name: esp32_spiflash_work
*
* Description:
* Do SPI Flash operation, cache result and send semaphore to wake up
* blocked task.
*
* Input Parameters:
* p - SPI Flash work arguments
*
****************************************************************************/
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
static void esp32_spiflash_work(void *p)
{
struct spiflash_work_arg *work_arg = (struct spiflash_work_arg *)p;
if (work_arg->op_code == SPIFLASH_OP_CODE_WRITE)
{
work_arg->ret = esp32_writedata(work_arg->op_arg.priv,
work_arg->op_arg.addr,
work_arg->op_arg.buffer,
work_arg->op_arg.size);
}
else if (work_arg->op_code == SPIFLASH_OP_CODE_READ)
{
esp32_set_read_opt(work_arg->op_arg.priv);
work_arg->ret = esp32_readdata(work_arg->op_arg.priv,
work_arg->op_arg.addr,
work_arg->op_arg.buffer,
work_arg->op_arg.size);
}
else if (work_arg->op_code == SPIFLASH_OP_CODE_ERASE)
{
work_arg->ret = esp32_erasesector(work_arg->op_arg.priv,
work_arg->op_arg.addr,
work_arg->op_arg.size);
}
else if (work_arg->op_code == SPIFLASH_OP_CODE_ENCRYPT_READ)
{
esp32_set_read_opt(work_arg->op_arg.priv);
work_arg->ret = esp32_readdata_encrypted(work_arg->op_arg.priv,
work_arg->op_arg.addr,
work_arg->op_arg.buffer,
work_arg->op_arg.size);
}
else if (work_arg->op_code == SPIFLASH_OP_CODE_ENCRYPT_WRITE)
{
work_arg->ret = esp32_writeblk_encrypted(work_arg->op_arg.priv,
work_arg->op_arg.addr,
work_arg->op_arg.buffer,
work_arg->op_arg.size);
}
else
{
ferr("ERROR: op_code=%d is not supported\n", work_arg->op_code);
}
nxsem_post(&work_arg->sem);
}
/****************************************************************************
* Name: esp32_async_op
*
* Description:
* Send operation code and arguments to workqueue so that workqueue do SPI
* Flash operation actually.
*
* Input Parameters:
* p - SPI Flash work arguments
*
* Returned Value:
* 0 if success or a negative value if fail.
*
****************************************************************************/
static int esp32_async_op(enum spiflash_op_code_e opcode,
struct esp32_spiflash_s *priv,
uint32_t addr,
const uint8_t *buffer,
uint32_t size)
{
int ret;
struct spiflash_work_arg work_arg =
{
.op_code = opcode,
.op_arg =
{
.priv = priv,
.addr = addr,
.buffer = (uint8_t *)buffer,
.size = size,
},
.sem = NXSEM_INITIALIZER(0, 0)
};
ret = work_queue(LPWORK, &g_work, esp32_spiflash_work, &work_arg, 0);
if (ret == 0)
{
nxsem_wait(&work_arg.sem);
ret = work_arg.ret;
}
return ret;
}
#endif
/****************************************************************************
* Name: esp32_erase
*
@ -1509,7 +1796,18 @@ static int esp32_erase(struct mtd_dev_s *dev, off_t startblock,
return ret;
}
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32_async_op(SPIFLASH_OP_CODE_ERASE, priv, addr, NULL, size);
}
else
{
ret = esp32_erasesector(priv, addr, size);
}
#else
ret = esp32_erasesector(priv, addr, size);
#endif
nxmutex_unlock(&g_lock);
if (ret == OK)
@ -1559,8 +1857,21 @@ static ssize_t esp32_read(struct mtd_dev_s *dev, off_t offset,
return ret;
}
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32_async_op(SPIFLASH_OP_CODE_READ, priv,
offset, buffer, nbytes);
}
else
{
esp32_set_read_opt(priv);
ret = esp32_readdata(priv, offset, buffer, nbytes);
}
#else
esp32_set_read_opt(priv);
ret = esp32_readdata(priv, offset, buffer, nbytes);
#endif
nxmutex_unlock(&g_lock);
if (ret == OK)
@ -1658,7 +1969,19 @@ static ssize_t esp32_read_decrypt(struct mtd_dev_s *dev,
return ret;
}
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32_async_op(SPIFLASH_OP_CODE_ENCRYPT_READ, priv,
offset, buffer, nbytes);
}
else
{
ret = esp32_readdata_encrypted(priv, offset, tmpbuff, nbytes);
}
#else
ret = esp32_readdata_encrypted(priv, offset, tmpbuff, nbytes);
#endif
nxmutex_unlock(&g_lock);
if (ret == OK)
@ -1761,7 +2084,19 @@ static ssize_t esp32_write(struct mtd_dev_s *dev, off_t offset,
return ret;
}
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32_async_op(SPIFLASH_OP_CODE_WRITE, priv,
offset, buffer, nbytes);
}
else
{
ret = esp32_writedata(priv, offset, buffer, nbytes);
}
#else
ret = esp32_writedata(priv, offset, buffer, nbytes);
#endif
nxmutex_unlock(&g_lock);
if (ret == OK)
@ -1845,12 +2180,6 @@ static ssize_t esp32_bwrite_encrypt(struct mtd_dev_s *dev,
const uint8_t *buffer)
{
ssize_t ret;
ssize_t n;
off_t addr;
uint8_t *wbuf;
uint8_t *rbuf;
uint8_t tmp_buf[SPI_FLASH_ENCRYPT_UNIT_SIZE];
size_t wbytes = 0;
struct esp32_spiflash_s *priv = MTD2PRIV(dev);
uint32_t offset = MTD_BLK2SIZE(priv, startblock);
uint32_t nbytes = MTD_BLK2SIZE(priv, nblocks);
@ -1872,76 +2201,22 @@ static ssize_t esp32_bwrite_encrypt(struct mtd_dev_s *dev,
return ret;
}
while (nbytes)
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
if (offset % SPI_FLASH_ENCRYPT_UNIT_SIZE)
{
wbuf = tmp_buf;
rbuf = tmp_buf;
addr = offset - SPI_FLASH_ENCRYPT_MIN_SIZE;
n = SPI_FLASH_ENCRYPT_MIN_SIZE;
ret = esp32_readdata_encrypted(priv, addr, rbuf, n);
if (ret < 0)
{
ferr("esp32_readdata_encrypted failed ret=%d\n", ret);
break;
}
memcpy(wbuf + n, buffer, n);
}
else if (nbytes % SPI_FLASH_ENCRYPT_UNIT_SIZE)
{
wbuf = tmp_buf;
if (offset % SPI_FLASH_ENCRYPT_UNIT_SIZE)
{
rbuf = tmp_buf;
addr = offset - SPI_FLASH_ENCRYPT_MIN_SIZE;
}
else
{
rbuf = tmp_buf + SPI_FLASH_ENCRYPT_MIN_SIZE;
addr = offset;
}
n = SPI_FLASH_ENCRYPT_MIN_SIZE;
ret = esp32_readdata_encrypted(priv, addr, rbuf, n);
if (ret < 0)
{
ferr("esp32_readdata_encrypted failed ret=%d\n", ret);
break;
}
if (offset % SPI_FLASH_ENCRYPT_UNIT_SIZE)
{
memcpy(wbuf + n, buffer, n);
}
else
{
memcpy(wbuf, buffer, n);
}
}
else
{
n = SPI_FLASH_ENCRYPT_UNIT_SIZE;
wbuf = (uint8_t *)buffer;
addr = offset;
}
ret = esp32_writedata_encrypted(priv, addr, wbuf,
SPI_FLASH_ENCRYPT_UNIT_SIZE);
if (ret < 0)
{
ferr("esp32_writedata_encrypted failed ret=%d\n", ret);
break;
}
offset += n;
nbytes -= n;
buffer += n;
wbytes += n;
ret = esp32_async_op(SPIFLASH_OP_CODE_ENCRYPT_WRITE, priv,
offset, buffer, nbytes);
}
else
{
ret = esp32_writeblk_encrypted(priv, offset, buffer, nbytes);
}
#else
ret = esp32_writeblk_encrypted(priv, offset, buffer, nbytes);
#endif
if (ret == nbytes)
{
ret = nblocks;
}
nxmutex_unlock(&g_lock);

View File

@ -20,8 +20,10 @@ CONFIG_ARCH_XTENSA=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
CONFIG_DEV_ZERO=y
CONFIG_ESP32_SPIFLASH=y
CONFIG_ESP32_SPIRAM=y
CONFIG_ESP32_SPIRAM_USER_HEAP=y
CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK=y
CONFIG_ESP32_UART0=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y