Minidump: Add update region support for minidump regions

Add support to update client's entry physical/virtual addresses,
which is useful for DLKM, dynamic address changing clients.

Currently, msm_minidump_add_region() returns 0 on success, instead
of that, return 'region number' of the entry in the minidump table.

So clients who wants to update their address in future, needs to
book keep their entry in minidump table.

Change-Id: I03abbbd87bf6d2e11cf637525412d352772821cf
Signed-off-by: Lingutla Chandrasekhar <clingutla@codeaurora.org>
Signed-off-by: Neeraj Upadhyay <neeraju@codeaurora.org>
This commit is contained in:
Lingutla Chandrasekhar 2018-08-13 17:07:14 +05:30 committed by Neeraj Upadhyay
parent b76161f6ac
commit 465231e616
8 changed files with 98 additions and 20 deletions

View File

@ -2183,7 +2183,7 @@ int cnss_minidump_add_region(struct cnss_plat_data *plat_priv,
md_entry.name, va, &pa, size);
ret = msm_minidump_add_region(&md_entry);
if (ret)
if (ret < 0)
cnss_pr_err("Failed to add mini dump region, err = %d\n", ret);
return ret;

View File

@ -1849,7 +1849,7 @@ static int dcc_probe(struct platform_device *pdev)
md_entry.virt_addr = (uintptr_t)drvdata->ram_base;
md_entry.phys_addr = res->start;
md_entry.size = drvdata->ram_size;
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
dev_err(drvdata->dev, "Failed to add DCC data in Minidump\n");
return 0;

View File

@ -662,7 +662,7 @@ int msm_dump_data_register(enum msm_dump_table_ids id,
ret = register_dump_table_entry(id, entry);
if (!ret)
if (msm_dump_data_add_minidump(entry))
if (msm_dump_data_add_minidump(entry) < 0)
pr_err("Failed to add entry in Minidump table\n");
return ret;
@ -856,7 +856,7 @@ static int mem_dump_alloc(struct platform_device *pdev)
md_entry.size = size;
md_entry.id = id;
strlcpy(md_entry.name, child_node->name, sizeof(md_entry.name));
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
dev_err(&pdev->dev, "Mini dump entry failed id = %d\n",
id);

View File

@ -33,7 +33,7 @@ static void __init register_log_buf(void)
md_entry.virt_addr = (uintptr_t) (*log_bufp);
md_entry.phys_addr = virt_to_phys(*log_bufp);
md_entry.size = *log_buf_lenp;
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
pr_err("Failed to add logbuf in Minidump\n");
}
@ -52,7 +52,7 @@ static void register_stack_entry(struct md_region *ksp_entry, u64 sp, u64 size,
ksp_entry->phys_addr = virt_to_phys((uintptr_t *)sp);
}
if (msm_minidump_add_region(ksp_entry))
if (msm_minidump_add_region(ksp_entry) < 0)
pr_err("Failed to add stack of cpu %d in Minidump\n", cpu);
}
@ -68,7 +68,7 @@ static void __init register_kernel_sections(void)
ksec_entry.virt_addr = (uintptr_t)_sdata;
ksec_entry.phys_addr = virt_to_phys(_sdata);
ksec_entry.size = roundup((__bss_stop - _sdata), 4);
if (msm_minidump_add_region(&ksec_entry))
if (msm_minidump_add_region(&ksec_entry) < 0)
pr_err("Failed to add data section in Minidump\n");
/* Add percpu static sections */
@ -81,7 +81,7 @@ static void __init register_kernel_sections(void)
ksec_entry.virt_addr = (uintptr_t)start;
ksec_entry.phys_addr = per_cpu_ptr_to_phys(start);
ksec_entry.size = static_size;
if (msm_minidump_add_region(&ksec_entry))
if (msm_minidump_add_region(&ksec_entry) < 0)
pr_err("Failed to add percpu sections in Minidump\n");
}
}
@ -153,7 +153,7 @@ void dump_stack_minidump(u64 sp)
ktsk_entry.virt_addr = (u64)current;
ktsk_entry.phys_addr = virt_to_phys((uintptr_t *)current);
ktsk_entry.size = sizeof(struct task_struct);
if (msm_minidump_add_region(&ktsk_entry))
if (msm_minidump_add_region(&ktsk_entry) < 0)
pr_err("Failed to add current task %d in Minidump\n", cpu);
}

View File

@ -34,7 +34,7 @@ struct md_table {
struct md_ss_toc *md_ss_toc;
struct md_global_toc *md_gbl_toc;
struct md_ss_region *md_regions;
struct md_region entry[MAX_NUM_ENTRIES];
struct md_region entry[MAX_NUM_ENTRIES];
};
/**
@ -55,8 +55,11 @@ struct md_elfhdr {
/* Protect elfheader and smem table from deferred calls contention */
static DEFINE_SPINLOCK(mdt_lock);
static DEFINE_RWLOCK(mdt_remove_lock);
static struct md_table minidump_table;
static struct md_elfhdr minidump_elfheader;
static int first_removed_entry = INT_MAX;
static bool md_init_done;
/* Number of pending entries to be added in ToC regions */
static unsigned int pendings;
@ -166,11 +169,8 @@ bool msm_minidump_enabled(void)
}
EXPORT_SYMBOL(msm_minidump_enabled);
int msm_minidump_add_region(const struct md_region *entry)
static inline int validate_region(const struct md_region *entry)
{
u32 entries;
struct md_region *mdr;
if (!entry)
return -EINVAL;
@ -180,6 +180,68 @@ int msm_minidump_add_region(const struct md_region *entry)
return -EINVAL;
}
return 0;
}
int msm_minidump_update_region(int regno, const struct md_region *entry)
{
int ret = 0;
struct md_region *mdr;
struct md_ss_region *mdssr;
struct elfhdr *hdr = minidump_elfheader.ehdr;
struct elf_shdr *shdr;
struct elf_phdr *phdr;
/* Ensure that init completes before we update regions */
if (!smp_load_acquire(&md_init_done))
return -EINVAL;
if (validate_region(entry) || (regno >= MAX_NUM_ENTRIES))
return -EINVAL;
read_lock(&mdt_remove_lock);
if (regno >= first_removed_entry) {
pr_err("Region:[%s] was moved\n", entry->name);
ret = -EINVAL;
goto err_unlock;
}
if (md_entry_num(entry) < 0) {
pr_err("Region:[%s] does not exist to update.\n", entry->name);
ret = -ENOMEM;
goto err_unlock;
}
mdr = &minidump_table.entry[regno];
mdr->virt_addr = entry->virt_addr;
mdr->phys_addr = entry->phys_addr;
mdssr = &minidump_table.md_regions[regno + 1];
mdssr->region_base_address = entry->phys_addr;
shdr = elf_section(hdr, regno + 4);
phdr = elf_program(hdr, regno + 1);
shdr->sh_addr = (elf_addr_t)entry->virt_addr;
phdr->p_vaddr = entry->virt_addr;
phdr->p_paddr = entry->phys_addr;
err_unlock:
read_unlock(&mdt_remove_lock);
return ret;
}
EXPORT_SYMBOL(msm_minidump_update_region);
int msm_minidump_add_region(const struct md_region *entry)
{
u32 entries;
struct md_region *mdr;
if (validate_region(entry))
return -EINVAL;
spin_lock(&mdt_lock);
if (md_entry_num(entry) >= 0) {
pr_err("Entry name already exist.\n");
@ -212,7 +274,7 @@ int msm_minidump_add_region(const struct md_region *entry)
spin_unlock(&mdt_lock);
return 0;
return entries;
}
EXPORT_SYMBOL(msm_minidump_add_region);
@ -301,6 +363,7 @@ int msm_minidump_remove_region(const struct md_region *entry)
return -EINVAL;
spin_lock(&mdt_lock);
write_lock(&mdt_remove_lock);
ecount = minidump_table.num_regions;
rcount = minidump_table.md_ss_toc->ss_region_count;
rgno = md_entry_num(entry);
@ -309,6 +372,8 @@ int msm_minidump_remove_region(const struct md_region *entry)
goto out;
}
if (first_removed_entry > rgno)
first_removed_entry = rgno;
minidump_table.md_ss_toc->md_ss_toc_init = 0;
/* Remove entry from: entry list, ss region list and elf header */
@ -338,9 +403,11 @@ int msm_minidump_remove_region(const struct md_region *entry)
minidump_table.md_ss_toc->md_ss_toc_init = 1;
minidump_table.num_regions--;
write_unlock(&mdt_remove_lock);
spin_unlock(&mdt_lock);
return 0;
out:
write_unlock(&mdt_remove_lock);
spin_unlock(&mdt_lock);
pr_err("Minidump is broken..disable Minidump collection\n");
return -EINVAL;
@ -507,6 +574,8 @@ static int __init msm_minidump_init(void)
pr_info("Enabled with max number of regions %d\n",
CONFIG_MINIDUMP_MAX_ENTRIES);
/* All updates above should be visible, before init completes */
smp_store_release(&md_init_done, true);
return 0;
}
subsys_initcall(msm_minidump_init)

View File

@ -573,7 +573,7 @@ int qcom_wdt_register(struct platform_device *pdev,
md_entry.virt_addr = (uintptr_t)wdog_dd;
md_entry.phys_addr = virt_to_phys(wdog_dd);
md_entry.size = sizeof(*wdog_dd);
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
dev_err(wdog_dd->dev, "Failed to add Wdt data in Minidump\n");
return 0;
err:

View File

@ -25,14 +25,23 @@ struct md_region {
u64 size;
};
/* Register an entry in Minidump table
/*
* Register an entry in Minidump table
* Returns:
* Zero: on successful addition
* Negetive error number on failures
* region number: entry position in minidump table.
* Negative error number on failures.
*/
#if IS_ENABLED(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);
/*
* Update registered region address in Minidump table.
* It does not hold any locks, so strictly serialize the region updates.
* Returns:
* Zero: on successfully update
* Negetive error number on failures.
*/
extern int msm_minidump_update_region(int regno, const struct md_region *entry);
extern bool msm_minidump_enabled(void);
extern void dump_stack_minidump(u64 sp);
#else

View File

@ -290,7 +290,7 @@ static int msm_rtb_probe(struct platform_device *pdev)
md_entry.virt_addr = (uintptr_t)msm_rtb.rtb;
md_entry.phys_addr = msm_rtb.phys;
md_entry.size = msm_rtb.size;
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
pr_info("Failed to add RTB in Minidump\n");
#if defined(CONFIG_QCOM_RTB_SEPARATE_CPUS)