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