Skip to contentSkip to conversation

MIPS Read Inhibit/eXecute Inhibit support (v2).

PATCH In review David Daney 4 participants 14 messages Feb 10, 2010 – Feb 15, 2010 MIPS

lore
Share & tools
lore
#0 lore raw

cover MIPS Read Inhibit/eXecute Inhibit support (v2).

This patch set adds execute and read inhibit support. By default glibc based tool chains will create mappings for data areas of a program and shared libraries with PROT_EXEC cleared. With this patch applied, a SIGSEGV is correctly sent if an attempt is made to execute from data areas.

The first three patch just make a few tweaks in preperation for the main body of the patch in 4/6. The last two turn on the feature for some Octeon CPUs.

I will reply with the six patches.

David Daney (6):
MIPS: Use 64-bit stores to c0_entrylo on 64-bit kernels.
MIPS: Add accessor functions and bit definitions for c0_PageGrain
MIPS: Add TLBR and ROTR to uasm.
MIPS: Implement Read Inhibit/eXecute Inhibit
MIPS: Give Octeon+ CPUs their own cputype.
MIPS: Enable Read Inhibit/eXecute Inhibit for Octeon+ CPUs

 arch/mips/include/asm/cpu-features.h               |    3 +
 arch/mips/include/asm/cpu.h                        |    2 +-
 .../asm/mach-cavium-octeon/cpu-feature-overrides.h |    3 +
 arch/mips/include/asm/mipsregs.h                   |   11 ++
 arch/mips/include/asm/pgtable-32.h                 |    4 +-
 arch/mips/include/asm/pgtable-64.h                 |    4 +-
 arch/mips/include/asm/pgtable-bits.h               |  105 ++++++++++--
 arch/mips/include/asm/pgtable.h                    |   26 ++-
 arch/mips/include/asm/uasm.h                       |    4 +
 arch/mips/kernel/cpu-probe.c                       |    6 +-
 arch/mips/mm/c-octeon.c                            |    7 +-
 arch/mips/mm/cache.c                               |   53 ++++--
 arch/mips/mm/fault.c                               |   27 +++-
 arch/mips/mm/init.c                                |    2 +-
 arch/mips/mm/tlb-r4k.c                             |   19 ++-
 arch/mips/mm/tlbex.c                               |  183 
++++++++++++++++----
 arch/mips/mm/uasm.c                                |    9 +-
 17 files changed, 375 insertions(+), 93 deletions(-)
#1 lore raw

PATCH 1/6 MIPS: Use 64-bit stores to c0_entrylo on 64-bit kernels.

64-bit CPUs have 64-bit c0_entrylo{0,1} registers. We should use the 64-bit dmtc0 instruction to set them. This becomes important if we want to set the RI and XI bits present in some processors.

---
 arch/mips/mm/tlbex.c |   20 ++++++++++----------
 1 files changed, 10 insertions(+), 10 deletions(-)
arch/mips/mm/tlbex.c +10 -10
index 2c68849..35431e1 100644
@@ -460,14 +460,14 @@ static __cpuinit void build_huge_update_entries(u32 **p,
 		uasm_i_lui(p, tmp, HPAGE_SIZE >> (7 + 16));
 
 	UASM_i_SRL(p, pte, pte, 6); /* convert to entrylo */
-	uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* load it */
+	UASM_i_MTC0(p, pte, C0_ENTRYLO0); /* load it */
 	/* convert to entrylo1 */
 	if (small_sequence)
 		UASM_i_ADDIU(p, pte, pte, HPAGE_SIZE >> 7);
 	else
 		UASM_i_ADDU(p, pte, pte, tmp);
 
-	uasm_i_mtc0(p, pte, C0_ENTRYLO1); /* load it */
+	UASM_i_MTC0(p, pte, C0_ENTRYLO1); /* load it */
 }
 
 static __cpuinit void build_huge_handler_tail(u32 **p,
@@ -686,18 +686,18 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,
 		uasm_i_ld(p, tmp, 0, ptep); /* get even pte */
 		uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
 		uasm_i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
-		uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+		UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
 		uasm_i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */
-		uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+		UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */
 	} else {
 		int pte_off_even = sizeof(pte_t) / 2;
 		int pte_off_odd = pte_off_even + sizeof(pte_t);
 
 		/* The pte entries are pre-shifted */
 		uasm_i_lw(p, tmp, pte_off_even, ptep); /* get even pte */
-		uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+		UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
 		uasm_i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */
-		uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+		UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */
 	}
 #else
 	UASM_i_LW(p, tmp, 0, ptep); /* get even pte */
@@ -706,14 +706,14 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,
 		build_tlb_probe_entry(p);
 	UASM_i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
 	if (r4k_250MHZhwbug())
