Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions drivers/flash/flash_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ static inline int z_vrfy_flash_get_size(const struct device *dev, uint64_t *size
}
#include <zephyr/syscalls/flash_get_size_mrsh.c>

static inline int z_vrfy_flash_mmap(const struct device *dev, void **base,
uint64_t *size, uint32_t flags)
{
K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH));
K_OOPS(K_SYSCALL_MEMORY_READ(*base, sizeof(*base)));
K_OOPS(K_SYSCALL_MEMORY_WRITE(*base, sizeof(*base)));
K_OOPS(K_SYSCALL_MEMORY_READ(size, sizeof(*size)));
K_OOPS(K_SYSCALL_MEMORY_WRITE(size, sizeof(*size)));
return z_impl_flash_mmap((const struct device *)dev, base, size, flags);
}
#include <zephyr/syscalls/flash_mmap_mrsh.c>

static inline size_t z_vrfy_flash_get_write_block_size(const struct device *dev)
{
K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_FLASH));
Expand Down
17 changes: 17 additions & 0 deletions drivers/flash/flash_simulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,22 @@ static int flash_sim_get_size(const struct device *dev, uint64_t *size)

return 0;
}

static int flash_sim_mmap(const struct device *dev, void **base, uint64_t *size,
uint32_t flags)
{
ARG_UNUSED(dev);

if (flags & ~(FLASH_MMAP_F_READ | FLASH_MMAP_F_WRITE)) {
return -EINVAL;
}

*base = (void *)&mock_flash[0];
*size = (uint64_t)FLASH_SIMULATOR_FLASH_SIZE;

return 0;
}

