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