-		uasm_i_mtc0(p, 0, C0_ENTRYLO0);
-	uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+		UASM_i_MTC0(p, 0, C0_ENTRYLO0);
+	UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
 	UASM_i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
 	if (r45k_bvahwbug())
 		uasm_i_mfc0(p, tmp, C0_INDEX);
 	if (r4k_250MHZhwbug())
-		uasm_i_mtc0(p, 0, C0_ENTRYLO1);
-	uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+		UASM_i_MTC0(p, 0, C0_ENTRYLO1);
+	UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */
 #endif
 }
 
Signature · 1 line
1.6.2.5
#2 lore raw

PATCH 2/6 MIPS: Add accessor functions and bit definitions for c0_PageGrain

In reply to David Daney
---
 arch/mips/include/asm/mipsregs.h |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)
arch/mips/include/asm/mipsregs.h +11 -0
index b30819c..9893758 100644
@@ -251,6 +251,14 @@
 #define PL_256M		28
 
 /*
+ * PageGrain bits
+ */
+#define PG_RIE		(_ULCAST_(1) <<  31)
+#define PG_XIE		(_ULCAST_(1) <<  30)
+#define PG_ELPA		(_ULCAST_(1) <<  29)
+#define PG_ESP		(_ULCAST_(1) <<  28)
+
+/*
  * R4x00 interrupt enable / cause bits
  */
 #define IE_SW0          (_ULCAST_(1) <<  8)
