From 6d243dd37002bcee54841852ab1b8606fd457851 Mon Sep 17 00:00:00 2001 From: Stuart Menefy Date: Mon, 24 Aug 2009 18:16:56 +0900 Subject: [PATCH] sh: Add sys_cacheflush() call for SH CPUs. Adds a system call to allow user code to flush code from the cache. You can use instructions for the data side, but the iside can only be done by a flush ROM which really only works with a direct mapped cache. The later SH4's have 2 way Iside, so this call allows a portable way to flush the cache. Signed-off-by: Stuart Menefy Signed-off-by: Paul Mundt --- arch/sh/include/asm/Kbuild | 2 +- arch/sh/include/asm/cachectl.h | 12 ++++++++++++ arch/sh/include/asm/unistd_32.h | 2 +- arch/sh/include/asm/unistd_64.h | 2 +- arch/sh/kernel/sys_sh.c | 43 +++++++++++++++++++++++++++++++++++++++++ arch/sh/kernel/syscalls_32.S | 2 +- arch/sh/kernel/syscalls_64.S | 2 +- 7 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 arch/sh/include/asm/cachectl.h diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild index 43910cd..e121c30 100644 --- a/arch/sh/include/asm/Kbuild +++ b/arch/sh/include/asm/Kbuild @@ -1,6 +1,6 @@ include include/asm-generic/Kbuild.asm -header-y += cpu-features.h +header-y += cachectl.h cpu-features.h unifdef-y += unistd_32.h unifdef-y += unistd_64.h diff --git a/arch/sh/include/asm/cachectl.h b/arch/sh/include/asm/cachectl.h new file mode 100644 index 0000000..305dd70 --- /dev/null +++ b/arch/sh/include/asm/cachectl.h @@ -0,0 +1,12 @@ +#ifndef _SH_CACHECTL_H +#define _SH_CACHECTL_H + +/* Definitions for the cacheflush system call. */ + +#define CACHEFLUSH_D_INVAL 0x1 /* invalidate (without write back) */ +#define CACHEFLUSH_D_WB 0x2 /* write back (without invalidate) */ +#define CACHEFLUSH_D_PURGE 0x3 /* writeback and invalidate */ + +#define CACHEFLUSH_I 0x4 + +#endif /* _SH_CACHECTL_H */ diff --git a/arch/sh/include/asm/unistd_32.h b/arch/sh/include/asm/unistd_32.h index 61d6ad9..925dd40 100644 --- a/arch/sh/include/asm/unistd_32.h +++ b/arch/sh/include/asm/unistd_32.h @@ -132,7 +132,7 @@ #define __NR_clone 120 #define __NR_setdomainname 121 #define __NR_uname 122 -#define __NR_modify_ldt 123 +#define __NR_cacheflush 123 #define __NR_adjtimex 124 #define __NR_mprotect 125 #define __NR_sigprocmask 126 diff --git a/arch/sh/include/asm/unistd_64.h b/arch/sh/include/asm/unistd_64.h index a751699..2b84bc9 100644 --- a/arch/sh/include/asm/unistd_64.h +++ b/arch/sh/include/asm/unistd_64.h @@ -137,7 +137,7 @@ #define __NR_clone 120 #define __NR_setdomainname 121 #define __NR_uname 122 -#define __NR_modify_ldt 123 +#define __NR_cacheflush 123 #define __NR_adjtimex 124 #define __NR_mprotect 125 #define __NR_sigprocmask 126 diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 90d00e4..ec65dd8 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include static inline long do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, @@ -179,6 +181,47 @@ asmlinkage int sys_ipc(uint call, int first, int second, return -EINVAL; } +/* sys_cacheflush -- flush (part of) the processor cache. */ +asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op) +{ + struct vm_area_struct *vma; + + if ((op < 0) || (op > (CACHEFLUSH_D_PURGE|CACHEFLUSH_I))) + return -EINVAL; + + /* + * Verify that the specified address region actually belongs + * to this process. + */ + if (addr + len < addr) + return -EFAULT; + + down_read(¤t->mm->mmap_sem); + vma = find_vma (current->mm, addr); + if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) { + up_read(¤t->mm->mmap_sem); + return -EFAULT; + } + + switch (op & CACHEFLUSH_D_PURGE) { + case CACHEFLUSH_D_INVAL: + __flush_invalidate_region((void *)addr, len); + break; + case CACHEFLUSH_D_WB: + __flush_wback_region((void *)addr, len); + break; + case CACHEFLUSH_D_PURGE: + __flush_purge_region((void *)addr, len); + break; + } + + if (op & CACHEFLUSH_I) + flush_cache_all(); + + up_read(¤t->mm->mmap_sem); + return 0; +} + asmlinkage int sys_uname(struct old_utsname __user *name) { int err; diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index f9e21fa..16ba225 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -139,7 +139,7 @@ ENTRY(sys_call_table) .long sys_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_ni_syscall /* sys_modify_ldt */ + .long sys_cacheflush /* x86: sys_modify_ldt */ .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index bf420b6..af6fb74 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -143,7 +143,7 @@ sys_call_table: .long sys_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_ni_syscall /* sys_modify_ldt */ + .long sys_cacheflush /* x86: sys_modify_ldt */ .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask -- 2.7.4