1 // SPDX-License-Identifier: GPL-2.0-only 1 2 /* 3 * powerpc code to implement the kexec_file_lo 4 * 5 * Copyright (C) 2004 Adam Litke (agl@us.ibm. 6 * Copyright (C) 2004 IBM Corp. 7 * Copyright (C) 2004,2005 Milton D Miller II 8 * Copyright (C) 2005 R Sharada (sharada@in.i 9 * Copyright (C) 2006 Mohan Kumar M (mohan@in 10 * Copyright (C) 2020 IBM Corporation 11 * 12 * Based on kexec-tools' kexec-ppc64.c, fs2dt. 13 * Heavily modified for the kernel by 14 * Hari Bathini, IBM Corporation. 15 */ 16 17 #define pr_fmt(fmt) "kexec ranges: " fmt 18 19 #include <linux/sort.h> 20 #include <linux/kexec.h> 21 #include <linux/of.h> 22 #include <linux/slab.h> 23 #include <linux/memblock.h> 24 #include <linux/crash_core.h> 25 #include <asm/sections.h> 26 #include <asm/kexec_ranges.h> 27 #include <asm/crashdump-ppc64.h> 28 29 #if defined(CONFIG_KEXEC_FILE) || defined(CONF 30 /** 31 * get_max_nr_ranges - Get the max no. of rang 32 * could hold, given the s 33 * @size: Allocation size of cras 34 * 35 * Returns the maximum no. of ranges. 36 */ 37 static inline unsigned int get_max_nr_ranges(s 38 { 39 return ((size - sizeof(struct crash_me 40 sizeof(struct range)); 41 } 42 43 /** 44 * get_mem_rngs_size - Get the allocated size 45 * max_nr_ranges and chunk 46 * @mem_rngs: Memory ranges. 47 * 48 * Returns the maximum size of @mem_rngs. 49 */ 50 static inline size_t get_mem_rngs_size(struct 51 { 52 size_t size; 53 54 if (!mem_rngs) 55 return 0; 56 57 size = (sizeof(struct crash_mem) + 58 (mem_rngs->max_nr_ranges * siz 59 60 /* 61 * Memory is allocated in size multipl 62 * So, align to get the actual length. 63 */ 64 return ALIGN(size, MEM_RANGE_CHUNK_SZ) 65 } 66 67 /** 68 * __add_mem_range - add a memory range to mem 69 * @mem_ranges: Range list to add the mem 70 * @base: Base address of the range 71 * @size: Size of the memory range 72 * 73 * (Re)allocates memory, if needed. 74 * 75 * Returns 0 on success, negative errno on err 76 */ 77 static int __add_mem_range(struct crash_mem ** 78 { 79 struct crash_mem *mem_rngs = *mem_rang 80 81 if (!mem_rngs || (mem_rngs->nr_ranges 82 mem_rngs = realloc_mem_ranges( 83 if (!mem_rngs) 84 return -ENOMEM; 85 } 86 87 mem_rngs->ranges[mem_rngs->nr_ranges]. 88 mem_rngs->ranges[mem_rngs->nr_ranges]. 89 pr_debug("Added memory range [%#016llx 90 base, base + size - 1, mem_rn 91 mem_rngs->nr_ranges++; 92 return 0; 93 } 94 95 /** 96 * __merge_memory_ranges - Merges the given me 97 * @mem_rngs: Range list to merge 98 * 99 * Assumes a sorted range list. 100 * 101 * Returns nothing. 102 */ 103 static void __merge_memory_ranges(struct crash 104 { 105 struct range *ranges; 106 int i, idx; 107 108 if (!mem_rngs) 109 return; 110 111 idx = 0; 112 ranges = &(mem_rngs->ranges[0]); 113 for (i = 1; i < mem_rngs->nr_ranges; i 114 if (ranges[i].start <= (ranges 115 ranges[idx].end = rang 116 else { 117 idx++; 118 if (i == idx) 119 continue; 120 121 ranges[idx] = ranges[i 122 } 123 } 124 mem_rngs->nr_ranges = idx + 1; 125 } 126 127 /* cmp_func_t callback to sort ranges with sor 128 static int rngcmp(const void *_x, const void * 129 { 130 const struct range *x = _x, *y = _y; 131 132 if (x->start > y->start) 133 return 1; 134 if (x->start < y->start) 135 return -1; 136 return 0; 137 } 138 139 /** 140 * sort_memory_ranges - Sorts the given memory 141 * @mem_rngs: Range list to sort. 142 * @merge: If true, merge the lis 143 * 144 * Returns nothing. 145 */ 146 void sort_memory_ranges(struct crash_mem *mem_ 147 { 148 int i; 149 150 if (!mem_rngs) 151 return; 152 153 /* Sort the ranges in-place */ 154 sort(&(mem_rngs->ranges[0]), mem_rngs- 155 sizeof(mem_rngs->ranges[0]), rngc 156 157 if (merge) 158 __merge_memory_ranges(mem_rngs 159 160 /* For debugging purpose */ 161 pr_debug("Memory ranges:\n"); 162 for (i = 0; i < mem_rngs->nr_ranges; i 163 pr_debug("\t[%03d][%#016llx - 164 mem_rngs->ranges[i].s 165 mem_rngs->ranges[i].e 166 } 167 } 168 169 /** 170 * realloc_mem_ranges - reallocate mem_ranges 171 * by MEM_RANGE_CHUNK_SZ. 172 * if memory allocation f 173 * @mem_ranges: Memory ranges to reall 174 * 175 * Returns pointer to reallocated memory on su 176 */ 177 struct crash_mem *realloc_mem_ranges(struct cr 178 { 179 struct crash_mem *mem_rngs = *mem_rang 180 unsigned int nr_ranges; 181 size_t size; 182 183 size = get_mem_rngs_size(mem_rngs); 184 nr_ranges = mem_rngs ? mem_rngs->nr_ra 185 186 size += MEM_RANGE_CHUNK_SZ; 187 mem_rngs = krealloc(*mem_ranges, size, 188 if (!mem_rngs) { 189 kfree(*mem_ranges); 190 *mem_ranges = NULL; 191 return NULL; 192 } 193 194 mem_rngs->nr_ranges = nr_ranges; 195 mem_rngs->max_nr_ranges = get_max_nr_r 196 *mem_ranges = mem_rngs; 197 198 return mem_rngs; 199 } 200 201 /** 202 * add_mem_range - Updates existing memory ran 203 * Else, adds a new memory ran 204 * @mem_ranges: Range list to add the memor 205 * @base: Base address of the range t 206 * @size: Size of the memory range to 207 * 208 * (Re)allocates memory, if needed. 209 * 210 * Returns 0 on success, negative errno on err 211 */ 212 int add_mem_range(struct crash_mem **mem_range 213 { 214 struct crash_mem *mem_rngs = *mem_rang 215 u64 mstart, mend, end; 216 unsigned int i; 217 218 if (!size) 219 return 0; 220 221 end = base + size - 1; 222 223 if (!mem_rngs || !(mem_rngs->nr_ranges 224 return __add_mem_range(mem_ran 225 226 for (i = 0; i < mem_rngs->nr_ranges; i 227 mstart = mem_rngs->ranges[i].s 228 mend = mem_rngs->ranges[i].end 229 if (base < mend && end > mstar 230 if (base < mstart) 231 mem_rngs->rang 232 if (end > mend) 233 mem_rngs->rang 234 return 0; 235 } 236 } 237 238 return __add_mem_range(mem_ranges, bas 239 } 240 241 #endif /* CONFIG_KEXEC_FILE || CONFIG_CRASH_DU 242 243 #ifdef CONFIG_KEXEC_FILE 244 /** 245 * add_tce_mem_ranges - Adds tce-table range t 246 * @mem_ranges: Range list to add the 247 * 248 * Returns 0 on success, negative errno on err 249 */ 250 static int add_tce_mem_ranges(struct crash_mem 251 { 252 struct device_node *dn = NULL; 253 int ret = 0; 254 255 for_each_node_by_type(dn, "pci") { 256 u64 base; 257 u32 size; 258 259 ret = of_property_read_u64(dn, 260 ret |= of_property_read_u32(dn 261 if (ret) { 262 /* 263 * It is ok to have pc 264 * property does not e 265 */ 266 if (ret == -EINVAL) { 267 ret = 0; 268 continue; 269 } 270 break; 271 } 272 273 ret = add_mem_range(mem_ranges 274 if (ret) 275 break; 276 } 277 278 of_node_put(dn); 279 return ret; 280 } 281 282 /** 283 * add_initrd_mem_range - Adds initrd range to 284 * if the initrd was re 285 * @mem_ranges: Range list to add th 286 * 287 * Returns 0 on success, negative errno on err 288 */ 289 static int add_initrd_mem_range(struct crash_m 290 { 291 u64 base, end; 292 int ret; 293 294 /* This range means something, only if 295 if (!strstr(saved_command_line, "retai 296 return 0; 297 298 ret = of_property_read_u64(of_chosen, 299 ret |= of_property_read_u64(of_chosen, 300 if (!ret) 301 ret = add_mem_range(mem_ranges 302 303 return ret; 304 } 305 306 /** 307 * add_htab_mem_range - Adds htab range to the 308 * if it exists 309 * @mem_ranges: Range list to add the 310 * 311 * Returns 0 on success, negative errno on err 312 */ 313 static int add_htab_mem_range(struct crash_mem 314 { 315 316 #ifdef CONFIG_PPC_64S_HASH_MMU 317 if (!htab_address) 318 return 0; 319 320 return add_mem_range(mem_ranges, __pa( 321 #else 322 return 0; 323 #endif 324 } 325 326 /** 327 * add_kernel_mem_range - Adds kernel text reg 328 * memory ranges list. 329 * @mem_ranges: Range list to add th 330 * 331 * Returns 0 on success, negative errno on err 332 */ 333 static int add_kernel_mem_range(struct crash_m 334 { 335 return add_mem_range(mem_ranges, 0, __ 336 } 337 #endif /* CONFIG_KEXEC_FILE */ 338 339 #if defined(CONFIG_KEXEC_FILE) || defined(CONF 340 /** 341 * add_rtas_mem_range - Adds RTAS region to th 342 * @mem_ranges: Range list to add the 343 * 344 * Returns 0 on success, negative errno on err 345 */ 346 static int add_rtas_mem_range(struct crash_mem 347 { 348 struct device_node *dn; 349 u32 base, size; 350 int ret = 0; 351 352 dn = of_find_node_by_path("/rtas"); 353 if (!dn) 354 return 0; 355 356 ret = of_property_read_u32(dn, "linux, 357 ret |= of_property_read_u32(dn, "rtas- 358 if (!ret) 359 ret = add_mem_range(mem_ranges 360 361 of_node_put(dn); 362 return ret; 363 } 364 365 /** 366 * add_opal_mem_range - Adds OPAL region to th 367 * @mem_ranges: Range list to add the 368 * 369 * Returns 0 on success, negative errno on err 370 */ 371 static int add_opal_mem_range(struct crash_mem 372 { 373 struct device_node *dn; 374 u64 base, size; 375 int ret; 376 377 dn = of_find_node_by_path("/ibm,opal") 378 if (!dn) 379 return 0; 380 381 ret = of_property_read_u64(dn, "opal-b 382 ret |= of_property_read_u64(dn, "opal- 383 if (!ret) 384 ret = add_mem_range(mem_ranges 385 386 of_node_put(dn); 387 return ret; 388 } 389 #endif /* CONFIG_KEXEC_FILE || CONFIG_CRASH_DU 390 391 #ifdef CONFIG_KEXEC_FILE 392 /** 393 * add_reserved_mem_ranges - Adds "/reserved-r 394 * to the given memo 395 * @mem_ranges: Range list to add 396 * 397 * Returns 0 on success, negative errno on err 398 */ 399 static int add_reserved_mem_ranges(struct cras 400 { 401 int n_mem_addr_cells, n_mem_size_cells 402 struct device_node *root = of_find_nod 403 const __be32 *prop; 404 405 prop = of_get_property(root, "reserved 406 n_mem_addr_cells = of_n_addr_cells(roo 407 n_mem_size_cells = of_n_size_cells(roo 408 of_node_put(root); 409 if (!prop) 410 return 0; 411 412 cells = n_mem_addr_cells + n_mem_size_ 413 414 /* Each reserved range is an (address, 415 for (i = 0; i < (len / (sizeof(u32) * 416 u64 base, size; 417 418 base = of_read_number(prop + ( 419 size = of_read_number(prop + ( 420 n_mem_si 421 422 ret = add_mem_range(mem_ranges 423 if (ret) 424 break; 425 } 426 427 return ret; 428 } 429 430 /** 431 * get_reserved_memory_ranges - Get reserve me 432 * memory regions 433 * memory reserve 434 * protected from 435 * @mem_ranges: Range list to 436 * 437 * Returns 0 on success, negative errno on err 438 */ 439 int get_reserved_memory_ranges(struct crash_me 440 { 441 int ret; 442 443 ret = add_rtas_mem_range(mem_ranges); 444 if (ret) 445 goto out; 446 447 ret = add_tce_mem_ranges(mem_ranges); 448 if (ret) 449 goto out; 450 451 ret = add_reserved_mem_ranges(mem_rang 452 out: 453 if (ret) 454 pr_err("Failed to setup reserv 455 return ret; 456 } 457 458 /** 459 * get_exclude_memory_ranges - Get exclude mem 460 * regions like op 461 * kernel, htab wh 462 * setting up kexe 463 * @mem_ranges: Range list to a 464 * 465 * Returns 0 on success, negative errno on err 466 */ 467 int get_exclude_memory_ranges(struct crash_mem 468 { 469 int ret; 470 471 ret = add_tce_mem_ranges(mem_ranges); 472 if (ret) 473 goto out; 474 475 ret = add_initrd_mem_range(mem_ranges) 476 if (ret) 477 goto out; 478 479 ret = add_htab_mem_range(mem_ranges); 480 if (ret) 481 goto out; 482 483 ret = add_kernel_mem_range(mem_ranges) 484 if (ret) 485 goto out; 486 487 ret = add_rtas_mem_range(mem_ranges); 488 if (ret) 489 goto out; 490 491 ret = add_opal_mem_range(mem_ranges); 492 if (ret) 493 goto out; 494 495 ret = add_reserved_mem_ranges(mem_rang 496 if (ret) 497 goto out; 498 499 /* exclude memory ranges should be sor 500 sort_memory_ranges(*mem_ranges, true); 501 out: 502 if (ret) 503 pr_err("Failed to setup exclud 504 return ret; 505 } 506 507 #ifdef CONFIG_CRASH_DUMP 508 /** 509 * get_usable_memory_ranges - Get usable memor 510 * regions like cra 511 * that kdump kerne 512 * @mem_ranges: Range list to ad 513 * 514 * Returns 0 on success, negative errno on err 515 */ 516 int get_usable_memory_ranges(struct crash_mem 517 { 518 int ret; 519 520 /* 521 * Early boot failure observed on gues 522 * block?) is not added to usable memo 523 * instead of [crashk_res.start, crash 524 * Also, crashed kernel's memory must 525 * avoid kdump kernel from using it. 526 */ 527 ret = add_mem_range(mem_ranges, 0, cra 528 if (ret) 529 goto out; 530 531 ret = add_rtas_mem_range(mem_ranges); 532 if (ret) 533 goto out; 534 535 ret = add_opal_mem_range(mem_ranges); 536 if (ret) 537 goto out; 538 539 ret = add_tce_mem_ranges(mem_ranges); 540 out: 541 if (ret) 542 pr_err("Failed to setup usable 543 return ret; 544 } 545 #endif /* CONFIG_CRASH_DUMP */ 546 #endif /* CONFIG_KEXEC_FILE */ 547 548 #ifdef CONFIG_CRASH_DUMP 549 /** 550 * get_crash_memory_ranges - Get crash memory 551 * first/crashing ke 552 * would be exported 553 * @mem_ranges: Range list to add 554 * 555 * Returns 0 on success, negative errno on err 556 */ 557 int get_crash_memory_ranges(struct crash_mem * 558 { 559 phys_addr_t base, end; 560 struct crash_mem *tmem; 561 u64 i; 562 int ret; 563 564 for_each_mem_range(i, &base, &end) { 565 u64 size = end - base; 566 567 /* Skip backup memory region, 568 if (base == BACKUP_SRC_START) 569 if (size > BACKUP_SRC_ 570 base = BACKUP_ 571 size -= BACKUP 572 } else 573 continue; 574 } 575 576 ret = add_mem_range(mem_ranges 577 if (ret) 578 goto out; 579 580 /* Try merging adjacent ranges 581 if ((*mem_ranges)->nr_ranges = 582 sort_memory_ranges(*me 583 } 584 585 /* Reallocate memory ranges if there i 586 tmem = *mem_ranges; 587 if (tmem && (tmem->nr_ranges == tmem-> 588 tmem = realloc_mem_ranges(mem_ 589 if (!tmem) 590 goto out; 591 } 592 593 /* Exclude crashkernel region */ 594 ret = crash_exclude_mem_range(tmem, cr 595 if (ret) 596 goto out; 597 598 /* 599 * FIXME: For now, stay in parity with 600 * regions are exported to save 601 * crash, they should actually 602 * first 64K bytes of memory. 603 */ 604 ret = add_rtas_mem_range(mem_ranges); 605 if (ret) 606 goto out; 607 608 ret = add_opal_mem_range(mem_ranges); 609 if (ret) 610 goto out; 611 612 /* create a separate program header fo 613 ret = add_mem_range(mem_ranges, BACKUP 614 if (ret) 615 goto out; 616 617 sort_memory_ranges(*mem_ranges, false) 618 out: 619 if (ret) 620 pr_err("Failed to setup crash 621 return ret; 622 } 623 624 /** 625 * remove_mem_range - Removes the given memory 626 * @mem_ranges: Range list to remove the me 627 * @base: Base address of the range t 628 * @size: Size of the memory range to 629 * 630 * (Re)allocates memory, if needed. 631 * 632 * Returns 0 on success, negative errno on err 633 */ 634 int remove_mem_range(struct crash_mem **mem_ra 635 { 636 u64 end; 637 int ret = 0; 638 unsigned int i; 639 u64 mstart, mend; 640 struct crash_mem *mem_rngs = *mem_rang 641 642 if (!size) 643 return 0; 644 645 /* 646 * Memory range are stored as start an 647 * the same format to do remove operat 648 */ 649 end = base + size - 1; 650 651 for (i = 0; i < mem_rngs->nr_ranges; i 652 mstart = mem_rngs->ranges[i].s 653 mend = mem_rngs->ranges[i].end 654 655 /* 656 * Memory range to remove is n 657 * in the memory range list 658 */ 659 if (!(base >= mstart && end <= 660 continue; 661 662 /* 663 * Memory range to remove is e 664 * memory range list. Remove t 665 */ 666 if (base == mstart && end == m 667 for (; i < mem_rngs->n 668 mem_rngs->rang 669 mem_rngs->rang 670 } 671 mem_rngs->nr_ranges--; 672 goto out; 673 } 674 /* 675 * Start address of the memory 676 * current memory range entry 677 * move the start address of t 678 * entry in the list to end + 679 */ 680 else if (base == mstart) { 681 mem_rngs->ranges[i].st 682 goto out; 683 } 684 /* 685 * End address of the memory r 686 * current memory range entry 687 * Just move the end address o 688 * range entry in the list to 689 */ 690 else if (end == mend) { 691 mem_rngs->ranges[i].en 692 goto out; 693 } 694 /* 695 * Memory range to remove is n 696 * memory range entry. Split t 697 * two half. 698 */ 699 else { 700 mem_rngs->ranges[i].en 701 size = mem_rngs->range 702 ret = add_mem_range(me 703 } 704 } 705 out: 706 return ret; 707 } 708 #endif /* CONFIG_CRASH_DUMP */ 709
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.