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