Blame view

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

382bee57f   Simon Glass   env: Rename seten...
84
  	env_set("netretry", saved_netretry);
4bae90904   Bartlomiej Sieka   Automatic softwar...
85
86
87
88
  	if (saved_netretry != NULL)
  		free(saved_netretry);
  
  	if (saved_bootfile != NULL) {
1411157d8   Joe Hershberger   net: cosmetic: Fi...
89
90
  		copy_filename(net_boot_file_name, saved_bootfile,
  			      sizeof(net_boot_file_name));
4bae90904   Bartlomiej Sieka   Automatic softwar...
91
92
93
94
95
  		free(saved_bootfile);
  	}
  
  	return rv;
  }
e856bdcfb   Masahiro Yamada   flash: complete C...
96
  #ifdef CONFIG_MTD_NOR_FLASH
4bae90904   Bartlomiej Sieka   Automatic softwar...
97
98
99
100
101
102
103
104
105
106
107
  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...
108
  			calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
4bae90904   Bartlomiej Sieka   Automatic softwar...
109
110
111
  		if (!saved_prot_info)
  			return 1;
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
112
  	for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
4bae90904   Bartlomiej Sieka   Automatic softwar...
113
114
115
116
117
118
119
120
  		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...
121
  		sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
4bae90904   Bartlomiej Sieka   Automatic softwar...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  
  		/*
  		 * 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...
146
  #if defined(CONFIG_SYS_FLASH_PROTECTION)
4bae90904   Bartlomiej Sieka   Automatic softwar...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  				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...
168
  #endif
4bae90904   Bartlomiej Sieka   Automatic softwar...
169
170
171
  
  static int update_flash(ulong addr_source, ulong addr_first, ulong size)
  {
e856bdcfb   Masahiro Yamada   flash: complete C...
172
  #ifdef CONFIG_MTD_NOR_FLASH
4bae90904   Bartlomiej Sieka   Automatic softwar...
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
213
  	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...
214
  #endif
4bae90904   Bartlomiej Sieka   Automatic softwar...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  	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...
233
  int update_tftp(ulong addr, char *interface, char *devstring)
4bae90904   Bartlomiej Sieka   Automatic softwar...
234
  {
c7ff55284   Lukasz Majewski   update: tftp: dfu...
235
  	char *filename, *env_addr, *fit_image_name;
4bae90904   Bartlomiej Sieka   Automatic softwar...
236
  	ulong update_addr, update_fladdr, update_size;
c7ff55284   Lukasz Majewski   update: tftp: dfu...
237
238
  	int images_noffset, ndepth, noffset;
  	bool update_tftp_dfu;
8d6b73202   Andreas Pretzsch   automatic update ...
239
  	int ret = 0;
c7ff55284   Lukasz Majewski   update: tftp: dfu...
240
241
242
243
244
245
246
  	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...
247
248
  		pr_err("Interface: %s and devstring: %s not supported!
  ",
c7ff55284   Lukasz Majewski   update: tftp: dfu...
249
250
251
  		      interface, devstring);
  		return -EINVAL;
  	}
8d6b73202   Andreas Pretzsch   automatic update ...
252
253
254
255
  
  	/* use already present image */
  	if (addr)
  		goto got_update_file;
4bae90904   Bartlomiej Sieka   Automatic softwar...
256
257
258
259
  
  	printf("Auto-update from TFTP: ");
  
  	/* get the file name of the update file */
00caae6d4   Simon Glass   env: Rename geten...
260
  	filename = env_get(UPDATE_FILE_ENV);
4bae90904   Bartlomiej Sieka   Automatic softwar...
261
262
263
264
  	if (filename == NULL) {
  		printf("failed, env. variable '%s' not found
  ",
  							UPDATE_FILE_ENV);
8d6b73202   Andreas Pretzsch   automatic update ...
265
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
266
267
268
269
270
271
  	}
  
  	printf("trying update file '%s'
  ", filename);
  
  	/* get load address of downloaded update file */
00caae6d4   Simon Glass   env: Rename geten...
272
273
  	env_addr = env_get("loadaddr");
  	if (env_addr)
4bae90904   Bartlomiej Sieka   Automatic softwar...
274
275
276
277
278
279
280
281
282
  		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 ...
283
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
284
  	}
8d6b73202   Andreas Pretzsch   automatic update ...
285
  got_update_file:
4bae90904   Bartlomiej Sieka   Automatic softwar...
286
287
288
289
290
291
  	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 ...
292
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
293
294
295
296
297
298
299
300
301
302
  	}
  
  	/* 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...
303
304
  		fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
  		printf("Processing update '%s' :", fit_image_name);
4bae90904   Bartlomiej Sieka   Automatic softwar...
305

b8da83665   Simon Glass   image: Rename fit...
306
  		if (!fit_image_verify(fit, noffset)) {
4bae90904   Bartlomiej Sieka   Automatic softwar...
307
308
  			printf("Error: invalid update hash, aborting
  ");
8d6b73202   Andreas Pretzsch   automatic update ...
309
  			ret = 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
310
311
312
313
314
315
316
317
318
319
  			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 ...
320
  			ret = 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
321
322
  			goto next_node;
  		}
c7ff55284   Lukasz Majewski   update: tftp: dfu...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  
  		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...
338
339
340
341
  		}
  next_node:
  		noffset = fdt_next_node(fit, noffset, &ndepth);
  	}
8d6b73202   Andreas Pretzsch   automatic update ...
342
  	return ret;
4bae90904   Bartlomiej Sieka   Automatic softwar...
343
  }