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 Enable this option, read and write of SPI Flash
will show input arguments and result. 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 if ESP32_APP_FORMAT_LEGACY
comment "Partition Table Configuration" comment "Partition Table Configuration"

View File

@ -103,6 +103,19 @@
#define PRO_IRAM0_FIRST_PAGE ((SOC_IRAM_LOW - SOC_DRAM_HIGH) /\ #define PRO_IRAM0_FIRST_PAGE ((SOC_IRAM_LOW - SOC_DRAM_HIGH) /\
(SPI_FLASH_MMU_PAGE_SIZE + IROM0_PAGES_START)) (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 * Private Types
****************************************************************************/ ****************************************************************************/
@ -170,6 +183,27 @@ struct spiflash_cachestate_s
uint32_t val[CONFIG_SMP_NCPUS]; 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 * 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, static int IRAM_ATTR esp32_readdata(struct esp32_spiflash_s *priv,
uint32_t addr, uint32_t addr,
uint8_t *buffer, uint32_t size); 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 #if 0
static int esp32_read_highstatus(struct esp32_spiflash_s *priv, static int esp32_read_highstatus(struct esp32_spiflash_s *priv,
uint32_t *status); uint32_t *status);
@ -226,6 +273,10 @@ static int esp32_write_status(struct esp32_spiflash_s *priv,
uint32_t status); uint32_t status);
#endif #endif
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
static void esp32_spiflash_work(void *p);
#endif
/* MTD driver methods */ /* MTD driver methods */
static int esp32_erase(struct mtd_dev_s *dev, off_t startblock, 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 */ /* Enxusre exculisve access to the driver */
static mutex_t g_lock = NXMUTEX_INITIALIZER; static mutex_t g_lock = NXMUTEX_INITIALIZER;
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
static struct work_s g_work;
#endif
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
@ -460,6 +514,26 @@ static inline void IRAM_ATTR
leave_critical_section(state->flags); 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 * 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: * Description:
* Write plaintext data to SPI Flash at designated address by SPI Flash * 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; 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 * Name: esp32_erase
* *
@ -1509,7 +1796,18 @@ static int esp32_erase(struct mtd_dev_s *dev, off_t startblock,
return ret; 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); ret = esp32_erasesector(priv, addr, size);
#endif
nxmutex_unlock(&g_lock); nxmutex_unlock(&g_lock);
if (ret == OK) if (ret == OK)
@ -1559,8 +1857,21 @@ static ssize_t esp32_read(struct mtd_dev_s *dev, off_t offset,
return ret; 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); esp32_set_read_opt(priv);
ret = esp32_readdata(priv, offset, buffer, nbytes); ret = esp32_readdata(priv, offset, buffer, nbytes);
#endif
nxmutex_unlock(&g_lock); nxmutex_unlock(&g_lock);
if (ret == OK) if (ret == OK)
@ -1658,7 +1969,19 @@ static ssize_t esp32_read_decrypt(struct mtd_dev_s *dev,
return ret; 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); ret = esp32_readdata_encrypted(priv, offset, tmpbuff, nbytes);
#endif
nxmutex_unlock(&g_lock); nxmutex_unlock(&g_lock);
if (ret == OK) if (ret == OK)
@ -1761,7 +2084,19 @@ static ssize_t esp32_write(struct mtd_dev_s *dev, off_t offset,
return ret; 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); ret = esp32_writedata(priv, offset, buffer, nbytes);
#endif
nxmutex_unlock(&g_lock); nxmutex_unlock(&g_lock);
if (ret == OK) if (ret == OK)
@ -1845,12 +2180,6 @@ static ssize_t esp32_bwrite_encrypt(struct mtd_dev_s *dev,
const uint8_t *buffer) const uint8_t *buffer)
{ {
ssize_t ret; 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); struct esp32_spiflash_s *priv = MTD2PRIV(dev);
uint32_t offset = MTD_BLK2SIZE(priv, startblock); uint32_t offset = MTD_BLK2SIZE(priv, startblock);
uint32_t nbytes = MTD_BLK2SIZE(priv, nblocks); uint32_t nbytes = MTD_BLK2SIZE(priv, nblocks);
@ -1872,76 +2201,22 @@ static ssize_t esp32_bwrite_encrypt(struct mtd_dev_s *dev,
return ret; return ret;
} }
while (nbytes) #ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{ {
if (offset % SPI_FLASH_ENCRYPT_UNIT_SIZE) ret = esp32_async_op(SPIFLASH_OP_CODE_ENCRYPT_WRITE, priv,
{ offset, buffer, nbytes);
wbuf = tmp_buf; }
rbuf = tmp_buf; else
addr = offset - SPI_FLASH_ENCRYPT_MIN_SIZE; {
ret = esp32_writeblk_encrypted(priv, offset, buffer, nbytes);
n = SPI_FLASH_ENCRYPT_MIN_SIZE; }
#else
ret = esp32_readdata_encrypted(priv, addr, rbuf, n); ret = esp32_writeblk_encrypted(priv, offset, buffer, nbytes);
if (ret < 0) #endif
{ if (ret == nbytes)
ferr("esp32_readdata_encrypted failed ret=%d\n", ret); {
break; ret = nblocks;
}
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;
} }
nxmutex_unlock(&g_lock); nxmutex_unlock(&g_lock);

View File

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