1 /* 2 * (C) Copyright 2021 Rockchip Electronics Co., Ltd. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <boot_rkimg.h> 9 #include <crypto.h> 10 #include <dm.h> 11 #include <sysmem.h> 12 #include <u-boot/sha256.h> 13 #ifdef CONFIG_ANDROID_AB 14 #include <android_avb/avb_ops_user.h> 15 #include <android_avb/rk_avb_ops_user.h> 16 #endif 17 #include <asm/arch/vendor.h> 18 19 DECLARE_GLOBAL_DATA_PTR; 20 21 #define TFTPUD_I(fmt, args...) printf("[TFTPUD]: "fmt, ##args) 22 #define TFTPUD_E(fmt, args...) printf("[TFTPUD-ERROR]: "fmt, ##args) 23 24 #define UPDATE_HDR_FILE "update.hdr" 25 #define GPT_ENV_FILE "gpt_env.txt" 26 #define MAX_UPDATE_HEADER_SIZE SZ_128K 27 #define MAX_REMAIN_TRIES 3 28 #define SHA256_HASH_SIZE 32 29 30 struct update_header { 31 struct list_head images; 32 void *shared_buf; 33 u32 version; 34 u32 rollback_idx; 35 u32 lba_step; 36 u32 mb; 37 int force_update; 38 const char *spec_partition; 39 }; 40 41 struct local_information { 42 u32 version; 43 u32 rollback_idx; 44 char current_slot[3]; 45 }; 46 47 struct image_element { 48 char file_name[32]; 49 char part_name[32]; 50 void *buf; 51 u32 size; /* uint: byte */ 52 u32 lba_start; 53 u32 lba_offset; 54 u32 lba_cnt; 55 u8 remain_tries; 56 int hash_noffset; 57 struct list_head node; 58 }; 59 60 static struct update_header update_hdr; 61 static struct local_information local_info; 62 static const char *server_dir; 63 64 static int tftpfw_version_set(u32 version) 65 { 66 int ret; 67 68 ret = vendor_storage_write(FIRMWARE_VER_ID, &version, sizeof(version)); 69 70 return ret < 0 ? ret : 0; 71 } 72 73 static u32 tftpfw_version_get(void) 74 { 75 u32 version; 76 int ret; 77 78 ret = vendor_storage_read(FIRMWARE_VER_ID, &version, sizeof(version)); 79 if (ret < 0) { 80 if (ret == -EINVAL) { 81 version = 0; /* first initial as 0 */ 82 TFTPUD_I("Initial firmware version as 0\n"); 83 ret = tftpfw_version_set(version); 84 if (ret < 0) 85 return ret; 86 } else { 87 return ret; 88 } 89 } 90 91 return version; 92 } 93 94 static int tftp_download(void *addr, const char *file) 95 { 96 char tftp_cmd[64]; 97 98 if (server_dir) 99 snprintf(tftp_cmd, 64, "tftp 0x%lx %s/%s", 100 (ulong)addr, server_dir, file); 101 else 102 snprintf(tftp_cmd, 64, "tftp 0x%lx %s", (ulong)addr, file); 103 104 return run_command(tftp_cmd, 0); 105 } 106 107 static void update_cleanup(void *fit, struct update_header *hdr) 108 { 109 struct image_element *e; 110 struct list_head *node; 111 112 list_for_each(node, &hdr->images) { 113 e = list_entry(node, struct image_element, node); 114 free(e); 115 } 116 117 if (hdr->shared_buf) 118 free(hdr->shared_buf); 119 if (fit) 120 free(fit); 121 } 122 123 static inline int is_gpt(const char *name) 124 { 125 if (!name) 126 return 0; 127 128 return !strcmp(name, GPT_ENV_FILE); 129 } 130 131 static int update_populate_image(void *fit, struct update_header *hdr) 132 { 133 struct blk_desc *dev_desc; 134 struct image_element *e; 135 disk_partition_t part; 136 const char *name, *dp; 137 const char *noseq_name; 138 char *last_part_name = NULL; 139 uint last_lba_offset = 0; 140 uint lba_offset; 141 int images, noffset; 142 int ret; 143 144 images = fdt_path_offset(fit, FIT_IMAGES_PATH); 145 if (images < 0) 146 return images; 147 148 dev_desc = rockchip_get_bootdev(); 149 if (!dev_desc) 150 return -ENODEV; 151 152 fdt_for_each_subnode(noffset, fit, images) { 153 name = fit_get_name(fit, noffset, NULL); 154 printf("# %s:\n", name); 155 156 if (is_gpt(name)) 157 continue; 158 159 e = malloc(sizeof(*e)); 160 if (!e) 161 return -ENOMEM; 162 163 e->remain_tries = MAX_REMAIN_TRIES; 164 e->buf = hdr->shared_buf; 165 e->size = fdtdec_get_uint(fit, noffset, "data-size", -ENODATA); 166 if (e->size == -ENODATA) 167 return -ENODATA; 168 169 /* part name */ 170 strcpy(e->file_name, name); 171 strcat(e->file_name, ".part.img"); 172 noseq_name = strstr(name, "-"); 173 if (!noseq_name) 174 return -EINVAL; 175 noseq_name++; 176 dp = strstr(noseq_name, "-"); 177 if (!dp) 178 return -EINVAL; 179 dp++; 180 strlcpy(e->part_name, noseq_name, strlen(noseq_name) - strlen(dp)); 181 ret = part_get_info_by_name_strict(dev_desc, e->part_name, &part); 182 if (ret < 0) { 183 TFTPUD_E("No partition '%s'\n", e->part_name); 184 return -EINVAL; 185 } 186 187 /* lba */ 188 if (!strcmp(last_part_name, e->part_name)) 189 lba_offset = last_lba_offset + hdr->lba_step; 190 else 191 lba_offset = 0; 192 193 e->lba_start = part.start; 194 e->lba_offset = lba_offset; 195 e->lba_cnt = DIV_ROUND_UP(e->size, 512); 196 e->hash_noffset = fdt_subnode_offset(fit, noffset, "hash"); 197 if (e->hash_noffset < 0) 198 return e->hash_noffset; 199 200 list_add_tail(&e->node, &hdr->images); 201 last_part_name = e->part_name; 202 last_lba_offset = lba_offset; 203 204 printf(" file: %s\n", e->file_name); 205 printf(" partition: %s\n", e->part_name); 206 printf(" buf: 0x%08lx\n", (ulong)e->buf); 207 printf(" size: 0x%08x\n", e->size); 208 printf(" lba_start: 0x%08x\n", e->lba_start); 209 printf(" lba_offset: 0x%08x\n", e->lba_offset); 210 printf(" lba_cnt: 0x%08x\n", e->lba_cnt); 211 printf(" remain_tries: %d\n", e->remain_tries); 212 printf(" hash_noffset: 0x%08x\n\n", e->hash_noffset); 213 } 214 215 return 0; 216 } 217 218 static void *update_download_hdr(struct update_header *hdr) 219 { 220 u32 filesz; 221 void *fit; 222 223 fit = memalign(ARCH_DMA_MINALIGN, MAX_UPDATE_HEADER_SIZE); 224 if (!fit) 225 return NULL; 226 227 if (tftp_download(fit, UPDATE_HDR_FILE)) { 228 free(fit); 229 return NULL; 230 } 231 232 if (fdt_check_header(fit)) { 233 TFTPUD_E("invalid update hdr magic\n"); 234 free(fit); 235 return NULL; 236 } 237 238 /* sha256 csum was appended at the end of update.hdr */ 239 filesz = env_get_ulong("filesize", 16, 0); 240 if ((fdt_totalsize(fit) + SHA256_HASH_SIZE) != filesz) { 241 TFTPUD_E("invalid sha256 hash at the tail of hdr\n"); 242 return NULL; 243 } 244 245 return fit; 246 } 247 248 #ifndef CONFIG_FIT_SIGNATURE 249 static int hdr_checksum_verify(void *fit, struct update_header *hdr) 250 { 251 u8 *hash, csum[SHA256_HASH_SIZE]; 252 int ret, i; 253 254 hash = (u8 *)fit + fdt_totalsize(fit); 255 sha256_csum((const uchar *)fit, fdt_totalsize(fit), csum); 256 ret = memcmp(hash, csum, SHA256_HASH_SIZE) ? -EINVAL : 0; 257 if (ret) { 258 printf(" update.hash: "); 259 for (i = 0; i < SHA256_HASH_SIZE; i++) 260 printf("%02x", hash[i]); 261 printf("\n"); 262 263 printf(" calculate hash: "); 264 for (i = 0; i < SHA256_HASH_SIZE; i++) 265 printf("%02x", csum[i]); 266 printf("\n"); 267 } 268 269 return ret; 270 } 271 #endif 272 273 static void print_hdr_local(struct update_header *hdr, 274 struct local_information *local) 275 { 276 printf("# Server:\n"); 277 printf(" version: %d\n", hdr->version); 278 printf(" rollback_idx: %d\n", hdr->rollback_idx); 279 printf(" force_update: %d\n", hdr->force_update); 280 printf(" MB: %d\n", hdr->mb); 281 printf(" lba_step: 0x%08x\n", hdr->lba_step); 282 printf(" shared_buf: 0x%08lx - 0x%08lx\n", 283 (ulong)hdr->shared_buf, (ulong)hdr->shared_buf + hdr->mb * SZ_1M); 284 printf(" spec_partition: %s\n\n", hdr->spec_partition); 285 286 printf("# Local:\n"); 287 printf(" version: %d\n", local->version); 288 printf(" rollback_idx: %d\n", local->rollback_idx); 289 printf(" current_slot: %s\n", local->current_slot); 290 printf("\n"); 291 } 292 293 static int hdr_param_verify(void *fit, struct update_header *hdr, 294 struct local_information *local, int conf) 295 { 296 u32 size; 297 int ret; 298 299 /* remote */ 300 hdr->version = fdtdec_get_uint(fit, 0, "version", 0); 301 hdr->rollback_idx = fdtdec_get_uint(fit, conf, "rollback-index", 0); 302 hdr->force_update = fdtdec_get_uint(fit, conf, "force_update", 0); 303 hdr->mb = fdtdec_get_uint(fit, conf, "image-size-MB", 0); 304 size = hdr->mb * SZ_1M; 305 hdr->lba_step = size / 512; 306 /* TODO: use sysmem alloc/free */ 307 hdr->shared_buf = malloc(size); 308 if (!hdr->shared_buf) 309 return -ENOMEM; 310 311 /* local */ 312 ret = tftpfw_version_get(); 313 if (ret < 0) { 314 TFTPUD_E("Failed to get local firmware version, ret=%d\n", ret); 315 return local->version; 316 } 317 local->version = ret; 318 #ifdef CONFIG_FIT_ROLLBACK_PROTECT 319 u32 remote_rollback_idx; 320 321 ret = fit_rollback_index_verify(fit, FIT_ROLLBACK_INDEX, 322 &remote_rollback_idx, &local->rollback_idx); 323 if (ret) { 324 TFTPUD_E("Failed to get local rollback-index, ret=%d\n", ret); 325 return ret; 326 } 327 #else 328 local->rollback_idx = -1; 329 #endif 330 #ifdef CONFIG_ANDROID_AB 331 ret = rk_avb_get_current_slot(local->current_slot); 332 if (ret) { 333 TFTPUD_E("Failed to get local current slot, ret=%d\n", ret); 334 return ret; 335 } 336 #else 337 strcpy(local->current_slot, "-"); 338 #endif 339 340 print_hdr_local(hdr, local); 341 342 /* verify */ 343 if (hdr->force_update) { 344 TFTPUD_I("Remote requires force upgrade !\n"); 345 return 0; 346 } 347 if (hdr->version < local->version) { 348 TFTPUD_E("Invalid firmware version: %d(remote) < %d(local)\n", 349 hdr->version, local->version); 350 return -EINVAL; 351 } 352 #ifdef CONFIG_FIT_ROLLBACK_PROTECT 353 if (remote_rollback_idx < local->rollback_idx) { 354 TFTPUD_E("Invalid rollback-index: %d(remote) < %d(local)\n", 355 remote_rollback_idx, local->rollback_idx); 356 return -EINVAL; 357 } 358 #endif 359 360 return 0; 361 } 362 363 static int update_verify_hdr(void *fit, struct update_header *hdr, 364 struct local_information *local) 365 { 366 const char *name; 367 int noffset; 368 int conf; 369 int ret; 370 371 noffset = fdt_path_offset(fit, FIT_CONFS_PATH); 372 name = fdt_getprop(fit, noffset, "default", NULL); 373 conf = fdt_subnode_offset(fit, noffset, name); 374 if (conf < 0) 375 return conf; 376 377 #ifdef CONFIG_FIT_SIGNATURE 378 /* Secure: verify signature */ 379 ret = fit_config_verify(fit, conf); 380 if (ret) 381 return ret; 382 383 TFTPUD_I("hdr signature verified\n"); 384 #else 385 /* Non-secure: verify hash */ 386 ret = hdr_checksum_verify(fit, hdr); 387 if (ret) 388 return ret; 389 390 TFTPUD_I("hdr checksum verified\n"); 391 #endif 392 /* verify rollback index ..., etc */ 393 ret = hdr_param_verify(fit, hdr, local, conf); 394 if (ret) 395 return ret; 396 397 TFTPUD_I("hdr param verified\n"); 398 399 return 0; 400 } 401 402 static int update_local_info(void *fit, struct update_header *hdr) 403 { 404 int ret; 405 406 TFTPUD_I("Update local information... "); 407 408 ret = tftpfw_version_set(hdr->version); 409 if (ret) { 410 TFTPUD_E("Update local param FAIL, ret=%d\n", ret); 411 return ret; 412 } 413 printf("fw_version=%d ", hdr->version); 414 415 #ifdef CONFIG_FIT_ROLLBACK_PROTECT 416 ret = fit_write_trusty_rollback_index(hdr->rollback_idx); 417 if (ret) 418 return ret; 419 printf("rollback_idx=%d ", hdr->rollback_idx); 420 #endif 421 printf("\n"); 422 423 return 0; 424 } 425 426 static int update_ignore_image(void *fit, struct update_header *hdr, 427 struct image_element *e) 428 { 429 #ifdef CONFIG_ANDROID_AB 430 char *slot_suffix; 431 432 /* Android A/B skip current slot */ 433 slot_suffix = (char *)e->part_name + strlen(e->part_name) - 2; 434 if (!strcmp(hdr->current_slot, slot_suffix)) 435 return 1; 436 #endif 437 /* try to find expected target partition */ 438 if (hdr->spec_partition && strcmp(e->part_name, hdr->spec_partition)) 439 return 1; 440 441 return 0; 442 } 443 444 static int download_image(void *fit, struct image_element *e) 445 { 446 ulong fileaddr; 447 ulong filesize; 448 char *msg = ""; 449 int ret; 450 451 /* download */ 452 printf("[TFTPUD-0]: download \"%s\" at 0x%lx\n", 453 e->file_name, (ulong)e->buf); 454 455 ret = tftp_download(e->buf, e->file_name); 456 if (ret) 457 return ret; 458 459 fileaddr = env_get_ulong("fileaddr", 16, 0); 460 filesize = env_get_ulong("filesize", 16, 0); 461 if (!fileaddr || !filesize) { 462 TFTPUD_E("No fileaddr and filesize\n"); 463 return -ENOENT; 464 } 465 466 if (filesize != e->size) { 467 TFTPUD_E("Expected filesize 0x%08lx != 0x%08x\n", filesize, e->size); 468 return -EINVAL; 469 } 470 471 /* verify */ 472 printf("[TFTPUD-1]: verify "); 473 ret = fit_image_check_hash(fit, e->hash_noffset, e->buf, e->size, &msg); 474 printf("[%s]\n", ret ? "-" : "+"); 475 476 return ret; 477 } 478 479 static int update_flash_image(struct image_element *e) 480 { 481 struct blk_desc *dev_desc; 482 int ret; 483 484 dev_desc = rockchip_get_bootdev(); 485 if (!dev_desc) { 486 TFTPUD_E("No boot device\n"); 487 return -ENODEV; 488 } 489 490 printf("[TFTPUD-2]: Flash to \"%s\" partition at LBA offset 0x%08x, " 491 "with 0x%08x sectors ... ", 492 e->part_name, e->lba_offset, e->lba_cnt); 493 494 if (dev_desc->if_type == IF_TYPE_MTD) { 495 dev_desc->op_flag |= BLK_MTD_CONT_WRITE; 496 ret = blk_dwrite(dev_desc, e->lba_start + e->lba_offset, 497 e->lba_cnt, (void *)e->buf); 498 dev_desc->op_flag &= ~(BLK_MTD_CONT_WRITE); 499 } else { 500 ret = blk_dwrite(dev_desc, e->lba_start + e->lba_offset, 501 e->lba_cnt, (void *)e->buf); 502 } 503 504 if (ret != e->lba_cnt) 505 printf("Failed(%d)\n\n\n", ret); 506 else 507 printf("OK\n\n\n"); 508 509 return 0; 510 } 511 512 static int update_download_image(void *fit, struct image_element *e) 513 { 514 int i, ret; 515 516 for (i = 0; i < e->remain_tries; i++) { 517 ret = download_image(fit, e); 518 if (!ret) 519 return 0; 520 521 TFTPUD_E("retry-%d download\n", i); 522 continue; 523 } 524 525 return -ENODATA; 526 } 527 528 static int update_write_gpt(void *fit, struct update_header *hdr) 529 { 530 struct image_element *e; 531 char *gpt_parts, *p; 532 const char *name; 533 int images; 534 int noffset; 535 int ret = 0; 536 537 images = fdt_path_offset(fit, FIT_IMAGES_PATH); 538 if (images < 0) 539 return images; 540 541 noffset = fdt_first_subnode(fit, images); 542 if (noffset < 0) 543 return noffset; 544 545 /* gpt must be the 1st node */ 546 name = fit_get_name(fit, noffset, NULL); 547 if (!is_gpt(name)) 548 return 0; 549 550 e = malloc(sizeof(*e)); 551 if (!e) 552 return -ENOMEM; 553 554 e->remain_tries = MAX_REMAIN_TRIES; 555 e->buf = hdr->shared_buf; 556 e->size = fdtdec_get_uint(fit, noffset, "data-size", -ENODATA); 557 if (e->size == -ENODATA) { 558 ret = -EINVAL; 559 goto out; 560 } 561 562 strcpy(e->file_name, name); 563 e->hash_noffset = fdt_subnode_offset(fit, noffset, "hash"); 564 if (e->hash_noffset < 0) 565 return e->hash_noffset; 566 567 printf("\n# %s:\n", e->file_name); 568 printf(" buf: 0x%08lx\n", (ulong)e->buf); 569 printf(" size: 0x%08x\n", e->size); 570 printf(" remain_tries: %d\n", e->remain_tries); 571 printf(" hash_noffset: 0x%08x\n\n", e->hash_noffset); 572 573 /* download */ 574 ret = update_download_image(fit, e); 575 if (ret) { 576 TFTPUD_E("\"%s\" download fail, ret=%d\n", 577 e->file_name, ret); 578 goto out; 579 } 580 581 /* terminate gpt string */ 582 gpt_parts = (char *)e->buf; 583 p = gpt_parts + e->size - 1; 584 *p = '\0'; 585 586 /* write */ 587 printf("[TFTPUD-2]: Write gpt ...\n"); 588 printf(" %s\n\n", gpt_parts); 589 env_set("gpt_parts", gpt_parts); 590 ret = run_command("gpt write ${devtype} ${devnum} ${gpt_parts}", 0); 591 if (ret) { 592 printf("Failed to write gpt\n"); 593 ret = -EIO; 594 goto out; 595 } 596 ret = run_command("gpt verify ${devtype} ${devnum} ${gpt_parts}", 0); 597 if (ret) { 598 printf("Failed to verify gpt\n"); 599 ret = -EIO; 600 goto out; 601 } 602 printf("\n"); 603 out: 604 free(e); 605 606 return ret; 607 } 608 609 static int do_tftp_full_update(cmd_tbl_t *cmdtp, int flag, 610 int argc, char * const argv[]) 611 { 612 struct local_information *local = &local_info; 613 struct update_header *hdr = &update_hdr; 614 struct image_element *e; 615 struct list_head *node; 616 const char *dir_part_str; 617 const char *part_str; 618 const char *dir_str; 619 char *dup_str = NULL; 620 u32 total_success = 0; 621 u32 total_traverse = 0; 622 ulong start_ms; 623 ulong total_ms; 624 void *fit; 625 int ret; 626 627 start_ms = get_timer(0); 628 memset(hdr, 0, sizeof(*hdr)); 629 memset(local, 0, sizeof(*local)); 630 631 /* only handle a single partititon ? */ 632 if (argc > 1) { 633 dir_part_str = argv[1]; 634 part_str = strchr(dir_part_str, ':'); 635 if (part_str) { 636 /* 637 * eg: tftpupdate image:recovery 638 * tftpupdate image:* 639 * tftpupdate image: 640 */ 641 dup_str = strdup(dir_part_str); 642 dup_str[part_str - dir_part_str] = 0; 643 dir_str = dup_str; 644 part_str++; 645 if (*part_str == '*') 646 part_str = NULL; 647 } else { 648 /* eg: tftpupdate recovery */ 649 dir_str = NULL; 650 part_str = argv[1]; 651 } 652 } else { 653 dir_str = NULL; 654 part_str = NULL; 655 } 656 657 server_dir = dir_str; 658 hdr->spec_partition = part_str; 659 INIT_LIST_HEAD(&hdr->images); 660 661 fit = update_download_hdr(hdr); 662 if (!fit) { 663 TFTPUD_E("download hdr fail\n"); 664 ret = -EINVAL; 665 goto out; 666 } 667 668 ret = update_verify_hdr(fit, hdr, local); 669 if (ret) { 670 TFTPUD_E("verify hdr fail, ret=%d\n", ret); 671 goto out; 672 } 673 674 /* flash gpt table early than any other partition */ 675 ret = update_write_gpt(fit, hdr); 676 if (ret) { 677 TFTPUD_E("write gpt fail, ret=%d\n", ret); 678 goto out; 679 } 680 681 ret = update_populate_image(fit, hdr); 682 if (ret) { 683 TFTPUD_E("populate image fail, ret=%d\n", ret); 684 goto out; 685 } 686 687 list_for_each(node, &hdr->images) { 688 e = list_entry(node, struct image_element, node); 689 total_traverse++; 690 691 /* ignore ? */ 692 if (update_ignore_image(fit, hdr, e)) 693 continue; 694 695 ret = update_download_image(fit, e); 696 if (ret) { 697 TFTPUD_E("\"%s\" download fail, ret=%d\n", 698 e->file_name, ret); 699 goto out; 700 } 701 702 ret = update_flash_image(e); 703 if (ret) { 704 TFTPUD_E("\"%s\" flash fail, ret=%d\n", 705 e->file_name, ret); 706 goto out; 707 } 708 709 total_success++; 710 } 711 712 if (total_success == 0) { 713 if (hdr->spec_partition) { 714 TFTPUD_E("No %s partition was found\n", hdr->spec_partition); 715 ret = CMD_RET_FAILURE; 716 } 717 goto out; 718 } 719 720 /* If this is full upgrade, update local info */ 721 if (!hdr->spec_partition) 722 update_local_info(fit, hdr); 723 out: 724 update_cleanup(fit, hdr); 725 if (!ret) { 726 total_ms = get_timer(start_ms); 727 TFTPUD_I("tftpupdate is OK (total time: %lds, upgrade: %d/%d), " 728 "system reboot is recommend\n", 729 total_ms / 1000, total_success, total_traverse); 730 } 731 732 return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; 733 } 734 735 U_BOOT_CMD( 736 tftp_full_update, 2, 1, do_tftp_full_update, 737 "Update a set of images organized with FIT via network using TFTP protocol", 738 "[[server-dir:][partition]" 739 ); 740 741