1 /* 2 * Mailbox Daemon Window Helpers 3 * 4 * Copyright 2016 IBM 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 */ 19 20 #define _GNU_SOURCE 21 #include <assert.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <getopt.h> 25 #include <limits.h> 26 #include <poll.h> 27 #include <stdbool.h> 28 #include <stdint.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <syslog.h> 33 #include <signal.h> 34 #include <sys/ioctl.h> 35 #include <sys/mman.h> 36 #include <sys/stat.h> 37 #include <sys/timerfd.h> 38 #include <sys/types.h> 39 #include <time.h> 40 #include <unistd.h> 41 #include <inttypes.h> 42 #include <mtd/mtd-abi.h> 43 44 #include "mbox.h" 45 #include "common.h" 46 #include "mboxd_msg.h" 47 #include "mboxd_windows.h" 48 #include "mboxd_flash.h" 49 50 /* Initialisation Functions */ 51 52 /* 53 * init_window_state() - Initialise a new window to a known state 54 * @window: The window to initialise 55 * @size: The size of the window 56 */ 57 static void init_window_state(struct window_context *window, uint32_t size) 58 { 59 window->mem = NULL; 60 window->flash_offset = FLASH_OFFSET_UNINIT; 61 window->size = size; 62 window->dirty_bmap = NULL; 63 window->age = 0; 64 } 65 66 /* 67 * init_window_mem() - Divide the reserved memory region among the windows 68 * @context: The mbox context pointer 69 * 70 * Return: 0 on success otherwise negative error code 71 */ 72 static int init_window_mem(struct mbox_context *context) 73 { 74 void *mem_location = context->mem; 75 int i; 76 77 /* 78 * Carve up the reserved memory region and allocate it to each of the 79 * windows. The windows are placed one after the other in ascending 80 * order, so the first window will be first in memory and so on. We 81 * shouldn't have allocated more windows than we have memory, but if we 82 * did we will error out here 83 */ 84 for (i = 0; i < context->windows.num; i++) { 85 uint32_t size = context->windows.window[i].size; 86 MSG_DBG("Window %d @ %p for size 0x%.8x\n", i, 87 mem_location, size); 88 context->windows.window[i].mem = mem_location; 89 mem_location += size; 90 if (mem_location > (context->mem + context->mem_size)) { 91 /* Tried to allocate window past the end of memory */ 92 MSG_ERR("Total size of windows exceeds reserved mem\n"); 93 MSG_ERR("Try smaller or fewer windows\n"); 94 MSG_ERR("Mem size: 0x%.8x\n", context->mem_size); 95 return -1; 96 } 97 } 98 99 return 0; 100 } 101 /* 102 * init_windows() - Initalise the window cache 103 * @context: The mbox context pointer 104 * 105 * Return: 0 on success otherwise negative 106 */ 107 int init_windows(struct mbox_context *context) 108 { 109 int i; 110 111 /* Check if window size and number set - otherwise set to default */ 112 if (!context->windows.default_size) { 113 /* Default to 1MB windows */ 114 context->windows.default_size = 1 << 20; 115 } 116 MSG_INFO("Window size: 0x%.8x\n", context->windows.default_size); 117 if (!context->windows.num) { 118 /* Use the entire reserved memory region by default */ 119 context->windows.num = context->mem_size / 120 context->windows.default_size; 121 } 122 MSG_INFO("Number of windows: %d\n", context->windows.num); 123 124 context->windows.window = calloc(context->windows.num, 125 sizeof(*context->windows.window)); 126 if (!context->windows.window) { 127 MSG_ERR("Memory allocation failed\n"); 128 return -1; 129 } 130 131 for (i = 0; i < context->windows.num; i++) { 132 init_window_state(&context->windows.window[i], 133 context->windows.default_size); 134 } 135 136 return init_window_mem(context); 137 } 138 139 /* 140 * free_windows() - Free the window cache 141 * @context: The mbox context pointer 142 */ 143 void free_windows(struct mbox_context *context) 144 { 145 int i; 146 147 /* Check window cache has actually been allocated */ 148 if (context->windows.window) { 149 for (i = 0; i < context->windows.num; i++) { 150 free(context->windows.window[i].dirty_bmap); 151 } 152 free(context->windows.window); 153 } 154 } 155 156 /* Write from Window Functions */ 157 158 /* 159 * write_from_window_v1() - Handle writing when erase and block size differ 160 * @context: The mbox context pointer 161 * @offset_bytes: The offset in the current window to write from (bytes) 162 * @count_bytes: Number of bytes to write 163 * 164 * Handle a write_from_window for dirty memory when block_size is less than the 165 * flash erase size 166 * This requires us to be a bit careful because we might have to erase more 167 * than we want to write which could result in data loss if we don't have the 168 * entire portion of flash to be erased already saved in memory (for us to 169 * write back after the erase) 170 * 171 * Return: 0 on success otherwise negative error code 172 */ 173 int write_from_window_v1(struct mbox_context *context, 174 uint32_t offset_bytes, uint32_t count_bytes) 175 { 176 int rc; 177 uint32_t flash_offset; 178 struct window_context low_mem = { 0 }, high_mem = { 0 }; 179 180 /* Find where in phys flash this is based on the window.flash_offset */ 181 flash_offset = context->current->flash_offset + offset_bytes; 182 183 /* 184 * low_mem.flash_offset = erase boundary below where we're writing 185 * low_mem.size = size from low_mem.flash_offset to where we're writing 186 * 187 * high_mem.flash_offset = end of where we're writing 188 * high_mem.size = size from end of where we're writing to next erase 189 * boundary 190 */ 191 low_mem.flash_offset = align_down(flash_offset, 192 context->mtd_info.erasesize); 193 low_mem.size = flash_offset - low_mem.flash_offset; 194 high_mem.flash_offset = flash_offset + count_bytes; 195 high_mem.size = align_up(high_mem.flash_offset, 196 context->mtd_info.erasesize) - 197 high_mem.flash_offset; 198 199 /* 200 * Check if we already have a copy of the required flash areas in 201 * memory as part of the existing window 202 */ 203 if (low_mem.flash_offset < context->current->flash_offset) { 204 /* Before the start of our current window */ 205 low_mem.mem = malloc(low_mem.size); 206 if (!low_mem.mem) { 207 MSG_ERR("Unable to allocate memory\n"); 208 return -MBOX_R_SYSTEM_ERROR; 209 } 210 rc = copy_flash(context, low_mem.flash_offset, 211 low_mem.mem, low_mem.size); 212 if (rc < 0) { 213 goto out; 214 } 215 } 216 if ((high_mem.flash_offset + high_mem.size) > 217 (context->current->flash_offset + context->current->size)) { 218 /* After the end of our current window */ 219 high_mem.mem = malloc(high_mem.size); 220 if (!high_mem.mem) { 221 MSG_ERR("Unable to allocate memory\n"); 222 rc = -MBOX_R_SYSTEM_ERROR; 223 goto out; 224 } 225 rc = copy_flash(context, high_mem.flash_offset, 226 high_mem.mem, high_mem.size); 227 if (rc < 0) { 228 goto out; 229 } 230 } 231 232 /* 233 * We need to erase the flash from low_mem.flash_offset-> 234 * high_mem.flash_offset + high_mem.size 235 */ 236 rc = erase_flash(context, low_mem.flash_offset, 237 (high_mem.flash_offset - low_mem.flash_offset) + 238 high_mem.size); 239 if (rc < 0) { 240 MSG_ERR("Couldn't erase flash\n"); 241 goto out; 242 } 243 244 /* Write back over the erased area */ 245 if (low_mem.mem) { 246 /* Exceed window at the start */ 247 rc = write_flash(context, low_mem.flash_offset, low_mem.mem, 248 low_mem.size); 249 if (rc < 0) { 250 goto out; 251 } 252 } 253 rc = write_flash(context, flash_offset, 254 context->current->mem + offset_bytes, count_bytes); 255 if (rc < 0) { 256 goto out; 257 } 258 /* 259 * We still need to write the last little bit that we erased - it's 260 * either in the current window or the high_mem window. 261 */ 262 if (high_mem.mem) { 263 /* Exceed window at the end */ 264 rc = write_flash(context, high_mem.flash_offset, high_mem.mem, 265 high_mem.size); 266 if (rc < 0) { 267 goto out; 268 } 269 } else { 270 /* Write from the current window - it's atleast that big */ 271 rc = write_flash(context, high_mem.flash_offset, 272 context->current->mem + offset_bytes + 273 count_bytes, high_mem.size); 274 if (rc < 0) { 275 goto out; 276 } 277 } 278 279 out: 280 free(low_mem.mem); 281 free(high_mem.mem); 282 return rc; 283 } 284 285 /* 286 * write_from_window() - Write back to the flash from the current window 287 * @context: The mbox context pointer 288 * @offset_bytes: The offset in the current window to write from (blocks) 289 * @count_bytes: Number of blocks to write 290 * @type: Whether this is an erase & write or just an erase 291 * 292 * Return: 0 on success otherwise negative error code 293 */ 294 int write_from_window(struct mbox_context *context, uint32_t offset, 295 uint32_t count, uint8_t type) 296 { 297 int rc; 298 uint32_t flash_offset, count_bytes = count << context->block_size_shift; 299 uint32_t offset_bytes = offset << context->block_size_shift; 300 301 switch (type) { 302 case WINDOW_ERASED: /* >= V2 ONLY -> block_size == erasesize */ 303 flash_offset = context->current->flash_offset + offset_bytes; 304 rc = erase_flash(context, flash_offset, count_bytes); 305 if (rc < 0) { 306 MSG_ERR("Couldn't erase flash\n"); 307 return rc; 308 } 309 break; 310 case WINDOW_DIRTY: 311 /* 312 * For protocol V1, block_size may be smaller than erase size 313 * so we have a special function to make sure that we do this 314 * correctly without losing data. 315 */ 316 if (log_2(context->mtd_info.erasesize) != 317 context->block_size_shift) { 318 return write_from_window_v1(context, offset_bytes, 319 count_bytes); 320 } 321 flash_offset = context->current->flash_offset + offset_bytes; 322 323 /* Erase the flash */ 324 rc = erase_flash(context, flash_offset, count_bytes); 325 if (rc < 0) { 326 return rc; 327 } 328 329 /* Write to the erased flash */ 330 rc = write_flash(context, flash_offset, 331 context->current->mem + offset_bytes, 332 count_bytes); 333 if (rc < 0) { 334 return rc; 335 } 336 337 break; 338 default: 339 /* We shouldn't be able to get here */ 340 MSG_ERR("Write from window with invalid type: %d\n", type); 341 return -MBOX_R_SYSTEM_ERROR; 342 } 343 344 return 0; 345 } 346 347 /* Window Management Functions */ 348 349 /* 350 * alloc_window_dirty_bytemap() - (re)allocate all the window dirty bytemaps 351 * @context: The mbox context pointer 352 */ 353 void alloc_window_dirty_bytemap(struct mbox_context *context) 354 { 355 struct window_context *cur; 356 int i; 357 358 for (i = 0; i < context->windows.num; i++) { 359 cur = &context->windows.window[i]; 360 /* There may already be one allocated */ 361 free(cur->dirty_bmap); 362 /* Allocate the new one */ 363 cur->dirty_bmap = calloc((cur->size >> 364 context->block_size_shift), 365 sizeof(*cur->dirty_bmap)); 366 } 367 } 368 369 /* 370 * set_window_bytemap() - Set the window bytemap 371 * @context: The mbox context pointer 372 * @cur: The window to set the bytemap of 373 * @offset: Where in the window to set the bytemap (blocks) 374 * @size: The number of blocks to set 375 * @val: The value to set the bytemap to 376 * 377 * Return: 0 on success otherwise negative error code 378 */ 379 int set_window_bytemap(struct mbox_context *context, struct window_context *cur, 380 uint32_t offset, uint32_t size, uint8_t val) 381 { 382 if (offset + size > (cur->size >> context->block_size_shift)) { 383 MSG_ERR("Tried to set window bytemap past end of window\n"); 384 MSG_ERR("Requested offset: 0x%x size: 0x%x window size: 0x%x\n", 385 offset << context->block_size_shift, 386 size << context->block_size_shift, 387 cur->size << context->block_size_shift); 388 return -MBOX_R_PARAM_ERROR; 389 } 390 391 memset(cur->dirty_bmap + offset, val, size); 392 return 0; 393 } 394 395 /* 396 * close_current_window() - Close the current (active) window 397 * @context: The mbox context pointer 398 * @set_bmc_event: Whether to set the bmc event bit 399 * @flags: Flags as defined for a close command in the protocol 400 * 401 * This closes the current window. If the host has requested the current window 402 * be closed then we don't need to set the bmc event bit 403 * (set_bmc_event == false), otherwise if the current window has been closed 404 * without the host requesting it the bmc event bit must be set to indicate this 405 * to the host (set_bmc_event == true). 406 */ 407 void close_current_window(struct mbox_context *context, bool set_bmc_event, 408 uint8_t flags) 409 { 410 MSG_DBG("Close current window, flags: 0x%.2x\n", flags); 411 412 if (set_bmc_event) { 413 set_bmc_events(context, BMC_EVENT_WINDOW_RESET, SET_BMC_EVENT); 414 } 415 416 if (flags & FLAGS_SHORT_LIFETIME) { 417 context->current->age = 0; 418 } 419 420 context->current = NULL; 421 context->current_is_write = false; 422 } 423 424 /* 425 * reset_window() - Reset a window context to a well defined default state 426 * @context: The mbox context pointer 427 * @window: The window to reset 428 */ 429 void reset_window(struct mbox_context *context, struct window_context *window) 430 { 431 window->flash_offset = FLASH_OFFSET_UNINIT; 432 window->size = context->windows.default_size; 433 if (window->dirty_bmap) { /* Might not have been allocated */ 434 set_window_bytemap(context, window, 0, 435 window->size >> context->block_size_shift, 436 WINDOW_CLEAN); 437 } 438 window->age = 0; 439 } 440 441 /* 442 * reset_all_windows() - Reset all windows to a well defined default state 443 * @context: The mbox context pointer 444 * @set_bmc_event: If any state change should be indicated to the host 445 */ 446 void reset_all_windows(struct mbox_context *context, bool set_bmc_event) 447 { 448 int i; 449 450 MSG_DBG("Resetting all windows\n"); 451 /* We might have an open window which needs closing */ 452 if (context->current) { 453 close_current_window(context, set_bmc_event, FLAGS_NONE); 454 } 455 for (i = 0; i < context->windows.num; i++) { 456 reset_window(context, &context->windows.window[i]); 457 } 458 459 context->windows.max_age = 0; 460 } 461 462 /* 463 * find_oldest_window() - Find the oldest (Least Recently Used) window 464 * @context: The mbox context pointer 465 * 466 * Return: Pointer to the least recently used window 467 */ 468 struct window_context *find_oldest_window(struct mbox_context *context) 469 { 470 struct window_context *oldest = NULL, *cur; 471 uint32_t min_age = context->windows.max_age + 1; 472 int i; 473 474 for (i = 0; i < context->windows.num; i++) { 475 cur = &context->windows.window[i]; 476 477 if (cur->age < min_age) { 478 min_age = cur->age; 479 oldest = cur; 480 } 481 } 482 483 return oldest; 484 } 485 486 /* 487 * find_largest_window() - Find the largest window in the window cache 488 * @context: The mbox context pointer 489 * 490 * Return: The largest window 491 */ 492 struct window_context *find_largest_window(struct mbox_context *context) 493 { 494 struct window_context *largest = NULL, *cur; 495 uint32_t max_size = 0; 496 int i; 497 498 for (i = 0; i < context->windows.num; i++) { 499 cur = &context->windows.window[i]; 500 501 if (cur->size > max_size) { 502 max_size = cur->size; 503 largest = cur; 504 } 505 } 506 507 return largest; 508 } 509 510 /* 511 * search_windows() - Search the window cache for a window containing offset 512 * @context: The mbox context pointer 513 * @offset: Absolute flash offset to search for (bytes) 514 * @exact: If the window must exactly map the requested offset 515 * 516 * This will search the cache of windows for one containing the requested 517 * offset. For V1 of the protocol windows must exactly map the offset since we 518 * can't tell the host how much of its request we actually mapped and it will 519 * thus assume it can access window->size from the offset we give it. 520 * 521 * Return: Pointer to a window containing the requested offset otherwise 522 * NULL 523 */ 524 struct window_context *search_windows(struct mbox_context *context, 525 uint32_t offset, bool exact) 526 { 527 struct window_context *cur; 528 int i; 529 530 MSG_DBG("Searching for window which contains 0x%.8x %s\n", 531 offset, exact ? "exactly" : ""); 532 for (i = 0; i < context->windows.num; i++) { 533 cur = &context->windows.window[i]; 534 if (cur->flash_offset == FLASH_OFFSET_UNINIT) { 535 /* Uninitialised Window */ 536 if (offset == FLASH_OFFSET_UNINIT) { 537 return cur; 538 } 539 continue; 540 } 541 if ((offset >= cur->flash_offset) && 542 (offset < (cur->flash_offset + cur->size))) { 543 if (exact && (cur->flash_offset != offset)) { 544 continue; 545 } 546 /* This window contains the requested offset */ 547 cur->age = ++(context->windows.max_age); 548 return cur; 549 } 550 } 551 552 return NULL; 553 } 554 555 /* 556 * create_map_window() - Create a window mapping which maps the requested offset 557 * @context: The mbox context pointer 558 * @this_window: A pointer to update to the "new" window 559 * @offset: Absolute flash offset to create a mapping for (bytes) 560 * @exact: If the window must exactly map the requested offset 561 * 562 * This is used to create a window mapping for the requested offset when there 563 * is no existing window in the cache which satisfies the offset. This involves 564 * choosing an existing window from the window cache to evict so we can use it 565 * to store the flash contents from the requested offset, we then point the 566 * caller to that window since it now maps their request. 567 * 568 * Return: 0 on success otherwise negative error code 569 */ 570 int create_map_window(struct mbox_context *context, 571 struct window_context **this_window, uint32_t offset, 572 bool exact) 573 { 574 struct window_context *cur = NULL; 575 int rc; 576 577 MSG_DBG("Creating window which maps 0x%.8x %s\n", offset, 578 exact ? "exactly" : ""); 579 580 /* Search for an uninitialised window, use this before evicting */ 581 cur = search_windows(context, FLASH_OFFSET_UNINIT, true); 582 583 /* No uninitialised window found, we need to choose one to "evict" */ 584 if (!cur) { 585 MSG_DBG("No uninitialised window, evicting one\n"); 586 cur = find_oldest_window(context); 587 } 588 589 /* 590 * In case of the virtual pnor, as of now it's possible that a window may 591 * have content less than it's max size. We basically copy one flash partition 592 * per window, and some partitions are smaller than the max size. An offset 593 * right after such a small partition ends should lead to new mapping. The code 594 * below prevents that. 595 */ 596 #ifndef VIRTUAL_PNOR_ENABLED 597 if (!exact) { 598 /* 599 * It would be nice to align the offsets which we map to window 600 * size, this will help prevent overlap which would be an 601 * inefficient use of our reserved memory area (we would like 602 * to "cache" as much of the acutal flash as possible in 603 * memory). If we're protocol V1 however we must ensure the 604 * offset requested is exactly mapped. 605 */ 606 offset &= ~(cur->size - 1); 607 } 608 #endif 609 610 if ((offset + cur->size) > context->flash_size) { 611 /* 612 * There is V1 skiboot implementations out there which don't 613 * mask offset with window size, meaning when we have 614 * window size == flash size we will never allow the host to 615 * open a window except at 0x0, which isn't always where the 616 * host requests it. Thus we have to ignore this check and just 617 * hope the host doesn't access past the end of the window 618 * (which it shouldn't) for V1 implementations to get around 619 * this. 620 */ 621 if (context->version == API_VERSION_1) { 622 cur->size = align_down(context->flash_size - offset, 623 1 << context->block_size_shift); 624 } else { 625 /* Trying to read past the end of flash */ 626 MSG_ERR("Tried to open read window past flash limit\n"); 627 return -MBOX_R_PARAM_ERROR; 628 } 629 } 630 631 /* Copy from flash into the window buffer */ 632 rc = copy_flash(context, offset, cur->mem, cur->size); 633 if (rc < 0) { 634 /* We don't know how much we've copied -> better reset window */ 635 reset_window(context, cur); 636 return rc; 637 } 638 /* rc isn't guaranteed to be aligned, so align up */ 639 cur->size = align_up(rc, (1ULL << context->block_size_shift)); 640 /* Would like a known value, pick 0xFF to it looks like erased flash */ 641 memset(cur->mem + rc, 0xFF, cur->size - rc); 642 643 /* 644 * Since for V1 windows aren't constrained to start at multiples of 645 * window size it's possible that something already maps this offset. 646 * Reset any windows which map this offset to avoid coherency problems. 647 * We just have to check for anything which maps the start or the end 648 * of the window since all windows are the same size so another window 649 * cannot map just the middle of this window. 650 */ 651 if (context->version == API_VERSION_1) { 652 uint32_t i; 653 654 MSG_DBG("Checking for window overlap\n"); 655 656 for (i = offset; i < (offset + cur->size); i += (cur->size - 1)) { 657 struct window_context *tmp = NULL; 658 do { 659 tmp = search_windows(context, i, false); 660 if (tmp) { 661 reset_window(context, tmp); 662 } 663 } while (tmp); 664 } 665 } 666 667 /* Clear the bytemap of the window just loaded -> we know it's clean */ 668 set_window_bytemap(context, cur, 0, 669 cur->size >> context->block_size_shift, 670 WINDOW_CLEAN); 671 672 /* Update so we know what's in the window */ 673 cur->flash_offset = offset; 674 cur->age = ++(context->windows.max_age); 675 *this_window = cur; 676 677 return 0; 678 } 679