]> git.sur5r.net Git - u-boot/blob - common/cmd_elf.c
cmd: bootvx: Avoid strlen() calls when constructing VxWorks bootline
[u-boot] / common / cmd_elf.c
1 /*
2  * Copyright (c) 2001 William L. Pitts
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are freely
6  * permitted provided that the above copyright notice and this
7  * paragraph and the following disclaimer are duplicated in all
8  * such forms.
9  *
10  * This software is provided "AS IS" and without any express or
11  * implied warranties, including, without limitation, the implied
12  * warranties of merchantability and fitness for a particular
13  * purpose.
14  */
15
16 #include <common.h>
17 #include <command.h>
18 #include <elf.h>
19 #include <net.h>
20 #include <vxworks.h>
21
22 /*
23  * A very simple elf loader, assumes the image is valid, returns the
24  * entry point address.
25  */
26 static unsigned long load_elf_image_phdr(unsigned long addr)
27 {
28         Elf32_Ehdr *ehdr; /* Elf header structure pointer */
29         Elf32_Phdr *phdr; /* Program header structure pointer */
30         int i;
31
32         ehdr = (Elf32_Ehdr *)addr;
33         phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
34
35         /* Load each program header */
36         for (i = 0; i < ehdr->e_phnum; ++i) {
37                 void *dst = (void *)(uintptr_t)phdr->p_paddr;
38                 void *src = (void *)addr + phdr->p_offset;
39                 debug("Loading phdr %i to 0x%p (%i bytes)\n",
40                       i, dst, phdr->p_filesz);
41                 if (phdr->p_filesz)
42                         memcpy(dst, src, phdr->p_filesz);
43                 if (phdr->p_filesz != phdr->p_memsz)
44                         memset(dst + phdr->p_filesz, 0x00,
45                                phdr->p_memsz - phdr->p_filesz);
46                 flush_cache((unsigned long)dst, phdr->p_filesz);
47                 ++phdr;
48         }
49
50         return ehdr->e_entry;
51 }
52
53 static unsigned long load_elf_image_shdr(unsigned long addr)
54 {
55         Elf32_Ehdr *ehdr; /* Elf header structure pointer */
56         Elf32_Shdr *shdr; /* Section header structure pointer */
57         unsigned char *strtab = 0; /* String table pointer */
58         unsigned char *image; /* Binary image pointer */
59         int i; /* Loop counter */
60
61         ehdr = (Elf32_Ehdr *)addr;
62
63         /* Find the section header string table for output info */
64         shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
65                              (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
66
67         if (shdr->sh_type == SHT_STRTAB)
68                 strtab = (unsigned char *)(addr + shdr->sh_offset);
69
70         /* Load each appropriate section */
71         for (i = 0; i < ehdr->e_shnum; ++i) {
72                 shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
73                                      (i * sizeof(Elf32_Shdr)));
74
75                 if (!(shdr->sh_flags & SHF_ALLOC) ||
76                     shdr->sh_addr == 0 || shdr->sh_size == 0) {
77                         continue;
78                 }
79
80                 if (strtab) {
81                         debug("%sing %s @ 0x%08lx (%ld bytes)\n",
82                               (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
83                                &strtab[shdr->sh_name],
84                                (unsigned long)shdr->sh_addr,
85                                (long)shdr->sh_size);
86                 }
87
88                 if (shdr->sh_type == SHT_NOBITS) {
89                         memset((void *)(uintptr_t)shdr->sh_addr, 0,
90                                shdr->sh_size);
91                 } else {
92                         image = (unsigned char *)addr + shdr->sh_offset;
93                         memcpy((void *)(uintptr_t)shdr->sh_addr,
94                                (const void *)image, shdr->sh_size);
95                 }
96                 flush_cache(shdr->sh_addr, shdr->sh_size);
97         }
98
99         return ehdr->e_entry;
100 }
101
102 /* Allow ports to override the default behavior */
103 static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
104                                      int argc, char * const argv[])
105 {
106         unsigned long ret;
107
108         /*
109          * QNX images require the data cache is disabled.
110          * Data cache is already flushed, so just turn it off.
111          */
112         int dcache = dcache_status();
113         if (dcache)
114                 dcache_disable();
115
116         /*
117          * pass address parameter as argv[0] (aka command name),
118          * and all remaining args
119          */
120         ret = entry(argc, argv);
121
122         if (dcache)
123                 dcache_enable();
124
125         return ret;
126 }
127
128 /*
129  * Determine if a valid ELF image exists at the given memory location.
130  * First look at the ELF header magic field, then make sure that it is
131  * executable.
132  */
133 int valid_elf_image(unsigned long addr)
134 {
135         Elf32_Ehdr *ehdr; /* Elf header structure pointer */
136
137         ehdr = (Elf32_Ehdr *)addr;
138
139         if (!IS_ELF(*ehdr)) {
140                 printf("## No elf image at address 0x%08lx\n", addr);
141                 return 0;
142         }
143
144         if (ehdr->e_type != ET_EXEC) {
145                 printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
146                 return 0;
147         }
148
149         return 1;
150 }
151
152 /* Interpreter command to boot an arbitrary ELF image from memory */
153 int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
154 {
155         unsigned long addr; /* Address of the ELF image */
156         unsigned long rc; /* Return value from user code */
157         char *sload, *saddr;
158         const char *ep = getenv("autostart");
159
160         int rcode = 0;
161
162         sload = saddr = NULL;
163         if (argc == 3) {
164                 sload = argv[1];
165                 saddr = argv[2];
166         } else if (argc == 2) {
167                 if (argv[1][0] == '-')
168                         sload = argv[1];
169                 else
170                         saddr = argv[1];
171         }
172
173         if (saddr)
174                 addr = simple_strtoul(saddr, NULL, 16);
175         else
176                 addr = load_addr;
177
178         if (!valid_elf_image(addr))
179                 return 1;
180
181         if (sload && sload[1] == 'p')
182                 addr = load_elf_image_phdr(addr);
183         else
184                 addr = load_elf_image_shdr(addr);
185
186         if (ep && !strcmp(ep, "no"))
187                 return rcode;
188
189         printf("## Starting application at 0x%08lx ...\n", addr);
190
191         /*
192          * pass address parameter as argv[0] (aka command name),
193          * and all remaining args
194          */
195         rc = do_bootelf_exec((void *)addr, argc - 1, argv + 1);
196         if (rc != 0)
197                 rcode = 1;
198
199         printf("## Application terminated, rc = 0x%lx\n", rc);
200
201         return rcode;
202 }
203
204 /*
205  * Interpreter command to boot VxWorks from a memory image.  The image can
206  * be either an ELF image or a raw binary.  Will attempt to setup the
207  * bootline and other parameters correctly.
208  */
209 int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
210 {
211         unsigned long addr; /* Address of image */
212         unsigned long bootaddr; /* Address to put the bootline */
213         char *bootline; /* Text of the bootline */
214         char *tmp; /* Temporary char pointer */
215         char build_buf[128]; /* Buffer for building the bootline */
216         int ptr = 0;
217
218         /*
219          * Check the loadaddr variable.
220          * If we don't know where the image is then we're done.
221          */
222         if (argc < 2)
223                 addr = load_addr;
224         else
225                 addr = simple_strtoul(argv[1], NULL, 16);
226
227 #if defined(CONFIG_CMD_NET)
228         /*
229          * Check to see if we need to tftp the image ourselves
230          * before starting
231          */
232         if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
233                 if (net_loop(TFTPGET) <= 0)
234                         return 1;
235                 printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
236                         addr);
237         }
238 #endif
239
240         /*
241          * This should equate to
242          * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
243          * from the VxWorks BSP header files.
244          * This will vary from board to board
245          */
246 #if defined(CONFIG_WALNUT)
247         tmp = (char *)CONFIG_SYS_NVRAM_BASE_ADDR + 0x500;
248         eth_getenv_enetaddr("ethaddr", (uchar *)build_buf);
249         memcpy(tmp, &build_buf[3], 3);
250 #elif defined(CONFIG_SYS_VXWORKS_MAC_PTR)
251         tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
252         eth_getenv_enetaddr("ethaddr", (uchar *)build_buf);
253         memcpy(tmp, build_buf, 6);
254 #else
255         puts("## Ethernet MAC address not copied to NV RAM\n");
256 #endif
257
258         /*
259          * Use bootaddr to find the location in memory that VxWorks
260          * will look for the bootline string. The default value for
261          * PowerPC is LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET which
262          * defaults to 0x4200.
263          */
264         tmp = getenv("bootaddr");
265         if (!tmp)
266                 bootaddr = CONFIG_SYS_VXWORKS_BOOT_ADDR;
267         else
268                 bootaddr = simple_strtoul(tmp, NULL, 16);
269
270         /*
271          * Check to see if the bootline is defined in the 'bootargs'
272          * parameter. If it is not defined, we may be able to
273          * construct the info.
274          */
275         bootline = getenv("bootargs");
276         if (bootline) {
277                 memcpy((void *)bootaddr, bootline,
278                        max(strlen(bootline), (size_t)255));
279                 flush_cache(bootaddr, max(strlen(bootline), (size_t)255));
280         } else {
281                 ptr = sprintf(build_buf, CONFIG_SYS_VXWORKS_BOOT_DEVICE);
282                 tmp = getenv("bootfile");
283                 if (tmp)
284                         ptr += sprintf(build_buf + ptr, "%s:%s ",
285                                        CONFIG_SYS_VXWORKS_SERVERNAME, tmp);
286                 else
287                         ptr += sprintf(build_buf + ptr, "%s:file ",
288                                        CONFIG_SYS_VXWORKS_SERVERNAME);
289
290                 tmp = getenv("ipaddr");
291                 if (tmp)
292                         ptr += sprintf(build_buf + ptr, "e=%s ", tmp);
293
294                 tmp = getenv("serverip");
295                 if (tmp)
296                         ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
297
298                 tmp = getenv("hostname");
299                 if (tmp)
300                         ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
301
302 #ifdef CONFIG_SYS_VXWORKS_ADD_PARAMS
303                 ptr += sprintf(build_buf + ptr, CONFIG_SYS_VXWORKS_ADD_PARAMS);
304 #endif
305
306                 memcpy((void *)bootaddr, build_buf,
307                        max(strlen(build_buf), (size_t)255));
308                 flush_cache(bootaddr, max(strlen(build_buf), (size_t)255));
309         }
310
311         /*
312          * If the data at the load address is an elf image, then
313          * treat it like an elf image. Otherwise, assume that it is a
314          * binary image.
315          */
316         if (valid_elf_image(addr))
317                 addr = load_elf_image_shdr(addr);
318         else
319                 puts("## Not an ELF image, assuming binary\n");
320
321         printf("## Using bootline (@ 0x%lx): %s\n", bootaddr,
322                (char *)bootaddr);
323         printf("## Starting vxWorks at 0x%08lx ...\n", addr);
324
325         dcache_disable();
326         ((void (*)(int))addr)(0);
327
328         puts("## vxWorks terminated\n");
329
330         return 1;
331 }
332
333 U_BOOT_CMD(
334         bootelf, 3, 0, do_bootelf,
335         "Boot from an ELF image in memory",
336         "[-p|-s] [address]\n"
337         "\t- load ELF image at [address] via program headers (-p)\n"
338         "\t  or via section headers (-s)"
339 );
340
341 U_BOOT_CMD(
342         bootvx, 2, 0, do_bootvx,
343         "Boot vxWorks from an ELF image",
344         " [address] - load address of vxWorks ELF image."
345 );