1 /*
2  * (C) Copyright 2008 Semihalf
3  *
4  * Written by: Rafal Czubak <rcz@semihalf.com>
5  *             Bartlomiej Sieka <tur@semihalf.com>
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  *
25  */
26 
27 #include <common.h>
28 
29 #if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT))
30 #error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature"
31 #endif
32 
33 #if defined(CONFIG_SYS_NO_FLASH)
34 #error "CONFIG_SYS_NO_FLASH defined, but FLASH is required for auto-update feature"
35 #endif
36 
37 #include <command.h>
38 #include <flash.h>
39 #include <net.h>
40 #include <malloc.h>
41 
42 /* env variable holding the location of the update file */
43 #define UPDATE_FILE_ENV		"updatefile"
44 
45 /* set configuration defaults if needed */
46 #ifndef CONFIG_UPDATE_LOAD_ADDR
47 #define CONFIG_UPDATE_LOAD_ADDR	0x100000
48 #endif
49 
50 #ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
51 #define CONFIG_UPDATE_TFTP_MSEC_MAX	100
52 #endif
53 
54 #ifndef CONFIG_UPDATE_TFTP_CNT_MAX
55 #define CONFIG_UPDATE_TFTP_CNT_MAX	0
56 #endif
57 
58 extern ulong TftpRRQTimeoutMSecs;
59 extern int TftpRRQTimeoutCountMax;
60 extern flash_info_t flash_info[];
61 extern ulong load_addr;
62 
63 static uchar *saved_prot_info;
64 
update_load(char * filename,ulong msec_max,int cnt_max,ulong addr)65 static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr)
66 {
67 	int size, rv;
68 	ulong saved_timeout_msecs;
69 	int saved_timeout_count;
70 	char *saved_netretry, *saved_bootfile;
71 
72 	rv = 0;
73 	/* save used globals and env variable */
74 	saved_timeout_msecs = TftpRRQTimeoutMSecs;
75 	saved_timeout_count = TftpRRQTimeoutCountMax;
76 	saved_netretry = strdup(getenv("netretry"));
77 	saved_bootfile = strdup(BootFile);
78 
79 	/* set timeouts for auto-update */
80 	TftpRRQTimeoutMSecs = msec_max;
81 	TftpRRQTimeoutCountMax = cnt_max;
82 
83 	/* we don't want to retry the connection if errors occur */
84 	setenv("netretry", "no");
85 
86 	/* download the update file */
87 	load_addr = addr;
88 	copy_filename(BootFile, filename, sizeof(BootFile));
89 	size = NetLoop(TFTP);
90 
91 	if (size < 0)
92 		rv = 1;
93 	else if (size > 0)
94 		flush_cache(addr, size);
95 
96 	/* restore changed globals and env variable */
97 	TftpRRQTimeoutMSecs = saved_timeout_msecs;
98 	TftpRRQTimeoutCountMax = saved_timeout_count;
99 
100 	setenv("netretry", saved_netretry);
101 	if (saved_netretry != NULL)
102 		free(saved_netretry);
103 
104 	if (saved_bootfile != NULL) {
105 		copy_filename(BootFile, saved_bootfile, sizeof(BootFile));
106 		free(saved_bootfile);
107 	}
108 
109 	return rv;
110 }
111 
update_flash_protect(int prot,ulong addr_first,ulong addr_last)112 static int update_flash_protect(int prot, ulong addr_first, ulong addr_last)
113 {
114 	uchar *sp_info_ptr;
115 	ulong s;
116 	int i, bank, cnt;
117 	flash_info_t *info;
118 
119 	sp_info_ptr = NULL;
120 
121 	if (prot == 0) {
122 		saved_prot_info =
123 			calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
124 		if (!saved_prot_info)
125 			return 1;
126 	}
127 
128 	for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
129 		cnt = 0;
130 		info = &flash_info[bank];
131 
132 		/* Nothing to do if the bank doesn't exist */
133 		if (info->sector_count == 0)
134 			return 0;
135 
136 		/* Point to current bank protection information */
137 		sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
138 
139 		/*
140 		 * Adjust addr_first or addr_last if we are on bank boundary.
141 		 * Address space between banks must be continuous for other
142 		 * flash functions (like flash_sect_erase or flash_write) to
143 		 * succeed. Banks must also be numbered in correct order,
144 		 * according to increasing addresses.
145 		 */
146 		if (addr_last > info->start[0] + info->size - 1)
147 			addr_last = info->start[0] + info->size - 1;
148 		if (addr_first < info->start[0])
149 			addr_first = info->start[0];
150 
151 		for (i = 0; i < info->sector_count; i++) {
152 			/* Save current information about protected sectors */
153 			if (prot == 0) {
154 				s = info->start[i];
155 				if ((s >= addr_first) && (s <= addr_last))
156 					sp_info_ptr[i] = info->protect[i];
157 
158 			}
159 
160 			/* Protect/unprotect sectors */
161 			if (sp_info_ptr[i] == 1) {
162 #if defined(CONFIG_SYS_FLASH_PROTECTION)
163 				if (flash_real_protect(info, i, prot))
164 					return 1;
165 #else
166 				info->protect[i] = prot;
167 #endif
168 				cnt++;
169 			}
170 		}
171 
172 		if (cnt) {
173 			printf("%sProtected %d sectors\n",
174 						prot ? "": "Un-", cnt);
175 		}
176 	}
177 
178 	if((prot == 1) && saved_prot_info)
179 		free(saved_prot_info);
180 
181 	return 0;
182 }
183 
update_flash(ulong addr_source,ulong addr_first,ulong size)184 static int update_flash(ulong addr_source, ulong addr_first, ulong size)
185 {
186 	ulong addr_last = addr_first + size - 1;
187 
188 	/* round last address to the sector boundary */
189 	if (flash_sect_roundb(&addr_last) > 0)
190 		return 1;
191 
192 	if (addr_first >= addr_last) {
193 		printf("Error: end address exceeds addressing space\n");
194 		return 1;
195 	}
196 
197 	/* remove protection on processed sectors */
198 	if (update_flash_protect(0, addr_first, addr_last) > 0) {
199 		printf("Error: could not unprotect flash sectors\n");
200 		return 1;
201 	}
202 
203 	printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last);
204 	if (flash_sect_erase(addr_first, addr_last) > 0) {
205 		printf("Error: could not erase flash\n");
206 		return 1;
207 	}
208 
209 	printf("Copying to flash...");
210 	if (flash_write((char *)addr_source, addr_first, size) > 0) {
211 		printf("Error: could not copy to flash\n");
212 		return 1;
213 	}
214 	printf("done\n");
215 
216 	/* enable protection on processed sectors */
217 	if (update_flash_protect(1, addr_first, addr_last) > 0) {
218 		printf("Error: could not protect flash sectors\n");
219 		return 1;
220 	}
221 
222 	return 0;
223 }
224 
update_fit_getparams(const void * fit,int noffset,ulong * addr,ulong * fladdr,ulong * size)225 static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
226 						ulong *fladdr, ulong *size)
227 {
228 	const void *data;
229 
230 	if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
231 		return 1;
232 
233 	if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
234 		return 1;
235 
236 	*addr = (ulong)data;
237 
238 	return 0;
239 }
240 
update_tftp(void)241 void update_tftp(void)
242 {
243 	char *filename, *env_addr;
244 	int images_noffset, ndepth, noffset;
245 	ulong update_addr, update_fladdr, update_size;
246 	ulong addr;
247 	void *fit;
248 
249 	printf("Auto-update from TFTP: ");
250 
251 	/* get the file name of the update file */
252 	filename = getenv(UPDATE_FILE_ENV);
253 	if (filename == NULL) {
254 		printf("failed, env. variable '%s' not found\n",
255 							UPDATE_FILE_ENV);
256 		return;
257 	}
258 
259 	printf("trying update file '%s'\n", filename);
260 
261 	/* get load address of downloaded update file */
262 	if ((env_addr = getenv("loadaddr")) != NULL)
263 		addr = simple_strtoul(env_addr, NULL, 16);
264 	else
265 		addr = CONFIG_UPDATE_LOAD_ADDR;
266 
267 
268 	if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
269 					CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
270 		printf("Can't load update file, aborting auto-update\n");
271 		return;
272 	}
273 
274 	fit = (void *)addr;
275 
276 	if (!fit_check_format((void *)fit)) {
277 		printf("Bad FIT format of the update file, aborting "
278 							"auto-update\n");
279 		return;
280 	}
281 
282 	/* process updates */
283 	images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
284 
285 	ndepth = 0;
286 	noffset = fdt_next_node(fit, images_noffset, &ndepth);
287 	while (noffset >= 0 && ndepth > 0) {
288 		if (ndepth != 1)
289 			goto next_node;
290 
291 		printf("Processing update '%s' :",
292 			fit_get_name(fit, noffset, NULL));
293 
294 		if (!fit_image_check_hashes(fit, noffset)) {
295 			printf("Error: invalid update hash, aborting\n");
296 			goto next_node;
297 		}
298 
299 		printf("\n");
300 		if (update_fit_getparams(fit, noffset, &update_addr,
301 					&update_fladdr, &update_size)) {
302 			printf("Error: can't get update parameteres, "
303 								"aborting\n");
304 			goto next_node;
305 		}
306 		if (update_flash(update_addr, update_fladdr, update_size)) {
307 			printf("Error: can't flash update, aborting\n");
308 			goto next_node;
309 		}
310 next_node:
311 		noffset = fdt_next_node(fit, noffset, &ndepth);
312 	}
313 
314 	return;
315 }
316