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