Blame view

common/update.c 8 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
4bae90904   Bartlomiej Sieka   Automatic softwar...
2
3
4
5
6
  /*
   * (C) Copyright 2008 Semihalf
   *
   * Written by: Rafal Czubak <rcz@semihalf.com>
   *             Bartlomiej Sieka <tur@semihalf.com>
4bae90904   Bartlomiej Sieka   Automatic softwar...
7
8
9
10
11
12
13
   */
  
  #include <common.h>
  
  #if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT))
  #error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature"
  #endif
e856bdcfb   Masahiro Yamada   flash: complete C...
14
15
  #if defined(CONFIG_UPDATE_TFTP) && !defined(CONFIG_MTD_NOR_FLASH)
  #error "CONFIG_UPDATE_TFTP and !CONFIG_MTD_NOR_FLASH needed for legacy behaviour"
c7ff55284   Lukasz Majewski   update: tftp: dfu...
16
  #endif
4bae90904   Bartlomiej Sieka   Automatic softwar...
17
18
19
  #include <command.h>
  #include <flash.h>
  #include <net.h>
063705908   Kim Phillips   net/: sparse fixes
20
  #include <net/tftp.h>
4bae90904   Bartlomiej Sieka   Automatic softwar...
21
  #include <malloc.h>
c7ff55284   Lukasz Majewski   update: tftp: dfu...
22
23
  #include <dfu.h>
  #include <errno.h>
175c3e3ad   Marek Vasut   tftp: update: Inc...
24
  #include <mtd/cfi_flash.h>
4bae90904   Bartlomiej Sieka   Automatic softwar...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  
  /* env variable holding the location of the update file */
  #define UPDATE_FILE_ENV		"updatefile"
  
  /* set configuration defaults if needed */
  #ifndef CONFIG_UPDATE_LOAD_ADDR
  #define CONFIG_UPDATE_LOAD_ADDR	0x100000
  #endif
  
  #ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
  #define CONFIG_UPDATE_TFTP_MSEC_MAX	100
  #endif
  
  #ifndef CONFIG_UPDATE_TFTP_CNT_MAX
  #define CONFIG_UPDATE_TFTP_CNT_MAX	0
  #endif
8885c5fe9   Joe Hershberger   net: cosmetic: Cl...
41
42
  extern ulong tftp_timeout_ms;
  extern int tftp_timeout_count_max;
4bae90904   Bartlomiej Sieka   Automatic softwar...
43
  extern ulong load_addr;
e856bdcfb   Masahiro Yamada   flash: complete C...
44
  #ifdef CONFIG_MTD_NOR_FLASH
66a647238   Lukasz Majewski   tftp: update: All...
45
  extern flash_info_t flash_info[];
4bae90904   Bartlomiej Sieka   Automatic softwar...
46
  static uchar *saved_prot_info;
66a647238   Lukasz Majewski   tftp: update: All...
47
  #endif
