237 lines
5.8 KiB
C
237 lines
5.8 KiB
C
/*
|
|
* Copyright (c) 2019 Jan Van Winkel <jan.van_winkel@dxplore.eu>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <device.h>
|
|
#include <drivers/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);
|