@@ -840,6 +848,9 @@ do {									\
 #define read_c0_pagemask()	__read_32bit_c0_register($5, 0)
 #define write_c0_pagemask(val)	__write_32bit_c0_register($5, 0, val)
 
+#define read_c0_pagegrain()	__read_32bit_c0_register($5, 1)
+#define write_c0_pagegrain(val)	__write_32bit_c0_register($5, 1, val)
+
 #define read_c0_wired()		__read_32bit_c0_register($6, 0)
 #define write_c0_wired(val)	__write_32bit_c0_register($6, 0, val)
 
Signature · 1 line
1.6.2.5
#3 lore raw

PATCH 3/6 MIPS: Add TLBR and ROTR to uasm.

In reply to David Daney

The soon to follow Read Inhibit/eXecute Inhibit patch needs TLBR and ROTR support in uasm. We also add a UASM_i_ROTR macro.

---
 arch/mips/include/asm/uasm.h |    4 ++++
 arch/mips/mm/uasm.c          |    9 +++++++--
 2 files changed, 11 insertions(+), 2 deletions(-)
arch/mips/include/asm/uasm.h +4 -0
index 3d153ed..b99bd07 100644
@@ -92,9 +92,11 @@ Ip_u2s3u1(_sd);
 Ip_u2u1u3(_sll);
 Ip_u2u1u3(_sra);
 Ip_u2u1u3(_srl);
+Ip_u2u1u3(_rotr);
 Ip_u3u1u2(_subu);
 Ip_u2s3u1(_sw);
 Ip_0(_tlbp);
+Ip_0(_tlbr);
 Ip_0(_tlbwi);
 Ip_0(_tlbwr);
 Ip_u3u1u2(_xor);
@@ -129,6 +131,7 @@ static inline void __cpuinit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
 # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh)
 # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh)
 # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh)
+# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_drotr(buf, rs, rt, sh)
 # define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
 # define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
 # define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val)
@@ -142,6 +145,7 @@ static inline void __cpuinit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
 # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh)
 # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh)
 # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
+# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_rotr(buf, rs, rt, sh)
 # define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
 # define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
 # define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val)
arch/mips/mm/uasm.c +7 -2
index e3ca0f7..1581e98 100644
@@ -62,8 +62,9 @@ enum opcode {
 	insn_dsrl32, insn_drotr, insn_dsubu, insn_eret, insn_j, insn_jal,
 	insn_jr, insn_ld, insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0,
 	insn_mtc0, insn_ori, insn_pref, insn_rfe, insn_sc, insn_scd,
-	insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw,
-	insn_tlbp, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori, insn_dins
+	insn_sd, insn_sll, insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw,
+	insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori,
+	insn_dins
 };
 
 struct insn {
@@ -125,9 +126,11 @@ static struct insn insn_table[] __cpuinitdata = {
 	{ insn_sll,  M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE },
 	{ insn_sra,  M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE },
 	{ insn_srl,  M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE },
+	{ insn_rotr,  M(spec_op, 1, 0, 0, 0, srl_op),  RT | RD | RE },
 	{ insn_subu,  M(spec_op, 0, 0, 0, 0, subu_op),  RS | RT | RD },
 	{ insn_sw,  M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 	{ insn_tlbp,  M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0 },
+	{ insn_tlbr,  M(cop0_op, cop_op, 0, 0, 0, tlbr_op),  0 },
 	{ insn_tlbwi,  M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0 },
 	{ insn_tlbwr,  M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0 },
 	{ insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
@@ -378,9 +381,11 @@ I_u2s3u1(_sd)
 I_u2u1u3(_sll)
 I_u2u1u3(_sra)
 I_u2u1u3(_srl)
+I_u2u1u3(_rotr)
 I_u3u1u2(_subu)
 I_u2s3u1(_sw)
 I_0(_tlbp)
+I_0(_tlbr)
 I_0(_tlbwi)
 I_0(_tlbwr)
 I_u3u1u2(_xor)
Signature · 1 line
1.6.2.5
#4 lore raw

PATCH 4/6 MIPS: Implement Read Inhibit/eXecute Inhibit

In reply to David Daney

The SmartMIPS ASE specifies how Read Inhibit (RI) and eXecute Inhibit (XI) bits in the page tables work. The upper two bits of EntryLo{0,1} are RI and XI when the feature is enabled in the PageGrain register. SmartMIPS only covers 32-bit systems. Cavium Octeon+ extends this to 64-bit systems by continuing to place the RI and XI bits in the top of EntryLo even when EntryLo is 64-bits wide.

Because we need to carry the RI and XI bits in the PTE, the layout of the PTE is changed. There is a two instruction overhead in the TLB refill hot path to get the EntryLo bits into the proper position. Also the TLB load exception has to probe the TLB to check if RI or XI caused the exception.

Also of note is that the layout of the PTE bits is done at compile and runtime rather than statically. In the 32-bit case this allows for the same number of PFN bits as before the patch as the _PAGE_HUGE is not supported in 32-bit kernels (we have _PAGE_NO_EXEC and _PAGE_NO_READ instead of _PAGE_READ and _PAGE_HUGE).

The patch is tested on Cavium Octeon+, but should also work on 32-bit systems with the Smart-MIPS ASE.

---
 arch/mips/include/asm/cpu-features.h |    3 +
 arch/mips/include/asm/pgtable-32.h   |    4 +-
 arch/mips/include/asm/pgtable-64.h   |    4 +-
 arch/mips/include/asm/pgtable-bits.h |  105 ++++++++++++++++++---
 arch/mips/include/asm/pgtable.h      |   26 +++--
 arch/mips/mm/cache.c                 |   53 ++++++++---
 arch/mips/mm/fault.c                 |   27 +++++-
 arch/mips/mm/init.c                  |    2 +-
 arch/mips/mm/tlb-r4k.c               |   19 +++-
 arch/mips/mm/tlbex.c                 |  169 ++++++++++++++++++++++++++++------
 10 files changed, 333 insertions(+), 79 deletions(-)
arch/mips/include/asm/cpu-features.h +3 -0
index 272c5ef..ac73ced 100644
@@ -95,6 +95,9 @@
 #ifndef cpu_has_smartmips
 #define cpu_has_smartmips      (cpu_data[0].ases & MIPS_ASE_SMARTMIPS)
 #endif
+#ifndef kernel_uses_smartmips_rixi
+#define kernel_uses_smartmips_rixi 0
+#endif
 #ifndef cpu_has_vtag_icache
 #define cpu_has_vtag_icache	(cpu_data[0].icache.flags & MIPS_CACHE_VTAG)
 #endif
arch/mips/include/asm/pgtable-32.h +2 -2
index 55813d6..ae90412 100644
@@ -127,8 +127,8 @@ pfn_pte(unsigned long pfn, pgprot_t prot)
 #define pte_pfn(x)		((unsigned long)((x).pte >> (PAGE_SHIFT + 2)))
 #define pfn_pte(pfn, prot)	__pte(((pfn) << (PAGE_SHIFT + 2)) | pgprot_val(prot))
 #else
-#define pte_pfn(x)		((unsigned long)((x).pte >> PAGE_SHIFT))
-#define pfn_pte(pfn, prot)	__pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pte_pfn(x)		((unsigned long)((x).pte >> _PFN_SHIFT))
+#define pfn_pte(pfn, prot)	__pte(((unsigned long long)(pfn) << _PFN_SHIFT) | pgprot_val(prot))
 #endif
 #endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */
 
arch/mips/include/asm/pgtable-64.h +2 -2
index 2c1d194..adc2093 100644
@@ -216,8 +216,8 @@ static inline void pud_clear(pud_t *pudp)
 #define pte_pfn(x)		((unsigned long)((x).pte >> (PAGE_SHIFT + 2)))
 #define pfn_pte(pfn, prot)	__pte(((pfn) << (PAGE_SHIFT + 2)) | pgprot_val(prot))
 #else
-#define pte_pfn(x)		((unsigned long)((x).pte >> PAGE_SHIFT))
-#define pfn_pte(pfn, prot)	__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pte_pfn(x)		((unsigned long)((x).pte >> _PFN_SHIFT))
+#define pfn_pte(pfn, prot)	__pte(((pfn) << _PFN_SHIFT) | pgprot_val(prot))
 #endif
 
 #define __pgd_offset(address)	pgd_index(address)
arch/mips/include/asm/pgtable-bits.h +90 -15

136 lines not on this page · raw message

arch/mips/include/asm/pgtable.h +16 -10
index 02335fd..93598ba 100644
@@ -22,23 +22,24 @@ struct mm_struct;
 struct vm_area_struct;
 
 #define PAGE_NONE	__pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT)
-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_WRITE | (kernel_uses_smartmips_rixi ? 0 : _PAGE_READ) | \
 				 _page_cachable_default)
-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_READ | \
-				 _page_cachable_default)
-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_READ | \
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | (kernel_uses_smartmips_rixi ? 0 : _PAGE_READ) | \
+				 (kernel_uses_smartmips_rixi ?  _PAGE_NO_EXEC : 0) | _page_cachable_default)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | (kernel_uses_smartmips_rixi ? 0 : _PAGE_READ) | \
 				 _page_cachable_default)
 #define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
 				 _PAGE_GLOBAL | _page_cachable_default)
