Skip to contentSkip to conversation

fix ppc64 kernel access of user pages

PATCH New Anton Blanchard 1 participant 2 messages Feb 27, 2004

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 fix ppc64 kernel access of user pages

Set the ks bit on userspace segments otherwise the kernel can read/write into userspace mprotected pages.

--

arch/ppc64/kernel/head.S +8 -1
diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
@@ -826,7 +826,14 @@
 _GLOBAL(do_hash_page_ISI)
 	li	r4,0
 _GLOBAL(do_hash_page_DSI)
-	rlwimi	r4,r23,32-13,30,30	/* Insert MSR_PR as _PAGE_USER */
+	/*
+	 * We need to set the _PAGE_USER bit if MSR_PR is set or if we are
+	 * accessing a userspace segment (even from the kernel). We assume
+	 * kernel addresses always have the high bit set.
+	 */
+	rotldi	r0,r3,15		/* Move high bit into MSR_PR position */
+	orc	r0,r23,r0
+	rlwimi	r4,r0,32-13,30,30	/* Insert into _PAGE_USER */
 	ori	r4,r4,1			/* add _PAGE_PRESENT */
 
 	mflr	r21			/* Save LR in r21 */
arch/ppc64/kernel/stab.c +8 -0
diff -Nru a/arch/ppc64/kernel/stab.c b/arch/ppc64/kernel/stab.c
@@ -73,6 +73,8 @@
 	unsigned long entry, group, old_esid, castout_entry, i;
 	unsigned int global_entry;
 	STE *ste, *castout_ste;
+	unsigned long kernel_segment = (REGION_ID(esid << SID_SHIFT) != 
+					USER_REGION_ID);
 
 	/* Search the primary group first. */
 	global_entry = (esid & 0x1f) << 3;
@@ -85,6 +87,8 @@
 				ste->dw1.dw1.vsid = vsid;
 				ste->dw0.dw0.esid = esid;
 				ste->dw0.dw0.kp = 1;
+				if (!kernel_segment)
+					ste->dw0.dw0.ks = 1;
 				asm volatile("eieio":::"memory");
 				ste->dw0.dw0.v = 1;
 				return (global_entry | entry);
@@ -131,6 +135,8 @@
 	old_esid = castout_ste->dw0.dw0.esid;
 	castout_ste->dw0.dw0.esid = esid;
 	castout_ste->dw0.dw0.kp = 1;
+	if (!kernel_segment)
+		castout_ste->dw0.dw0.ks = 1;
 	asm volatile("eieio" : : : "memory");   /* Order update */
 	castout_ste->dw0.dw0.v  = 1;
 	asm volatile("slbie  %0" : : "r" (old_esid << SID_SHIFT)); 
@@ -340,6 +346,8 @@
 		vsid_data.data.l = 1;
 	if (kernel_segment)
 		vsid_data.data.c = 1;
+	else
+		vsid_data.data.ks = 1;
 
 	esid_data.word0 = 0;
 	esid_data.data.esid = esid;
#1 lore raw

PATCH 1/1 ppc64 TLB flush rework

ppc64 tlb flush rework from Paul Mackerras

Instead of doing a double pass of the pagetables, we batch things up in the pte flush routines and then shoot the batch down in flush_tlb_pending.

Our page aging was broken, we never flushed entries out of the ppc64 hashtable. We now flush in ptep_test_and_clear_young.

A number of other things were fixed up in the process:

- change ppc64_tlb_batch to per cpu data
- remove some LPAR debug code
- be more careful with ioremap_mm inits
- clean up arch/ppc64/mm/init.c, create tlb.c

---

 forakpm-anton/arch/ppc64/kernel/pSeries_htab.c |    2 
 forakpm-anton/arch/ppc64/kernel/pSeries_lpar.c |   10 
 forakpm-anton/arch/ppc64/kernel/process.c      |   12 
 forakpm-anton/arch/ppc64/mm/Makefile           |    2 
 forakpm-anton/arch/ppc64/mm/hash_utils.c       |    3 
 forakpm-anton/arch/ppc64/mm/init.c             |  376 +++++--------------------
 forakpm-anton/arch/ppc64/mm/tlb.c              |  155 ++++++++++
 forakpm-anton/include/asm-ppc64/pgtable.h      |  122 ++++++--
 forakpm-anton/include/asm-ppc64/tlb.h          |   61 ----
 forakpm-anton/include/asm-ppc64/tlbflush.h     |   43 +-
 10 files changed, 388 insertions(+), 398 deletions(-)
