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 static int fit_image_get_subnode(const void *fit, int noffset, const char *name) 58 { 59 int sub_noffset; 60 61 fdt_for_each_subnode(sub_noffset, fit, noffset) { 62 if (!strncmp(fit_get_name(fit, sub_noffset, NULL), 63 name, strlen(name))) 64 return sub_noffset; 65 } 66 67 return -ENOENT; 68 } 69 70 int fit_default_conf_get_node(const void *fit, const char *prop_name) 71 { 72 int conf_noffset; 73 74 conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */ 75 if (conf_noffset < 0) 76 return conf_noffset; 77 78 return fit_conf_get_prop_node(fit, conf_noffset, prop_name); 79 } 80 81 int fix_image_set_addr(const void *fit, const char *prop_name, 82 ulong old, ulong new) 83 { 84 int noffset; 85 86 /* do not fix if verified-boot */ 87 if (!fit_image_addr_is_placeholder(old) || 88 fit_sig_require_conf(fit, gd_fdt_blob())) 89 return 0; 90 91 noffset = fit_default_conf_get_node(fit, prop_name); 92 if (noffset < 0) 93 return noffset; 94 95 /* optional */ 96 fit_image_set_entry(fit, noffset, new); 97 98 return fit_image_set_load(fit, noffset, new); 99 } 100 101 static int fdt_image_get_offset_size(const void *fit, const char *prop_name, 102 int *offset, int *size) 103 { 104 int sz, offs; 105 int noffset; 106 int ret; 107 108 noffset = fit_default_conf_get_node(fit, prop_name); 109 if (noffset < 0) 110 return noffset; 111 112 ret = fit_image_get_data_size(fit, noffset, &sz); 113 if (ret) 114 return ret; 115 116 ret = fit_image_get_data_position(fit, noffset, &offs); 117 if (!ret) 118 offs -= fdt_totalsize(fit); 119 else 120 ret = fit_image_get_data_offset(fit, noffset, &offs); 121 122 *offset = offs; 123 *size = sz; 124 125 return ret; 126 } 127 128 static int fdt_image_get_load(const void *fit, const char *prop_name, 129 ulong *load) 130 { 131 int noffset; 132 133 noffset = fit_default_conf_get_node(fit, prop_name); 134 if (noffset < 0) 135 return noffset; 136 137 return fit_image_get_load(fit, noffset, load); 138 } 139 140 static int fit_image_get_param(const void *fit, const char *prop_name, 141 ulong *load, int *offset, int *size) 142 { 143 int ret; 144 145 ret = fdt_image_get_offset_size(fit, prop_name, offset, size); 146 if (ret < 0) 147 return ret; 148 149 return fdt_image_get_load(fit, prop_name, load); 150 } 151 152 static void *fit_get_blob(struct blk_desc *dev_desc, disk_partition_t *part) 153 { 154 void *fit, *fdt; 155 int blk_num; 156 157 blk_num = DIV_ROUND_UP(sizeof(struct fdt_header), dev_desc->blksz); 158 fdt = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz); 159 if (!fdt) 160 return NULL; 161 162 if (blk_dread(dev_desc, part->start, blk_num, fdt) != blk_num) { 163 debug("Failed to read fdt header\n"); 164 goto fail; 165 } 166 167 if (fdt_check_header(fdt)) { 168 debug("No fdt header\n"); 169 goto fail; 170 } 171 172 if (!fit_is_ext_type(fdt)) { 173 debug("Not external type\n"); 174 goto fail; 175 } 176 177 blk_num = DIV_ROUND_UP(fdt_totalsize(fdt), dev_desc->blksz); 178 fit = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz); 179 if (!fit) { 180 debug("No memory\n"); 181 goto fail; 182 } 183 184 if (blk_dread(dev_desc, part->start, blk_num, fit) != blk_num) { 185 free(fit); 186 debug("Failed to read fit blob\n"); 187 goto fail; 188 } 189 190 return fit; 191 192 fail: 193 free(fdt); 194 return NULL; 195 } 196 197 static int fit_image_fixup_alloc(const void *fit, const char *prop_name, 198 const char *addr_name, enum memblk_id mem) 199 { 200 ulong load, addr; 201 int offset, size = 0; 202 int ret; 203 204 addr = env_get_ulong(addr_name, 16, 0); 205 if (!addr) 206 return -EINVAL; 207 208 ret = fit_image_get_param(fit, prop_name, &load, &offset, &size); 209 if (ret) 210 return (ret == -FDT_ERR_NOTFOUND) ? 0 : ret; 211 212 if (!size) 213 return 0; 214 215 ret = fix_image_set_addr(fit, prop_name, load, addr); 216 if (ret) 217 return ret; 218 219 if (!sysmem_alloc_base(mem, (phys_addr_t)addr, 220 ALIGN(size, RK_BLK_SIZE))) 221 return -ENOMEM; 222 223 return 0; 224 } 225 226 int fit_image_pre_process(const void *fit) 227 { 228 int ret; 229 230 #ifdef CONFIG_USING_KERNEL_DTB 231 sysmem_free((phys_addr_t)gd->fdt_blob); 232 #endif 233 ret = fit_image_fixup_alloc(fit, FIT_FDT_PROP, 234 "fdt_addr_r", MEM_FDT); 235 if (ret < 0) 236 return ret; 237 238 ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP, 239 "kernel_addr_r", MEM_KERNEL); 240 if (ret < 0) 241 return ret; 242 243 return fit_image_fixup_alloc(fit, FIT_RAMDISK_PROP, 244 "ramdisk_addr_r", MEM_RAMDISK); 245 } 246 247 int fit_image_fail_process(const void *fit) 248 { 249 ulong raddr, kaddr, faddr; 250 251 raddr = env_get_ulong("ramdisk_addr_r", 16, 0); 252 kaddr = env_get_ulong("kernel_addr_r", 16, 0); 253 faddr = env_get_ulong("fdt_addr_r", 16, 0); 254 255 sysmem_free((phys_addr_t)fit); 256 sysmem_free((phys_addr_t)raddr); 257 sysmem_free((phys_addr_t)kaddr); 258 sysmem_free((phys_addr_t)faddr); 259 260 return 0; 261 } 262 263 static int fit_image_load_one(const void *fit, struct blk_desc *dev_desc, 264 disk_partition_t *part, char *prop_name, 265 void *data, int check_hash) 266 { 267 u32 blk_num, blk_off; 268 int offset, size; 269 int noffset, ret; 270 char *msg = ""; 271 272 ret = fdt_image_get_offset_size(fit, prop_name, &offset, &size); 273 if (ret) 274 return ret; 275 276 blk_off = (FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz; 277 blk_num = DIV_ROUND_UP(size, dev_desc->blksz); 278 if (blk_dread(dev_desc, part->start + blk_off, blk_num, data) != blk_num) 279 return -EIO; 280 281 if (check_hash) { 282 int hash_noffset; 283 284 noffset = fit_default_conf_get_node(fit, prop_name); 285 if (noffset < 0) 286 return noffset; 287 288 hash_noffset = fit_image_get_subnode(fit, noffset, 289 FIT_HASH_NODENAME); 290 if (hash_noffset < 0) 291 return hash_noffset; 292 293 printf("%s: ", fdt_get_name(fit, noffset, NULL)); 294 ret = fit_image_check_hash(fit, hash_noffset, data, size, &msg); 295 if (ret) 296 return ret; 297 298 puts("+\n"); 299 } 300 301 return 0; 302 } 303 304 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE 305 static int fit_image_load_resource(const void *fit, struct blk_desc *dev_desc, 306 disk_partition_t *part, ulong *addr) 307 { 308 int offset, size; 309 int ret; 310 void *data; 311 312 ret = fdt_image_get_offset_size(fit, FIT_MULTI_PROP, &offset, &size); 313 if (ret) 314 return ret; 315 316 data = malloc(ALIGN(size, dev_desc->blksz)); 317 if (!data) 318 return -ENOMEM; 319 320 *addr = (ulong)data; 321 322 return fit_image_load_one(fit, dev_desc, part, FIT_MULTI_PROP, 323 data, IS_ENABLED(CONFIG_FIT_SIGNATURE)); 324 } 325 #endif 326 327 /* Calculate what we really need */ 328 ulong fit_image_get_bootables_size(const void *fit) 329 { 330 ulong off[3] = { 0, 0, 0 }; 331 ulong max_off, load; 332 int offset, size; 333 334 #if 0 335 if (!fit_get_totalsize(fit, &size)) 336 return size; 337 #endif 338 339 if (!fit_image_get_param(fit, FIT_FDT_PROP, &load, &offset, &size)) 340 off[0] = offset + FIT_ALIGN(size); 341 342 if (!fit_image_get_param(fit, FIT_KERNEL_PROP, &load, &offset, &size)) 343 off[1] = offset + FIT_ALIGN(size); 344 345 if (!fit_image_get_param(fit, FIT_RAMDISK_PROP, &load, &offset, &size)) 346 off[2] = offset + FIT_ALIGN(size); 347 348 max_off = max(off[0], off[1]); 349 max_off = max(max_off, off[2]); 350 351 return FIT_ALIGN(fdt_totalsize(fit)) + max_off; 352 } 353 354 void *fit_image_load_bootables(ulong *size) 355 { 356 struct blk_desc *dev_desc; 357 disk_partition_t part; 358 char *part_name; 359 int blk_num; 360 void *fit; 361 362 dev_desc = rockchip_get_bootdev(); 363 if (!dev_desc) 364 return NULL; 365 366 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) 367 part_name = PART_RECOVERY; 368 else 369 part_name = PART_BOOT; 370 371 if (part_get_info_by_name(dev_desc, part_name, &part) < 0) { 372 FIT_I("No %s partition\n", part_name); 373 return NULL; 374 } 375 376 fit = fit_get_blob(dev_desc, &part); 377 if (!fit) { 378 FIT_I("No fit blob\n"); 379 return NULL; 380 } 381 382 *size = fit_image_get_bootables_size(fit); 383 if (*size == 0) { 384 FIT_I("No bootable image\n"); 385 return NULL; 386 } 387 388 blk_num = DIV_ROUND_UP(*size, dev_desc->blksz); 389 fit = sysmem_alloc(MEM_FIT, blk_num * dev_desc->blksz); 390 if (!fit) 391 return NULL; 392 393 if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) { 394 FIT_I("Failed to load bootable images\n"); 395 return NULL; 396 } 397 398 return fit; 399 } 400 401 static void fit_msg(const void *fit) 402 { 403 FIT_I("%ssigned, %sconf required\n", 404 fit_is_signed(fit, gd_fdt_blob()) ? "" : "no ", 405 fit_sig_require_conf(fit, gd_fdt_blob()) ? "" : "no "); 406 } 407 408 int fit_image_init_resource(void) 409 { 410 int conf_noffset __maybe_unused; 411 ulong rsce __maybe_unused; 412 struct blk_desc *dev_desc; 413 disk_partition_t part; 414 char *part_name; 415 void *fit; 416 int ret; 417 418 dev_desc = rockchip_get_bootdev(); 419 if (!dev_desc) { 420 FIT_I("No dev_desc!\n"); 421 return -ENODEV; 422 } 423 424 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) 425 part_name = PART_RECOVERY; 426 else 427 part_name = PART_BOOT; 428 429 ret = part_get_info_by_name(dev_desc, part_name, &part); 430 if (ret < 0) { 431 FIT_I("No %s partition\n", part_name); 432 return ret; 433 } 434 435 fit = fit_get_blob(dev_desc, &part); 436 if (!fit) { 437 FIT_I("No fdt blob\n"); 438 return -EINVAL; 439 } 440 441 #ifdef CONFIG_FIT_SIGNATURE 442 conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */ 443 if (conf_noffset < 0) 444 return conf_noffset; 445 446 printf("%s: ", fdt_get_name(fit, conf_noffset, NULL)); 447 if (fit_config_verify(fit, conf_noffset)) 448 return -EACCES; 449 450 puts("\n"); 451 #endif 452 453 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE 454 ret = fit_image_load_resource(fit, dev_desc, &part, &rsce); 455 if (ret) { 456 FIT_I("Failed to load resource\n"); 457 goto out; 458 } 459 460 ret = resource_create_ram_list(dev_desc, (void *)rsce); 461 if (ret) { 462 FIT_I("Failed to create resource list\n"); 463 goto out; 464 } 465 #endif 466 467 fit_msg(fit); 468 out: 469 free(fit); 470 471 return ret; 472 } 473 474