Merge branch 'master' of git://git.denx.de/u-boot-net
[platform/kernel/u-boot.git] / common / cmd_autoscript.c
1 /*
2  * (C) Copyright 2001
3  * Kyle Harris, kharris@nexus-tech.net
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * autoscript allows a remote host to download a command file and,
26  * optionally, binary data for automatically updating the target. For
27  * example, you create a new kernel image and want the user to be
28  * able to simply download the image and the machine does the rest.
29  * The kernel image is postprocessed with mkimage, which creates an
30  * image with a script file prepended. If enabled, autoscript will
31  * verify the script and contents of the download and execute the
32  * script portion. This would be responsible for erasing flash,
33  * copying the new image, and rebooting the machine.
34  */
35
36 /* #define DEBUG */
37
38 #include <common.h>
39 #include <command.h>
40 #include <image.h>
41 #include <malloc.h>
42 #include <asm/byteorder.h>
43 #if defined(CONFIG_8xx)
44 #include <mpc8xx.h>
45 #endif
46 #ifdef CONFIG_SYS_HUSH_PARSER
47 #include <hush.h>
48 #endif
49
50 int
51 autoscript (ulong addr, const char *fit_uname)
52 {
53         ulong           len;
54         image_header_t  *hdr;
55         ulong           *data;
56         char            *cmd;
57         int             rcode = 0;
58         int             verify;
59 #if defined(CONFIG_FIT)
60         const void*     fit_hdr;
61         int             noffset;
62         const void      *fit_data;
63         size_t          fit_len;
64 #endif
65
66         verify = getenv_yesno ("verify");
67
68         switch (genimg_get_format ((void *)addr)) {
69         case IMAGE_FORMAT_LEGACY:
70                 hdr = (image_header_t *)addr;
71
72                 if (!image_check_magic (hdr)) {
73                         puts ("Bad magic number\n");
74                         return 1;
75                 }
76
77                 if (!image_check_hcrc (hdr)) {
78                         puts ("Bad header crc\n");
79                         return 1;
80                 }
81
82                 if (verify) {
83                         if (!image_check_dcrc (hdr)) {
84                                 puts ("Bad data crc\n");
85                                 return 1;
86                         }
87                 }
88
89                 if (!image_check_type (hdr, IH_TYPE_SCRIPT)) {
90                         puts ("Bad image type\n");
91                         return 1;
92                 }
93
94                 /* get length of script */
95                 data = (ulong *)image_get_data (hdr);
96
97                 if ((len = uimage_to_cpu (*data)) == 0) {
98                         puts ("Empty Script\n");
99                         return 1;
100                 }
101
102                 /*
103                  * scripts are just multi-image files with one component, seek
104                  * past the zero-terminated sequence of image lengths to get
105                  * to the actual image data
106                  */
107                 while (*data++);
108                 break;
109 #if defined(CONFIG_FIT)
110         case IMAGE_FORMAT_FIT:
111                 if (fit_uname == NULL) {
112                         puts ("No FIT subimage unit name\n");
113                         return 1;
114                 }
115
116                 fit_hdr = (const void *)addr;
117                 if (!fit_check_format (fit_hdr)) {
118                         puts ("Bad FIT image format\n");
119                         return 1;
120                 }
121
122                 /* get script component image node offset */
123                 noffset = fit_image_get_node (fit_hdr, fit_uname);
124                 if (noffset < 0) {
125                         printf ("Can't find '%s' FIT subimage\n", fit_uname);
126                         return 1;
127                 }
128
129                 if (!fit_image_check_type (fit_hdr, noffset, IH_TYPE_SCRIPT)) {
130                         puts ("Not a image image\n");
131                         return 1;
132                 }
133
134                 /* verify integrity */
135                 if (verify) {
136                         if (!fit_image_check_hashes (fit_hdr, noffset)) {
137                                 puts ("Bad Data Hash\n");
138                                 return 1;
139                         }
140                 }
141
142                 /* get script subimage data address and length */
143                 if (fit_image_get_data (fit_hdr, noffset, &fit_data, &fit_len)) {
144                         puts ("Could not find script subimage data\n");
145                         return 1;
146                 }
147
148                 data = (ulong *)fit_data;
149                 len = (ulong)fit_len;
150                 break;
151 #endif
152         default:
153                 puts ("Wrong image format for autoscript\n");
154                 return 1;
155         }
156
157         debug ("** Script length: %ld\n", len);
158
159         if ((cmd = malloc (len + 1)) == NULL) {
160                 return 1;
161         }
162
163         /* make sure cmd is null terminated */
164         memmove (cmd, (char *)data, len);
165         *(cmd + len) = 0;
166
167 #ifdef CONFIG_SYS_HUSH_PARSER /*?? */
168         rcode = parse_string_outer (cmd, FLAG_PARSE_SEMICOLON);
169 #else
170         {
171                 char *line = cmd;
172                 char *next = cmd;
173
174                 /*
175                  * break into individual lines,
176                  * and execute each line;
177                  * terminate on error.
178                  */
179                 while (*next) {
180                         if (*next == '\n') {
181                                 *next = '\0';
182                                 /* run only non-empty commands */
183                                 if (*line) {
184                                         debug ("** exec: \"%s\"\n",
185                                                 line);
186                                         if (run_command (line, 0) < 0) {
187                                                 rcode = 1;
188                                                 break;
189                                         }
190                                 }
191                                 line = next + 1;
192                         }
193                         ++next;
194                 }
195                 if (rcode == 0 && *line)
196                         rcode = (run_command(line, 0) >= 0);
197         }
198 #endif
199         free (cmd);
200         return rcode;
201 }
202
203 /**************************************************/
204 #if defined(CONFIG_CMD_AUTOSCRIPT)
205 int
206 do_autoscript (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
207 {
208         ulong addr;
209         int rcode;
210         const char *fit_uname = NULL;
211
212         /* Find script image */
213         if (argc < 2) {
214                 addr = CONFIG_SYS_LOAD_ADDR;
215                 debug ("*  autoscr: default load address = 0x%08lx\n", addr);
216 #if defined(CONFIG_FIT)
217         } else if (fit_parse_subimage (argv[1], load_addr, &addr, &fit_uname)) {
218                 debug ("*  autoscr: subimage '%s' from FIT image at 0x%08lx\n",
219                                 fit_uname, addr);
220 #endif
221         } else {
222                 addr = simple_strtoul(argv[1], NULL, 16);
223                 debug ("*  autoscr: cmdline image address = 0x%08lx\n", addr);
224         }
225
226         printf ("## Executing script at %08lx\n", addr);
227         rcode = autoscript (addr, fit_uname);
228         return rcode;
229 }
230
231 U_BOOT_CMD(
232         autoscr, 2, 0,  do_autoscript,
233         "run script from memory",
234         "[addr] - run script starting at addr"
235         " - A valid autoscr header must be present\n"
236 #if defined(CONFIG_FIT)
237         "For FIT format uImage addr must include subimage\n"
238         "unit name in the form of addr:<subimg_uname>\n"
239 #endif
240 );
241 #endif