diff options
author | Suraj Jitindar Singh <sjitindarsingh@gmail.com> | 2017-03-28 10:47:43 +1100 |
---|---|---|
committer | Suraj Jitindar Singh <sjitindarsingh@gmail.com> | 2017-04-11 11:41:54 +1000 |
commit | e39c91637337fc1afc54fe8e215f1493395601a3 (patch) | |
tree | 0af6bb466ed1ca0afcb03e568a3a98da5723c06d /mboxd_dbus.c | |
parent | 2dff340a846068f33a0de171a75d4187bc189ea3 (diff) | |
download | phosphor-mboxd-e39c91637337fc1afc54fe8e215f1493395601a3.tar.gz phosphor-mboxd-e39c91637337fc1afc54fe8e215f1493395601a3.zip |
mboxd: Update mboxd to implement protocol V2 and add dbus support
Version 2 of the mbox protocol contains a few changes such as:
- All sizes are in block size
- Adds an erase command
- Adds new response codes
- Adds new BMC events
- Open windows commands now take a size directive
Update the mailbox daemon to support version 2 of the protocol which
includes implementing all of the V2 functionality. Also entirely refactor
the mboxd.c code to make it more modular improving readability and
maintainability.
At the same time improve the functionality by adding:
- Multiple windows in the daemon (still only one active window) to cache
flash contents
- Implement a dbus interface to allow interaction with the daemon
- Handle sigterm and sigint and terminate cleanly
The previous implementation utilised the entire reserved memory region.
Update the daemon so that on the command line the number of windows and
the size of each which the reserved memory region will be split into can
be specified. The reserved memory region is then divided between the
windows, however there can still only be one "active" window at a time.
The daemon uses these windows to cache the flash contents meaning the
flash doesn't have to be copied when the host requests access assuming
the daemon already has a copy.
A dbus interface is added so that commands can be sent to the daemon to
control it's operation from the bmc. These include suspending and resuming
the daemon to synchronise flash access, telling the daemon to point the lpc
mapping back to flash and telling the daemon when the flash has been
modified out from under it.
Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Change-Id: I10be01a395c2bec437cf2c825fdd144580b60dbc
Diffstat (limited to 'mboxd_dbus.c')
-rw-r--r-- | mboxd_dbus.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/mboxd_dbus.c b/mboxd_dbus.c new file mode 100644 index 0000000..3b09bb1 --- /dev/null +++ b/mboxd_dbus.c @@ -0,0 +1,372 @@ +/* + * Mailbox Daemon DBUS Helpers + * + * Copyright 2016 IBM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#define _GNU_SOURCE +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> +#include <poll.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/timerfd.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> +#include <inttypes.h> +#include <systemd/sd-bus.h> + +#include "mbox.h" +#include "common.h" +#include "dbus.h" +#include "mboxd_dbus.h" +#include "mboxd_windows.h" +#include "mboxd_msg.h" +#include "mboxd_lpc.h" +#include "mboxd_flash.h" + +typedef int (*mboxd_dbus_handler)(struct mbox_context *, struct mbox_dbus_msg *, + struct mbox_dbus_msg *); + +/* DBUS Functions */ + +/* + * Command: DBUS Ping + * Ping the daemon + * + * Args: NONE + * Resp: NONE + */ +static int dbus_handle_ping(struct mbox_context *context, + struct mbox_dbus_msg *req, + struct mbox_dbus_msg *resp) +{ + return 0; +} + +/* + * Command: DBUS Status + * Get the status of the daemon + * + * Args: NONE + * Resp[0]: Status Code + */ +static int dbus_handle_daemon_state(struct mbox_context *context, + struct mbox_dbus_msg *req, + struct mbox_dbus_msg *resp) +{ + resp->num_args = DAEMON_STATE_NUM_ARGS; + resp->args = calloc(resp->num_args, sizeof(*resp->args)); + resp->args[0] = (context->state & STATE_SUSPENDED) ? + DAEMON_STATE_SUSPENDED : DAEMON_STATE_ACTIVE; + + return 0; +} + +/* + * Command: DBUS LPC State + * Get the state of the lpc bus mapping (whether it points to memory or flash + * + * Args: NONE + * Resp[0]: LPC Bus State Code + */ +static int dbus_handle_lpc_state(struct mbox_context *context, + struct mbox_dbus_msg *req, + struct mbox_dbus_msg *resp) +{ + resp->num_args = LPC_STATE_NUM_ARGS; + resp->args = calloc(resp->num_args, sizeof(*resp->args)); + if ((context->state & MAPS_MEM) && !(context->state & MAPS_FLASH)) { + resp->args[0] = LPC_STATE_MEM; + } else if (!(context->state & MAPS_MEM) && + (context->state & MAPS_FLASH)) { + resp->args[0] = LPC_STATE_FLASH; + } else { + resp->args[0] = LPC_STATE_INVALID; + } + + return 0; +} + +/* + * Command: DBUS Reset + * Reset the daemon state, final operation TBA. + * For now we just point the lpc mapping back at the flash. + * + * Args: NONE + * Resp: NONE + */ +static int dbus_handle_reset(struct mbox_context *context, + struct mbox_dbus_msg *req, + struct mbox_dbus_msg *resp) +{ + int rc; + + /* We don't let the host access flash if the daemon is suspened */ + if (context->state & STATE_SUSPENDED) { + return -E_DBUS_REJECTED; + } + + /* + * This will close (and flush) the current window and point the lpc bus + * mapping back to flash. Better set the bmc event to notify the host + * of this. + */ + reset_all_windows(context, SET_BMC_EVENT); + rc = point_to_flash(context); + if (rc < 0) { + return -E_DBUS_HARDWARE; + } + + return 0; +} + +/* + * Command: DBUS Kill + * Stop the daemon + * + * Args: NONE + * Resp: NONE + */ +static int dbus_handle_kill(struct mbox_context *context, + struct mbox_dbus_msg *req, + struct mbox_dbus_msg *resp) +{ + context->terminate = 1; + + MSG_OUT("DBUS Kill - Exiting...\n"); + + return 0; +} + +/* + * Command: DBUS Flash Modified + * Used to notify the daemon that the flash has been modified out from under + * it - We need to reset all out windows to ensure flash will be reloaded + * when a new window is opened. + * Note: We don't flush any previously opened windows + * + * Args: NONE + * Resp: NONE + */ +static int dbus_handle_modified(struct mbox_context *context, + struct mbox_dbus_msg *req, + struct mbox_dbus_msg *resp) +{ + /* Flash has been modified - can no longer trust our erased bytemap */ + set_flash_bytemap(context, 0, context->flash_size, FLASH_DIRTY); + + /* Force daemon to reload all windows -> Set BMC event to notify host */ + reset_all_windows(context, SET_BMC_EVENT); + + return 0; +} + +/* + * Command: DBUS Suspend + * Suspend the daemon to inhibit it from performing flash accesses. + * This is used to synchronise access to the flash between the daemon and + * directly from the BMC. + * + * Args: NONE + * Resp: NONE + */ +static int dbus_handle_suspend(struct mbox_context *context, + struct mbox_dbus_msg *req, + struct mbox_dbus_msg *resp) +{ + int rc; + + if (context->state & STATE_SUSPENDED) { + /* Already Suspended */ + return DBUS_SUCCESS; + } + + /* Nothing to check - Just set the bit to notify the host */ + rc = set_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST, SET_BMC_EVENT); + if (rc < 0) { + return -E_DBUS_HARDWARE; + } + + context->state |= STATE_SUSPENDED; + + return rc; +} + +/* + * Command: DBUS Resume + * Resume the daemon to let it perform flash accesses again. + * + * Args[0]: Flash Modified (0 - no | 1 - yes) + * Resp: NONE + */ +static int dbus_handle_resume(struct mbox_context *context, + struct mbox_dbus_msg *req, + struct mbox_dbus_msg *resp) +{ + int rc; + + if (req->num_args != 1) { + return -E_DBUS_INVAL; + } + + if (!(context->state & STATE_SUSPENDED)) { + /* We weren't suspended... */ + return DBUS_SUCCESS; + } + + if (req->args[0] == RESUME_FLASH_MODIFIED) { + /* Clear the bit and call the flash modified handler */ + clr_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST, + NO_BMC_EVENT); + rc = dbus_handle_modified(context, req, resp); + } else { + /* Flash wasn't modified - just clear the bit with writeback */ + rc = clr_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST, + SET_BMC_EVENT); + } + + if (rc < 0) { + rc = -E_DBUS_HARDWARE; + } + context->state &= ~STATE_SUSPENDED; + + return rc; +} + +static const mboxd_dbus_handler dbus_handlers[NUM_DBUS_CMDS] = { + dbus_handle_ping, + dbus_handle_daemon_state, + dbus_handle_reset, + dbus_handle_suspend, + dbus_handle_resume, + dbus_handle_modified, + dbus_handle_kill, + dbus_handle_lpc_state +}; + +static int method_cmd(sd_bus_message *m, void *userdata, + sd_bus_error *ret_error) +{ + struct mbox_dbus_msg req = { 0 }, resp = { 0 }; + struct mbox_context *context; + sd_bus_message *n; + int rc; + + context = (struct mbox_context *) userdata; + if (!context) { + MSG_ERR("DBUS Internal Error\n"); + rc = -E_DBUS_INTERNAL; + goto out; + } + + /* Read the command */ + rc = sd_bus_message_read(m, "y", &req.cmd); + if (rc < 0) { + MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); + rc = -E_DBUS_INTERNAL; + goto out; + } + + /* Read the args */ + rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args, + &req.num_args); + if (rc < 0) { + MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); + rc = -E_DBUS_INTERNAL; + goto out; + } + + /* Handle the command */ + if (req.cmd >= NUM_DBUS_CMDS) { + rc = -E_DBUS_INVAL; + MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd); + } else { + rc = dbus_handlers[req.cmd](context, &req, &resp); + } + +out: + if (rc < 0) { + resp.cmd = -rc; + } + sd_bus_message_new_method_return(m, &n); /* Generate response */ + sd_bus_message_append(n, "y", resp.cmd); /* Set return code */ + sd_bus_message_append_array(n, 'y', resp.args, resp.num_args); + sd_bus_send(sd_bus_message_get_bus(m), n, NULL); /* Send response */ + free(resp.args); + return 0; +} + +static const sd_bus_vtable mboxd_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END +}; + +int init_mboxd_dbus(struct mbox_context *context) +{ + int rc; + + rc = sd_bus_default_system(&context->bus); + if (rc < 0) { + MSG_ERR("Failed to connect to the system bus: %s\n", + strerror(-rc)); + return rc; + } + + rc = sd_bus_add_object_vtable(context->bus, NULL, DOBJ_NAME, DBUS_NAME, + mboxd_vtable, context); + if (rc < 0) { + MSG_ERR("Failed to register vtable: %s\n", strerror(-rc)); + return rc; + } + + rc = sd_bus_request_name(context->bus, DBUS_NAME, + SD_BUS_NAME_ALLOW_REPLACEMENT | + SD_BUS_NAME_REPLACE_EXISTING); + if (rc < 0) { + MSG_ERR("Failed to acquire service name: %s\n", strerror(-rc)); + return rc; + } + + rc = sd_bus_get_fd(context->bus); + if (rc < 0) { + MSG_ERR("Failed to get bus fd: %s\n", strerror(-rc)); + return rc; + } + + context->fds[DBUS_FD].fd = rc; + + return 0; +} + +void free_mboxd_dbus(struct mbox_context *context) +{ + sd_bus_unref(context->bus); +} |