Commit 5320f6e0 authored by Andrew Jeffery's avatar Andrew Jeffery

mboxd: Add backend DBus interface and commandline options

Also implement a backend commandline option to mboxctl: `mboxctl
--backend ...`, to allow easy run-time switching of the backend from the
commandline.

Switching between VPNOR and file backends via mboxctl was tested on
Witherspoon, and MTD and file backends on Romulus.

Change-Id: Iaf0e27ecf1d5cdd9e3a31729fb179096bbc37408
Signed-off-by: Andrew Jeffery's avatarAndrew Jeffery <andrew@aj.id.au>
parent a042978b
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define BACKEND_H #define BACKEND_H
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <mtd/mtd-abi.h> #include <mtd/mtd-abi.h>
...@@ -16,10 +17,6 @@ ...@@ -16,10 +17,6 @@
/* Estimate as to how long (milliseconds) it takes to access a MB from flash */ /* Estimate as to how long (milliseconds) it takes to access a MB from flash */
#define FLASH_ACCESS_MS_PER_MB 8000 #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 }; enum backend_reset_mode { reset_lpc_flash, reset_lpc_memory };
struct backend_ops; struct backend_ops;
...@@ -146,7 +143,8 @@ static inline int backend_init(struct backend *master, struct backend *with, ...@@ -146,7 +143,8 @@ static inline int backend_init(struct backend *master, struct backend *with,
master->block_size_shift = 34; master->block_size_shift = 34;
#endif #endif
assert(master->ops->init); if (!master->ops->init)
return -ENOTSUP;
rc = master->ops->init(master, data); rc = master->ops->init(master, data);
if (rc < 0) if (rc < 0)
...@@ -224,11 +222,32 @@ static inline int backend_reset(struct backend *backend, void *buf, ...@@ -224,11 +222,32 @@ static inline int backend_reset(struct backend *backend, void *buf,
return backend->ops->reset(backend, buf, count); return backend->ops->reset(backend, buf, count);
} }
struct backend backend_get_mtd(void);
int backend_probe_mtd(struct backend *master, const char *path); int backend_probe_mtd(struct backend *master, const char *path);
struct backend backend_get_file(void);
int backend_probe_file(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 */ /* Avoid dependency on vpnor/mboxd_pnor_partition_table.h */
struct vpnor_partition_paths; struct vpnor_partition_paths;
#ifdef VIRTUAL_PNOR_ENABLED
struct backend backend_get_vpnor(void);
int backend_probe_vpnor(struct backend *master, int backend_probe_vpnor(struct backend *master,
const struct vpnor_partition_paths *paths); const struct vpnor_partition_paths *paths);
#else
static inline struct backend backend_get_vpnor(void)
{
struct backend be = { 0 };
return be;
}
static inline int backend_probe_vpnor(struct backend *master,
const struct vpnor_partition_paths *paths)
{
return -ENOTSUP;
}
#endif
#endif /* BACKEND_H */ #endif /* BACKEND_H */
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include "backend.h"
#include "common.h" #include "common.h"
#include "dbus.h" #include "dbus.h"
#include "mboxd.h"
#include "backend.h"
#include "lpc.h" #include "lpc.h"
#include "transport_mbox.h" #include "mboxd.h"
#include "protocol.h"
#include "windows.h" #include "windows.h"
int control_ping(struct mbox_context *context) int control_ping(struct mbox_context *context)
...@@ -116,3 +116,29 @@ int control_resume(struct mbox_context *context, bool modified) ...@@ -116,3 +116,29 @@ int control_resume(struct mbox_context *context, bool modified)
return rc; return rc;
} }
int control_set_backend(struct mbox_context *context, struct backend *backend,
void *data)
{
int rc;
if (context->state & STATE_SUSPENDED)
return -EINVAL;
rc = protocol_events_clear(context, BMC_EVENT_DAEMON_READY);
if (rc < 0)
return rc;
backend_free(&context->backend);
rc = backend_init(&context->backend, backend, data);
if (rc < 0)
return rc;
rc = __protocol_reset(context);
if (rc < 0)
return rc;
return protocol_events_set(context,
BMC_EVENT_DAEMON_READY | BMC_EVENT_PROTOCOL_RESET);
}
...@@ -2,12 +2,14 @@ ...@@ -2,12 +2,14 @@
// Copyright (C) 2018 IBM Corp. // Copyright (C) 2018 IBM Corp.
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <systemd/sd-bus.h> #include <systemd/sd-bus.h>
#include "common.h" #include "common.h"
#include "dbus.h" #include "dbus.h"
#include "control_dbus.h" #include "control_dbus.h"
#include "mboxd.h" #include "mboxd.h"
#include "vpnor/mboxd_pnor_partition_table.h"
typedef int (*control_action)(struct mbox_context *context); typedef int (*control_action)(struct mbox_context *context);
...@@ -108,6 +110,90 @@ static int control_dbus_resume(sd_bus_message *m, void *userdata, ...@@ -108,6 +110,90 @@ static int control_dbus_resume(sd_bus_message *m, void *userdata,
return sd_bus_send(NULL, n, NULL); return sd_bus_send(NULL, n, NULL);
} }
static int control_dbus_set_backend(sd_bus_message *m, void *userdata,
sd_bus_error *ret_error)
{
struct mbox_context *context;
struct backend backend;
sd_bus_message *n;
const char *name;
int rc;
context = (struct mbox_context *) userdata;
if (!context) {
MSG_ERR("DBUS Internal Error\n");
return -EINVAL;
}
rc = sd_bus_message_read_basic(m, 's', &name);
if (rc < 0) {
MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
return rc;
}
if (!strcmp(name, "vpnor")) {
struct vpnor_partition_paths paths;
vpnor_default_paths(&paths);
backend = backend_get_vpnor();
rc = control_set_backend(context, &backend, &paths);
if (rc < 0)
return rc;
} else if (!strcmp(name, "mtd")) {
char **paths = NULL;
char *path = NULL;
rc = sd_bus_message_read_strv(m, &paths);
if (rc < 0)
return rc;
if (paths && *paths)
path = *paths;
else
path = get_dev_mtd();
backend = backend_get_mtd();
rc = control_set_backend(context, &backend, path);
if (rc < 0)
return rc;
free(path);
free(paths);
} else if (!strcmp(name, "file")) {
char **paths = NULL;
char *path = NULL;
rc = sd_bus_message_read_strv(m, &paths);
if (rc < 0)
return rc;
if (!(paths && *paths))
return -EINVAL;
path = *paths;
backend = backend_get_file();
rc = control_set_backend(context, &backend, path);
if (rc < 0)
return rc;
free(path);
free(paths);
} else {
return -EINVAL;
}
rc = sd_bus_message_new_method_return(m, &n);
if (rc < 0) {
MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
return rc;
}
return sd_bus_send(NULL, n, NULL);
}
static int control_dbus_get_u8(sd_bus *bus, const char *path, static int control_dbus_get_u8(sd_bus *bus, const char *path,
const char *interface, const char *property, const char *interface, const char *property,
sd_bus_message *reply, void *userdata, sd_bus_message *reply, void *userdata,
...@@ -144,6 +230,8 @@ static const sd_bus_vtable mboxd_vtable[] = { ...@@ -144,6 +230,8 @@ static const sd_bus_vtable mboxd_vtable[] = {
SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Resume", "b", NULL, &control_dbus_resume, SD_BUS_METHOD("Resume", "b", NULL, &control_dbus_resume,
SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetBackend", "sas", NULL, &control_dbus_set_backend,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_PROPERTY("DaemonState", "y", &control_dbus_get_u8, 0, SD_BUS_PROPERTY("DaemonState", "y", &control_dbus_get_u8, 0,
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("LpcState", "y", &control_dbus_get_u8, 0, SD_BUS_PROPERTY("LpcState", "y", &control_dbus_get_u8, 0,
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define DBUS_CONTROL_H #define DBUS_CONTROL_H
struct mbox_context; struct mbox_context;
struct backend;
int control_dbus_init(struct mbox_context *context); int control_dbus_init(struct mbox_context *context);
void control_dbus_free(struct mbox_context *context); void control_dbus_free(struct mbox_context *context);
...@@ -18,5 +19,6 @@ int control_kill(struct mbox_context *context); ...@@ -18,5 +19,6 @@ int control_kill(struct mbox_context *context);
int control_modified(struct mbox_context *context); int control_modified(struct mbox_context *context);
int control_suspend(struct mbox_context *context); int control_suspend(struct mbox_context *context);
int control_resume(struct mbox_context *context, bool modified); int control_resume(struct mbox_context *context, bool modified);
int control_set_backend(struct mbox_context *context, struct backend *backend, void *data);
#endif #endif
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -25,7 +26,8 @@ ...@@ -25,7 +26,8 @@
"\t\t--suspend\t\t- suspend the daemon to inhibit flash accesses (0)\n" \ "\t\t--suspend\t\t- suspend the daemon to inhibit flash accesses (0)\n" \
"\t\t--resume\t\t- resume the daemon (1)\n" \ "\t\t--resume\t\t- resume the daemon (1)\n" \
"\t\t\targ[0]: < \"clean\" | \"modified\" >\n" \ "\t\t\targ[0]: < \"clean\" | \"modified\" >\n" \
"\t\t--clear-cache\t- tell the daemon to discard any caches (0)\n" "\t\t--clear-cache\t- tell the daemon to discard any caches (0)\n" \
"\t\t--backend <vpnor|mtd[:PATH]|file:PATH>\n"
#define NAME "Mailbox Control" #define NAME "Mailbox Control"
...@@ -269,6 +271,95 @@ static int handle_cmd_modified(struct mboxctl_context *context) ...@@ -269,6 +271,95 @@ static int handle_cmd_modified(struct mboxctl_context *context)
return rc; return rc;
} }
static int handle_cmd_backend(struct mboxctl_context *context, char *sarg)
{
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *m = NULL, *n = NULL;
char *delim = NULL;
char *strv[2];
int rc;
if (!sarg) {
MSG_ERR("Backend command takes an argument\n");
return -EINVAL;
}
rc = sd_bus_message_new_method_call(context->bus, &m,
MBOX_DBUS_NAME,
MBOX_DBUS_OBJECT,
MBOX_DBUS_CONTROL_IFACE,
"SetBackend");
if (rc < 0) {
MSG_ERR("Failed to init method call: %s\n",
strerror(-rc));
goto out;
}
if (!strncmp(sarg, "vpnor", strlen("vpnor"))) {
if (strchr(sarg, ':')) {
MSG_ERR("Path parameter not supported for vpnor\n");
rc = -EINVAL;
goto out;
}
rc = sd_bus_message_append(m, "s", "vpnor");
if (rc < 0)
goto out;
} else if (!strncmp(sarg, "mtd", strlen("mtd"))) {
rc = sd_bus_message_append(m, "s", "mtd");
if (rc < 0)
goto out;
} else if (!strncmp(sarg, "file", strlen("file"))) {
rc = sd_bus_message_append(m, "s", "file");
if (rc < 0)
goto out;
} else {
rc = -EINVAL;
goto out;
}
delim = strchr(sarg, ':');
if (delim) {
char *path;
path = realpath(delim + 1, NULL);
if (!path) {
MSG_ERR("Failed to resolve path: %s\n",
strerror(errno));
rc = -errno;
goto out;
}
strv[0] = path;
strv[1] = NULL;
rc = sd_bus_message_append_strv(m, &strv[0]);
free(path);
if (rc < 0)
goto out;
} else {
strv[0] = NULL;
strv[1] = NULL;
rc = sd_bus_message_append_strv(m, &strv[0]);
if (rc < 0)
goto out;
}
rc = sd_bus_call(context->bus, m, 0, &error, &n);
if (rc < 0) {
MSG_ERR("Failed to post message: %s\n", strerror(-rc));
goto out;
}
MSG_OUT("SetBackend: %s\n", rc < 0 ? strerror(-rc) : "Success");
out:
sd_bus_error_free(&error);
sd_bus_message_unref(m);
return rc < 0 ? rc : 0;
}
static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv) static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
{ {
int opt, rc = -1; int opt, rc = -1;
...@@ -284,6 +375,7 @@ static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv) ...@@ -284,6 +375,7 @@ static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
{ "suspend", no_argument, 0, 'u' }, { "suspend", no_argument, 0, 'u' },
{ "resume", required_argument, 0, 'e' }, { "resume", required_argument, 0, 'e' },
{ "clear-cache", no_argument, 0, 'c' }, { "clear-cache", no_argument, 0, 'c' },
{ "backend", required_argument, 0, 'b' },
{ "version", no_argument, 0, 'v' }, { "version", no_argument, 0, 'v' },
{ "help", no_argument, 0, 'h' }, { "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
...@@ -325,6 +417,9 @@ static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv) ...@@ -325,6 +417,9 @@ static int parse_cmdline(struct mboxctl_context *context, int argc, char **argv)
case 'c': case 'c':
rc = handle_cmd_modified(context); rc = handle_cmd_modified(context);
break; break;
case 'b':
rc = handle_cmd_backend(context, optarg);
break;
case 'v': case 'v':
MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION); MSG_OUT("%s V%s\n", NAME, PACKAGE_VERSION);
rc = 0; rc = 0;
......
...@@ -44,9 +44,9 @@ const char* USAGE = ...@@ -44,9 +44,9 @@ const char* USAGE =
"\t\t[-w | --window-size <size>M]\n" "\t\t[-w | --window-size <size>M]\n"
"\t\t-f | --flash <size>[K|M]\n" "\t\t-f | --flash <size>[K|M]\n"
#ifdef VIRTUAL_PNOR_ENABLED #ifdef VIRTUAL_PNOR_ENABLED
"\t\t-s | --source <vpnor|path>\n\n" "\t\t-b | --backend <vpnor|mtd[:PATH]|file:PATH>\n"
#else #else
"\t\t-s | --source <path>\n\n" "\t\t-b | --backend <mtd[:PATH]|file:PATH>\n"
#endif #endif
"\t-v | --verbose\t\tBe [more] verbose\n" "\t-v | --verbose\t\tBe [more] verbose\n"
"\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n" "\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n"
...@@ -272,7 +272,7 @@ static bool parse_cmdline(int argc, char **argv, ...@@ -272,7 +272,7 @@ static bool parse_cmdline(int argc, char **argv,
} }
break; break;
case 'b': case 'b':
context->path = optarg; context->source = optarg;
break; break;
case 'n': case 'n':
context->windows.num = strtol(argv[optind], &endptr, context->windows.num = strtol(argv[optind], &endptr,
...@@ -316,9 +316,6 @@ static bool parse_cmdline(int argc, char **argv, ...@@ -316,9 +316,6 @@ static bool parse_cmdline(int argc, char **argv,
} }
} }
if (!context->path) {
context->path = get_dev_mtd();
}
if (!context->backend.flash_size) { if (!context->backend.flash_size) {
fprintf(stderr, "Must specify a non-zero flash size\n"); fprintf(stderr, "Must specify a non-zero flash size\n");
return false; return false;
...@@ -336,23 +333,44 @@ static bool parse_cmdline(int argc, char **argv, ...@@ -336,23 +333,44 @@ static bool parse_cmdline(int argc, char **argv,
static int mboxd_backend_init(struct mbox_context *context) static int mboxd_backend_init(struct mbox_context *context)
{ {
const char *delim;
const char *path;
int rc; int rc;
#ifdef VIRTUAL_PNOR_ENABLED if (!context->source) {
struct vpnor_partition_paths paths; struct vpnor_partition_paths paths;
vpnor_default_paths(&paths); vpnor_default_paths(&paths);
rc = backend_probe_vpnor(&context->backend, &paths); rc = backend_probe_vpnor(&context->backend, &paths);
if(rc) if(rc < 0)
#endif rc = backend_probe_mtd(&context->backend, NULL);
{
rc = backend_probe_mtd(&context->backend, context->path); return rc;
if (rc) { }
rc = backend_probe_file(&context->backend,
context->path); delim = strchr(context->source, ':');
path = delim ? delim + 1 : NULL;
if (!strncmp(context->source, "vpnor", strlen("vpnor"))) {
struct vpnor_partition_paths paths;
if (path) {
rc = -EINVAL;
} else {
vpnor_default_paths(&paths);
rc = backend_probe_vpnor(&context->backend, &paths);
} }
} else if (!strncmp(context->source, "mtd", strlen("mtd"))) {
rc = backend_probe_mtd(&context->backend, path);
} else if (!strncmp(context->source, "file", strlen("file"))) {
rc = backend_probe_file(&context->backend, path);
} else {
rc = -EINVAL;
} }
if (rc < 0)
MSG_ERR("Invalid backend argument: %s\n", context->source);
return rc; return rc;
} }
......
...@@ -76,7 +76,7 @@ struct mbox_context { ...@@ -76,7 +76,7 @@ struct mbox_context {
struct backend backend; struct backend backend;
/* Commandline parameters */ /* Commandline parameters */
const char *path; const char *source;
/* System State */ /* System State */
enum mbox_state state; enum mbox_state state;
......
...@@ -35,7 +35,7 @@ TEST_MOCK_CORE = \ ...@@ -35,7 +35,7 @@ TEST_MOCK_CORE = \
%reldir%/mbox.c \ %reldir%/mbox.c \
%reldir%/system.c %reldir%/system.c
TEST_MOCK_SRCS = %reldir%/backend.c $(TEST_MOCK_CORE) TEST_MOCK_SRCS = $(TEST_MOCK_CORE)
test_get_mbox_info_v2_SOURCES = %reldir%/get_mbox_info_v2.c \ test_get_mbox_info_v2_SOURCES = %reldir%/get_mbox_info_v2.c \
$(TEST_MBOX_SRCS) $(TEST_MOCK_SRCS) $(TEST_MBOX_SRCS) $(TEST_MOCK_SRCS)
......
#include "backend.h"
#include "mboxd.h"
#include <errno.h>
struct backend backend_get_vpnor(void)
{
struct backend be = {0};
return be;
}
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
/* Copyright (C) 2018 IBM Corp. */ /* Copyright (C) 2018 IBM Corp. */
#pragma once #pragma once
#ifdef VIRTUAL_PNOR_ENABLED
#include <limits.h> #include <limits.h>
#include "pnor_partition_defs.h" #include "pnor_partition_defs.h"
#include "backend.h" #include "backend.h"
...@@ -34,8 +32,16 @@ extern "C" { ...@@ -34,8 +32,16 @@ extern "C" {
* *
* Returns 0 if the call succeeds, else a negative error code. * Returns 0 if the call succeeds, else a negative error code.
*/ */
#ifdef VIRTUAL_PNOR_ENABLED
void vpnor_default_paths(struct vpnor_partition_paths *paths); void vpnor_default_paths(struct vpnor_partition_paths *paths);
#else
static inline void vpnor_default_paths(struct vpnor_partition_paths *paths)
{
memset(paths, 0, sizeof(*paths));
}
#endif
#ifdef VIRTUAL_PNOR_ENABLED
/** @brief Create a virtual PNOR partition table. /** @brief Create a virtual PNOR partition table.
* *
* @param[in] backend - The backend context pointer * @param[in] backend - The backend context pointer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment