Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 738dd8e0 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: Add entry removal support for Minidump"

parents 992541c0 06312743
Loading
Loading
Loading
Loading
+167 −30
Original line number Diff line number Diff line
@@ -86,31 +86,33 @@ static inline unsigned int set_section_name(const char *name)
	return ret;
}

static inline bool md_check_name(const char *name)
{
	struct md_region *mde = minidump_table.entry;
	int i, regno = minidump_table.num_regions;

	for (i = 0; i < regno; i++, mde++)
		if (!strcmp(mde->name, name))
			return true;
	return false;
}

/* Return next seq no, if name already exists in the table */
static inline int md_get_seq_num(const char *name)
static inline int md_region_num(const char *name, int *seqno)
{
	struct md_ss_region *mde = minidump_table.md_regions;
	int i, regno = minidump_table.md_ss_toc->ss_region_count;
	int seqno = 0;
	int ret = -EINVAL;

	for (i = 0; i < (regno - 1); i++, mde++) {
	for (i = 0; i < regno; i++, mde++) {
		if (!strcmp(mde->name, name)) {
			if (mde->seq_num >= seqno)
				seqno = mde->seq_num + 1;
			ret = i;
			if (mde->seq_num > *seqno)
				*seqno = mde->seq_num;
		}
	}
	return seqno;
	return ret;
}

static inline int md_entry_num(const struct md_region *entry)
{
	struct md_region *mdr;
	int i, regno = minidump_table.num_regions;

	for (i = 0; i < regno; i++) {
		mdr = &minidump_table.entry[i];
		if (!strcmp(mdr->name, entry->name))
			return i;
	}
	return -EINVAL;
}

/* Update Mini dump table in SMEM */
@@ -120,14 +122,15 @@ static void md_update_ss_toc(const struct md_region *entry)
	struct elfhdr *hdr = minidump_elfheader.ehdr;
	struct elf_shdr *shdr = elf_section(hdr, hdr->e_shnum++);
	struct elf_phdr *phdr = elf_program(hdr, hdr->e_phnum++);
	int reg_cnt = minidump_table.md_ss_toc->ss_region_count++;
	int seq = 0, reg_cnt = minidump_table.md_ss_toc->ss_region_count;

	mdr = &minidump_table.md_regions[reg_cnt];

	strlcpy(mdr->name, entry->name, sizeof(mdr->name));
	mdr->region_base_address = entry->phys_addr;
	mdr->region_size = entry->size;
	mdr->seq_num = md_get_seq_num(entry->name);
	if (md_region_num(entry->name, &seq) >= 0)
		mdr->seq_num = seq + 1;

	/* Update elf header */
	shdr->sh_type = SHT_PROGBITS;
@@ -144,9 +147,9 @@ static void md_update_ss_toc(const struct md_region *entry)
	phdr->p_paddr = entry->phys_addr;
	phdr->p_filesz = phdr->p_memsz =  mdr->region_size;
	phdr->p_flags = PF_R | PF_W;

	minidump_elfheader.elf_offset += shdr->sh_size;
	mdr->md_valid = MD_REGION_VALID;
	minidump_table.md_ss_toc->ss_region_count++;
}

