]> Git Repo - u-boot.git/blame - common/update.c
spl: opensbi: fix typo
[u-boot.git] / common / update.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
4bae9090
BS
2/*
3 * (C) Copyright 2008 Semihalf
4 *
5 * Written by: Rafal Czubak <[email protected]>
6 * Bartlomiej Sieka <[email protected]>
4bae9090
BS
7 */
8
9#include <common.h>
1eb69ae4 10#include <cpu_func.h>
8e8ccfe1 11#include <image.h>
4bae9090
BS
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
e856bdcf
MY
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"
c7ff5528
LM
19#endif
20
4bae9090 21#include <command.h>
9fb625ce 22#include <env.h>
4bae9090 23#include <net.h>
06370590 24#include <net/tftp.h>
4bae9090 25#include <malloc.h>
73f4ebb6 26#include <mapmem.h>
c7ff5528
LM
27#include <dfu.h>
28#include <errno.h>
4bae9090 29
50efdf2c 30#if defined(CONFIG_DFU_TFTP) || defined(CONFIG_UPDATE_TFTP)
4bae9090
BS
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
8885c5fe
JH
47extern ulong tftp_timeout_ms;
48extern int tftp_timeout_count_max;
e856bdcf 49#ifdef CONFIG_MTD_NOR_FLASH
17ead040
TR
50#include <flash.h>
51#include <mtd/cfi_flash.h>
4bae9090 52static uchar *saved_prot_info;
66a64723 53#endif
4bae9090
BS
54static 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 */
8885c5fe
JH
63 saved_timeout_msecs = tftp_timeout_ms;
64 saved_timeout_count = tftp_timeout_count_max;
00caae6d 65 saved_netretry = strdup(env_get("netretry"));
1411157d 66 saved_bootfile = strdup(net_boot_file_name);
4bae9090
BS
67
68 /* set timeouts for auto-update */
8885c5fe
JH
69 tftp_timeout_ms = msec_max;
70 tftp_timeout_count_max = cnt_max;
4bae9090
BS
71
72 /* we don't want to retry the connection if errors occur */
382bee57 73 env_set("netretry", "no");
4bae9090
BS
74
75 /* download the update file */
bb872dd9 76 image_load_addr = addr;
1411157d 77 copy_filename(net_boot_file_name, filename, sizeof(net_boot_file_name));
bc0571fc 78 size = net_loop(TFTPGET);
4bae9090
BS
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 */
8885c5fe
JH
86 tftp_timeout_ms = saved_timeout_msecs;
87 tftp_timeout_count_max = saved_timeout_count;
4bae9090 88
382bee57 89 env_set("netretry", saved_netretry);
4bae9090
BS
90 if (saved_netretry != NULL)
91 free(saved_netretry);
92
93 if (saved_bootfile != NULL) {
1411157d
JH
94 copy_filename(net_boot_file_name, saved_bootfile,
95 sizeof(net_boot_file_name));
4bae9090
BS
96 free(saved_bootfile);
97 }
98
99 return rv;
100}
101
e856bdcf 102#ifdef CONFIG_MTD_NOR_FLASH
4bae9090
BS
103static 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 =
98150e7e 114 calloc(CFI_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
4bae9090
BS
115 if (!saved_prot_info)
116 return 1;
117 }
118
98150e7e 119 for (bank = 0; bank < CFI_FLASH_BANKS; ++bank) {
4bae9090
BS
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 */
6d0f6bcf 128 sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
4bae9090
BS
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) {
6d0f6bcf 153#if defined(CONFIG_SYS_FLASH_PROTECTION)
4bae9090
BS
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}
66a64723 174#endif
4bae9090
BS
175
176static int update_flash(ulong addr_source, ulong addr_first, ulong size)
177{
e856bdcf 178#ifdef CONFIG_MTD_NOR_FLASH
4bae9090
BS
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 }
66a64723 214#endif
4bae9090
BS
215 return 0;
216}
50efdf2c 217#endif /* CONFIG_DFU_TFTP || CONFIG_UPDATE_TFTP */
4bae9090
BS
218
219static 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
50efdf2c 235#if defined(CONFIG_DFU_TFTP) || defined(CONFIG_UPDATE_TFTP)
c7ff5528 236int update_tftp(ulong addr, char *interface, char *devstring)
4bae9090 237{
c7ff5528 238 char *filename, *env_addr, *fit_image_name;
4bae9090 239 ulong update_addr, update_fladdr, update_size;
c7ff5528
LM
240 int images_noffset, ndepth, noffset;
241 bool update_tftp_dfu;
8d6b7320 242 int ret = 0;
c7ff5528
LM
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 {
9b643e31 250 pr_err("Interface: %s and devstring: %s not supported!\n",
c7ff5528
LM
251 interface, devstring);
252 return -EINVAL;
253 }
8d6b7320
AP
254
255 /* use already present image */
256 if (addr)
257 goto got_update_file;
4bae9090
BS
258
259 printf("Auto-update from TFTP: ");
260
261 /* get the file name of the update file */
00caae6d 262 filename = env_get(UPDATE_FILE_ENV);
4bae9090
BS
263 if (filename == NULL) {
264 printf("failed, env. variable '%s' not found\n",
265 UPDATE_FILE_ENV);
8d6b7320 266 return 1;
4bae9090
BS
267 }
268
269 printf("trying update file '%s'\n", filename);
270
271 /* get load address of downloaded update file */
00caae6d
SG
272 env_addr = env_get("loadaddr");
273 if (env_addr)
7e5f460e 274 addr = hextoul(env_addr, NULL);
4bae9090
BS
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");
8d6b7320 282 return 1;
4bae9090
BS
283 }
284
8d6b7320 285got_update_file:
73f4ebb6 286 fit = map_sysmem(addr, 0);
4bae9090 287
c5819701 288 if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
4bae9090
BS
289 printf("Bad FIT format of the update file, aborting "
290 "auto-update\n");
8d6b7320 291 return 1;
4bae9090
BS
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
c7ff5528
LM
303 fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
304 printf("Processing update '%s' :", fit_image_name);
4bae9090 305
b8da8366 306 if (!fit_image_verify(fit, noffset)) {
4bae9090 307 printf("Error: invalid update hash, aborting\n");
8d6b7320 308 ret = 1;
4bae9090
BS
309 goto next_node;
310 }
311
312 printf("\n");
313 if (update_fit_getparams(fit, noffset, &update_addr,
314 &update_fladdr, &update_size)) {
4e620eb9 315 printf("Error: can't get update parameters, aborting\n");
8d6b7320 316 ret = 1;
4bae9090
BS
317 goto next_node;
318 }
c7ff5528
LM
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)) {
1c2d1293
AT
329 ret = dfu_write_by_name(fit_image_name,
330 (void *)update_addr,
045fd8b1
AT
331 update_size, interface,
332 devstring);
c7ff5528
LM
333 if (ret)
334 return ret;
4bae9090
BS
335 }
336next_node:
337 noffset = fdt_next_node(fit, noffset, &ndepth);
338 }
339
8d6b7320 340 return ret;
4bae9090 341}
50efdf2c 342#endif /* CONFIG_DFU_UPDATE || CONFIG_UPDATE_TFTP */
3149e524
AT
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 */
355int 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
c5819701 365 if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
3149e524
AT
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 }
403next_node:
404 noffset = fdt_next_node(fit, noffset, &ndepth);
405 }
406
407 return ret;
408}
409#endif /* CONFIG_UPDATE_FIT */
This page took 0.400139 seconds and 4 git commands to generate.