Re: [PATCH] m68knommu: remove set_fs()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jul 5, 2021 at 1:46 AM Geert Uytterhoeven <geert@xxxxxxxxxxxxxx> wrote:

Probably this should be

    select SET_FS if CPU_HAS_ADDRESS_SPACES

Actually, I don't think m68k has a single real "set_fs()" at all, and
it should just be converted as-is to not use CONFIG_SET_FS.

Yes, there is a "set_fs()" function, but none of the remaining uses
actually are the traditional kernel style of "use kernel addresses as
user addresses". So as far as the *kernel* is concerned, m68k already
looks like a no-SET_FS architecture, and "set-fs()" is purely a
syntactic thing.

So I think the right thing to do looks something like this:

 - make the rule be that SFC/DFC is always normally USER_DATA

 - the special m68k sequences that need to play with special segments
will always do

        preempt_disable();
        set_segment(..whatever segment they need..);
        .. do the special operation ..
        set_segment(USER_DATA);
        preempt_enable();

 - set_fs() goes away entirely, because the user access functions
always work on USER_DATA and SFC/DFC is always right for them.

Anyway, I'm attaching a COMPLETELY UNTESTED AND ALMOST CERTAINLY VERY
VERY BROKEN patch that is likely not at all correct, but shows what I
think the solution should be.

The important thing is really just the removal of SET_FS entirely, the
rest is me winging it.

NOTE! The above very much assumes that all the special non-USER_DATA
accesses can always be done with preemption disabled. Why? Because I
also made the context switching always just save USER_DATA as the
segment. I didn't *remove* the segment switching - because I'm not
sure if that "just disable preemption across things that do segment
games" is actually valid.

So *if* that preempt_disable/enable is ok, then the segment switching
can just be removed entirely at context switch time.

And if it is *not* ok, then the preempt_disable/enable should go away,
and the context switch should save/restore the actual SFC/DFC value.

Again - let me be very very clear: the only m68k I've ever used was a
68008. It didn't have segments. This patch is COMPLETE GARBAGE. Do not
trust it. Do not use it for anything but a "Linus suggests maybe
something along these lines could work".

This has not even been build-tested, and I'm pretty sure it won't
build as-is. It really is a "Linus did some pattern matching and a few
grep's".

Oh, and if the magical SFC/DFC games can happen in interrupts, then
the "preempt_disable/enable" actually needs to be a full interrupt
disable/enable, or the code needs to re-introduce that "save old
value, restore it". So that's another assumption this example patch
makes - that the SFC/DFC games only happen in process context. Which
may be complete garbage too.

Did I mention that I think this patch is garbage? Because it really is.

                Linus
 arch/m68k/Kconfig                |  1 -
 arch/m68k/include/asm/segment.h  | 21 +++------------------
 arch/m68k/include/asm/tlbflush.h |  7 ++++---
 arch/m68k/kernel/process.c       |  2 +-
 arch/m68k/kernel/traps.c         | 16 ++++++++--------
 arch/m68k/mm/cache.c             | 23 ++++++++++++++---------
 arch/m68k/mm/init.c              |  2 +-
 arch/m68k/mm/motorola.c          |  2 +-
 arch/m68k/sun3/config.c          |  2 +-
 arch/m68k/sun3/mmu_emu.c         |  7 ++++---
 10 files changed, 37 insertions(+), 46 deletions(-)

diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 96989ad46f66..3a83013f0a96 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -32,7 +32,6 @@ config M68K
 	select NO_DMA if !MMU && !COLDFIRE
 	select OLD_SIGACTION
 	select OLD_SIGSUSPEND3
-	select SET_FS
 	select UACCESS_MEMCPY if !MMU
 	select VIRT_TO_BUS
 	select ZONE_DMA
