Commit 68ca3e53 authored by Haavard Skinnemoen's avatar Haavard Skinnemoen

[AVR32] Fix copy_to_user_page() breakage

The current implementation of copy_to_user_page() gives "vaddr" to the
cache instruction when trying to sync the icache with the dcache. If
vaddr does not exist in the TLB, the CPU will silently abort the
operation, which may result in the caches staying out of sync.

To fix this, pass the "dst" parameter to flush_icache_range() instead
-- we know this is valid because we just wrote to it.
Signed-off-by: default avatarHaavard Skinnemoen <hskinnemoen@atmel.com>
parent 2507bc13
...@@ -122,16 +122,6 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *page) ...@@ -122,16 +122,6 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *page)
} }
} }
/*
* This one is used by copy_to_user_page()
*/
void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
unsigned long addr, int len)
{
if (vma->vm_flags & VM_EXEC)
flush_icache_range(addr, addr + len);
}
asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len) asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
{ {
int ret; int ret;
...@@ -159,3 +149,13 @@ asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len) ...@@ -159,3 +149,13 @@ asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
out: out:
return ret; return ret;
} }
void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, const void *src,
unsigned long len)
{
memcpy(dst, src, len);
if (vma->vm_flags & VM_EXEC)
flush_icache_range((unsigned long)dst,
(unsigned long)dst + len);
}
...@@ -116,15 +116,16 @@ extern void flush_icache_page(struct vm_area_struct *vma, struct page *page); ...@@ -116,15 +116,16 @@ extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
* flush with all configurations. * flush with all configurations.
*/ */
extern void flush_icache_range(unsigned long start, unsigned long end); extern void flush_icache_range(unsigned long start, unsigned long end);
extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page,
unsigned long addr, int len);
#define copy_to_user_page(vma, page, vaddr, dst, src, len) do { \ extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
memcpy(dst, src, len); \ unsigned long vaddr, void *dst, const void *src,
flush_icache_user_range(vma, page, vaddr, len); \ unsigned long len);
} while(0)
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ static inline void copy_from_user_page(struct vm_area_struct *vma,
memcpy(dst, src, len) struct page *page, unsigned long vaddr, void *dst,
const void *src, unsigned long len)
{
memcpy(dst, src, len);
}
#endif /* __ASM_AVR32_CACHEFLUSH_H */ #endif /* __ASM_AVR32_CACHEFLUSH_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment