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

Commit aa06ebe5 authored by Shrenuj Bansal's avatar Shrenuj Bansal Committed by Gerrit - the friendly Code Review server
Browse files

msm: kgsl: Update addr variable in kgsl_get_unmapped_area



If the addr variable exceeds KGSL_SVM_UPPER_BOUND we take care of
the high limit to the vm_unmapped_area() call but never actually
update the addr variable. Therefore, if we have an addr exceeding
our mmap range and vm_unmapped_area returns failure, then we simply
use the invalid addr value for the mmap_range_valid() check which
fails.

Fix this by updating the addr with the returned value of the
unmapped area. Also fix the low limits from TASK_UNMAPPED_BASE to
SZ_1M since the former value is very large for 64 bit.

Change-Id: I33cf736e07cdf095b1552407f71dd79e435393f0
Signed-off-by: default avatarShrenuj Bansal <shrenujb@codeaurora.org>
parent ad7adec6
Loading
Loading
Loading
Loading
+15 −13
Original line number Original line Diff line number Diff line
@@ -3765,8 +3765,8 @@ err_put:
static inline bool
static inline bool
mmap_range_valid(unsigned long addr, unsigned long len)
mmap_range_valid(unsigned long addr, unsigned long len)
{
{
	return ((ULONG_MAX - addr) > len) && ((addr + len) <
	return ((ULONG_MAX - addr) > len) && ((addr + len) <=
		KGSL_SVM_UPPER_BOUND);
		KGSL_SVM_UPPER_BOUND) && (addr >= KGSL_SVM_LOWER_BOUND);
}
}


/**
/**
@@ -3977,7 +3977,7 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr,
	}
	}
	/* special case handling for MAP_FIXED */
	/* special case handling for MAP_FIXED */
	if (flags & MAP_FIXED) {
	if (flags & MAP_FIXED) {
		if (addr + len > KGSL_SVM_UPPER_BOUND) {
		if (!mmap_range_valid(addr, len)) {
			ret = -EFAULT;
			ret = -EFAULT;
			goto put;
			goto put;
		}
		}
@@ -4002,14 +4002,11 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr,
	if (align)
	if (align)
		len += 1 << align;
		len += 1 << align;


	if (!mmap_range_valid(addr, len))
		addr = 0;

	/*
	/*
	 * first try to see if the suggested address is accepted by the
	 * first try to see if the suggested address is accepted by the
	 * system map and our gpu map
	 * system map and our gpu map
	 */
	 */
	if (addr && (addr + len <= KGSL_SVM_UPPER_BOUND)) {
	if (mmap_range_valid(addr, len)) {
		vma = find_vma(current->mm, addr);
		vma = find_vma(current->mm, addr);
		if (!vma || ((addr + len) <= vma->vm_start)) {
		if (!vma || ((addr + len) <= vma->vm_start)) {


@@ -4028,6 +4025,10 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr,
			}
			}
		}
		}
	}
	}

	if (mmap_min_addr >= KGSL_SVM_UPPER_BOUND)
		return -ERANGE;

	addr = current->mm->mmap_base;
	addr = current->mm->mmap_base;
	info.length = orig_len;
	info.length = orig_len;
	info.align_mask = ((1 << align) - 1);
	info.align_mask = ((1 << align) - 1);
@@ -4036,14 +4037,15 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr,
	 * Loop through the address space to find a address region agreeable to
	 * Loop through the address space to find a address region agreeable to
	 * both system map and gpu map
	 * both system map and gpu map
	 */
	 */
	do {
	while (1) {
		if (retry) {
		if (retry) {
			/*
			/*
			 * try the bottom up approach if top down failed
			 * try the bottom up approach if top down failed
			 */
			 */
			if (flag_top_down) {
			if (flag_top_down) {
				flag_top_down = false;
				flag_top_down = false;
				addr = TASK_UNMAPPED_BASE;
				addr = max_t(unsigned long,
					KGSL_SVM_LOWER_BOUND, mmap_min_addr);
				gpumap_free_addr = 0;
				gpumap_free_addr = 0;
				ret = 0;
				ret = 0;
				retry = 0;
				retry = 0;
@@ -4074,7 +4076,8 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr,
			addr = gpumap_free_addr;
			addr = gpumap_free_addr;
		if (flag_top_down) {
		if (flag_top_down) {
			info.flags = VM_UNMAPPED_AREA_TOPDOWN;
			info.flags = VM_UNMAPPED_AREA_TOPDOWN;
			info.low_limit = PAGE_SIZE;
			info.low_limit = max_t(unsigned long,
					KGSL_SVM_LOWER_BOUND, mmap_min_addr);
			info.high_limit = (addr > KGSL_SVM_UPPER_BOUND) ?
			info.high_limit = (addr > KGSL_SVM_UPPER_BOUND) ?
						KGSL_SVM_UPPER_BOUND : addr;
						KGSL_SVM_UPPER_BOUND : addr;
		} else {
		} else {
@@ -4121,13 +4124,12 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr,
		 * the whole address space at least once by wrapping
		 * the whole address space at least once by wrapping
		 * back around once.
		 * back around once.
		 */
		 */
		if (!mmap_range_valid(addr, len) ||
		if (!mmap_range_valid(gpumap_free_addr, len)) {
			!mmap_range_valid(gpumap_free_addr, len)) {
			retry = 1;
			retry = 1;
			ret = -EBUSY;
			ret = -EBUSY;
			continue;
			continue;
		}
		}
	} while (mmap_range_valid(addr, orig_len));
	}


put:
put:
	if (IS_ERR_VALUE(ret))
	if (IS_ERR_VALUE(ret))
+2 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,8 @@
/* The SVM upper bound is the same as the TASK_SIZE in arm32 */
/* The SVM upper bound is the same as the TASK_SIZE in arm32 */
#define KGSL_SVM_UPPER_BOUND (0xC0000000 - SZ_16M)
#define KGSL_SVM_UPPER_BOUND (0xC0000000 - SZ_16M)


#define KGSL_SVM_LOWER_BOUND PAGE_SIZE

/* A macro for memory statistics - add the new size to the stat and if
/* A macro for memory statistics - add the new size to the stat and if
   the statisic is greater then _max, set _max
   the statisic is greater then _max, set _max
*/
*/