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

Commit 1917e979 authored by Vikram Mulukutla's avatar Vikram Mulukutla
Browse files

qcom: ramdump: Allow callers to specify segment virtual mappings



Memory allocation APIs do not necessarily allow memory
to be ioremapped into the kernel address space. Allow drivers
to specify the virtual address of a segment in memory. The
physical addresses of these segments must still be specified
to discourage drivers from using the ramdump API to dump any
random virtual address space. This will also keep the API
backward compatible.

Change-Id: I149527b84711c5b655fc8f1565a6863444634ef1
Signed-off-by: default avatarVikram Mulukutla <markivx@codeaurora.org>
parent c5564588
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -78,7 +78,8 @@ struct pil_mdt {
/**
 * struct pil_seg - memory map representing one segment
 * @next: points to next seg mentor NULL if last segment
 * @paddr: start address of segment
 * @paddr: physical start address of segment
 * @vaddr: virtual start address of segment
 * @sz: size of segment
 * @filesz: size of segment on disk
 * @num: segment number
@@ -89,6 +90,7 @@ struct pil_mdt {
 */
struct pil_seg {
	phys_addr_t paddr;
	void *vaddr;
	unsigned long sz;
	unsigned long filesz;
	int num;
@@ -171,6 +173,7 @@ int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
	s = ramdump_segs;
	list_for_each_entry(seg, &priv->segs, list) {
		s->address = seg->paddr;
		s->v_address = seg->vaddr;
		s->size = seg->sz;
		s++;
	}
@@ -305,6 +308,8 @@ static struct pil_seg *pil_init_seg(const struct pil_desc *desc,
		return ERR_PTR(-ENOMEM);
	seg->num = num;
	seg->paddr = reloc ? pil_reloc(priv, phdr->p_paddr) : phdr->p_paddr;
	seg->vaddr = reloc ? priv->region +
			(seg->paddr - priv->region_start) : 0;
	seg->filesz = phdr->p_filesz;
	seg->sz = phdr->p_memsz;
	seg->relocated = reloc;
+15 −6
Original line number Diff line number Diff line
@@ -66,9 +66,11 @@ static int ramdump_release(struct inode *inode, struct file *filep)
}

static unsigned long offset_translate(loff_t user_offset,
		struct ramdump_device *rd_dev, unsigned long *data_left)
		struct ramdump_device *rd_dev, unsigned long *data_left,
		void **vaddr)
{
	int i = 0;
	*vaddr = NULL;

	for (i = 0; i < rd_dev->nsegments; i++)
		if (user_offset >= rd_dev->segments[i].size)
@@ -89,6 +91,9 @@ static unsigned long offset_translate(loff_t user_offset,
		rd_dev->name, rd_dev->segments[i].address + user_offset,
		*data_left);

	if (rd_dev->segments[i].v_address)
		*vaddr = rd_dev->segments[i].v_address + user_offset;

	return rd_dev->segments[i].address + user_offset;
}

@@ -99,7 +104,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
{
	struct ramdump_device *rd_dev = container_of(filep->private_data,
				struct ramdump_device, device);
	void *device_mem = NULL, *origdevice_mem = NULL;
	void *device_mem = NULL, *origdevice_mem = NULL, *vaddr = NULL;
	unsigned long data_left = 0, bytes_before, bytes_after;
	unsigned long addr = 0;
	size_t copy_size = 0, alignsize;
@@ -130,7 +135,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
	}

	addr = offset_translate(*pos - rd_dev->elfcore_size, rd_dev,
				&data_left);
				&data_left, &vaddr);

	/* EOF check */
	if (data_left == 0) {
@@ -143,7 +148,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,

	copy_size = min(count, (size_t)MAX_IOREMAP_SIZE);
	copy_size = min((unsigned long)copy_size, data_left);
	device_mem = ioremap_nocache(addr, copy_size);
	device_mem = vaddr ?: ioremap_nocache(addr, copy_size);
	origdevice_mem = device_mem;

	if (device_mem == NULL) {
@@ -185,13 +190,16 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
		memcpy(alignbuf, device_mem, alignsize);

	if (copy_to_user(buf, finalbuf, copy_size)) {
		pr_err("Ramdump(%s): Couldn't copy all data to user.",
			rd_dev->name);
		rd_dev->ramdump_status = -1;
		ret = -EFAULT;
		goto ramdump_done;
	}

	iounmap(origdevice_mem);
	kfree(finalbuf);
	if (!vaddr)
		iounmap(origdevice_mem);
	*pos += copy_size;

	pr_debug("Ramdump(%s): Read %zd bytes from address %lx.",
@@ -200,6 +208,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
	return *pos - orig_pos;

ramdump_done:
	if (!vaddr)
		iounmap(origdevice_mem);
	kfree(finalbuf);
	rd_dev->data_ready = 0;
+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@ struct device;

struct ramdump_segment {
	unsigned long address;
	void *v_address;
	unsigned long size;
};