diff --git a/arch/m68k/include/asm/segment.h b/arch/m68k/include/asm/segment.h
index 2b5e68a71ef7..a9fabf7d2a2c 100644
--- a/arch/m68k/include/asm/segment.h
+++ b/arch/m68k/include/asm/segment.h
@@ -26,19 +26,9 @@ typedef struct {
 
 #ifdef CONFIG_CPU_HAS_ADDRESS_SPACES
 /*
- * Get/set the SFC/DFC registers for MOVES instructions
+ * Set the SFC/DFC registers for MOVES instructions
  */
-#define USER_DS		MAKE_MM_SEG(__USER_DS)
-#define KERNEL_DS	MAKE_MM_SEG(__KERNEL_DS)
-
-static inline mm_segment_t get_fs(void)
-{
-	mm_segment_t _v;
-	__asm__ ("movec %/dfc,%0":"=r" (_v.seg):);
-	return _v;
-}
-
-static inline void set_fs(mm_segment_t val)
+static inline void set_segment(mm_segment_t val)
 {
 	__asm__ __volatile__ ("movec %0,%/sfc\n\t"
 			      "movec %0,%/dfc\n\t"
@@ -46,14 +36,9 @@ static inline void set_fs(mm_segment_t val)
 }
 
 #else
-#define USER_DS		MAKE_MM_SEG(TASK_SIZE)
-#define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
-#define get_fs()	(current_thread_info()->addr_limit)
-#define set_fs(x)	(current_thread_info()->addr_limit = (x))
+#define set_segment(x)	((void)(x))
 #endif
 
-#define uaccess_kernel()	(get_fs().seg == KERNEL_DS.seg)
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _M68K_SEGMENT_H */
diff --git a/arch/m68k/include/asm/tlbflush.h b/arch/m68k/include/asm/tlbflush.h
index a6318ccd308f..3c9e35c7e93f 100644
--- a/arch/m68k/include/asm/tlbflush.h
+++ b/arch/m68k/include/asm/tlbflush.h
@@ -13,13 +13,14 @@ 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) {
-		mm_segment_t old_fs = get_fs();
-		set_fs(KERNEL_DS);
+		preempt_disable();
+		set_segment(SUPER_DATA);
 		__asm__ __volatile__(".chip 68040\n\t"
 				     "pflush (%0)\n\t"
 				     ".chip 68k"
 				     : : "a" (addr));
-		set_fs(old_fs);
+		set_segment(USER_DATA);
+		preempt_enable();
 	} else if (CPU_IS_020_OR_030)
 		__asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr));
 }
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index db49f9091711..a176d00ffc97 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.fs = get_fs().seg;
+	p->thread.fs = USER_DATA.seg;
 
 	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 9e1261462bcc..85863181466c 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -181,9 +181,9 @@ static inline void access_error060 (struct frame *fp)
 static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
 {
 	unsigned long mmusr;
-	mm_segment_t old_fs = get_fs();
 
-	set_fs(MAKE_MM_SEG(wbs));
+	preempt_disable();
+	set_segment(MAKE_MM_SEG(wbs));
 
 	if (iswrite)
 		asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr));
@@ -192,7 +192,8 @@ static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
 
 	asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr));
 
-	set_fs(old_fs);
+	set_segment(USER_DATA);
+	preempt_enable();
 
 	return mmusr;
 }
