From fcb3f2543125ca3fe269b50646f8c4782d31ba80 Mon Sep 17 00:00:00 2001 From: Michael Schmitz Date: Sun, 1 Aug 2021 12:11:59 +1200 Subject: [PATCH 1/2] m68k: add get_fc() to read uaccess mode Add back get_fc(), force_user_fc_begin() and force_user_fc_end(), and use these to restore original DFC after uaccess operations, instead of unconditionally setting USER_DATA. Signed-off-by: Michael Schmitz --- arch/m68k/include/asm/processor.h | 35 +++++++++++++++++++++++++++++++++++ arch/m68k/include/asm/tlbflush.h | 8 ++++++-- arch/m68k/kernel/process.c | 2 +- arch/m68k/kernel/traps.c | 6 ++++-- arch/m68k/mm/cache.c | 4 +++- 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index debb453..29dfa54 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -94,10 +94,45 @@ static inline void set_fc(unsigned long val) "movec %0,%/dfc\n\t" : /* no outputs */ : "r" (val) : "memory"); } +static inline unsigned long get_fc(void) +{ + unsigned long val; + __asm__ ("movec %/dfc,%0":"=r" (val):); + return val; +} +/* + * Force the uaccess routines to be wired up for actual userspace access, + * overriding any possible set_fs(KERNEL_DS) still lingering around. Undone + * using force_uaccess_end below. + */ +static inline unsigned long force_user_fc_begin(void) +{ + unsigned long fc = get_fc(); + + set_fc(USER_DATA); + return fc; +} + +static inline void force_user_fc_end(unsigned long oldfc) +{ + set_fc(oldfc); +} #else static inline void set_fc(unsigned long val) { } +static inline unsigned long get_fs(void) +{ + return USER_DATA; +} +static inline unsigned long force_user_fc_begin(void) +{ + return USER_DATA; +} + +static inline void force_user_fc_end(unsigned long oldfc) +{ +} #endif /* CONFIG_CPU_HAS_ADDRESS_SPACES */ struct thread_struct { diff --git a/arch/m68k/include/asm/tlbflush.h b/arch/m68k/include/asm/tlbflush.h index 524b13d..7c34d14 100644 --- a/arch/m68k/include/asm/tlbflush.h +++ b/arch/m68k/include/asm/tlbflush.h @@ -13,12 +13,13 @@ static inline void flush_tlb_kernel_page(void *addr) if (CPU_IS_COLDFIRE) { mmu_write(MMUOR, MMUOR_CNL); } else if (CPU_IS_040_OR_060) { + unsigned long old_fc = get_fc(); set_fc(SUPER_DATA); __asm__ __volatile__(".chip 68040\n\t" "pflush (%0)\n\t" ".chip 68k" : : "a" (addr)); - set_fc(USER_DATA); + set_fc(old_fc); } else if (CPU_IS_020_OR_030) __asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr)); } @@ -83,8 +84,11 @@ static inline void flush_tlb_mm(struct mm_struct *mm) static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { - if (vma->vm_mm == current->active_mm) + if (vma->vm_mm == current->active_mm) { + unsigned long old_fc = force_user_fc_begin(); __flush_tlb_one(addr); + force_user_fc_end(old_fc); + } } static inline void flush_tlb_range(struct vm_area_struct *vma, diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index fb257b7..cab012d 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -155,7 +155,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, * Must save the current SFC/DFC value, NOT the value when * the parent was last descheduled - RGH 10-08-96 */ - p->thread.fc = USER_DATA; + p->thread.fc = get_fc(); if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { /* kernel thread */ diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index c5e0a4f..1b07329 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -181,6 +181,7 @@ static inline void access_error060 (struct frame *fp) static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs) { unsigned long mmusr; + unsigned long old_fc = get_fc(); set_fc(wbs); @@ -191,7 +192,7 @@ static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs) asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr)); - set_fc(USER_DATA); + set_fc(old_fc); return mmusr; } @@ -200,6 +201,7 @@ static inline int do_040writeback1(unsigned short wbs, unsigned long wba, unsigned long wbd) { int res = 0; + unsigned long old_fc = get_fc(); set_fc(wbs); @@ -215,7 +217,7 @@ static inline int do_040writeback1(unsigned short wbs, unsigned long wba, break; } - set_fc(USER_DATA); + set_fc(old_fc); pr_debug("do_040writeback1, res=%d\n", res); diff --git a/arch/m68k/mm/cache.c b/arch/m68k/mm/cache.c index d26eb1a..70fd62b 100644 --- a/arch/m68k/mm/cache.c +++ b/arch/m68k/mm/cache.c @@ -109,14 +109,16 @@ static void __flush_icache_range(unsigned long address, unsigned long endaddr, void flush_icache_user_range(unsigned long address, unsigned long endaddr) { + unsigned long old_fc = get_fc(); __flush_icache_range(address, endaddr, USER_DATA); } void flush_icache_range(unsigned long address, unsigned long endaddr) { + unsigned long old_fc = get_fc(); set_fc(SUPER_DATA); __flush_icache_range(address, endaddr, SUPER_DATA); - set_fc(USER_DATA); + set_fc(old_fc); } EXPORT_SYMBOL(flush_icache_range); -- 2.7.4