1 /* 2 * (C) Copyright 2019 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include <common.h> 7 #include <boot_rkimg.h> 8 #include <image.h> 9 #include <malloc.h> 10 #include <sysmem.h> 11 #include <asm/arch/fit.h> 12 #include <asm/arch/resource_img.h> 13 14 DECLARE_GLOBAL_DATA_PTR; 15 16 #define FIT_PLACEHOLDER_ADDR 0xffffff00 17 18 /* 19 * Must use args '-E -p' for mkimage to generate FIT image, 4K as max assumption. 20 */ 21 #define FIT_FDT_MAX_SIZE SZ_4K 22 23 static int fit_is_ext_type(const void *fit) 24 { 25 return fdt_totalsize(fit) < FIT_FDT_MAX_SIZE; 26 } 27 28 static int fit_is_signed(const void *fit, const void *sig_blob) 29 { 30 return fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME) < 0 ? 0 : 1; 31 } 32 33 static inline int fit_image_addr_is_placeholder(ulong addr) 34 { 35 return (addr & 0xffffff00) == FIT_PLACEHOLDER_ADDR; 36 } 37 38 static int fit_sig_require_conf(const void *fit, const void *sig_blob) 39 { 40 const char *required; 41 int sig_node; 42 int noffset; 43 44 sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); 45 if (sig_node < 0) 46 return 0; 47 48 fdt_for_each_subnode(noffset, sig_blob, sig_node) { 49 required = fdt_getprop(sig_blob, noffset, "required", NULL); 50 if (required && !strcmp(required, "conf")) 51 return 1; 52 } 53 54 return 0; 55 } 56 57 int fit_default_conf_get_node(const void *fit, const char *prop_name) 58 { 59 int conf_noffset; 60 61 conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */ 62 if (conf_noffset < 0) 63 return conf_noffset; 64 65 return fit_conf_get_prop_node(fit, conf_noffset, prop_name); 66 } 67 68 int fix_image_set_addr(const void *fit, const char *prop_name, 69 ulong old, ulong new) 70 { 71 int noffset; 72 73 /* do not fix if verified-boot */ 74 if (!fit_image_addr_is_placeholder(old) || 75 fit_sig_require_conf(fit, gd_fdt_blob())) 76 return 0; 77 78 noffset = fit_default_conf_get_node(fit, prop_name); 79 if (noffset < 0) 80 return noffset; 81 82 /* optional */ 83 fit_image_set_entry(fit, noffset, new); 84 85 return fit_image_set_load(fit, noffset, new); 86 } 87 88 static int fdt_image_get_offset_size(const void *fit, const char *prop_name, 89 int *offset, int *size) 90 { 91 int sz, offs; 92 int noffset; 93 int ret; 94 95 noffset = fit_default_conf_get_node(fit, prop_name); 96 if (noffset < 0) 97 return noffset; 98 99 ret = fit_image_get_data_size(fit, noffset, &sz); 100 if (ret) 101 return ret; 102 103 ret = fit_image_get_data_position(fit, noffset, &offs); 104 if (!ret) 105 offs -= fdt_totalsize(fit); 106 else 107 ret = fit_image_get_data_offset(fit, noffset, &offs); 108 109 *offset = offs; 110 *size = sz; 111 112 return ret; 113 } 114 115 static int fdt_image_get_load(const void *fit, const char *prop_name, 116 ulong *load) 117 { 118 int noffset; 119 120 noffset = fit_default_conf_get_node(fit, prop_name); 121 if (noffset < 0) 122 return noffset; 123 124 return fit_image_get_load(fit, noffset, load); 125 } 126 127 static int fit_image_get_param(const void *fit, const char *prop_name, 128 ulong *load, int *offset, int *size) 129 { 130 int ret; 131 132 ret = fdt_image_get_offset_size(fit, prop_name, offset, size); 133 if (ret < 0) 134 return ret; 135 136 return fdt_image_get_load(fit, prop_name, load); 137 } 138 139 static void *fit_get_blob(struct blk_desc *dev_desc, 140 disk_partition_t *out_part, 141 bool verify) 142 { 143 __maybe_unused int conf_noffset; 144 disk_partition_t part; 145 char *part_name = PART_BOOT; 146 void *fit, *fdt; 147 int blk_num; 148 149 #ifndef CONFIG_ANDROID_AB 150 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) 151 part_name = PART_RECOVERY; 152 #endif 153 154 if (part_get_info_by_name(dev_desc, part_name, &part) < 0) { 155 FIT_I("No %s partition\n", part_name); 156 return NULL; 157 } 158 159 *out_part = part; 160 blk_num = DIV_ROUND_UP(sizeof(struct fdt_header), dev_desc->blksz); 161 fdt = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz); 162 if (!fdt) 163 return NULL; 164 165 if (blk_dread(dev_desc, part.start, blk_num, fdt) != blk_num) { 166 debug("Failed to read fdt header\n"); 167 goto fail; 168 } 169 170 if (fdt_check_header(fdt)) { 171 debug("No fdt header\n"); 172 goto fail; 173 } 174 175 if (!fit_is_ext_type(fdt)) { 176 debug("Not external type\n"); 177 goto fail; 178 } 179 180 blk_num = DIV_ROUND_UP(fdt_totalsize(fdt), dev_desc->blksz); 181 fit = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz); 182 if (!fit) { 183 debug("No memory\n"); 184 goto fail; 185 } 186 187 if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) { 188 free(fit); 189 debug("Failed to read fit blob\n"); 190 goto fail; 191 } 192 193 #ifdef CONFIG_FIT_SIGNATURE 194 if (!verify) 195 return fit; 196 197 conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */ 198 if (conf_noffset < 0) 199 goto fail; 200 201 printf("%s: ", fdt_get_name(fit, conf_noffset, NULL)); 202 if (fit_config_verify(fit, conf_noffset)) { 203 puts("\n"); 204 /* don't remove this failure handle */ 205 run_command("download", 0); 206 hang(); 207 } 208 puts("\n"); 209 #endif 210 return fit; 211 212 fail: 213 free(fdt); 214 return NULL; 215 } 216 217 static int fit_image_fixup_alloc(const void *fit, const char *prop_name, 218 const char *addr_name, enum memblk_id mem) 219 { 220 ulong load, addr; 221 int offset, size = 0; 222 int ret; 223 224 addr = env_get_ulong(addr_name, 16, 0); 225 if (!addr) 226 return -EINVAL; 227 228 ret = fit_image_get_param(fit, prop_name, &load, &offset, &size); 229 if (ret) 230 return (ret == -FDT_ERR_NOTFOUND) ? 0 : ret; 231 232 if (!size) 233 return 0; 234 235 ret = fix_image_set_addr(fit, prop_name, load, addr); 236 if (ret) 237 return ret; 238 239 /* 240 * 1. When need load HWID dtb, gd->fdt_blob points to HWID dtb 241 * and U-Boot will re-alloc MEM_FDT based on fdt node in 242 * ITB instead of resource. So alloc the larger size to 243 * avoid fail in sysmem. It will already skip load DTB in fdt node. 244 * 245 * 2. Additionally increase size with CONFIG_SYS_FDT_PAD to reserve 246 * some space for adding more props to dtb afterwards. 247 */ 248 if (!strcmp(prop_name, FIT_FDT_PROP) && !fdt_check_header(gd->fdt_blob)) 249 size = ((size > fdt_totalsize(gd->fdt_blob)) ? 250 size : fdt_totalsize(gd->fdt_blob)) + 251 CONFIG_SYS_FDT_PAD; 252 253 if (!sysmem_alloc_base(mem, (phys_addr_t)addr, 254 ALIGN(size, RK_BLK_SIZE))) 255 return -ENOMEM; 256 257 return 0; 258 } 259 260 int fit_image_pre_process(const void *fit) 261 { 262 int ret; 263 264 /* free for fit_image_fixup_alloc(FIT_FDT_PROP) to re-alloc */ 265 if ((gd->flags & GD_FLG_KDTB_READY) && !gd->fdt_blob_kern) 266 sysmem_free((phys_addr_t)gd->fdt_blob); 267 268 ret = fit_image_fixup_alloc(fit, FIT_FDT_PROP, 269 "fdt_addr_r", MEM_FDT); 270 if (ret < 0) { 271 return ret; 272 } 273 274 #if defined(CONFIG_CMD_BOOTZ) 275 int cfg_noffset, noffset; 276 const void *buf; 277 ulong start, end; 278 size_t size; 279 280 cfg_noffset = fit_conf_get_node(fit, NULL); 281 if (cfg_noffset < 0) { 282 printf("Could not find configuration node\n"); 283 return -ENOENT; 284 } 285 286 noffset = fit_conf_get_prop_node_index(fit, cfg_noffset, FIT_KERNEL_PROP, 0); 287 if (noffset < 0) { 288 printf("Could not find kernel node\n"); 289 return -ENOENT; 290 } 291 292 /* 293 * "kernel_addr_r" is for 64-bit kernel Image by default. 294 * Here in case of 64-bit U-Boot load 32-bit kenrel Image. 295 */ 296 #ifdef CONFIG_ARM64 297 char *kernel_addr_r; 298 299 if (fit_image_check_arch(fit, noffset, IH_ARCH_ARM)) { 300 kernel_addr_r = env_get("kernel_addr_aarch32_r"); 301 if (kernel_addr_r) 302 env_set("kernel_addr_r", kernel_addr_r); 303 } 304 #endif 305 /* get image data address and length */ 306 if (fit_image_get_data(fit, noffset, &buf, &size)) { 307 printf("Could not find %s subimage data!\n", FIT_KERNEL_PROP); 308 return -ENOENT; 309 } 310 311 if (!bootz_setup((ulong)buf, &start, &end)) 312 ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP, 313 "kernel_addr_c", MEM_KERNEL); 314 else 315 #endif 316 ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP, 317 "kernel_addr_r", MEM_KERNEL); 318 if (ret < 0) 319 return ret; 320 321 return fit_image_fixup_alloc(fit, FIT_RAMDISK_PROP, 322 "ramdisk_addr_r", MEM_RAMDISK); 323 } 324 325 int fit_image_fail_process(const void *fit) 326 { 327 ulong raddr, kaddr, faddr; 328 329 raddr = env_get_ulong("ramdisk_addr_r", 16, 0); 330 kaddr = env_get_ulong("kernel_addr_r", 16, 0); 331 faddr = env_get_ulong("fdt_addr_r", 16, 0); 332 333 sysmem_free((phys_addr_t)fit); 334 sysmem_free((phys_addr_t)raddr); 335 sysmem_free((phys_addr_t)kaddr); 336 sysmem_free((phys_addr_t)faddr); 337 338 return 0; 339 } 340 341 static int fit_image_get_subnode(const void *fit, int noffset, const char *name) 342 { 343 int sub_noffset; 344 345 fdt_for_each_subnode(sub_noffset, fit, noffset) { 346 if (!strncmp(fit_get_name(fit, sub_noffset, NULL), 347 name, strlen(name))) 348 return sub_noffset; 349 } 350 351 return -ENOENT; 352 } 353 354 static int fit_image_load_one(const void *fit, struct blk_desc *dev_desc, 355 disk_partition_t *part, char *prop_name, 356 void *data, int check_hash) 357 { 358 u32 blk_num, blk_off; 359 int offset, size; 360 int noffset, ret; 361 char *msg = ""; 362 363 ret = fdt_image_get_offset_size(fit, prop_name, &offset, &size); 364 if (ret) 365 return ret; 366 367 blk_off = (FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz; 368 blk_num = DIV_ROUND_UP(size, dev_desc->blksz); 369 if (blk_dread(dev_desc, part->start + blk_off, blk_num, data) != blk_num) 370 return -EIO; 371 372 if (check_hash) { 373 int hash_noffset; 374 375 noffset = fit_default_conf_get_node(fit, prop_name); 376 if (noffset < 0) 377 return noffset; 378 379 hash_noffset = fit_image_get_subnode(fit, noffset, 380 FIT_HASH_NODENAME); 381 if (hash_noffset < 0) 382 return hash_noffset; 383 384 printf("%s: ", fdt_get_name(fit, noffset, NULL)); 385 ret = fit_image_check_hash(fit, hash_noffset, data, size, &msg); 386 if (ret) 387 return ret; 388 389 puts("+\n"); 390 } 391 392 return 0; 393 } 394 395 /* Calculate what we really need */ 396 ulong fit_image_get_bootables_size(const void *fit) 397 { 398 ulong off[3] = { 0, 0, 0 }; 399 ulong max_off, load; 400 int offset, size; 401 402 #if 0 403 if (!fit_get_totalsize(fit, &size)) 404 return size; 405 #endif 406 407 if (!fit_image_get_param(fit, FIT_FDT_PROP, &load, &offset, &size)) 408 off[0] = offset + FIT_ALIGN(size); 409 410 if (!fit_image_get_param(fit, FIT_KERNEL_PROP, &load, &offset, &size)) 411 off[1] = offset + FIT_ALIGN(size); 412 413 if (!fit_image_get_param(fit, FIT_RAMDISK_PROP, &load, &offset, &size)) 414 off[2] = offset + FIT_ALIGN(size); 415 416 max_off = max(off[0], off[1]); 417 max_off = max(max_off, off[2]); 418 419 return FIT_ALIGN(fdt_totalsize(fit)) + max_off; 420 } 421 422 void *fit_image_load_bootables(ulong *size) 423 { 424 struct blk_desc *dev_desc; 425 disk_partition_t part; 426 int blk_num; 427 void *fit; 428 429 dev_desc = rockchip_get_bootdev(); 430 if (!dev_desc) 431 return NULL; 432 433 fit = fit_get_blob(dev_desc, &part, false); 434 if (!fit) { 435 FIT_I("No fit blob\n"); 436 return NULL; 437 } 438 439 *size = fit_image_get_bootables_size(fit); 440 if (*size == 0) { 441 FIT_I("No bootable image\n"); 442 return NULL; 443 } 444 445 blk_num = DIV_ROUND_UP(*size, dev_desc->blksz); 446 fit = sysmem_alloc(MEM_FIT, blk_num * dev_desc->blksz); 447 if (!fit) 448 return NULL; 449 450 if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) { 451 FIT_I("Failed to load bootable images\n"); 452 return NULL; 453 } 454 455 return fit; 456 } 457 458 static void fit_msg(const void *fit) 459 { 460 FIT_I("%ssigned, %sconf required\n", 461 fit_is_signed(fit, gd_fdt_blob()) ? "" : "no ", 462 fit_sig_require_conf(fit, gd_fdt_blob()) ? "" : "no "); 463 } 464 465 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE 466 ulong fit_image_init_resource(struct blk_desc *dev_desc) 467 { 468 disk_partition_t part; 469 void *fit, *buf; 470 int offset, size; 471 int ret = 0; 472 473 if (!dev_desc) 474 return -ENODEV; 475 476 fit = fit_get_blob(dev_desc, &part, true); 477 if (!fit) 478 return -EAGAIN; 479 480 ret = fdt_image_get_offset_size(fit, FIT_MULTI_PROP, &offset, &size); 481 if (ret) 482 return -EINVAL; 483 484 buf = memalign(ARCH_DMA_MINALIGN, ALIGN(size, dev_desc->blksz)); 485 if (!buf) 486 return -ENOMEM; 487 488 printf("RESC: '%s', blk@0x%08lx\n", part.name, 489 part.start + ((FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz)); 490 ret = fit_image_load_one(fit, dev_desc, &part, FIT_MULTI_PROP, buf, 1); 491 if (ret) 492 return ret; 493 494 ret = resource_setup_ram_list(dev_desc, buf); 495 if (ret) { 496 FIT_I("Failed to setup resource ram list, ret=%d\n", ret); 497 free(fit); 498 return ret; 499 } 500 501 fit_msg(fit); 502 free(fit); 503 504 return 0; 505 } 506 #else 507 int fit_image_read_dtb(void *fdt_addr) 508 { 509 struct blk_desc *dev_desc; 510 disk_partition_t part; 511 void *fit; 512 513 dev_desc = rockchip_get_bootdev(); 514 if (!dev_desc) { 515 FIT_I("No dev_desc!\n"); 516 return -ENODEV;; 517 } 518 519 fit = fit_get_blob(dev_desc, &part, true); 520 if (!fit) 521 return -EINVAL; 522 523 fit_msg(fit); 524 525 return fit_image_load_one(fit, dev_desc, &part, FIT_FDT_PROP, 526 (void *)fdt_addr, 1); 527 } 528 #endif 529