@@ -201,10 +202,9 @@ static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
 				   unsigned long wbd)
 {
 	int res = 0;
-	mm_segment_t old_fs = get_fs();
 
-	/* set_fs can not be moved, otherwise put_user() may oops */
-	set_fs(MAKE_MM_SEG(wbs));
+	preempt_disable();
+	set_segment(MAKE_MM_SEG(wbs));
 
 	switch (wbs & WBSIZ_040) {
 	case BA_SIZE_BYTE:
@@ -218,8 +218,8 @@ static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
 		break;
 	}
 
-	/* set_fs can not be moved, otherwise put_user() may oops */
-	set_fs(old_fs);
+	set_segment(USER_DATA);
+	preempt_enable();
 
 
 	pr_debug("do_040writeback1, res=%d\n", res);
diff --git a/arch/m68k/mm/cache.c b/arch/m68k/mm/cache.c
index b486c0889eec..80e311aa924d 100644
--- a/arch/m68k/mm/cache.c
+++ b/arch/m68k/mm/cache.c
@@ -12,7 +12,7 @@
 #include <asm/traps.h>
 
 
-static unsigned long virt_to_phys_slow(unsigned long vaddr)
+static unsigned long virt_to_phys_slow(unsigned long vaddr, mm_segment_t seg)
 {
 	if (CPU_IS_060) {
 		unsigned long paddr;
@@ -55,7 +55,7 @@ static unsigned long virt_to_phys_slow(unsigned long vaddr)
 		asm volatile ("ptestr %3,%2@,#7,%0\n\t"
 			      "pmove %%psr,%1"
 			      : "=a&" (descaddr), "=m" (mmusr)
-			      : "a" (vaddr), "d" (get_fs().seg));
+			      : "a" (vaddr), "d" (seg.seg));
 		if (mmusr & (MMU_I|MMU_B|MMU_L))
 			return 0;
 		descaddr = phys_to_virt((unsigned long)descaddr);
@@ -73,7 +73,7 @@ static unsigned long virt_to_phys_slow(unsigned long vaddr)
 
 /* Push n pages at kernel virtual address and clear the icache */
 /* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
-void flush_icache_user_range(unsigned long address, unsigned long endaddr)
+static void do_flush_icache_user_range(unsigned long address, unsigned long endaddr, mm_segment_t seg)
 {
 	if (CPU_IS_COLDFIRE) {
 		unsigned long start, end;
@@ -92,7 +92,7 @@ void flush_icache_user_range(unsigned long address, unsigned long endaddr)
 				      ".chip 68040\n\t"
 				      "cpushp %%bc,(%0)\n\t"
 				      ".chip 68k"
-				      : : "a" (virt_to_phys_slow(address)));
+				      : : "a" (virt_to_phys_slow(address, seg)));
 			address += PAGE_SIZE;
 		} while (address < endaddr);
 	} else {
@@ -105,13 +105,18 @@ void flush_icache_user_range(unsigned long address, unsigned long endaddr)
 	}
 }
 
-void flush_icache_range(unsigned long address, unsigned long endaddr)
+void flush_icache_user_range(unsigned long address, unsigned long endaddr)
 {
-	mm_segment_t old_fs = get_fs();
+	do_flush_icache_range(address, endaddr, USER_DATA);
+}
 
-	set_fs(KERNEL_DS);
-	flush_icache_user_range(address, endaddr);
-	set_fs(old_fs);
+void flush_icache_range(unsigned long address, unsigned long endaddr)
+{
+	preempt_disable();
+	set_segment(SUPER_DATA);
+	do_flush_icache_range(address, endaddr, SUPER_DATA);
+	set_segment(USER_DATA);
+	preempt_enable();
 }
 EXPORT_SYMBOL(flush_icache_range);
 
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 5d749e188246..4a7a56139013 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -76,7 +76,7 @@ void __init paging_init(void)
 	/*
 	 * Set up SFC/DFC registers (user data space).
 	 */
-	set_fs (USER_DS);
+	set_segment(USER_DATA);
 
 	max_zone_pfn[ZONE_DMA] = end_mem >> PAGE_SHIFT;
 	free_area_init(max_zone_pfn);
diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c
index 3a653f0a4188..7af7d5a1ac77 100644
--- a/arch/m68k/mm/motorola.c
+++ b/arch/m68k/mm/motorola.c
@@ -467,7 +467,7 @@ void __init paging_init(void)
 	/*
 	 * Set up SFC/DFC registers
 	 */
-	set_fs(KERNEL_DS);
+	set_segment(USER_DATA);
 
 #ifdef DEBUG
 	printk ("before free_area_init\n");
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index f7dd47232b6c..849457dbb424 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -89,7 +89,7 @@ void __init sun3_init(void)
 	sun3_reserved_pmeg[249] = 1;
 	sun3_reserved_pmeg[252] = 1;
 	sun3_reserved_pmeg[253] = 1;
-	set_fs(KERNEL_DS);
+	set_segment(USER_DATA);
 }
 
 /* Without this, Bad Things happen when something calls arch_reset. */
diff --git a/arch/m68k/sun3/mmu_emu.c b/arch/m68k/sun3/mmu_emu.c
index 7aa879b7c7ff..2bcf7e9822e6 100644
--- a/arch/m68k/sun3/mmu_emu.c
+++ b/arch/m68k/sun3/mmu_emu.c
@@ -191,14 +191,15 @@ void __init mmu_emu_init(unsigned long bootmem_end)
 	for(seg = 0; seg < PAGE_OFFSET; seg += SUN3_PMEG_SIZE)
 		sun3_put_segmap(seg, SUN3_INVALID_PMEG);
 
-	set_fs(MAKE_MM_SEG(3));
+	preempt_disable();
+	set_segment(MAKE_MM_SEG(3));
 	for(seg = 0; seg < 0x10000000; seg += SUN3_PMEG_SIZE) {
 		i = sun3_get_segmap(seg);
 		for(j = 1; j < CONTEXTS_NUM; j++)
 			(*(romvec->pv_setctxt))(j, (void *)seg, i);
 	}
-	set_fs(KERNEL_DS);
-
+	set_segment(USER_DATA);
+	preempt_enable();
 }
 
 /* erase the mappings for a dead context.  Uses the pg_dir for hints

[Index of Archives]     [Video for Linux]     [Yosemite News]     [Linux S/390]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux