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