12e192b24SSimon Glass /* 22e192b24SSimon Glass * Copyright (c) 2001 William L. Pitts 32e192b24SSimon Glass * All rights reserved. 42e192b24SSimon Glass * 52e192b24SSimon Glass * Redistribution and use in source and binary forms are freely 62e192b24SSimon Glass * permitted provided that the above copyright notice and this 72e192b24SSimon Glass * paragraph and the following disclaimer are duplicated in all 82e192b24SSimon Glass * such forms. 92e192b24SSimon Glass * 102e192b24SSimon Glass * This software is provided "AS IS" and without any express or 112e192b24SSimon Glass * implied warranties, including, without limitation, the implied 122e192b24SSimon Glass * warranties of merchantability and fitness for a particular 132e192b24SSimon Glass * purpose. 142e192b24SSimon Glass */ 152e192b24SSimon Glass 162e192b24SSimon Glass #include <common.h> 172e192b24SSimon Glass #include <command.h> 182e192b24SSimon Glass #include <elf.h> 199925f1dbSAlex Kiernan #include <environment.h> 202e192b24SSimon Glass #include <net.h> 212e192b24SSimon Glass #include <vxworks.h> 222e192b24SSimon Glass #ifdef CONFIG_X86 232e192b24SSimon Glass #include <asm/e820.h> 242e192b24SSimon Glass #include <linux/linkage.h> 252e192b24SSimon Glass #endif 262e192b24SSimon Glass 272e192b24SSimon Glass /* 282e192b24SSimon Glass * A very simple elf loader, assumes the image is valid, returns the 292e192b24SSimon Glass * entry point address. 302e192b24SSimon Glass */ 312e192b24SSimon Glass static unsigned long load_elf_image_phdr(unsigned long addr) 322e192b24SSimon Glass { 332e192b24SSimon Glass Elf32_Ehdr *ehdr; /* Elf header structure pointer */ 342e192b24SSimon Glass Elf32_Phdr *phdr; /* Program header structure pointer */ 352e192b24SSimon Glass int i; 362e192b24SSimon Glass 372e192b24SSimon Glass ehdr = (Elf32_Ehdr *)addr; 382e192b24SSimon Glass phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff); 392e192b24SSimon Glass 402e192b24SSimon Glass /* Load each program header */ 412e192b24SSimon Glass for (i = 0; i < ehdr->e_phnum; ++i) { 422e192b24SSimon Glass void *dst = (void *)(uintptr_t)phdr->p_paddr; 432e192b24SSimon Glass void *src = (void *)addr + phdr->p_offset; 442e192b24SSimon Glass debug("Loading phdr %i to 0x%p (%i bytes)\n", 452e192b24SSimon Glass i, dst, phdr->p_filesz); 462e192b24SSimon Glass if (phdr->p_filesz) 472e192b24SSimon Glass memcpy(dst, src, phdr->p_filesz); 482e192b24SSimon Glass if (phdr->p_filesz != phdr->p_memsz) 492e192b24SSimon Glass memset(dst + phdr->p_filesz, 0x00, 502e192b24SSimon Glass phdr->p_memsz - phdr->p_filesz); 512e192b24SSimon Glass flush_cache((unsigned long)dst, phdr->p_filesz); 522e192b24SSimon Glass ++phdr; 532e192b24SSimon Glass } 542e192b24SSimon Glass 552e192b24SSimon Glass return ehdr->e_entry; 562e192b24SSimon Glass } 572e192b24SSimon Glass 582e192b24SSimon Glass static unsigned long load_elf_image_shdr(unsigned long addr) 592e192b24SSimon Glass { 602e192b24SSimon Glass Elf32_Ehdr *ehdr; /* Elf header structure pointer */ 612e192b24SSimon Glass Elf32_Shdr *shdr; /* Section header structure pointer */ 622e192b24SSimon Glass unsigned char *strtab = 0; /* String table pointer */ 632e192b24SSimon Glass unsigned char *image; /* Binary image pointer */ 642e192b24SSimon Glass int i; /* Loop counter */ 652e192b24SSimon Glass 662e192b24SSimon Glass ehdr = (Elf32_Ehdr *)addr; 672e192b24SSimon Glass 682e192b24SSimon Glass /* Find the section header string table for output info */ 692e192b24SSimon Glass shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + 702e192b24SSimon Glass (ehdr->e_shstrndx * sizeof(Elf32_Shdr))); 712e192b24SSimon Glass 722e192b24SSimon Glass if (shdr->sh_type == SHT_STRTAB) 732e192b24SSimon Glass strtab = (unsigned char *)(addr + shdr->sh_offset); 742e192b24SSimon Glass 752e192b24SSimon Glass /* Load each appropriate section */ 762e192b24SSimon Glass for (i = 0; i < ehdr->e_shnum; ++i) { 772e192b24SSimon Glass shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + 782e192b24SSimon Glass (i * sizeof(Elf32_Shdr))); 792e192b24SSimon Glass 802e192b24SSimon Glass if (!(shdr->sh_flags & SHF_ALLOC) || 812e192b24SSimon Glass shdr->sh_addr == 0 || shdr->sh_size == 0) { 822e192b24SSimon Glass continue; 832e192b24SSimon Glass } 842e192b24SSimon Glass 852e192b24SSimon Glass if (strtab) { 862e192b24SSimon Glass debug("%sing %s @ 0x%08lx (%ld bytes)\n", 872e192b24SSimon Glass (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load", 882e192b24SSimon Glass &strtab[shdr->sh_name], 892e192b24SSimon Glass (unsigned long)shdr->sh_addr, 902e192b24SSimon Glass (long)shdr->sh_size); 912e192b24SSimon Glass } 922e192b24SSimon Glass 932e192b24SSimon Glass if (shdr->sh_type == SHT_NOBITS) { 942e192b24SSimon Glass memset((void *)(uintptr_t)shdr->sh_addr, 0, 952e192b24SSimon Glass shdr->sh_size); 962e192b24SSimon Glass } else { 972e192b24SSimon Glass image = (unsigned char *)addr + shdr->sh_offset; 982e192b24SSimon Glass memcpy((void *)(uintptr_t)shdr->sh_addr, 992e192b24SSimon Glass (const void *)image, shdr->sh_size); 1002e192b24SSimon Glass } 1012e192b24SSimon Glass flush_cache(shdr->sh_addr, shdr->sh_size); 1022e192b24SSimon Glass } 1032e192b24SSimon Glass 1042e192b24SSimon Glass return ehdr->e_entry; 1052e192b24SSimon Glass } 1062e192b24SSimon Glass 1072e192b24SSimon Glass /* Allow ports to override the default behavior */ 1082e192b24SSimon Glass static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]), 1092e192b24SSimon Glass int argc, char * const argv[]) 1102e192b24SSimon Glass { 1112e192b24SSimon Glass unsigned long ret; 1122e192b24SSimon Glass 1132e192b24SSimon Glass /* 1142e192b24SSimon Glass * pass address parameter as argv[0] (aka command name), 1152e192b24SSimon Glass * and all remaining args 1162e192b24SSimon Glass */ 1172e192b24SSimon Glass ret = entry(argc, argv); 1182e192b24SSimon Glass 1192e192b24SSimon Glass return ret; 1202e192b24SSimon Glass } 1212e192b24SSimon Glass 1222e192b24SSimon Glass /* 1232e192b24SSimon Glass * Determine if a valid ELF image exists at the given memory location. 1242e192b24SSimon Glass * First look at the ELF header magic field, then make sure that it is 1252e192b24SSimon Glass * executable. 1262e192b24SSimon Glass */ 1272e192b24SSimon Glass int valid_elf_image(unsigned long addr) 1282e192b24SSimon Glass { 1292e192b24SSimon Glass Elf32_Ehdr *ehdr; /* Elf header structure pointer */ 1302e192b24SSimon Glass 1312e192b24SSimon Glass ehdr = (Elf32_Ehdr *)addr; 1322e192b24SSimon Glass 1332e192b24SSimon Glass if (!IS_ELF(*ehdr)) { 1342e192b24SSimon Glass printf("## No elf image at address 0x%08lx\n", addr); 1352e192b24SSimon Glass return 0; 1362e192b24SSimon Glass } 1372e192b24SSimon Glass 1382e192b24SSimon Glass if (ehdr->e_type != ET_EXEC) { 1392e192b24SSimon Glass printf("## Not a 32-bit elf image at address 0x%08lx\n", addr); 1402e192b24SSimon Glass return 0; 1412e192b24SSimon Glass } 1422e192b24SSimon Glass 1432e192b24SSimon Glass return 1; 1442e192b24SSimon Glass } 1452e192b24SSimon Glass 1462e192b24SSimon Glass /* Interpreter command to boot an arbitrary ELF image from memory */ 1472e192b24SSimon Glass int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1482e192b24SSimon Glass { 1492e192b24SSimon Glass unsigned long addr; /* Address of the ELF image */ 1502e192b24SSimon Glass unsigned long rc; /* Return value from user code */ 151be1b8679STom Rini char *sload = NULL; 15200caae6dSSimon Glass const char *ep = env_get("autostart"); 1532e192b24SSimon Glass int rcode = 0; 1542e192b24SSimon Glass 155be1b8679STom Rini /* Consume 'bootelf' */ 156be1b8679STom Rini argc--; argv++; 1572e192b24SSimon Glass 158be1b8679STom Rini /* Check for flag. */ 159be1b8679STom Rini if (argc >= 1 && (argv[0][0] == '-' && \ 160be1b8679STom Rini (argv[0][1] == 'p' || argv[0][1] == 's'))) { 161be1b8679STom Rini sload = argv[0]; 162be1b8679STom Rini /* Consume flag. */ 163be1b8679STom Rini argc--; argv++; 164be1b8679STom Rini } 165be1b8679STom Rini /* Check for address. */ 166be1b8679STom Rini if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) { 167be1b8679STom Rini /* Consume address */ 168be1b8679STom Rini argc--; argv++; 169be1b8679STom Rini } else 1702e192b24SSimon Glass addr = load_addr; 1712e192b24SSimon Glass 1722e192b24SSimon Glass if (!valid_elf_image(addr)) 1732e192b24SSimon Glass return 1; 1742e192b24SSimon Glass 1752e192b24SSimon Glass if (sload && sload[1] == 'p') 1762e192b24SSimon Glass addr = load_elf_image_phdr(addr); 1772e192b24SSimon Glass else 1782e192b24SSimon Glass addr = load_elf_image_shdr(addr); 1792e192b24SSimon Glass 1802e192b24SSimon Glass if (ep && !strcmp(ep, "no")) 1812e192b24SSimon Glass return rcode; 1822e192b24SSimon Glass 1832e192b24SSimon Glass printf("## Starting application at 0x%08lx ...\n", addr); 1842e192b24SSimon Glass 1852e192b24SSimon Glass /* 1862e192b24SSimon Glass * pass address parameter as argv[0] (aka command name), 1872e192b24SSimon Glass * and all remaining args 1882e192b24SSimon Glass */ 189be1b8679STom Rini rc = do_bootelf_exec((void *)addr, argc, argv); 1902e192b24SSimon Glass if (rc != 0) 1912e192b24SSimon Glass rcode = 1; 1922e192b24SSimon Glass 1932e192b24SSimon Glass printf("## Application terminated, rc = 0x%lx\n", rc); 1942e192b24SSimon Glass 1952e192b24SSimon Glass return rcode; 1962e192b24SSimon Glass } 1972e192b24SSimon Glass 1982e192b24SSimon Glass /* 1992e192b24SSimon Glass * Interpreter command to boot VxWorks from a memory image. The image can 2002e192b24SSimon Glass * be either an ELF image or a raw binary. Will attempt to setup the 2012e192b24SSimon Glass * bootline and other parameters correctly. 2022e192b24SSimon Glass */ 2032e192b24SSimon Glass int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 2042e192b24SSimon Glass { 2052e192b24SSimon Glass unsigned long addr; /* Address of image */ 2062e192b24SSimon Glass unsigned long bootaddr; /* Address to put the bootline */ 2072e192b24SSimon Glass char *bootline; /* Text of the bootline */ 2082e192b24SSimon Glass char *tmp; /* Temporary char pointer */ 2092e192b24SSimon Glass char build_buf[128]; /* Buffer for building the bootline */ 2102e192b24SSimon Glass int ptr = 0; 2112e192b24SSimon Glass #ifdef CONFIG_X86 2122e192b24SSimon Glass struct e820info *info; 2132e192b24SSimon Glass struct e820entry *data; 2142e192b24SSimon Glass #endif 2152e192b24SSimon Glass 2162e192b24SSimon Glass /* 2172e192b24SSimon Glass * Check the loadaddr variable. 2182e192b24SSimon Glass * If we don't know where the image is then we're done. 2192e192b24SSimon Glass */ 2202e192b24SSimon Glass if (argc < 2) 2212e192b24SSimon Glass addr = load_addr; 2222e192b24SSimon Glass else 2232e192b24SSimon Glass addr = simple_strtoul(argv[1], NULL, 16); 2242e192b24SSimon Glass 2252e192b24SSimon Glass #if defined(CONFIG_CMD_NET) 2262e192b24SSimon Glass /* 2272e192b24SSimon Glass * Check to see if we need to tftp the image ourselves 2282e192b24SSimon Glass * before starting 2292e192b24SSimon Glass */ 2302e192b24SSimon Glass if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) { 2312e192b24SSimon Glass if (net_loop(TFTPGET) <= 0) 2322e192b24SSimon Glass return 1; 2332e192b24SSimon Glass printf("Automatic boot of VxWorks image at address 0x%08lx ...\n", 2342e192b24SSimon Glass addr); 2352e192b24SSimon Glass } 2362e192b24SSimon Glass #endif 2372e192b24SSimon Glass 2382e192b24SSimon Glass /* 2392e192b24SSimon Glass * This should equate to 2402e192b24SSimon Glass * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET 2412e192b24SSimon Glass * from the VxWorks BSP header files. 2422e192b24SSimon Glass * This will vary from board to board 2432e192b24SSimon Glass */ 2448996975fSTuomas Tynkkynen #if defined(CONFIG_SYS_VXWORKS_MAC_PTR) 2452e192b24SSimon Glass tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR; 24635affd7aSSimon Glass eth_env_get_enetaddr("ethaddr", (uchar *)build_buf); 2472e192b24SSimon Glass memcpy(tmp, build_buf, 6); 2482e192b24SSimon Glass #else 2492e192b24SSimon Glass puts("## Ethernet MAC address not copied to NV RAM\n"); 2502e192b24SSimon Glass #endif 2512e192b24SSimon Glass 2522e192b24SSimon Glass /* 2532e192b24SSimon Glass * Use bootaddr to find the location in memory that VxWorks 2542e192b24SSimon Glass * will look for the bootline string. The default value is 2552e192b24SSimon Glass * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by 2562e192b24SSimon Glass * VxWorks BSP. For example, on PowerPC it defaults to 0x4200. 2572e192b24SSimon Glass */ 25800caae6dSSimon Glass tmp = env_get("bootaddr"); 2592e192b24SSimon Glass if (!tmp) { 2602e192b24SSimon Glass printf("## VxWorks bootline address not specified\n"); 2612e192b24SSimon Glass } else { 2622e192b24SSimon Glass bootaddr = simple_strtoul(tmp, NULL, 16); 2632e192b24SSimon Glass 2642e192b24SSimon Glass /* 2652e192b24SSimon Glass * Check to see if the bootline is defined in the 'bootargs' 2662e192b24SSimon Glass * parameter. If it is not defined, we may be able to 2672e192b24SSimon Glass * construct the info. 2682e192b24SSimon Glass */ 26900caae6dSSimon Glass bootline = env_get("bootargs"); 2702e192b24SSimon Glass if (bootline) { 2712e192b24SSimon Glass memcpy((void *)bootaddr, bootline, 2722e192b24SSimon Glass max(strlen(bootline), (size_t)255)); 2732e192b24SSimon Glass flush_cache(bootaddr, max(strlen(bootline), 2742e192b24SSimon Glass (size_t)255)); 2752e192b24SSimon Glass } else { 27600caae6dSSimon Glass tmp = env_get("bootdev"); 2772e192b24SSimon Glass if (tmp) { 2782e192b24SSimon Glass strcpy(build_buf, tmp); 2792e192b24SSimon Glass ptr = strlen(tmp); 2802e192b24SSimon Glass } else 2812e192b24SSimon Glass printf("## VxWorks boot device not specified\n"); 2822e192b24SSimon Glass 28300caae6dSSimon Glass tmp = env_get("bootfile"); 2842e192b24SSimon Glass if (tmp) 2852e192b24SSimon Glass ptr += sprintf(build_buf + ptr, 2862e192b24SSimon Glass "host:%s ", tmp); 2872e192b24SSimon Glass else 2882e192b24SSimon Glass ptr += sprintf(build_buf + ptr, 2892e192b24SSimon Glass "host:vxWorks "); 2902e192b24SSimon Glass 2912e192b24SSimon Glass /* 2922e192b24SSimon Glass * The following parameters are only needed if 'bootdev' 2932e192b24SSimon Glass * is an ethernet device, otherwise they are optional. 2942e192b24SSimon Glass */ 29500caae6dSSimon Glass tmp = env_get("ipaddr"); 2962e192b24SSimon Glass if (tmp) { 2972e192b24SSimon Glass ptr += sprintf(build_buf + ptr, "e=%s", tmp); 29800caae6dSSimon Glass tmp = env_get("netmask"); 2992e192b24SSimon Glass if (tmp) { 300723806ccSSimon Glass u32 mask = env_get_ip("netmask").s_addr; 3012e192b24SSimon Glass ptr += sprintf(build_buf + ptr, 3022e192b24SSimon Glass ":%08x ", ntohl(mask)); 3032e192b24SSimon Glass } else { 3042e192b24SSimon Glass ptr += sprintf(build_buf + ptr, " "); 3052e192b24SSimon Glass } 3062e192b24SSimon Glass } 3072e192b24SSimon Glass 30800caae6dSSimon Glass tmp = env_get("serverip"); 3092e192b24SSimon Glass if (tmp) 3102e192b24SSimon Glass ptr += sprintf(build_buf + ptr, "h=%s ", tmp); 3112e192b24SSimon Glass 31200caae6dSSimon Glass tmp = env_get("gatewayip"); 3132e192b24SSimon Glass if (tmp) 3142e192b24SSimon Glass ptr += sprintf(build_buf + ptr, "g=%s ", tmp); 3152e192b24SSimon Glass 31600caae6dSSimon Glass tmp = env_get("hostname"); 3172e192b24SSimon Glass if (tmp) 3182e192b24SSimon Glass ptr += sprintf(build_buf + ptr, "tn=%s ", tmp); 3192e192b24SSimon Glass 32000caae6dSSimon Glass tmp = env_get("othbootargs"); 3212e192b24SSimon Glass if (tmp) { 3222e192b24SSimon Glass strcpy(build_buf + ptr, tmp); 3232e192b24SSimon Glass ptr += strlen(tmp); 3242e192b24SSimon Glass } 3252e192b24SSimon Glass 3262e192b24SSimon Glass memcpy((void *)bootaddr, build_buf, 3272e192b24SSimon Glass max(strlen(build_buf), (size_t)255)); 3282e192b24SSimon Glass flush_cache(bootaddr, max(strlen(build_buf), 3292e192b24SSimon Glass (size_t)255)); 3302e192b24SSimon Glass } 3312e192b24SSimon Glass 3322e192b24SSimon Glass printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, 3332e192b24SSimon Glass (char *)bootaddr); 3342e192b24SSimon Glass } 3352e192b24SSimon Glass 3362e192b24SSimon Glass #ifdef CONFIG_X86 3372e192b24SSimon Glass /* 3382e192b24SSimon Glass * Since E820 information is critical to the kernel, if we don't 3392e192b24SSimon Glass * specify these in the environments, use a default one. 3402e192b24SSimon Glass */ 34100caae6dSSimon Glass tmp = env_get("e820data"); 3422e192b24SSimon Glass if (tmp) 3432e192b24SSimon Glass data = (struct e820entry *)simple_strtoul(tmp, NULL, 16); 3442e192b24SSimon Glass else 3452e192b24SSimon Glass data = (struct e820entry *)VXWORKS_E820_DATA_ADDR; 34600caae6dSSimon Glass tmp = env_get("e820info"); 3472e192b24SSimon Glass if (tmp) 3482e192b24SSimon Glass info = (struct e820info *)simple_strtoul(tmp, NULL, 16); 3492e192b24SSimon Glass else 3502e192b24SSimon Glass info = (struct e820info *)VXWORKS_E820_INFO_ADDR; 3512e192b24SSimon Glass 3522e192b24SSimon Glass memset(info, 0, sizeof(struct e820info)); 3532e192b24SSimon Glass info->sign = E820_SIGNATURE; 3542e192b24SSimon Glass info->entries = install_e820_map(E820MAX, data); 3552e192b24SSimon Glass info->addr = (info->entries - 1) * sizeof(struct e820entry) + 3562e192b24SSimon Glass VXWORKS_E820_DATA_ADDR; 3572e192b24SSimon Glass #endif 3582e192b24SSimon Glass 3592e192b24SSimon Glass /* 3602e192b24SSimon Glass * If the data at the load address is an elf image, then 3612e192b24SSimon Glass * treat it like an elf image. Otherwise, assume that it is a 3622e192b24SSimon Glass * binary image. 3632e192b24SSimon Glass */ 3642e192b24SSimon Glass if (valid_elf_image(addr)) 365476c2fcdSChristian Gmeiner addr = load_elf_image_phdr(addr); 3662e192b24SSimon Glass else 3672e192b24SSimon Glass puts("## Not an ELF image, assuming binary\n"); 3682e192b24SSimon Glass 3692e192b24SSimon Glass printf("## Starting vxWorks at 0x%08lx ...\n", addr); 3702e192b24SSimon Glass 3712e192b24SSimon Glass dcache_disable(); 372*3194daa1SVasyl Vavrychuk #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI) 373*3194daa1SVasyl Vavrychuk armv8_setup_psci(); 374*3194daa1SVasyl Vavrychuk smp_kick_all_cpus(); 375*3194daa1SVasyl Vavrychuk #endif 376*3194daa1SVasyl Vavrychuk 3772e192b24SSimon Glass #ifdef CONFIG_X86 3782e192b24SSimon Glass /* VxWorks on x86 uses stack to pass parameters */ 3792e192b24SSimon Glass ((asmlinkage void (*)(int))addr)(0); 3802e192b24SSimon Glass #else 3812e192b24SSimon Glass ((void (*)(int))addr)(0); 3822e192b24SSimon Glass #endif 3832e192b24SSimon Glass 3842e192b24SSimon Glass puts("## vxWorks terminated\n"); 3852e192b24SSimon Glass 3862e192b24SSimon Glass return 1; 3872e192b24SSimon Glass } 3882e192b24SSimon Glass 3892e192b24SSimon Glass U_BOOT_CMD( 390be1b8679STom Rini bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf, 3912e192b24SSimon Glass "Boot from an ELF image in memory", 3922e192b24SSimon Glass "[-p|-s] [address]\n" 3932e192b24SSimon Glass "\t- load ELF image at [address] via program headers (-p)\n" 3942e192b24SSimon Glass "\t or via section headers (-s)" 3952e192b24SSimon Glass ); 3962e192b24SSimon Glass 3972e192b24SSimon Glass U_BOOT_CMD( 3982e192b24SSimon Glass bootvx, 2, 0, do_bootvx, 3992e192b24SSimon Glass "Boot vxWorks from an ELF image", 4002e192b24SSimon Glass " [address] - load address of vxWorks ELF image." 4012e192b24SSimon Glass ); 402