fix ppc64 kernel access of user pages
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
@@ -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
@@ -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 ; asmvolatile ("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 ; asmvolatile ("eieio" : : :"memory" );/* Order update */ castout_ste->dw0.dw0.v =1 ; asmvolatile ("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;
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
@@ -300,7 +300,7 @@ static void pSeries_flush_hash_range(unsint 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
@@ -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
@@ -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 = ¤t->thread;
arch/ppc64/mm/Makefile renamed from arch/ppc64/mm/Makefile~tlb_flush_rework +1 -1
@@ -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
@@ -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
_