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(void *fit) 24 { 25 return fdt_totalsize(fit) < FIT_FDT_MAX_SIZE; 26 } 27 28 static int fit_is_signed(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_is_placeholder_addr(ulong addr) 34 { 35 return (addr & 0xffffff00) == FIT_PLACEHOLDER_ADDR; 36 } 37 38 static int fit_is_required(void *fit, const void *sig_blob) 39 { 40 int sig_node; 41 int noffset; 42 43 sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); 44 if (sig_node < 0) 45 return 0; 46 47 fdt_for_each_subnode(noffset, sig_blob, sig_node) { 48 const char *required; 49 50 required = fdt_getprop(sig_blob, noffset, "required", NULL); 51 if (required && !strcmp(required, "conf")) 52 return 1; 53 } 54 55 return 0; 56 } 57 58 int fit_fixup_load_entry(void *fit, int images, int defconf, 59 char *name, ulong *load, ulong new_addr) 60 { 61 const char *uname; 62 int uname_cfg; 63 int err; 64 65 if (!fit_is_placeholder_addr(*load) || 66 fit_is_required(fit, gd_fdt_blob())) 67 return 0; 68 69 *load = new_addr; 70 71 uname = fdt_getprop(fit, defconf, name, NULL); 72 if (!uname) 73 return -ENODEV; 74 75 uname_cfg = fdt_subnode_offset(fit, images, uname); 76 if (uname_cfg < 0) 77 return -ENODEV; 78 79 err = fit_image_set_load(fit, uname_cfg, new_addr); 80 if (err) 81 return err; 82 83 fit_image_set_entry(fit, uname_cfg, new_addr); 84 85 return 0; 86 } 87 88 static int fit_get_load_and_data(void *fit, int images, int defconf, 89 const char *name, ulong *load, 90 int *offset, int *size) 91 { 92 const char *uname; 93 int uname_cfg; 94 int off, sz; 95 int err; 96 97 uname = fdt_getprop(fit, defconf, name, NULL); 98 if (!uname) 99 return -ENODEV; 100 101 uname_cfg = fdt_subnode_offset(fit, images, uname); 102 if (uname_cfg < 0) 103 return -ENODEV; 104 105 err = fit_image_get_data_size(fit, uname_cfg, &sz); 106 if (err) 107 return err; 108 109 err = fit_image_get_data_position(fit, uname_cfg, &off); 110 if (!err) { 111 off -= fdt_totalsize(fit); 112 } else { 113 err = fit_image_get_data_offset(fit, uname_cfg, &off); 114 if (err) 115 return err; 116 } 117 118 /* optional */ 119 if (load) { 120 err = fit_image_get_load(fit, uname_cfg, load); 121 if (err) 122 return err; 123 } 124 125 *offset = off; 126 *size = sz; 127 128 return 0; 129 } 130 131 int fit_image_fixup_and_sysmem_rsv(void *fit) 132 { 133 ulong load, kaddr, faddr, raddr; 134 int images, defconf; 135 int offset, size; 136 int err; 137 138 faddr = env_get_ulong("fdt_addr_r", 16, 0); 139 kaddr = env_get_ulong("kernel_addr_r", 16, 0); 140 raddr = env_get_ulong("ramdisk_addr_r", 16, 0); 141 142 if (!faddr || !kaddr || !raddr) 143 return -EINVAL; 144 145 if (fit_get_image_defconf_node(fit, &images, &defconf)) { 146 FIT_I("Failed to get default config\n"); 147 return -ENODEV; 148 } 149 150 /* fdt */ 151 if (fit_get_load_and_data(fit, images, defconf, FIT_FDT_PROP, 152 &load, &offset, &size)) { 153 FIT_I("Invalid fdt node\n"); 154 return -ENOENT; 155 } 156 157 #ifdef CONFIG_USING_KERNEL_DTB 158 sysmem_free((phys_addr_t)gd->fdt_blob); 159 #endif 160 if (fit_fixup_load_entry(fit, images, defconf, 161 FIT_FDT_PROP, &load, faddr)) { 162 FIT_I("Failed to fixup fdt load addr\n"); 163 return -EINVAL; 164 } 165 166 if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)load, 167 ALIGN(size, RK_BLK_SIZE))) 168 return -ENOMEM; 169 170 /* kernel */ 171 if (fit_get_load_and_data(fit, images, defconf, FIT_KERNEL_PROP, 172 &load, &offset, &size)) { 173 FIT_I("Invalid kernel node\n"); 174 return -EINVAL; 175 } 176 177 if (fit_fixup_load_entry(fit, images, defconf, 178 FIT_KERNEL_PROP, &load, kaddr)) { 179 FIT_I("Failed to fixup kernel load addr\n"); 180 return -EINVAL; 181 } 182 183 if (!sysmem_alloc_base(MEM_KERNEL, (phys_addr_t)load, 184 ALIGN(size, RK_BLK_SIZE))) 185 return -ENOMEM; 186 187 /* ramdisk(optional) */ 188 err = fit_get_load_and_data(fit, images, defconf, FIT_RAMDISK_PROP, 189 &load, &offset, &size); 190 if (err && err != -ENODEV) { 191 FIT_I("Invalid ramdisk node\n"); 192 return err; 193 } 194 195 if (size) { 196 if (fit_fixup_load_entry(fit, images, defconf, 197 FIT_RAMDISK_PROP, &load, raddr)) { 198 FIT_I("Failed to fixup ramdisk load addr\n"); 199 return -EINVAL; 200 } 201 202 if (!sysmem_alloc_base(MEM_RAMDISK, (phys_addr_t)load, 203 ALIGN(size, RK_BLK_SIZE))) 204 return -ENOMEM; 205 } 206 207 return 0; 208 } 209 210 int fit_sysmem_free_each(void *fit) 211 { 212 ulong raddr, kaddr, faddr; 213 214 raddr = env_get_ulong("ramdisk_addr_r", 16, 0); 215 kaddr = env_get_ulong("kernel_addr_r", 16, 0); 216 faddr = env_get_ulong("fdt_addr_r", 16, 0); 217 218 sysmem_free((phys_addr_t)fit); 219 sysmem_free((phys_addr_t)raddr); 220 sysmem_free((phys_addr_t)kaddr); 221 sysmem_free((phys_addr_t)faddr); 222 223 return 0; 224 } 225 226 static int fit_image_load_one(void *fit, struct blk_desc *dev_desc, 227 disk_partition_t *part, int images, 228 int defconf, char *name, void *dst) 229 { 230 u32 blknum, blkoff; 231 int offset, size; 232 233 if (fit_get_load_and_data(fit, images, defconf, name, 234 NULL, &offset, &size)) 235 return -EINVAL; 236 237 blkoff = (FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz; 238 blknum = DIV_ROUND_UP(size, dev_desc->blksz); 239 240 if (blk_dread(dev_desc, part->start + blkoff, blknum, dst) != blknum) 241 return -EIO; 242 243 return 0; 244 } 245 246 static int fit_image_load_fdt(void *fit, struct blk_desc *dev_desc, 247 disk_partition_t *part, int images, 248 int defconf, void *dst) 249 { 250 return fit_image_load_one(fit, dev_desc, part, images, 251 defconf, FIT_FDT_PROP, dst); 252 } 253 254 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE 255 static int fit_image_load_resource(void *fit, struct blk_desc *dev_desc, 256 disk_partition_t *part, int images, 257 int defconf, ulong *addr) 258 { 259 ulong fdt_addr_r, dst; 260 int offset, size; 261 int err; 262 263 err = fit_get_load_and_data(fit, images, defconf, FIT_MULTI_PROP, 264 NULL, &offset, &size); 265 if (err) 266 return err; 267 268 fdt_addr_r = env_get_ulong("fdt_addr_r", 16, 0); 269 if (!fdt_addr_r) 270 return -EINVAL; 271 272 /* reserve enough space before fdt */ 273 dst = fdt_addr_r - 274 ALIGN(size, dev_desc->blksz) - CONFIG_SYS_FDT_PAD; 275 276 if (!sysmem_alloc_base(MEM_RESOURCE, (phys_addr_t)dst, 277 ALIGN(size, dev_desc->blksz))) 278 return -ENOMEM; 279 280 *addr = dst; 281 282 return fit_image_load_one(fit, dev_desc, part, images, defconf, 283 FIT_MULTI_PROP, (void *)dst); 284 } 285 #endif 286 287 static void *fit_get_blob(struct blk_desc *dev_desc, disk_partition_t *part) 288 { 289 void *fit, *fdt; 290 int blknum; 291 292 blknum = DIV_ROUND_UP(sizeof(struct fdt_header), dev_desc->blksz); 293 fdt = memalign(ARCH_DMA_MINALIGN, blknum * dev_desc->blksz); 294 if (!fdt) 295 return NULL; 296 297 if (blk_dread(dev_desc, part->start, blknum, fdt) != blknum) { 298 debug("Failed to read fdt header\n"); 299 goto fail; 300 } 301 302 if (fdt_check_header(fdt)) { 303 debug("Invalid fdt header\n"); 304 goto fail; 305 } 306 307 if (!fit_is_ext_type(fdt)) { 308 debug("Not external type\n"); 309 goto fail; 310 } 311 312 blknum = DIV_ROUND_UP(fdt_totalsize(fdt), dev_desc->blksz); 313 fit = memalign(ARCH_DMA_MINALIGN, blknum * dev_desc->blksz); 314 if (!fit) { 315 debug("No memory\n"); 316 goto fail; 317 } 318 319 if (blk_dread(dev_desc, part->start, blknum, fit) != blknum) { 320 free(fit); 321 debug("Failed to read fit\n"); 322 goto fail; 323 } 324 325 return fit; 326 327 fail: 328 free(fdt); 329 return NULL; 330 } 331 332 static int fit_image_get_fdt_hash(void *fit, int images, int defconf, 333 char **hash, int *hash_size) 334 { 335 const char *fdt_name; 336 const char *name; 337 uint8_t *fit_value2; 338 uint8_t *fit_value; 339 int fit_value_len; 340 int hash_off; 341 int fdt_off; 342 int found = 0; 343 char *algo; 344 345 fdt_name = fdt_getprop(fit, defconf, FIT_FDT_PROP, NULL); 346 if (!fdt_name) 347 return -EBADF; 348 349 fdt_off = fdt_subnode_offset(fit, images, fdt_name); 350 if (fdt_off < 0) 351 return -EBADF; 352 353 fdt_for_each_subnode(hash_off, fit, fdt_off) { 354 name = fit_get_name(fit, hash_off, NULL); 355 if (!strncmp(name, FIT_HASH_NODENAME, 356 strlen(FIT_HASH_NODENAME))) { 357 found = 1; 358 break; 359 } 360 } 361 362 if (!found) 363 return -ENODEV; 364 365 if (fit_image_hash_get_algo(fit, hash_off, &algo)) 366 return -EINVAL; 367 368 if (fit_image_hash_get_value(fit, hash_off, &fit_value, 369 &fit_value_len)) 370 return -EINVAL; 371 372 if (!strcmp(algo, "sha1")) 373 *hash_size = 20; 374 else if (!strcmp(algo, "sha256")) 375 *hash_size = 32; 376 else 377 return -EINVAL; 378 379 /* avoid freed */ 380 fit_value2 = malloc(fit_value_len); 381 if (!fit_value2) 382 return -ENOMEM; 383 384 memcpy(fit_value2, fit_value, fit_value_len); 385 *hash = (char *)fit_value2; 386 387 return 0; 388 } 389 390 ulong fit_image_get_bootable_size(void *fit) 391 { 392 ulong off[3] = { 0, 0, 0 }; 393 ulong max_off, load; 394 int images, defconf; 395 int offset, size; 396 397 if (fit_get_image_defconf_node(fit, &images, &defconf)) 398 return -ENODEV; 399 400 if (!fit_get_load_and_data(fit, images, defconf, FIT_FDT_PROP, 401 &load, &offset, &size)) 402 off[0] = offset + FIT_ALIGN(size); 403 404 if (!fit_get_load_and_data(fit, images, defconf, FIT_KERNEL_PROP, 405 &load, &offset, &size)) 406 off[1] = offset + FIT_ALIGN(size); 407 408 if (!fit_get_load_and_data(fit, images, defconf, FIT_RAMDISK_PROP, 409 &load, &offset, &size)) 410 off[2] = offset + FIT_ALIGN(size); 411 412 max_off = max(off[0], off[1]); 413 max_off = max(max_off, off[2]); 414 415 return FIT_ALIGN(fdt_totalsize(fit)) + max_off; 416 } 417 418 void *fit_image_load_bootables(ulong *size) 419 { 420 struct blk_desc *dev_desc; 421 disk_partition_t part; 422 char *part_name; 423 int blknum; 424 void *fit; 425 426 dev_desc = rockchip_get_bootdev(); 427 if (!dev_desc) { 428 FIT_I("No dev_desc\n"); 429 return NULL; 430 } 431 432 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) 433 part_name = PART_RECOVERY; 434 else 435 part_name = PART_BOOT; 436 437 if (part_get_info_by_name(dev_desc, part_name, &part) < 0) { 438 FIT_I("No %s partition\n", part_name); 439 return NULL; 440 } 441 442 fit = fit_get_blob(dev_desc, &part); 443 if (!fit) { 444 FIT_I("No fit blob\n"); 445 return NULL; 446 } 447 448 *size = fit_image_get_bootable_size(fit); 449 if (*size == 0) { 450 FIT_I("No bootable image size\n"); 451 return NULL; 452 } 453 454 blknum = DIV_ROUND_UP(*size, dev_desc->blksz); 455 fit = sysmem_alloc(MEM_FIT, blknum * dev_desc->blksz); 456 if (!fit) 457 return NULL; 458 459 if (blk_dread(dev_desc, part.start, blknum, fit) != blknum) { 460 FIT_I("Failed to load bootable images\n"); 461 return NULL; 462 } 463 464 return fit; 465 } 466 467 static void verbose_msg(void *fit, int defconf) 468 { 469 FIT_I("%ssigned, %sconf-required\n", 470 fit_is_signed(fit, gd_fdt_blob()) ? "" : "no ", 471 fit_is_required(fit, gd_fdt_blob()) ? "" : "no "); 472 473 printf("DTB: %s\n", 474 (char *)fdt_getprop(fit, defconf, FIT_FDT_PROP, NULL)); 475 } 476 477 int rockchip_read_fit_dtb(void *fdt_addr, char **hash, int *hash_size) 478 { 479 struct blk_desc *dev_desc; 480 disk_partition_t part; 481 char *part_name; 482 void *fit; 483 ulong rsce; 484 int images; 485 int defconf; 486 int err; 487 488 dev_desc = rockchip_get_bootdev(); 489 if (!dev_desc) { 490 FIT_I("No dev_desc!\n"); 491 return -ENODEV; 492 } 493 494 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) 495 part_name = PART_RECOVERY; 496 else 497 part_name = PART_BOOT; 498 499 err = part_get_info_by_name(dev_desc, part_name, &part); 500 if (err < 0) { 501 FIT_I("No %s partition\n", part_name); 502 return err; 503 } 504 505 fit = fit_get_blob(dev_desc, &part); 506 if (!fit) { 507 FIT_I("No fdt blob\n"); 508 return -EINVAL; 509 } 510 511 if (fit_get_image_defconf_node(fit, &images, &defconf)) { 512 FIT_I("Failed to get /images and /configures default\n"); 513 err = -ENODEV; 514 goto out; 515 } 516 517 if (fit_image_load_fdt(fit, dev_desc, &part, 518 images, defconf, fdt_addr)) { 519 FIT_I("Failed to load fdt\n"); 520 err = -EINVAL; 521 goto out; 522 } 523 524 err = fit_image_get_fdt_hash(fit, images, defconf, hash, hash_size); 525 if (err && err != -ENODEV) { 526 FIT_I("Failed to get fdt hash\n"); 527 err = -EINVAL; 528 goto out; 529 } 530 531 verbose_msg(fit, defconf); 532 533 /* load resource file */ 534 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE 535 err = fit_image_load_resource(fit, dev_desc, &part, 536 images, defconf, &rsce); 537 if (!err) { 538 if (resource_create_ram_list(dev_desc, (void *)rsce)) 539 FIT_I("Failed to create resource list\n"); 540 } else if (err == -ENODEV) { 541 FIT_I("No resource file\n"); 542 } else { 543 FIT_I("Failed to load resource file\n"); 544 } 545 #endif 546 out: 547 free(fit); 548 549 return err; 550 } 551