/* * (C) Copyright 2013-2016 * Allwinner Technology Co., Ltd. * */ #include #include #include #ifdef CFG_ELF_64BIT #define Elf_Ehdr Elf64_Ehdr #define Elf_Phdr Elf64_Phdr #define Elf_Shdr Elf64_Shdr #else #define Elf_Ehdr Elf32_Ehdr #define Elf_Phdr Elf32_Phdr #define Elf_Shdr Elf32_Shdr #endif /* copy from u-boot-2018/drivers/riscv/common/riscv_img.h */ struct vaddr_range_t { unsigned long vstart; unsigned long vend; unsigned long pstart; }; /* * riscv need to remap addresses for some addr. */ static struct vaddr_range_t addr_mapping[] = { #ifdef CFG_RISCV_E906 { 0x3FFC0000, 0x4003FFFF, 0x07280000 }, { 0x40400000, 0x7FFFFFFF, 0x40400000}, #endif /*others (c906/e907) has the same addresses mapping as a7 */ }; static unsigned long set_img_va_to_pa(unsigned long vaddr, struct vaddr_range_t *map, int size) { unsigned long paddr = vaddr; int i; for (i = 0; i < size; i++) { if (vaddr >= map[i].vstart && vaddr <= map[i].vend) { paddr = vaddr - map[i].vstart + map[i].pstart; break; } } return paddr; } phys_addr_t elf_get_entry_addr(phys_addr_t base) { Elf_Ehdr *ehdr; ehdr = (Elf_Ehdr *)base; return ehdr->e_entry; } int load_elf_image(phys_addr_t img_addr) { int i; Elf_Ehdr *ehdr; Elf_Phdr *phdr; void *dst = NULL; void *src = NULL; int size = sizeof(addr_mapping) / sizeof(struct vaddr_range_t); ehdr = (Elf_Ehdr *)img_addr; phdr = (Elf_Phdr *)((phys_addr_t)(img_addr + ehdr->e_phoff)); /* load elf program segment */ for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) { //remap addresses dst = (void *)(phys_addr_t)set_img_va_to_pa((unsigned long)phdr->p_paddr, \ addr_mapping, size); src = (void *)((phys_addr_t)(img_addr + phdr->p_offset)); if (phdr->p_type != PT_LOAD) continue; if ((phdr->p_memsz == 0) || (phdr->p_filesz == 0)) continue; if (phdr->p_filesz) memcpy(dst, src, phdr->p_filesz); if (phdr->p_filesz != phdr->p_memsz) memset((u8 *)dst + phdr->p_filesz, 0x00, phdr->p_memsz - phdr->p_filesz); } return 0; } static Elf_Shdr *elf_find_segment(phys_addr_t elf_addr, const char *seg_name) { int i; Elf_Shdr *shdr; Elf_Ehdr *ehdr; const char *name_table; const uint8_t *elf_data = (void *)elf_addr; ehdr = (Elf_Ehdr *)elf_data; shdr = (Elf_Shdr *)(elf_data + ehdr->e_shoff); name_table = (const char *)(elf_data + shdr[ehdr->e_shstrndx].sh_offset); for (i = 0; i < ehdr->e_shnum; i++, shdr++) { if (strcmp(name_table + shdr->sh_name, seg_name)) continue; return shdr; } return NULL; } void *elf_find_segment_offset(phys_addr_t elf_addr, const char *seg_name) { Elf_Shdr *shdr; shdr = elf_find_segment(elf_addr, seg_name); if (!shdr) return NULL; return (void *)((phys_addr_t)(elf_addr + shdr->sh_offset)); } void *elf_find_segment_addr(phys_addr_t elf_addr, const char *seg_name) { Elf_Shdr *shdr; shdr = elf_find_segment(elf_addr, seg_name); if (!shdr) return NULL; return (void *)((phys_addr_t)shdr->sh_addr); } #if defined(CFG_RISCV_E907) || defined(CFG_RISCV_E906) || defined(CFG_RISCV_C906) void boot_riscv(phys_addr_t base, unsigned long fdt_addr) { #if defined(CFG_RISCV_E907) void boot_e907(phys_addr_t base, unsigned long fdt_addr); boot_e907(base, fdt_addr); #elif defined(CFG_RISCV_E906) void boot_e906(phys_addr_t base, unsigned long fdt_addr); boot_e906(base, fdt_addr); #elif defined(CFG_RISCV_C906) void boot_c906(phys_addr_t base, unsigned long fdt_addr); boot_c906(base, fdt_addr); #endif } #endif