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