shithub: riscv

Download patch

ref: 128ea44a89c7905612ad2fa5a61a9325ddfb5e1e
parent: 91a8d03040a3533e27f51d33bbbfed33d84b5043
author: cinap_lenrek <[email protected]>
date: Mon Aug 26 18:34:38 EDT 2019

kernel: expose no execute bit to portable mmu code as SG_NOEXEC / PTENOEXEC, add PTECACHED bits

a portable SG_NOEXEC segment attribute was added to allow
non-executable (physical) segments. which will set the
PTENOEXEC bits for putmmu().

in the future, this can be used to make non-executable
stack / bss segments.

the SG_DEVICE attribute was added to distinguish between
mmio regions and uncached memory. only matterns on arm64.

on arm, theres the issue that PTEUNCACHED would have
no bits set when using the hardware bit definitions.
this is the reason bcm, kw, teg2 and omap kernels use
arteficial PTE constants. on zynq, the XN bit was used
as a hack to give PTEUNCACHED a non-zero value and when
the bit is clear then cache attributes where added to
the pte.

to fix this, PTECACHED constant was added.

the portable mmu code in fault.c will now explicitely set
PTECACHED bits for cached memory and PTEUNCACHED for
uncached memory. that way the hardware bit definitions
can be used everywhere.

--- a/sys/src/9/bcm/arm.h
+++ b/sys/src/9/bcm/arm.h
@@ -293,6 +293,7 @@
 #define L1noexec	(1<<4)
 #define L2wralloc	(1<<6)			/* L2 TEX (small pages) */
 #define L2sharable	(1<<10)
+#define L2noexec	(1<<0)			/* L2 XN (small pages) */
 
 /* attributes for memory containing locks -- differs between armv6 and armv7 */
 //#define L1ptedramattrs	(Cached | Buffered | L1wralloc | L1sharable)
--- a/sys/src/9/bcm/gpio.c
+++ b/sys/src/9/bcm/gpio.c
@@ -130,7 +130,7 @@
 	Physseg seg;
 
 	memset(&seg, 0, sizeof seg);
-	seg.attr = SG_PHYSICAL;
+	seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
 	seg.name = "gpio";
 	seg.pa = (GPIOREGS - soc.virtio) + soc.physio;
 	seg.size = BY2PG;
--- a/sys/src/9/bcm/mem.h
+++ b/sys/src/9/bcm/mem.h
@@ -79,13 +79,15 @@
 #define	PPN(x)		((x)&~(BY2PG-1))
 
 /*
+ * These bits are completely artificial.
  * With a little work these move to port.
  */
 #define	PTEVALID	(1<<0)
 #define	PTERONLY	0
 #define	PTEWRITE	(1<<1)
+#define	PTECACHED	0
 #define	PTEUNCACHED	(1<<2)
-#define PTEKERNEL	(1<<3)
+#define	PTENOEXEC	(1<<4)
 
 /*
  * Physical machine information from here on.
--- a/sys/src/9/bcm/mmu.c
+++ b/sys/src/9/bcm/mmu.c
@@ -255,6 +255,8 @@
 		x |= L2AP(Urw);
 	else
 		x |= L2AP(Uro);
+	if(pa & PTENOEXEC)
+		x |= L2noexec;
 	pte[L2X(va)] = PPN(pa)|x;
 	cachedwbtlb(&pte[L2X(va)], sizeof(PTE));
 
--- a/sys/src/9/bcm64/mem.h
+++ b/sys/src/9/bcm64/mem.h
@@ -124,10 +124,12 @@
 #define PTEUSER		PTEAP(1)
 #define PTEWRITE	PTEAP(0)
 #define PTERONLY	PTEAP(2)
+#define PTENOEXEC	(PTEPXN|PTEUXN)
 
+#define PTECACHED	PTEMA(MA_MEM_WB)
 #define PTEWT		PTEMA(MA_MEM_WT)
-#define	PTEUNCACHED	PTEMA(MA_MEM_UC)
-#define	PTEDEVICE	PTEMA(MA_DEV_nGnRE)
+#define PTEUNCACHED	PTEMA(MA_MEM_UC)
+#define PTEDEVICE	PTEMA(MA_DEV_nGnRE)
 
 /*
  * Physical machine information from here on.
--- a/sys/src/9/bcm64/mmu.c
+++ b/sys/src/9/bcm64/mmu.c
@@ -453,7 +453,8 @@
 		flushasidvall((uvlong)up->asid<<48 | va>>12);
 	else
 		flushasidva((uvlong)up->asid<<48 | va>>12);
-	*pte = pa | PTEPAGE | PTEUSER | PTEPXN | PTENG | PTEAF | PTESH(SHARE_INNER);
+	*pte = pa | PTEPAGE | PTEUSER | PTEPXN | PTENG | PTEAF |
+		(((pa & PTEMA(7)) == PTECACHED)? PTESH(SHARE_INNER): PTESH(SHARE_OUTER));
 	if(pg->txtflush & (1UL<<m->machno)){
 		/* pio() sets PG_TXTFLUSH whenever a text pg has been written */
 		cachedwbinvse(kmap(pg), BY2PG);
