xref: /OK3568_Linux_fs/u-boot/cmd/tftp_update.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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
249 #ifdef CONFIG_DM_CRYPTO
sha256_checksum(char * input,u32 input_len,u8 * output)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
sha256_checksum(char * input,u32 input_len,u8 * output)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 
hdr_checksum_verify(void * fit,struct update_header * hdr)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 
print_hdr_local(struct update_header * hdr,struct local_information * local)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 
hdr_param_verify(void * fit,struct update_header * hdr,struct local_information * local,int conf)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 
update_verify_hdr(void * fit,struct update_header * hdr,struct local_information * local)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 
update_local_info(void * fit,struct update_header * hdr)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 
update_ignore_image(void * fit,struct update_header * hdr,struct image_element * e)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 
download_image(void * fit,struct image_element * e)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 
update_flash_image(struct image_element * e)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 
update_download_image(void * fit,struct image_element * e)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 
update_write_gpt(void * fit,struct update_header * hdr)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 
do_tftp_full_update(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])631 static int do_tftp_full_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 	tftp_full_update, 2, 1, do_tftp_full_update,
759 	"Update a set of images organized with FIT via network using TFTP protocol",
760 	"[[server-dir:][partition]"
761 );
762 
763