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