mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
217 lines
5.0 KiB
C
217 lines
5.0 KiB
C
/*
|
|
* Copyright (C) 2023 Gunar Schorcht
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include "assert.h"
|
|
#include "macros/utils.h"
|
|
#include "mtd_emulated.h"
|
|
|
|
static int _init(mtd_dev_t *dev)
|
|
{
|
|
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
|
|
|
assert(mtd);
|
|
|
|
if (!mtd->init_done) {
|
|
memset(mtd->memory, 0xff, mtd->size);
|
|
mtd->init_done = true;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int _read(mtd_dev_t *dev, void *dest, uint32_t addr, uint32_t count)
|
|
{
|
|
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
|
|
|
assert(mtd);
|
|
assert(dest);
|
|
|
|
uint32_t addr_count;
|
|
|
|
if (__builtin_add_overflow(addr, count, &addr_count)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
if (addr_count > mtd->size) {
|
|
/* addr + count must not exceed the size of memory */
|
|
return -EOVERFLOW;
|
|
}
|
|
memcpy(dest, mtd->memory + addr, count);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _read_page(mtd_dev_t *dev, void *dest,
|
|
uint32_t page, uint32_t offset, uint32_t size)
|
|
{
|
|
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
|
|
|
(void)mtd;
|
|
|
|
assert(mtd);
|
|
assert(dest);
|
|
|
|
uint32_t page_addr;
|
|
|
|
if (__builtin_mul_overflow(page, mtd->base.page_size, &page_addr)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
uint32_t offset_size;
|
|
|
|
if (__builtin_add_overflow(offset, size, &offset_size)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
uint32_t page_addr_offset_size;
|
|
|
|
if (__builtin_add_overflow(page_addr, offset_size, &page_addr_offset_size)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
if (page_addr_offset_size > mtd->size) {
|
|
/* page addr + offset + size must not exceed the size of memory */
|
|
return -EOVERFLOW;
|
|
}
|
|
memcpy(dest, mtd->memory + page_addr + offset, size);
|
|
|
|
return size;
|
|
}
|
|
|
|
int _write_page(mtd_dev_t *dev, const void *src,
|
|
uint32_t page, uint32_t offset, uint32_t size)
|
|
{
|
|
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
|
|
|
(void)mtd;
|
|
|
|
assert(mtd);
|
|
assert(src);
|
|
|
|
if (offset >= mtd->base.page_size) {
|
|
/* offset must be smaller than the page size */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
uint32_t page_addr;
|
|
|
|
if (__builtin_mul_overflow(page, mtd->base.page_size, &page_addr)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
uint32_t offset_size;
|
|
|
|
if (__builtin_add_overflow(offset, size, &offset_size)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
uint32_t page_addr_offset_size;
|
|
|
|
if (__builtin_add_overflow(page_addr, offset_size, &page_addr_offset_size)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
if (page_addr_offset_size > mtd->size) {
|
|
/* page addr + offset + size must not exceed the size of memory */
|
|
return -EOVERFLOW;
|
|
}
|
|
memcpy(mtd->memory + page_addr + offset, src, size);
|
|
|
|
return size;
|
|
}
|
|
|
|
static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t count)
|
|
{
|
|
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
|
|
|
(void)mtd;
|
|
assert(mtd);
|
|
|
|
uint32_t addr_count;
|
|
|
|
if (__builtin_add_overflow(addr, count, &addr_count)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
if (addr % (mtd->base.pages_per_sector * mtd->base.page_size) != 0) {
|
|
/* addr must be aligned on a sector boundary */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
if (count % (mtd->base.pages_per_sector * mtd->base.page_size) != 0) {
|
|
/* count must be a multiple of a sector size. */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
if (addr_count > mtd->size) {
|
|
/* addr + count must not exceed the size of memory */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
memset(mtd->memory + addr, 0xff, count);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _erase_sector(mtd_dev_t *dev, uint32_t sector, uint32_t num)
|
|
{
|
|
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
|
|
|
|
(void)mtd;
|
|
assert(mtd);
|
|
|
|
uint32_t sector_num;
|
|
|
|
if (__builtin_add_overflow(sector, num, §or_num)) {
|
|
/* check for integer overflow */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
if (sector >= mtd->base.sector_count) {
|
|
/* sector must not exceed the number of sectors */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
if (sector_num > mtd->base.sector_count) {
|
|
/* sector + num must not exceed the number of sectors */
|
|
return -EOVERFLOW;
|
|
}
|
|
|
|
memset(mtd->memory + (sector * (mtd->base.pages_per_sector * mtd->base.page_size)),
|
|
0xff, num * (mtd->base.pages_per_sector * mtd->base.page_size));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _power(mtd_dev_t *dev, enum mtd_power_state power)
|
|
{
|
|
(void)dev;
|
|
(void)power;
|
|
return 0;
|
|
}
|
|
|
|
const mtd_desc_t _mtd_emulated_driver = {
|
|
.init = _init,
|
|
.read = _read,
|
|
.read_page = _read_page,
|
|
.write_page = _write_page,
|
|
.erase = _erase,
|
|
.erase_sector = _erase_sector,
|
|
.power = _power,
|
|
};
|