// SPDX-License-Identifier: GPL-2.0-only /* * Remote Processor Framework Elf loader * * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. * * Ohad Ben-Cohen * Brian Swetland * Mark Grosen * Fernando Guzman Lugo * Suman Anna * Robert Tivy * Armando Uribe De Leon * Sjur Brændeland */ #include #include #include #include "remoteproc_internal.h" int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) { struct device_d *dev = &rproc->dev; struct elf32_hdr *ehdr; struct elf32_phdr *phdr; int i, ret = 0; const u8 *elf_data = fw->data; ehdr = (struct elf32_hdr *)elf_data; phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff); /* go through the available ELF segments */ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { u32 da = phdr->p_paddr; u32 memsz = phdr->p_memsz; u32 filesz = phdr->p_filesz; u32 offset = phdr->p_offset; void *ptr; if (phdr->p_type != PT_LOAD) continue; dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n", phdr->p_type, da, memsz, filesz); if (filesz > memsz) { dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n", filesz, memsz); ret = -EINVAL; break; } if (offset + filesz > fw->size) { dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n", offset + filesz, fw->size); ret = -EINVAL; break; } /* grab the kernel address for this device address */ ptr = rproc_da_to_va(rproc, da, memsz); if (!ptr) { dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz); ret = -EINVAL; break; } /* put the segment where the remote processor expects it */ if (phdr->p_filesz) memcpy(ptr, elf_data + phdr->p_offset, filesz); /* * Zero out remaining memory for this segment. * * This isn't strictly required since dma_alloc_coherent already * did this for us. albeit harmless, we may consider removing * this. */ if (memsz > filesz) memset(ptr + filesz, 0, memsz - filesz); } return ret; } EXPORT_SYMBOL(rproc_elf_load_segments);