blob: 4a0b38fb75282a17be3668e47dedddfe6d147de7 [file] [log] [blame]
Andrew Jeffery4fe996c2018-02-27 12:16:48 +10301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +11003
4#define _GNU_SOURCE
5#include <assert.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <getopt.h>
9#include <limits.h>
10#include <poll.h>
11#include <stdbool.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <syslog.h>
17#include <signal.h>
18#include <sys/ioctl.h>
19#include <sys/mman.h>
20#include <sys/stat.h>
21#include <sys/timerfd.h>
22#include <sys/types.h>
23#include <time.h>
24#include <unistd.h>
25#include <inttypes.h>
26#include <systemd/sd-bus.h>
27
28#include "mbox.h"
29#include "common.h"
30#include "dbus.h"
31#include "mboxd_dbus.h"
32#include "mboxd_windows.h"
33#include "mboxd_msg.h"
34#include "mboxd_lpc.h"
35#include "mboxd_flash.h"
36
37typedef int (*mboxd_dbus_handler)(struct mbox_context *, struct mbox_dbus_msg *,
38 struct mbox_dbus_msg *);
39
40/* DBUS Functions */
41
42/*
43 * Command: DBUS Ping
44 * Ping the daemon
45 *
46 * Args: NONE
47 * Resp: NONE
48 */
49static int dbus_handle_ping(struct mbox_context *context,
50 struct mbox_dbus_msg *req,
51 struct mbox_dbus_msg *resp)
52{
53 return 0;
54}
55
56/*
57 * Command: DBUS Status
58 * Get the status of the daemon
59 *
60 * Args: NONE
61 * Resp[0]: Status Code
62 */
63static int dbus_handle_daemon_state(struct mbox_context *context,
64 struct mbox_dbus_msg *req,
65 struct mbox_dbus_msg *resp)
66{
67 resp->num_args = DAEMON_STATE_NUM_ARGS;
68 resp->args = calloc(resp->num_args, sizeof(*resp->args));
69 resp->args[0] = (context->state & STATE_SUSPENDED) ?
70 DAEMON_STATE_SUSPENDED : DAEMON_STATE_ACTIVE;
71
72 return 0;
73}
74
75/*
76 * Command: DBUS LPC State
77 * Get the state of the lpc bus mapping (whether it points to memory or flash
78 *
79 * Args: NONE
80 * Resp[0]: LPC Bus State Code
81 */
82static int dbus_handle_lpc_state(struct mbox_context *context,
83 struct mbox_dbus_msg *req,
84 struct mbox_dbus_msg *resp)
85{
86 resp->num_args = LPC_STATE_NUM_ARGS;
87 resp->args = calloc(resp->num_args, sizeof(*resp->args));
88 if ((context->state & MAPS_MEM) && !(context->state & MAPS_FLASH)) {
89 resp->args[0] = LPC_STATE_MEM;
90 } else if (!(context->state & MAPS_MEM) &&
91 (context->state & MAPS_FLASH)) {
92 resp->args[0] = LPC_STATE_FLASH;
93 } else {
94 resp->args[0] = LPC_STATE_INVALID;
95 }
96
97 return 0;
98}
99
100/*
101 * Command: DBUS Reset
102 * Reset the daemon state, final operation TBA.
103 * For now we just point the lpc mapping back at the flash.
104 *
105 * Args: NONE
106 * Resp: NONE
107 */
108static int dbus_handle_reset(struct mbox_context *context,
109 struct mbox_dbus_msg *req,
110 struct mbox_dbus_msg *resp)
111{
112 int rc;
113
114 /* We don't let the host access flash if the daemon is suspened */
115 if (context->state & STATE_SUSPENDED) {
116 return -E_DBUS_REJECTED;
117 }
118
119 /*
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500120 * This will close (and flush) the current window and reset the lpc bus
121 * mapping back to flash, or memory in case we're using a virtual pnor.
122 * Better set the bmc event to notify the host of this.
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100123 */
124 reset_all_windows(context, SET_BMC_EVENT);
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500125 rc = reset_lpc(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100126 if (rc < 0) {
127 return -E_DBUS_HARDWARE;
128 }
129
130 return 0;
131}
132
133/*
134 * Command: DBUS Kill
135 * Stop the daemon
136 *
137 * Args: NONE
138 * Resp: NONE
139 */
140static int dbus_handle_kill(struct mbox_context *context,
141 struct mbox_dbus_msg *req,
142 struct mbox_dbus_msg *resp)
143{
144 context->terminate = 1;
145
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000146 MSG_INFO("DBUS Kill - Exiting...\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100147
148 return 0;
149}
150
151/*
152 * Command: DBUS Flash Modified
153 * Used to notify the daemon that the flash has been modified out from under
154 * it - We need to reset all out windows to ensure flash will be reloaded
155 * when a new window is opened.
156 * Note: We don't flush any previously opened windows
157 *
158 * Args: NONE
159 * Resp: NONE
160 */
161static int dbus_handle_modified(struct mbox_context *context,
162 struct mbox_dbus_msg *req,
163 struct mbox_dbus_msg *resp)
164{
165 /* Flash has been modified - can no longer trust our erased bytemap */
166 set_flash_bytemap(context, 0, context->flash_size, FLASH_DIRTY);
167
168 /* Force daemon to reload all windows -> Set BMC event to notify host */
169 reset_all_windows(context, SET_BMC_EVENT);
170
171 return 0;
172}
173
174/*
175 * Command: DBUS Suspend
176 * Suspend the daemon to inhibit it from performing flash accesses.
177 * This is used to synchronise access to the flash between the daemon and
178 * directly from the BMC.
179 *
180 * Args: NONE
181 * Resp: NONE
182 */
183static int dbus_handle_suspend(struct mbox_context *context,
184 struct mbox_dbus_msg *req,
185 struct mbox_dbus_msg *resp)
186{
187 int rc;
188
189 if (context->state & STATE_SUSPENDED) {
190 /* Already Suspended */
191 return DBUS_SUCCESS;
192 }
193
194 /* Nothing to check - Just set the bit to notify the host */
195 rc = set_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST, SET_BMC_EVENT);
196 if (rc < 0) {
197 return -E_DBUS_HARDWARE;
198 }
199
200 context->state |= STATE_SUSPENDED;
201
202 return rc;
203}
204
205/*
206 * Command: DBUS Resume
207 * Resume the daemon to let it perform flash accesses again.
208 *
209 * Args[0]: Flash Modified (0 - no | 1 - yes)
210 * Resp: NONE
211 */
212static int dbus_handle_resume(struct mbox_context *context,
213 struct mbox_dbus_msg *req,
214 struct mbox_dbus_msg *resp)
215{
216 int rc;
217
218 if (req->num_args != 1) {
219 return -E_DBUS_INVAL;
220 }
221
222 if (!(context->state & STATE_SUSPENDED)) {
223 /* We weren't suspended... */
224 return DBUS_SUCCESS;
225 }
226
227 if (req->args[0] == RESUME_FLASH_MODIFIED) {
Suraj Jitindar Singh7760fd82017-09-20 18:03:35 +1000228 /* Call the flash modified handler */
229 dbus_handle_modified(context, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100230 }
231
Suraj Jitindar Singh7760fd82017-09-20 18:03:35 +1000232 /* Clear the bit and send the BMC Event to the host */
233 rc = clr_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST, SET_BMC_EVENT);
234
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100235 if (rc < 0) {
236 rc = -E_DBUS_HARDWARE;
237 }
238 context->state &= ~STATE_SUSPENDED;
239
240 return rc;
241}
242
243static const mboxd_dbus_handler dbus_handlers[NUM_DBUS_CMDS] = {
244 dbus_handle_ping,
245 dbus_handle_daemon_state,
246 dbus_handle_reset,
247 dbus_handle_suspend,
248 dbus_handle_resume,
249 dbus_handle_modified,
250 dbus_handle_kill,
251 dbus_handle_lpc_state
252};
253
254static int method_cmd(sd_bus_message *m, void *userdata,
255 sd_bus_error *ret_error)
256{
257 struct mbox_dbus_msg req = { 0 }, resp = { 0 };
258 struct mbox_context *context;
259 sd_bus_message *n;
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000260 int rc, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100261
262 context = (struct mbox_context *) userdata;
263 if (!context) {
264 MSG_ERR("DBUS Internal Error\n");
265 rc = -E_DBUS_INTERNAL;
266 goto out;
267 }
268
269 /* Read the command */
270 rc = sd_bus_message_read(m, "y", &req.cmd);
271 if (rc < 0) {
272 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
273 rc = -E_DBUS_INTERNAL;
274 goto out;
275 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000276 MSG_DBG("DBUS request: %u\n", req.cmd);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100277
278 /* Read the args */
279 rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args,
280 &req.num_args);
281 if (rc < 0) {
282 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
283 rc = -E_DBUS_INTERNAL;
284 goto out;
285 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000286 MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args);
287 for (i = 0; i < req.num_args; i++) {
288 MSG_DBG("DBUS arg[%d]: %u\n", i, req.args[i]);
289 }
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100290
291 /* Handle the command */
292 if (req.cmd >= NUM_DBUS_CMDS) {
293 rc = -E_DBUS_INVAL;
294 MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd);
295 } else {
296 rc = dbus_handlers[req.cmd](context, &req, &resp);
297 }
298
299out:
300 if (rc < 0) {
301 resp.cmd = -rc;
302 }
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930303 rc = sd_bus_message_new_method_return(m, &n); /* Generate response */
304 if (rc < 0) {
305 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
306 goto cleanup;
307 }
308
309 rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
310 if (rc < 0) {
311 MSG_ERR("sd_bus_message_append failed: %d\n", rc);
312 goto cleanup;
313 }
314
315 rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
316 if (rc < 0) {
317 MSG_ERR("sd_bus_message_append_array failed: %d\n", rc);
318 goto cleanup;
319 }
320
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000321 MSG_DBG("DBUS response: %u\n", resp.cmd);
322 MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args);
323 for (i = 0; i < resp.num_args; i++) {
324 MSG_DBG("DBUS arg[%d]: %u\n", i, resp.args[i]);
325 }
326
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930327 rc = sd_bus_send(NULL, n, NULL); /* Send response */
328 if (rc < 0)
329 MSG_ERR("sd_bus_send failed: %d\n", rc);
330
331cleanup:
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100332 free(resp.args);
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930333 return rc;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100334}
335
336static const sd_bus_vtable mboxd_vtable[] = {
337 SD_BUS_VTABLE_START(0),
338 SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd,
339 SD_BUS_VTABLE_UNPRIVILEGED),
340 SD_BUS_VTABLE_END
341};
342
Andrew Jefferyba0bbab2018-08-06 09:43:57 +0930343int mboxd_dbus_init(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100344{
345 int rc;
346
347 rc = sd_bus_default_system(&context->bus);
348 if (rc < 0) {
349 MSG_ERR("Failed to connect to the system bus: %s\n",
350 strerror(-rc));
351 return rc;
352 }
353
354 rc = sd_bus_add_object_vtable(context->bus, NULL, DOBJ_NAME, DBUS_NAME,
355 mboxd_vtable, context);
356 if (rc < 0) {
357 MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
358 return rc;
359 }
360
361 rc = sd_bus_request_name(context->bus, DBUS_NAME,
362 SD_BUS_NAME_ALLOW_REPLACEMENT |
363 SD_BUS_NAME_REPLACE_EXISTING);
364 if (rc < 0) {
365 MSG_ERR("Failed to acquire service name: %s\n", strerror(-rc));
366 return rc;
367 }
368
369 rc = sd_bus_get_fd(context->bus);
370 if (rc < 0) {
371 MSG_ERR("Failed to get bus fd: %s\n", strerror(-rc));
372 return rc;
373 }
374
375 context->fds[DBUS_FD].fd = rc;
376
377 return 0;
378}
379
Andrew Jefferyba0bbab2018-08-06 09:43:57 +0930380void mboxd_dbus_free(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100381{
382 sd_bus_unref(context->bus);
383}