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