--- a/sys/src/9/kw/mem.h
+++ b/sys/src/9/kw/mem.h
@@ -108,13 +108,14 @@
 #define	PPN(x)		((x)&~(BY2PG-1))
 
 /*
+ * These bits are completely artificial.
  * With a little work these move to port.
  */
 #define	PTEVALID	(1<<0)
 #define	PTERONLY	0
 #define	PTEWRITE	(1<<1)
+#define	PTECACHED	0
 #define	PTEUNCACHED	(1<<2)
-#define PTEKERNEL	(1<<3)
 
 /*
  * Physical machine information from here on.
--- a/sys/src/9/mtx/mem.h
+++ b/sys/src/9/mtx/mem.h
@@ -163,6 +163,7 @@
 #define	PTEWRITE		PTE1_RW
 #define	PTERONLY	PTE1_RO
 #define	PTEUNCACHED	PTE1_I
+#define	PTECACHED	0
 
 /*
  * Address spaces
--- a/sys/src/9/omap/mem.h
+++ b/sys/src/9/omap/mem.h
@@ -97,13 +97,14 @@
 #define	PPN(x)		((x)&~(BY2PG-1))	/* pure page number? */
 
 /*
+ * These bits are completely artificial.
  * With a little work these move to port.
  */
 #define	PTEVALID	(1<<0)
 #define	PTERONLY	0
 #define	PTEWRITE	(1<<1)
+#define	PTECACHED	0
 #define	PTEUNCACHED	(1<<2)
-#define PTEKERNEL	(1<<3)
 
 /*
  * Physical machine information from here on.
--- a/sys/src/9/pc/devlml.c
+++ b/sys/src/9/pc/devlml.c
@@ -185,7 +185,7 @@
 		}
 
 		memset(&segbuf, 0, sizeof(segbuf));
-		segbuf.attr = SG_PHYSICAL;
+		segbuf.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
 		sprint(name, "lml%d.regs", nlml);
 		kstrdup(&segbuf.name, name);
 		segbuf.pa = (ulong)regpa;
--- a/sys/src/9/pc/mem.h
+++ b/sys/src/9/pc/mem.h
@@ -156,6 +156,7 @@
 #define	PTEVALID	(1<<0)
 #define	PTEWT		(1<<3)
 #define	PTEUNCACHED	(1<<4)
+#define	PTECACHED	(0<<4)
 #define	PTEWRITE	(1<<1)
 #define	PTERONLY	(0<<1)
 #define	PTEKERNEL	(0<<2)
--- a/sys/src/9/pc/vga.c
+++ b/sys/src/9/pc/vga.c
@@ -257,7 +257,7 @@
 	Physseg seg;
 
 	memset(&seg, 0, sizeof seg);
-	seg.attr = SG_PHYSICAL;
+	seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
 	seg.name = name;
 	seg.pa = pa;
 	seg.size = size;
--- a/sys/src/9/pc64/mem.h
+++ b/sys/src/9/pc64/mem.h
@@ -151,6 +151,7 @@
 #define	PTEVALID	(1ull<<0)
 #define	PTEWT		(1ull<<3)
 #define	PTEUNCACHED	(1ull<<4)
+#define	PTECACHED	(0ull<<4)
 #define	PTEWRITE	(1ull<<1)
 #define	PTERONLY	(0ull<<1)
 #define	PTEKERNEL	(0ull<<2)
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -169,7 +169,7 @@
 		if(pagedout(*pg))
 			pio(s, addr, soff, pg);
 
-		mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
+		mmuphys = PPN((*pg)->pa) | PTERONLY | PTECACHED | PTEVALID;
 		(*pg)->modref = PG_REF;
 		break;
 
@@ -192,7 +192,7 @@
 		 *  we're the only user of the segment.
 		 */
 		if(read && conf.copymode == 0 && s->ref == 1) {
-			mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID;
+			mmuphys = PPN((*pg)->pa) | PTERONLY | PTECACHED | PTEVALID;
 			(*pg)->modref |= PG_REF;
 			break;
 		}
