diff options
author | Evan Lojewski <github@meklort.com> | 2019-03-13 15:25:44 +1030 |
---|---|---|
committer | Andrew Jeffery <andrew@aj.id.au> | 2019-03-18 10:46:11 +1030 |
commit | a042978b03c91ca3a716e99f313ef5cda42820ba (patch) | |
tree | 76563db5c33895654e70b300b724c3ed40f78317 | |
parent | 0297e5b82ea1bf8b151f8208c5f28a121d82eb4c (diff) | |
download | phosphor-mboxbridge-a042978b03c91ca3a716e99f313ef5cda42820ba.tar.gz phosphor-mboxbridge-a042978b03c91ca3a716e99f313ef5cda42820ba.zip |
mboxd: Add support for file-backed flash devices.
This commit adds a new file based backing source. The file based
backing source takes a raw pnor image that is usually flashed to a mtd
device.
This backing source enabled rapid testing of pnor images.
Tested on Witherspoon with the VPNOR and file backends, and Romulus for
the MTD and file backends.
Change-Id: I253ecfa6b58d071c7982f153ad50da8e4ad39fa2
Signed-off-by: Evan Lojewski <github@meklort.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | backend.h | 2 | ||||
-rw-r--r-- | file/Makefile.am.include | 1 | ||||
-rw-r--r-- | file/backend.c | 282 | ||||
-rw-r--r-- | mboxd.c | 39 |
5 files changed, 314 insertions, 13 deletions
diff --git a/Makefile.am b/Makefile.am index 0ce5242..27d63a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,9 @@ mboxd_CFLAGS = $(LIBSYSTEMD_CFLAGS) # MTD Backing storage include mtd/Makefile.am.include +# File Backing storage +include file/Makefile.am.include + if VIRTUAL_PNOR_ENABLED # VPNOR Backing storage include vpnor/Makefile.am.include @@ -17,6 +17,7 @@ #define FLASH_ACCESS_MS_PER_MB 8000 struct backend backend_get_mtd(void); +struct backend backend_get_file(void); struct backend backend_get_vpnor(void); enum backend_reset_mode { reset_lpc_flash, reset_lpc_memory }; @@ -224,6 +225,7 @@ static inline int backend_reset(struct backend *backend, void *buf, } int backend_probe_mtd(struct backend *master, const char *path); +int backend_probe_file(struct backend *master, const char *path); /* Avoid dependency on vpnor/mboxd_pnor_partition_table.h */ struct vpnor_partition_paths; int backend_probe_vpnor(struct backend *master, diff --git a/file/Makefile.am.include b/file/Makefile.am.include new file mode 100644 index 0000000..155db50 --- /dev/null +++ b/file/Makefile.am.include @@ -0,0 +1 @@ +mboxd_SOURCES += %reldir%/backend.c diff --git a/file/backend.c b/file/backend.c new file mode 100644 index 0000000..224719d --- /dev/null +++ b/file/backend.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2018 IBM Corp. +// Copyright (C) 2018 Evan Lojewski. + +#define _GNU_SOURCE +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <inttypes.h> +#include <limits.h> +#include <mtd/mtd-abi.h> +#include <poll.h> +#include <signal.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/timerfd.h> +#include <sys/types.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> + +#include "common.h" +#include "backend.h" +#include "lpc.h" +#include "mboxd.h" + +#define MIN(__x__, __y__) (((__x__) < (__y__)) ? (__x__) : (__y__)) + +#define FILE_ERASE_SIZE (4 * 1024) + +struct file_data { + int fd; +}; + +static int file_dev_init(struct backend *backend, void *data) +{ + struct mtd_info_user info; + const char *path = data; + struct file_data *priv; + struct stat statbuf; + int rc = 0; + + if (!path) { + MSG_ERR("No PNOR file specified\n"); + return -EINVAL; + } + + priv = malloc(sizeof(*priv)); + if (!priv) + return -errno; + + MSG_DBG("Opening %s\n", path); + + priv->fd = open(path, O_RDWR); + if (priv->fd < 0) { + MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", path, + strerror(errno)); + rc = -errno; + goto cleanup_data; + } + + /* Don't attach to mtd devices. */ + rc = ioctl(priv->fd, MEMGETINFO, &info); + if (rc != -1) { + rc = -errno; + goto cleanup_fd; + } + + rc = fstat(priv->fd, &statbuf); + if (rc < 0) { + rc = -errno; + goto cleanup_fd; + } + + if (backend->flash_size == 0) { + MSG_INFO("Flash size should be supplied on the commandline.\n"); + backend->flash_size = statbuf.st_size; + } + + /* Pick an erase size congruent with partition alignment */ + backend->erase_size_shift = log_2(FILE_ERASE_SIZE); + backend->block_size_shift = backend->erase_size_shift; + MSG_DBG("Flash erase size: 0x%.8x\n", FILE_ERASE_SIZE); + + backend->priv = priv; + return rc; + +cleanup_fd: + close(priv->fd); +cleanup_data: + free(priv); + return rc; +} + +static void file_dev_free(struct backend *backend) +{ + struct file_data *priv = backend->priv; + + close(priv->fd); + free(priv); +} + +/* Flash Functions */ + +/* + * file_erase() - Erase the flash + * @context: The mbox context pointer + * @offset: The flash offset to erase (bytes) + * @size: The number of bytes to erase + * + * Return: 0 on success otherwise negative error code + */ +static int file_erase(struct backend *backend, uint32_t offset, uint32_t count) +{ + const uint32_t erase_size = 1 << backend->erase_size_shift; + struct file_data *priv = backend->priv; + struct erase_info_user erase_info = {0}; + int rc; + + MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n", offset, count); + + uint8_t* erase_buf = (uint8_t*)malloc(count); + if (!erase_buf) { + MSG_ERR("Couldn't malloc erase buffer. %s\n", strerror(errno)); + return -1; + } + memset(erase_buf, 0xFF, erase_size); + rc = pwrite(priv->fd, erase_buf, count, offset); + free(erase_buf); + + if (rc < 0) { + MSG_ERR("Couldn't erase flash at 0x%.8x\n", erase_info.start); + return -errno; + } + + + return 0; +} + +#define CHUNKSIZE (64 * 1024) + +/* + * file_copy() - Copy data from the flash device into a provided buffer + * @context: The backend context pointer + * @offset: The flash offset to copy from (bytes) + * @mem: The buffer to copy into (must be of atleast 'size' bytes) + * @size: The number of bytes to copy + * Return: Number of bytes copied on success, otherwise negative error + * code. file_copy will copy at most 'size' bytes, but it may + * copy less. + */ +static int64_t file_copy(struct backend *backend, uint32_t offset, + void *mem, uint32_t size) +{ + struct file_data *priv = backend->priv; + int32_t size_read; + void *start = mem; + + MSG_DBG("Copy flash to %p for size 0x%.8x from offset 0x%.8x\n", mem, + size, offset); + if (lseek(priv->fd, offset, SEEK_SET) != offset) { + MSG_ERR("Couldn't seek flash at pos: %u %s\n", offset, + strerror(errno)); + return -errno; + } + + do { + size_read = read(priv->fd, mem, min_u32(CHUNKSIZE, size)); + if (size_read < 0) { + MSG_ERR("Couldn't copy file into ram: %s\n", + strerror(errno)); + return -errno; + } + + size -= size_read; + mem += size_read; + } while (size && size_read); + + return size_read ? mem - start : -EIO; +} + +/* + * file_write() - Write the flash from a provided buffer + * @context: The mbox context pointer + * @offset: The flash offset to write to (bytes) + * @buf: The buffer to write from (must be of atleast size) + * @size: The number of bytes to write + * + * Return: 0 on success otherwise negative error code + */ +static int file_write(struct backend *backend, uint32_t offset, void *buf, + uint32_t count) +{ + struct file_data *priv = backend->priv; + uint32_t buf_offset = 0; + int rc; + + MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count, + buf); + + if (lseek(priv->fd, offset, SEEK_SET) != offset) { + MSG_ERR("Couldn't seek flash at pos: %u %s\n", offset, + strerror(errno)); + return -errno; + } + + while (count) { + rc = write(priv->fd, buf + buf_offset, count); + if (rc < 0) { + MSG_ERR("Couldn't write to file, write lost: %s\n", + strerror(errno)); + return -errno; + } + count -= rc; + buf_offset += rc; + } + + return 0; +} + +/* + * file_reset() - Reset the lpc bus mapping + * @context: The backend context pointer + * @buf: Pointer to the LPC reserved memory + * @count: The size of the LPC reserved memory + * + * Return: 0 on success otherwise negative error code + */ +static int file_reset(struct backend *backend, void *buf, uint32_t count) +{ + struct file_data *priv = backend->priv; + size_t len; + int rc; + + len = MIN(backend->flash_size, count); + + /* Ugh, otherwise we need to parse the FFS image */ + assert(len == backend->flash_size); + + /* Preload Flash contents into memory window */ + rc = pread(priv->fd, buf, len, 0); + if (rc < 0) + return -errno; + + return reset_lpc_memory; +} + +static const struct backend_ops file_ops = { + .init = file_dev_init, + .free = file_dev_free, + .copy = file_copy, + .erase = file_erase, + .write = file_write, + .reset = file_reset, + .validate = NULL, +}; + +struct backend backend_get_file(void) +{ + struct backend be = {0}; + + be.ops = &file_ops; + + return be; +} + +int backend_probe_file(struct backend *master, const char *path) +{ + struct backend with; + + assert(master); + with = backend_get_file(); + + return backend_init(master, &with, (void *)path); +} @@ -38,18 +38,23 @@ #include "windows.h" #include "vpnor/mboxd_pnor_partition_table.h" -#define USAGE \ -"\nUsage: %s [-V | --version] [-h | --help] [-v[v] | --verbose] [-s | --syslog]\n" \ -"\t\t[-n | --window-num <num>]\n" \ -"\t\t[-w | --window-size <size>M]\n" \ -"\t\t-f | --flash <size>[K|M]\n\n" \ -"\t-v | --verbose\t\tBe [more] verbose\n" \ -"\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n" \ -"\t-n | --window-num\tThe number of windows\n" \ -"\t\t\t\t(default: fill the reserved memory region)\n" \ -"\t-w | --window-size\tThe window size (power of 2) in MB\n" \ -"\t\t\t\t(default: 1MB)\n" \ -"\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n" +const char* USAGE = + "\nUsage: %s [-V | --version] [-h | --help] [-v[v] | --verbose] [-s | --syslog]\n" + "\t\t[-n | --window-num <num>]\n" + "\t\t[-w | --window-size <size>M]\n" + "\t\t-f | --flash <size>[K|M]\n" +#ifdef VIRTUAL_PNOR_ENABLED + "\t\t-s | --source <vpnor|path>\n\n" +#else + "\t\t-s | --source <path>\n\n" +#endif + "\t-v | --verbose\t\tBe [more] verbose\n" + "\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n" + "\t-n | --window-num\tThe number of windows\n" + "\t\t\t\t(default: fill the reserved memory region)\n" + "\t-w | --window-size\tThe window size (power of 2) in MB\n" + "\t\t\t\t(default: 1MB)\n" + "\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n"; static int dbus_init(struct mbox_context *context, const struct transport_ops **ops) @@ -226,6 +231,7 @@ static bool parse_cmdline(int argc, char **argv, static const struct option long_options[] = { { "flash", required_argument, 0, 'f' }, + { "backend", required_argument, 0, 'b' }, { "window-size", optional_argument, 0, 'w' }, { "window-num", optional_argument, 0, 'n' }, { "verbose", no_argument, 0, 'v' }, @@ -240,7 +246,7 @@ static bool parse_cmdline(int argc, char **argv, context->current = NULL; /* No current window */ - while ((opt = getopt_long(argc, argv, "f:w::n::vsVh", long_options, NULL)) + while ((opt = getopt_long(argc, argv, "f:b:w::n::vsVh", long_options, NULL)) != -1) { switch (opt) { case 0: @@ -265,6 +271,9 @@ static bool parse_cmdline(int argc, char **argv, return false; } break; + case 'b': + context->path = optarg; + break; case 'n': context->windows.num = strtol(argv[optind], &endptr, 10); @@ -338,6 +347,10 @@ static int mboxd_backend_init(struct mbox_context *context) #endif { rc = backend_probe_mtd(&context->backend, context->path); + if (rc) { + rc = backend_probe_file(&context->backend, + context->path); + } } return rc; |