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