@@ -212,7 +212,7 @@
 		}
 		/* wet floor */
 	case SG_STICKY:			/* Never paged out */
-		mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
+		mmuphys = PPN((*pg)->pa) | PTEWRITE | PTECACHED | PTEVALID;
 		(*pg)->modref = PG_MOD|PG_REF;
 		break;
 
@@ -242,8 +242,24 @@
 	mmuphys = PPN(pg.pa) | PTEVALID;
 	if((attr & SG_RONLY) == 0)
 		mmuphys |= PTEWRITE;
+	else
+		mmuphys |= PTERONLY;
+
+#ifdef PTENOEXEC
+	if((attr & SG_NOEXEC) == SG_NOEXEC)
+		mmuphys |= PTENOEXEC;
+#endif
+
+#ifdef PTEDEVICE
+	if((attr & SG_DEVICE) == SG_DEVICE)
+		mmuphys |= PTEDEVICE;
+	else
+#endif
 	if((attr & SG_CACHED) == 0)
 		mmuphys |= PTEUNCACHED;
+	else
+		mmuphys |= PTECACHED;
+
 	qunlock(s);
 
 	putmmu(addr, mmuphys, &pg);
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -373,7 +373,9 @@
 	SG_RONLY	= 0040,		/* Segment is read only */
 	SG_CEXEC	= 0100,		/* Detach at exec */
 	SG_FAULT	= 0200,		/* Fault on access */
-	SG_CACHED	= 0400,
+	SG_CACHED	= 0400,		/* Normal cached memory */
+	SG_DEVICE	= 01000,	/* Memory mapped device */
+	SG_NOEXEC	= 02000,	/* No execute */
 };
 
 #define PG_ONSWAP	1
--- a/sys/src/9/port/sdram.c
+++ b/sys/src/9/port/sdram.c
@@ -104,7 +104,7 @@
 
 	rd->pa = base;
 	rd->size = size;
-	rd->attr = SG_CACHED;
+	rd->attr = SG_PHYSICAL | SG_CACHED | SG_NOEXEC;
 }
 
 static vlong
@@ -204,7 +204,7 @@
 	if(unit->sectors != 0)
 		return 1;
 
-	rd->seg = newseg(SG_PHYSICAL, UTZERO, rd->size/BY2PG);
+	rd->seg = newseg(rd->attr, UTZERO, rd->size/BY2PG);
 	if(rd->seg == nil)
 		return 0;
 	rd->seg->pseg = rd;
--- a/sys/src/9/ppc/m8260.c
+++ b/sys/src/9/ppc/m8260.c
@@ -441,7 +441,7 @@
 	Physseg segbuf;
 
 	memset(&segbuf, 0, sizeof(segbuf));
-	segbuf.attr = SG_PHYSICAL;
+	segbuf.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
 	kstrdup(&segbuf.name, name);
 	segbuf.pa = start;
 	segbuf.size = length;
--- a/sys/src/9/ppc/ucu.h
+++ b/sys/src/9/ppc/ucu.h
@@ -19,3 +19,4 @@
 #define	PTEWRITE		(PTE1_RW|PTE1_C)
 #define	PTERONLY	PTE1_RO
 #define	PTEUNCACHED	PTE1_I
+#define	PTECACHED	0
--- a/sys/src/9/sgi/mem.h
+++ b/sys/src/9/sgi/mem.h
@@ -241,8 +241,8 @@
 #define PTECOHERUPDW	(6<<3)
 
 /* how much faster is it? mflops goes from about .206 (WT) to .37 (WB) */
-// #define PTECACHABILITY PTENONCOHERWT	/* 24k erratum 48 disallows WB */
-#define PTECACHABILITY	PTENONCOHERWB
+// #define PTECACHED PTENONCOHERWT	/* 24k erratum 48 disallows WB */
+#define PTECACHED	PTENONCOHERWB
 
 #define	PTEPID(n)	(n)
 #define PTEMAPMEM	(1024*1024)
--- a/sys/src/9/sgi/mmu.c
+++ b/sys/src/9/sgi/mmu.c
@@ -180,14 +180,14 @@
 	virt |= KMAPADDR | ((k-kpte)<<KMAPSHIFT);
 
 	k->virt = virt;
-	pte = PPN(pg->pa)|PTECACHABILITY|PTEGLOBL|PTEWRITE|PTEVALID;
+	pte = PPN(pg->pa)|PTECACHED|PTEGLOBL|PTEWRITE|PTEVALID;
 	if(virt & BY2PG) {
-		k->phys0 = PTEGLOBL | PTECACHABILITY;
+		k->phys0 = PTEGLOBL | PTECACHED;
 		k->phys1 = pte;
 	}
 	else {
 		k->phys0 = pte;
-		k->phys1 = PTEGLOBL | PTECACHABILITY;
+		k->phys1 = PTEGLOBL | PTECACHED;
 	}
 
 	putktlb(k);
