From ca08ac1beead443988ca00e4650af33dadf3b8b9 Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Wed, 29 Sep 2021 12:47:03 -0700 Subject: [PATCH 1/4] soc: qcom: ramdump: Remove the timeout in wait for completion Freeing a completion after setting it to complete can be racy with the thread that is waiting for completion. To avoid this race the ramdump descriptor should remain on the stack so that we only "free" the completion once wait_for_completion() returns. Change-Id: Ice02260a4f91aa6cd107eb371601d9ed910fb6cf Signed-off-by: Siddharth Gupta Signed-off-by: Vamsi Krishna Lanka --- drivers/soc/qcom/qcom_ramdump.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/qcom_ramdump.c b/drivers/soc/qcom/qcom_ramdump.c index 924d4f292d24..095dfa8e4935 100644 --- a/drivers/soc/qcom/qcom_ramdump.c +++ b/drivers/soc/qcom/qcom_ramdump.c @@ -16,8 +16,6 @@ #include #include -#define RAMDUMP_TIMEOUT 120000 - struct qcom_ramdump_desc { void *data; struct completion dump_done; @@ -45,24 +43,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) From 72f355f2d00f7d5c189af8f2e2aec04eaad5ccab Mon Sep 17 00:00:00 2001 From: Gokul krishna Krishnakumar Date: Tue, 7 Sep 2021 17:18:12 -0700 Subject: [PATCH 2/4] soc: qcom: ramdump: Add support for elf64 dumps The qcom_elf_dump() API currently only supported elf32 dumps, but the kernel is compiled as CONFIG_BIT64=y. This results in the addresses in the elf header being truncated. This change adds support to specify the class of the elf file to be generated. Change-Id: I1b72a828df0b45978891ed6ba6261273200500b0 Signed-off-by: Siddharth Gupta Signed-off-by: Gokul krishna Krishnakumar [quic_gurus@quicinc.com: Remove adsprpc.c; hasn't been ported yet] Signed-off-by: Guru Das Srinagesh --- drivers/soc/qcom/qcom_ramdump.c | 99 ++++++++++++++++++++++----------- include/soc/qcom/qcom_ramdump.h | 5 +- 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/drivers/soc/qcom/qcom_ramdump.c b/drivers/soc/qcom/qcom_ramdump.c index 095dfa8e4935..0583a5b90ae6 100644 --- a/drivers/soc/qcom/qcom_ramdump.c +++ b/drivers/soc/qcom/qcom_ramdump.c @@ -16,6 +16,33 @@ #include #include +#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; @@ -101,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; @@ -116,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++; } @@ -130,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); @@ -172,7 +205,7 @@ int qcom_elf_dump(struct list_head *segs, struct device *dev) segment->size); } - offset += phdr->p_filesz; + offset += segment->size; phdr++; } @@ -214,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; } From 53346fbff06e3b16d687543cbf39d4b6981fa8aa Mon Sep 17 00:00:00 2001 From: Gokul krishna Krishnakumar Date: Wed, 13 Oct 2021 12:11:29 -0700 Subject: [PATCH 3/4] soc: qcom: ramdump: Fix elf phdr increment logic To add support for elf64 dumps phdr was converted to a void pointer, but the logic to increment the phdr was not updated accordingly. This change increments the address of phdr based on the elf class. Fixes: fc0253777c4c ('soc: qcom: ramdump: Add support for elf64 dumps') Change-Id: I103835cfa1333aacfc8fe8ca3ae02dc84607a5cc Signed-off-by: Siddharth Gupta Signed-off-by: Gokul krishna Krishnakumar --- drivers/soc/qcom/qcom_ramdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qcom_ramdump.c b/drivers/soc/qcom/qcom_ramdump.c index 0583a5b90ae6..6379f3884412 100644 --- a/drivers/soc/qcom/qcom_ramdump.c +++ b/drivers/soc/qcom/qcom_ramdump.c @@ -206,7 +206,7 @@ int qcom_elf_dump(struct list_head *segs, struct device *dev, unsigned char clas } offset += segment->size; - phdr++; + phdr += sizeof_elf_phdr(class); } return qcom_devcd_dump(dev, data, data_size, GFP_KERNEL); From ecb19ca5637742bdd5e14f705d8c94ef43cf0d2c Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Thu, 8 Sep 2022 15:29:36 -0700 Subject: [PATCH 4/4] defconfig: pineapple-gki: Enable QCOM_RAMDUMP Enable the QCOM Ramdump driver on pineapple platforms. Change-Id: Ica92d8a605fdda7845d55a2766c31407be86a945 Signed-off-by: Guru Das Srinagesh --- arch/arm64/configs/vendor/pineapple_GKI.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/pineapple_GKI.config b/arch/arm64/configs/vendor/pineapple_GKI.config index 27804ad4d320..f895e97ae458 100644 --- a/arch/arm64/configs/vendor/pineapple_GKI.config +++ b/arch/arm64/configs/vendor/pineapple_GKI.config @@ -78,6 +78,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