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