4bae90904   Bartlomiej Sieka   Automatic softwar...
48
49
50
51
52
53
54
55
56
  static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr)
  {
  	int size, rv;
  	ulong saved_timeout_msecs;
  	int saved_timeout_count;
  	char *saved_netretry, *saved_bootfile;
  
  	rv = 0;
  	/* save used globals and env variable */
8885c5fe9   Joe Hershberger   net: cosmetic: Cl...
57
58
  	saved_timeout_msecs = tftp_timeout_ms;
  	saved_timeout_count = tftp_timeout_count_max;
00caae6d4   Simon Glass   env: Rename geten...
59
  	saved_netretry = strdup(env_get("netretry"));
1411157d8   Joe Hershberger   net: cosmetic: Fi...
60
  	saved_bootfile = strdup(net_boot_file_name);
4bae90904   Bartlomiej Sieka   Automatic softwar...
61
62
  
  	/* set timeouts for auto-update */
8885c5fe9   Joe Hershberger   net: cosmetic: Cl...
63
64
  	tftp_timeout_ms = msec_max;
  	tftp_timeout_count_max = cnt_max;
4bae90904   Bartlomiej Sieka   Automatic softwar...
65
66
  
  	/* we don't want to retry the connection if errors occur */
382bee57f   Simon Glass   env: Rename seten...
67
  	env_set("netretry", "no");
4bae90904   Bartlomiej Sieka   Automatic softwar...
68
69
70
  
  	/* download the update file */
  	load_addr = addr;
1411157d8   Joe Hershberger   net: cosmetic: Fi...
71
  	copy_filename(net_boot_file_name, filename, sizeof(net_boot_file_name));
bc0571fc1   Joe Hershberger   net: cosmetic: Fi...
72
  	size = net_loop(TFTPGET);
4bae90904   Bartlomiej Sieka   Automatic softwar...
73
74
75
76
77
78
79
  
  	if (size < 0)
  		rv = 1;
  	else if (size > 0)
  		flush_cache(addr, size);
  
  	/* restore changed globals and env variable */
8885c5fe9   Joe Hershberger   net: cosmetic: Cl...
80
81
  	tftp_timeout_ms = saved_timeout_msecs;
  	tftp_timeout_count_max = saved_timeout_count;
4bae90904   Bartlomiej Sieka   Automatic softwar...
82

382bee57f   Simon Glass   env: Rename seten...
83
  	env_set("netretry", saved_netretry);
4bae90904   Bartlomiej Sieka   Automatic softwar...
84
85
86
87
  	if (saved_netretry != NULL)
  		free(saved_netretry);
  
  	if (saved_bootfile != NULL) {
1411157d8   Joe Hershberger   net: cosmetic: Fi...
88
89
  		copy_filename(net_boot_file_name, saved_bootfile,
  			      sizeof(net_boot_file_name));
4bae90904   Bartlomiej Sieka   Automatic softwar...
90
91
92
93
94
  		free(saved_bootfile);
  	}
  
  	return rv;
  }
e856bdcfb   Masahiro Yamada   flash: complete C...
95
  #ifdef CONFIG_MTD_NOR_FLASH
4bae90904   Bartlomiej Sieka   Automatic softwar...
96
97
98
99
100
101
102
103
104
105
106
  static int update_flash_protect(int prot, ulong addr_first, ulong addr_last)
  {
  	uchar *sp_info_ptr;
  	ulong s;
  	int i, bank, cnt;
  	flash_info_t *info;
  
  	sp_info_ptr = NULL;
  
  	if (prot == 0) {
  		saved_prot_info =
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
107
  			calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
4bae90904   Bartlomiej Sieka   Automatic softwar...
108
109
110
  		if (!saved_prot_info)
  			return 1;
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
111
  	for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
4bae90904   Bartlomiej Sieka   Automatic softwar...
112
113
114
115
116
117
118
119
  		cnt = 0;
  		info = &flash_info[bank];
  
  		/* Nothing to do if the bank doesn't exist */
  		if (info->sector_count == 0)
  			return 0;
  
  		/* Point to current bank protection information */
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
120
  		sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
4bae90904   Bartlomiej Sieka   Automatic softwar...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  
  		/*
  		 * Adjust addr_first or addr_last if we are on bank boundary.
  		 * Address space between banks must be continuous for other
  		 * flash functions (like flash_sect_erase or flash_write) to
  		 * succeed. Banks must also be numbered in correct order,
  		 * according to increasing addresses.
  		 */
  		if (addr_last > info->start[0] + info->size - 1)
  			addr_last = info->start[0] + info->size - 1;
  		if (addr_first < info->start[0])
  			addr_first = info->start[0];
  
  		for (i = 0; i < info->sector_count; i++) {
  			/* Save current information about protected sectors */
  			if (prot == 0) {
  				s = info->start[i];
  				if ((s >= addr_first) && (s <= addr_last))
  					sp_info_ptr[i] = info->protect[i];
  
  			}
  
  			/* Protect/unprotect sectors */
  			if (sp_info_ptr[i] == 1) {
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
145
  #if defined(CONFIG_SYS_FLASH_PROTECTION)
4bae90904   Bartlomiej Sieka   Automatic softwar...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  				if (flash_real_protect(info, i, prot))
  					return 1;
  #else
  				info->protect[i] = prot;
  #endif
  				cnt++;
  			}
  		}
  
  		if (cnt) {
  			printf("%sProtected %d sectors
  ",
  						prot ? "": "Un-", cnt);
  		}
  	}
  
  	if((prot == 1) && saved_prot_info)
  		free(saved_prot_info);
  
  	return 0;
  }
