Newer
Older
/*
* Copyright (c) 2001 William L. Pitts
* All rights reserved.
*
* Redistribution and use in source and binary forms are freely
* permitted provided that the above copyright notice and this
* paragraph and the following disclaimer are duplicated in all
* such forms.
*
* This software is provided "AS IS" and without any express or
* implied warranties, including, without limitation, the implied
* warranties of merchantability and fitness for a particular
* purpose.
*/
#include <common.h>
#include <command.h>
#include <elf.h>
#include <vxworks.h>
#ifdef CONFIG_X86
#include <asm/e820.h>
#include <linux/linkage.h>
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
* A very simple elf loader, assumes the image is valid, returns the
* entry point address.
*/
static unsigned long load_elf_image_phdr(unsigned long addr)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
Elf32_Phdr *phdr; /* Program header structure pointer */
int i;
ehdr = (Elf32_Ehdr *)addr;
phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
/* Load each program header */
for (i = 0; i < ehdr->e_phnum; ++i) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
debug("Loading phdr %i to 0x%p (%i bytes)\n",
i, dst, phdr->p_filesz);
if (phdr->p_filesz)
memcpy(dst, src, phdr->p_filesz);
if (phdr->p_filesz != phdr->p_memsz)
memset(dst + phdr->p_filesz, 0x00,
phdr->p_memsz - phdr->p_filesz);
flush_cache((unsigned long)dst, phdr->p_filesz);
++phdr;
}
return ehdr->e_entry;
}
static unsigned long load_elf_image_shdr(unsigned long addr)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
Elf32_Shdr *shdr; /* Section header structure pointer */
unsigned char *strtab = 0; /* String table pointer */
unsigned char *image; /* Binary image pointer */
int i; /* Loop counter */
ehdr = (Elf32_Ehdr *)addr;
/* Find the section header string table for output info */
shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
(ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
if (shdr->sh_type == SHT_STRTAB)
strtab = (unsigned char *)(addr + shdr->sh_offset);
/* Load each appropriate section */
for (i = 0; i < ehdr->e_shnum; ++i) {
shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
(i * sizeof(Elf32_Shdr)));
if (!(shdr->sh_flags & SHF_ALLOC) ||
shdr->sh_addr == 0 || shdr->sh_size == 0) {
continue;
}
if (strtab) {
debug("%sing %s @ 0x%08lx (%ld bytes)\n",
(shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
&strtab[shdr->sh_name],
(unsigned long)shdr->sh_addr,
(long)shdr->sh_size);
}
if (shdr->sh_type == SHT_NOBITS) {
memset((void *)(uintptr_t)shdr->sh_addr, 0,
shdr->sh_size);
} else {
image = (unsigned char *)addr + shdr->sh_offset;
memcpy((void *)(uintptr_t)shdr->sh_addr,
(const void *)image, shdr->sh_size);
}
flush_cache(shdr->sh_addr, shdr->sh_size);
}
return ehdr->e_entry;
}
/* Allow ports to override the default behavior */
static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
/*
* QNX images require the data cache is disabled.
* Data cache is already flushed, so just turn it off.
*/
int dcache = dcache_status();
/*
* pass address parameter as argv[0] (aka command name),
* and all remaining args
*/
ret = entry(argc, argv);
* Determine if a valid ELF image exists at the given memory location.
* First look at the ELF header magic field, then make sure that it is
* executable.
*/
int valid_elf_image(unsigned long addr)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
if (!IS_ELF(*ehdr)) {
printf("## No elf image at address 0x%08lx\n", addr);
return 0;
}
if (ehdr->e_type != ET_EXEC) {
printf("## Not a 32-bit elf image at address 0x%08lx\n", addr);
return 0;
}
return 1;
}
/* Interpreter command to boot an arbitrary ELF image from memory */
int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
unsigned long addr; /* Address of the ELF image */
unsigned long rc; /* Return value from user code */
char *sload, *saddr;
const char *ep = getenv("autostart");
sload = saddr = NULL;
if (argc == 3) {
sload = argv[1];
saddr = argv[2];
} else if (argc == 2) {
if (argv[1][0] == '-')
sload = argv[1];
else
saddr = argv[1];
}
if (saddr)
addr = simple_strtoul(saddr, NULL, 16);
addr = load_addr;
if (!valid_elf_image(addr))
if (sload && sload[1] == 'p')
addr = load_elf_image_phdr(addr);
else
addr = load_elf_image_shdr(addr);
if (ep && !strcmp(ep, "no"))
return rcode;
printf("## Starting application at 0x%08lx ...\n", addr);
/*
* pass address parameter as argv[0] (aka command name),
* and all remaining args
*/
rc = do_bootelf_exec((void *)addr, argc - 1, argv + 1);
printf("## Application terminated, rc = 0x%lx\n", rc);
* Interpreter command to boot VxWorks from a memory image. The image can
* be either an ELF image or a raw binary. Will attempt to setup the
* bootline and other parameters correctly.
int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
unsigned long addr; /* Address of image */
unsigned long bootaddr; /* Address to put the bootline */
char *bootline; /* Text of the bootline */
char *tmp; /* Temporary char pointer */
char build_buf[128]; /* Buffer for building the bootline */
int ptr = 0;
#ifdef CONFIG_X86
struct e820info *info;
struct e820entry *data;
#endif
* Check the loadaddr variable.
* If we don't know where the image is then we're done.
*/
addr = load_addr;
else
addr = simple_strtoul(argv[1], NULL, 16);
#if defined(CONFIG_CMD_NET)
* Check to see if we need to tftp the image ourselves
* before starting
if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
if (net_loop(TFTPGET) <= 0)
printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
addr);
/*
* This should equate to
* NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
* from the VxWorks BSP header files.
* This will vary from board to board
*/
#if defined(CONFIG_WALNUT)
tmp = (char *)CONFIG_SYS_NVRAM_BASE_ADDR + 0x500;
eth_getenv_enetaddr("ethaddr", (uchar *)build_buf);
memcpy(tmp, &build_buf[3], 3);
#elif defined(CONFIG_SYS_VXWORKS_MAC_PTR)
eth_getenv_enetaddr("ethaddr", (uchar *)build_buf);
puts("## Ethernet MAC address not copied to NV RAM\n");
/*
* Use bootaddr to find the location in memory that VxWorks
* will look for the bootline string. The default value is
* (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
* VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
tmp = getenv("bootaddr");
if (!tmp) {
printf("## VxWorks bootline address not specified\n");
bootaddr = simple_strtoul(tmp, NULL, 16);
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*
* Check to see if the bootline is defined in the 'bootargs'
* parameter. If it is not defined, we may be able to
* construct the info.
*/
bootline = getenv("bootargs");
if (bootline) {
memcpy((void *)bootaddr, bootline,
max(strlen(bootline), (size_t)255));
flush_cache(bootaddr, max(strlen(bootline),
(size_t)255));
} else {
tmp = getenv("bootdev");
if (tmp)
ptr = sprintf(build_buf, tmp);
else
printf("## VxWorks boot device not specified\n");
tmp = getenv("bootfile");
if (tmp)
ptr += sprintf(build_buf + ptr,
"host:%s ", tmp);
else
ptr += sprintf(build_buf + ptr,
"host:vxWorks ");
/*
* The following parameters are only needed if 'bootdev'
* is an ethernet device, otherwise they are optional.
*/
tmp = getenv("ipaddr");
ptr += sprintf(build_buf + ptr, "e=%s", tmp);
tmp = getenv("netmask");
if (tmp) {
u32 mask = getenv_ip("netmask").s_addr;
ptr += sprintf(build_buf + ptr,
":%08x ", ntohl(mask));
} else {
ptr += sprintf(build_buf + ptr, " ");
}
tmp = getenv("serverip");
if (tmp)
ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
tmp = getenv("gatewayip");
if (tmp)
ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
tmp = getenv("hostname");
if (tmp)
ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
tmp = getenv("othbootargs");
if (tmp)
ptr += sprintf(build_buf + ptr, tmp);
memcpy((void *)bootaddr, build_buf,
max(strlen(build_buf), (size_t)255));
flush_cache(bootaddr, max(strlen(build_buf),
(size_t)255));
}
printf("## Using bootline (@ 0x%lx): %s\n", bootaddr,
(char *)bootaddr);
#ifdef CONFIG_X86
/*
* Since E820 information is critical to the kernel, if we don't
* specify these in the environments, use a default one.
*/
tmp = getenv("e820data");
if (tmp)
data = (struct e820entry *)simple_strtoul(tmp, NULL, 16);
else
data = (struct e820entry *)VXWORKS_E820_DATA_ADDR;
tmp = getenv("e820info");
if (tmp)
info = (struct e820info *)simple_strtoul(tmp, NULL, 16);
else
info = (struct e820info *)VXWORKS_E820_INFO_ADDR;
memset(info, 0, sizeof(struct e820info));
info->sign = E820_SIGNATURE;
info->entries = install_e820_map(E820MAX, data);
info->addr = (info->entries - 1) * sizeof(struct e820entry) +
VXWORKS_E820_DATA_ADDR;
#endif
/*
* If the data at the load address is an elf image, then
* treat it like an elf image. Otherwise, assume that it is a
addr = load_elf_image_shdr(addr);
puts("## Not an ELF image, assuming binary\n");
printf("## Starting vxWorks at 0x%08lx ...\n", addr);
dcache_disable();
#ifdef CONFIG_X86
/* VxWorks on x86 uses stack to pass parameters */
((asmlinkage void (*)(int))addr)(0);
#else
puts("## vxWorks terminated\n");
"[-p|-s] [address]\n"
"\t- load ELF image at [address] via program headers (-p)\n"
"\t or via section headers (-s)"
" [address] - load address of vxWorks ELF image."