-#define PAGE_USERIO	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+#define PAGE_USERIO	__pgprot(_PAGE_PRESENT | (kernel_uses_smartmips_rixi ? 0 : _PAGE_READ) | _PAGE_WRITE | \
 				 _page_cachable_default)
 #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \
 			__WRITEABLE | _PAGE_GLOBAL | _CACHE_UNCACHED)
 
 /*
- * MIPS can't do page protection for execute, and considers that the same like
- * read. Also, write permissions imply read permissions. This is the closest
- * we can get by reasonable means..
+ * If _PAGE_NO_EXEC is not defined, we can't do page protection for
+ * execute, and consider it to be the same as read. Also, write
+ * permissions imply read permissions. This is the closest we can get
+ * by reasonable means..
  */
 
 /*
@@ -298,8 +299,13 @@ static inline pte_t pte_mkdirty(pte_t pte)
 static inline pte_t pte_mkyoung(pte_t pte)
 {
 	pte_val(pte) |= _PAGE_ACCESSED;
-	if (pte_val(pte) & _PAGE_READ)
-		pte_val(pte) |= _PAGE_SILENT_READ;
+	if (kernel_uses_smartmips_rixi) {
+		if (!(pte_val(pte) & _PAGE_NO_READ))
+			pte_val(pte) |= _PAGE_SILENT_READ;
+	} else {
+		if (pte_val(pte) & _PAGE_READ)
+			pte_val(pte) |= _PAGE_SILENT_READ;
+	}
 	return pte;
 }
 
arch/mips/mm/cache.c +37 -16

59 lines not on this page · raw message

arch/mips/mm/fault.c +25 -2
index e97a7a2..b78f7d9 100644
@@ -99,8 +99,31 @@ good_area:
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
 	} else {
-		if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)))
-			goto bad_area;
+		if (kernel_uses_smartmips_rixi) {
+			if (address == regs->cp0_epc && !(vma->vm_flags & VM_EXEC)) {
+#if 0
+				pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] XI violation\n",
+					  raw_smp_processor_id(),
+					  current->comm, current->pid,
+					  field, address, write,
+					  field, regs->cp0_epc);
+#endif
+				goto bad_area;
+			}
+			if (!(vma->vm_flags & VM_READ)) {
+#if 0
+				pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n",
+					  raw_smp_processor_id(),
+					  current->comm, current->pid,
+					  field, address, write,
+					  field, regs->cp0_epc);
+#endif
+				goto bad_area;
+			}
+		} else {
+			if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)))
+				goto bad_area;
+		}
 	}
 
 	/*
arch/mips/mm/init.c +1 -1
index 3c5b7de..f34c264 100644
@@ -143,7 +143,7 @@ void *kmap_coherent(struct page *page, unsigned long addr)
 #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
 	entrylo = pte.pte_high;
 #else
-	entrylo = pte_val(pte) >> 6;
+	entrylo = pte_to_entrylo(pte_val(pte));
 #endif
 
 	ENTER_CRITICAL(flags);
arch/mips/mm/tlb-r4k.c +16 -3
index e551559..1032e71 100644
@@ -303,7 +303,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
 		unsigned long lo;
 		write_c0_pagemask(PM_HUGE_MASK);
 		ptep = (pte_t *)pmdp;
-		lo = pte_val(*ptep) >> 6;
+		lo = pte_to_entrylo(pte_val(*ptep));
 		write_c0_entrylo0(lo);
 		write_c0_entrylo1(lo + (HPAGE_SIZE >> 7));
 
@@ -323,8 +323,8 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
 		ptep++;
 		write_c0_entrylo1(ptep->pte_high);
 #else
-		write_c0_entrylo0(pte_val(*ptep++) >> 6);
-		write_c0_entrylo1(pte_val(*ptep) >> 6);
+		write_c0_entrylo0(pte_to_entrylo(pte_val(*ptep++)));
+		write_c0_entrylo1(pte_to_entrylo(pte_val(*ptep)));
 #endif
 		mtc0_tlbw_hazard();
 		if (idx < 0)
@@ -439,6 +439,19 @@ void __cpuinit tlb_init(void)
 	    current_cpu_type() == CPU_R12000 ||
 	    current_cpu_type() == CPU_R14000)
 		write_c0_framemask(0);
+
+	if (kernel_uses_smartmips_rixi) {
+		/*
+		 * Enable the no read, no exec bits, and enable large virtual
+		 * address.
+		 */
+		u32 pg = PG_RIE | PG_XIE;
+#ifdef CONFIG_64BIT
+		pg |= PG_ELPA;
+#endif
+		write_c0_pagegrain(pg);
+	}
+
 	temp_tlb_entry = current_cpu_data.tlbsize - 1;
 
         /* From this point on the ARC firmware is dead.  */
