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 ulong base; 213 struct e820info *info; 214 struct e820entry *data; 215 #endif 216 217 /* 218 * Check the loadaddr variable. 219 * If we don't know where the image is then we're done. 220 */ 221 if (argc < 2) 222 addr = load_addr; 223 else 224 addr = simple_strtoul(argv[1], NULL, 16); 225 226 #if defined(CONFIG_CMD_NET) 227 /* 228 * Check to see if we need to tftp the image ourselves 229 * before starting 230 */ 231 if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) { 232 if (net_loop(TFTPGET) <= 0) 233 return 1; 234 printf("Automatic boot of VxWorks image at address 0x%08lx ...\n", 235 addr); 236 } 237 #endif 238 239 /* 240 * This should equate to 241 * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET 242 * from the VxWorks BSP header files. 243 * This will vary from board to board 244 */ 245 #if defined(CONFIG_SYS_VXWORKS_MAC_PTR) 246 tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR; 247 eth_env_get_enetaddr("ethaddr", (uchar *)build_buf); 248 memcpy(tmp, build_buf, 6); 249 #else 250 puts("## Ethernet MAC address not copied to NV RAM\n"); 251 #endif 252 253 /* 254 * Use bootaddr to find the location in memory that VxWorks 255 * will look for the bootline string. The default value is 256 * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by 257 * VxWorks BSP. For example, on PowerPC it defaults to 0x4200. 258 */ 259 tmp = env_get("bootaddr"); 260 if (!tmp) { 261 printf("## VxWorks bootline address not specified\n"); 262 } else { 263 bootaddr = simple_strtoul(tmp, NULL, 16); 264 265 /* 266 * Check to see if the bootline is defined in the 'bootargs' 267 * parameter. If it is not defined, we may be able to 268 * construct the info. 269 */ 270 bootline = env_get("bootargs"); 271 if (bootline) { 272 memcpy((void *)bootaddr, bootline, 273 max(strlen(bootline), (size_t)255)); 274 flush_cache(bootaddr, max(strlen(bootline), 275 (size_t)255)); 276 } else { 277 tmp = env_get("bootdev"); 278 if (tmp) { 279 strcpy(build_buf, tmp); 280 ptr = strlen(tmp); 281 } else 282 printf("## VxWorks boot device not specified\n"); 283 284 tmp = env_get("bootfile"); 285 if (tmp) 286 ptr += sprintf(build_buf + ptr, 287 "host:%s ", tmp); 288 else 289 ptr += sprintf(build_buf + ptr, 290 "host:vxWorks "); 291 292 /* 293 * The following parameters are only needed if 'bootdev' 294 * is an ethernet device, otherwise they are optional. 295 */ 296 tmp = env_get("ipaddr"); 297 if (tmp) { 298 ptr += sprintf(build_buf + ptr, "e=%s", tmp); 299 tmp = env_get("netmask"); 300 if (tmp) { 301 u32 mask = env_get_ip("netmask").s_addr; 302 ptr += sprintf(build_buf + ptr, 303 ":%08x ", ntohl(mask)); 304 } else { 305 ptr += sprintf(build_buf + ptr, " "); 306 } 307 } 308 309 tmp = env_get("serverip"); 310 if (tmp) 311 ptr += sprintf(build_buf + ptr, "h=%s ", tmp); 312 313 tmp = env_get("gatewayip"); 314 if (tmp) 315 ptr += sprintf(build_buf + ptr, "g=%s ", tmp); 316 317 tmp = env_get("hostname"); 318 if (tmp) 319 ptr += sprintf(build_buf + ptr, "tn=%s ", tmp); 320 321 tmp = env_get("othbootargs"); 322 if (tmp) { 323 strcpy(build_buf + ptr, tmp); 324 ptr += strlen(tmp); 325 } 326 327 memcpy((void *)bootaddr, build_buf, 328 max(strlen(build_buf), (size_t)255)); 329 flush_cache(bootaddr, max(strlen(build_buf), 330 (size_t)255)); 331 } 332 333 printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, 334 (char *)bootaddr); 335 } 336 337 #ifdef CONFIG_X86 338 /* 339 * Get VxWorks's physical memory base address from environment, 340 * if we don't specify it in the environment, use a default one. 341 */ 342 base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE); 343 data = (struct e820entry *)(base + E820_DATA_OFFSET); 344 info = (struct e820info *)(base + E820_INFO_OFFSET); 345 346 memset(info, 0, sizeof(struct e820info)); 347 info->sign = E820_SIGNATURE; 348 info->entries = install_e820_map(E820MAX, data); 349 info->addr = (info->entries - 1) * sizeof(struct e820entry) + 350 E820_DATA_OFFSET; 351 #endif 352 353 /* 354 * If the data at the load address is an elf image, then 355 * treat it like an elf image. Otherwise, assume that it is a 356 * binary image. 357 */ 358 if (valid_elf_image(addr)) 359 addr = load_elf_image_phdr(addr); 360 else 361 puts("## Not an ELF image, assuming binary\n"); 362 363 printf("## Starting vxWorks at 0x%08lx ...\n", addr); 364 365 dcache_disable(); 366 #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI) 367 armv8_setup_psci(); 368 smp_kick_all_cpus(); 369 #endif 370 371 #ifdef CONFIG_X86 372 /* VxWorks on x86 uses stack to pass parameters */ 373 ((asmlinkage void (*)(int))addr)(0); 374 #else 375 ((void (*)(int))addr)(0); 376 #endif 377 378 puts("## vxWorks terminated\n"); 379 380 return 1; 381 } 382 383 U_BOOT_CMD( 384 bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf, 385 "Boot from an ELF image in memory", 386 "[-p|-s] [address]\n" 387 "\t- load ELF image at [address] via program headers (-p)\n" 388 "\t or via section headers (-s)" 389 ); 390 391 U_BOOT_CMD( 392 bootvx, 2, 0, do_bootvx, 393 "Boot vxWorks from an ELF image", 394 " [address] - load address of vxWorks ELF image." 395 ); 396