uboot/cmd/elf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-2-Clause
   2/*
   3 * Copyright (c) 2001 William L. Pitts
   4 * All rights reserved.
   5 */
   6
   7#include <common.h>
   8#include <command.h>
   9#include <cpu_func.h>
  10#include <elf.h>
  11#include <env.h>
  12#include <image.h>
  13#include <log.h>
  14#include <net.h>
  15#include <vxworks.h>
  16#ifdef CONFIG_X86
  17#include <vbe.h>
  18#include <asm/cache.h>
  19#include <asm/e820.h>
  20#include <linux/linkage.h>
  21#endif
  22
  23/* Allow ports to override the default behavior */
  24static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
  25                                     int argc, char *const argv[])
  26{
  27        unsigned long ret;
  28
  29        /*
  30         * pass address parameter as argv[0] (aka command name),
  31         * and all remaining args
  32         */
  33        ret = entry(argc, argv);
  34
  35        return ret;
  36}
  37
  38/* Interpreter command to boot an arbitrary ELF image from memory */
  39int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
  40{
  41        unsigned long addr; /* Address of the ELF image */
  42        unsigned long rc; /* Return value from user code */
  43        char *sload = NULL;
  44        const char *ep = env_get("autostart");
  45        int rcode = 0;
  46
  47        /* Consume 'bootelf' */
  48        argc--; argv++;
  49
  50        /* Check for flag. */
  51        if (argc >= 1 && (argv[0][0] == '-' && \
  52                                (argv[0][1] == 'p' || argv[0][1] == 's'))) {
  53                sload = argv[0];
  54                /* Consume flag. */
  55                argc--; argv++;
  56        }
  57        /* Check for address. */
  58        if (argc >= 1 && strict_strtoul(argv[0], 16, &addr) != -EINVAL) {
  59                /* Consume address */
  60                argc--; argv++;
  61        } else
  62                addr = image_load_addr;
  63
  64        if (!valid_elf_image(addr))
  65                return 1;
  66
  67        if (sload && sload[1] == 'p')
  68                addr = load_elf_image_phdr(addr);
  69        else
  70                addr = load_elf_image_shdr(addr);
  71
  72        if (ep && !strcmp(ep, "no"))
  73                return rcode;
  74
  75        printf("## Starting application at 0x%08lx ...\n", addr);
  76
  77        /*
  78         * pass address parameter as argv[0] (aka command name),
  79         * and all remaining args
  80         */
  81        rc = do_bootelf_exec((void *)addr, argc, argv);
  82        if (rc != 0)
  83                rcode = 1;
  84
  85        printf("## Application terminated, rc = 0x%lx\n", rc);
  86
  87        return rcode;
  88}
  89
  90/*
  91 * Interpreter command to boot VxWorks from a memory image.  The image can
  92 * be either an ELF image or a raw binary.  Will attempt to setup the
  93 * bootline and other parameters correctly.
  94 */
  95int do_bootvx(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
  96{
  97        unsigned long addr; /* Address of image */
  98        unsigned long bootaddr = 0; /* Address to put the bootline */
  99        char *bootline; /* Text of the bootline */
 100        char *tmp; /* Temporary char pointer */
 101        char build_buf[128]; /* Buffer for building the bootline */
 102        int ptr = 0;
 103#ifdef CONFIG_X86
 104        ulong base;
 105        struct e820_info *info;
 106        struct e820_entry *data;
 107        struct efi_gop_info *gop;
 108        struct vesa_mode_info *vesa = &mode_info.vesa;
 109#endif
 110
 111        /*
 112         * Check the loadaddr variable.
 113         * If we don't know where the image is then we're done.
 114         */
 115        if (argc < 2)
 116                addr = image_load_addr;
 117        else
 118                addr = hextoul(argv[1], NULL);
 119
 120#if defined(CONFIG_CMD_NET)
 121        /*
 122         * Check to see if we need to tftp the image ourselves
 123         * before starting
 124         */
 125        if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) {
 126                if (net_loop(TFTPGET) <= 0)
 127                        return 1;
 128                printf("Automatic boot of VxWorks image at address 0x%08lx ...\n",
 129                        addr);
 130        }
 131#endif
 132
 133        /*
 134         * This should equate to
 135         * NV_RAM_ADRS + NV_BOOT_OFFSET + NV_ENET_OFFSET
 136         * from the VxWorks BSP header files.
 137         * This will vary from board to board
 138         */
 139#if defined(CONFIG_SYS_VXWORKS_MAC_PTR)
 140        tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
 141        eth_env_get_enetaddr("ethaddr", (uchar *)build_buf);
 142        memcpy(tmp, build_buf, 6);
 143#else
 144        puts("## Ethernet MAC address not copied to NV RAM\n");
 145#endif
 146
 147#ifdef CONFIG_X86
 148        /*
 149         * Get VxWorks's physical memory base address from environment,
 150         * if we don't specify it in the environment, use a default one.
 151         */
 152        base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE);
 153        data = (struct e820_entry *)(base + E820_DATA_OFFSET);
 154        info = (struct e820_info *)(base + E820_INFO_OFFSET);
 155
 156        memset(info, 0, sizeof(struct e820_info));
 157        info->sign = E820_SIGNATURE;
 158        info->entries = install_e820_map(E820MAX, data);
 159        info->addr = (info->entries - 1) * sizeof(struct e820_entry) +
 160                     E820_DATA_OFFSET;
 161
 162        /*
 163         * Explicitly clear the bootloader image size otherwise if memory
 164         * at this offset happens to contain some garbage data, the final
 165         * available memory size for the kernel is insane.
 166         */
 167        *(u32 *)(base + BOOT_IMAGE_SIZE_OFFSET) = 0;
 168
 169        /*
 170         * Prepare compatible framebuffer information block.
 171         * The VESA mode has to be 32-bit RGBA.
 172         */
 173        if (vesa->x_resolution && vesa->y_resolution) {
 174                gop = (struct efi_gop_info *)(base + EFI_GOP_INFO_OFFSET);
 175                gop->magic = EFI_GOP_INFO_MAGIC;
 176                gop->info.version = 0;
 177                gop->info.width = vesa->x_resolution;
 178                gop->info.height = vesa->y_resolution;
 179                gop->info.pixel_format = EFI_GOT_RGBA8;
 180                gop->info.pixels_per_scanline = vesa->bytes_per_scanline / 4;
 181                gop->fb_base = vesa->phys_base_ptr;
 182                gop->fb_size = vesa->bytes_per_scanline * vesa->y_resolution;
 183        }
 184#endif
 185
 186        /*
 187         * Use bootaddr to find the location in memory that VxWorks
 188         * will look for the bootline string. The default value is
 189         * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
 190         * VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
 191         */
 192        tmp = env_get("bootaddr");
 193        if (!tmp) {
 194#ifdef CONFIG_X86
 195                bootaddr = base + X86_BOOT_LINE_OFFSET;
 196#else
 197                printf("## VxWorks bootline address not specified\n");
 198                return 1;
 199#endif
 200        }
 201
 202        if (!bootaddr)
 203                bootaddr = hextoul(tmp, NULL);
 204
 205        /*
 206         * Check to see if the bootline is defined in the 'bootargs' parameter.
 207         * If it is not defined, we may be able to construct the info.
 208         */
 209        bootline = env_get("bootargs");
 210        if (!bootline) {
 211                tmp = env_get("bootdev");
 212                if (tmp) {
 213                        strcpy(build_buf, tmp);
 214                        ptr = strlen(tmp);
 215                } else {
 216                        printf("## VxWorks boot device not specified\n");
 217                }
 218
 219                tmp = env_get("bootfile");
 220                if (tmp)
 221                        ptr += sprintf(build_buf + ptr, "host:%s ", tmp);
 222                else
 223                        ptr += sprintf(build_buf + ptr, "host:vxWorks ");
 224
 225                /*
 226                 * The following parameters are only needed if 'bootdev'
 227                 * is an ethernet device, otherwise they are optional.
 228                 */
 229                tmp = env_get("ipaddr");
 230                if (tmp) {
 231                        ptr += sprintf(build_buf + ptr, "e=%s", tmp);
 232                        tmp = env_get("netmask");
 233                        if (tmp) {
 234                                u32 mask = env_get_ip("netmask").s_addr;
 235                                ptr += sprintf(build_buf + ptr,
 236                                               ":%08x ", ntohl(mask));
 237                        } else {
 238                                ptr += sprintf(build_buf + ptr, " ");
 239                        }
 240                }
 241
 242                tmp = env_get("serverip");
 243                if (tmp)
 244                        ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
 245
 246                tmp = env_get("gatewayip");
 247                if (tmp)
 248                        ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
 249
 250                tmp = env_get("hostname");
 251                if (tmp)
 252                        ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
 253
 254                tmp = env_get("othbootargs");
 255                if (tmp) {
 256                        strcpy(build_buf + ptr, tmp);
 257                        ptr += strlen(tmp);
 258                }
 259
 260                bootline = build_buf;
 261        }
 262
 263        memcpy((void *)bootaddr, bootline, max(strlen(bootline), (size_t)255));
 264        flush_cache(bootaddr, max(strlen(bootline), (size_t)255));
 265        printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, (char *)bootaddr);
 266
 267        /*
 268         * If the data at the load address is an elf image, then
 269         * treat it like an elf image. Otherwise, assume that it is a
 270         * binary image.
 271         */
 272        if (valid_elf_image(addr))
 273                addr = load_elf_image_phdr(addr);
 274        else
 275                puts("## Not an ELF image, assuming binary\n");
 276
 277        printf("## Starting vxWorks at 0x%08lx ...\n", addr);
 278
 279        dcache_disable();
 280#if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
 281        armv8_setup_psci();
 282        smp_kick_all_cpus();
 283#endif
 284
 285#ifdef CONFIG_X86
 286        /* VxWorks on x86 uses stack to pass parameters */
 287        ((asmlinkage void (*)(int))addr)(0);
 288#else
 289        ((void (*)(int))addr)(0);
 290#endif
 291
 292        puts("## vxWorks terminated\n");
 293
 294        return 1;
 295}
 296
 297U_BOOT_CMD(
 298        bootelf, CONFIG_SYS_MAXARGS, 0, do_bootelf,
 299        "Boot from an ELF image in memory",
 300        "[-p|-s] [address]\n"
 301        "\t- load ELF image at [address] via program headers (-p)\n"
 302        "\t  or via section headers (-s)"
 303);
 304
 305U_BOOT_CMD(
 306        bootvx, 2, 0, do_bootvx,
 307        "Boot vxWorks from an ELF image",
 308        " [address] - load address of vxWorks ELF image."
 309);
 310