xref: /openbmc/linux/drivers/remoteproc/remoteproc_elf_helpers.h (revision 762f99f4f3cb41a775b5157dd761217beba65873)
173516a33SClement Leger /* SPDX-License-Identifier: GPL-2.0 */
273516a33SClement Leger /*
373516a33SClement Leger  * Remote processor elf helpers defines
473516a33SClement Leger  *
573516a33SClement Leger  * Copyright (C) 2020 Kalray, Inc.
673516a33SClement Leger  */
773516a33SClement Leger 
873516a33SClement Leger #ifndef REMOTEPROC_ELF_LOADER_H
973516a33SClement Leger #define REMOTEPROC_ELF_LOADER_H
1073516a33SClement Leger 
1173516a33SClement Leger #include <linux/elf.h>
1273516a33SClement Leger #include <linux/types.h>
1373516a33SClement Leger 
1473516a33SClement Leger /**
1573516a33SClement Leger  * fw_elf_get_class - Get elf class
1673516a33SClement Leger  * @fw: the ELF firmware image
1773516a33SClement Leger  *
18*c080128bSDong Aisheng  * Note that we use elf32_hdr to access the class since the start of the
1973516a33SClement Leger  * struct is the same for both elf class
2073516a33SClement Leger  *
2173516a33SClement Leger  * Return: elf class of the firmware
2273516a33SClement Leger  */
fw_elf_get_class(const struct firmware * fw)2373516a33SClement Leger static inline u8 fw_elf_get_class(const struct firmware *fw)
2473516a33SClement Leger {
2573516a33SClement Leger 	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
2673516a33SClement Leger 
2773516a33SClement Leger 	return ehdr->e_ident[EI_CLASS];
2873516a33SClement Leger }
2973516a33SClement Leger 
elf_hdr_init_ident(struct elf32_hdr * hdr,u8 class)3073516a33SClement Leger static inline void elf_hdr_init_ident(struct elf32_hdr *hdr, u8 class)
3173516a33SClement Leger {
3273516a33SClement Leger 	memcpy(hdr->e_ident, ELFMAG, SELFMAG);
3373516a33SClement Leger 	hdr->e_ident[EI_CLASS] = class;
3473516a33SClement Leger 	hdr->e_ident[EI_DATA] = ELFDATA2LSB;
3573516a33SClement Leger 	hdr->e_ident[EI_VERSION] = EV_CURRENT;
3673516a33SClement Leger 	hdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
3773516a33SClement Leger }
3873516a33SClement Leger 
3973516a33SClement Leger /* Generate getter and setter for a specific elf struct/field */
4073516a33SClement Leger #define ELF_GEN_FIELD_GET_SET(__s, __field, __type) \
4173516a33SClement Leger static inline __type elf_##__s##_get_##__field(u8 class, const void *arg) \
4273516a33SClement Leger { \
4373516a33SClement Leger 	if (class == ELFCLASS32) \
4473516a33SClement Leger 		return (__type) ((const struct elf32_##__s *) arg)->__field; \
4573516a33SClement Leger 	else \
4673516a33SClement Leger 		return (__type) ((const struct elf64_##__s *) arg)->__field; \
4773516a33SClement Leger } \
4873516a33SClement Leger static inline void elf_##__s##_set_##__field(u8 class, void *arg, \
4973516a33SClement Leger 					     __type value) \
5073516a33SClement Leger { \
5173516a33SClement Leger 	if (class == ELFCLASS32) \
5273516a33SClement Leger 		((struct elf32_##__s *) arg)->__field = (__type) value; \
5373516a33SClement Leger 	else \
5473516a33SClement Leger 		((struct elf64_##__s *) arg)->__field = (__type) value; \
5573516a33SClement Leger }
5673516a33SClement Leger 
ELF_GEN_FIELD_GET_SET(hdr,e_entry,u64)5773516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_entry, u64)
5873516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_phnum, u16)
5973516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_shnum, u16)
6073516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_phoff, u64)
6173516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_shoff, u64)
6273516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_shstrndx, u16)
6373516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_machine, u16)
6473516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_type, u16)
6573516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_version, u32)
6673516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_ehsize, u32)
6773516a33SClement Leger ELF_GEN_FIELD_GET_SET(hdr, e_phentsize, u16)
68abc72b64SSiddharth Gupta ELF_GEN_FIELD_GET_SET(hdr, e_shentsize, u16)
6973516a33SClement Leger 
7073516a33SClement Leger ELF_GEN_FIELD_GET_SET(phdr, p_paddr, u64)
7173516a33SClement Leger ELF_GEN_FIELD_GET_SET(phdr, p_vaddr, u64)
7273516a33SClement Leger ELF_GEN_FIELD_GET_SET(phdr, p_filesz, u64)
7373516a33SClement Leger ELF_GEN_FIELD_GET_SET(phdr, p_memsz, u64)
7473516a33SClement Leger ELF_GEN_FIELD_GET_SET(phdr, p_type, u32)
7573516a33SClement Leger ELF_GEN_FIELD_GET_SET(phdr, p_offset, u64)
7673516a33SClement Leger ELF_GEN_FIELD_GET_SET(phdr, p_flags, u32)
7773516a33SClement Leger ELF_GEN_FIELD_GET_SET(phdr, p_align, u64)
7873516a33SClement Leger 
79abc72b64SSiddharth Gupta ELF_GEN_FIELD_GET_SET(shdr, sh_type, u32)
80abc72b64SSiddharth Gupta ELF_GEN_FIELD_GET_SET(shdr, sh_flags, u32)
81abc72b64SSiddharth Gupta ELF_GEN_FIELD_GET_SET(shdr, sh_entsize, u16)
8273516a33SClement Leger ELF_GEN_FIELD_GET_SET(shdr, sh_size, u64)
8373516a33SClement Leger ELF_GEN_FIELD_GET_SET(shdr, sh_offset, u64)
8473516a33SClement Leger ELF_GEN_FIELD_GET_SET(shdr, sh_name, u32)
8573516a33SClement Leger ELF_GEN_FIELD_GET_SET(shdr, sh_addr, u64)
8673516a33SClement Leger 
8773516a33SClement Leger #define ELF_STRUCT_SIZE(__s) \
8873516a33SClement Leger static inline unsigned long elf_size_of_##__s(u8 class) \
8973516a33SClement Leger { \
9073516a33SClement Leger 	if (class == ELFCLASS32)\
9173516a33SClement Leger 		return sizeof(struct elf32_##__s); \
9273516a33SClement Leger 	else \
9373516a33SClement Leger 		return sizeof(struct elf64_##__s); \
9473516a33SClement Leger }
9573516a33SClement Leger 
9673516a33SClement Leger ELF_STRUCT_SIZE(shdr)
9773516a33SClement Leger ELF_STRUCT_SIZE(phdr)
9873516a33SClement Leger ELF_STRUCT_SIZE(hdr)
9973516a33SClement Leger 
100abc72b64SSiddharth Gupta static inline unsigned int elf_strtbl_add(const char *name, void *ehdr, u8 class, size_t *index)
101abc72b64SSiddharth Gupta {
102abc72b64SSiddharth Gupta 	u16 shstrndx = elf_hdr_get_e_shstrndx(class, ehdr);
103abc72b64SSiddharth Gupta 	void *shdr;
104abc72b64SSiddharth Gupta 	char *strtab;
105abc72b64SSiddharth Gupta 	size_t idx, ret;
106abc72b64SSiddharth Gupta 
107abc72b64SSiddharth Gupta 	shdr = ehdr + elf_size_of_hdr(class) + shstrndx * elf_size_of_shdr(class);
108abc72b64SSiddharth Gupta 	strtab = ehdr + elf_shdr_get_sh_offset(class, shdr);
109abc72b64SSiddharth Gupta 	idx = index ? *index : 0;
110abc72b64SSiddharth Gupta 	if (!strtab || !name)
111abc72b64SSiddharth Gupta 		return 0;
112abc72b64SSiddharth Gupta 
113abc72b64SSiddharth Gupta 	ret = idx;
114abc72b64SSiddharth Gupta 	strcpy((strtab + idx), name);
115abc72b64SSiddharth Gupta 	idx += strlen(name) + 1;
116abc72b64SSiddharth Gupta 	if (index)
117abc72b64SSiddharth Gupta 		*index = idx;
118abc72b64SSiddharth Gupta 
119abc72b64SSiddharth Gupta 	return ret;
120abc72b64SSiddharth Gupta }
121abc72b64SSiddharth Gupta 
12273516a33SClement Leger #endif /* REMOTEPROC_ELF_LOADER_H */
123