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();