162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Remote processor elf helpers defines 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 Kalray, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef REMOTEPROC_ELF_LOADER_H 962306a36Sopenharmony_ci#define REMOTEPROC_ELF_LOADER_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/elf.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/** 1562306a36Sopenharmony_ci * fw_elf_get_class - Get elf class 1662306a36Sopenharmony_ci * @fw: the ELF firmware image 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Note that we use elf32_hdr to access the class since the start of the 1962306a36Sopenharmony_ci * struct is the same for both elf class 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * Return: elf class of the firmware 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cistatic inline u8 fw_elf_get_class(const struct firmware *fw) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci return ehdr->e_ident[EI_CLASS]; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic inline void elf_hdr_init_ident(struct elf32_hdr *hdr, u8 class) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci memcpy(hdr->e_ident, ELFMAG, SELFMAG); 3362306a36Sopenharmony_ci hdr->e_ident[EI_CLASS] = class; 3462306a36Sopenharmony_ci hdr->e_ident[EI_DATA] = ELFDATA2LSB; 3562306a36Sopenharmony_ci hdr->e_ident[EI_VERSION] = EV_CURRENT; 3662306a36Sopenharmony_ci hdr->e_ident[EI_OSABI] = ELFOSABI_NONE; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Generate getter and setter for a specific elf struct/field */ 4062306a36Sopenharmony_ci#define ELF_GEN_FIELD_GET_SET(__s, __field, __type) \ 4162306a36Sopenharmony_cistatic inline __type elf_##__s##_get_##__field(u8 class, const void *arg) \ 4262306a36Sopenharmony_ci{ \ 4362306a36Sopenharmony_ci if (class == ELFCLASS32) \ 4462306a36Sopenharmony_ci return (__type) ((const struct elf32_##__s *) arg)->__field; \ 4562306a36Sopenharmony_ci else \ 4662306a36Sopenharmony_ci return (__type) ((const struct elf64_##__s *) arg)->__field; \ 4762306a36Sopenharmony_ci} \ 4862306a36Sopenharmony_cistatic inline void elf_##__s##_set_##__field(u8 class, void *arg, \ 4962306a36Sopenharmony_ci __type value) \ 5062306a36Sopenharmony_ci{ \ 5162306a36Sopenharmony_ci if (class == ELFCLASS32) \ 5262306a36Sopenharmony_ci ((struct elf32_##__s *) arg)->__field = (__type) value; \ 5362306a36Sopenharmony_ci else \ 5462306a36Sopenharmony_ci ((struct elf64_##__s *) arg)->__field = (__type) value; \ 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_entry, u64) 5862306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_phnum, u16) 5962306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_shnum, u16) 6062306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_phoff, u64) 6162306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_shoff, u64) 6262306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_shstrndx, u16) 6362306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_machine, u16) 6462306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_type, u16) 6562306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_version, u32) 6662306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_ehsize, u32) 6762306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_phentsize, u16) 6862306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(hdr, e_shentsize, u16) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(phdr, p_paddr, u64) 7162306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(phdr, p_vaddr, u64) 7262306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(phdr, p_filesz, u64) 7362306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(phdr, p_memsz, u64) 7462306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(phdr, p_type, u32) 7562306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(phdr, p_offset, u64) 7662306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(phdr, p_flags, u32) 7762306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(phdr, p_align, u64) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(shdr, sh_type, u32) 8062306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(shdr, sh_flags, u32) 8162306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(shdr, sh_entsize, u16) 8262306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(shdr, sh_size, u64) 8362306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(shdr, sh_offset, u64) 8462306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(shdr, sh_name, u32) 8562306a36Sopenharmony_ciELF_GEN_FIELD_GET_SET(shdr, sh_addr, u64) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define ELF_STRUCT_SIZE(__s) \ 8862306a36Sopenharmony_cistatic inline unsigned long elf_size_of_##__s(u8 class) \ 8962306a36Sopenharmony_ci{ \ 9062306a36Sopenharmony_ci if (class == ELFCLASS32)\ 9162306a36Sopenharmony_ci return sizeof(struct elf32_##__s); \ 9262306a36Sopenharmony_ci else \ 9362306a36Sopenharmony_ci return sizeof(struct elf64_##__s); \ 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ciELF_STRUCT_SIZE(shdr) 9762306a36Sopenharmony_ciELF_STRUCT_SIZE(phdr) 9862306a36Sopenharmony_ciELF_STRUCT_SIZE(hdr) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic inline unsigned int elf_strtbl_add(const char *name, void *ehdr, u8 class, size_t *index) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci u16 shstrndx = elf_hdr_get_e_shstrndx(class, ehdr); 10362306a36Sopenharmony_ci void *shdr; 10462306a36Sopenharmony_ci char *strtab; 10562306a36Sopenharmony_ci size_t idx, ret; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci shdr = ehdr + elf_size_of_hdr(class) + shstrndx * elf_size_of_shdr(class); 10862306a36Sopenharmony_ci strtab = ehdr + elf_shdr_get_sh_offset(class, shdr); 10962306a36Sopenharmony_ci idx = index ? *index : 0; 11062306a36Sopenharmony_ci if (!strtab || !name) 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci ret = idx; 11462306a36Sopenharmony_ci strcpy((strtab + idx), name); 11562306a36Sopenharmony_ci idx += strlen(name) + 1; 11662306a36Sopenharmony_ci if (index) 11762306a36Sopenharmony_ci *index = idx; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return ret; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#endif /* REMOTEPROC_ELF_LOADER_H */ 123