blob: 1186a541bc75fd2ee966270dda092271a3c8d822 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenkd0dd1072002-10-20 17:17:16 +00002/*
3 * (C) Copyright 2001
4 * Kyle Harris, kharris@nexus-tech.net
wdenkd0dd1072002-10-20 17:17:16 +00005 */
6
7/*
Wolfgang Denk74de7ae2009-04-01 23:34:12 +02008 * The "source" command allows to define "script images", i. e. files
9 * that contain command sequences that can be executed by the command
10 * interpreter. It returns the exit status of the last command
11 * executed from the script. This is very similar to running a shell
12 * script in a UNIX shell, hence the name for the command.
wdenkd0dd1072002-10-20 17:17:16 +000013 */
14
15/* #define DEBUG */
16
17#include <common.h>
18#include <command.h>
Simon Glass6bf6dbe2019-08-01 09:46:49 -060019#include <env.h>
wdenkd0dd1072002-10-20 17:17:16 +000020#include <image.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060021#include <log.h>
wdenkd0dd1072002-10-20 17:17:16 +000022#include <malloc.h>
Joe Hershberger0eb25b62015-03-22 17:08:59 -050023#include <mapmem.h>
wdenkd0dd1072002-10-20 17:17:16 +000024#include <asm/byteorder.h>
Simon Glass4ca30d62013-04-20 08:42:49 +000025#include <asm/io.h>
wdenkd0dd1072002-10-20 17:17:16 +000026
Alex Kiernan201d9cd2018-06-22 14:58:02 +000027/**
28 * get_default_image() - Return default property from /images
29 *
30 * Return: Pointer to value of default property (or NULL)
31 */
32static const char *get_default_image(const void *fit)
33{
34 int images_noffset;
35
36 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
37 if (images_noffset < 0)
38 return NULL;
39
40 return fdt_getprop(fit, images_noffset, FIT_DEFAULT_PROP, NULL);
41}
Alex Kiernan201d9cd2018-06-22 14:58:02 +000042
Simon Glass858fefd2023-01-06 08:52:27 -060043int image_locate_script(void *buf, int size, const char *fit_uname,
44 const char *confname, char **datap, uint *lenp)
wdenkd0dd1072002-10-20 17:17:16 +000045{
Wolfgang Denk53677ef2008-05-20 16:00:29 +020046 ulong len;
Simon Glassf3543e62022-09-06 20:26:52 -060047 const struct legacy_img_hdr *hdr;
Gong Qianyu210fbee2015-07-30 14:00:01 +080048 u32 *data;
Marian Balakowicz424c4ab2008-03-12 10:33:00 +010049 int verify;
Marian Balakowicz424c4ab2008-03-12 10:33:00 +010050 const void* fit_hdr;
51 int noffset;
52 const void *fit_data;
53 size_t fit_len;
wdenkd0dd1072002-10-20 17:17:16 +000054
Simon Glassbfebc8c2017-08-03 12:22:13 -060055 verify = env_get_yesno("verify");
wdenkd0dd1072002-10-20 17:17:16 +000056
Simon Glass4ca30d62013-04-20 08:42:49 +000057 switch (genimg_get_format(buf)) {
Marian Balakowiczd5934ad2008-02-04 08:28:09 +010058 case IMAGE_FORMAT_LEGACY:
Simon Glass858fefd2023-01-06 08:52:27 -060059 if (IS_ENABLED(CONFIG_LEGACY_IMAGE_FORMAT)) {
60 hdr = buf;
wdenkd0dd1072002-10-20 17:17:16 +000061
Simon Glass858fefd2023-01-06 08:52:27 -060062 if (!image_check_magic(hdr)) {
63 puts("Bad magic number\n");
Marian Balakowiczd5934ad2008-02-04 08:28:09 +010064 return 1;
65 }
Simon Glass858fefd2023-01-06 08:52:27 -060066
67 if (!image_check_hcrc(hdr)) {
68 puts("Bad header crc\n");
69 return 1;
70 }
71
72 if (verify) {
73 if (!image_check_dcrc(hdr)) {
74 puts("Bad data crc\n");
75 return 1;
76 }
77 }
78
79 if (!image_check_type(hdr, IH_TYPE_SCRIPT)) {
80 puts("Bad image type\n");
81 return 1;
82 }
83
84 /* get length of script */
85 data = (u32 *)image_get_data(hdr);
86
87 len = uimage_to_cpu(*data);
88 if (!len) {
89 puts("Empty Script\n");
90 return 1;
91 }
92
93 /*
94 * scripts are just multi-image files with one
95 * component, so seek past the zero-terminated sequence
96 * of image lengths to get to the actual image data
97 */
98 while (*data++);
Marian Balakowiczd5934ad2008-02-04 08:28:09 +010099 }
Marian Balakowiczd5934ad2008-02-04 08:28:09 +0100100 break;
Marian Balakowiczd5934ad2008-02-04 08:28:09 +0100101 case IMAGE_FORMAT_FIT:
Simon Glass858fefd2023-01-06 08:52:27 -0600102 if (IS_ENABLED(CONFIG_FIT)) {
103 fit_hdr = buf;
104 if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) {
105 puts("Bad FIT image format\n");
Sean Andersonbcc85b92022-12-12 14:12:11 -0500106 return 1;
107 }
Alex Kiernan201d9cd2018-06-22 14:58:02 +0000108
Sean Andersonbcc85b92022-12-12 14:12:11 -0500109 if (!fit_uname) {
Simon Glass858fefd2023-01-06 08:52:27 -0600110 /* If confname is empty, use the default */
111 if (confname && *confname)
112 noffset = fit_conf_get_node(fit_hdr, confname);
113 else
114 noffset = fit_conf_get_node(fit_hdr, NULL);
115 if (noffset < 0) {
116 if (!confname)
117 goto fallback;
118 printf("Could not find config %s\n", confname);
119 return 1;
120 }
121
122 if (verify && fit_config_verify(fit_hdr, noffset))
123 return 1;
124
125 noffset = fit_conf_get_prop_node(fit_hdr,
126 noffset,
127 FIT_SCRIPT_PROP,
128 IH_PHASE_NONE);
129 if (noffset < 0) {
130 if (!confname)
131 goto fallback;
132 printf("Could not find script in %s\n", confname);
133 return 1;
134 }
135 } else {
136fallback:
137 if (!fit_uname || !*fit_uname)
138 fit_uname = get_default_image(fit_hdr);
139 if (!fit_uname) {
140 puts("No FIT subimage unit name\n");
141 return 1;
142 }
143
144 /* get script component image node offset */
145 noffset = fit_image_get_node(fit_hdr, fit_uname);
146 if (noffset < 0) {
147 printf("Can't find '%s' FIT subimage\n",
148 fit_uname);
149 return 1;
150 }
151 }
152
153 if (!fit_image_check_type(fit_hdr, noffset,
154 IH_TYPE_SCRIPT)) {
155 puts("Not a image image\n");
Sean Andersonbcc85b92022-12-12 14:12:11 -0500156 return 1;
157 }
158
Simon Glass858fefd2023-01-06 08:52:27 -0600159 /* verify integrity */
160 if (verify && !fit_image_verify(fit_hdr, noffset)) {
161 puts("Bad Data Hash\n");
Sean Andersonbcc85b92022-12-12 14:12:11 -0500162 return 1;
163 }
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100164
Simon Glass858fefd2023-01-06 08:52:27 -0600165 /* get script subimage data address and length */
166 if (fit_image_get_data(fit_hdr, noffset, &fit_data, &fit_len)) {
167 puts("Could not find script subimage data\n");
168 return 1;
169 }
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100170
Simon Glass858fefd2023-01-06 08:52:27 -0600171 data = (u32 *)fit_data;
172 len = (ulong)fit_len;
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100173 }
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100174 break;
Marian Balakowiczd5934ad2008-02-04 08:28:09 +0100175 default:
Simon Glass858fefd2023-01-06 08:52:27 -0600176 puts("Wrong image format for \"source\" command\n");
177 return -EPERM;
wdenkd0dd1072002-10-20 17:17:16 +0000178 }
179
Simon Glass858fefd2023-01-06 08:52:27 -0600180 *datap = (char *)data;
181 *lenp = len;
182
183 return 0;
184}
185
186int image_source_script(ulong addr, const char *fit_uname, const char *confname)
187{
188 char *data;
189 void *buf;
190 uint len;
191 int ret;
192
193 buf = map_sysmem(addr, 0);
194 ret = image_locate_script(buf, 0, fit_uname, confname, &data, &len);
195 unmap_sysmem(buf);
196 if (ret)
197 return CMD_RET_FAILURE;
198
199 debug("** Script length: %d\n", len);
200 return run_command_list(data, len, 0);
wdenkd0dd1072002-10-20 17:17:16 +0000201}
202
wdenk8bde7f72003-06-27 21:31:46 +0000203/**************************************************/
Wolfgang Denk74de7ae2009-04-01 23:34:12 +0200204#if defined(CONFIG_CMD_SOURCE)
Simon Glass09140112020-05-10 11:40:03 -0600205static int do_source(struct cmd_tbl *cmdtp, int flag, int argc,
206 char *const argv[])
wdenkd0dd1072002-10-20 17:17:16 +0000207{
208 ulong addr;
209 int rcode;
Sean Andersonbcc85b92022-12-12 14:12:11 -0500210 const char *fit_uname = NULL, *confname = NULL;
wdenkd0dd1072002-10-20 17:17:16 +0000211
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100212 /* Find script image */
wdenkd0dd1072002-10-20 17:17:16 +0000213 if (argc < 2) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200214 addr = CONFIG_SYS_LOAD_ADDR;
Simon Glass3c7dded2020-05-10 11:40:04 -0600215 debug("* source: default load address = 0x%08lx\n", addr);
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100216#if defined(CONFIG_FIT)
Simon Glassbb872dd2019-12-28 10:45:02 -0700217 } else if (fit_parse_subimage(argv[1], image_load_addr, &addr,
218 &fit_uname)) {
Simon Glass3c7dded2020-05-10 11:40:04 -0600219 debug("* source: subimage '%s' from FIT image at 0x%08lx\n",
220 fit_uname, addr);
Sean Andersonbcc85b92022-12-12 14:12:11 -0500221 } else if (fit_parse_conf(argv[1], image_load_addr, &addr, &confname)) {
222 debug("* source: config '%s' from FIT image at 0x%08lx\n",
223 confname, addr);
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100224#endif
wdenkd0dd1072002-10-20 17:17:16 +0000225 } else {
Simon Glass7e5f4602021-07-24 09:03:29 -0600226 addr = hextoul(argv[1], NULL);
Simon Glass3c7dded2020-05-10 11:40:04 -0600227 debug("* source: cmdline image address = 0x%08lx\n", addr);
wdenkd0dd1072002-10-20 17:17:16 +0000228 }
229
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100230 printf ("## Executing script at %08lx\n", addr);
Sean Andersonbcc85b92022-12-12 14:12:11 -0500231 rcode = image_source_script(addr, fit_uname, confname);
wdenkd0dd1072002-10-20 17:17:16 +0000232 return rcode;
233}
wdenk8bde7f72003-06-27 21:31:46 +0000234
Kim Phillips088f1b12012-10-29 13:34:31 +0000235#ifdef CONFIG_SYS_LONGHELP
236static char source_help_text[] =
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100237#if defined(CONFIG_FIT)
Sean Andersonbcc85b92022-12-12 14:12:11 -0500238 "[<addr>][:[<image>]|#[<config>]]\n"
239 "\t- Run script starting at addr\n"
240 "\t- A FIT config name or subimage name may be specified with : or #\n"
241 "\t (like bootm). If the image or config name is omitted, the\n"
242 "\t default is used.";
243#else
244 "[<addr>]\n"
245 "\t- Run script starting at addr";
Jon Loeliger90253172007-07-10 11:02:44 -0500246#endif
Kim Phillips088f1b12012-10-29 13:34:31 +0000247#endif
248
249U_BOOT_CMD(
250 source, 2, 0, do_source,
251 "run script from memory", source_help_text
Marian Balakowicz424c4ab2008-03-12 10:33:00 +0100252);
Jon Loeliger90253172007-07-10 11:02:44 -0500253#endif