X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=cmd%2Felf.c;h=538562fda581ba6b6978199db8e8a2ae1f8f5231;hb=83a9f0a3d703a37044d2438a3c4223561de503b3;hp=30c845833b6f6030545bb33a273f061867e0b3c1;hpb=447ae4f7adb2c667eec1e0861e2346694c57a2e0;p=oweals%2Fu-boot.git diff --git a/cmd/elf.c b/cmd/elf.c index 30c845833b..538562fda5 100644 --- a/cmd/elf.c +++ b/cmd/elf.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #ifdef CONFIG_X86 @@ -53,10 +53,87 @@ static unsigned long load_elf64_image_phdr(unsigned long addr) 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); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup(phdr->p_memsz, ARCH_DMA_MINALIGN)); ++phdr; } + if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags & + EF_PPC64_ELFV1_ABI)) { + /* + * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function + * descriptor pointer with the first double word being the + * address of the entry point of the function. + */ + uintptr_t addr = ehdr->e_entry; + + return *(Elf64_Addr *)addr; + } + + return ehdr->e_entry; +} + +static unsigned long load_elf64_image_shdr(unsigned long addr) +{ + Elf64_Ehdr *ehdr; /* Elf header structure pointer */ + Elf64_Shdr *shdr; /* Section header structure pointer */ + unsigned char *strtab = 0; /* String table pointer */ + unsigned char *image; /* Binary image pointer */ + int i; /* Loop counter */ + + ehdr = (Elf64_Ehdr *)addr; + + /* Find the section header string table for output info */ + shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff + + (ehdr->e_shstrndx * sizeof(Elf64_Shdr))); + + if (shdr->sh_type == SHT_STRTAB) + strtab = (unsigned char *)(addr + (ulong)shdr->sh_offset); + + /* Load each appropriate section */ + for (i = 0; i < ehdr->e_shnum; ++i) { + shdr = (Elf64_Shdr *)(addr + (ulong)ehdr->e_shoff + + (i * sizeof(Elf64_Shdr))); + + if (!(shdr->sh_flags & SHF_ALLOC) || + shdr->sh_addr == 0 || shdr->sh_size == 0) { + continue; + } + + if (strtab) { + debug("%sing %s @ 0x%08lx (%ld bytes)\n", + (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load", + &strtab[shdr->sh_name], + (unsigned long)shdr->sh_addr, + (long)shdr->sh_size); + } + + if (shdr->sh_type == SHT_NOBITS) { + memset((void *)(uintptr_t)shdr->sh_addr, 0, + shdr->sh_size); + } else { + image = (unsigned char *)addr + (ulong)shdr->sh_offset; + memcpy((void *)(uintptr_t)shdr->sh_addr, + (const void *)image, shdr->sh_size); + } + flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN), + roundup((shdr->sh_addr + shdr->sh_size), + ARCH_DMA_MINALIGN) - + rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN)); + } + + if (ehdr->e_machine == EM_PPC64 && (ehdr->e_flags & + EF_PPC64_ELFV1_ABI)) { + /* + * For the 64-bit PowerPC ELF V1 ABI, e_entry is a function + * descriptor pointer with the first double word being the + * address of the entry point of the function. + */ + uintptr_t addr = ehdr->e_entry; + + return *(Elf64_Addr *)addr; + } + return ehdr->e_entry; } @@ -91,7 +168,8 @@ static unsigned long load_elf_image_phdr(unsigned long addr) 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); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup(phdr->p_memsz, ARCH_DMA_MINALIGN)); ++phdr; } @@ -107,6 +185,8 @@ static unsigned long load_elf_image_shdr(unsigned long addr) int i; /* Loop counter */ ehdr = (Elf32_Ehdr *)addr; + if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) + return load_elf64_image_shdr(addr); /* Find the section header string table for output info */ shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + @@ -141,7 +221,10 @@ static unsigned long load_elf_image_shdr(unsigned long addr) memcpy((void *)(uintptr_t)shdr->sh_addr, (const void *)image, shdr->sh_size); } - flush_cache(shdr->sh_addr, shdr->sh_size); + flush_cache(rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN), + roundup((shdr->sh_addr + shdr->sh_size), + ARCH_DMA_MINALIGN) - + rounddown(shdr->sh_addr, ARCH_DMA_MINALIGN)); } return ehdr->e_entry; @@ -246,7 +329,7 @@ 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 */ @@ -295,90 +378,6 @@ int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) puts("## Ethernet MAC address not copied to NV RAM\n"); #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 = env_get("bootaddr"); - if (!tmp) { - printf("## VxWorks bootline address not specified\n"); - } else { - 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 = env_get("bootargs"); - if (bootline) { - memcpy((void *)bootaddr, bootline, - max(strlen(bootline), (size_t)255)); - flush_cache(bootaddr, max(strlen(bootline), - (size_t)255)); - } else { - tmp = env_get("bootdev"); - if (tmp) { - strcpy(build_buf, tmp); - ptr = strlen(tmp); - } else - printf("## VxWorks boot device not specified\n"); - - 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 = env_get("ipaddr"); - if (tmp) { - ptr += sprintf(build_buf + ptr, "e=%s", tmp); - tmp = env_get("netmask"); - if (tmp) { - u32 mask = env_get_ip("netmask").s_addr; - ptr += sprintf(build_buf + ptr, - ":%08x ", ntohl(mask)); - } else { - ptr += sprintf(build_buf + ptr, " "); - } - } - - tmp = env_get("serverip"); - if (tmp) - ptr += sprintf(build_buf + ptr, "h=%s ", tmp); - - tmp = env_get("gatewayip"); - if (tmp) - ptr += sprintf(build_buf + ptr, "g=%s ", tmp); - - tmp = env_get("hostname"); - if (tmp) - ptr += sprintf(build_buf + ptr, "tn=%s ", tmp); - - tmp = env_get("othbootargs"); - if (tmp) { - strcpy(build_buf + ptr, tmp); - ptr += strlen(tmp); - } - - memcpy((void *)bootaddr, build_buf, - max(strlen(build_buf), (size_t)255)); - flush_cache(bootaddr, max(strlen(build_buf), - (size_t)255)); - } - - printf("## Using bootline (@ 0x%lx): %s\n", bootaddr, - (char *)bootaddr); - } - #ifdef CONFIG_X86 /* * Get VxWorks's physical memory base address from environment, @@ -418,6 +417,87 @@ int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } #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 = env_get("bootaddr"); + if (!tmp) { +#ifdef CONFIG_X86 + bootaddr = base + X86_BOOT_LINE_OFFSET; +#else + printf("## VxWorks bootline address not specified\n"); + 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 = env_get("bootargs"); + if (!bootline) { + tmp = env_get("bootdev"); + if (tmp) { + strcpy(build_buf, tmp); + ptr = strlen(tmp); + } else { + printf("## VxWorks boot device not specified\n"); + } + + 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 = env_get("ipaddr"); + if (tmp) { + ptr += sprintf(build_buf + ptr, "e=%s", tmp); + tmp = env_get("netmask"); + if (tmp) { + u32 mask = env_get_ip("netmask").s_addr; + ptr += sprintf(build_buf + ptr, + ":%08x ", ntohl(mask)); + } else { + ptr += sprintf(build_buf + ptr, " "); + } + } + + tmp = env_get("serverip"); + if (tmp) + ptr += sprintf(build_buf + ptr, "h=%s ", tmp); + + tmp = env_get("gatewayip"); + if (tmp) + ptr += sprintf(build_buf + ptr, "g=%s ", tmp); + + tmp = env_get("hostname"); + if (tmp) + ptr += sprintf(build_buf + ptr, "tn=%s ", tmp); + + tmp = env_get("othbootargs"); + if (tmp) { + strcpy(build_buf + ptr, tmp); + ptr += strlen(tmp); + } + + bootline = build_buf; + } + + 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 * treat it like an elf image. Otherwise, assume that it is a