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>
[neeraju@codeaurora: Add mdt_remove_lock to serialize with removal]
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 c77acc02d4
commit facd0a72d9
8 changed files with 94 additions and 23 deletions

View file

@ -1842,7 +1842,7 @@ static int lpm_probe(struct platform_device *pdev)
md_entry.phys_addr = lpm_debug_phys;
md_entry.size = size;
md_entry.id = MINIDUMP_DEFAULT_ID;
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
pr_info("Failed to add lpm_debug in Minidump\n");
return 0;

View file

@ -1897,7 +1897,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

@ -679,7 +679,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;
@ -876,7 +876,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

@ -34,7 +34,7 @@ static void __init register_log_buf(void)
md_entry.phys_addr = virt_to_phys(*log_bufp);
md_entry.size = *log_buf_lenp;
md_entry.id = MINIDUMP_DEFAULT_ID;
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
pr_err("Failed to add logbuf in Minidump\n");
}
@ -54,7 +54,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);
}
@ -71,7 +71,7 @@ static void __init register_kernel_sections(void)
ksec_entry.phys_addr = virt_to_phys(_sdata);
ksec_entry.size = roundup((__bss_stop - _sdata), 4);
ksec_entry.id = MINIDUMP_DEFAULT_ID;
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 */
@ -85,7 +85,7 @@ static void __init register_kernel_sections(void)
ksec_entry.phys_addr = per_cpu_ptr_to_phys(start);
ksec_entry.size = static_size;
ksec_entry.id = MINIDUMP_DEFAULT_ID;
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");
}
}
@ -158,7 +158,7 @@ void dump_stack_minidump(u64 sp)
ktsk_entry.phys_addr = virt_to_phys((uintptr_t *)current);
ktsk_entry.size = sizeof(struct task_struct);
ktsk_entry.id = MINIDUMP_DEFAULT_ID;
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,10 @@ 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;
/* Number of pending entries to be added in ToC regions */
static unsigned int pendings;
@ -166,11 +168,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 +179,64 @@ 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;
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 +269,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 +358,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 +367,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 +398,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;

View file

@ -803,7 +803,7 @@ static void minidump_reg_init_log_buf(void)
md_entry.phys_addr = log_buf_paddr;
md_entry.size = *log_buf_size;
md_entry.id = MINIDUMP_DEFAULT_ID;
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
pr_err("Failed to add init_log_buf in Minidump\n");
}
@ -1049,7 +1049,7 @@ static int msm_watchdog_probe(struct platform_device *pdev)
md_entry.phys_addr = virt_to_phys(wdog_dd);
md_entry.size = sizeof(*wdog_dd);
md_entry.id = MINIDUMP_DEFAULT_ID;
if (msm_minidump_add_region(&md_entry))
if (msm_minidump_add_region(&md_entry) < 0)
pr_info("Failed to add Watchdog data in Minidump\n");
return 0;

View file

@ -27,14 +27,23 @@ struct md_region {
u64 size;
};
/* Register an entry in Minidump table
* Returns:
* Zero: on successful addition
* Negetive error number on failures
*/
#ifdef CONFIG_QCOM_MINIDUMP
/*
* Register an entry in Minidump table
* Returns:
* region number: entry position in minidump table.
* Negetive error number on failures.
*/
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

@ -292,7 +292,7 @@ static int msm_rtb_probe(struct platform_device *pdev)
md_entry.phys_addr = msm_rtb.phys;
md_entry.size = msm_rtb.size;
md_entry.id = MINIDUMP_DEFAULT_ID;
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)