Merge branch '2020-10-23-misc-changes'
[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 <flash.h>
24 #include <net.h>
25 #include <net/tftp.h>
26 #include <malloc.h>
27 #include <mapmem.h>
28 #include <dfu.h>
29 #include <errno.h>
30 #include <mtd/cfi_flash.h>
31
32 /* env variable holding the location of the update file */
33 #define UPDATE_FILE_ENV         "updatefile"
34
35 /* set configuration defaults if needed */
36 #ifndef CONFIG_UPDATE_LOAD_ADDR
37 #define CONFIG_UPDATE_LOAD_ADDR 0x100000
38 #endif
39
40 #ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
41 #define CONFIG_UPDATE_TFTP_MSEC_MAX     100
42 #endif
43
44 #ifndef CONFIG_UPDATE_TFTP_CNT_MAX
45 #define CONFIG_UPDATE_TFTP_CNT_MAX      0
46 #endif
47
48 extern ulong tftp_timeout_ms;
49 extern int tftp_timeout_count_max;
50 #ifdef CONFIG_MTD_NOR_FLASH
51 extern flash_info_t flash_info[];
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(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
115                 if (!saved_prot_info)
116                         return 1;
117         }
118
119         for (bank = 0; bank < CONFIG_SYS_MAX_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
218 static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
219                                                 ulong *fladdr, ulong *size)
220 {
221         const void *data;
222
223         if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
224                 return 1;
225
226         if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
227                 return 1;
228
229         *addr = (ulong)data;
230
231         return 0;
232 }
233
234 int update_tftp(ulong addr, char *interface, char *devstring)
235 {
236         char *filename, *env_addr, *fit_image_name;
237         ulong update_addr, update_fladdr, update_size;
238         int images_noffset, ndepth, noffset;
239         bool update_tftp_dfu;
240         int ret = 0;
241         void *fit;
242
243         if (interface == NULL && devstring == NULL) {
244                 update_tftp_dfu = false;
245         } else if (interface && devstring) {
246                 update_tftp_dfu = true;
247         } else {
248                 pr_err("Interface: %s and devstring: %s not supported!\n",
249                       interface, devstring);
250                 return -EINVAL;
251         }
252
253         /* use already present image */
254         if (addr)
255                 goto got_update_file;
256
257         printf("Auto-update from TFTP: ");
258
259         /* get the file name of the update file */
260         filename = env_get(UPDATE_FILE_ENV);
261         if (filename == NULL) {
262                 printf("failed, env. variable '%s' not found\n",
263                                                         UPDATE_FILE_ENV);
264                 return 1;
265         }
266
267         printf("trying update file '%s'\n", filename);
268
269         /* get load address of downloaded update file */
270         env_addr = env_get("loadaddr");
271         if (env_addr)
272                 addr = simple_strtoul(env_addr, NULL, 16);
273         else
274                 addr = CONFIG_UPDATE_LOAD_ADDR;
275
276
277         if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
278                                         CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
279                 printf("Can't load update file, aborting auto-update\n");
280                 return 1;
281         }
282
283 got_update_file:
284         fit = map_sysmem(addr, 0);
285
286         if (!fit_check_format((void *)fit)) {
287                 printf("Bad FIT format of the update file, aborting "
288                                                         "auto-update\n");
289                 return 1;
290         }
291
292         /* process updates */
293         images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
294
295         ndepth = 0;
296         noffset = fdt_next_node(fit, images_noffset, &ndepth);
297         while (noffset >= 0 && ndepth > 0) {
298                 if (ndepth != 1)
299                         goto next_node;
300
301                 fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
302                 printf("Processing update '%s' :", fit_image_name);
303
304                 if (!fit_image_verify(fit, noffset)) {
305                         printf("Error: invalid update hash, aborting\n");
306                         ret = 1;
307                         goto next_node;
308                 }
309
310                 printf("\n");
311                 if (update_fit_getparams(fit, noffset, &update_addr,
312                                         &update_fladdr, &update_size)) {
313                         printf("Error: can't get update parameters, aborting\n");
314                         ret = 1;
315                         goto next_node;
316                 }
317
318                 if (!update_tftp_dfu) {
319                         if (update_flash(update_addr, update_fladdr,
320                                          update_size)) {
321                                 printf("Error: can't flash update, aborting\n");
322                                 ret = 1;
323                                 goto next_node;
324                         }
325                 } else if (fit_image_check_type(fit, noffset,
326                                                 IH_TYPE_FIRMWARE)) {
327                         ret = dfu_tftp_write(fit_image_name, update_addr,
328                                              update_size, interface, devstring);
329                         if (ret)
330                                 return ret;
331                 }
332 next_node:
333                 noffset = fdt_next_node(fit, noffset, &ndepth);
334         }
335
336         return ret;
337 }