66a647238   Lukasz Majewski   tftp: update: All...
167
  #endif
4bae90904   Bartlomiej Sieka   Automatic softwar...
168
169
170
  
  static int update_flash(ulong addr_source, ulong addr_first, ulong size)
  {
e856bdcfb   Masahiro Yamada   flash: complete C...
171
  #ifdef CONFIG_MTD_NOR_FLASH
4bae90904   Bartlomiej Sieka   Automatic softwar...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  	ulong addr_last = addr_first + size - 1;
  
  	/* round last address to the sector boundary */
  	if (flash_sect_roundb(&addr_last) > 0)
  		return 1;
  
  	if (addr_first >= addr_last) {
  		printf("Error: end address exceeds addressing space
  ");
  		return 1;
  	}
  
  	/* remove protection on processed sectors */
  	if (update_flash_protect(0, addr_first, addr_last) > 0) {
  		printf("Error: could not unprotect flash sectors
  ");
  		return 1;
  	}
  
  	printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last);
  	if (flash_sect_erase(addr_first, addr_last) > 0) {
  		printf("Error: could not erase flash
  ");
  		return 1;
  	}
  
  	printf("Copying to flash...");
  	if (flash_write((char *)addr_source, addr_first, size) > 0) {
  		printf("Error: could not copy to flash
  ");
  		return 1;
  	}
  	printf("done
  ");
  
  	/* enable protection on processed sectors */
  	if (update_flash_protect(1, addr_first, addr_last) > 0) {
  		printf("Error: could not protect flash sectors
  ");
  		return 1;
  	}
66a647238   Lukasz Majewski   tftp: update: All...
213
  #endif
4bae90904   Bartlomiej Sieka   Automatic softwar...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  	return 0;
  }
  
  static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
  						ulong *fladdr, ulong *size)
  {
  	const void *data;
  
  	if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
  		return 1;
  
  	if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
  		return 1;
  
  	*addr = (ulong)data;
  
  	return 0;
  }
c7ff55284   Lukasz Majewski   update: tftp: dfu...
232
  int update_tftp(ulong addr, char *interface, char *devstring)
4bae90904   Bartlomiej Sieka   Automatic softwar...
233
  {
c7ff55284   Lukasz Majewski   update: tftp: dfu...
234
  	char *filename, *env_addr, *fit_image_name;
4bae90904   Bartlomiej Sieka   Automatic softwar...
235
  	ulong update_addr, update_fladdr, update_size;
c7ff55284   Lukasz Majewski   update: tftp: dfu...
236
237
  	int images_noffset, ndepth, noffset;
  	bool update_tftp_dfu;
8d6b73202   Andreas Pretzsch   automatic update ...
238
  	int ret = 0;
c7ff55284   Lukasz Majewski   update: tftp: dfu...
239
240
241
242
243
244
245
  	void *fit;
  
  	if (interface == NULL && devstring == NULL) {
  		update_tftp_dfu = false;
  	} else if (interface && devstring) {
  		update_tftp_dfu = true;
  	} else {
9b643e312   Masahiro Yamada   treewide: replace...
246
247
  		pr_err("Interface: %s and devstring: %s not supported!
  ",
c7ff55284   Lukasz Majewski   update: tftp: dfu...
248
249
250
  		      interface, devstring);
  		return -EINVAL;
  	}
8d6b73202   Andreas Pretzsch   automatic update ...
251
252
253
254
  
  	/* use already present image */
  	if (addr)
  		goto got_update_file;
4bae90904   Bartlomiej Sieka   Automatic softwar...
255
256
257
258
  
  	printf("Auto-update from TFTP: ");
  
  	/* get the file name of the update file */
00caae6d4   Simon Glass   env: Rename geten...
259
  	filename = env_get(UPDATE_FILE_ENV);
4bae90904   Bartlomiej Sieka   Automatic softwar...
260
261
262
263
  	if (filename == NULL) {
  		printf("failed, env. variable '%s' not found
  ",
  							UPDATE_FILE_ENV);
8d6b73202   Andreas Pretzsch   automatic update ...
264
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
265
266
267
268
269
270
  	}
  
  	printf("trying update file '%s'
  ", filename);
  
  	/* get load address of downloaded update file */
00caae6d4   Simon Glass   env: Rename geten...
271
272
  	env_addr = env_get("loadaddr");
  	if (env_addr)
4bae90904   Bartlomiej Sieka   Automatic softwar...
273
274
275
276
277
278
279
280
281
  		addr = simple_strtoul(env_addr, NULL, 16);
  	else
  		addr = CONFIG_UPDATE_LOAD_ADDR;
  
  
  	if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
  					CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
  		printf("Can't load update file, aborting auto-update
  ");
8d6b73202   Andreas Pretzsch   automatic update ...
282
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
283
  	}
8d6b73202   Andreas Pretzsch   automatic update ...
284
  got_update_file:
4bae90904   Bartlomiej Sieka   Automatic softwar...
285
286
287
288
289
290
  	fit = (void *)addr;
  
  	if (!fit_check_format((void *)fit)) {
  		printf("Bad FIT format of the update file, aborting "
  							"auto-update
  ");
8d6b73202   Andreas Pretzsch   automatic update ...
291
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
292
293
294
295
296
297
298
299
300
301
  	}
  
  	/* process updates */
  	images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
  
  	ndepth = 0;
  	noffset = fdt_next_node(fit, images_noffset, &ndepth);
  	while (noffset >= 0 && ndepth > 0) {
  		if (ndepth != 1)
  			goto next_node;
c7ff55284   Lukasz Majewski   update: tftp: dfu...
302
303
  		fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
  		printf("Processing update '%s' :", fit_image_name);
4bae90904   Bartlomiej Sieka   Automatic softwar...
304

b8da83665   Simon Glass   image: Rename fit...
305
  		if (!fit_image_verify(fit, noffset)) {
4bae90904   Bartlomiej Sieka   Automatic softwar...
306
307
  			printf("Error: invalid update hash, aborting
  ");
8d6b73202   Andreas Pretzsch   automatic update ...
308
  			ret = 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
309
310
311
312
313
314
315
316
317
318
  			goto next_node;
  		}
  
  		printf("
  ");
  		if (update_fit_getparams(fit, noffset, &update_addr,
  					&update_fladdr, &update_size)) {
  			printf("Error: can't get update parameteres, "
  								"aborting
  ");
8d6b73202   Andreas Pretzsch   automatic update ...
319
  			ret = 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
320
321
  			goto next_node;
  		}
c7ff55284   Lukasz Majewski   update: tftp: dfu...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  
  		if (!update_tftp_dfu) {
  			if (update_flash(update_addr, update_fladdr,
  					 update_size)) {
  				printf("Error: can't flash update, aborting
  ");
  				ret = 1;
  				goto next_node;
  			}
  		} else if (fit_image_check_type(fit, noffset,
  						IH_TYPE_FIRMWARE)) {
  			ret = dfu_tftp_write(fit_image_name, update_addr,
  					     update_size, interface, devstring);
  			if (ret)
  				return ret;
4bae90904   Bartlomiej Sieka   Automatic softwar...
337
338
339
340
  		}
  next_node:
  		noffset = fdt_next_node(fit, noffset, &ndepth);
  	}
8d6b73202   Andreas Pretzsch   automatic update ...
341
  	return ret;
4bae90904   Bartlomiej Sieka   Automatic softwar...
342
  }