To: linux-m68k@lists.linux-m68k.org
Subject: L68K: Make PROT_NONE working
X-Yow: Is this TERMINAL fun?
From: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
Date: 17 Nov 1997 10:52:33 +0100
Sender: owner-linux-m68k@phil.uni-sb.de

Currently the PROT_NONE protection mode does not work: as soon as such a
page is allocated by the kernel it is freely readable without causing
access errors.  For example if you mmap a region of memory with a
protection mode other than PROT_NONE and then change the protection of
some pages to PROT_NONE with mprotect those pages will still be readable.
This causes Electric Fence to fail.  The following patch fixes this bug.
For the m680[46]0 this is easy: just set the S bit in the page descriptor
to protect it from user access.  Note: i'm assuming that the '060 page
descriptor has the same S bit as the '040 (i'm still waiting for the
m68060 manual to arrive).  On the 680[23]0 unfortunately the S bit is only
available in the long format page descriptor (although the short format
descriptor still has enough reserved bits :-( ).  I had to fake the S bit
by using an encoding that is still considered invalid by the MMU, but is
distinguishable from both an absent page and a swapped out page.  With
these changes Electric Fence now works correctly.

Andreas.

--- linux/arch/m68k/mm/init.c.~1~	Tue Oct  7 22:35:28 1997
+++ linux/arch/m68k/mm/init.c	Sun Nov 16 00:40:46 1997
@@ -319,6 +319,18 @@
 		for (i = 0; i < 16; i++)
 			pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
 	}
+	/* Fix the PAGE_NONE value. */
+	if (CPU_IS_040_OR_060) {
+		/* On the 680[46]0 we can use the _PAGE_SUPER bit.  */
+		pgprot_val(protection_map[0]) |= _PAGE_SUPER;
+		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER;
+	} else {
+		/* Otherwise we must fake it. */
+		pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT;
+		pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER;
+		pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT;
+		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER;
+	}
 
 	/*
 	 * Map the physical memory available into the kernel virtual
--- linux/include/asm-m68k/pgtable.h.~1~	Fri Nov  7 19:16:09 1997
+++ linux/include/asm-m68k/pgtable.h	Sun Nov 16 00:40:29 1997
@@ -300,6 +300,8 @@
 #define _PAGE_RONLY	0x004
 #define _PAGE_ACCESSED	0x008
 #define _PAGE_DIRTY	0x010
+#define _PAGE_SUPER	0x080	/* 68040 supervisor only */
+#define _PAGE_FAKE_SUPER 0x200	/* fake supervisor only on 680[23]0 */
 #define _PAGE_GLOBAL040	0x400	/* 68040 global bit, used for kva descs */
 #define _PAGE_COW	0x800	/* implemented in software */
 #define _PAGE_NOCACHE030 0x040	/* 68030 no-cache mode */
@@ -442,7 +444,7 @@
 { return PTOV(pgd_val(pgd) & _TABLE_MASK); }
 
 extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
-extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
+extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & (_PAGE_PRESENT | _PAGE_FAKE_SUPER); }
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
 
 extern inline int pmd_none2(pmd_t *pmd)		{ return !pmd_val(*pmd); }
@@ -763,6 +765,8 @@
  * I don't know what is going on here, but since these were changed,
  * swapping hasn't been working on the 68040.
  */
+/* With the new handling of PAGE_NONE the old definitions definitely
+   don't work any more.  */
 
 #define SWP_TYPE(entry)  (((entry) >> 2) & 0x7f)
 #if 0
