[PATCH] microblaze: fix instruction cache invalidation

From: Romeo Cane
Date: Mon May 23 2016 - 09:46:24 EST



Microblaze invalidates the instruction cache via WIC opcode which,
unlike WDC for data cache, requires the virtual address of the target
location when MMU is used. The current code always uses the physical
address, preventing the instruction cache to be properly invalidated
and exposing the risk of user space applications to crash with
signal 4 (illegal instruction) when executing the trampoline code in return
from a signal handler.
Same issue when the code is modified via copy_to_user_page.
This patch fixes the calls to instruction cache invalidation using
the correct addresses.

Signed-off-by: Romeo Cane <romeo.cane@xxxxxxxxxxxx>
---
arch/microblaze/include/asm/cacheflush.h | 6 +++---
arch/microblaze/kernel/signal.c | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h
index ffea82a..c978e64 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -106,11 +106,11 @@ static inline void copy_to_user_page(struct vm_area_struct *vma,
struct page *page, unsigned long vaddr,
void *dst, void *src, int len)
{
- u32 addr = virt_to_phys(dst);
+ u32 paddr = virt_to_phys(dst);
memcpy(dst, src, len);
if (vma->vm_flags & VM_EXEC) {
- invalidate_icache_range(addr, addr + PAGE_SIZE);
- flush_dcache_range(addr, addr + PAGE_SIZE);
+ invalidate_icache_range(vaddr, vaddr + PAGE_SIZE);
+ flush_dcache_range(paddr, paddr + PAGE_SIZE);
}
}

diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 9700152..757dd40 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -200,6 +200,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
address), address);

preempt_disable();
+ invalidate_icache_range(address, address + 8);
ptep = pte_offset_map(pmdp, address);
if (pte_present(*ptep)) {
address = (unsigned long) page_address(pte_page(*ptep));
@@ -207,7 +208,6 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
address += ((unsigned long)frame->tramp) & ~PAGE_MASK;
/* MS address is virtual */
address = __virt_to_phys(address);
- invalidate_icache_range(address, address + 8);
flush_dcache_range(address, address + 8);
}
pte_unmap(ptep);
--
1.9.1