1 // SPDX-License-Identifier: GPL-2.0-only OR MIT 2 /* Copyright (c) 2024 Imagination Technologies Ltd. */ 3 4 #include "pvr_device.h" 5 #include "pvr_fw.h" 6 7 #include <drm/drm_device.h> 8 #include <drm/drm_print.h> 9 10 #include <linux/elf.h> 11 #include <linux/string.h> 12 #include <linux/types.h> 13 14 /** 15 * pvr_fw_process_elf_command_stream() - Process ELF firmware image and populate 16 * firmware sections 17 * @pvr_dev: Device pointer. 18 * @fw: Pointer to firmware image. 19 * @fw_code_ptr: Pointer to FW code section. 20 * @fw_data_ptr: Pointer to FW data section. 21 * @fw_core_code_ptr: Pointer to FW coremem code section. 22 * @fw_core_data_ptr: Pointer to FW coremem data section. 23 * 24 * Returns : 25 * * 0 on success, or 26 * * -EINVAL on any error in ELF command stream. 27 */ 28 int 29 pvr_fw_process_elf_command_stream(struct pvr_device *pvr_dev, const u8 *fw, 30 u8 *fw_code_ptr, u8 *fw_data_ptr, 31 u8 *fw_core_code_ptr, u8 *fw_core_data_ptr) 32 { 33 struct elf32_hdr *header = (struct elf32_hdr *)fw; 34 struct elf32_phdr *program_header = (struct elf32_phdr *)(fw + header->e_phoff); 35 struct drm_device *drm_dev = from_pvr_device(pvr_dev); 36 int err; 37 38 for (u32 entry = 0; entry < header->e_phnum; entry++, program_header++) { 39 void *write_addr; 40 41 /* Only consider loadable entries in the ELF segment table */ 42 if (program_header->p_type != PT_LOAD) 43 continue; 44 45 err = pvr_fw_find_mmu_segment(pvr_dev, program_header->p_vaddr, 46 program_header->p_memsz, fw_code_ptr, fw_data_ptr, 47 fw_core_code_ptr, fw_core_data_ptr, &write_addr); 48 if (err) { 49 drm_err(drm_dev, 50 "Addr 0x%x (size: %d) not found in any firmware segment", 51 program_header->p_vaddr, program_header->p_memsz); 52 return err; 53 } 54 55 /* Write to FW allocation only if available */ 56 if (write_addr) { 57 memcpy(write_addr, fw + program_header->p_offset, 58 program_header->p_filesz); 59 60 memset((u8 *)write_addr + program_header->p_filesz, 0, 61 program_header->p_memsz - program_header->p_filesz); 62 } 63 } 64 65 return 0; 66 } 67