summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvan Lojewski <github@meklort.com>2019-03-13 15:25:44 +1030
committerAndrew Jeffery <andrew@aj.id.au>2019-03-18 10:46:11 +1030
commita042978b03c91ca3a716e99f313ef5cda42820ba (patch)
tree76563db5c33895654e70b300b724c3ed40f78317
parent0297e5b82ea1bf8b151f8208c5f28a121d82eb4c (diff)
downloadphosphor-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.am3
-rw-r--r--backend.h2
-rw-r--r--file/Makefile.am.include1
-rw-r--r--file/backend.c282
-rw-r--r--mboxd.c39
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
diff --git a/backend.h b/backend.h
index 05c5498..5b043ec 100644
--- a/backend.h
+++ b/backend.h
@@ -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);
+}
diff --git a/mboxd.c b/mboxd.c
index a7b2283..85e1d3f 100644
--- a/mboxd.c
+++ b/mboxd.c
@@ -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;
OpenPOWER on IntegriCloud