diff --git a/src/bif.c b/src/bif.c index f3e0615..e26cfd9 100644 --- a/src/bif.c +++ b/src/bif.c @@ -332,6 +332,7 @@ static error bif_parse_file(lexer_t *lex, bif_cfg_t *cfg, bif_node_t *node) { node->load = 0; node->offset = 0; node->bootloader = 0; + node->elf_use_ph = 0; node->fsbl_config = 0; node->pmufw_image = 0; node->exception_level = BOOTROM_PART_ATTR_EXC_LVL_EL0; @@ -462,6 +463,11 @@ error bif_node_set_attr( return SUCCESS; } + if (strcmp(attr_name, "elf_use_ph") == 0) { + node->elf_use_ph = 0xFF; + return SUCCESS; + } + if (strcmp(attr_name, "partition_owner") == 0) { if (!value) { perrorf(lex, "the \"%s\" attribute requires an argument\n", attr_name); diff --git a/src/bif.h b/src/bif.h index f76b13e..cf73670 100644 --- a/src/bif.h +++ b/src/bif.h @@ -40,6 +40,7 @@ typedef struct bif_node_t { uint32_t load; uint32_t offset; uint32_t partition_owner; + uint8_t elf_use_ph; /* boolean */ /* supported zynqmp attributes */ uint8_t fsbl_config; /* boolean */ diff --git a/src/bootrom.c b/src/bootrom.c index 4b6ee25..af90570 100644 --- a/src/bootrom.c +++ b/src/bootrom.c @@ -187,7 +187,8 @@ error append_file_to_image(uint32_t *addr, img_size, &elf_nbits, &elf_load, - &elf_entry); + &elf_entry, + node.elf_use_ph); if (err) { errorf("ELF file reading failed\n"); @@ -372,7 +373,8 @@ error create_boot_image(uint32_t *img_ptr, &pmufw_img_size, &pmufw_img_nbits, &pmufw_img_load, - &pmufw_img_entry); + &pmufw_img_entry, + bif_cfg->nodes[i].elf_use_ph); if (err) { errorf("failed to parse ELF file: %s\n", bif_cfg->nodes[i].fname); return ERROR_BOOTROM_ELF; diff --git a/src/file/elf.c b/src/file/elf.c index 410fed6..00ad58c 100644 --- a/src/file/elf.c +++ b/src/file/elf.c @@ -34,11 +34,73 @@ #include #include +static error elf_create_image_from_ph(Elf *elf, uint32_t start_addr, uint8_t *out_buf) { + size_t n_phdrs; + + if(elf_getphdrnum(elf, &n_phdrs) != 0) { + printf("elf_getphdrnum failed\n"); + return ERROR_BOOTROM_ELF; + } + size_t file_size; + uint8_t *raw_data = elf_rawfile(elf, &file_size); + if (raw_data == NULL) { + return ERROR_BOOTROM_ELF; + } + for (size_t i = 0; i < n_phdrs; ++i) { + GElf_Phdr phdr; + if (gelf_getphdr(elf, i, &phdr) == NULL) { + printf("gelf_getphdr returned no address\n"); + continue; + } + if (phdr.p_type == PT_LOAD) { + if (phdr.p_offset + phdr.p_filesz > file_size) { + return ERROR_BOOTROM_ELF; + } + if (phdr.p_filesz > 0) { + uint8_t *segment_data = raw_data + phdr.p_offset; + size_t segment_size = phdr.p_filesz; + + memcpy(out_buf + phdr.p_paddr - start_addr, + segment_data, + segment_size); + } + } + } + return SUCCESS; +} + static bool elf_is_loadable_section(const GElf_Shdr *elf_shdr) { return elf_shdr->sh_type != SHT_NOBITS && (elf_shdr->sh_flags & SHF_ALLOC) && elf_shdr->sh_size != 0; } +static error elf_get_startaddr_endaddr_from_ph(Elf *elf, uint32_t *start_addr, uint32_t *end_addr) { + size_t n_phdrs; + *start_addr = -1; + *end_addr = 0; + + if (elf_getphdrnum(elf, &n_phdrs) != 0) { + return ERROR_BOOTROM_ELF; + } + + for (size_t i = 0; i < n_phdrs; ++i) { + GElf_Phdr phdr; + if (gelf_getphdr(elf, i, &phdr) == NULL) { + continue; + } + if (phdr.p_type == PT_LOAD) { + if (*start_addr > phdr.p_paddr) { + *start_addr = phdr.p_paddr; + } + + if (phdr.p_paddr + phdr.p_filesz > *end_addr) { + *end_addr = phdr.p_paddr + phdr.p_filesz; + } + } + } + return SUCCESS; +} + static error elf_get_startaddr_endaddr(Elf *elf, uint32_t *start_addr, uint32_t *end_addr) { Elf_Scn *elf_scn = NULL; GElf_Shdr elf_shdr; @@ -95,7 +157,8 @@ error elf_append(void *addr, uint32_t *img_size, uint8_t *elf_nbits, uint32_t *elf_load, - uint32_t *elf_entry) { + uint32_t *elf_entry, + uint8_t elf_use_ph) { error err; int fd_elf; Elf *elf; @@ -124,10 +187,18 @@ error elf_append(void *addr, return ERROR_BOOTROM_ELF; } - if ((err = elf_get_startaddr_endaddr(elf, &start_addr, &end_addr))) { - elf_end(elf); - close(fd_elf); - return err; + if (elf_use_ph) { + if ((err = elf_get_startaddr_endaddr_from_ph(elf, &start_addr, &end_addr))) { + elf_end(elf); + close(fd_elf); + return err; + } + } else { + if ((err = elf_get_startaddr_endaddr(elf, &start_addr, &end_addr))) { + elf_end(elf); + close(fd_elf); + return err; + } } if (end_addr - start_addr > img_max_size) { @@ -138,10 +209,18 @@ error elf_append(void *addr, memset(addr, 0, end_addr - start_addr); - if ((err = elf_create_image(elf, start_addr, addr))) { - elf_end(elf); - close(fd_elf); - return err; + if (elf_use_ph) { + if ((err = elf_create_image_from_ph(elf, start_addr, addr))) { + elf_end(elf); + close(fd_elf); + return err; + } + } else { + if ((err = elf_create_image(elf, start_addr, addr))) { + elf_end(elf); + close(fd_elf); + return err; + } } if (gelf_getehdr(elf, &elf_ehdr) != &elf_ehdr) { @@ -159,4 +238,4 @@ error elf_append(void *addr, close(fd_elf); return SUCCESS; -} +} \ No newline at end of file diff --git a/src/file/elf.h b/src/file/elf.h index 062616e..88d27ff 100644 --- a/src/file/elf.h +++ b/src/file/elf.h @@ -9,6 +9,7 @@ error elf_append(void *addr, uint32_t *img_size, uint8_t *elf_nbits, uint32_t *elf_load, - uint32_t *elf_entry); + uint32_t *elf_entry, + uint8_t elf_use_ph); #endif