From bfb5214ef8a4ac5e32323908c7865782c21912af Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Wed, 28 Oct 2020 17:59:12 +0800 Subject: [PATCH] xtensa/esp32: Add SPI Flash hardware encryption I/O support --- arch/xtensa/src/esp32/esp32_spiflash.c | 830 ++++++++++++++---- arch/xtensa/src/esp32/esp32_spiflash.h | 16 + arch/xtensa/src/esp32/hardware/esp32_dport.h | 8 + arch/xtensa/src/esp32/hardware/esp32_soc.h | 14 + boards/xtensa/esp32/esp32-core/Kconfig | 16 + .../esp32/esp32-core/scripts/esp32_rom.ld | 1 + .../xtensa/esp32/esp32-core/src/esp32-core.h | 20 + .../esp32/esp32-core/src/esp32_bringup.c | 5 + .../esp32/esp32-core/src/esp32_spiflash.c | 161 ++++ 9 files changed, 918 insertions(+), 153 deletions(-) diff --git a/arch/xtensa/src/esp32/esp32_spiflash.c b/arch/xtensa/src/esp32/esp32_spiflash.c index eb077c7579..95611b569f 100644 --- a/arch/xtensa/src/esp32/esp32_spiflash.c +++ b/arch/xtensa/src/esp32/esp32_spiflash.c @@ -53,6 +53,14 @@ #define SPI_FLASH_WRITE_BUF_SIZE (32) #define SPI_FLASH_READ_BUF_SIZE (64) +#define SPI_FLASH_WRITE_WORDS (SPI_FLASH_WRITE_BUF_SIZE / 4) +#define SPI_FLASH_READ_WORDS (SPI_FLASH_READ_BUF_SIZE / 4) + +#define SPI_FLASH_MAP_PAGE_SIZE (0x10000) + +#define SPI_FLASH_ENCRYPT_UNIT_SIZE (32) +#define SPI_FLASH_ENCRYPT_WORDS (32 / 4) + #define ESP32_MTD_OFFSET CONFIG_ESP32_MTD_OFFSET #define ESP32_MTD_SIZE CONFIG_ESP32_MTD_SIZE @@ -63,10 +71,26 @@ #define MTD_BLK2SIZE(_priv, _b) (MTD_BLKSIZE(_priv) * (_b)) #define MTD_SIZE2BLK(_priv, _s) ((_s) / MTD_BLKSIZE(_priv)) +#define MMU_ADDR2PAGE(_addr) ((_addr) / SPI_FLASH_MAP_PAGE_SIZE) +#define MMU_ADDR2OFF(_addr) ((_addr) % SPI_FLASH_MAP_PAGE_SIZE) +#define MMU_BYTES2PAGES(_n) (((_n) + SPI_FLASH_MAP_PAGE_SIZE - 1) \ + / SPI_FLASH_MAP_PAGE_SIZE) + #ifndef MIN # define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif +#define DPORT_INTERRUPT_DISABLE() +#define DPORT_INTERRUPT_RESTORE() + +/* Flash MMU table for PRO CPU */ + +#define PRO_MMU_TABLE ((volatile uint32_t *)DPORT_PRO_FLASH_MMU_TABLE_REG) + +/* Flash MMU table for APP CPU */ + +#define APP_MMU_TABLE ((volatile uint32_t *)DPORT_APP_FLASH_MMU_TABLE_REG) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -99,6 +123,31 @@ struct esp32_spiflash_s uint8_t *dummies; }; +/* SPI Flash map request data */ + +struct spiflash_map_req +{ + /* Request mapping SPI Flash base address */ + + uint32_t src_addr; + + /* Request mapping SPI Flash size */ + + uint32_t size; + + /* Mapped memory pointer */ + + void *ptr; + + /* Mapped started MMU page index */ + + uint32_t start_page; + + /* Mapped MMU page count */ + + uint32_t page_cnt; +}; + /**************************************************************************** * ROM function prototypes ****************************************************************************/ @@ -121,7 +170,6 @@ static inline void spi_set_regbits(struct esp32_spiflash_s *priv, int offset, uint32_t bits); static inline void spi_reset_regbits(struct esp32_spiflash_s *priv, int offset, uint32_t bits); -static inline void IRAM_ATTR spi_memcpy(void *d, const void *s, uint32_t n); /* Misc. helpers */ @@ -161,12 +209,24 @@ static int esp32_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); static ssize_t esp32_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR uint8_t *buffer); +static ssize_t esp32_read_decrypt(FAR struct mtd_dev_s *dev, + off_t offset, + size_t nbytes, + FAR uint8_t *buffer); static ssize_t esp32_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, FAR uint8_t *buffer); +static ssize_t esp32_bread_decrypt(FAR struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + FAR uint8_t *buffer); static ssize_t esp32_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR const uint8_t *buffer); static ssize_t esp32_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, FAR const uint8_t *buffer); +static ssize_t esp32_bwrite_encrypt(FAR struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + FAR const uint8_t *buffer); static int esp32_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); @@ -198,7 +258,26 @@ static struct esp32_spiflash_s g_esp32_spiflash1 = .dummies = g_rom_spiflash_dummy_len_plus }; -/* Ensure exclusive access to the driver */ +static struct esp32_spiflash_s g_esp32_spiflash1_encrypt = +{ + .mtd = + { + .erase = esp32_erase, + .bread = esp32_bread_decrypt, + .bwrite = esp32_bwrite_encrypt, + .read = esp32_read_decrypt, + .ioctl = esp32_ioctl, +#ifdef CONFIG_MTD_BYTE_WRITE + .write = NULL, +#endif + .name = "esp32_mainflash_encrypt" + }, + .config = &g_esp32_spiflash1_config, + .chip = &g_rom_flashchip, + .dummies = g_rom_spiflash_dummy_len_plus +}; + +/* Enxusre exculisve access to the driver */ static sem_t g_exclsem = SEM_INITIALIZER(1); @@ -297,35 +376,6 @@ static inline void spi_reset_regbits(struct esp32_spiflash_s *priv, putreg32(tmp & (~bits), priv->config->reg_base + offset); } -/**************************************************************************** - * Name: spi_memcpy - * - * Description: - * Copy data from one block of memory to another block of memory. - * The function must be linked in IRAM not in flash, so add this function - * instead of libc memcpy. - * - * Input Parameters: - * d - destination address - * s - source address - * n - data bytes - * - * Returned Value: - * None - * - ****************************************************************************/ - -static inline void IRAM_ATTR spi_memcpy(void *d, const void *s, uint32_t n) -{ - uint8_t *dest = (uint8_t *)d; - const uint8_t *src = (const uint8_t *)s; - - while (n--) - { - *dest++ = *src++; - } -} - /**************************************************************************** * Name: esp32_spiflash_opstart * @@ -719,7 +769,7 @@ static int esp32_write_status(FAR struct esp32_spiflash_s *priv, * ****************************************************************************/ -static int esp32_enable_write(FAR struct esp32_spiflash_s *priv) +static int IRAM_ATTR esp32_enable_write(FAR struct esp32_spiflash_s *priv) { uint32_t flags; uint32_t regval; @@ -772,6 +822,8 @@ static int IRAM_ATTR esp32_erasesector(FAR struct esp32_spiflash_s *priv, int me; uint32_t flags; + esp32_set_write_opt(priv); + if (esp32_wait_idle(priv) != OK) { return -EIO; @@ -806,6 +858,78 @@ static int IRAM_ATTR esp32_erasesector(FAR struct esp32_spiflash_s *priv, return 0; } +/**************************************************************************** + * Name: esp32_writeonce + * + * Description: + * Write max 32 byte data to SPI Flash at designated address. + * + * ESP32 can write max 32 byte once transmission by hardware. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * addr - target address + * buffer - data buffer pointer + * size - data number by bytes + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int IRAM_ATTR esp32_writeonce(FAR struct esp32_spiflash_s *priv, + uint32_t addr, + const uint32_t *buffer, + uint32_t size) +{ + uint32_t regval; + uint32_t i; + + if (size > SPI_FLASH_WRITE_BUF_SIZE) + { + return -EINVAL; + } + + if (esp32_wait_idle(priv) != OK) + { + return -EIO; + } + + if (esp32_enable_write(priv) != OK) + { + return -EIO; + } + + regval = addr & 0xffffff; + regval |= size << ESP_ROM_SPIFLASH_BYTES_LEN; + spi_set_reg(priv, SPI_ADDR_OFFSET, regval); + + for (i = 0; i < (size / 4); i++) + { + spi_set_reg(priv, SPI_W0_OFFSET + i * 4, buffer[i]); + } + + if (size & 0x3) + { + memcpy(®val, &buffer[i], size & 0x3); + spi_set_reg(priv, SPI_W0_OFFSET + i * 4, regval); + } + + spi_set_reg(priv, SPI_RD_STATUS_OFFSET, 0); + spi_set_reg(priv, SPI_CMD_OFFSET, SPI_FLASH_PP); + while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + { + ; + } + + if (esp32_wait_idle(priv) != OK) + { + return -EIO; + } + + return OK; +} + /**************************************************************************** * Name: esp32_writedata * @@ -823,34 +947,22 @@ static int IRAM_ATTR esp32_erasesector(FAR struct esp32_spiflash_s *priv, * ****************************************************************************/ -static int esp32_writedata(FAR struct esp32_spiflash_s *priv, uint32_t addr, - const uint8_t *buffer, uint32_t size) +static int IRAM_ATTR esp32_writedata(FAR struct esp32_spiflash_s *priv, + uint32_t addr, + const uint8_t *buffer, + uint32_t size) { - uint32_t regval; - uint32_t i; - uint32_t bytes; - uint32_t tmp; - uint32_t res; - const uint8_t *tmpbuff = buffer; - int ret = OK; + int ret; int me; uint32_t flags; + uint32_t off = 0; + uint32_t bytes; + uint32_t tmp_buf[SPI_FLASH_WRITE_WORDS]; - if (esp32_wait_idle(priv) != OK) - { - return -EIO; - } + esp32_set_write_opt(priv); while (size > 0) { - flags = esp32_spiflash_opstart(priv, &me); - - if (esp32_enable_write(priv) != OK) - { - esp32_spiflash_opdone(priv, flags, me); - return -EIO; - } - bytes = MTD_BLKSIZE(priv) - addr % MTD_BLKSIZE(priv) ; if (!bytes) { @@ -862,41 +974,175 @@ static int esp32_writedata(FAR struct esp32_spiflash_s *priv, uint32_t addr, bytes = MIN(bytes, SPI_FLASH_WRITE_BUF_SIZE); } - regval = addr & 0xffffff; - regval |= bytes << ESP_ROM_SPIFLASH_BYTES_LEN; - spi_set_reg(priv, SPI_ADDR_OFFSET, regval); + memcpy(tmp_buf, &buffer[off], bytes); - for (i = 0; i < bytes; i += 4) + flags = esp32_spiflash_opstart(priv, &me); + ret = esp32_writeonce(priv, addr, tmp_buf, bytes); + esp32_spiflash_opdone(priv, flags, me); + + if (ret) { - res = MIN(4, bytes - i); - - spi_memcpy(&tmp, tmpbuff, res); - spi_set_reg(priv, SPI_W0_OFFSET + i, tmp); - tmpbuff += res; - } - - spi_set_reg(priv, SPI_RD_STATUS_OFFSET, 0); - spi_set_reg(priv, SPI_CMD_OFFSET, SPI_FLASH_PP); - while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) - { - ; - } - - if (esp32_wait_idle(priv) != OK) - { - esp32_spiflash_opdone(priv, flags, me); - return -EIO; + return ret; } addr += bytes; size -= bytes; - - esp32_spiflash_opdone(priv, flags, me); + off += bytes; } + return OK; +} + +/**************************************************************************** + * Name: esp32_writedata + * + * Description: + * Write plaintext data to SPI Flash at designated address by SPI Flash + * hardware encryption, and written data in SPI Flash is ciphertext. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * addr - target address + * buffer - data buffer pointer + * size - data number + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int IRAM_ATTR esp32_writedata_encrypted( + FAR struct esp32_spiflash_s *priv, + uint32_t addr, + const uint8_t *buffer, + uint32_t size) +{ + int i; + int blocks; + int ret = OK; + int me; + uint32_t flags; + uint32_t tmp_buf[SPI_FLASH_ENCRYPT_WORDS]; + + if (addr % SPI_FLASH_ENCRYPT_UNIT_SIZE) + { + ferr("ERROR: address=0x%x is not %d-byte align\n", + addr, SPI_FLASH_ENCRYPT_UNIT_SIZE); + return -EINVAL; + } + + if (size % SPI_FLASH_ENCRYPT_UNIT_SIZE) + { + ferr("ERROR: size=%u is not %d-byte align\n", + size, SPI_FLASH_ENCRYPT_UNIT_SIZE); + return -EINVAL; + } + + blocks = size / SPI_FLASH_ENCRYPT_UNIT_SIZE; + + for (i = 0; i < blocks; i++) + { + memcpy(tmp_buf, buffer, SPI_FLASH_ENCRYPT_UNIT_SIZE); + + flags = esp32_spiflash_opstart(priv, &me); + esp_rom_spiflash_write_encrypted_enable(); + + ret = esp_rom_spiflash_prepare_encrypted_data(addr, tmp_buf); + if (ret) + { + ferr("ERROR: Failed to prepare encrypted data\n"); + goto exit; + } + + ret = esp32_writeonce(priv, addr, tmp_buf, + SPI_FLASH_ENCRYPT_UNIT_SIZE); + if (ret) + { + ferr("ERROR: Failed to write encrypted data @ 0x%x\n", addr); + goto exit; + } + + esp_rom_spiflash_write_encrypted_disable(); + esp32_spiflash_opdone(priv, flags, me); + + addr += SPI_FLASH_ENCRYPT_UNIT_SIZE; + buffer += SPI_FLASH_ENCRYPT_UNIT_SIZE; + size -= SPI_FLASH_ENCRYPT_UNIT_SIZE; + } + + return 0; + +exit: + esp_rom_spiflash_write_encrypted_disable(); + esp32_spiflash_opdone(priv, flags, me); + return ret; } +/**************************************************************************** + * Name: esp32_readdata + * + * Description: + * Read max 64 byte data data from SPI Flash at designated address. + * + * ESP32 can read max 64 byte once transmission by hardware. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * addr - target address + * buffer - data buffer pointer + * size - data number by bytes + * + * Returned Value: + * OK if success or a negative value if fail. + * + ****************************************************************************/ + +static int IRAM_ATTR esp32_readonce(FAR struct esp32_spiflash_s *priv, + uint32_t addr, + uint32_t *buffer, + uint32_t size) +{ + uint32_t regval; + uint32_t i; + + if (size > SPI_FLASH_READ_BUF_SIZE) + { + return -EINVAL; + } + + if (esp32_wait_idle(priv) != OK) + { + return -EIO; + } + + regval = ((size << 3) - 1) << SPI_USR_MISO_DBITLEN_S; + spi_set_reg(priv, SPI_MISO_DLEN_OFFSET, regval); + + regval = addr << 8; + spi_set_reg(priv, SPI_ADDR_OFFSET, regval); + + spi_set_reg(priv, SPI_RD_STATUS_OFFSET, 0); + spi_set_reg(priv, SPI_CMD_OFFSET, SPI_USR); + while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + { + ; + } + + for (i = 0; i < (size / 4); i++) + { + buffer[i] = spi_get_reg(priv, SPI_W0_OFFSET + i * 4); + } + + if (size & 0x3) + { + regval = spi_get_reg(priv, SPI_W0_OFFSET + i * 4); + memcpy(&buffer[i], ®val, size & 0x3); + } + + return OK; +} + /**************************************************************************** * Name: esp32_readdata * @@ -914,59 +1160,197 @@ static int esp32_writedata(FAR struct esp32_spiflash_s *priv, uint32_t addr, * ****************************************************************************/ -static int esp32_readdata(FAR struct esp32_spiflash_s *priv, uint32_t addr, - uint8_t *buffer, uint32_t size) +static int IRAM_ATTR esp32_readdata(FAR struct esp32_spiflash_s *priv, + uint32_t addr, + uint8_t *buffer, + uint32_t size) { - uint32_t regval; - uint32_t i; - uint32_t bytes; - uint32_t tmp; - uint32_t res; - uint8_t *tmpbuff = buffer; + int ret; int me; uint32_t flags; - - if (esp32_wait_idle(priv) != OK) - { - return -EIO; - } + uint32_t off = 0; + uint32_t bytes; + uint32_t tmp_buf[SPI_FLASH_READ_WORDS]; while (size > 0) { - flags = esp32_spiflash_opstart(priv, &me); - bytes = MIN(size, SPI_FLASH_READ_BUF_SIZE); - regval = ((bytes << 3) - 1) << SPI_USR_MISO_DBITLEN_S; - spi_set_reg(priv, SPI_MISO_DLEN_OFFSET, regval); - regval = addr << 8; - spi_set_reg(priv, SPI_ADDR_OFFSET, regval); + flags = esp32_spiflash_opstart(priv, &me); + ret = esp32_readonce(priv, addr, tmp_buf, bytes); + esp32_spiflash_opdone(priv, flags, me); - spi_set_reg(priv, SPI_RD_STATUS_OFFSET, 0); - spi_set_reg(priv, SPI_CMD_OFFSET, SPI_USR); - while (spi_get_reg(priv, SPI_CMD_OFFSET) != 0) + if (ret) { - ; + return ret; } - for (i = 0; i < bytes; i += 4) - { - res = MIN(4, bytes - i); - - tmp = spi_get_reg(priv, SPI_W0_OFFSET + i); - spi_memcpy(tmpbuff, &tmp, res); - tmpbuff += res; - } + memcpy(&buffer[off], tmp_buf, bytes); addr += bytes; size -= bytes; - - esp32_spiflash_opdone(priv, flags, me); + off += bytes; } return OK; } +/**************************************************************************** + * Name: esp32_mmap + * + * Description: + * Mapped SPI Flash address to ESP32's address bus, so that software + * can read SPI Flash data by reading data from memory access. + * + * If SPI Flash hardware encryption is enable, the read from mapped + * address is decrypted. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * req - SPI Flash mapping requesting parameters + * + * Returned Value: + * 0 if success or a negative value if fail. + * + ****************************************************************************/ + +static int IRAM_ATTR esp32_mmap(FAR struct esp32_spiflash_s *priv, + struct spiflash_map_req *req) +{ + int ret; + int i; + int me; + int start_page; + int flash_page; + int page_cnt; + uint32_t flags; + + flags = esp32_spiflash_opstart(priv, &me); + + for (start_page = DROM0_PAGES_START; + start_page < DROM0_PAGES_END; + ++start_page) + { + if (PRO_MMU_TABLE[start_page] == INVALID_MMU_VAL +#ifdef CONFIG_SMP + && APP_MMU_TABLE[start_page] == INVALID_MMU_VAL +#endif + ) + { + break; + } + } + + flash_page = MMU_ADDR2PAGE(req->src_addr); + page_cnt = MMU_BYTES2PAGES(req->size); + + if (start_page + page_cnt < DROM0_PAGES_END) + { + for (i = 0; i < page_cnt; i++) + { + PRO_MMU_TABLE[start_page + i] = flash_page + i; +#ifdef CONFIG_SMP + APP_MMU_TABLE[start_page + i] = flash_page + i; +#endif + } + + req->start_page = start_page; + req->page_cnt = page_cnt; + req->ptr = (void *)(VADDR0_START_ADDR + + start_page * SPI_FLASH_MAP_PAGE_SIZE + + MMU_ADDR2OFF(req->src_addr)); + + ret = 0; + } + else + { + ret = -ENOBUFS; + } + + esp32_spiflash_opdone(priv, flags, me); + + return ret; +} + +/**************************************************************************** + * Name: esp32_ummap + * + * Description: + * Unmap SPI Flash address in ESP32's address bus, and free resource. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * req - SPI Flash mapping requesting paramters + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void IRAM_ATTR esp32_ummap(FAR struct esp32_spiflash_s *priv, + const struct spiflash_map_req *req) +{ + uint32_t flags; + int me; + int i; + + flags = esp32_spiflash_opstart(priv, &me); + + for (i = req->start_page; i < req->start_page + req->page_cnt; ++i) + { + PRO_MMU_TABLE[i] = INVALID_MMU_VAL; +#ifdef CONFIG_SMP + APP_MMU_TABLE[i] = INVALID_MMU_VAL; +#endif + } + + esp32_spiflash_opdone(priv, flags, me); +} + +/**************************************************************************** + * Name: esp32_readdata_encrypted + * + * Description: + * Read decrypted data from SPI Flash at designated address when + * enable SPI Flash hardware encryption. + * + * Input Parameters: + * spi - ESP32 SPI Flash chip data + * addr - target address + * buffer - data buffer pointer + * size - data number + * + * Returned Value: + * OK if success or a negative value if fail. + * + ****************************************************************************/ + +static int IRAM_ATTR esp32_readdata_encrypted( + FAR struct esp32_spiflash_s *priv, + uint32_t addr, + uint8_t *buffer, + uint32_t size) +{ + int ret; + struct spiflash_map_req req = + { + .src_addr = addr, + .size = size + }; + + ret = esp32_mmap(priv, &req); + if (ret) + { + return ret; + } + + memcpy(buffer, req.ptr, size); + + esp32_ummap(priv, &req); + + return OK; +} + /**************************************************************************** * Name: esp32_erase * @@ -1006,7 +1390,6 @@ static int esp32_erase(FAR struct mtd_dev_s *dev, off_t startblock, return ret; } - esp32_set_write_opt(priv); ret = esp32_erasesector(priv, addr, size); nxsem_post(&g_exclsem); @@ -1044,24 +1427,12 @@ static ssize_t esp32_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR uint8_t *buffer) { int ret; - uint8_t *tmpbuff = buffer; FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); #ifdef CONFIG_ESP32_SPIFLASH_DEBUG finfo("esp32_read(%p, 0x%x, %d, %p)\n", dev, offset, nbytes, buffer); #endif -#ifdef CONFIG_XTENSA_USE_SEPARATE_IMEM - if (esp32_ptr_extram(buffer)) - { - tmpbuff = xtensa_imm_malloc(nbytes); - if (tmpbuff == NULL) - { - return (ssize_t)-ENOMEM; - } - } -#endif - /* Acquire the semaphore. */ ret = nxsem_wait(&g_exclsem); @@ -1071,7 +1442,7 @@ static ssize_t esp32_read(FAR struct mtd_dev_s *dev, off_t offset, } esp32_set_read_opt(priv); - ret = esp32_readdata(priv, offset, tmpbuff, nbytes); + ret = esp32_readdata(priv, offset, buffer, nbytes); nxsem_post(&g_exclsem); @@ -1085,13 +1456,6 @@ static ssize_t esp32_read(FAR struct mtd_dev_s *dev, off_t offset, #endif error_with_buffer: -#ifdef CONFIG_XTENSA_USE_SEPARATE_IMEM - if (esp32_ptr_extram(buffer)) - { - memcpy(buffer, tmpbuff, (ret == OK) ? nbytes : 0); - xtensa_imm_free(tmpbuff); - } -#endif return (ssize_t)ret; } @@ -1139,6 +1503,109 @@ static ssize_t esp32_bread(FAR struct mtd_dev_s *dev, off_t startblock, return ret; } +/**************************************************************************** + * Name: esp32_read_decrypt + * + * Description: + * Read encrypted data and decrypt automatically from SPI Flash + * at designated address. + * + * Input Parameters: + * dev - ESP32 MTD device data + * offset - target address offset + * nbytes - data number + * buffer - data buffer pointer + * + * Returned Value: + * Read data bytes if success or a negative value if fail. + * + ****************************************************************************/ + +static ssize_t esp32_read_decrypt(FAR struct mtd_dev_s *dev, + off_t offset, + size_t nbytes, + FAR uint8_t *buffer) +{ + int ret; + uint8_t *tmpbuff = buffer; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_read_decrypt(%p, 0x%x, %d, %p)\n", + dev, offset, nbytes, buffer); +#endif + + /* Acquire the semaphore. */ + + ret = nxsem_wait(&g_exclsem); + if (ret < 0) + { + goto error_with_buffer; + } + + ret = esp32_readdata_encrypted(priv, offset, tmpbuff, nbytes); + + nxsem_post(&g_exclsem); + + if (ret == OK) + { + ret = nbytes; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_read_decrypt()=%d\n", ret); +#endif + +error_with_buffer: + + return (ssize_t)ret; +} + +/**************************************************************************** + * Name: esp32_bread_decrypt + * + * Description: + * Read encrypted data and decrypt automatically from designated blocks. + * + * Input Parameters: + * dev - ESP32 MTD device data + * startblock - start block number, it is not equal to SPI Flash's block + * nblocks - blocks number + * buffer - data buffer pointer + * + * Returned Value: + * Read block number if success or a negative value if fail. + * + ****************************************************************************/ + +static ssize_t esp32_bread_decrypt(FAR struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + FAR uint8_t *buffer) +{ + int ret; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + uint32_t addr = MTD_BLK2SIZE(priv, startblock); + uint32_t size = MTD_BLK2SIZE(priv, nblocks); + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_bread_decrypt(%p, 0x%x, %d, %p)\n", + dev, startblock, nblocks, buffer); +#endif + + ret = esp32_read_decrypt(dev, addr, size, buffer); + if (ret == size) + { + ret = nblocks; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_bread_decrypt()=%d\n", ret); +#endif + + return ret; +} + /**************************************************************************** * Name: esp32_write * @@ -1160,7 +1627,6 @@ static ssize_t esp32_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR const uint8_t *buffer) { int ret; - uint8_t *tmpbuff = (uint8_t *)buffer; FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); ASSERT(buffer); @@ -1170,19 +1636,6 @@ static ssize_t esp32_write(FAR struct mtd_dev_s *dev, off_t offset, return -EINVAL; } -#ifdef CONFIG_XTENSA_USE_SEPARATE_IMEM - if (esp32_ptr_extram(buffer)) - { - tmpbuff = xtensa_imm_malloc(nbytes); - if (tmpbuff == NULL) - { - return (ssize_t)-ENOMEM; - } - - memcpy(tmpbuff, buffer, nbytes); - } -#endif - #ifdef CONFIG_ESP32_SPIFLASH_DEBUG finfo("esp32_write(%p, 0x%x, %d, %p)\n", dev, offset, nbytes, buffer); #endif @@ -1195,8 +1648,7 @@ static ssize_t esp32_write(FAR struct mtd_dev_s *dev, off_t offset, goto error_with_buffer; } - esp32_set_write_opt(priv); - ret = esp32_writedata(priv, offset, tmpbuff, nbytes); + ret = esp32_writedata(priv, offset, buffer, nbytes); nxsem_post(&g_exclsem); @@ -1210,12 +1662,6 @@ static ssize_t esp32_write(FAR struct mtd_dev_s *dev, off_t offset, #endif error_with_buffer: -#ifdef CONFIG_XTENSA_USE_SEPARATE_IMEM - if (esp32_ptr_extram(buffer)) - { - xtensa_imm_free(tmpbuff); - } -#endif return (ssize_t)ret; } @@ -1264,6 +1710,63 @@ static ssize_t esp32_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, return ret; } +/**************************************************************************** + * Name: esp32_bwrite_encrypt + * + * Description: + * Write data to designated blocks by SPI Flash hardware encryption. + * + * Input Parameters: + * dev - ESP32 MTD device data + * startblock - start MTD block number, + * it is not equal to SPI Flash's block + * nblocks - blocks number + * buffer - data buffer pointer + * + * Returned Value: + * Writen block number if success or a negative value if fail. + * + ****************************************************************************/ + +static ssize_t esp32_bwrite_encrypt(FAR struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + FAR const uint8_t *buffer) +{ + ssize_t ret; + FAR struct esp32_spiflash_s *priv = MTD2PRIV(dev); + uint32_t addr = MTD_BLK2SIZE(priv, startblock); + uint32_t size = MTD_BLK2SIZE(priv, nblocks); + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_bwrite_encrypt(%p, 0x%x, %d, %p)\n", + dev, startblock, nblocks, buffer); +#endif + + ret = nxsem_wait(&g_exclsem); + if (ret < 0) + { + goto error_with_buffer; + } + + ret = esp32_writedata_encrypted(priv, addr, buffer, size); + + nxsem_post(&g_exclsem); + + if (ret == OK) + { + ret = nblocks; + } + +#ifdef CONFIG_ESP32_SPIFLASH_DEBUG + finfo("esp32_bwrite_encrypt()=%d\n", ret); +#endif + +error_with_buffer: + + return ret; +} + /**************************************************************************** * Name: esp32_ioctl * @@ -1398,4 +1901,25 @@ FAR struct mtd_dev_s *esp32_spiflash_get_mtd(void) return &priv->mtd; } +/**************************************************************************** + * Name: esp32_spiflash_get_mtd + * + * Description: + * Get ESP32 SPI Flash encryption raw MTD. + * + * Input Parameters: + * None + * + * Returned Value: + * ESP32 SPI Flash encryption raw MTD data pointer. + * + ****************************************************************************/ + +FAR struct mtd_dev_s *esp32_spiflash_encrypt_get_mtd(void) +{ + struct esp32_spiflash_s *priv = &g_esp32_spiflash1_encrypt; + + return &priv->mtd; +} + #endif /* CONFIG_ESP32_SPIFLASH */ diff --git a/arch/xtensa/src/esp32/esp32_spiflash.h b/arch/xtensa/src/esp32/esp32_spiflash.h index 1b3702d02c..3c9099aa1a 100644 --- a/arch/xtensa/src/esp32/esp32_spiflash.h +++ b/arch/xtensa/src/esp32/esp32_spiflash.h @@ -78,6 +78,22 @@ FAR struct mtd_dev_s *esp32_spiflash_alloc_mtdpart(void); FAR struct mtd_dev_s *esp32_spiflash_get_mtd(void); +/**************************************************************************** + * Name: esp32_spiflash_get_mtd + * + * Description: + * Get ESP32 SPI Flash encryption raw MTD. + * + * Input Parameters: + * None + * + * Returned Value: + * ESP32 SPI Flash encryption raw MTD data pointer. + * + ****************************************************************************/ + +FAR struct mtd_dev_s *esp32_spiflash_encrypt_get_mtd(void); + #ifdef __cplusplus } #endif diff --git a/arch/xtensa/src/esp32/hardware/esp32_dport.h b/arch/xtensa/src/esp32/hardware/esp32_dport.h index f81b6dea81..d5a74becb1 100644 --- a/arch/xtensa/src/esp32/hardware/esp32_dport.h +++ b/arch/xtensa/src/esp32/hardware/esp32_dport.h @@ -4387,4 +4387,12 @@ #define DPORT_DATE_S 0 #define DPORT_DPORT_DATE_VERSION 0x1605190 +/* SPI Flash MMU table regitser base address for PRO CPU */ + +#define DPORT_PRO_FLASH_MMU_TABLE_REG (DR_REG_DPORT_BASE + 0x10000) + +/* SPI Flash MMU table regitser base address for APP CPU */ + +#define DPORT_APP_FLASH_MMU_TABLE_REG (DR_REG_DPORT_BASE + 0x12000) + #endif /* __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_DPORT_H */ diff --git a/arch/xtensa/src/esp32/hardware/esp32_soc.h b/arch/xtensa/src/esp32/hardware/esp32_soc.h index 2109315fad..214108ea04 100644 --- a/arch/xtensa/src/esp32/hardware/esp32_soc.h +++ b/arch/xtensa/src/esp32/hardware/esp32_soc.h @@ -275,6 +275,11 @@ #define SOC_EXTRAM_DATA_LOW 0x3f800000 #define SOC_EXTRAM_DATA_HIGH 0x3fc00000 +/* Virtual address 0 */ + +#define VADDR0_START_ADDR SOC_DROM_LOW +#define VADDR0_END_ADDR (SOC_DROM_HIGH - 1) + /* Interrupt hardware source table * This table is decided by hardware, don't touch this. */ @@ -776,6 +781,15 @@ extern int rom_i2c_writeReg(int block, int block_id, int reg_add, #define FE2_TX_INF_FORCE_PD_V 1 #define FE2_TX_INF_FORCE_PD_S 9 +/* RO data page in MMU index */ + +#define DROM0_PAGES_START 0 +#define DROM0_PAGES_END 64 + +/* MMU invaild value */ + +#define INVALID_MMU_VAL 0x100 + /**************************************************************************** * Inline Functions ****************************************************************************/ diff --git a/boards/xtensa/esp32/esp32-core/Kconfig b/boards/xtensa/esp32/esp32-core/Kconfig index e6a5e293cc..9a42a5d3cc 100644 --- a/boards/xtensa/esp32/esp32-core/Kconfig +++ b/boards/xtensa/esp32/esp32-core/Kconfig @@ -63,6 +63,22 @@ choice depends on FS_LITTLEFS endchoice +config ESP32_SPIFLASH_ENCRYPTION_TEST + bool "SPI Flash encryption test" + default n + depends on ESP32_SPIFLASH + select DEBUG_ASSERTIONS + help + Enable SPI Flash encryption test. This option will also select + DEBUG_ASSERTIONS to enable kernel assert macro. + +config ESP32_SPIFLASH_TEST_ADDRESS + hex "SPI Flash test address" + default 0x180000 + depends on ESP32_SPIFLASH_ENCRYPTION_TEST + help + SPI Flash encryption test read/write address. + if PM config PM_ALARM_SEC diff --git a/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld b/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld index 870c405e1e..306f4ef6a0 100644 --- a/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld +++ b/boards/xtensa/esp32/esp32-core/scripts/esp32_rom.ld @@ -1851,6 +1851,7 @@ PROVIDE ( g_rom_flashchip = 0x3ffae270 ); PROVIDE ( g_rom_spiflash_dummy_len_plus = 0x3ffae290 ); PROVIDE ( esp_rom_spiflash_read_user_cmd = 0x400621b0 ); PROVIDE ( esp_rom_spiflash_write_encrypted_enable = 0x40062df4 ); +PROVIDE ( esp_rom_spiflash_write_encrypted_disable = 0x40062e60 ); PROVIDE ( esp_rom_spiflash_prepare_encrypted_data = 0x40062e1c ); PROVIDE ( esp_rom_printf = ets_printf ); diff --git a/boards/xtensa/esp32/esp32-core/src/esp32-core.h b/boards/xtensa/esp32/esp32-core/src/esp32-core.h index 0bce83f0f3..3627b2348f 100644 --- a/boards/xtensa/esp32/esp32-core/src/esp32-core.h +++ b/boards/xtensa/esp32/esp32-core/src/esp32-core.h @@ -118,5 +118,25 @@ int esp32_timer_driver_init(void); int esp32_wtd_driver_init(void); #endif +/**************************************************************************** + * Name: esp32_spiflash_encrypt_test + * + * Description: + * Test ESP32 SPI Flash driver read/write with encryption. + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32_SPIFLASH_ENCRYPTION_TEST + +void esp32_spiflash_encrypt_test(void); + +#endif + #endif /* __ASSEMBLY__ */ #endif /* __BOARDS_XTENSA_ESP32_ESP32_CORE_SRC_ESP32_CORE_H */ diff --git a/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c b/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c index c337c062de..867ac4aa02 100644 --- a/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c +++ b/boards/xtensa/esp32/esp32-core/src/esp32_bringup.c @@ -162,6 +162,11 @@ int esp32_bringup(void) #endif #ifdef CONFIG_ESP32_SPIFLASH + +#ifdef CONFIG_ESP32_SPIFLASH_ENCRYPTION_TEST + esp32_spiflash_encrypt_test(); +#endif + ret = esp32_spiflash_init(); if (ret) { diff --git a/boards/xtensa/esp32/esp32-core/src/esp32_spiflash.c b/boards/xtensa/esp32/esp32-core/src/esp32_spiflash.c index 3ac6ca674d..7407117c4c 100644 --- a/boards/xtensa/esp32/esp32-core/src/esp32_spiflash.c +++ b/boards/xtensa/esp32/esp32-core/src/esp32_spiflash.c @@ -99,3 +99,164 @@ int esp32_spiflash_init(void) return ret; } +/**************************************************************************** + * Name: esp32_spiflash_encrypt_test + * + * Description: + * Test ESP32 SPI Flash driver read/write with encryption. + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32_SPIFLASH_ENCRYPTION_TEST + +void esp32_spiflash_encrypt_test(void) +{ + int i; + int ret; + uint8_t *wbuf; + uint8_t *rbuf; + struct mtd_geometry_s geo; + uint32_t erase_block; + uint32_t erase_nblocks; + uint32_t rw_block; + uint32_t rw_nblocks; + struct mtd_dev_s *mtd = esp32_spiflash_get_mtd(); + struct mtd_dev_s *enc_mtd = esp32_spiflash_encrypt_get_mtd(); + const uint32_t address = CONFIG_ESP32_SPIFLASH_TEST_ADDRESS; + const uint32_t size = 4096; + + ret = MTD_IOCTL(enc_mtd, MTDIOC_GEOMETRY, + (unsigned long)(uintptr_t)&geo); + if (ret < 0) + { + ferr("ERROR: Failed to get GEO errno =%d\n", ret); + DEBUGASSERT(0); + } + + wbuf = kmm_malloc(size); + if (!wbuf) + { + ferr("ERROR: Failed to alloc %d heap\n", size); + DEBUGASSERT(0); + } + + rbuf = kmm_malloc(size); + if (!rbuf) + { + ferr("ERROR: Failed to alloc %d heap\n", size); + DEBUGASSERT(0); + } + + for (i = 0; i < size; i++) + { + wbuf[i] = (uint8_t)random(); + } + + erase_block = address / geo.erasesize; + erase_nblocks = size / geo.erasesize; + + rw_block = address / geo.blocksize; + rw_nblocks = size / geo.blocksize; + + ret = MTD_ERASE(enc_mtd, erase_block, erase_nblocks); + if (ret != erase_nblocks) + { + ferr("ERROR: Failed to erase block errno=%d\n", ret); + DEBUGASSERT(0); + } + + ret = MTD_BWRITE(enc_mtd, rw_block, rw_nblocks, wbuf); + if (ret != rw_nblocks) + { + ferr("ERROR: Failed to encrypt write errno=%d\n", ret); + DEBUGASSERT(0); + } + + memset(rbuf, 0, size); + ret = MTD_BREAD(enc_mtd, rw_block, rw_nblocks, rbuf); + if (ret != rw_nblocks) + { + ferr("ERROR: Failed to decrypt read errno=%d\n", ret); + DEBUGASSERT(0); + } + + if (memcmp(wbuf, rbuf, size)) + { + ferr("ASSERT: Encrypted and decrypted data is not same\n"); + DEBUGASSERT(0); + } + + memset(rbuf, 0, size); + ret = MTD_BREAD(mtd, rw_block, rw_nblocks, rbuf); + if (ret != rw_nblocks) + { + ferr("ERROR: Failed to read errno=%d\n", ret); + DEBUGASSERT(0); + } + + if (!memcmp(wbuf, rbuf, size)) + { + ferr("ASSERT: Encrypted and normal data is same\n"); + DEBUGASSERT(0); + } + + for (i = 0; i < size; i++) + { + wbuf[i] = (uint8_t)random(); + } + + ret = MTD_ERASE(enc_mtd, erase_block, erase_nblocks); + if (ret != erase_nblocks) + { + ferr("ERROR: Failed to erase errno=%d\n", ret); + DEBUGASSERT(0); + } + + ret = MTD_BWRITE(mtd, rw_block, rw_nblocks, wbuf); + if (ret != rw_nblocks) + { + ferr("ERROR: Failed to write errno=%d\n", ret); + DEBUGASSERT(0); + } + + memset(rbuf, 0, size); + ret = MTD_BREAD(enc_mtd, rw_block, rw_nblocks, rbuf); + if (ret != rw_nblocks) + { + ferr("ERROR: Failed to decrypt read errno=%d\n", ret); + DEBUGASSERT(0); + } + + if (!memcmp(wbuf, rbuf, size)) + { + ferr("ASSERT: Normal and decrypted data is same\n"); + DEBUGASSERT(0); + } + + memset(rbuf, 0, size); + ret = MTD_BREAD(mtd, rw_block, rw_nblocks, rbuf); + if (ret != rw_nblocks) + { + ferr("ERROR: Failed to read errno=%d\n", ret); + DEBUGASSERT(0); + } + + if (memcmp(wbuf, rbuf, size)) + { + ferr("ASSERT: Normal and normal data is not same\n"); + DEBUGASSERT(0); + } + + kmm_free(wbuf); + kmm_free(rbuf); + + finfo("INFO: ESP32 SPI Flash encryption test successfully\n"); +} + +#endif /* CONFIG_ESP32_SPIFLASH_ENCRYPTION_TEST */