arch/ppc64/kernel/pSeries_htab.c renamed from arch/ppc64/kernel/pSeries_htab.c~tlb_flush_rework +1 -1
diff -puN arch/ppc64/kernel/pSeries_htab.c~tlb_flush_rework arch/ppc64/kernel/pSeries_htab.c
@@ -300,7 +300,7 @@ static void pSeries_flush_hash_range(uns
 	int i, j;
 	HPTE *hptep;
 	Hpte_dword0 dw0;
-	struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[smp_processor_id()];
+	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
 
 	/* XXX fix for large ptes */
 	unsigned long large = 0;
arch/ppc64/kernel/pSeries_lpar.c renamed from arch/ppc64/kernel/pSeries_lpar.c~tlb_flush_rework +3 -7
diff -puN arch/ppc64/kernel/pSeries_lpar.c~tlb_flush_rework arch/ppc64/kernel/pSeries_lpar.c
@@ -422,10 +422,8 @@ static long pSeries_lpar_hpte_updatepp(u
 
 	lpar_rc = plpar_pte_protect(flags, slot, (avpn << 7));
 
-	if (lpar_rc == H_Not_Found) {
-		udbg_printf("updatepp missed\n");
+	if (lpar_rc == H_Not_Found)
 		return -1;
-	}
 
 	if (lpar_rc != H_Success)
 		panic("bad return code from pte protect rc = %lx\n", lpar_rc);
@@ -523,10 +521,8 @@ static void pSeries_lpar_hpte_invalidate
 	lpar_rc = plpar_pte_remove(H_AVPN, slot, (avpn << 7), &dummy1,
 				   &dummy2);
 
-	if (lpar_rc == H_Not_Found) {
-		udbg_printf("invalidate missed\n");
+	if (lpar_rc == H_Not_Found)
 		return;
-	}
 
 	if (lpar_rc != H_Success)
 		panic("Bad return code from invalidate rc = %lx\n", lpar_rc);
@@ -541,7 +537,7 @@ void pSeries_lpar_flush_hash_range(unsig
 {
 	int i;
 	unsigned long flags;
-	struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[smp_processor_id()];
+	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
 
 	spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
 
arch/ppc64/kernel/process.c renamed from arch/ppc64/kernel/process.c~tlb_flush_rework +10 -2
diff -puN arch/ppc64/kernel/process.c~tlb_flush_rework arch/ppc64/kernel/process.c
@@ -49,14 +49,20 @@
 #include <asm/hardirq.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
+#include <asm/tlbflush.h>
 
 #ifndef CONFIG_SMP
 struct task_struct *last_task_used_math = NULL;
 struct task_struct *last_task_used_altivec = NULL;
 #endif
 
-struct mm_struct ioremap_mm = { pgd             : ioremap_dir  
-                               ,page_table_lock : SPIN_LOCK_UNLOCKED };
+struct mm_struct ioremap_mm = {
+	.pgd		= ioremap_dir,
+	.mm_users	= ATOMIC_INIT(2),
+	.mm_count	= ATOMIC_INIT(1),
+	.cpu_vm_mask	= CPU_MASK_ALL,
+	.page_table_lock = SPIN_LOCK_UNLOCKED,
+};
 
 char *sysmap = NULL;
 unsigned long sysmap_size = 0;
@@ -146,6 +152,8 @@ struct task_struct *__switch_to(struct t
 		new->thread.regs->msr |= MSR_VEC;
 #endif /* CONFIG_ALTIVEC */
 
+	flush_tlb_pending();
+
 	new_thread = &new->thread;
 	old_thread = &current->thread;
 
arch/ppc64/mm/Makefile renamed from arch/ppc64/mm/Makefile~tlb_flush_rework +1 -1
diff -puN arch/ppc64/mm/Makefile~tlb_flush_rework arch/ppc64/mm/Makefile
@@ -4,6 +4,6 @@
 
 EXTRA_CFLAGS += -mno-minimal-toc
 
-obj-y := fault.o init.o imalloc.o hash_utils.o hash_low.o
+obj-y := fault.o init.o imalloc.o hash_utils.o hash_low.o tlb.o
 obj-$(CONFIG_DISCONTIGMEM) += numa.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
arch/ppc64/mm/hash_utils.c renamed from arch/ppc64/mm/hash_utils.c~tlb_flush_rework +1 -2
diff -puN arch/ppc64/mm/hash_utils.c~tlb_flush_rework arch/ppc64/mm/hash_utils.c
@@ -326,8 +326,7 @@ void flush_hash_range(unsigned long cont
 		ppc_md.flush_hash_range(context, number, local);
 	} else {
 		int i;
-		struct ppc64_tlb_batch *batch =
-			&ppc64_tlb_batch[smp_processor_id()];
+		struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
 
 		for (i = 0; i < number; i++)
 			flush_hash_page(context, batch->addr[i], batch->pte[i],
arch/ppc64/mm/init.c renamed from arch/ppc64/mm/init.c~tlb_flush_rework +90 -286

429 lines not on this page · raw message

arch/ppc64/mm/tlb.c new file +155 -0

155 lines not on this page · raw message

include/asm-ppc64/pgtable.h renamed from include/asm-ppc64/pgtable.h~tlb_flush_rework +96 -26

174 lines not on this page · raw message

include/asm-ppc64/tlb.h renamed from include/asm-ppc64/tlb.h~tlb_flush_rework +3 -58

80 lines not on this page · raw message

include/asm-ppc64/tlbflush.h renamed from include/asm-ppc64/tlbflush.h~tlb_flush_rework +28 -15

60 lines not on this page · raw message

_