xref: /openbmc/hiomapd/control_legacy.c (revision f1e547c7)
1 // 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"
8 #include "control_dbus.h"
9 #include "mboxd.h"
10 
11 /* 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 
30 struct mbox_dbus_msg {
31        uint8_t cmd;
32        size_t num_args;
33        uint8_t *args;
34 };
35 
36 /*
37  * Command: DBUS Ping
38  * Ping the daemon
39  *
40  * Args: NONE
41  * Resp: NONE
42  */
43 static 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  */
57 static 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  */
75 static 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  */
94 static 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  */
119 static 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  */
136 static 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  */
152 static 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  */
174 static 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 
193 typedef int (*control_action)(struct mbox_context *context,
194 				 struct mbox_dbus_msg *req,
195 				 struct mbox_dbus_msg *resp);
196 static 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 
207 static 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 
252 out:
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 
284 cleanup:
285 	free(resp.args);
286 	return rc;
287 }
288 
289 static 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 
296 int 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 
314 void control_legacy_free(struct mbox_context *context __attribute__((unused)))
315 {
316 	return;
317 }
318