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
tftpfw_version_set(u32 version)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
tftpfw_version_get(void)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
tftp_download(void * addr,const char * file)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
update_cleanup(void * fit,struct update_header * hdr)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
is_gpt(const char * name)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
update_populate_image(void * fit,struct update_header * hdr)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
update_download_hdr(struct update_header * hdr)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
hdr_checksum_verify(void * fit,struct update_header * hdr)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
print_hdr_local(struct update_header * hdr,struct local_information * local)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
hdr_param_verify(void * fit,struct update_header * hdr,struct local_information * local,int conf)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
update_verify_hdr(void * fit,struct update_header * hdr,struct local_information * local)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
update_local_info(void * fit,struct update_header * hdr)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
update_ignore_image(void * fit,struct update_header * hdr,struct image_element * e)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
download_image(void * fit,struct image_element * e)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
update_flash_image(struct image_element * e)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
update_download_image(void * fit,struct image_element * e)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
update_write_gpt(void * fit,struct update_header * hdr)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
do_tftp_full_update(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])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