bool msm_minidump_enabled(void)
@@ -167,23 +170,23 @@ int msm_minidump_add_region(const struct md_region *entry)
{
	u32 entries;
	struct md_region *mdr;
	int ret = 0;

	if (!entry)
		return -EINVAL;

	if ((strlen(entry->name) > MAX_NAME_LENGTH) ||
		md_check_name(entry->name) || !entry->virt_addr) {
	if ((strlen(entry->name) > MAX_NAME_LENGTH) || !entry->virt_addr ||
		(!IS_ALIGNED(entry->size, 4))) {
		pr_err("Invalid entry details\n");
		return -EINVAL;
	}

	if (!IS_ALIGNED(entry->size, 4)) {
		pr_err("size should be 4 byte aligned\n");
	spin_lock(&mdt_lock);
	if (md_entry_num(entry) >= 0) {
		pr_err("Entry name already exist.\n");
		spin_unlock(&mdt_lock);
		return -EINVAL;
	}

	spin_lock(&mdt_lock);
	entries = minidump_table.num_regions;
	if (entries >= MAX_NUM_ENTRIES) {
		pr_err("Maximum entries reached.\n");
@@ -209,10 +212,141 @@ int msm_minidump_add_region(const struct md_region *entry)

	spin_unlock(&mdt_lock);

	return ret;
	return 0;
}
EXPORT_SYMBOL(msm_minidump_add_region);

int msm_minidump_clear_headers(const struct md_region *entry)
{
	struct elfhdr *hdr = minidump_elfheader.ehdr;
	struct elf_shdr *shdr = NULL, *tshdr = NULL;
	struct elf_phdr *phdr = NULL, *tphdr = NULL;
	int pidx, shidx, strln, i;
	char *shname;
	u64 esize;

	esize = entry->size;
	for (i = 0; i < hdr->e_phnum; i++) {
		phdr = elf_program(hdr, i);
		if ((phdr->p_paddr == entry->phys_addr) &&
			(phdr->p_memsz == entry->size))
			break;
	}
	if (i == hdr->e_phnum) {
		pr_err("Cannot find entry in elf\n");
		return -EINVAL;
	}
	pidx = i;

	for (i = 0; i < hdr->e_shnum; i++) {
		shdr = elf_section(hdr, i);
		shname = elf_lookup_string(hdr, shdr->sh_name);
		if (shname && !strcmp(shname, entry->name))
			if ((shdr->sh_addr == entry->virt_addr) &&
				(shdr->sh_size == entry->size))
				break;

	}
	if (i == hdr->e_shnum) {
		pr_err("Cannot find entry in elf\n");
		return -EINVAL;
	}
	shidx = i;

	if (shdr->sh_offset != phdr->p_offset) {
		pr_err("Invalid entry details in elf, Minidump broken..\n");
		return -EINVAL;
	}

	/* Clear name in string table */
	strln = strlen(shname) + 1;
	memmove(shname, shname + strln,
		(minidump_elfheader.strtable_idx - shdr->sh_name));
	minidump_elfheader.strtable_idx -= strln;

	/* Clear program header */
	tphdr = elf_program(hdr, pidx);
	for (i = pidx; i < hdr->e_phnum - 1; i++) {
		tphdr = elf_program(hdr, i + 1);
		phdr = elf_program(hdr, i);
		memcpy(phdr, tphdr, sizeof(struct elf_phdr));
		phdr->p_offset = phdr->p_offset - esize;
	}
	memset(tphdr, 0, sizeof(struct elf_phdr));
	hdr->e_phnum--;

	/* Clear section header */
	tshdr = elf_section(hdr, shidx);
	for (i = shidx; i < hdr->e_shnum - 1; i++) {
		tshdr = elf_section(hdr, i + 1);
		shdr = elf_section(hdr, i);
		memcpy(shdr, tshdr, sizeof(struct elf_shdr));
		shdr->sh_offset -= esize;
		shdr->sh_name -= strln;
	}
	memset(tshdr, 0, sizeof(struct elf_shdr));
	hdr->e_shnum--;

	minidump_elfheader.elf_offset -= esize;
	return 0;
}

int msm_minidump_remove_region(const struct md_region *entry)
{
	int rcount, ecount, seq = 0, rgno, ret;

	if (!entry || !minidump_table.md_ss_toc ||
		(minidump_table.md_ss_toc->md_ss_enable_status !=
						MD_SS_ENABLED))
		return -EINVAL;

	spin_lock(&mdt_lock);
	ecount = minidump_table.num_regions;
	rcount = minidump_table.md_ss_toc->ss_region_count;
	rgno = md_entry_num(entry);
	if (rgno < 0) {
		pr_err("Not able to find the entry in table\n");
		goto out;
	}

	minidump_table.md_ss_toc->md_ss_toc_init = 0;

	/* Remove entry from: entry list, ss region list and elf header */
	memmove(&minidump_table.entry[rgno], &minidump_table.entry[rgno + 1],
		((ecount - rgno - 1) * sizeof(struct md_region)));
	memset(&minidump_table.entry[ecount - 1], 0, sizeof(struct md_region));


	rgno = md_region_num(entry->name, &seq);
	if (rgno < 0) {
		pr_err("Not able to find region in table\n");
		goto out;
	}

	memmove(&minidump_table.md_regions[rgno],
		&minidump_table.md_regions[rgno + 1],
		((rcount - rgno - 1) * sizeof(struct md_ss_region)));
	memset(&minidump_table.md_regions[rcount - 1], 0,
					sizeof(struct md_ss_region));


	ret = msm_minidump_clear_headers(entry);
	if (ret)
		goto out;

	minidump_table.md_ss_toc->ss_region_count--;
	minidump_table.md_ss_toc->md_ss_toc_init = 1;

	minidump_table.num_regions--;
	spin_unlock(&mdt_lock);
	return 0;
out:
	spin_unlock(&mdt_lock);
	pr_err("Minidump is broken..disable Minidump collection\n");
	return -EINVAL;
}
EXPORT_SYMBOL(msm_minidump_remove_region);

static int msm_minidump_add_header(void)
{
	struct md_ss_region *mdreg = &minidump_table.md_regions[0];
@@ -226,8 +360,11 @@ static int msm_minidump_add_header(void)
	 * elf header, MAX_NUM_ENTRIES+4 of section and program elf headers,
	 * string table section and linux banner.
	 */
	elfh_size = sizeof(*ehdr) + MAX_STRTBL_SIZE + (strlen(linux_banner) +
		1) + ((sizeof(*shdr) + sizeof(*phdr)) * (MAX_NUM_ENTRIES + 4));
	elfh_size = sizeof(*ehdr) + MAX_STRTBL_SIZE +
			(strlen(linux_banner) + 1) +
			((sizeof(*shdr) + sizeof(*phdr))
			 * (MAX_NUM_ENTRIES + 4));

	elfh_size = ALIGN(elfh_size, 4);

	minidump_elfheader.ehdr = kzalloc(elfh_size, GFP_KERNEL);
+5 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ struct md_region {
 */
#ifdef CONFIG_QCOM_MINIDUMP
extern int msm_minidump_add_region(const struct md_region *entry);
extern int msm_minidump_remove_region(const struct md_region *entry);
extern bool msm_minidump_enabled(void);
extern void dump_stack_minidump(u64 sp);
#else
@@ -38,6 +39,10 @@ static inline int msm_minidump_add_region(const struct md_region *entry)
	/* Return quietly, if minidump is not supported */
	return 0;
}
static inline int msm_minidump_remove_region(const struct md_region *entry)
{
	return 0;
}
static inline bool msm_minidump_enabled(void) { return false; }
static inline void dump_stack_minidump(u64 sp) {}
#endif