Blame view

common/update.c 7.15 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
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
15
16
  #if defined(CONFIG_SYS_NO_FLASH)
  #error "CONFIG_SYS_NO_FLASH defined, but FLASH is required for auto-update feature"
4bae90904   Bartlomiej Sieka   Automatic softwar...
17
18
19
20
21
  #endif
  
  #include <command.h>
  #include <flash.h>
  #include <net.h>
063705908   Kim Phillips   net/: sparse fixes
22
  #include <net/tftp.h>
4bae90904   Bartlomiej Sieka   Automatic softwar...
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  #include <malloc.h>
  
  /* 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
  
  extern ulong TftpRRQTimeoutMSecs;
  extern int TftpRRQTimeoutCountMax;
  extern flash_info_t flash_info[];
  extern ulong load_addr;
  
  static uchar *saved_prot_info;
  
  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 */
  	saved_timeout_msecs = TftpRRQTimeoutMSecs;
  	saved_timeout_count = TftpRRQTimeoutCountMax;
  	saved_netretry = strdup(getenv("netretry"));
  	saved_bootfile = strdup(BootFile);
  
  	/* set timeouts for auto-update */
  	TftpRRQTimeoutMSecs = msec_max;
  	TftpRRQTimeoutCountMax = cnt_max;
  
  	/* we don't want to retry the connection if errors occur */
  	setenv("netretry", "no");
  
  	/* download the update file */
  	load_addr = addr;
  	copy_filename(BootFile, filename, sizeof(BootFile));
e4bf0c5cf   Simon Glass   net: tftpput: Ren...
72
  	size = NetLoop(TFTPGET);
4bae90904   Bartlomiej Sieka   Automatic softwar...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  
  	if (size < 0)
  		rv = 1;
  	else if (size > 0)
  		flush_cache(addr, size);
  
  	/* restore changed globals and env variable */
  	TftpRRQTimeoutMSecs = saved_timeout_msecs;
  	TftpRRQTimeoutCountMax = saved_timeout_count;
  
  	setenv("netretry", saved_netretry);
  	if (saved_netretry != NULL)
  		free(saved_netretry);
  
  	if (saved_bootfile != NULL) {
  		copy_filename(BootFile, saved_bootfile, sizeof(BootFile));
  		free(saved_bootfile);
  	}
  
  	return rv;
  }
  
  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...
106
  			calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
4bae90904   Bartlomiej Sieka   Automatic softwar...
107
108
109
  		if (!saved_prot_info)
  			return 1;
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
110
  	for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
4bae90904   Bartlomiej Sieka   Automatic softwar...
111
112
113
114
115
116
117
118
  		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...
119
  		sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
4bae90904   Bartlomiej Sieka   Automatic softwar...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  
  		/*
  		 * 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...
144
  #if defined(CONFIG_SYS_FLASH_PROTECTION)
4bae90904   Bartlomiej Sieka   Automatic softwar...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  				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;
  }
  
  static int update_flash(ulong addr_source, ulong addr_first, ulong size)
  {
  	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;
  	}
  
  	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;
  }
8d6b73202   Andreas Pretzsch   automatic update ...
229
  int update_tftp(ulong addr)
4bae90904   Bartlomiej Sieka   Automatic softwar...
230
231
232
233
  {
  	char *filename, *env_addr;
  	int images_noffset, ndepth, noffset;
  	ulong update_addr, update_fladdr, update_size;
4bae90904   Bartlomiej Sieka   Automatic softwar...
234
  	void *fit;
8d6b73202   Andreas Pretzsch   automatic update ...
235
236
237
238
239
  	int ret = 0;
  
  	/* use already present image */
  	if (addr)
  		goto got_update_file;
4bae90904   Bartlomiej Sieka   Automatic softwar...
240
241
242
243
244
245
246
247
248
  
  	printf("Auto-update from TFTP: ");
  
  	/* get the file name of the update file */
  	filename = getenv(UPDATE_FILE_ENV);
  	if (filename == NULL) {
  		printf("failed, env. variable '%s' not found
  ",
  							UPDATE_FILE_ENV);
8d6b73202   Andreas Pretzsch   automatic update ...
249
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  	}
  
  	printf("trying update file '%s'
  ", filename);
  
  	/* get load address of downloaded update file */
  	if ((env_addr = getenv("loadaddr")) != NULL)
  		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 ...
266
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
267
  	}
8d6b73202   Andreas Pretzsch   automatic update ...
268
  got_update_file:
4bae90904   Bartlomiej Sieka   Automatic softwar...
269
270
271
272
273
274
  	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 ...
275
  		return 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
276
277
278
279
280
281
282
283
284
285
286
287
288
  	}
  
  	/* 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;
  
  		printf("Processing update '%s' :",
  			fit_get_name(fit, noffset, NULL));
b8da83665   Simon Glass   image: Rename fit...
289
  		if (!fit_image_verify(fit, noffset)) {
4bae90904   Bartlomiej Sieka   Automatic softwar...
290
291
  			printf("Error: invalid update hash, aborting
  ");
8d6b73202   Andreas Pretzsch   automatic update ...
292
  			ret = 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
293
294
295
296
297
298
299
300
301
302
  			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 ...
303
  			ret = 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
304
305
306
307
308
  			goto next_node;
  		}
  		if (update_flash(update_addr, update_fladdr, update_size)) {
  			printf("Error: can't flash update, aborting
  ");
8d6b73202   Andreas Pretzsch   automatic update ...
309
  			ret = 1;
4bae90904   Bartlomiej Sieka   Automatic softwar...
310
311
312
313
314
  			goto next_node;
  		}
  next_node:
  		noffset = fdt_next_node(fit, noffset, &ndepth);
  	}
8d6b73202   Andreas Pretzsch   automatic update ...
315
  	return ret;
4bae90904   Bartlomiej Sieka   Automatic softwar...
316
  }