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