]> git.sur5r.net Git - u-boot/blobdiff - cmd/elf.c
Merge branch 'master' of git://git.denx.de/u-boot-sunxi
[u-boot] / cmd / elf.c
index ed9625b221fe1d76abf424840e80dc6ab920b0ab..eafea38aed18938621ecafa4a5d3da0a13322046 100644 (file)
--- a/cmd/elf.c
+++ b/cmd/elf.c
 #include <common.h>
 #include <command.h>
 #include <elf.h>
+#include <environment.h>
 #include <net.h>
 #include <vxworks.h>
 #ifdef CONFIG_X86
+#include <vbe.h>
 #include <asm/e820.h>
 #include <linux/linkage.h>
 #endif
 
 /*
- * A very simple elf loader, assumes the image is valid, returns the
+ * A very simple ELF64 loader, assumes the image is valid, returns the
  * entry point address.
+ *
+ * Note if U-Boot is 32-bit, the loader assumes the to segment's
+ * physical address and size is within the lower 32-bit address space.
+ */
+static unsigned long load_elf64_image_phdr(unsigned long addr)
+{
+       Elf64_Ehdr *ehdr; /* Elf header structure pointer */
+       Elf64_Phdr *phdr; /* Program header structure pointer */
+       int i;
+
+       ehdr = (Elf64_Ehdr *)addr;
+       phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
+
+       /* Load each program header */
+       for (i = 0; i < ehdr->e_phnum; ++i) {
+               void *dst = (void *)(ulong)phdr->p_paddr;
+               void *src = (void *)addr + phdr->p_offset;
+
+               debug("Loading phdr %i to 0x%p (%lu bytes)\n",
+                     i, dst, (ulong)phdr->p_filesz);
+               if (phdr->p_filesz)
+                       memcpy(dst, src, phdr->p_filesz);
+               if (phdr->p_filesz != phdr->p_memsz)
+                       memset(dst + phdr->p_filesz, 0x00,
+                              phdr->p_memsz - phdr->p_filesz);
+               flush_cache((unsigned long)dst, phdr->p_filesz);
+               ++phdr;
+       }
+
+       return ehdr->e_entry;
+}
+
+/*
+ * A very simple ELF loader, assumes the image is valid, returns the
+ * entry point address.
+ *
+ * The loader firstly reads the EFI class to see if it's a 64-bit image.
+ * If yes, call the ELF64 loader. Otherwise continue with the ELF32 loader.
  */
 static unsigned long load_elf_image_phdr(unsigned long addr)
 {
@@ -34,12 +74,16 @@ static unsigned long load_elf_image_phdr(unsigned long addr)
        int i;
 
        ehdr = (Elf32_Ehdr *)addr;
+       if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+               return load_elf64_image_phdr(addr);
+
        phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
 
        /* Load each program header */
        for (i = 0; i < ehdr->e_phnum; ++i) {
                void *dst = (void *)(uintptr_t)phdr->p_paddr;
                void *src = (void *)addr + phdr->p_offset;
+
                debug("Loading phdr %i to 0x%p (%i bytes)\n",
                      i, dst, phdr->p_filesz);
                if (phdr->p_filesz)
@@ -148,7 +192,7 @@ int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        unsigned long addr; /* Address of the ELF image */
        unsigned long rc; /* Return value from user code */
        char *sload = NULL;
-       const char *ep = getenv("autostart");
+       const char *ep = env_get("autostart");
        int rcode = 0;
 
        /* Consume 'bootelf' */
@@ -202,14 +246,17 @@ int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
        unsigned long addr; /* Address of image */
-       unsigned long bootaddr; /* Address to put the bootline */
+       unsigned long bootaddr = 0; /* Address to put the bootline */
        char *bootline; /* Text of the bootline */
        char *tmp; /* Temporary char pointer */
        char build_buf[128]; /* Buffer for building the bootline */
        int ptr = 0;
 #ifdef CONFIG_X86
-       struct e820info *info;
-       struct e820entry *data;
+       ulong base;
+       struct e820_info *info;
+       struct e820_entry *data;
+       struct efi_gop_info *gop;
+       struct vesa_mode_info *vesa = &mode_info.vesa;
 #endif
 
        /*
@@ -240,124 +287,133 @@ int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
         * from the VxWorks BSP header files.
         * This will vary from board to board
         */
-#if defined(CONFIG_WALNUT)
-       tmp = (char *)CONFIG_SYS_NVRAM_BASE_ADDR + 0x500;
-       eth_getenv_enetaddr("ethaddr", (uchar *)build_buf);
-       memcpy(tmp, &build_buf[3], 3);
-#elif defined(CONFIG_SYS_VXWORKS_MAC_PTR)
+#if defined(CONFIG_SYS_VXWORKS_MAC_PTR)
        tmp = (char *)CONFIG_SYS_VXWORKS_MAC_PTR;
-       eth_getenv_enetaddr("ethaddr", (uchar *)build_buf);
+       eth_env_get_enetaddr("ethaddr", (uchar *)build_buf);
        memcpy(tmp, build_buf, 6);
 #else
        puts("## Ethernet MAC address not copied to NV RAM\n");
 #endif
 
+#ifdef CONFIG_X86
+       /*
+        * Get VxWorks's physical memory base address from environment,
+        * if we don't specify it in the environment, use a default one.
+        */
+       base = env_get_hex("vx_phys_mem_base", VXWORKS_PHYS_MEM_BASE);
+       data = (struct e820_entry *)(base + E820_DATA_OFFSET);
+       info = (struct e820_info *)(base + E820_INFO_OFFSET);
+
+       memset(info, 0, sizeof(struct e820_info));
+       info->sign = E820_SIGNATURE;
+       info->entries = install_e820_map(E820MAX, data);
+       info->addr = (info->entries - 1) * sizeof(struct e820_entry) +
+                    E820_DATA_OFFSET;
+
+       /*
+        * Explicitly clear the bootloader image size otherwise if memory
+        * at this offset happens to contain some garbage data, the final
+        * available memory size for the kernel is insane.
+        */
+       *(u32 *)(base + BOOT_IMAGE_SIZE_OFFSET) = 0;
+
+       /*
+        * Prepare compatible framebuffer information block.
+        * The VESA mode has to be 32-bit RGBA.
+        */
+       if (vesa->x_resolution && vesa->y_resolution) {
+               gop = (struct efi_gop_info *)(base + EFI_GOP_INFO_OFFSET);
+               gop->magic = EFI_GOP_INFO_MAGIC;
+               gop->info.version = 0;
+               gop->info.width = vesa->x_resolution;
+               gop->info.height = vesa->y_resolution;
+               gop->info.pixel_format = EFI_GOT_RGBA8;
+               gop->info.pixels_per_scanline = vesa->bytes_per_scanline / 4;
+               gop->fb_base = vesa->phys_base_ptr;
+               gop->fb_size = vesa->bytes_per_scanline * vesa->y_resolution;
+       }
+#endif
+
        /*
         * Use bootaddr to find the location in memory that VxWorks
         * will look for the bootline string. The default value is
         * (LOCAL_MEM_LOCAL_ADRS + BOOT_LINE_OFFSET) as defined by
         * VxWorks BSP. For example, on PowerPC it defaults to 0x4200.
         */
-       tmp = getenv("bootaddr");
+       tmp = env_get("bootaddr");
        if (!tmp) {
+#ifdef CONFIG_X86
+               bootaddr = base + X86_BOOT_LINE_OFFSET;
+#else
                printf("## VxWorks bootline address not specified\n");
-       } else {
+               return 1;
+#endif
+       }
+
+       if (!bootaddr)
                bootaddr = simple_strtoul(tmp, NULL, 16);
 
-               /*
-                * Check to see if the bootline is defined in the 'bootargs'
-                * parameter. If it is not defined, we may be able to
-                * construct the info.
-                */
-               bootline = getenv("bootargs");
-               if (bootline) {
-                       memcpy((void *)bootaddr, bootline,
-                              max(strlen(bootline), (size_t)255));
-                       flush_cache(bootaddr, max(strlen(bootline),
-                                                 (size_t)255));
+       /*
+        * Check to see if the bootline is defined in the 'bootargs' parameter.
+        * If it is not defined, we may be able to construct the info.
+        */
+       bootline = env_get("bootargs");
+       if (!bootline) {
+               tmp = env_get("bootdev");
+               if (tmp) {
+                       strcpy(build_buf, tmp);
+                       ptr = strlen(tmp);
                } else {
-                       tmp = getenv("bootdev");
-                       if (tmp) {
-                               strcpy(build_buf, tmp);
-                               ptr = strlen(tmp);
-                       } else
-                               printf("## VxWorks boot device not specified\n");
+                       printf("## VxWorks boot device not specified\n");
+               }
 
-                       tmp = getenv("bootfile");
-                       if (tmp)
-                               ptr += sprintf(build_buf + ptr,
-                                              "host:%s ", tmp);
-                       else
-                               ptr += sprintf(build_buf + ptr,
-                                              "host:vxWorks ");
+               tmp = env_get("bootfile");
+               if (tmp)
+                       ptr += sprintf(build_buf + ptr, "host:%s ", tmp);
+               else
+                       ptr += sprintf(build_buf + ptr, "host:vxWorks ");
 
-                       /*
-                        * The following parameters are only needed if 'bootdev'
-                        * is an ethernet device, otherwise they are optional.
-                        */
-                       tmp = getenv("ipaddr");
+               /*
+                * The following parameters are only needed if 'bootdev'
+                * is an ethernet device, otherwise they are optional.
+                */
+               tmp = env_get("ipaddr");
+               if (tmp) {
+                       ptr += sprintf(build_buf + ptr, "e=%s", tmp);
+                       tmp = env_get("netmask");
                        if (tmp) {
-                               ptr += sprintf(build_buf + ptr, "e=%s", tmp);
-                               tmp = getenv("netmask");
-                               if (tmp) {
-                                       u32 mask = getenv_ip("netmask").s_addr;
-                                       ptr += sprintf(build_buf + ptr,
-                                                      ":%08x ", ntohl(mask));
-                               } else {
-                                       ptr += sprintf(build_buf + ptr, " ");
-                               }
+                               u32 mask = env_get_ip("netmask").s_addr;
+                               ptr += sprintf(build_buf + ptr,
+                                              ":%08x ", ntohl(mask));
+                       } else {
+                               ptr += sprintf(build_buf + ptr, " ");
                        }
+               }
 
-                       tmp = getenv("serverip");
-                       if (tmp)
-                               ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
-
-                       tmp = getenv("gatewayip");
-                       if (tmp)
-                               ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
+               tmp = env_get("serverip");
+               if (tmp)
+                       ptr += sprintf(build_buf + ptr, "h=%s ", tmp);
 
-                       tmp = getenv("hostname");
-                       if (tmp)
-                               ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
+               tmp = env_get("gatewayip");
+               if (tmp)
+                       ptr += sprintf(build_buf + ptr, "g=%s ", tmp);
 
-                       tmp = getenv("othbootargs");
-                       if (tmp) {
-                               strcpy(build_buf + ptr, tmp);
-                               ptr += strlen(tmp);
-                       }
+               tmp = env_get("hostname");
+               if (tmp)
+                       ptr += sprintf(build_buf + ptr, "tn=%s ", tmp);
 
-                       memcpy((void *)bootaddr, build_buf,
-                              max(strlen(build_buf), (size_t)255));
-                       flush_cache(bootaddr, max(strlen(build_buf),
-                                                 (size_t)255));
+               tmp = env_get("othbootargs");
+               if (tmp) {
+                       strcpy(build_buf + ptr, tmp);
+                       ptr += strlen(tmp);
                }
 
-               printf("## Using bootline (@ 0x%lx): %s\n", bootaddr,
-                      (char *)bootaddr);
+               bootline = build_buf;
        }
 
-#ifdef CONFIG_X86
-       /*
-        * Since E820 information is critical to the kernel, if we don't
-        * specify these in the environments, use a default one.
-        */
-       tmp = getenv("e820data");
-       if (tmp)
-               data = (struct e820entry *)simple_strtoul(tmp, NULL, 16);
-       else
-               data = (struct e820entry *)VXWORKS_E820_DATA_ADDR;
-       tmp = getenv("e820info");
-       if (tmp)
-               info = (struct e820info *)simple_strtoul(tmp, NULL, 16);
-       else
-               info = (struct e820info *)VXWORKS_E820_INFO_ADDR;
-
-       memset(info, 0, sizeof(struct e820info));
-       info->sign = E820_SIGNATURE;
-       info->entries = install_e820_map(E820MAX, data);
-       info->addr = (info->entries - 1) * sizeof(struct e820entry) +
-                    VXWORKS_E820_DATA_ADDR;
-#endif
+       memcpy((void *)bootaddr, bootline, max(strlen(bootline), (size_t)255));
+       flush_cache(bootaddr, max(strlen(bootline), (size_t)255));
+       printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, (char *)bootaddr);
 
        /*
         * If the data at the load address is an elf image, then
@@ -365,13 +421,18 @@ int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
         * binary image.
         */
        if (valid_elf_image(addr))
-               addr = load_elf_image_shdr(addr);
+               addr = load_elf_image_phdr(addr);
        else
                puts("## Not an ELF image, assuming binary\n");
 
        printf("## Starting vxWorks at 0x%08lx ...\n", addr);
 
        dcache_disable();
+#if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
+       armv8_setup_psci();
+       smp_kick_all_cpus();
+#endif
+
 #ifdef CONFIG_X86
        /* VxWorks on x86 uses stack to pass parameters */
        ((asmlinkage void (*)(int))addr)(0);