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