diff options
author | Vladimir Murzin <vladimir.murzin@arm.com> | 2014-12-01 05:53:08 -0500 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2014-12-01 08:31:12 -0500 |
commit | a2d25a5391ca219f196f9fee7b535c40d201c6bf (patch) | |
tree | 4b2e208ebac21cf53793db6ba4ed5a74b04a6d59 | |
parent | a1ae65b219416a72c15577bd4c8c11174fffbb8b (diff) |
arm64: compat: align cacheflush syscall with arch/arm
Update handling of cacheflush syscall with changes made in arch/arm
counterpart:
- return error to userspace when flushing syscall fails
- split user cache-flushing into interruptible chunks
- don't bother rounding to nearest vma
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
[will: changed internal return value from -EINTR to 0 to match arch/arm/]
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm64/include/asm/cacheflush.h | 2 | ||||
-rw-r--r-- | arch/arm64/kernel/sys_compat.c | 49 | ||||
-rw-r--r-- | arch/arm64/mm/cache.S | 6 |
3 files changed, 35 insertions, 22 deletions
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index 689b6379188c..7ae31a2cc6c0 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h | |||
@@ -73,7 +73,7 @@ extern void flush_cache_all(void); | |||
73 | extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); | 73 | extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); |
74 | extern void flush_icache_range(unsigned long start, unsigned long end); | 74 | extern void flush_icache_range(unsigned long start, unsigned long end); |
75 | extern void __flush_dcache_area(void *addr, size_t len); | 75 | extern void __flush_dcache_area(void *addr, size_t len); |
76 | extern void __flush_cache_user_range(unsigned long start, unsigned long end); | 76 | extern long __flush_cache_user_range(unsigned long start, unsigned long end); |
77 | 77 | ||
78 | static inline void flush_cache_mm(struct mm_struct *mm) | 78 | static inline void flush_cache_mm(struct mm_struct *mm) |
79 | { | 79 | { |
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c index dc47e53e9e28..28c511b06edf 100644 --- a/arch/arm64/kernel/sys_compat.c +++ b/arch/arm64/kernel/sys_compat.c | |||
@@ -28,29 +28,39 @@ | |||
28 | #include <asm/cacheflush.h> | 28 | #include <asm/cacheflush.h> |
29 | #include <asm/unistd.h> | 29 | #include <asm/unistd.h> |
30 | 30 | ||
31 | static inline void | 31 | static long |
32 | do_compat_cache_op(unsigned long start, unsigned long end, int flags) | 32 | __do_compat_cache_op(unsigned long start, unsigned long end) |
33 | { | 33 | { |
34 | struct mm_struct *mm = current->active_mm; | 34 | long ret; |
35 | struct vm_area_struct *vma; | ||
36 | 35 | ||
37 | if (end < start || flags) | 36 | do { |
38 | return; | 37 | unsigned long chunk = min(PAGE_SIZE, end - start); |
39 | 38 | ||
40 | down_read(&mm->mmap_sem); | 39 | if (fatal_signal_pending(current)) |
41 | vma = find_vma(mm, start); | 40 | return 0; |
42 | if (vma && vma->vm_start < end) { | 41 | |
43 | if (start < vma->vm_start) | 42 | ret = __flush_cache_user_range(start, start + chunk); |
44 | start = vma->vm_start; | 43 | if (ret) |
45 | if (end > vma->vm_end) | 44 | return ret; |
46 | end = vma->vm_end; | 45 | |
47 | up_read(&mm->mmap_sem); | 46 | cond_resched(); |
48 | __flush_cache_user_range(start & PAGE_MASK, PAGE_ALIGN(end)); | 47 | start += chunk; |
49 | return; | 48 | } while (start < end); |
50 | } | 49 | |
51 | up_read(&mm->mmap_sem); | 50 | return 0; |
52 | } | 51 | } |
53 | 52 | ||
53 | static inline long | ||
54 | do_compat_cache_op(unsigned long start, unsigned long end, int flags) | ||
55 | { | ||
56 | if (end < start || flags) | ||
57 | return -EINVAL; | ||
58 | |||
59 | if (!access_ok(VERIFY_READ, start, end - start)) | ||
60 | return -EFAULT; | ||
61 | |||
62 | return __do_compat_cache_op(start, end); | ||
63 | } | ||
54 | /* | 64 | /* |
55 | * Handle all unrecognised system calls. | 65 | * Handle all unrecognised system calls. |
56 | */ | 66 | */ |
@@ -74,8 +84,7 @@ long compat_arm_syscall(struct pt_regs *regs) | |||
74 | * the specified region). | 84 | * the specified region). |
75 | */ | 85 | */ |
76 | case __ARM_NR_compat_cacheflush: | 86 | case __ARM_NR_compat_cacheflush: |
77 | do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]); | 87 | return do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]); |
78 | return 0; | ||
79 | 88 | ||
80 | case __ARM_NR_compat_set_tls: | 89 | case __ARM_NR_compat_set_tls: |
81 | current->thread.tp_value = regs->regs[0]; | 90 | current->thread.tp_value = regs->regs[0]; |
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 8eaf18577d71..2560e1e1562e 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S | |||
@@ -17,6 +17,7 @@ | |||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/errno.h> | ||
20 | #include <linux/linkage.h> | 21 | #include <linux/linkage.h> |
21 | #include <linux/init.h> | 22 | #include <linux/init.h> |
22 | #include <asm/assembler.h> | 23 | #include <asm/assembler.h> |
@@ -140,9 +141,12 @@ USER(9f, ic ivau, x4 ) // invalidate I line PoU | |||
140 | add x4, x4, x2 | 141 | add x4, x4, x2 |
141 | cmp x4, x1 | 142 | cmp x4, x1 |
142 | b.lo 1b | 143 | b.lo 1b |
143 | 9: // ignore any faulting cache operation | ||
144 | dsb ish | 144 | dsb ish |
145 | isb | 145 | isb |
146 | mov x0, #0 | ||
147 | ret | ||
148 | 9: | ||
149 | mov x0, #-EFAULT | ||
146 | ret | 150 | ret |
147 | ENDPROC(flush_icache_range) | 151 | ENDPROC(flush_icache_range) |
148 | ENDPROC(__flush_cache_user_range) | 152 | ENDPROC(__flush_cache_user_range) |