"Das U-Boot" Source Tree
at master 691 lines 18 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2013, Google Inc. 4 * 5 * (C) Copyright 2008 Semihalf 6 * 7 * (C) Copyright 2000-2006 8 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 9 */ 10 11#include <command.h> 12#include <fdt_support.h> 13#include <fdtdec.h> 14#include <env.h> 15#include <errno.h> 16#include <image.h> 17#include <lmb.h> 18#include <log.h> 19#include <malloc.h> 20#include <asm/global_data.h> 21#include <linux/libfdt.h> 22#include <mapmem.h> 23#include <asm/io.h> 24#include <dm/ofnode.h> 25#include <tee/optee.h> 26 27DECLARE_GLOBAL_DATA_PTR; 28 29static void fdt_error(const char *msg) 30{ 31 puts("ERROR: "); 32 puts(msg); 33 puts(" - must RESET the board to recover.\n"); 34} 35 36#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) 37static const struct legacy_img_hdr *image_get_fdt(ulong fdt_addr) 38{ 39 const struct legacy_img_hdr *fdt_hdr = map_sysmem(fdt_addr, 0); 40 41 image_print_contents(fdt_hdr); 42 43 puts(" Verifying Checksum ... "); 44 if (!image_check_hcrc(fdt_hdr)) { 45 fdt_error("fdt header checksum invalid"); 46 return NULL; 47 } 48 49 if (!image_check_dcrc(fdt_hdr)) { 50 fdt_error("fdt checksum invalid"); 51 return NULL; 52 } 53 puts("OK\n"); 54 55 if (!image_check_type(fdt_hdr, IH_TYPE_FLATDT)) { 56 fdt_error("uImage is not a fdt"); 57 return NULL; 58 } 59 if (image_get_comp(fdt_hdr) != IH_COMP_NONE) { 60 fdt_error("uImage is compressed"); 61 return NULL; 62 } 63 if (fdt_check_header((void *)image_get_data(fdt_hdr)) != 0) { 64 fdt_error("uImage data is not a fdt"); 65 return NULL; 66 } 67 return fdt_hdr; 68} 69#endif 70 71static void boot_fdt_reserve_region(u64 addr, u64 size, u32 flags) 72{ 73 long ret; 74 75 ret = lmb_reserve(addr, size, flags); 76 if (!ret) { 77 debug(" reserving fdt memory region: addr=%llx size=%llx flags=%x\n", 78 (unsigned long long)addr, 79 (unsigned long long)size, flags); 80 } else if (ret != -EEXIST) { 81 puts("ERROR: reserving fdt memory region failed "); 82 printf("(addr=%llx size=%llx flags=%x)\n", 83 (unsigned long long)addr, 84 (unsigned long long)size, flags); 85 } 86} 87 88/** 89 * boot_fdt_add_mem_rsv_regions - Mark the memreserve and reserved-memory 90 * sections as unusable 91 * @fdt_blob: pointer to fdt blob base address 92 * 93 * Adds the and reserved-memorymemreserve regions in the dtb to the lmb block. 94 * Adding the memreserve regions prevents u-boot from using them to store the 95 * initrd or the fdt blob. 96 */ 97void boot_fdt_add_mem_rsv_regions(void *fdt_blob) 98{ 99 uint64_t addr, size; 100 int i, total, ret; 101 int nodeoffset, subnode; 102 struct fdt_resource res; 103 u32 flags; 104 105 if (fdt_check_header(fdt_blob) != 0) 106 return; 107 108 /* process memreserve sections */ 109 total = fdt_num_mem_rsv(fdt_blob); 110 for (i = 0; i < total; i++) { 111 if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0) 112 continue; 113 boot_fdt_reserve_region(addr, size, LMB_NOOVERWRITE); 114 } 115 116 /* process reserved-memory */ 117 nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory"); 118 if (nodeoffset >= 0) { 119 subnode = fdt_first_subnode(fdt_blob, nodeoffset); 120 while (subnode >= 0) { 121 /* check if this subnode has a reg property */ 122 ret = fdt_get_resource(fdt_blob, subnode, "reg", 0, 123 &res); 124 if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) { 125 flags = LMB_NOOVERWRITE; 126 if (fdtdec_get_bool(fdt_blob, subnode, 127 "no-map")) 128 flags = LMB_NOMAP; 129 addr = res.start; 130 size = res.end - res.start + 1; 131 boot_fdt_reserve_region(addr, size, flags); 132 } 133 134 subnode = fdt_next_subnode(fdt_blob, subnode); 135 } 136 } 137} 138 139/** 140 * boot_relocate_fdt - relocate flat device tree 141 * @of_flat_tree: pointer to a char* variable, will hold fdt start address 142 * @of_size: pointer to a ulong variable, will hold fdt length 143 * 144 * boot_relocate_fdt() allocates a region of memory within the bootmap and 145 * relocates the of_flat_tree into that region, even if the fdt is already in 146 * the bootmap. It also expands the size of the fdt by CONFIG_SYS_FDT_PAD 147 * bytes. 148 * 149 * of_flat_tree and of_size are set to final (after relocation) values 150 * 151 * returns: 152 * 0 - success 153 * 1 - failure 154 */ 155int boot_relocate_fdt(char **of_flat_tree, ulong *of_size) 156{ 157 u64 start, size, usable, addr, low, mapsize; 158 void *fdt_blob = *of_flat_tree; 159 void *of_start = NULL; 160 char *fdt_high; 161 ulong of_len = 0; 162 int bank; 163 int err; 164 int disable_relocation = 0; 165 166 /* nothing to do */ 167 if (*of_size == 0) 168 return 0; 169 170 if (fdt_check_header(fdt_blob) != 0) { 171 fdt_error("image is not a fdt"); 172 goto error; 173 } 174 175 /* position on a 4K boundary before the alloc_current */ 176 /* Pad the FDT by a specified amount */ 177 of_len = *of_size + CONFIG_SYS_FDT_PAD; 178 179 /* If fdt_high is set use it to select the relocation address */ 180 fdt_high = env_get("fdt_high"); 181 if (fdt_high) { 182 ulong desired_addr = hextoul(fdt_high, NULL); 183 184 if (desired_addr == ~0UL) { 185 /* All ones means use fdt in place */ 186 of_start = fdt_blob; 187 lmb_reserve(map_to_sysmem(of_start), of_len, LMB_NONE); 188 disable_relocation = 1; 189 } else if (desired_addr) { 190 addr = lmb_alloc_base(of_len, 0x1000, desired_addr, 191 LMB_NONE); 192 of_start = map_sysmem(addr, of_len); 193 if (of_start == NULL) { 194 puts("Failed using fdt_high value for Device Tree"); 195 goto error; 196 } 197 } else { 198 addr = lmb_alloc(of_len, 0x1000); 199 of_start = map_sysmem(addr, of_len); 200 } 201 } else { 202 mapsize = env_get_bootm_mapsize(); 203 low = env_get_bootm_low(); 204 of_start = NULL; 205 206 for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { 207 start = gd->bd->bi_dram[bank].start; 208 size = gd->bd->bi_dram[bank].size; 209 210 /* DRAM bank addresses are too low, skip it. */ 211 if (start + size < low) 212 continue; 213 214 /* 215 * At least part of this DRAM bank is usable, try 216 * using the DRAM bank up to 'usable' address limit 217 * for LMB allocation. 218 */ 219 usable = min(start + size, low + mapsize); 220 addr = lmb_alloc_base(of_len, 0x1000, usable, LMB_NONE); 221 of_start = map_sysmem(addr, of_len); 222 /* Allocation succeeded, use this block. */ 223 if (of_start != NULL) 224 break; 225 226 /* 227 * Reduce the mapping size in the next bank 228 * by the size of attempt in current bank. 229 */ 230 mapsize -= usable - max(start, low); 231 if (!mapsize) 232 break; 233 } 234 } 235 236 if (of_start == NULL) { 237 puts("device tree - allocation error\n"); 238 goto error; 239 } 240 241 if (disable_relocation) { 242 /* 243 * We assume there is space after the existing fdt to use 244 * for padding 245 */ 246 fdt_set_totalsize(of_start, of_len); 247 printf(" Using Device Tree in place at %p, end %p\n", 248 of_start, of_start + of_len - 1); 249 } else { 250 debug("## device tree at %p ... %p (len=%ld [0x%lX])\n", 251 fdt_blob, fdt_blob + *of_size - 1, of_len, of_len); 252 253 printf(" Loading Device Tree to %p, end %p ... ", 254 of_start, of_start + of_len - 1); 255 256 err = fdt_open_into(fdt_blob, of_start, of_len); 257 if (err != 0) { 258 fdt_error("fdt move failed"); 259 goto error; 260 } 261 puts("OK\n"); 262 } 263 264 *of_flat_tree = of_start; 265 *of_size = of_len; 266 267 if (IS_ENABLED(CONFIG_CMD_FDT)) 268 set_working_fdt_addr(map_to_sysmem(*of_flat_tree)); 269 return 0; 270 271error: 272 return 1; 273} 274 275/** 276 * select_fdt() - Select and locate the FDT to use 277 * 278 * @images: pointer to the bootm images structure 279 * @select: name of FDT to select, or NULL for any 280 * @arch: expected FDT architecture 281 * @fdt_addrp: pointer to a ulong variable, will hold FDT pointer 282 * Return: 0 if OK, -ENOPKG if no FDT (but an error should not be reported), 283 * other -ve value on other error 284 */ 285 286static int select_fdt(struct bootm_headers *images, const char *select, u8 arch, 287 ulong *fdt_addrp) 288{ 289 const char *buf; 290 ulong fdt_addr; 291 292#if CONFIG_IS_ENABLED(FIT) 293 const char *fit_uname_config = images->fit_uname_cfg; 294 const char *fit_uname_fdt = NULL; 295 ulong default_addr; 296 int fdt_noffset; 297 298 if (select) { 299 /* 300 * If the FDT blob comes from the FIT image and the 301 * FIT image address is omitted in the command line 302 * argument, try to use ramdisk or os FIT image 303 * address or default load address. 304 */ 305 if (images->fit_uname_rd) 306 default_addr = (ulong)images->fit_hdr_rd; 307 else if (images->fit_uname_os) 308 default_addr = (ulong)images->fit_hdr_os; 309 else 310 default_addr = image_load_addr; 311 312 if (fit_parse_conf(select, default_addr, &fdt_addr, 313 &fit_uname_config)) { 314 debug("* fdt: config '%s' from image at 0x%08lx\n", 315 fit_uname_config, fdt_addr); 316 } else if (fit_parse_subimage(select, default_addr, &fdt_addr, 317 &fit_uname_fdt)) { 318 debug("* fdt: subimage '%s' from image at 0x%08lx\n", 319 fit_uname_fdt, fdt_addr); 320 } else 321#endif 322 { 323 fdt_addr = hextoul(select, NULL); 324 debug("* fdt: cmdline image address = 0x%08lx\n", 325 fdt_addr); 326 } 327#if CONFIG_IS_ENABLED(FIT) 328 } else { 329 /* use FIT configuration provided in first bootm 330 * command argument 331 */ 332 fdt_addr = map_to_sysmem(images->fit_hdr_os); 333 fdt_noffset = fit_get_node_from_config(images, FIT_FDT_PROP, 334 fdt_addr); 335 if (fdt_noffset == -ENOENT) 336 return -ENOPKG; 337 else if (fdt_noffset < 0) 338 return fdt_noffset; 339 } 340#endif 341 debug("## Checking for 'FDT'/'FDT Image' at %08lx\n", 342 fdt_addr); 343 344 /* 345 * Check if there is an FDT image at the 346 * address provided in the second bootm argument 347 * check image type, for FIT images get a FIT node. 348 */ 349 buf = map_sysmem(fdt_addr, 0); 350 switch (genimg_get_format(buf)) { 351#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) 352 case IMAGE_FORMAT_LEGACY: { 353 const struct legacy_img_hdr *fdt_hdr; 354 ulong load, load_end; 355 ulong image_start, image_data, image_end; 356 357 /* verify fdt_addr points to a valid image header */ 358 printf("## Flattened Device Tree from Legacy Image at %08lx\n", 359 fdt_addr); 360 fdt_hdr = image_get_fdt(fdt_addr); 361 if (!fdt_hdr) 362 return -ENOPKG; 363 364 /* 365 * move image data to the load address, 366 * make sure we don't overwrite initial image 367 */ 368 image_start = (ulong)fdt_hdr; 369 image_data = (ulong)image_get_data(fdt_hdr); 370 image_end = image_get_image_end(fdt_hdr); 371 372 load = image_get_load(fdt_hdr); 373 load_end = load + image_get_data_size(fdt_hdr); 374 375 if (load == image_start || 376 load == image_data) { 377 fdt_addr = load; 378 break; 379 } 380 381 if ((load < image_end) && (load_end > image_start)) { 382 fdt_error("fdt overwritten"); 383 return -EFAULT; 384 } 385 386 debug(" Loading FDT from 0x%08lx to 0x%08lx\n", 387 image_data, load); 388 389 memmove((void *)load, 390 (void *)image_data, 391 image_get_data_size(fdt_hdr)); 392 393 fdt_addr = load; 394 break; 395 } 396#endif 397 case IMAGE_FORMAT_FIT: 398 /* 399 * This case will catch both: new uImage format 400 * (libfdt based) and raw FDT blob (also libfdt 401 * based). 402 */ 403#if CONFIG_IS_ENABLED(FIT) 404 /* check FDT blob vs FIT blob */ 405 if (!fit_check_format(buf, IMAGE_SIZE_INVAL)) { 406 ulong load, len; 407 408 fdt_noffset = boot_get_fdt_fit(images, fdt_addr, 409 &fit_uname_fdt, 410 &fit_uname_config, 411 arch, &load, &len); 412 413 if (fdt_noffset < 0) 414 return -ENOENT; 415 416 images->fit_hdr_fdt = map_sysmem(fdt_addr, 0); 417 images->fit_uname_fdt = fit_uname_fdt; 418 images->fit_noffset_fdt = fdt_noffset; 419 fdt_addr = load; 420 421 break; 422 } else 423#endif 424 { 425 /* 426 * FDT blob 427 */ 428 debug("* fdt: raw FDT blob\n"); 429 printf("## Flattened Device Tree blob at %08lx\n", 430 (long)fdt_addr); 431 } 432 break; 433 default: 434 puts("ERROR: Did not find a cmdline Flattened Device Tree\n"); 435 return -ENOENT; 436 } 437 *fdt_addrp = fdt_addr; 438 439 return 0; 440} 441 442int boot_get_fdt(void *buf, const char *select, uint arch, 443 struct bootm_headers *images, char **of_flat_tree, 444 ulong *of_size) 445{ 446 char *fdt_blob = NULL; 447 ulong fdt_addr; 448 449 *of_flat_tree = NULL; 450 *of_size = 0; 451 452 if (select || genimg_has_config(images)) { 453 int ret; 454 455 ret = select_fdt(images, select, arch, &fdt_addr); 456 if (ret == -ENOPKG) 457 goto no_fdt; 458 else if (ret) 459 return 1; 460 printf(" Booting using the fdt blob at %#08lx\n", fdt_addr); 461 fdt_blob = map_sysmem(fdt_addr, 0); 462 } else if (images->legacy_hdr_valid && 463 image_check_type(&images->legacy_hdr_os_copy, 464 IH_TYPE_MULTI)) { 465 ulong fdt_data, fdt_len; 466 467 /* 468 * Now check if we have a legacy multi-component image, 469 * get second entry data start address and len. 470 */ 471 printf("## Flattened Device Tree from multi component Image at %08lX\n", 472 (ulong)images->legacy_hdr_os); 473 474 image_multi_getimg(images->legacy_hdr_os, 2, &fdt_data, 475 &fdt_len); 476 if (fdt_len) { 477 fdt_blob = (char *)fdt_data; 478 printf(" Booting using the fdt at 0x%p\n", fdt_blob); 479 480 if (fdt_check_header(fdt_blob) != 0) { 481 fdt_error("image is not a fdt"); 482 goto error; 483 } 484 485 if (fdt_totalsize(fdt_blob) != fdt_len) { 486 fdt_error("fdt size != image size"); 487 goto error; 488 } 489 } else { 490 debug("## No Flattened Device Tree\n"); 491 goto no_fdt; 492 } 493#ifdef CONFIG_ANDROID_BOOT_IMAGE 494 } else if (genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) { 495 void *hdr = buf; 496 ulong fdt_data, fdt_len; 497 u32 fdt_size, dtb_idx; 498 /* 499 * Firstly check if this android boot image has dtb field. 500 */ 501 dtb_idx = (u32)env_get_ulong("adtb_idx", 10, 0); 502 if (android_image_get_dtb_by_index((ulong)hdr, get_avendor_bootimg_addr(), 503 dtb_idx, &fdt_addr, &fdt_size)) { 504 fdt_blob = (char *)map_sysmem(fdt_addr, 0); 505 if (fdt_check_header(fdt_blob)) 506 goto no_fdt; 507 508 debug("## Using FDT in Android image dtb area with idx %u\n", dtb_idx); 509 } else if (!android_image_get_second(hdr, &fdt_data, &fdt_len) && 510 !fdt_check_header((char *)fdt_data)) { 511 fdt_blob = (char *)fdt_data; 512 if (fdt_totalsize(fdt_blob) != fdt_len) 513 goto error; 514 515 debug("## Using FDT in Android image second area\n"); 516 } else { 517 fdt_addr = env_get_hex("fdtaddr", 0); 518 if (!fdt_addr) 519 goto no_fdt; 520 521 fdt_blob = map_sysmem(fdt_addr, 0); 522 if (fdt_check_header(fdt_blob)) 523 goto no_fdt; 524 525 debug("## Using FDT at ${fdtaddr}=Ox%lx\n", fdt_addr); 526 } 527#endif 528 } else { 529 debug("## No Flattened Device Tree\n"); 530 goto no_fdt; 531 } 532 533 *of_flat_tree = fdt_blob; 534 *of_size = fdt_totalsize(fdt_blob); 535 debug(" of_flat_tree at 0x%08lx size 0x%08lx\n", 536 (ulong)*of_flat_tree, *of_size); 537 538 return 0; 539 540no_fdt: 541 debug("Continuing to boot without FDT\n"); 542 return 0; 543error: 544 return 1; 545} 546 547/* 548 * Verify the device tree. 549 * 550 * This function is called after all device tree fix-ups have been enacted, 551 * so that the final device tree can be verified. The definition of "verified" 552 * is up to the specific implementation. However, it generally means that the 553 * addresses of some of the devices in the device tree are compared with the 554 * actual addresses at which U-Boot has placed them. 555 * 556 * Returns 1 on success, 0 on failure. If 0 is returned, U-Boot will halt the 557 * boot process. 558 */ 559__weak int ft_verify_fdt(void *fdt) 560{ 561 return 1; 562} 563 564__weak int arch_fixup_fdt(void *blob) 565{ 566 return 0; 567} 568 569int image_setup_libfdt(struct bootm_headers *images, void *blob, bool lmb) 570{ 571 ulong *initrd_start = &images->initrd_start; 572 ulong *initrd_end = &images->initrd_end; 573 int ret, fdt_ret, of_size; 574 575 if (IS_ENABLED(CONFIG_OF_ENV_SETUP)) { 576 const char *fdt_fixup; 577 578 fdt_fixup = env_get("fdt_fixup"); 579 if (fdt_fixup) { 580 set_working_fdt_addr(map_to_sysmem(blob)); 581 ret = run_command_list(fdt_fixup, -1, 0); 582 if (ret) 583 printf("WARNING: fdt_fixup command returned %d\n", 584 ret); 585 } 586 } 587 588 ret = -EPERM; 589 590 if (fdt_root(blob) < 0) { 591 printf("ERROR: root node setup failed\n"); 592 goto err; 593 } 594 if (fdt_chosen(blob) < 0) { 595 printf("ERROR: /chosen node create failed\n"); 596 goto err; 597 } 598 if (arch_fixup_fdt(blob) < 0) { 599 printf("ERROR: arch-specific fdt fixup failed\n"); 600 goto err; 601 } 602 603 fdt_ret = optee_copy_fdt_nodes(blob); 604 if (fdt_ret) { 605 printf("ERROR: transfer of optee nodes to new fdt failed: %s\n", 606 fdt_strerror(fdt_ret)); 607 goto err; 608 } 609 610 /* Store name of configuration node as u-boot,bootconf in /chosen node */ 611 if (images->fit_uname_cfg) 612 fdt_find_and_setprop(blob, "/chosen", "u-boot,bootconf", 613 images->fit_uname_cfg, 614 strlen(images->fit_uname_cfg) + 1, 1); 615 616 /* Update ethernet nodes */ 617 fdt_fixup_ethernet(blob); 618#if IS_ENABLED(CONFIG_CMD_PSTORE) 619 /* Append PStore configuration */ 620 fdt_fixup_pstore(blob); 621#endif 622 if (IS_ENABLED(CONFIG_OF_BOARD_SETUP)) { 623 const char *skip_board_fixup; 624 625 skip_board_fixup = env_get("skip_board_fixup"); 626 if (skip_board_fixup && ((int)simple_strtol(skip_board_fixup, NULL, 10) == 1)) { 627 printf("skip board fdt fixup\n"); 628 } else { 629 fdt_ret = ft_board_setup(blob, gd->bd); 630 if (fdt_ret) { 631 printf("ERROR: board-specific fdt fixup failed: %s\n", 632 fdt_strerror(fdt_ret)); 633 goto err; 634 } 635 } 636 } 637 if (IS_ENABLED(CONFIG_OF_SYSTEM_SETUP)) { 638 fdt_ret = ft_system_setup(blob, gd->bd); 639 if (fdt_ret) { 640 printf("ERROR: system-specific fdt fixup failed: %s\n", 641 fdt_strerror(fdt_ret)); 642 goto err; 643 } 644 } 645 646 if (fdt_initrd(blob, *initrd_start, *initrd_end)) 647 goto err; 648 649 if (!ft_verify_fdt(blob)) 650 goto err; 651 652 /* after here we are using a livetree */ 653 if (!of_live_active() && CONFIG_IS_ENABLED(EVENT)) { 654 struct event_ft_fixup fixup; 655 656 fixup.tree = oftree_from_fdt(blob); 657 fixup.images = images; 658 if (oftree_valid(fixup.tree)) { 659 ret = event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup)); 660 if (ret) { 661 printf("ERROR: fdt fixup event failed: %d\n", 662 ret); 663 goto err; 664 } 665 } 666 } 667 668 /* Delete the old LMB reservation */ 669 if (CONFIG_IS_ENABLED(LMB) && lmb) 670 lmb_free(map_to_sysmem(blob), fdt_totalsize(blob)); 671 672 ret = fdt_shrink_to_minimum(blob, 0); 673 if (ret < 0) 674 goto err; 675 of_size = ret; 676 677 /* Create a new LMB reservation */ 678 if (CONFIG_IS_ENABLED(LMB) && lmb) 679 lmb_reserve(map_to_sysmem(blob), of_size, LMB_NONE); 680 681#if defined(CONFIG_ARCH_KEYSTONE) 682 if (IS_ENABLED(CONFIG_OF_BOARD_SETUP)) 683 ft_board_setup_ex(blob, gd->bd); 684#endif 685 686 return 0; 687err: 688 printf(" - must RESET the board to recover.\n\n"); 689 690 return ret; 691}