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