/** * qcom_mdt_read_metadata() - read header and metadata from mdt or mbn * @fw: firmware of mdt header or mbn * @data_len: length of the read metadata blob * @fw_name: name of the firmware, for construction of segment file names * @dev: device handle to associate resources with * * The mechanism that performs the authentication of the loading firmware * expects an ELF header directly followed by the segment of hashes, with no * padding inbetween. This function allocates a chunk of memory for this pair * and copy the two pieces into the buffer. * * In the case of split firmware the hash is found directly following the ELF * header, rather than at p_offset described by the second program header. * * The caller is responsible to free (kfree()) the returned pointer. * * Return: pointer to data, or ERR_PTR()
*/ void *qcom_mdt_read_metadata(conststruct firmware *fw, size_t *data_len, constchar *fw_name, struct device *dev)
{ conststruct elf32_phdr *phdrs; conststruct elf32_hdr *ehdr; unsignedint hash_segment = 0;
size_t hash_offset;
size_t hash_size;
size_t ehdr_size; unsignedint i;
ssize_t ret; void *data;
if (!mdt_header_valid(fw)) return ERR_PTR(-EINVAL);
if (ehdr_size + hash_size == fw->size) { /* Firmware is split and hash is packed following the ELF header */
hash_offset = phdrs[0].p_filesz;
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
} elseif (phdrs[hash_segment].p_offset + hash_size <= fw->size) { /* Hash is in its own segment, but within the loaded file */
hash_offset = phdrs[hash_segment].p_offset;
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
} else { /* Hash is in its own segment, beyond the loaded file */
ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev); if (ret) {
kfree(data); return ERR_PTR(ret);
}
}
/** * qcom_mdt_pas_init() - initialize PAS region for firmware loading * @dev: device handle to associate resources with * @fw: firmware object for the mdt file * @fw_name: name of the firmware, for construction of segment file names * @pas_id: PAS identifier * @mem_phys: physical address of allocated memory region * @ctx: PAS metadata context, to be released by caller * * Returns 0 on success, negative errno otherwise.
*/ int qcom_mdt_pas_init(struct device *dev, conststruct firmware *fw, constchar *fw_name, int pas_id, phys_addr_t mem_phys, struct qcom_scm_pas_metadata *ctx)
{ conststruct elf32_phdr *phdrs; conststruct elf32_phdr *phdr; conststruct elf32_hdr *ehdr;
phys_addr_t min_addr = PHYS_ADDR_MAX;
phys_addr_t max_addr = 0; bool relocate = false;
size_t metadata_len; void *metadata; int ret; int i;
if (relocate) {
ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); if (ret) { /* Unable to set up relocation */
dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name); goto out;
}
}
for (i = 0; i < ehdr->e_phnum; i++) { /* * The size of the MDT file is not padded to include any * zero-sized segments at the end. Ignore these, as they should * not affect the decision about image being split or not.
*/ if (!phdrs[i].p_filesz) continue;
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
if (!mdt_phdr_loadable(phdr)) continue;
if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
relocate = true;
if (phdr->p_paddr < min_addr)
min_addr = phdr->p_paddr;
}
if (relocate) { /* * The image is relocatable, so offset each segment based on * the lowest segment address.
*/
mem_reloc = min_addr;
} else { /* * Image is not relocatable, so offset each segment based on * the allocated physical chunk of memory.
*/
mem_reloc = mem_phys;
}
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
if (phdr->p_filesz > phdr->p_memsz) {
dev_err(dev, "refusing to load segment %d with p_filesz > p_memsz\n",
i);
ret = -EINVAL; break;
}
ptr = mem_region + offset;
if (phdr->p_filesz && !is_split) { /* Firmware is large enough to be non-split */ if (phdr->p_offset + phdr->p_filesz > fw->size) {
dev_err(dev, "file %s segment %d would be truncated\n",
fw_name, i);
ret = -EINVAL; break;
}
memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
} elseif (phdr->p_filesz) { /* Firmware not large enough, load split-out segments */
ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev); if (ret) break;
}
/** * qcom_mdt_load() - load the firmware which header is loaded as fw * @dev: device handle to associate resources with * @fw: firmware object for the mdt file * @firmware: name of the firmware, for construction of segment file names * @pas_id: PAS identifier * @mem_region: allocated memory region to load firmware into * @mem_phys: physical address of allocated memory region * @mem_size: size of the allocated memory region * @reloc_base: adjusted physical address after relocation * * Returns 0 on success, negative errno otherwise.
*/ int qcom_mdt_load(struct device *dev, conststruct firmware *fw, constchar *firmware, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base)
{ int ret;
ret = qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL); if (ret) return ret;
/** * qcom_mdt_load_no_init() - load the firmware which header is loaded as fw * @dev: device handle to associate resources with * @fw: firmware object for the mdt file * @firmware: name of the firmware, for construction of segment file names * @pas_id: PAS identifier * @mem_region: allocated memory region to load firmware into * @mem_phys: physical address of allocated memory region * @mem_size: size of the allocated memory region * @reloc_base: adjusted physical address after relocation * * Returns 0 on success, negative errno otherwise.
*/ int qcom_mdt_load_no_init(struct device *dev, conststruct firmware *fw, constchar *firmware, int pas_id, void *mem_region, phys_addr_t mem_phys,
size_t mem_size, phys_addr_t *reloc_base)
{ return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
mem_size, reloc_base, false);
}
EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init);
MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format");
MODULE_LICENSE("GPL v2");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.