xref: /openbmc/hiomapd/transport_mbox.c (revision d86141b6)
1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (C) 2018 IBM Corp.
3 
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 
27 #include "mbox.h"
28 #include "common.h"
29 #include "transport_mbox.h"
30 #include "windows.h"
31 #include "lpc.h"
32 
33 struct errno_map {
34 	int rc;
35 	int mbox_errno;
36 };
37 
38 static const struct errno_map errno_map_v1[] = {
39 	{ 0, MBOX_R_SUCCESS },
40 	{ EACCES, MBOX_R_PARAM_ERROR },
41 	{ EBADMSG, MBOX_R_PARAM_ERROR },
42 	{ EBUSY, MBOX_R_SYSTEM_ERROR },
43 	{ EINVAL, MBOX_R_PARAM_ERROR },
44 	{ ENOTSUP, MBOX_R_PARAM_ERROR },
45 	{ EPERM, MBOX_R_PARAM_ERROR },
46 	{ EPROTO, MBOX_R_PARAM_ERROR },
47 	{ ETIMEDOUT, MBOX_R_TIMEOUT },
48 	{ -1, MBOX_R_SYSTEM_ERROR },
49 };
50 
51 static const struct errno_map errno_map_v2[] = {
52 	{ 0, MBOX_R_SUCCESS },
53 	{ EACCES, MBOX_R_WINDOW_ERROR },
54 	{ EBADMSG, MBOX_R_SEQ_ERROR },
55 	{ EBUSY, MBOX_R_BUSY },
56 	{ EINVAL, MBOX_R_PARAM_ERROR },
57 	{ ENOTSUP, MBOX_R_PARAM_ERROR },
58 	{ EPERM, MBOX_R_WINDOW_ERROR },
59 	{ EPROTO, MBOX_R_PARAM_ERROR },
60 	{ ETIMEDOUT, MBOX_R_TIMEOUT },
61 	{ -1, MBOX_R_SYSTEM_ERROR },
62 };
63 
64 static const struct errno_map *errno_maps[] = {
65 	[0] = NULL,
66 	[1] = errno_map_v1,
67 	[2] = errno_map_v2,
68 };
69 
70 static inline int mbox_xlate_errno(struct mbox_context *context,
71 					     int rc)
72 {
73 	const struct errno_map *entry;
74 
75 	rc = -rc;
76 	MSG_DBG("Translating errno %d: %s\n", rc, strerror(rc));
77 	for(entry = errno_maps[context->version]; entry->rc != -1; entry++) {
78 		if (rc == entry->rc) {
79 			return entry->mbox_errno;
80 		}
81 	}
82 
83 	return entry->mbox_errno;
84 }
85 
86 /*
87  * transport_mbox_flush_events() - Write to the BMC controlled status register
88  * 				   (reg 15)
89  * @context:	The mbox context pointer
90  *
91  * Return:	0 on success otherwise negative error code
92  */
93 static int transport_mbox_flush_events(struct mbox_context *context)
94 {
95 	int rc;
96 
97 	/* Seek mbox registers */
98 	rc = lseek(context->fds[MBOX_FD].fd, MBOX_BMC_EVENT, SEEK_SET);
99 	if (rc != MBOX_BMC_EVENT) {
100 		MSG_ERR("Couldn't lseek mbox to byte %d: %s\n", MBOX_BMC_EVENT,
101 				strerror(errno));
102 		return -errno;
103 	}
104 
105 	/* Write to mbox status register */
106 	rc = write(context->fds[MBOX_FD].fd, &context->bmc_events, 1);
107 	if (rc != 1) {
108 		MSG_ERR("Couldn't write to BMC status reg: %s\n",
109 				strerror(errno));
110 		return -errno;
111 	}
112 
113 	/* Reset to start */
114 	rc = lseek(context->fds[MBOX_FD].fd, 0, SEEK_SET);
115 	if (rc) {
116 		MSG_ERR("Couldn't reset MBOX offset to zero: %s\n",
117 				strerror(errno));
118 		return -errno;
119 	}
120 
121 	return 0;
122 }
123 
124 /* Command Handlers */
125 
126 /*
127  * Command: RESET_STATE
128  * Reset the LPC mapping to point back at the flash, or memory in case we're
129  * using a virtual pnor.
130  */
131 static int mbox_handle_reset(struct mbox_context *context,
132 			     union mbox_regs *req, struct mbox_msg *resp)
133 {
134 	return context->protocol->reset(context);
135 }
136 
137 /*
138  * Command: GET_MBOX_INFO
139  * Get the API version, default window size and block size
140  * We also set the LPC mapping to point to the reserved memory region here so
141  * this command must be called before any window manipulation
142  *
143  * V1:
144  * ARGS[0]: API Version
145  *
146  * RESP[0]: API Version
147  * RESP[1:2]: Default read window size (number of blocks)
148  * RESP[3:4]: Default write window size (number of blocks)
149  * RESP[5]: Block size (as shift)
150  *
151  * V2:
152  * ARGS[0]: API Version
153  *
154  * RESP[0]: API Version
155  * RESP[1:2]: Default read window size (number of blocks)
156  * RESP[3:4]: Default write window size (number of blocks)
157  * RESP[5]: Block size (as shift)
158  */
159 static int mbox_handle_mbox_info(struct mbox_context *context,
160 				 union mbox_regs *req, struct mbox_msg *resp)
161 {
162 	uint8_t mbox_api_version = req->msg.args[0];
163 	struct protocol_get_info io = {
164 		.req = { .api_version = mbox_api_version }
165 	};
166 	int rc;
167 
168 	rc = context->protocol->get_info(context, &io);
169 	if (rc < 0) {
170 		return rc;
171 	}
172 
173 	resp->args[0] = io.resp.api_version;
174 	if (io.resp.api_version == API_VERSION_1) {
175 		put_u16(&resp->args[1], io.resp.v1.read_window_size);
176 		put_u16(&resp->args[3], io.resp.v1.write_window_size);
177 	} else if (io.resp.api_version >= API_VERSION_2) {
178 		resp->args[5] = io.resp.v2.block_size_shift;
179 		put_u16(&resp->args[6], io.resp.v2.timeout);
180 	}
181 
182 	return 0;
183 }
184 
185 /*
186  * Command: GET_FLASH_INFO
187  * Get the flash size and erase granularity
188  *
189  * V1:
190  * RESP[0:3]: Flash Size (bytes)
191  * RESP[4:7]: Erase Size (bytes)
192  * V2:
193  * RESP[0:1]: Flash Size (number of blocks)
194  * RESP[2:3]: Erase Size (number of blocks)
195  */
196 static int mbox_handle_flash_info(struct mbox_context *context,
197 				  union mbox_regs *req, struct mbox_msg *resp)
198 {
199 	struct protocol_get_flash_info io;
200 	int rc;
201 
202 	rc = context->protocol->get_flash_info(context, &io);
203 	if (rc < 0) {
204 		return rc;
205 	}
206 
207 	switch (context->version) {
208 	case API_VERSION_1:
209 		/* Both Sizes in Bytes */
210 		put_u32(&resp->args[0], io.resp.v1.flash_size);
211 		put_u32(&resp->args[4], io.resp.v1.erase_size);
212 		break;
213 	case API_VERSION_2:
214 		/* Both Sizes in Block Size */
215 		put_u16(&resp->args[0], io.resp.v2.flash_size);
216 		put_u16(&resp->args[2], io.resp.v2.erase_size);
217 		break;
218 	default:
219 		MSG_ERR("API Version Not Valid - Invalid System State\n");
220 		return -MBOX_R_SYSTEM_ERROR;
221 	}
222 
223 	return 0;
224 }
225 
226 /*
227  * get_lpc_addr_shifted() - Get lpc address of the current window
228  * @context:		The mbox context pointer
229  *
230  * Return:	The lpc address to access that offset shifted by block size
231  */
232 static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
233 {
234 	uint32_t lpc_addr, mem_offset;
235 
236 	/* Offset of the current window in the reserved memory region */
237 	mem_offset = context->current->mem - context->mem;
238 	/* Total LPC Address */
239 	lpc_addr = context->lpc_base + mem_offset;
240 
241 	MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
242 
243 	return lpc_addr >> context->block_size_shift;
244 }
245 
246 static int mbox_handle_create_window(struct mbox_context *context, bool ro,
247 			      union mbox_regs *req, struct mbox_msg *resp)
248 {
249 	struct protocol_create_window io;
250 	int rc;
251 
252 	io.req.offset = get_u16(&req->msg.args[0]);
253 	io.req.ro = ro;
254 
255 	rc = context->protocol->create_window(context, &io);
256 	if (rc < 0) {
257 		return rc;
258 	}
259 
260 	put_u16(&resp->args[0], io.resp.lpc_address);
261 	if (context->version >= API_VERSION_2) {
262 		put_u16(&resp->args[2], io.resp.size);
263 		put_u16(&resp->args[4], io.resp.offset);
264 	}
265 
266 	return 0;
267 }
268 
269 /*
270  * Command: CREATE_READ_WINDOW
271  * Opens a read window
272  * First checks if any current window with the requested data, if so we just
273  * point the host to that. Otherwise we read the request data in from flash and
274  * point the host there.
275  *
276  * V1:
277  * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
278  *
279  * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
280  *
281  * V2:
282  * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
283  * ARGS[2:3]: Requested window size (number of blocks)
284  *
285  * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
286  * RESP[2:3]: Actual window size that the host can access (number of blocks)
287  */
288 static int mbox_handle_read_window(struct mbox_context *context,
289 				   union mbox_regs *req, struct mbox_msg *resp)
290 {
291 	return mbox_handle_create_window(context, true, req, resp);
292 }
293 
294 /*
295  * Command: CREATE_WRITE_WINDOW
296  * Opens a write window
297  * First checks if any current window with the requested data, if so we just
298  * point the host to that. Otherwise we read the request data in from flash and
299  * point the host there.
300  *
301  * V1:
302  * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
303  *
304  * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
305  *
306  * V2:
307  * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
308  * ARGS[2:3]: Requested window size (number of blocks)
309  *
310  * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
311  * RESP[2:3]: Actual window size that was mapped/host can access (n.o. blocks)
312  */
313 static int mbox_handle_write_window(struct mbox_context *context,
314 				    union mbox_regs *req, struct mbox_msg *resp)
315 {
316 	return mbox_handle_create_window(context, false, req, resp);
317 }
318 
319 /*
320  * Commands: MARK_WRITE_DIRTY
321  * Marks a portion of the current (write) window dirty, informing the daemon
322  * that is has been written to and thus must be at some point written to the
323  * backing store
324  * These changes aren't written back to the backing store unless flush is then
325  * called or the window closed
326  *
327  * V1:
328  * ARGS[0:1]: Where within flash to start (number of blocks)
329  * ARGS[2:5]: Number to mark dirty (number of bytes)
330  *
331  * V2:
332  * ARGS[0:1]: Where within window to start (number of blocks)
333  * ARGS[2:3]: Number to mark dirty (number of blocks)
334  */
335 static int mbox_handle_dirty_window(struct mbox_context *context,
336 				    union mbox_regs *req, struct mbox_msg *resp)
337 {
338 	struct protocol_mark_dirty io;
339 
340 	if (context->version == API_VERSION_1) {
341 		io.req.v1.offset = get_u16(&req->msg.args[0]);
342 		io.req.v1.size = get_u32(&req->msg.args[2]);
343 	} else {
344 		io.req.v2.offset = get_u16(&req->msg.args[0]);
345 		io.req.v2.size = get_u16(&req->msg.args[2]);
346 	}
347 
348 	return context->protocol->mark_dirty(context, &io);
349 }
350 
351 /*
352  * Commands: MARK_WRITE_ERASE
353  * Erases a portion of the current window
354  * These changes aren't written back to the backing store unless flush is then
355  * called or the window closed
356  *
357  * V1:
358  * Unimplemented
359  *
360  * V2:
361  * ARGS[0:1]: Where within window to start (number of blocks)
362  * ARGS[2:3]: Number to erase (number of blocks)
363  */
364 static int mbox_handle_erase_window(struct mbox_context *context,
365 				    union mbox_regs *req, struct mbox_msg *resp)
366 {
367 	struct protocol_erase io;
368 
369 	io.req.offset = get_u16(&req->msg.args[0]);
370 	io.req.size = get_u16(&req->msg.args[2]);
371 
372 	if (!context->protocol->erase) {
373 		MSG_ERR("Protocol Version invalid for Erase Command\n");
374 		return -ENOTSUP;
375 	}
376 
377 	return context->protocol->erase(context, &io);
378 }
379 
380 /*
381  * Command: WRITE_FLUSH
382  * Flushes any dirty or erased blocks in the current window back to the backing
383  * store
384  * NOTE: For V1 this behaves much the same as the dirty command in that it
385  * takes an offset and number of blocks to dirty, then also performs a flush as
386  * part of the same command. For V2 this will only flush blocks already marked
387  * dirty/erased with the appropriate commands and doesn't take any arguments
388  * directly.
389  *
390  * V1:
391  * ARGS[0:1]: Where within window to start (number of blocks)
392  * ARGS[2:5]: Number to mark dirty (number of bytes)
393  *
394  * V2:
395  * NONE
396  */
397 static int mbox_handle_flush_window(struct mbox_context *context,
398 				    union mbox_regs *req, struct mbox_msg *resp)
399 {
400 	struct protocol_flush io = { 0 };
401 
402 	if (context->version == API_VERSION_1) {
403 		io.req.offset = get_u16(&req->msg.args[0]);
404 		io.req.size = get_u32(&req->msg.args[2]);
405 	}
406 
407 	return context->protocol->flush(context, &io);
408 }
409 
410 /*
411  * Command: CLOSE_WINDOW
412  * Close the current window
413  * NOTE: There is an implicit flush
414  *
415  * V1:
416  * NONE
417  *
418  * V2:
419  * ARGS[0]: FLAGS
420  */
421 static int mbox_handle_close_window(struct mbox_context *context,
422 				    union mbox_regs *req, struct mbox_msg *resp)
423 {
424 	struct protocol_close io = { 0 };
425 
426 	if (context->version >= API_VERSION_2) {
427 		io.req.flags = req->msg.args[0];
428 	}
429 
430 	return context->protocol->close(context, &io);
431 }
432 
433 /*
434  * Command: BMC_EVENT_ACK
435  * Sent by the host to acknowledge BMC events supplied in mailbox register 15
436  *
437  * ARGS[0]: Bitmap of bits to ack (by clearing)
438  */
439 static int mbox_handle_ack(struct mbox_context *context, union mbox_regs *req,
440 			   struct mbox_msg *resp)
441 {
442 	struct protocol_ack io;
443 
444 	io.req.flags = req->msg.args[0];
445 
446 	return context->protocol->ack(context, &io);
447 }
448 
449 /*
450  * check_req_valid() - Check if the given request is a valid mbox request
451  * @context:	The mbox context pointer
452  * @cmd:	The request registers
453  *
454  * Return:	0 if request is valid otherwise negative error code
455  */
456 static int check_req_valid(struct mbox_context *context, union mbox_regs *req)
457 {
458 	uint8_t cmd = req->msg.command;
459 	uint8_t seq = req->msg.seq;
460 
461 	if (cmd > NUM_MBOX_CMDS) {
462 		MSG_ERR("Unknown mbox command: %d\n", cmd);
463 		return -ENOTSUP;
464 	}
465 
466 	if (seq == context->prev_seq && cmd != MBOX_C_GET_MBOX_INFO) {
467 		MSG_ERR("Invalid sequence number: %d, previous: %d\n", seq,
468 			context->prev_seq);
469 		return -EBADMSG;
470 	}
471 
472 	if (context->state & STATE_SUSPENDED) {
473 		if (cmd != MBOX_C_GET_MBOX_INFO && cmd != MBOX_C_ACK) {
474 			MSG_ERR("Cannot use that cmd while suspended: %d\n",
475 				cmd);
476 			return -EBUSY;
477 		}
478 	}
479 
480 	if (!(context->state & MAPS_MEM)) {
481 		if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO
482 					      && cmd != MBOX_C_ACK) {
483 			MSG_ERR("Must call GET_MBOX_INFO before %d\n", cmd);
484 			return -EPROTO;
485 		}
486 	}
487 
488 	return 0;
489 }
490 
491 typedef int (*mboxd_mbox_handler)(struct mbox_context *, union mbox_regs *,
492 				  struct mbox_msg *);
493 
494 static const mboxd_mbox_handler transport_mbox_handlers[] = {
495 	mbox_handle_reset,
496 	mbox_handle_mbox_info,
497 	mbox_handle_flash_info,
498 	mbox_handle_read_window,
499 	mbox_handle_close_window,
500 	mbox_handle_write_window,
501 	mbox_handle_dirty_window,
502 	mbox_handle_flush_window,
503 	mbox_handle_ack,
504 	mbox_handle_erase_window
505 };
506 
507 /*
508  * handle_mbox_req() - Handle an incoming mbox command request
509  * @context:	The mbox context pointer
510  * @req:	The mbox request message
511  *
512  * Return:	0 if handled successfully otherwise negative error code
513  */
514 static int handle_mbox_req(struct mbox_context *context, union mbox_regs *req)
515 {
516 	struct mbox_msg resp = {
517 		.command = req->msg.command,
518 		.seq = req->msg.seq,
519 		.args = { 0 },
520 		.response = MBOX_R_SUCCESS
521 	};
522 	int rc = 0, len, i;
523 
524 	MSG_INFO("Received MBOX command: %u\n", req->msg.command);
525 	rc = check_req_valid(context, req);
526 	if (!rc) {
527 		mboxd_mbox_handler handler;
528 
529 		/* Commands start at 1 so we have to subtract 1 from the cmd */
530 		handler = transport_mbox_handlers[req->msg.command - 1];
531 		rc = handler(context, req, &resp);
532 		if (rc < 0) {
533 			MSG_ERR("Error handling mbox cmd: %d\n",
534 				req->msg.command);
535 		}
536 	}
537 
538 	rc = mbox_xlate_errno(context, rc);
539 	resp.response = rc;
540 	context->prev_seq = req->msg.seq;
541 
542 	MSG_DBG("Writing MBOX response:\n");
543 	MSG_DBG("MBOX cmd: %u\n", resp.command);
544 	MSG_DBG("MBOX seq: %u\n", resp.seq);
545 	for (i = 0; i < MBOX_ARGS_BYTES; i++) {
546 		MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, resp.args[i]);
547 	}
548 	MSG_INFO("Writing MBOX response: %u\n", resp.response);
549 	len = write(context->fds[MBOX_FD].fd, &resp, sizeof(resp));
550 	if (len < sizeof(resp)) {
551 		MSG_ERR("Didn't write the full response\n");
552 		rc = -errno;
553 	}
554 
555 	return rc;
556 }
557 
558 /*
559  * get_message() - Read an mbox request message from the mbox registers
560  * @context:	The mbox context pointer
561  * @msg:	Where to put the received message
562  *
563  * Return:	0 if read successfully otherwise negative error code
564  */
565 static int get_message(struct mbox_context *context, union mbox_regs *msg)
566 {
567 	int rc, i;
568 
569 	rc = read(context->fds[MBOX_FD].fd, msg, sizeof(msg->raw));
570 	if (rc < 0) {
571 		MSG_ERR("Couldn't read: %s\n", strerror(errno));
572 		return -errno;
573 	} else if (rc < sizeof(msg->raw)) {
574 		MSG_ERR("Short read: %d expecting %zu\n", rc, sizeof(msg->raw));
575 		return -1;
576 	}
577 
578 	MSG_DBG("Received MBOX request:\n");
579 	MSG_DBG("MBOX cmd: %u\n", msg->msg.command);
580 	MSG_DBG("MBOX seq: %u\n", msg->msg.seq);
581 	for (i = 0; i < MBOX_ARGS_BYTES; i++) {
582 		MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, msg->msg.args[i]);
583 	}
584 
585 	return 0;
586 }
587 
588 /*
589  * transport_mbox_dispatch() - handle an mbox interrupt
590  * @context:	The mbox context pointer
591  *
592  * Return:	0 if handled successfully otherwise negative error code
593  */
594 int transport_mbox_dispatch(struct mbox_context *context)
595 {
596 	int rc = 0;
597 	union mbox_regs req = { 0 };
598 
599 	assert(context);
600 
601 	rc = get_message(context, &req);
602 	if (rc) {
603 		return rc;
604 	}
605 
606 	return handle_mbox_req(context, &req);
607 }
608 
609 static const struct transport_ops transport_mbox_ops = {
610 	.flush_events = transport_mbox_flush_events,
611 };
612 
613 int __init_mbox_dev(struct mbox_context *context, const char *path)
614 {
615 	int fd;
616 
617 	context->transport = &transport_mbox_ops;
618 
619 	/* Open MBOX Device */
620 	fd = open(path, O_RDWR | O_NONBLOCK);
621 	if (fd < 0) {
622 		MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
623 			path, strerror(errno));
624 		return -errno;
625 	}
626 	MSG_DBG("Opened mbox dev: %s\n", path);
627 
628 	context->fds[MBOX_FD].fd = fd;
629 
630 	return 0;
631 }
632 
633 int init_mbox_dev(struct mbox_context *context)
634 {
635 	return __init_mbox_dev(context, MBOX_HOST_PATH);
636 }
637 
638 void free_mbox_dev(struct mbox_context *context)
639 {
640 	close(context->fds[MBOX_FD].fd);
641 }
642