arch/mips/mm/tlbex.c +141 -28

239 lines not on this page · raw message

Signature · 1 line
1.6.2.5
#5 lore raw

Re: [PATCH 4/6] MIPS: Implement Read Inhibit/eXecute Inhibit

Hi David,

this patch breaks my Alchemy builds:

Using /mnt/data/_home/mano/db1200/kernel/linux-2.6.git as source for kernel

  GEN     /mnt/data/_home/mano/db1200/kernel/kbuild-linux-2.6.git/Makefile
  CHK     include/linux/version.h
  CHK     include/generated/utsrelease.h
  UPD     include/generated/utsrelease.h
  CC      arch/mips/kernel/asm-offsets.s

In file included from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/io.h:25,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/page.h:46,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/mm_types.h:15,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/sched.h:63,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/kernel/asm-offsets.c:13:
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:
In function 'pte_to_entrylo':
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:
error: '_PAGE_NO_READ_SHIFT' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:
error: (Each undeclared identifier is reported only once /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:
error: for each function it appears in.) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:155:
error: '_PAGE_GLOBAL_SHIFT' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:156:
error: '_PAGE_NO_EXEC' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:156:
error: '_PAGE_NO_READ' undeclared (first use in this function)
In file included from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/mm.h:39,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/kernel/asm-offsets.c:14:
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable.h:
In function 'pte_modify':
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable.h:351:
error: '_PFN_MASK' undeclared (first use in this function)
make[2]: *** [arch/mips/kernel/asm-offsets.s] Error 1
make[1]: *** [prepare0] Error 2
make: *** [sub-make] Error 2

Thanks!
Manuel Lauss

#6 lore raw

Re: [PATCH 4/6] MIPS: Implement Read Inhibit/eXecute Inhibit

Quoted 37 lines · Manuel Lauss

Hi David,

this patch breaks my Alchemy builds:

Using /mnt/data/_home/mano/db1200/kernel/linux-2.6.git as source for kernel

   GEN     /mnt/data/_home/mano/db1200/kernel/kbuild-linux-2.6.git/Makefile
   CHK     include/linux/version.h
   CHK     include/generated/utsrelease.h
   UPD     include/generated/utsrelease.h
   CC      arch/mips/kernel/asm-offsets.s

In file included from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/io.h:25,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/page.h:46,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/mm_types.h:15,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/sched.h:63,
from
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/kernel/asm-offsets.c:13:
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:
In function 'pte_to_entrylo':
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:
error: '_PAGE_NO_READ_SHIFT' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:
error: (Each undeclared identifier is reported only once /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:
error: for each function it appears in.) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:155:
error: '_PAGE_GLOBAL_SHIFT' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:156:
error: '_PAGE_NO_EXEC' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:156:
error: '_PAGE_NO_READ' undeclared (first use in this function)
In file included from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/mm.h:39,
from

Quoted 9 lines

/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/kernel/asm-offsets.c:14:
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable.h:
In function 'pte_modify':
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable.h:351:
error: '_PFN_MASK' undeclared (first use in this function)
make[2]: *** [arch/mips/kernel/asm-offsets.s] Error 1
make[1]: *** [prepare0] Error 2
make: *** [sub-make] Error 2

Whoops! I will endeavor to fix this.

Thanks for testing,
David Daney

#7 lore raw