@@ -385,11 +385,6 @@
 		tp = newtlbpid(up);
 
 	tlbvirt |= PTEPID(tp);
-	if((tlbphys & PTEALGMASK) != PTEUNCACHED) {
-		tlbphys &= ~PTEALGMASK;
-		tlbphys |= PTECACHABILITY;
-	}
-
 	entry = putstlb(tlbvirt, tlbphys);
 	x = gettlbp(tlbvirt, tlbent);
 	if(x < 0) x = getrandom();
--- a/sys/src/9/teg2/mem.h
+++ b/sys/src/9/teg2/mem.h
@@ -114,13 +114,14 @@
 #define	PPN(x)		((x)&~(BY2PG-1))	/* pure page number? */
 
 /*
+ * These bits are completely artificial.
  * With a little work these move to port.
  */
 #define	PTEVALID	(1<<0)
 #define	PTERONLY	0
 #define	PTEWRITE	(1<<1)
+#define	PTECACHED	0
 #define	PTEUNCACHED	(1<<2)
-#define PTEKERNEL	(1<<3)
 
 /*
  * Physical machine information from here on.
--- a/sys/src/9/xen/mem.h
+++ b/sys/src/9/xen/mem.h
@@ -86,6 +86,7 @@
 #define	PTEVALID	(1<<0)
 #define	PTEWT		(1<<3)
 #define	PTEUNCACHED	(1<<4)
+#define	PTECACHED	(0<<4)
 #define	PTEWRITE	(1<<1)
 #define	PTERONLY	(0<<1)
 #define	PTEKERNEL	(0<<2)
--- a/sys/src/9/zynq/devarch.c
+++ b/sys/src/9/zynq/devarch.c
@@ -181,7 +181,7 @@
 	Physseg seg;
 
 	memset(&seg, 0, sizeof seg);
-	seg.attr = SG_PHYSICAL | SG_FAULT;
+	seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC | SG_FAULT;
 	seg.name = "axi";
 	seg.pa = 0x40000000;
 	seg.size = 0x8000000;
--- a/sys/src/9/zynq/l.s
+++ b/sys/src/9/zynq/l.s
@@ -41,7 +41,7 @@
 	CMP.S R2, R3
 	BGE _start2
 
-	MOVW $(UART_BASE|L2VALID|L2DEVICE|L2KERRW), R0
+	MOVW $(UART_BASE|L2VALID|L2DEVICE|L2NOEXEC|L2KERRW), R0
 	MOVW $(VMAPL2-KZERO), R1
 	MOVW R0, (R1)
 
--- a/sys/src/9/zynq/mem.h
+++ b/sys/src/9/zynq/mem.h
@@ -62,6 +62,8 @@
 #define PTEVALID L2VALID
 #define PTERONLY L2RONLY
 #define PTEWRITE L2WRITE
+#define PTENOEXEC L2NOEXEC
+#define PTECACHED L2CACHED
 #define PTEUNCACHED L2DEVICE
 #define PPN(x) ((x)&~(BY2PG-1))
 
@@ -114,7 +116,8 @@
 
 #define L2VALID (2|1<<4)
 #define L2CACHED (1<<10|1<<8|1<<6|1<<2)
-#define L2DEVICE (1<<0)
+#define L2DEVICE 0
+#define L2NOEXEC (1<<0)
 #define L2KERRW L2KERNEL
 #define L2KERNEL 0
 #define L2USER (1<<5)
--- a/sys/src/9/zynq/mmu.c
+++ b/sys/src/9/zynq/mmu.c
@@ -147,8 +147,6 @@
 
 	if(up->l1 == nil)
 		upallocl1();
-	if((pa & PTEUNCACHED) == 0)
-		pa |= L2CACHED;
 	e = &up->l1->va[L1RX(va)];
 	if((*e & 3) == 0){
 		p = up->mmufree;
@@ -400,7 +398,7 @@
 	while(np-- != 0){
 		if(vp == ve)
 			panic("vmap: out of vmap space (pa=%#.8lux)", pa);
-		*vp++ = pa | L2VALID | L2DEVICE | L2KERRW;
+		*vp++ = pa | L2VALID | L2DEVICE | L2NOEXEC | L2KERRW;
 		pa += BY2PG;
 	}
 	coherence();