mirror of
https://github.com/apache/nuttx.git
synced 2026-10-08 14:55:18 +00:00
arch/arm/rp23xx: Check the flash MTD region against the flash size.
Some checks are pending
Build Documentation / build-html (push) Waiting to run
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
Some checks are pending
Build Documentation / build-html (push) Waiting to run
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
RP23XX_FLASH_MTD_OFFSET and RP23XX_FLASH_MTD_SIZE come from Kconfig. If the region ends past the end of the flash, the flash wraps the address around, and an erase or program hits the start of the flash, where the NuttX image is. For example, a 4M region at 1M does not fit on the 4M flash of a Raspberry Pi Pico 2. Read the JEDEC ID at initialization, in QMI direct mode as the Pico SDK flash_do_cmd() does, and refuse a region that does not fit. The capacity byte is log2 of the size in bytes. If the ID does not look valid, warn and do not check. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
parent
cb87f99b6e
commit
e7f9aaa52b
3 changed files with 123 additions and 4 deletions
|
|
@ -1241,7 +1241,8 @@ config RP23XX_FLASH_MTD_SIZE
|
|||
---help---
|
||||
Size of the MTD region in bytes. Must be a multiple of the 4096
|
||||
byte erase sector, and must fit within the flash fitted to the
|
||||
board.
|
||||
board. The driver reads the flash size from its JEDEC ID, and
|
||||
refuses to initialize if the region does not fit.
|
||||
|
||||
config RP23XX_FLASH_MTD_SAFE_XIP
|
||||
bool "Always restore XIP with the bootrom command mode"
|
||||
|
|
|
|||
|
|
@ -142,6 +142,11 @@
|
|||
#define FLASH_BLOCK_SIZE 65536
|
||||
#define FLASH_BLOCK_ERASE_CMD 0xd8
|
||||
|
||||
/* JEDEC ID: command, manufacturer, memory type, capacity (log2 bytes) */
|
||||
|
||||
#define FLASH_READ_ID_CMD 0x9f
|
||||
#define FLASH_READ_ID_SIZE 4
|
||||
|
||||
#define FS_OFFSET CONFIG_RP23XX_FLASH_MTD_OFFSET
|
||||
#define FS_SIZE CONFIG_RP23XX_FLASH_MTD_SIZE
|
||||
|
||||
|
|
@ -171,7 +176,7 @@ struct rp23xx_flash_op_s
|
|||
{
|
||||
CODE void (*func)(FAR struct rp23xx_flash_op_s *op);
|
||||
uint32_t addr;
|
||||
FAR const uint8_t *data;
|
||||
FAR uint8_t *data;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
|
|
@ -545,6 +550,63 @@ static void RAM_CODE(do_write)(FAR struct rp23xx_flash_op_s *op)
|
|||
rp23xx_flash_end(&state);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: do_read_id
|
||||
*
|
||||
* Description:
|
||||
* Read the JEDEC ID in QMI direct mode, as the Pico SDK flash_do_cmd()
|
||||
* does.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void RAM_CODE(do_read_id)(FAR struct rp23xx_flash_op_s *op)
|
||||
{
|
||||
struct rp23xx_qspi_state_s state;
|
||||
size_t tx = 0;
|
||||
size_t rx = 0;
|
||||
uint32_t csr;
|
||||
|
||||
rp23xx_flash_begin(&state);
|
||||
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) |
|
||||
RP23XX_QMI_DIRECT_CSR_ASSERT_CS0N, RP23XX_QMI_DIRECT_CSR);
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) | RP23XX_QMI_DIRECT_CSR_EN,
|
||||
RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
while ((getreg32(RP23XX_QMI_DIRECT_CSR) & RP23XX_QMI_DIRECT_CSR_BUSY) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
while (tx < op->count || rx < op->count)
|
||||
{
|
||||
csr = getreg32(RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
if ((csr & RP23XX_QMI_DIRECT_CSR_TXFULL) == 0 && tx < op->count)
|
||||
{
|
||||
putreg32(tx == 0 ? FLASH_READ_ID_CMD : 0, RP23XX_QMI_DIRECT_TX);
|
||||
tx++;
|
||||
}
|
||||
|
||||
if ((csr & RP23XX_QMI_DIRECT_CSR_RXEMPTY) == 0 && rx < op->count)
|
||||
{
|
||||
op->data[rx++] = (uint8_t)getreg32(RP23XX_QMI_DIRECT_RX);
|
||||
}
|
||||
}
|
||||
|
||||
/* BUSY stays high for half an SCK after the last bit, for CS timing */
|
||||
|
||||
while ((getreg32(RP23XX_QMI_DIRECT_CSR) & RP23XX_QMI_DIRECT_CSR_BUSY) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) & ~RP23XX_QMI_DIRECT_CSR_EN,
|
||||
RP23XX_QMI_DIRECT_CSR);
|
||||
putreg32(getreg32(RP23XX_QMI_DIRECT_CSR) &
|
||||
~RP23XX_QMI_DIRECT_CSR_ASSERT_CS0N, RP23XX_QMI_DIRECT_CSR);
|
||||
|
||||
rp23xx_flash_end(&state);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_flash_call
|
||||
*
|
||||
|
|
@ -607,6 +669,42 @@ static void rp23xx_flash_run(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_flash_size
|
||||
*
|
||||
* Description:
|
||||
* Return the flash size from its JEDEC ID, or 0 if the ID is not valid.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static size_t rp23xx_flash_size(void)
|
||||
{
|
||||
FAR uint8_t *id = g_flash_page;
|
||||
|
||||
if (nxmutex_lock(&g_flash_dev.lock) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_flash_op.func = do_read_id;
|
||||
g_flash_op.data = id;
|
||||
g_flash_op.count = FLASH_READ_ID_SIZE;
|
||||
|
||||
rp23xx_flash_run();
|
||||
nxmutex_unlock(&g_flash_dev.lock);
|
||||
|
||||
finfo("rp23xx_flash: JEDEC ID %02x %02x %02x\n", id[1], id[2], id[3]);
|
||||
|
||||
/* Accept a capacity from 64K to 64M */
|
||||
|
||||
if (id[1] == 0x00 || id[1] == 0xff || id[3] < 16 || id[3] > 26)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (size_t)1 << id[3];
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_flash_erase
|
||||
*
|
||||
|
|
@ -725,7 +823,7 @@ static ssize_t rp23xx_flash_bwrite(struct mtd_dev_s *dev, off_t startblock,
|
|||
{
|
||||
g_flash_op.func = do_write;
|
||||
g_flash_op.addr = FS_OFFSET + (startblock + i) * FLASH_PAGE_SIZE;
|
||||
g_flash_op.data = buffer + i * FLASH_PAGE_SIZE;
|
||||
g_flash_op.data = (FAR uint8_t *)buffer + i * FLASH_PAGE_SIZE;
|
||||
g_flash_op.count = FLASH_PAGE_SIZE;
|
||||
|
||||
if (IS_XIP_ADDR(g_flash_op.data))
|
||||
|
|
@ -858,6 +956,7 @@ static int rp23xx_flash_ioctl(struct mtd_dev_s *dev, int cmd,
|
|||
|
||||
struct mtd_dev_s *rp23xx_flash_mtd_initialize(void)
|
||||
{
|
||||
size_t size;
|
||||
#ifndef CONFIG_RP23XX_FLASH_MTD_SAFE_XIP
|
||||
int i;
|
||||
#endif
|
||||
|
|
@ -937,6 +1036,23 @@ struct mtd_dev_s *rp23xx_flash_mtd_initialize(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* An address past the end of the flash wraps around to the start, where
|
||||
* the NuttX image is. Refuse a region that does not fit.
|
||||
*/
|
||||
|
||||
size = rp23xx_flash_size();
|
||||
if (size == 0)
|
||||
{
|
||||
fwarn("rp23xx_flash: unknown flash size; not checked\n");
|
||||
}
|
||||
else if (FS_OFFSET + FS_SIZE > size)
|
||||
{
|
||||
merr("ERROR: flash MTD region ends at 0x%08x, past the end of the "
|
||||
"%zu byte flash\n", (unsigned)(FS_OFFSET + FS_SIZE), size);
|
||||
set_errno(EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_initialized = true;
|
||||
|
||||
finfo("rp23xx_flash: %u sectors of %u bytes at 0x%08x\n",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue