From 5d5d88b27158ebfbe833474784f4cf9f8affcaf5 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sat, 17 Sep 2022 17:31:37 +0200 Subject: [PATCH 1/5] drivers/mtd_flashpage: implement pagewise API --- drivers/include/mtd_flashpage.h | 7 +- drivers/mtd_flashpage/mtd_flashpage.c | 132 ++++++++++++++++++++++---- 2 files changed, 119 insertions(+), 20 deletions(-) diff --git a/drivers/include/mtd_flashpage.h b/drivers/include/mtd_flashpage.h index 137a415c9a12..932efc2bcc4b 100644 --- a/drivers/include/mtd_flashpage.h +++ b/drivers/include/mtd_flashpage.h @@ -43,9 +43,7 @@ extern "C" .sector_count = FLASHPAGE_NUMOF, \ .pages_per_sector = _pages_per_sector, \ .page_size = FLASHPAGE_SIZE / _pages_per_sector, \ - .write_size = FLASHPAGE_WRITE_BLOCK_SIZE >= FLASHPAGE_WRITE_BLOCK_ALIGNMENT \ - ? FLASHPAGE_WRITE_BLOCK_SIZE \ - : FLASHPAGE_WRITE_BLOCK_ALIGNMENT, \ + .write_size = 1 \ }, \ } @@ -59,6 +57,9 @@ extern const mtd_desc_t mtd_flashpage_driver; */ typedef struct { mtd_dev_t base; /**< MTD generic device */ + uint32_t offset; /**< Offset in terms of MTD pages, which must comprise + a whole number of sectors from the start of the + flash */ } mtd_flashpage_t; #ifdef __cplusplus diff --git a/drivers/mtd_flashpage/mtd_flashpage.c b/drivers/mtd_flashpage/mtd_flashpage.c index 2bfc34789c28..553ea8a5e1a2 100644 --- a/drivers/mtd_flashpage/mtd_flashpage.c +++ b/drivers/mtd_flashpage/mtd_flashpage.c @@ -16,6 +16,8 @@ * @brief Implementation for the flashpage memory driver * * @author Vincent Dupont + * @author Benjamin Valentin + * @author Fabian Hüßler * @} */ @@ -26,23 +28,38 @@ #include "architecture.h" #include "cpu.h" #include "cpu_conf.h" +#include "macros/utils.h" #include "mtd_flashpage.h" #include "periph/flashpage.h" +#define ENABLE_DEBUG 0 +#include "debug.h" + #define MTD_FLASHPAGE_END_ADDR ((uint32_t) CPU_FLASH_BASE + (FLASHPAGE_NUMOF * FLASHPAGE_SIZE)) static int _init(mtd_dev_t *dev) { - (void)dev; + mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base); + (void)super; assert(dev->pages_per_sector * dev->page_size == FLASHPAGE_SIZE); + assert(!(super->offset % dev->pages_per_sector)); + + assert((int)flashpage_addr(super->offset / dev->pages_per_sector) >= (int)CPU_FLASH_BASE); + assert((uintptr_t)flashpage_addr(super->offset / dev->pages_per_sector) + + dev->pages_per_sector * dev->page_size * dev->sector_count <= MTD_FLASHPAGE_END_ADDR); + assert((uintptr_t)flashpage_addr(super->offset / dev->pages_per_sector) + + dev->pages_per_sector * dev->page_size * dev->sector_count > CPU_FLASH_BASE); return 0; } static int _read(mtd_dev_t *dev, void *buf, uint32_t addr, uint32_t size) { - assert(addr < MTD_FLASHPAGE_END_ADDR); + mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base); - (void)dev; + addr += (uintptr_t)flashpage_addr(super->offset); + + DEBUG("flashpage: read %"PRIu32" bytes from 0x%"PRIx32" to %p\n", size, addr, buf); + assert(addr < MTD_FLASHPAGE_END_ADDR); #ifndef CPU_HAS_UNALIGNED_ACCESS if (addr % sizeof(uword_t)) { @@ -56,9 +73,49 @@ static int _read(mtd_dev_t *dev, void *buf, uint32_t addr, uint32_t size) return 0; } +static int _read_page(mtd_dev_t *dev, void *buf, uint32_t page, + uint32_t offset, uint32_t size) +{ + mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base); + + assert(page + super->offset >= page); + page += super->offset; + + /* mtd flashpage maps multiple pages to one virtual sector for unknown reason */ + uint32_t fpage = page / dev->pages_per_sector; + offset += (page % dev->pages_per_sector) * dev->page_size; + uintptr_t addr = (uintptr_t)flashpage_addr(fpage); + + addr += offset; + + DEBUG("flashpage: read %"PRIu32" bytes from %p to %p\n", size, (void *)addr, buf); + +#ifndef CPU_HAS_UNALIGNED_ACCESS + if (addr % sizeof(uword_t)) { + uword_t tmp; + + offset = addr % sizeof(uword_t); + size = MIN(size, sizeof(uword_t) - offset); + + DEBUG("flashpage: read %"PRIu32" unaligned bytes\n", size); + + memcpy(&tmp, (uint8_t *)addr - offset, sizeof(tmp)); + memcpy(buf, (uint8_t *)&tmp + offset, size); + return size; + } +#endif + + memcpy(buf, (void *)addr, size); + return size; +} + static int _write(mtd_dev_t *dev, const void *buf, uint32_t addr, uint32_t size) { - (void)dev; + mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base); + + addr += (uintptr_t)flashpage_addr(super->offset); + + DEBUG("flashpage: write %"PRIu32" bytes from %p to 0x%"PRIx32"\n", size, buf, addr); #ifndef CPU_HAS_UNALIGNED_ACCESS if ((uintptr_t)buf % sizeof(uword_t)) { @@ -81,24 +138,63 @@ static int _write(mtd_dev_t *dev, const void *buf, uint32_t addr, uint32_t size) return 0; } -int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size) +static int _write_page(mtd_dev_t *dev, const void *buf, uint32_t page, uint32_t offset, + uint32_t size) { - size_t sector_size = dev->page_size * dev->pages_per_sector; + mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base); - if (size % sector_size) { - return -EOVERFLOW; - } - if (addr + size > MTD_FLASHPAGE_END_ADDR) { - return -EOVERFLOW; + assert(page + super->offset >= page); + + page += super->offset; + + /* mtd flashpage maps multiple pages to one virtual sector for unknown reason */ + uint32_t fpage = page / dev->pages_per_sector; + offset += (page % dev->pages_per_sector) * dev->page_size; + uintptr_t addr = (uintptr_t)flashpage_addr(fpage); + + addr += offset; + + DEBUG("flashpage: write %"PRIu32" bytes from %p to %p\n", size, buf, (void *)addr); + + size = MIN(flashpage_size(fpage) - offset, size); + + if ((addr % FLASHPAGE_WRITE_BLOCK_ALIGNMENT) || (size < FLASHPAGE_WRITE_BLOCK_SIZE) || + ((uintptr_t)buf % FLASHPAGE_WRITE_BLOCK_ALIGNMENT)) { + uint8_t tmp[FLASHPAGE_WRITE_BLOCK_SIZE] + __attribute__ ((aligned (FLASHPAGE_WRITE_BLOCK_ALIGNMENT))); + + offset = addr % FLASHPAGE_WRITE_BLOCK_ALIGNMENT; + size = MIN(size, FLASHPAGE_WRITE_BLOCK_ALIGNMENT - offset); + + DEBUG("flashpage: write %"PRIu32" unaligned bytes\n", size); + + memcpy(&tmp[0], (uint8_t *)addr - offset, sizeof(tmp)); + memcpy(&tmp[offset], buf, size); + + flashpage_write((uint8_t *)addr - offset, tmp, sizeof(tmp)); + + return size; } - if (addr % sector_size) { + + /* don't write less than the write block size */ + size &= ~(FLASHPAGE_WRITE_BLOCK_SIZE - 1); + + flashpage_write((void *)addr, buf, size); + return size; +} + +static int _erase_sector(mtd_dev_t *dev, uint32_t sector, uint32_t count) +{ + mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base); + + if (sector + (super->offset / dev->pages_per_sector) < sector) { return -EOVERFLOW; } + sector += (super->offset / dev->pages_per_sector); - uword_t dst_addr = addr; - - for (size_t i = 0; i < size; i += sector_size) { - flashpage_erase(flashpage_page((void *)(dst_addr + i))); + while (count--) { + DEBUG("flashpage: erase sector %"PRIu32"\n", sector); + flashpage_erase(sector++); } return 0; @@ -107,6 +203,8 @@ int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size) const mtd_desc_t mtd_flashpage_driver = { .init = _init, .read = _read, + .read_page = _read_page, .write = _write, - .erase = _erase, + .write_page = _write_page, + .erase_sector = _erase_sector, }; From 68694a0da28f0d854c5d6ac65ac3e75e0a3b8bea Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 7 Feb 2023 17:48:53 +0100 Subject: [PATCH 2/5] tests/mtd_flashpage: adapt to mtd_flashpage API change --- tests/mtd_flashpage/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/mtd_flashpage/main.c b/tests/mtd_flashpage/main.c index ed95100d406b..ceaa754a9b78 100644 --- a/tests/mtd_flashpage/main.c +++ b/tests/mtd_flashpage/main.c @@ -28,13 +28,13 @@ #endif #if (__SIZEOF_POINTER__ == 2) -#define TEST_ADDRESS1 (uint16_t)flashpage_addr(LAST_AVAILABLE_PAGE) -#define TEST_ADDRESS2 (uint16_t)flashpage_addr(LAST_AVAILABLE_PAGE - 1) +#define TEST_ADDRESS1 (uint16_t)((uintptr_t)flashpage_addr(LAST_AVAILABLE_PAGE) - (uintptr_t)CPU_FLASH_BASE) +#define TEST_ADDRESS2 (uint16_t)((uintptr_t)flashpage_addr(LAST_AVAILABLE_PAGE - 1) - (uintptr_t)CPU_FLASH_BASE) #else -#define TEST_ADDRESS1 (uint32_t)flashpage_addr(LAST_AVAILABLE_PAGE) -#define TEST_ADDRESS2 (uint32_t)flashpage_addr(LAST_AVAILABLE_PAGE - 1) +#define TEST_ADDRESS1 (uint32_t)((uintptr_t)flashpage_addr(LAST_AVAILABLE_PAGE) - (uintptr_t)CPU_FLASH_BASE) +#define TEST_ADDRESS2 (uint32_t)((uintptr_t)flashpage_addr(LAST_AVAILABLE_PAGE - 1) - (uintptr_t)CPU_FLASH_BASE) #endif -#define TEST_ADDRESS0 (FLASHPAGE_NUMOF - 1) +#define TEST_ADDRESS0 ((FLASHPAGE_NUMOF - 1) - flashpage_page((void *)CPU_FLASH_BASE)) static mtd_flashpage_t _dev = MTD_FLASHPAGE_INIT_VAL(8); static mtd_dev_t *dev = &_dev.base; From d8ab11b51fb333e6a5ccf2c24ebe944f4f7ffa69 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 9 Feb 2023 14:27:25 +0100 Subject: [PATCH 3/5] drivers/mtd_flashpage: drop legacy API --- drivers/mtd_flashpage/mtd_flashpage.c | 52 --------------------------- 1 file changed, 52 deletions(-) diff --git a/drivers/mtd_flashpage/mtd_flashpage.c b/drivers/mtd_flashpage/mtd_flashpage.c index 553ea8a5e1a2..68d40688ff35 100644 --- a/drivers/mtd_flashpage/mtd_flashpage.c +++ b/drivers/mtd_flashpage/mtd_flashpage.c @@ -52,27 +52,6 @@ static int _init(mtd_dev_t *dev) return 0; } -static int _read(mtd_dev_t *dev, void *buf, uint32_t addr, uint32_t size) -{ - mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base); - - addr += (uintptr_t)flashpage_addr(super->offset); - - DEBUG("flashpage: read %"PRIu32" bytes from 0x%"PRIx32" to %p\n", size, addr, buf); - assert(addr < MTD_FLASHPAGE_END_ADDR); - -#ifndef CPU_HAS_UNALIGNED_ACCESS - if (addr % sizeof(uword_t)) { - return -EINVAL; - } -#endif - - uword_t dst_addr = addr; - memcpy(buf, (void *)dst_addr, size); - - return 0; -} - static int _read_page(mtd_dev_t *dev, void *buf, uint32_t page, uint32_t offset, uint32_t size) { @@ -109,35 +88,6 @@ static int _read_page(mtd_dev_t *dev, void *buf, uint32_t page, return size; } -static int _write(mtd_dev_t *dev, const void *buf, uint32_t addr, uint32_t size) -{ - mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base); - - addr += (uintptr_t)flashpage_addr(super->offset); - - DEBUG("flashpage: write %"PRIu32" bytes from %p to 0x%"PRIx32"\n", size, buf, addr); - -#ifndef CPU_HAS_UNALIGNED_ACCESS - if ((uintptr_t)buf % sizeof(uword_t)) { - return -EINVAL; - } -#endif - if (addr % FLASHPAGE_WRITE_BLOCK_ALIGNMENT) { - return -EINVAL; - } - if (size % FLASHPAGE_WRITE_BLOCK_SIZE) { - return -EOVERFLOW; - } - if (addr + size > MTD_FLASHPAGE_END_ADDR) { - return -EOVERFLOW; - } - - uword_t dst_addr = addr; - flashpage_write((void *)dst_addr, buf, size); - - return 0; -} - static int _write_page(mtd_dev_t *dev, const void *buf, uint32_t page, uint32_t offset, uint32_t size) { @@ -202,9 +152,7 @@ static int _erase_sector(mtd_dev_t *dev, uint32_t sector, uint32_t count) const mtd_desc_t mtd_flashpage_driver = { .init = _init, - .read = _read, .read_page = _read_page, - .write = _write, .write_page = _write_page, .erase_sector = _erase_sector, }; From 8e902bdf5da024db6a4db88a8d41ae17ea564696 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 9 Feb 2023 14:29:58 +0100 Subject: [PATCH 4/5] tests/mtd_flashpage: test unaligned read/write --- tests/mtd_flashpage/Makefile | 1 + tests/mtd_flashpage/app.config.test | 1 + tests/mtd_flashpage/main.c | 87 ++++++++++++++++++++++++++--- 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/tests/mtd_flashpage/Makefile b/tests/mtd_flashpage/Makefile index 4ebfdfb69b56..ed285b46f21f 100644 --- a/tests/mtd_flashpage/Makefile +++ b/tests/mtd_flashpage/Makefile @@ -1,6 +1,7 @@ include ../Makefile.tests_common USEMODULE += mtd_flashpage +USEMODULE += mtd_write_page USEMODULE += embunit include $(RIOTBASE)/Makefile.include diff --git a/tests/mtd_flashpage/app.config.test b/tests/mtd_flashpage/app.config.test index f8017426431a..54af22faabb2 100644 --- a/tests/mtd_flashpage/app.config.test +++ b/tests/mtd_flashpage/app.config.test @@ -2,4 +2,5 @@ # application configuration. This is only needed during migration. CONFIG_MODULE_MTD=y CONFIG_MODULE_MTD_FLASHPAGE=y +CONFIG_MODULE_MTD_WRITE_PAGE=y CONFIG_MODULE_EMBUNIT=y diff --git a/tests/mtd_flashpage/main.c b/tests/mtd_flashpage/main.c index ceaa754a9b78..1ed470252ba1 100644 --- a/tests/mtd_flashpage/main.c +++ b/tests/mtd_flashpage/main.c @@ -34,9 +34,12 @@ #define TEST_ADDRESS1 (uint32_t)((uintptr_t)flashpage_addr(LAST_AVAILABLE_PAGE) - (uintptr_t)CPU_FLASH_BASE) #define TEST_ADDRESS2 (uint32_t)((uintptr_t)flashpage_addr(LAST_AVAILABLE_PAGE - 1) - (uintptr_t)CPU_FLASH_BASE) #endif -#define TEST_ADDRESS0 ((FLASHPAGE_NUMOF - 1) - flashpage_page((void *)CPU_FLASH_BASE)) +/* Address of last flash page and not last available flashpage */ +#define TEST_ADDRESS0 (uint32_t)((uintptr_t)flashpage_addr((FLASHPAGE_NUMOF - 1)) - (uintptr_t)CPU_FLASH_BASE) -static mtd_flashpage_t _dev = MTD_FLASHPAGE_INIT_VAL(8); +#define PAGES_PER_SECTOR 8 + +static mtd_flashpage_t _dev = MTD_FLASHPAGE_INIT_VAL(PAGES_PER_SECTOR); static mtd_dev_t *dev = &_dev.base; static void setup(void) @@ -134,14 +137,83 @@ static void test_mtd_write_read(void) ret = mtd_erase(dev, TEST_ADDRESS1, dev->pages_per_sector * dev->page_size); TEST_ASSERT_EQUAL_INT(0, ret); + /* Out of bounds read */ + ret = mtd_read(dev, buf_read, TEST_ADDRESS0 + FLASHPAGE_SIZE - 1, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); + + /* Out of bounds write */ + ret = mtd_write(dev, buf, TEST_ADDRESS0 + FLASHPAGE_SIZE - 1, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); + /* Unaligned write / read */ - ret = mtd_write(dev, buf, TEST_ADDRESS1 + sizeof(buf_empty), sizeof(buf)); - TEST_ASSERT_EQUAL_INT(-EINVAL, ret); + ret = mtd_write(dev, &buf[1], TEST_ADDRESS1 + sizeof(buf_empty), sizeof(buf) - 1); + TEST_ASSERT_EQUAL_INT(0, ret); /* Only Cortex-M0 doesn't allow unaligned reads */ -#if defined(CPU_CORE_CORTEX_M0) - ret = mtd_read(dev, buf_read, TEST_ADDRESS1 + sizeof(buf_empty), sizeof(buf_read)); - TEST_ASSERT_EQUAL_INT(-EINVAL, ret); + ret = mtd_read(dev, &buf_read[1], TEST_ADDRESS1 + sizeof(buf_empty), sizeof(buf_read) - 1); + TEST_ASSERT_EQUAL_INT(0, ret); +} + +static void test_mtd_write_read_page(void) +{ +#ifdef MODULE_MTD_WRITE_PAGE + const char buf[] __attribute__ ((aligned (FLASHPAGE_WRITE_BLOCK_ALIGNMENT))) + = "abcdefghijklmno"; + + uint8_t buf_empty[3]; + memset(buf_empty, FLASHPAGE_ERASE_STATE, sizeof(buf_empty)); + char buf_read[sizeof(buf) + sizeof(buf_empty)]; + memset(buf_read, 0, sizeof(buf_read)); + int ret; + /* convert last flash page to MTD page */ + uint32_t last_vpage = LAST_AVAILABLE_PAGE * dev->pages_per_sector; + size_t vpage_size = dev->page_size; + + /* write to the beginning of last available page */ + ret = mtd_write_page(dev, buf, last_vpage, 0, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(0, ret); + + /* read back data from which some is erased */ + ret = mtd_read_page(dev, buf_read, last_vpage, 0, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(0, ret); + TEST_ASSERT_EQUAL_INT(0, memcmp(buf, buf_read, sizeof(buf))); + TEST_ASSERT_EQUAL_INT(0, memcmp(buf_empty, buf_read + sizeof(buf), sizeof(buf_empty))); + + /* clean */ + ret = mtd_erase_sector(dev, LAST_AVAILABLE_PAGE, 1); + + /* write to the beginning of the MTD page before the last available flash page */ + ret = mtd_write_page(dev, buf, last_vpage - 1, 0, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(0, ret); + + /* read back data from which some is erased */ + ret = mtd_read_page(dev, buf_read, last_vpage - 1, 0, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(0, ret); + TEST_ASSERT_EQUAL_INT(0, memcmp(buf, buf_read, sizeof(buf))); + TEST_ASSERT_EQUAL_INT(0, memcmp(buf_empty, buf_read + sizeof(buf), sizeof(buf_empty))); + + /* clean*/ + ret = mtd_erase_sector(dev, LAST_AVAILABLE_PAGE, 1); + + /* write across flash page boundary */ + ret = mtd_write_page(dev, buf, last_vpage - 1, vpage_size - sizeof(buf) + 1, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(0, ret); + + /* read back data from which some is erased */ + ret = mtd_read_page(dev, buf_read, last_vpage - 1, vpage_size - sizeof(buf) + 1, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(0, ret); + TEST_ASSERT_EQUAL_INT(0, memcmp(buf, buf_read, sizeof(buf))); + TEST_ASSERT_EQUAL_INT(0, memcmp(buf_empty, buf_read + sizeof(buf), sizeof(buf_empty))); + + /* Out of bounds read */ + ret = mtd_read_page(dev, buf_read, + FLASHPAGE_NUMOF * dev->pages_per_sector, 0, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); + + /* Out of bounds write */ + ret = mtd_write_page(dev, buf, + FLASHPAGE_NUMOF * dev->pages_per_sector, 0, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); #endif } @@ -152,6 +224,7 @@ Test *tests_mtd_flashpage_tests(void) new_TestFixture(test_mtd_erase), new_TestFixture(test_mtd_write_erase), new_TestFixture(test_mtd_write_read), + new_TestFixture(test_mtd_write_read_page), }; EMB_UNIT_TESTCALLER(mtd_flashpage_tests, setup, teardown, fixtures); From 43fffcd74f83a329dc279472c15f5a20116fdb83 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 15 Feb 2023 00:11:17 +0100 Subject: [PATCH 5/5] drivers/mtd: add bounds checking --- drivers/mtd/mtd.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtd.c b/drivers/mtd/mtd.c index 030b3f8fba84..b1728f5283a6 100644 --- a/drivers/mtd/mtd.c +++ b/drivers/mtd/mtd.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,23 @@ #include "bitarithm.h" #include "mtd.h" +static bool out_of_bounds(mtd_dev_t *mtd, uint32_t page, uint32_t offset, uint32_t len) +{ + const uint32_t page_shift = bitarithm_msb(mtd->page_size); + const uint32_t pages_numof = mtd->sector_count * mtd->pages_per_sector; + + /* 2 TiB SD cards might be a problem */ + assert(pages_numof >= mtd->sector_count); + + /* read n byte buffer -> last byte will be at n - 1 */ + page += (offset + len - 1) >> page_shift; + if (page >= pages_numof) { + return true; + } + + return false; +} + int mtd_init(mtd_dev_t *mtd) { if (!mtd || !mtd->driver) { @@ -70,6 +88,10 @@ int mtd_read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t count) return -ENODEV; } + if (out_of_bounds(mtd, 0, addr, count)) { + return -EOVERFLOW; + } + if (mtd->driver->read) { return mtd->driver->read(mtd, dest, addr, count); } @@ -88,6 +110,10 @@ int mtd_read_page(mtd_dev_t *mtd, void *dest, uint32_t page, uint32_t offset, return -ENODEV; } + if (out_of_bounds(mtd, page, offset, count)) { + return -EOVERFLOW; + } + if (mtd->driver->read_page == NULL) { /* TODO: remove when all backends implement read_page */ if (mtd->driver->read) { @@ -139,6 +165,10 @@ int mtd_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uint32_t count) return -ENODEV; } + if (out_of_bounds(mtd, 0, addr, count)) { + return -EOVERFLOW; + } + if (mtd->driver->write) { return mtd->driver->write(mtd, src, addr, count); } @@ -214,6 +244,10 @@ int mtd_write_page(mtd_dev_t *mtd, const void *data, uint32_t page, return -ENODEV; } + if (out_of_bounds(mtd, page, offset, len)) { + return -EOVERFLOW; + } + if (mtd->driver->flags & MTD_DRIVER_FLAG_DIRECT_WRITE) { return mtd_write_page_raw(mtd, data, page, offset, len); } @@ -247,6 +281,10 @@ int mtd_write_page_raw(mtd_dev_t *mtd, const void *src, uint32_t page, uint32_t return -ENODEV; } + if (out_of_bounds(mtd, page, offset, count)) { + return -EOVERFLOW; + } + if (mtd->driver->write_page == NULL) { /* TODO: remove when all backends implement write_page */ if (mtd->driver->write) { @@ -321,7 +359,11 @@ int mtd_erase_sector(mtd_dev_t *mtd, uint32_t sector, uint32_t count) return -ENODEV; } - if (sector >= mtd->sector_count) { + if (sector + count > mtd->sector_count) { + return -EOVERFLOW; + } + + if (sector + count < sector) { return -EOVERFLOW; }