drivers/soc/qcom/mdt_loader.c
Source file repositories/reference/linux-study-clean/drivers/soc/qcom/mdt_loader.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/soc/qcom/mdt_loader.c- Extension
.c- Size
- 13528 bytes
- Lines
- 502
- Domain
- Driver Families
- Bucket
- drivers/soc
- Inferred role
- Driver Families: exported/initcall integration point
- Status
- integration implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/cleanup.hlinux/device.hlinux/elf.hlinux/firmware.hlinux/kernel.hlinux/module.hlinux/firmware/qcom/qcom_scm.hlinux/sizes.hlinux/slab.hlinux/soc/qcom/mdt_loader.h
Detected Declarations
function Copyrightfunction mdt_phdr_loadablefunction mdt_load_split_segmentfunction qcom_mdt_get_sizefunction qcom_mdt_read_metadatafunction __qcom_mdt_pas_initfunction qcom_mdt_bins_are_splitfunction qcom_mdt_load_no_initfunction qcom_mdt_loadfunction segmentsexport qcom_mdt_get_sizeexport qcom_mdt_read_metadataexport qcom_mdt_load_no_initexport qcom_mdt_loadexport qcom_mdt_pas_load
Annotated Snippet
if ((phdrs[i].p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) {
hash_segment = i;
break;
}
}
if (!hash_segment) {
dev_err(dev, "no hash segment found in %s\n", fw_name);
return ERR_PTR(-EINVAL);
}
ehdr_size = phdrs[0].p_filesz;
hash_size = phdrs[hash_segment].p_filesz;
data = kmalloc(ehdr_size + hash_size, GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
/* Copy ELF header */
memcpy(data, fw->data, ehdr_size);
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);
} else if (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);
}
}
*data_len = ehdr_size + hash_size;
return data;
}
EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, phys_addr_t mem_phys,
struct qcom_scm_pas_context *ctx)
{
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
const struct 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 (!mdt_header_valid(fw))
return -EINVAL;
ehdr = (struct elf32_hdr *)fw->data;
phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
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 (phdr->p_paddr + phdr->p_memsz > max_addr)
max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
}
metadata = qcom_mdt_read_metadata(fw, &metadata_len, fw_name, dev);
if (IS_ERR(metadata)) {
ret = PTR_ERR(metadata);
dev_err(dev, "error %d reading firmware %s metadata\n", ret, fw_name);
goto out;
}
ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len, ctx);
kfree(metadata);
Annotation
- Immediate include surface: `linux/cleanup.h`, `linux/device.h`, `linux/elf.h`, `linux/firmware.h`, `linux/kernel.h`, `linux/module.h`, `linux/firmware/qcom/qcom_scm.h`, `linux/sizes.h`.
- Detected declarations: `function Copyright`, `function mdt_phdr_loadable`, `function mdt_load_split_segment`, `function qcom_mdt_get_size`, `function qcom_mdt_read_metadata`, `function __qcom_mdt_pas_init`, `function qcom_mdt_bins_are_split`, `function qcom_mdt_load_no_init`, `function qcom_mdt_load`, `function segments`.
- Atlas domain: Driver Families / drivers/soc.
- Implementation status: integration implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.