Merge tag 'tpm-030822' of https://source.denx.de/u-boot/custodians/u-boot-tpm
[platform/kernel/u-boot.git] / common / update.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2008 Semihalf
4  *
5  * Written by: Rafal Czubak <rcz@semihalf.com>
6  *             Bartlomiej Sieka <tur@semihalf.com>
7  */
8
9 #include <common.h>
10 #include <cpu_func.h>
11 #include <image.h>
12
13 #if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT))
14 #error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature"
15 #endif
16
17 #if defined(CONFIG_UPDATE_TFTP) && !defined(CONFIG_MTD_NOR_FLASH)
18 #error "CONFIG_UPDATE_TFTP and !CONFIG_MTD_NOR_FLASH needed for legacy behaviour"
19 #endif
20
21 #include <command.h>
22 #include <env.h>
23 #include <net.h>
24 #include <net/tftp.h>
25 #include <malloc.h>
26 #include <mapmem.h>
27 #include <dfu.h>
28 #include <errno.h>
29
30 #if defined(CONFIG_DFU_TFTP) || defined(CONFIG_UPDATE_TFTP)
31 /* env variable holding the location of the update file */
32 #define UPDATE_FILE_ENV         "updatefile"
33
34 /* set configuration defaults if needed */
35 #ifndef CONFIG_UPDATE_LOAD_ADDR
36 #define CONFIG_UPDATE_LOAD_ADDR 0x100000
37 #endif
38
39 #ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
40 #define CONFIG_UPDATE_TFTP_MSEC_MAX     100
41 #endif
42
43 #ifndef CONFIG_UPDATE_TFTP_CNT_MAX
44 #define CONFIG_UPDATE_TFTP_CNT_MAX      0
45 #endif
46
47 extern ulong tftp_timeout_ms;
48 extern int tftp_timeout_count_max;
49 #ifdef CONFIG_MTD_NOR_FLASH
50 #include <flash.h>
51 #include <mtd/cfi_flash.h>
52 static uchar *saved_prot_info;
53 #endif
54 static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr)
55 {
56         int size, rv;
57         ulong saved_timeout_msecs;
58         int saved_timeout_count;
59         char *saved_netretry, *saved_bootfile;
60
61         rv = 0;
62         /* save used globals and env variable */
63         saved_timeout_msecs = tftp_timeout_ms;
64         saved_timeout_count = tftp_timeout_count_max;
65         saved_netretry = strdup(env_get("netretry"));
66         saved_bootfile = strdup(net_boot_file_name);
67
68         /* set timeouts for auto-update */
69         tftp_timeout_ms = msec_max;
70         tftp_timeout_count_max = cnt_max;
71
72         /* we don't want to retry the connection if errors occur */
73         env_set("netretry", "no");
74
75         /* download the update file */
76         image_load_addr = addr;
77         copy_filename(net_boot_file_name, filename, sizeof(net_boot_file_name));
78         size = net_loop(TFTPGET);
79
80         if (size < 0)
81                 rv = 1;
82         else if (size > 0)
83                 flush_cache(addr, size);
84
85         /* restore changed globals and env variable */
86         tftp_timeout_ms = saved_timeout_msecs;
87         tftp_timeout_count_max = saved_timeout_count;
88
89         env_set("netretry", saved_netretry);
90         if (saved_netretry != NULL)
91                 free(saved_netretry);
92
93         if (saved_bootfile != NULL) {
94                 copy_filename(net_boot_file_name, saved_bootfile,
95                               sizeof(net_boot_file_name));
96                 free(saved_bootfile);
97         }
98
99         return rv;
100 }
101
102 #ifdef CONFIG_MTD_NOR_FLASH
103 static int update_flash_protect(int prot, ulong addr_first, ulong addr_last)
104 {
105         uchar *sp_info_ptr;
106         ulong s;
107         int i, bank, cnt;
108         flash_info_t *info;
109
110         sp_info_ptr = NULL;
111
112         if (prot == 0) {
113                 saved_prot_info =
114                         calloc(CFI_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
115                 if (!saved_prot_info)
116                         return 1;
117         }
118
119         for (bank = 0; bank < CFI_FLASH_BANKS; ++bank) {
120                 cnt = 0;
121                 info = &flash_info[bank];
122
123                 /* Nothing to do if the bank doesn't exist */
124                 if (info->sector_count == 0)
125                         return 0;
126
127                 /* Point to current bank protection information */
128                 sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
129
130                 /*
131                  * Adjust addr_first or addr_last if we are on bank boundary.
132                  * Address space between banks must be continuous for other
133                  * flash functions (like flash_sect_erase or flash_write) to
134                  * succeed. Banks must also be numbered in correct order,
135                  * according to increasing addresses.
136                  */
137                 if (addr_last > info->start[0] + info->size - 1)
138                         addr_last = info->start[0] + info->size - 1;
139                 if (addr_first < info->start[0])
140                         addr_first = info->start[0];
141
142                 for (i = 0; i < info->sector_count; i++) {
143                         /* Save current information about protected sectors */
144                         if (prot == 0) {
145                                 s = info->start[i];
146                                 if ((s >= addr_first) && (s <= addr_last))
147                                         sp_info_ptr[i] = info->protect[i];
148
149                         }
150
151                         /* Protect/unprotect sectors */
152                         if (sp_info_ptr[i] == 1) {
153 #if defined(CONFIG_SYS_FLASH_PROTECTION)
154                                 if (flash_real_protect(info, i, prot))
155                                         return 1;
156 #else
157                                 info->protect[i] = prot;
158 #endif
159                                 cnt++;
160                         }
161                 }
162
163                 if (cnt) {
164                         printf("%sProtected %d sectors\n",
165                                                 prot ? "": "Un-", cnt);
166                 }
167         }
168
169         if((prot == 1) && saved_prot_info)
170                 free(saved_prot_info);
171
172         return 0;
173 }
174 #endif
175
176 static int update_flash(ulong addr_source, ulong addr_first, ulong size)
177 {
178 #ifdef CONFIG_MTD_NOR_FLASH
179         ulong addr_last = addr_first + size - 1;
180
181         /* round last address to the sector boundary */
182         if (flash_sect_roundb(&addr_last) > 0)
183                 return 1;
184
185         if (addr_first >= addr_last) {
186                 printf("Error: end address exceeds addressing space\n");
187                 return 1;
188         }
189
190         /* remove protection on processed sectors */
191         if (update_flash_protect(0, addr_first, addr_last) > 0) {
192                 printf("Error: could not unprotect flash sectors\n");
193                 return 1;
194         }
195
196         printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last);
197         if (flash_sect_erase(addr_first, addr_last) > 0) {
198                 printf("Error: could not erase flash\n");
199                 return 1;
200         }
201
202         printf("Copying to flash...");
203         if (flash_write((char *)addr_source, addr_first, size) > 0) {
204                 printf("Error: could not copy to flash\n");
205                 return 1;
206         }
207         printf("done\n");
208
209         /* enable protection on processed sectors */
210         if (update_flash_protect(1, addr_first, addr_last) > 0) {
211                 printf("Error: could not protect flash sectors\n");
212                 return 1;
213         }
214 #endif
215         return 0;
216 }
217 #endif /* CONFIG_DFU_TFTP || CONFIG_UPDATE_TFTP */
218
219 static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
220                                                 ulong *fladdr, ulong *size)
221 {
222         const void *data;
223
224         if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
225                 return 1;
226
227         if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
228                 return 1;
229
230         *addr = (ulong)data;
231
232         return 0;
233 }
234
235 #if defined(CONFIG_DFU_TFTP) || defined(CONFIG_UPDATE_TFTP)
236 int update_tftp(ulong addr, char *interface, char *devstring)
237 {
238         char *filename, *env_addr, *fit_image_name;
239         ulong update_addr, update_fladdr, update_size;
240         int images_noffset, ndepth, noffset;
241         bool update_tftp_dfu;
242         int ret = 0;
243         void *fit;
244
245         if (interface == NULL && devstring == NULL) {
246                 update_tftp_dfu = false;
247         } else if (interface && devstring) {
248                 update_tftp_dfu = true;
249         } else {
250                 pr_err("Interface: %s and devstring: %s not supported!\n",
251                       interface, devstring);
252                 return -EINVAL;
253         }
254
255         /* use already present image */
256         if (addr)
257                 goto got_update_file;
258
259         printf("Auto-update from TFTP: ");
260
261         /* get the file name of the update file */
262         filename = env_get(UPDATE_FILE_ENV);
263         if (filename == NULL) {
264                 printf("failed, env. variable '%s' not found\n",
265                                                         UPDATE_FILE_ENV);
266                 return 1;
267         }
268
269         printf("trying update file '%s'\n", filename);
270
271         /* get load address of downloaded update file */
272         env_addr = env_get("loadaddr");
273         if (env_addr)
274                 addr = hextoul(env_addr, NULL);
275         else
276                 addr = CONFIG_UPDATE_LOAD_ADDR;
277
278
279         if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
280                                         CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
281                 printf("Can't load update file, aborting auto-update\n");
282                 return 1;
283         }
284
285 got_update_file:
286         fit = map_sysmem(addr, 0);
287
288         if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
289                 printf("Bad FIT format of the update file, aborting "
290                                                         "auto-update\n");
291                 return 1;
292         }
293
294         /* process updates */
295         images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
296
297         ndepth = 0;
298         noffset = fdt_next_node(fit, images_noffset, &ndepth);
299         while (noffset >= 0 && ndepth > 0) {
300                 if (ndepth != 1)
301                         goto next_node;
302
303                 fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
304                 printf("Processing update '%s' :", fit_image_name);
305
306                 if (!fit_image_verify(fit, noffset)) {
307                         printf("Error: invalid update hash, aborting\n");
308                         ret = 1;
309                         goto next_node;
310                 }
311
312                 printf("\n");
313                 if (update_fit_getparams(fit, noffset, &update_addr,
314                                         &update_fladdr, &update_size)) {
315                         printf("Error: can't get update parameters, aborting\n");
316                         ret = 1;
317                         goto next_node;
318                 }
319
320                 if (!update_tftp_dfu) {
321                         if (update_flash(update_addr, update_fladdr,
322                                          update_size)) {
323                                 printf("Error: can't flash update, aborting\n");
324                                 ret = 1;
325                                 goto next_node;
326                         }
327                 } else if (fit_image_check_type(fit, noffset,
328                                                 IH_TYPE_FIRMWARE)) {
329                         ret = dfu_write_by_name(fit_image_name,
330                                                 (void *)update_addr,
331                                                 update_size, interface,
332                                                 devstring);
333                         if (ret)
334                                 return ret;
335                 }
336 next_node:
337                 noffset = fdt_next_node(fit, noffset, &ndepth);
338         }
339
340         return ret;
341 }
342 #endif /* CONFIG_DFU_UPDATE || CONFIG_UPDATE_TFTP */
343
344 #ifdef CONFIG_UPDATE_FIT
345 /**
346  * fit_update - update storage with FIT image
347  * @fit:        Pointer to FIT image
348  *
349  * Update firmware on storage using FIT image as input.
350  * The storage area to be update will be identified by the name
351  * in FIT and matching it to "dfu_alt_info" variable.
352  *
353  * Return:      0 - on success, non-zero - otherwise
354  */
355 int fit_update(const void *fit)
356 {
357         char *fit_image_name;
358         ulong update_addr, update_fladdr, update_size;
359         int images_noffset, ndepth, noffset;
360         int ret = 0;
361
362         if (!fit)
363                 return -EINVAL;
364
365         if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
366                 printf("Bad FIT format of the update file, aborting auto-update\n");
367                 return -EINVAL;
368         }
369
370         /* process updates */
371         images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
372
373         ndepth = 0;
374         noffset = fdt_next_node(fit, images_noffset, &ndepth);
375         while (noffset >= 0 && ndepth > 0) {
376                 if (ndepth != 1)
377                         goto next_node;
378
379                 fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
380                 printf("Processing update '%s' :", fit_image_name);
381
382                 if (!fit_image_verify(fit, noffset)) {
383                         printf("Error: invalid update hash, aborting\n");
384                         ret = 1;
385                         goto next_node;
386                 }
387
388                 printf("\n");
389                 if (update_fit_getparams(fit, noffset, &update_addr,
390                                          &update_fladdr, &update_size)) {
391                         printf("Error: can't get update parameters, aborting\n");
392                         ret = 1;
393                         goto next_node;
394                 }
395
396                 if (fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE)) {
397                         ret = dfu_write_by_name(fit_image_name,
398                                                 (void *)update_addr,
399                                                 update_size, NULL, NULL);
400                         if (ret)
401                                 return ret;
402                 }
403 next_node:
404                 noffset = fdt_next_node(fit, noffset, &ndepth);
405         }
406
407         return ret;
408 }
409 #endif /* CONFIG_UPDATE_FIT */