diff options
author | Will Deacon <will.deacon@arm.com> | 2012-04-27 08:08:53 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-05-02 06:12:49 -0400 |
commit | c5102f5935503ebebad46e137d0eef68f272cc16 (patch) | |
tree | 888332340ca07cbd2a648fa603b8b252af02252a /arch/arm/kernel | |
parent | 435a7ef52db7d86e67a009b36cac1457f8972391 (diff) |
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: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/traps.c | 11 |
1 files changed, 5 insertions, 6 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 63d402f75e2..3647170e9a1 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -479,14 +479,14 @@ static int bad_syscall(int n, struct pt_regs *regs) | |||
479 | return regs->ARM_r0; | 479 | return regs->ARM_r0; |
480 | } | 480 | } |
481 | 481 | ||
482 | static inline void | 482 | static inline int |
483 | do_cache_op(unsigned long start, unsigned long end, int flags) | 483 | do_cache_op(unsigned long start, unsigned long end, int flags) |
484 | { | 484 | { |
485 | struct mm_struct *mm = current->active_mm; | 485 | struct mm_struct *mm = current->active_mm; |
486 | struct vm_area_struct *vma; | 486 | struct vm_area_struct *vma; |
487 | 487 | ||
488 | if (end < start || flags) | 488 | if (end < start || flags) |
489 | return; | 489 | return -EINVAL; |
490 | 490 | ||
491 | down_read(&mm->mmap_sem); | 491 | down_read(&mm->mmap_sem); |
492 | vma = find_vma(mm, start); | 492 | vma = find_vma(mm, start); |
@@ -497,10 +497,10 @@ do_cache_op(unsigned long start, unsigned long end, int flags) | |||
497 | end = vma->vm_end; | 497 | end = vma->vm_end; |
498 | 498 | ||
499 | up_read(&mm->mmap_sem); | 499 | up_read(&mm->mmap_sem); |
500 | flush_cache_user_range(start, end); | 500 | return flush_cache_user_range(start, end); |
501 | return; | ||
502 | } | 501 | } |
503 | up_read(&mm->mmap_sem); | 502 | up_read(&mm->mmap_sem); |
503 | return -EINVAL; | ||
504 | } | 504 | } |
505 | 505 | ||
506 | /* | 506 | /* |
@@ -546,8 +546,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
546 | * the specified region). | 546 | * the specified region). |
547 | */ | 547 | */ |
548 | case NR(cacheflush): | 548 | case NR(cacheflush): |
549 | do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2); | 549 | return do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2); |
550 | return 0; | ||
551 | 550 | ||
552 | case NR(usr26): | 551 | case NR(usr26): |
553 | if (!(elf_hwcap & HWCAP_26BIT)) | 552 | if (!(elf_hwcap & HWCAP_26BIT)) |