Re: [PATCH 4/6] MIPS: Implement Read Inhibit/eXecute Inhibit

Quoted 54 lines · David Daney
Quoted 53 lines · Manuel Lauss

Hi David,

this patch breaks my Alchemy builds:

Using /mnt/data/_home/mano/db1200/kernel/linux-2.6.git as source for kernel GEN /mnt/data/_home/mano/db1200/kernel/kbuild-linux-2.6.git/Makefile CHK include/linux/version.h
CHK include/generated/utsrelease.h
UPD include/generated/utsrelease.h
CC arch/mips/kernel/asm-offsets.s
In file included from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/io.h:25,

from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/page.h:46,

from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/mm_types.h:15,

from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/sched.h:63,

from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/kernel/asm-offsets.c:13:

/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:

In function 'pte_to_entrylo':
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:

error: '_PAGE_NO_READ_SHIFT' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:

error: (Each undeclared identifier is reported only once /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:146:

error: for each function it appears in.) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:155:

error: '_PAGE_GLOBAL_SHIFT' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:156:

error: '_PAGE_NO_EXEC' undeclared (first use in this function) /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable-bits.h:156:

error: '_PAGE_NO_READ' undeclared (first use in this function)
In file included from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/include/linux/mm.h:39, from /mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/kernel/asm-offsets.c:14:

/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable.h:

Quoted 8 lines
Quoted 7 lines

In function 'pte_modify':
/mnt/data/_home/mano/db1200/kernel/linux-2.6.git/arch/mips/include/asm/pgtable.h:351:

error: '_PFN_MASK' undeclared (first use in this function) make[2]: *** [arch/mips/kernel/asm-offsets.s] Error 1 make[1]: *** [prepare0] Error 2
make: *** [sub-make] Error 2

Whoops! I will endeavor to fix this.

Try the attached patch, it allows me to build an au1000 kernel. But since I don't have harware, I cannot test it.

I started with pb1500_defconfig, but had to disable au1000_eth.c:

drivers/net/au1000_eth.c: In function ‘au1000_probe’:
drivers/net/au1000_eth.c:1009: error: implicit declaration of function ‘DECLARE_MAC_BUF’ drivers/net/au1000_eth.c:1009: error: ‘ethaddr’ undeclared (first use in this function) drivers/net/au1000_eth.c:1009: error: (Each undeclared identifier is reported only once drivers/net/au1000_eth.c:1009: error: for each function it appears in.)

David Daney.

MIPS: Fix RIXI patch for au1000 processors.

---
 arch/mips/include/asm/pgtable-bits.h |   20 +++++++++++++++-----
 1 files changed, 15 insertions(+), 5 deletions(-)
arch/mips/include/asm/pgtable-bits.h +15 -5
index a2e646f..47ca734 100644
@@ -66,7 +66,6 @@
 #define _PAGE_SILENT_WRITE          (1<<10)
 #define _CACHE_UNCACHED             (1<<11)
 #define _CACHE_MASK                 (1<<11)
-#define _PFN_SHIFT                  PAGE_SHIFT
 
 #else /* 'Normal' r4K case */
 /*
@@ -129,10 +128,22 @@
 #define _CACHE_MASK		(7 << _CACHE_SHIFT)
 
 #define _PFN_SHIFT		(PAGE_SHIFT - 12 + _CACHE_SHIFT + 3)
-#define _PFN_MASK		(~((1 << (_PFN_SHIFT)) - 1))
 
 #endif /* defined(CONFIG_64BIT_PHYS_ADDR && defined(CONFIG_CPU_MIPS32) */
 
+#ifndef _PFN_SHIFT
+#define _PFN_SHIFT                  PAGE_SHIFT
+#endif
+#define _PFN_MASK		(~((1 << (_PFN_SHIFT)) - 1))
+
+#ifndef _PAGE_NO_READ
+#define _PAGE_NO_READ ({BUG(); 0; })
+#define _PAGE_NO_READ_SHIFT ({BUG(); 0; })
+#endif
+#ifndef _PAGE_NO_EXEC
+#define _PAGE_NO_EXEC ({BUG(); 0; })
+#endif
+
 #ifndef __ASSEMBLY__
 /*
  * pte_to_entrylo converts a page table entry (PTE) into a Mips
@@ -152,11 +163,10 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val)
 		 * followed by a ROTR 2.  Luckily in the fast path
 		 * this is done in assembly
 		 */
-		return (pte_val >> _PAGE_GLOBAL_SHIFT) |
+		return (pte_val >> ilog2(_PAGE_GLOBAL)) |
 			((pte_val & (_PAGE_NO_EXEC | _PAGE_NO_READ)) << sa);
 	}
-
-	return pte_val >> _PAGE_GLOBAL_SHIFT;
+	return pte_val >> ilog2(_PAGE_GLOBAL);
 }
 #endif
 
