diff --git a/arch/arm64/configs/vendor/pineapple_GKI.config b/arch/arm64/configs/vendor/pineapple_GKI.config index 2107a854429c..9ed30ab42eed 100644 --- a/arch/arm64/configs/vendor/pineapple_GKI.config +++ b/arch/arm64/configs/vendor/pineapple_GKI.config @@ -91,6 +91,7 @@ CONFIG_QCOM_Q6V5_COMMON=m CONFIG_QCOM_Q6V5_PAS=m # CONFIG_QCOM_Q6V5_WCSS is not set CONFIG_QCOM_QMI_HELPERS=m +CONFIG_QCOM_RAMDUMP=m CONFIG_QCOM_RPMH=m CONFIG_QCOM_RPROC_COMMON=m CONFIG_QCOM_RUN_QUEUE_STATS=m diff --git a/drivers/soc/qcom/qcom_ramdump.c b/drivers/soc/qcom/qcom_ramdump.c index 924d4f292d24..6379f3884412 100644 --- a/drivers/soc/qcom/qcom_ramdump.c +++ b/drivers/soc/qcom/qcom_ramdump.c @@ -18,6 +18,31 @@ #define RAMDUMP_TIMEOUT 120000 +#define SIZEOF_ELF_STRUCT(__xhdr) \ +static inline size_t sizeof_elf_##__xhdr(unsigned char class) \ +{ \ + if (class == ELFCLASS32) \ + return sizeof(struct elf32_##__xhdr); \ + else \ + return sizeof(struct elf64_##__xhdr); \ +} + +SIZEOF_ELF_STRUCT(phdr) +SIZEOF_ELF_STRUCT(hdr) + +#define set_xhdr_property(__xhdr, arg, class, member, value) \ +do { \ + if (class == ELFCLASS32) \ + ((struct elf32_##__xhdr *)arg)->member = value; \ + else \ + ((struct elf64_##__xhdr *)arg)->member = value; \ +} while (0) + +#define set_ehdr_property(arg, class, member, value) \ + set_xhdr_property(hdr, arg, class, member, value) +#define set_phdr_property(arg, class, member, value) \ + set_xhdr_property(phdr, arg, class, member, value) + struct qcom_ramdump_desc { void *data; struct completion dump_done; @@ -45,24 +70,21 @@ static void qcom_devcd_freev(void *data) struct qcom_ramdump_desc *desc = data; vfree(desc->data); - complete(&desc->dump_done); + complete_all(&desc->dump_done); } static int qcom_devcd_dump(struct device *dev, void *data, size_t datalen, gfp_t gfp) { struct qcom_ramdump_desc desc; - int ret; desc.data = data; init_completion(&desc.dump_done); dev_coredumpm(dev, NULL, &desc, datalen, gfp, qcom_devcd_readv, qcom_devcd_freev); - ret = wait_for_completion_timeout(&desc.dump_done, msecs_to_jiffies(RAMDUMP_TIMEOUT)); - if (!ret) - dev_err(dev, "ramdump collection timed out\n"); + wait_for_completion(&desc.dump_done); - return ret ? 0 : -ETIMEDOUT; + return !completion_done(&desc.dump_done); } int qcom_dump(struct list_head *segs, struct device *dev) @@ -106,11 +128,23 @@ int qcom_dump(struct list_head *segs, struct device *dev) } EXPORT_SYMBOL(qcom_dump); -int qcom_elf_dump(struct list_head *segs, struct device *dev) +/* Since the elf32 and elf64 identification is identical + * apart from the class we use elf32 by default. + */ +static void init_elf_identification(struct elf32_hdr *ehdr, unsigned char class) +{ + memcpy(ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = class; + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE; +} + +int qcom_elf_dump(struct list_head *segs, struct device *dev, unsigned char class) { struct qcom_dump_segment *segment; - struct elf32_phdr *phdr; - struct elf32_hdr *ehdr; + void *phdr; + void *ehdr; size_t data_size; size_t offset; int phnum = 0; @@ -121,10 +155,9 @@ int qcom_elf_dump(struct list_head *segs, struct device *dev) if (!segs || list_empty(segs)) return -EINVAL; - data_size = sizeof(*ehdr); + data_size = sizeof_elf_hdr(class); list_for_each_entry(segment, segs, node) { - data_size += sizeof(*phdr) + segment->size; - + data_size += sizeof_elf_phdr(class) + segment->size; phnum++; } @@ -135,33 +168,28 @@ int qcom_elf_dump(struct list_head *segs, struct device *dev) pr_debug("Creating elf with size %d\n", data_size); ehdr = data; - memset(ehdr, 0, sizeof(*ehdr)); - memcpy(ehdr->e_ident, ELFMAG, SELFMAG); - ehdr->e_ident[EI_CLASS] = ELFCLASS32; - ehdr->e_ident[EI_DATA] = ELFDATA2LSB; - ehdr->e_ident[EI_VERSION] = EV_CURRENT; - ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE; - ehdr->e_type = ET_CORE; - ehdr->e_machine = EM_NONE; - ehdr->e_version = EV_CURRENT; - ehdr->e_entry = 0; - ehdr->e_phoff = sizeof(*ehdr); - ehdr->e_ehsize = sizeof(*ehdr); - ehdr->e_phentsize = sizeof(*phdr); - ehdr->e_phnum = phnum; + memset(ehdr, 0, sizeof_elf_hdr(class)); + init_elf_identification(ehdr, class); + set_ehdr_property(ehdr, class, e_type, ET_CORE); + set_ehdr_property(ehdr, class, e_machine, EM_NONE); + set_ehdr_property(ehdr, class, e_version, EV_CURRENT); + set_ehdr_property(ehdr, class, e_phoff, sizeof_elf_hdr(class)); + set_ehdr_property(ehdr, class, e_ehsize, sizeof_elf_hdr(class)); + set_ehdr_property(ehdr, class, e_phentsize, sizeof_elf_phdr(class)); + set_ehdr_property(ehdr, class, e_phnum, phnum); - phdr = data + ehdr->e_phoff; - offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum; + phdr = data + sizeof_elf_hdr(class); + offset = sizeof_elf_hdr(class) + sizeof_elf_phdr(class) * phnum; list_for_each_entry(segment, segs, node) { - memset(phdr, 0, sizeof(*phdr)); - phdr->p_type = PT_LOAD; - phdr->p_offset = offset; - phdr->p_vaddr = segment->da; - phdr->p_paddr = segment->da; - phdr->p_filesz = segment->size; - phdr->p_memsz = segment->size; - phdr->p_flags = PF_R | PF_W | PF_X; - phdr->p_align = 0; + memset(phdr, 0, sizeof_elf_phdr(class)); + set_phdr_property(phdr, class, p_type, PT_LOAD); + set_phdr_property(phdr, class, p_offset, offset); + set_phdr_property(phdr, class, p_vaddr, segment->da); + set_phdr_property(phdr, class, p_paddr, segment->da); + set_phdr_property(phdr, class, p_filesz, segment->size); + set_phdr_property(phdr, class, p_memsz, segment->size); + set_phdr_property(phdr, class, p_flags, PF_R | PF_W | PF_X); + set_phdr_property(phdr, class, p_align, 0); if (segment->va) memcpy(data + offset, segment->va, segment->size); @@ -177,8 +205,8 @@ int qcom_elf_dump(struct list_head *segs, struct device *dev) segment->size); } - offset += phdr->p_filesz; - phdr++; + offset += segment->size; + phdr += sizeof_elf_phdr(class); } return qcom_devcd_dump(dev, data, data_size, GFP_KERNEL); @@ -219,7 +247,7 @@ int qcom_fw_elf_dump(struct firmware *fw, struct device *dev) list_add_tail(&segment->node, &head); } - qcom_elf_dump(&head, dev); + qcom_elf_dump(&head, dev, ELFCLASS32); return 0; } EXPORT_SYMBOL(qcom_fw_elf_dump); diff --git a/include/soc/qcom/qcom_ramdump.h b/include/soc/qcom/qcom_ramdump.h index f2f508512f63..7a01228be771 100644 --- a/include/soc/qcom/qcom_ramdump.h +++ b/include/soc/qcom/qcom_ramdump.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _QCOM_RAMDUMP_HEADER @@ -18,12 +19,12 @@ struct qcom_dump_segment { }; #if IS_ENABLED(CONFIG_QCOM_RAMDUMP) -extern int qcom_elf_dump(struct list_head *segs, struct device *dev); +extern int qcom_elf_dump(struct list_head *segs, struct device *dev, unsigned char class); extern int qcom_dump(struct list_head *head, struct device *dev); extern int qcom_fw_elf_dump(struct firmware *fw, struct device *dev); extern bool dump_enabled(void); #else -static inline int qcom_elf_dump(struct list_head *segs, struct device *dev) +static inline int qcom_elf_dump(struct list_head *segs, struct device *dev, unsigned char class) { return -ENODEV; }