Lines Matching +full:segment +full:- +full:0
1 // SPDX-License-Identifier: GPL-2.0-only
7 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
27 if (fw->size < sizeof(*ehdr)) in mdt_header_valid()
30 ehdr = (struct elf32_hdr *)fw->data; in mdt_header_valid()
32 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) in mdt_header_valid()
35 if (ehdr->e_phentsize != sizeof(struct elf32_phdr)) in mdt_header_valid()
38 phend = size_add(size_mul(sizeof(struct elf32_phdr), ehdr->e_phnum), ehdr->e_phoff); in mdt_header_valid()
39 if (phend > fw->size) in mdt_header_valid()
42 if (ehdr->e_shentsize || ehdr->e_shnum) { in mdt_header_valid()
43 if (ehdr->e_shentsize != sizeof(struct elf32_shdr)) in mdt_header_valid()
46 shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff); in mdt_header_valid()
47 if (shend > fw->size) in mdt_header_valid()
56 if (phdr->p_type != PT_LOAD) in mdt_phdr_loadable()
59 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) in mdt_phdr_loadable()
62 if (!phdr->p_memsz) in mdt_phdr_loadable()
69 unsigned int segment, const char *fw_name, in mdt_load_split_segment() argument
72 const struct elf32_phdr *phdr = &phdrs[segment]; in mdt_load_split_segment()
77 return -EINVAL; in mdt_load_split_segment()
81 return -ENOMEM; in mdt_load_split_segment()
83 sprintf(seg_name + strlen(fw_name) - 3, "b%02d", segment); in mdt_load_split_segment()
85 ptr, phdr->p_filesz); in mdt_load_split_segment()
91 if (seg_fw->size != phdr->p_filesz) { in mdt_load_split_segment()
93 "failed to load segment %d from truncated file %s\n", in mdt_load_split_segment()
94 segment, seg_name); in mdt_load_split_segment()
95 ret = -EINVAL; in mdt_load_split_segment()
104 * qcom_mdt_get_size() - acquire size of the memory region needed to load mdt
107 * Returns size of the loaded firmware blob, or -EINVAL on failure.
115 phys_addr_t max_addr = 0; in qcom_mdt_get_size()
119 return -EINVAL; in qcom_mdt_get_size()
121 ehdr = (struct elf32_hdr *)fw->data; in qcom_mdt_get_size()
122 phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); in qcom_mdt_get_size()
124 for (i = 0; i < ehdr->e_phnum; i++) { in qcom_mdt_get_size()
130 if (phdr->p_paddr < min_addr) in qcom_mdt_get_size()
131 min_addr = phdr->p_paddr; in qcom_mdt_get_size()
133 if (phdr->p_paddr + phdr->p_memsz > max_addr) in qcom_mdt_get_size()
134 max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K); in qcom_mdt_get_size()
137 return min_addr < max_addr ? max_addr - min_addr : -EINVAL; in qcom_mdt_get_size()
142 * qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
145 * @fw_name: name of the firmware, for construction of segment file names
149 * expects an ELF header directly followed by the segment of hashes, with no
165 unsigned int hash_segment = 0; in qcom_mdt_read_metadata()
174 return ERR_PTR(-EINVAL); in qcom_mdt_read_metadata()
176 ehdr = (struct elf32_hdr *)fw->data; in qcom_mdt_read_metadata()
177 phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); in qcom_mdt_read_metadata()
179 if (ehdr->e_phnum < 2) in qcom_mdt_read_metadata()
180 return ERR_PTR(-EINVAL); in qcom_mdt_read_metadata()
182 if (phdrs[0].p_type == PT_LOAD) in qcom_mdt_read_metadata()
183 return ERR_PTR(-EINVAL); in qcom_mdt_read_metadata()
185 for (i = 1; i < ehdr->e_phnum; i++) { in qcom_mdt_read_metadata()
193 dev_err(dev, "no hash segment found in %s\n", fw_name); in qcom_mdt_read_metadata()
194 return ERR_PTR(-EINVAL); in qcom_mdt_read_metadata()
197 ehdr_size = phdrs[0].p_filesz; in qcom_mdt_read_metadata()
202 return ERR_PTR(-ENOMEM); in qcom_mdt_read_metadata()
205 memcpy(data, fw->data, ehdr_size); in qcom_mdt_read_metadata()
207 if (ehdr_size + hash_size == fw->size) { in qcom_mdt_read_metadata()
209 hash_offset = phdrs[0].p_filesz; in qcom_mdt_read_metadata()
210 memcpy(data + ehdr_size, fw->data + hash_offset, hash_size); in qcom_mdt_read_metadata()
211 } else if (phdrs[hash_segment].p_offset + hash_size <= fw->size) { in qcom_mdt_read_metadata()
212 /* Hash is in its own segment, but within the loaded file */ in qcom_mdt_read_metadata()
214 memcpy(data + ehdr_size, fw->data + hash_offset, hash_size); in qcom_mdt_read_metadata()
216 /* Hash is in its own segment, beyond the loaded file */ in qcom_mdt_read_metadata()
231 * qcom_mdt_pas_init() - initialize PAS region for firmware loading
234 * @fw_name: name of the firmware, for construction of segment file names
239 * Returns 0 on success, negative errno otherwise.
249 phys_addr_t max_addr = 0; in qcom_mdt_pas_init()
257 return -EINVAL; in qcom_mdt_pas_init()
259 ehdr = (struct elf32_hdr *)fw->data; in qcom_mdt_pas_init()
260 phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); in qcom_mdt_pas_init()
262 for (i = 0; i < ehdr->e_phnum; i++) { in qcom_mdt_pas_init()
268 if (phdr->p_flags & QCOM_MDT_RELOCATABLE) in qcom_mdt_pas_init()
271 if (phdr->p_paddr < min_addr) in qcom_mdt_pas_init()
272 min_addr = phdr->p_paddr; in qcom_mdt_pas_init()
274 if (phdr->p_paddr + phdr->p_memsz > max_addr) in qcom_mdt_pas_init()
275 max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K); in qcom_mdt_pas_init()
294 ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); in qcom_mdt_pas_init()
314 ehdr = (struct elf32_hdr *)fw->data; in qcom_mdt_bins_are_split()
315 phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); in qcom_mdt_bins_are_split()
317 for (i = 0; i < ehdr->e_phnum; i++) { in qcom_mdt_bins_are_split()
320 * zero-sized segments at the end. Ignore these, as they should in qcom_mdt_bins_are_split()
328 if (seg_start > fw->size || seg_end > fw->size) in qcom_mdt_bins_are_split()
349 int ret = 0; in __qcom_mdt_load()
353 return -EINVAL; in __qcom_mdt_load()
356 return -EINVAL; in __qcom_mdt_load()
359 ehdr = (struct elf32_hdr *)fw->data; in __qcom_mdt_load()
360 phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff); in __qcom_mdt_load()
362 for (i = 0; i < ehdr->e_phnum; i++) { in __qcom_mdt_load()
368 if (phdr->p_flags & QCOM_MDT_RELOCATABLE) in __qcom_mdt_load()
371 if (phdr->p_paddr < min_addr) in __qcom_mdt_load()
372 min_addr = phdr->p_paddr; in __qcom_mdt_load()
377 * The image is relocatable, so offset each segment based on in __qcom_mdt_load()
378 * the lowest segment address. in __qcom_mdt_load()
383 * Image is not relocatable, so offset each segment based on in __qcom_mdt_load()
389 for (i = 0; i < ehdr->e_phnum; i++) { in __qcom_mdt_load()
395 offset = phdr->p_paddr - mem_reloc; in __qcom_mdt_load()
396 if (offset < 0 || offset + phdr->p_memsz > mem_size) { in __qcom_mdt_load()
397 dev_err(dev, "segment outside memory range\n"); in __qcom_mdt_load()
398 ret = -EINVAL; in __qcom_mdt_load()
402 if (phdr->p_filesz > phdr->p_memsz) { in __qcom_mdt_load()
404 "refusing to load segment %d with p_filesz > p_memsz\n", in __qcom_mdt_load()
406 ret = -EINVAL; in __qcom_mdt_load()
412 if (phdr->p_filesz && !is_split) { in __qcom_mdt_load()
413 /* Firmware is large enough to be non-split */ in __qcom_mdt_load()
414 if (phdr->p_offset + phdr->p_filesz > fw->size) { in __qcom_mdt_load()
415 dev_err(dev, "file %s segment %d would be truncated\n", in __qcom_mdt_load()
417 ret = -EINVAL; in __qcom_mdt_load()
421 memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz); in __qcom_mdt_load()
422 } else if (phdr->p_filesz) { in __qcom_mdt_load()
423 /* Firmware not large enough, load split-out segments */ in __qcom_mdt_load()
429 if (phdr->p_memsz > phdr->p_filesz) in __qcom_mdt_load()
430 memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); in __qcom_mdt_load()
440 * qcom_mdt_load() - load the firmware which header is loaded as fw
443 * @firmware: name of the firmware, for construction of segment file names
450 * Returns 0 on success, negative errno otherwise.
469 * qcom_mdt_load_no_init() - load the firmware which header is loaded as fw
472 * @firmware: name of the firmware, for construction of segment file names
478 * Returns 0 on success, negative errno otherwise.