#8 lore raw

Re: [PATCH 4/6] MIPS: Implement Read Inhibit/eXecute Inhibit

Hi David,

Quoted 6 lines · David Daney
Quoted 3 lines · Manuel Lauss
Quoted 2 lines

this patch breaks my Alchemy builds:

Try the attached patch, it allows me to build an au1000 kernel. But since I don't have harware, I cannot test it.

Boots my userspace, thank you!

Quoted 10 lines

I started with pb1500_defconfig, but had to disable au1000_eth.c:

drivers/net/au1000_eth.c: In function ‘au1000_probe’:
drivers/net/au1000_eth.c:1009: error: implicit declaration of function ‘DECLARE_MAC_BUF’
drivers/net/au1000_eth.c:1009: error: ‘ethaddr’ undeclared (first use in this function)
drivers/net/au1000_eth.c:1009: error: (Each undeclared identifier is reported only once
drivers/net/au1000_eth.c:1009: error: for each function it appears in.)

I'll try to fix this; usually I only build db1200_defconfig.

Manuel

#9 lore raw

Re: [PATCH 4/6] MIPS: Implement Read Inhibit/eXecute Inhibit

Quoted 12 lines · Manuel Lauss

Hi David,

Quoted 6 lines · David Daney
Quoted 3 lines · Manuel Lauss
Quoted 2 lines

this patch breaks my Alchemy builds:

Try the attached patch, it allows me to build an au1000 kernel. But since I don't have harware, I cannot test it.

Boots my userspace, thank you!

Ok. I am working on a functionally equivalent, but slightly cleaner patch.

Thanks for your patience,

David Daney

Quoted 16 lines
Quoted 11 lines

I started with pb1500_defconfig, but had to disable au1000_eth.c:

drivers/net/au1000_eth.c: In function ‘au1000_probe’:
drivers/net/au1000_eth.c:1009: error: implicit declaration of function ‘DECLARE_MAC_BUF’
drivers/net/au1000_eth.c:1009: error: ‘ethaddr’ undeclared (first use in this function)
drivers/net/au1000_eth.c:1009: error: (Each undeclared identifier is reported only once
drivers/net/au1000_eth.c:1009: error: for each function it appears in.)

I'll try to fix this; usually I only build db1200_defconfig.

Manuel

#10 lore raw

PATCH 5/6 MIPS: Give Octeon+ CPUs their own cputype.

In reply to David Daney

This allows us to treat them differently at runtime.

---
 arch/mips/include/asm/cpu.h  |    2 +-
 arch/mips/kernel/cpu-probe.c |    6 +++++-
 arch/mips/mm/c-octeon.c      |    7 ++++---
 3 files changed, 10 insertions(+), 5 deletions(-)
arch/mips/include/asm/cpu.h +1 -1
index cf373a9..a5acda4 100644
@@ -224,7 +224,7 @@ enum cpu_type_enum {
 	 * MIPS64 class processors
 	 */
 	CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
-	CPU_CAVIUM_OCTEON,
+	CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS,
 
 	CPU_LAST
 };
arch/mips/kernel/cpu-probe.c +5 -1
index 9ea5ca8..ee67aac 100644
@@ -162,6 +162,7 @@ void __init check_wait(void)
 	case CPU_BCM6348:
 	case CPU_BCM6358:
 	case CPU_CAVIUM_OCTEON:
+	case CPU_CAVIUM_OCTEON_PLUS:
 		cpu_wait = r4k_wait;
 		break;
 
@@ -911,11 +912,14 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
 	case PRID_IMP_CAVIUM_CN38XX:
 	case PRID_IMP_CAVIUM_CN31XX:
 	case PRID_IMP_CAVIUM_CN30XX:
+		c->cputype = CPU_CAVIUM_OCTEON;
+		goto name_and_platform;
 	case PRID_IMP_CAVIUM_CN58XX:
 	case PRID_IMP_CAVIUM_CN56XX:
 	case PRID_IMP_CAVIUM_CN50XX:
 	case PRID_IMP_CAVIUM_CN52XX:
-		c->cputype = CPU_CAVIUM_OCTEON;
+		c->cputype = CPU_CAVIUM_OCTEON_PLUS;
+name_and_platform:
 		__cpu_name[cpu] = "Cavium Octeon";
 		if (cpu == 0)
 			__elf_platform = "octeon";
