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