drivers: flash: Added native POSIX flash driver

Added native POSIX flash driver that writes flash content to a binary
file.

Signed-off-by: Jan Van Winkel <jan.van_winkel@dxplore.eu>
This commit is contained in:
Jan Van Winkel 2019-01-01 17:07:58 +01:00 committed by Anas Nashif
parent 7a246c30bd
commit 88964b99ec
7 changed files with 293 additions and 1 deletions

View file

@ -115,6 +115,7 @@
/drivers/dma/*sam0* @Sizurka
/drivers/ethernet/ @jukkar @tbursztyka @pfalcon
/drivers/flash/ @nashif
/drivers/flash/*native_posix* @vanwinkeljan
/drivers/flash/*stm32* @superna9999
/drivers/gpio/*ht16k33* @henrikbrixandersen
/drivers/gpio/*stm32* @rsalveti @idlethread

View file

@ -87,6 +87,13 @@ config TRACING_CTF_BOTTOM_POSIX
endif # TRACING_CTF
if FLASH
config FLASH_NATIVE_POSIX
default y
endif # FLASH
endif # BOARD_NATIVE_POSIX
if USB

View file

@ -533,8 +533,29 @@ The following peripherals are currently provided with this board:
.. _SDL2:
https://www.libsdl.org/download-2.0.php
**Flash driver**:
A flash driver is provided that accesses all flash data through a binary file
on the host file system.
The size of the flash device can be configured through the native POSIX board
device tree and the sector size is configurable via the Kconfig option
:option:`CONFIG_FLASH_NATIVE_POSIX_SECTOR_SIZE`. The sector size will only be
used to return flash page layout related information and no restrictions are
imposed by the driver based on the configured sector size. As such an erase
operation of arbitrary size will succeed on the emulated flash device.
Further the emulated device will not impose any write restriction that are
applicable for a regular flash device, including changing the state of a bit
from zero to one.
By default the binary data is located in the file *flash.bin* in the current
working directory. The location of this file can be changed through the
command line parameter *--flash*. The flash data will be stored in raw format
and the file will be truncated to match the size specified in the device tree
configuration. In case the file does not exists the driver will take care of
creating the file, else the existing file is used.
UART
*****
****
This driver can be configured with :option:`CONFIG_UART_NATIVE_POSIX`
to instantiate up to two UARTs. By default only one UART is enabled.

View file

@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM0 flash_sam0.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NIOS2_QSPI soc_flash_nios2_qspi.c)
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c)
zephyr_library_sources_ifdef(CONFIG_FLASH_NATIVE_POSIX flash_native_posix.c)
if(CONFIG_CLOCK_CONTROL_STM32_CUBE)
zephyr_sources(flash_stm32.c)

View file

@ -53,6 +53,8 @@ source "drivers/flash/Kconfig.nios2_qspi"
source "drivers/flash/Kconfig.gecko"
source "drivers/flash/Kconfig.native_posix"
source "drivers/flash/Kconfig.nor"
source "drivers/flash/Kconfig.qmsi"

View file

@ -0,0 +1,24 @@
# Kconfig - Native POSIX Flash driver
#
# Copyright (c) 2019, Jan Van Winkel (jan.van_winkel@dxplore.eu)
#
# SPDX-License-Identifier: Apache-2.0
menuconfig FLASH_NATIVE_POSIX
bool
prompt "Native POSIX Flash driver"
select FLASH_HAS_DRIVER_ENABLED
select FLASH_HAS_PAGE_LAYOUT
depends on FLASH
help
Enable Native POSIX flash driver.
if FLASH_NATIVE_POSIX
config FLASH_NATIVE_POSIX_SECTOR_SIZE
int "Sector size"
default 8
help
This option specifies the sector size of the Native POSIX flash in KB
endif # FLASH_NATIVE_POSIX

View file

@ -0,0 +1,236 @@
/*
* Copyright (c) 2019 Jan Van Winkel <jan.van_winkel@dxplore.eu>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <device.h>
#include <flash.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include "cmdline.h"
#include "soc.h"
#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(flash_native_posix);
static const char default_flash_path[] = "flash.bin";
struct flash_native_posix_data {
struct k_sem mutex;
const char *flash_path;
int fd;
u8_t *flash;
bool init_called;
};
struct flash_native_posix_config {
size_t flash_size;
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
struct flash_pages_layout layout;
#endif
};
#define DEV_NAME(dev) ((dev)->config->name)
#define DEV_CONFIG(dev) ((dev)->config->config_info)
#define DEV_DATA(dev) \
((struct flash_native_posix_data *const)(dev)->driver_data)
static int flash_native_posix_read(struct device *dev, off_t offset, void *data,
size_t size)
{
struct flash_native_posix_data *const dev_data = DEV_DATA(dev);
const struct flash_native_posix_config *config = DEV_CONFIG(dev);
if (dev_data->flash == MAP_FAILED) {
LOG_ERR("No flash device mapped");
return -EIO;
}
if ((offset + size) > config->flash_size) {
LOG_WRN("Reading outside of flash boundaries");
return -EINVAL;
}
memcpy(data, dev_data->flash + offset, size);
return 0;
}
static int flash_native_posix_write(struct device *dev, off_t offset,
const void *data, size_t size)
{
struct flash_native_posix_data *const dev_data = DEV_DATA(dev);
const struct flash_native_posix_config *config = DEV_CONFIG(dev);
if (dev_data->flash == MAP_FAILED) {
LOG_ERR("No flash device mapped");
return -EIO;
}
if ((offset + size) > config->flash_size) {
LOG_WRN("Writing outside of flash boundaries");
return -EINVAL;
}
memcpy(dev_data->flash + offset, data, size);
return 0;
}
static int flash_native_posix_erase(struct device *dev, off_t offset,
size_t size)
{
struct flash_native_posix_data *const dev_data = DEV_DATA(dev);
const struct flash_native_posix_config *config = DEV_CONFIG(dev);
if (dev_data->flash == MAP_FAILED) {
LOG_ERR("No flash device mapped");
return -EIO;
}
if ((offset + size) > config->flash_size) {
LOG_WRN("Erasing outside of flash boundaries");
return -EINVAL;
}
memset(dev_data->flash + offset, 0xff, size);
return 0;
}
static int flash_native_posix_write_protection(struct device *dev, bool enable)
{
return 0;
}
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
static void
flash_native_posix_pages_layout(struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
{
const struct flash_native_posix_config *config = DEV_CONFIG(dev);
*layout = &config->layout;
*layout_size = 1;
}
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
static int flash_native_posix_init(struct device *dev)
{
struct flash_native_posix_data *const data = DEV_DATA(dev);
const struct flash_native_posix_config *config = DEV_CONFIG(dev);
data->init_called = true;
k_sem_init(&data->mutex, 1, 1);
if (data->flash_path == NULL) {
data->flash_path = default_flash_path;
}
data->fd = open(data->flash_path, O_RDWR | O_CREAT, (mode_t)0600);
if (data->fd == -1) {
posix_print_warning("Failed to open flash device file "
"%s: %s\n",
data->flash_path, strerror(errno));
return -EIO;
}
if (ftruncate(data->fd, config->flash_size) == -1) {
posix_print_warning("Failed to resize flash device file "
"%s: %s\n",
data->flash_path, strerror(errno));
return -EIO;
}
data->flash = mmap(NULL, config->flash_size,
PROT_WRITE | PROT_READ, MAP_SHARED, data->fd, 0);
if (data->flash == MAP_FAILED) {
posix_print_warning("Failed to mmap flash device file "
"%s: %s\n",
data->flash_path, strerror(errno));
return -EIO;
}
LOG_INF("Device %s initialized", DEV_NAME(dev));
return 0;
}
static const struct flash_driver_api flash_native_posix_driver_api = {
.read = flash_native_posix_read,
.write = flash_native_posix_write,
.erase = flash_native_posix_erase,
.write_protection = flash_native_posix_write_protection,
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
.page_layout = flash_native_posix_pages_layout,
#endif
.write_block_size = 1,
};
static const struct flash_native_posix_config flash_native_posix_config = {
.flash_size = DT_FLASH_SIZE * 1024,
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
.layout = { .pages_count = (DT_FLASH_SIZE * 1024) /
(CONFIG_FLASH_NATIVE_POSIX_SECTOR_SIZE * 1024),
.pages_size = CONFIG_FLASH_NATIVE_POSIX_SECTOR_SIZE * 1024
},
#endif
};
static struct flash_native_posix_data flash_native_posix_data;
DEVICE_AND_API_INIT(flash_native_posix_0, DT_FLASH_DEV_NAME,
&flash_native_posix_init, &flash_native_posix_data,
&flash_native_posix_config, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&flash_native_posix_driver_api);
static void flash_native_posix_cleanup(void)
{
struct flash_native_posix_data *const data = &flash_native_posix_data;
const struct flash_native_posix_config *config =
&flash_native_posix_config;
if (!data->init_called) {
return;
}
if (data->flash != MAP_FAILED) {
munmap(data->flash, config->flash_size);
}
if (data->fd != -1) {
close(data->fd);
}
}
void flash_native_posix_options(void)
{
static struct args_struct_t flash_options[] = {
{ .manual = false,
.is_mandatory = false,
.is_switch = false,
.option = "flash",
.name = "path",
.type = 's',
.dest = (void *)&flash_native_posix_data.flash_path,
.call_when_found = NULL,
.descript = "Path to binary file to be used as flash" },
ARG_TABLE_ENDMARKER
};
native_add_command_line_opts(flash_options);
}
NATIVE_TASK(flash_native_posix_options, PRE_BOOT_1, 1);
NATIVE_TASK(flash_native_posix_cleanup, ON_EXIT, 1);