arch/mips/mm/c-octeon.c +4 -3
index af85959..0f9c488 100644
@@ -183,6 +183,7 @@ static void __cpuinit probe_octeon(void)
 
 	switch (c->cputype) {
 	case CPU_CAVIUM_OCTEON:
+	case CPU_CAVIUM_OCTEON_PLUS:
 		config1 = read_c0_config1();
 		c->icache.linesz = 2 << ((config1 >> 19) & 7);
 		c->icache.sets = 64 << ((config1 >> 22) & 7);
@@ -192,10 +193,10 @@ static void __cpuinit probe_octeon(void)
 			c->icache.sets * c->icache.ways * c->icache.linesz;
 		c->icache.waybit = ffs(icache_size / c->icache.ways) - 1;
 		c->dcache.linesz = 128;
-		if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
-			c->dcache.sets = 1; /* CN3XXX has one Dcache set */
-		else
+		if (c->cputype == CPU_CAVIUM_OCTEON_PLUS)
 			c->dcache.sets = 2; /* CN5XXX has two Dcache sets */
+		else
+			c->dcache.sets = 1; /* CN3XXX has one Dcache set */
 		c->dcache.ways = 64;
 		dcache_size =
 			c->dcache.sets * c->dcache.ways * c->dcache.linesz;
Signature · 1 line
1.6.2.5
#11 lore raw

PATCH 6/6 MIPS: Enable Read Inhibit/eXecute Inhibit for Octeon+ CPUs

In reply to David Daney
---
 .../asm/mach-cavium-octeon/cpu-feature-overrides.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h +3 -0
index 425e708..bbf0540 100644
@@ -58,6 +58,9 @@
 #define cpu_has_vint		0
 #define cpu_has_veic		0
 #define cpu_hwrena_impl_bits	0xc0000000
+
+#define kernel_uses_smartmips_rixi (cpu_data[0].cputype == CPU_CAVIUM_OCTEON_PLUS)
+
 #define ARCH_HAS_READ_CURRENT_TIMER 1
 #define ARCH_HAS_IRQ_PER_CPU	1
 #define ARCH_HAS_SPINLOCK_PREFETCH 1
Signature · 1 line
1.6.2.5
#12 lore raw
In reply to David Daney
Quoted 12 lines · David Daney

This patch set adds execute and read inhibit support. By default glibc based tool chains will create mappings for data areas of a program and shared libraries with PROT_EXEC cleared. With this patch applied, a SIGSEGV is correctly sent if an attempt is made to execute from data areas.

The first three patch just make a few tweaks in preperation for the main body of the patch in 4/6. The last two turn on the feature for some Octeon CPUs.

I will reply with the six patches.

Quoted 7 lines

David Daney (6):
MIPS: Use 64-bit stores to c0_entrylo on 64-bit kernels.
MIPS: Add accessor functions and bit definitions for c0_PageGrain
MIPS: Add TLBR and ROTR to uasm.
MIPS: Implement Read Inhibit/eXecute Inhibit
MIPS: Give Octeon+ CPUs their own cputype.
MIPS: Enable Read Inhibit/eXecute Inhibit for Octeon+ CPUs

Hangs on IP27 after

[...]
Calibrating delay loop... 178.17 BogoMIPS (lpj=89088) Dentry cache hash table entries: 262144 (order: 9, 2097152 bytes)

Ralf

#13 lore raw
Quoted 22 lines · Ralf Baechle
Quoted 12 lines · David Daney

This patch set adds execute and read inhibit support. By default glibc based tool chains will create mappings for data areas of a program and shared libraries with PROT_EXEC cleared. With this patch applied, a SIGSEGV is correctly sent if an attempt is made to execute from data areas.

The first three patch just make a few tweaks in preperation for the main body of the patch in 4/6. The last two turn on the feature for some Octeon CPUs.

I will reply with the six patches.

Quoted 7 lines

David Daney (6):
MIPS: Use 64-bit stores to c0_entrylo on 64-bit kernels.
MIPS: Add accessor functions and bit definitions for c0_PageGrain
MIPS: Add TLBR and ROTR to uasm.
MIPS: Implement Read Inhibit/eXecute Inhibit
MIPS: Give Octeon+ CPUs their own cputype.
MIPS: Enable Read Inhibit/eXecute Inhibit for Octeon+ CPUs

Quoted 6 lines

Hangs on IP27 after

[...]
Calibrating delay loop... 178.17 BogoMIPS (lpj=89088) Dentry cache hash table entries: 262144 (order: 9, 2097152 bytes)

Try the attached patch.

David Daney

arch/mips/mm/tlbex.c +2 -2
index ec60bd5..5ea0af8 100644
@@ -749,11 +749,11 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,
 		UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
 		UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
 	} else {
-		UASM_i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
+		UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */
 		if (r4k_250MHZhwbug())
 			UASM_i_MTC0(p, 0, C0_ENTRYLO0);
 		UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
-		UASM_i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
+		UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */
 		if (r45k_bvahwbug())
 			uasm_i_mfc0(p, tmp, C0_INDEX);
 	}