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