static const struct flash_parameters *
flash_sim_get_parameters(const struct device *dev)
{
Expand All @@ -384,6 +400,7 @@ static DEVICE_API(flash, flash_sim_api) = {
.read = flash_sim_read,
.write = flash_sim_write,
.erase = flash_sim_erase,
.mmap = flash_sim_mmap,
.get_parameters = flash_sim_get_parameters,
.get_size = flash_sim_get_size,
#ifdef CONFIG_FLASH_PAGE_LAYOUT
Expand Down
15 changes: 15 additions & 0 deletions drivers/flash/soc_flash_nrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,20 @@ static int flash_nrf_get_size(const struct device *dev, uint64_t *size)
return 0;
}

static int flash_nrf_mmap(const struct device *dev, void **base, uint64_t *size,
uint32_t flags)
{
/* Currently supporting read operation only */
if (flags & ~(FLASH_MMAP_F_READ)) {
return -EINVAL;
}

*base = (void *)DT_REG_ADDR(SOC_NV_FLASH_NODE);
*size = nrfx_nvmc_flash_size_get();

return 0;
}

#if defined(CONFIG_FLASH_PAGE_LAYOUT)
static struct flash_pages_layout dev_layout;

Expand All @@ -294,6 +308,7 @@ static DEVICE_API(flash, flash_nrf_api) = {
.read = flash_nrf_read,
.write = flash_nrf_write,
.erase = flash_nrf_erase,
.mmap = flash_nrf_mmap,
.get_parameters = flash_nrf_get_parameters,
.get_size = flash_nrf_get_size,
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
Expand Down
60 changes: 60 additions & 0 deletions include/zephyr/drivers/flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ typedef int (*flash_api_get_size)(const struct device *dev, uint64_t *size);

typedef const struct flash_parameters* (*flash_api_get_parameters)(const struct device *dev);

/**
* @brief Get device mapping to processor address space.
*
* When supported by driver this function will try to map device to MPU address
* space, either to default memory address or to requeste one.
*/
typedef int (*flash_api_mmap)(const struct device *dev, void **base, uint64_t *size,
uint32_t flags);

#if defined(CONFIG_FLASH_PAGE_LAYOUT)
/**
* @brief Retrieve a flash device's layout.
Expand Down Expand Up @@ -208,6 +217,7 @@ __subsystem struct flash_driver_api {
flash_api_erase erase;
flash_api_get_parameters get_parameters;
flash_api_get_size get_size;
flash_api_mmap mmap;
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
flash_api_pages_layout page_layout;
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
Expand Down Expand Up @@ -334,6 +344,56 @@ static inline int z_impl_flash_erase(const struct device *dev, off_t offset,
return rc;
}

/** Map at custom address */
#define FLASH_MMAP_F_CUSTOM_ADDR BIT(0)
/** Map for read */
#define FLASH_MMAP_F_READ BIT(1)
/** Map for write */
#define FLASH_MMAP_F_WRITE BIT(2)

/**
* @brief Get device mapping to processor address space
*
* Function returns base address for memory mapping of device to address space
* and size of the device mapped. Internal SoC memory and some XIP memories
* may be addressable through the same address space as device RAM, which allows
* data transfers via memcpy or direct access to storage by casting address
* range to data structures.
* Not all processors may support the feature and its usage should be well
* tested in user code, because while, for example, flash_read would return
* -EINVAL error in case when attempting read out of device range, directly
* accessing memory beyond given range may invoke CPU fault.
*
* @param dev device to get mapping for
* @param base pointer to void pointer for memory address, in case when
* FLASH_MMAP_CUSTOM_ADDR flag is set this is also read as desired
* address to map device to.
* @param size pointer to variable where device size will be reported.
* @param flags flags describing desired access and mapping.
*
* @return 0 on success, -ENOTSUP when driver does not support mapping,
* -EINVAL in case, when selected flags are not supported.
*/

__syscall int flash_mmap(const struct device *dev, void **base, uint64_t *size,
uint32_t flags);

static inline int z_impl_flash_mmap(const struct device *dev, void **base,
uint64_t *size, uint32_t flags)
{
int rc = -ENOSYS;

const struct flash_driver_api *api =
(const struct flash_driver_api *)dev->api;

if (api->mmap != NULL) {
rc = api->mmap(dev, base, size, flags);
}

return rc;
}


/**
* @brief Get device size in bytes.
*
Expand Down
19 changes: 19 additions & 0 deletions tests/drivers/flash/common/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,25 @@ ZTEST(flash_driver, test_flash_erase)
zassert_not_equal(expected[0], erase_value, "These values shall be different");
}

ZTEST(flash_driver, test_mmap)
{
int rc;
uint64_t size;
uint8_t *p;

rc = flash_mmap(flash_dev, (void **)&p, &size, FLASH_MMAP_F_READ);
if (rc == -ENOTSUP || rc == -ENOSYS) {
ztest_test_skip();
} else {
const static uint8_t out[] = "Hello World!!!\n";
struct flash_pages_info fp;

zassert_ok(flash_get_page_info_by_offs(flash_dev, size - 1, &fp));
zassert_ok(flash_erase(flash_dev, fp.start_offset, fp.size));
zassert_ok(flash_write(flash_dev, fp.start_offset, out, sizeof(out)));
zassert_ok(memcmp(p + fp.start_offset, out, sizeof(out)));
}
}
struct test_cb_data_type {
uint32_t page_counter; /* used to count how many pages was iterated */
uint32_t exit_page; /* terminate iteration when this page is reached */
Expand Down
92 changes: 84 additions & 8 deletions tests/drivers/flash_api/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ static struct {
int ret;
/* Some size */
uint64_t size;
/* Device mmap test values */
void *mmap_base;
ssize_t mmap_size;
uint32_t mmap_flags;
} simulated_values = {
.ret = 0,
.size = 0,
};

/*** Device definition atd == API Test Dev ***/
/*** Device definition of API pseudo functions **/
static int some_get_size(const struct device *dev, uint64_t *size)
{
__ASSERT_NO_MSG(dev != NULL);
Expand All @@ -42,21 +46,53 @@ static int enotsup_get_size(const struct device *dev, uint64_t *size)
return -ENOTSUP;
}

static int some_mmap(const struct device *dev, void **base, uint64_t *size,
uint32_t flags)
{
__ASSERT_NO_MSG(dev != NULL);

if (flags != simulated_values.mmap_flags) {
return -EINVAL;
}

if (base == NULL || size == NULL) {
return -EINVAL;
}

*base = simulated_values.mmap_base;
*size = simulated_values.mmap_size;

return 0;
}

static int enotsup_mmap(const struct device *dev, void **base, uint64_t *size,
uint32_t flags)
{
ARG_UNUSED(dev);
ARG_UNUSED(base);
ARG_UNUSED(size);
ARG_UNUSED(flags);

return 0;
}

/** Device objects **/
/* The device state, just to make it "ready" device */
static struct device_state some_dev_state = {
.init_res = 0,
.initialized = 1,
};

/* Device with get_size */
static DEVICE_API(flash, size_fun_api) = {
/* Device with implemented api calls */
static DEVICE_API(flash, some_fun_api) = {
.get_size = some_get_size,
.mmap = some_mmap,
};
const static struct device size_fun_dev = {
"get_size",

const static struct device some_fun_dev = {
"some_fun",
NULL,
&size_fun_api,
&some_fun_api,
&some_dev_state,
};

Expand All @@ -72,6 +108,7 @@ const static struct device no_fun_dev = {
/* Device with get_size implemented but returning -ENOTSUP */
static DEVICE_API(flash, enotsup_fun_api) = {
.get_size = enotsup_get_size,
.mmap = enotsup_mmap,
};
static struct device enotsup_fun_dev = {
"enotsup",
Expand All @@ -85,14 +122,53 @@ ZTEST(flash_api, test_get_size)
uint64_t size = 0;

simulated_values.size = 45;
zassert_ok(flash_get_size(&size_fun_dev, &size), "Expected success");
zassert_ok(flash_get_size(&some_fun_dev, &size), "Expected success");
zassert_equal(size, simulated_values.size, "Size mismatch");
simulated_values.size = 46;
zassert_ok(flash_get_size(&size_fun_dev, &size), "Expected success");
zassert_ok(flash_get_size(&some_fun_dev, &size), "Expected success");
zassert_equal(size, simulated_values.size, "Size mismatch");
zassert_equal(flash_get_size(&no_fun_dev, &size), -ENOSYS);

zassert_equal(flash_get_size(&enotsup_fun_dev, &size), -ENOTSUP);
}


ZTEST(flash_api, test_flash_mmap)
{
void *base = NULL;
uint64_t size = 0;

simulated_values.mmap_size = 40;
/* Just need some pointer */
simulated_values.mmap_base = (void *)&simulated_values;
/* 0 for error tests */
simulated_values.mmap_flags = 0;

zassert_equal(flash_mmap(&some_fun_dev, NULL, NULL, 0), -EINVAL);
zassert_equal(flash_mmap(&some_fun_dev, &base, NULL, 0), -EINVAL);
zassert_equal(flash_mmap(&some_fun_dev, NULL, &size, 0), -EINVAL);
zassert_equal(flash_mmap(&some_fun_dev, &base, &size, FLASH_MMAP_F_READ), -EINVAL);
zassert_equal(flash_mmap(&some_fun_dev, &base, &size, FLASH_MMAP_F_WRITE), -EINVAL);
zassert_equal(flash_mmap(&some_fun_dev, &base, &size,
FLASH_MMAP_F_READ | FLASH_MMAP_F_WRITE), -EINVAL);

simulated_values.mmap_flags = FLASH_MMAP_F_READ;
zassert_equal(flash_mmap(&some_fun_dev, &base, &size, FLASH_MMAP_F_WRITE), -EINVAL);

simulated_values.mmap_flags = FLASH_MMAP_F_WRITE;
zassert_equal(flash_mmap(&some_fun_dev, &base, &size, FLASH_MMAP_F_READ), -EINVAL);

zassert_equal(flash_get_size(&enotsup_fun_dev, &size), -ENOTSUP);

/* After all failures the base and size are expected to be not modified */
zassert_equal(base, NULL);
zassert_equal(size, 0);

simulated_values.mmap_flags = FLASH_MMAP_F_READ;
zassert_ok(flash_mmap(&some_fun_dev, &base, &size, FLASH_MMAP_F_READ));
/* Expected values to be read by API and updated */
zassert_equal(base, simulated_values.mmap_base);
zassert_equal(size, simulated_values.mmap_size);
}

ZTEST_SUITE(flash_api, NULL, NULL, NULL, NULL, NULL);
4 changes: 4 additions & 0 deletions tests/drivers/flash_api/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@ tests:
- driver
- flash
- userspace
platform_allow:
- nrf52840dk/nrf52840
integration_platforms:
- nrf52840dk/nrf52840
extra_configs:
- CONFIG_USERSPACE=y
47 changes: 47 additions & 0 deletions tests/drivers/flash_simulator/flash_sim_impl/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,53 @@ ZTEST(flash_sim_api, test_flash_fill)
}
}

ZTEST(flash_sim_api, test_flash_mmap)
{
const uint8_t out[] = "Hello world!!!\n";
uint8_t in[64];
uint8_t *p;
uint64_t size;
int rc;
#if defined(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
rc = flash_erase(flash_dev, FLASH_SIMULATOR_BASE_OFFSET,
FLASH_SIMULATOR_FLASH_SIZE);
zassert_equal(0, rc, "flash_erase should succeed");
#else
rc = flash_fill(flash_dev, FLASH_SIMULATOR_ERASE_VALUE,
FLASH_SIMULATOR_BASE_OFFSET,
FLASH_SIMULATOR_FLASH_SIZE);
zassert_equal(0, rc, "flash_fill should succeed");
#endif
zassert_ok(flash_mmap(flash_dev, (void **)&p, &size, FLASH_MMAP_F_READ));
zassert_ok(flash_write(flash_dev, FLASH_SIMULATOR_BASE_OFFSET, out,
sizeof(out)));

zassert_ok(memcmp(p, out, sizeof(out)));

zassert_ok(flash_read(flash_dev, FLASH_SIMULATOR_BASE_OFFSET, in,
sizeof(out)));
zassert_ok(memcmp(out, in, sizeof(out)));

#if defined(CONFIG_FLASH_SIMULATOR_EXPLICIT_ERASE)
rc = flash_erase(flash_dev, FLASH_SIMULATOR_BASE_OFFSET,
FLASH_SIMULATOR_FLASH_SIZE);
zassert_equal(0, rc, "flash_erase should succeed");
#else
rc = flash_fill(flash_dev, FLASH_SIMULATOR_ERASE_VALUE,
FLASH_SIMULATOR_BASE_OFFSET,
FLASH_SIMULATOR_FLASH_SIZE);
zassert_equal(0, rc, "flash_fill should succeed");
#endif
zassert_ok(flash_mmap(flash_dev, (void **)&p, &size, FLASH_MMAP_F_WRITE));
memset(in, 0, sizeof(in));
/* Write via memcpy */
memcpy(p, out, sizeof(out));
zassert_ok(memcmp(p, out, sizeof(out)));
zassert_ok(flash_read(flash_dev, FLASH_SIMULATOR_BASE_OFFSET, in,
sizeof(out)));
zassert_ok(memcmp(out, in, sizeof(out)));
}

ZTEST(flash_sim_api, test_flash_flatten)
{
int rc;
Expand Down
Loading