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

Commit c5102f59 authored by Will Deacon's avatar Will Deacon Committed by Russell King
Browse files

ARM: 7408/1: cacheflush: return error to userspace when flushing syscall fails



The cacheflush syscall can fail for two reasons:

(1) The arguments are invalid (nonsensical address range or no VMA)

(2) The region generates a translation fault on a VIPT or PIPT cache

This patch allows do_cache_op to return an error code to userspace in
the case of the above. The various coherent_user_range implementations
are modified to return 0 in the case of VIVT caches or -EFAULT in the
case of an abort on v6/v7 cores.

Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 435a7ef5
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ struct cpu_cache_fns {
	void (*flush_user_range)(unsigned long, unsigned long, unsigned int);

	void (*coherent_kern_range)(unsigned long, unsigned long);
	void (*coherent_user_range)(unsigned long, unsigned long);
	int  (*coherent_user_range)(unsigned long, unsigned long);
	void (*flush_kern_dcache_area)(void *, size_t);

	void (*dma_map_area)(const void *, size_t, int);
@@ -142,7 +142,7 @@ extern void __cpuc_flush_kern_all(void);
extern void __cpuc_flush_user_all(void);
extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);
extern void __cpuc_coherent_kern_range(unsigned long, unsigned long);
extern void __cpuc_coherent_user_range(unsigned long, unsigned long);
extern int  __cpuc_coherent_user_range(unsigned long, unsigned long);
extern void __cpuc_flush_dcache_area(void *, size_t);

/*
+5 −6
Original line number Diff line number Diff line
@@ -479,14 +479,14 @@ static int bad_syscall(int n, struct pt_regs *regs)
	return regs->ARM_r0;
}

static inline void
static inline int
do_cache_op(unsigned long start, unsigned long end, int flags)
{
	struct mm_struct *mm = current->active_mm;
	struct vm_area_struct *vma;

	if (end < start || flags)
		return;
		return -EINVAL;

	down_read(&mm->mmap_sem);
	vma = find_vma(mm, start);
@@ -497,10 +497,10 @@ do_cache_op(unsigned long start, unsigned long end, int flags)
			end = vma->vm_end;

		up_read(&mm->mmap_sem);
		flush_cache_user_range(start, end);
		return;
		return flush_cache_user_range(start, end);
	}
	up_read(&mm->mmap_sem);
	return -EINVAL;
}

/*
@@ -546,8 +546,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
	 * the specified region).
	 */
	case NR(cacheflush):
		do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2);
		return 0;
		return do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2);

	case NR(usr26):
		if (!(elf_hwcap & HWCAP_26BIT))
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ ENTRY(v3_coherent_kern_range)
 *	- end	 - virtual end address
 */
ENTRY(v3_coherent_user_range)
	mov	r0, #0
	mov	pc, lr

/*
+1 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ ENTRY(v4_coherent_kern_range)
 *	- end	 - virtual end address
 */
ENTRY(v4_coherent_user_range)
	mov	r0, #0
	mov	pc, lr

/*
+3 −3
Original line number Diff line number Diff line
@@ -167,9 +167,9 @@ ENTRY(v4wb_coherent_user_range)
	add	r0, r0, #CACHE_DLINESIZE
	cmp	r0, r1
	blo	1b
	mov	ip, #0
	mcr	p15, 0, ip, c7, c5, 0		@ invalidate I cache
	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
	mov	r0, #0
	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
	mov	pc, lr


Loading