blob: 8ef9ea96a2e0325838070ae3404a3a0e09646e03 [file] [log] [blame]
Andrew Jeffery68023072018-08-06 10:08:11 +09301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
3#include <errno.h>
4#include <stdlib.h>
5
6#include "common.h"
7#include "dbus.h"
Andrew Jeffery55f4d6f2018-08-06 12:26:44 +09308#include "control_dbus.h"
Andrew Jeffery68023072018-08-06 10:08:11 +09309#include "mbox.h"
10
Andrew Jefferyef9e62d2018-08-08 15:48:27 +093011/* Command IDs (Legacy interface) */
12#define DBUS_C_PING 0x00
13#define DBUS_C_DAEMON_STATE 0x01
14#define DBUS_C_RESET 0x02
15#define DBUS_C_SUSPEND 0x03
16#define DBUS_C_RESUME 0x04
17#define DBUS_C_MODIFIED 0x05
18#define DBUS_C_KILL 0x06
19#define DBUS_C_LPC_STATE 0x07
20#define NUM_DBUS_CMDS (DBUS_C_LPC_STATE + 1)
21
22/* Return Values (Legacy interface) */
23#define DBUS_SUCCESS 0x00 /* Command Succeded */
24#define E_DBUS_INTERNAL 0x01 /* Internal DBUS Error */
25#define E_DBUS_INVAL 0x02 /* Invalid Command */
26#define E_DBUS_REJECTED 0x03 /* Daemon Rejected Request */
27#define E_DBUS_HARDWARE 0x04 /* BMC Hardware Error */
28#define E_DBUS_NO_MEM 0x05 /* Failed Memory Allocation */
29
30struct mbox_dbus_msg {
31 uint8_t cmd;
32 size_t num_args;
33 uint8_t *args;
34};
35
Andrew Jeffery68023072018-08-06 10:08:11 +093036/*
37 * Command: DBUS Ping
38 * Ping the daemon
39 *
40 * Args: NONE
41 * Resp: NONE
42 */
43static int control_legacy_ping(struct mbox_context *context,
44 struct mbox_dbus_msg *req,
45 struct mbox_dbus_msg *resp)
46{
47 return control_ping(context);
48}
49
50/*
51 * Command: DBUS Status
52 * Get the status of the daemon
53 *
54 * Args: NONE
55 * Resp[0]: Status Code
56 */
57static int control_legacy_daemon_state(struct mbox_context *context,
58 struct mbox_dbus_msg *req,
59 struct mbox_dbus_msg *resp)
60{
61 resp->num_args = DAEMON_STATE_NUM_ARGS;
62 resp->args = calloc(resp->num_args, sizeof(*resp->args));
63 resp->args[0] = control_daemon_state(context);
64
65 return 0;
66}
67
68/*
69 * Command: DBUS LPC State
70 * Get the state of the lpc bus mapping (whether it points to memory or flash
71 *
72 * Args: NONE
73 * Resp[0]: LPC Bus State Code
74 */
75static int control_legacy_lpc_state(struct mbox_context *context,
76 struct mbox_dbus_msg *req,
77 struct mbox_dbus_msg *resp)
78{
79 resp->num_args = LPC_STATE_NUM_ARGS;
80 resp->args = calloc(resp->num_args, sizeof(*resp->args));
81 resp->args[0] = control_lpc_state(context);
82
83 return 0;
84}
85
86/*
87 * Command: DBUS Reset
88 * Reset the daemon state, final operation TBA.
89 * For now we just point the lpc mapping back at the flash.
90 *
91 * Args: NONE
92 * Resp: NONE
93 */
94static int control_legacy_reset(struct mbox_context *context,
95 struct mbox_dbus_msg *req,
96 struct mbox_dbus_msg *resp)
97{
98 int rc;
99
100 rc = control_reset(context);
101
102 /* Map return codes for compatibility */
103 if (rc == -EBUSY) {
104 return -E_DBUS_REJECTED;
105 } else if (rc < 0) {
106 return -E_DBUS_HARDWARE;
107 }
108
109 return rc;
110}
111
112/*
113 * Command: DBUS Kill
114 * Stop the daemon
115 *
116 * Args: NONE
117 * Resp: NONE
118 */
119static int control_legacy_kill(struct mbox_context *context,
120 struct mbox_dbus_msg *req,
121 struct mbox_dbus_msg *resp)
122{
123 return control_kill(context);
124}
125
126/*
127 * Command: DBUS Flash Modified
128 * Used to notify the daemon that the flash has been modified out from under
129 * it - We need to reset all out windows to ensure flash will be reloaded
130 * when a new window is opened.
131 * Note: We don't flush any previously opened windows
132 *
133 * Args: NONE
134 * Resp: NONE
135 */
136static int control_legacy_modified(struct mbox_context *context,
137 struct mbox_dbus_msg *req,
138 struct mbox_dbus_msg *resp)
139{
140 return control_modified(context);
141}
142
143/*
144 * Command: DBUS Suspend
145 * Suspend the daemon to inhibit it from performing flash accesses.
146 * This is used to synchronise access to the flash between the daemon and
147 * directly from the BMC.
148 *
149 * Args: NONE
150 * Resp: NONE
151 */
152static int control_legacy_suspend(struct mbox_context *context,
153 struct mbox_dbus_msg *req,
154 struct mbox_dbus_msg *resp)
155{
156 int rc;
157
158 rc = control_suspend(context);
159 if (rc < 0) {
160 /* Map return codes for compatibility */
161 return -E_DBUS_HARDWARE;
162 }
163
164 return rc;
165}
166
167/*
168 * Command: DBUS Resume
169 * Resume the daemon to let it perform flash accesses again.
170 *
171 * Args[0]: Flash Modified (0 - no | 1 - yes)
172 * Resp: NONE
173 */
174static int control_legacy_resume(struct mbox_context *context,
175 struct mbox_dbus_msg *req,
176 struct mbox_dbus_msg *resp)
177{
178 int rc;
179
180 if (req->num_args != 1) {
181 return -E_DBUS_INVAL;
182 }
183
184 rc = control_resume(context, req->args[0] == RESUME_FLASH_MODIFIED);
185 if (rc < 0) {
186 /* Map return codes for compatibility */
187 rc = -E_DBUS_HARDWARE;
188 }
189
190 return rc;
191}
192
193typedef int (*control_action)(struct mbox_context *context,
194 struct mbox_dbus_msg *req,
195 struct mbox_dbus_msg *resp);
196static const control_action dbus_handlers[NUM_DBUS_CMDS] = {
197 control_legacy_ping,
198 control_legacy_daemon_state,
199 control_legacy_reset,
200 control_legacy_suspend,
201 control_legacy_resume,
202 control_legacy_modified,
203 control_legacy_kill,
204 control_legacy_lpc_state
205};
206
207static int method_cmd(sd_bus_message *m, void *userdata,
208 sd_bus_error *ret_error)
209{
210 struct mbox_dbus_msg req = { 0 }, resp = { 0 };
211 struct mbox_context *context;
212 sd_bus_message *n;
213 int rc, i;
214
215 context = (struct mbox_context *) userdata;
216 if (!context) {
217 MSG_ERR("DBUS Internal Error\n");
218 rc = -E_DBUS_INTERNAL;
219 goto out;
220 }
221
222 /* Read the command */
223 rc = sd_bus_message_read(m, "y", &req.cmd);
224 if (rc < 0) {
225 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
226 rc = -E_DBUS_INTERNAL;
227 goto out;
228 }
229 MSG_DBG("DBUS request: %u\n", req.cmd);
230
231 /* Read the args */
232 rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args,
233 &req.num_args);
234 if (rc < 0) {
235 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
236 rc = -E_DBUS_INTERNAL;
237 goto out;
238 }
239 MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args);
240 for (i = 0; i < req.num_args; i++) {
241 MSG_DBG("DBUS arg[%d]: %u\n", i, req.args[i]);
242 }
243
244 /* Handle the command */
245 if (req.cmd >= NUM_DBUS_CMDS) {
246 rc = -E_DBUS_INVAL;
247 MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd);
248 } else {
249 rc = dbus_handlers[req.cmd](context, &req, &resp);
250 }
251
252out:
253 if (rc < 0) {
254 resp.cmd = -rc;
255 }
256 rc = sd_bus_message_new_method_return(m, &n); /* Generate response */
257 if (rc < 0) {
258 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
259 goto cleanup;
260 }
261
262 rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
263 if (rc < 0) {
264 MSG_ERR("sd_bus_message_append failed: %d\n", rc);
265 goto cleanup;
266 }
267
268 rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
269 if (rc < 0) {
270 MSG_ERR("sd_bus_message_append_array failed: %d\n", rc);
271 goto cleanup;
272 }
273
274 MSG_DBG("DBUS response: %u\n", resp.cmd);
275 MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args);
276 for (i = 0; i < resp.num_args; i++) {
277 MSG_DBG("DBUS arg[%d]: %u\n", i, resp.args[i]);
278 }
279
280 rc = sd_bus_send(NULL, n, NULL); /* Send response */
281 if (rc < 0)
282 MSG_ERR("sd_bus_send failed: %d\n", rc);
283
284cleanup:
285 free(resp.args);
286 return rc;
287}
288
289static const sd_bus_vtable control_legacy_vtable[] = {
290 SD_BUS_VTABLE_START(0),
291 SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd,
292 SD_BUS_VTABLE_UNPRIVILEGED),
293 SD_BUS_VTABLE_END
294};
295
296int control_legacy_init(struct mbox_context *context)
297{
298 int rc;
299
300 rc = sd_bus_add_object_vtable(context->bus, NULL,
301 MBOX_DBUS_LEGACY_OBJECT,
302 MBOX_DBUS_LEGACY_NAME,
303 control_legacy_vtable, context);
304 if (rc < 0) {
305 MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
306 return rc;
307 }
308
309 return sd_bus_request_name(context->bus, MBOX_DBUS_LEGACY_NAME,
310 SD_BUS_NAME_ALLOW_REPLACEMENT |
311 SD_BUS_NAME_REPLACE_EXISTING);
312}
313
314void control_legacy_free(struct mbox_context *context __attribute__((unused)))
315{
316 return;
317}