* [PATCH 0/4] Patches for -next @ 2010-05-20 14:29 Catalin Marinas 2010-05-20 14:30 ` [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs Catalin Marinas ` (4 more replies) 0 siblings, 5 replies; 23+ messages in thread From: Catalin Marinas @ 2010-05-20 14:29 UTC (permalink / raw) To: linux-arm-kernel Hi, I would like to get these patches in the linux-next tree for this release cycle and aim to submit them for upstream 2.6.36-rc1 (next merging window). Please let me know if you have any objections. Thanks. Catalin Marinas (4): ARM: Remove the domain switching on ARMv6k/v7 CPUs ARM: Use lazy cache flushing on ARMv7 SMP systems ARM: Assume new page cache pages have dirty D-cache ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP arch/arm/include/asm/assembler.h | 13 +++--- arch/arm/include/asm/cacheflush.h | 6 +-- arch/arm/include/asm/domain.h | 31 +++++++++++++- arch/arm/include/asm/futex.h | 9 ++-- arch/arm/include/asm/pgtable.h | 12 +++++ arch/arm/include/asm/smp_plat.h | 4 ++ arch/arm/include/asm/tlbflush.h | 2 - arch/arm/include/asm/uaccess.h | 16 ++++--- arch/arm/kernel/entry-armv.S | 4 +- arch/arm/kernel/traps.c | 17 ++++++++ arch/arm/lib/getuser.S | 13 +++--- arch/arm/lib/putuser.S | 29 +++++++------ arch/arm/lib/uaccess.S | 83 +++++++++++++++++++------------------ arch/arm/mm/Kconfig | 8 ++++ arch/arm/mm/copypage-v4mc.c | 2 - arch/arm/mm/copypage-v6.c | 2 - arch/arm/mm/copypage-xscale.c | 2 - arch/arm/mm/dma-mapping.c | 6 +++ arch/arm/mm/fault-armv.c | 21 ++++++--- arch/arm/mm/flush.c | 15 ++----- arch/arm/mm/proc-macros.S | 7 +++ arch/arm/mm/proc-v7.S | 5 +- 22 files changed, 197 insertions(+), 110 deletions(-) -- Catalin ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs 2010-05-20 14:29 [PATCH 0/4] Patches for -next Catalin Marinas @ 2010-05-20 14:30 ` Catalin Marinas 2010-05-24 11:45 ` Russell King - ARM Linux 2010-05-20 14:30 ` [PATCH 2/4] ARM: Use lazy cache flushing on ARMv7 SMP systems Catalin Marinas ` (3 subsequent siblings) 4 siblings, 1 reply; 23+ messages in thread From: Catalin Marinas @ 2010-05-20 14:30 UTC (permalink / raw) To: linux-arm-kernel This patch removes the domain switching functionality via the set_fs and __switch_to functions on cores that have a TLS register. Currently, the ioremap and vmalloc areas share the same level 1 page tables and therefore have the same domain (DOMAIN_KERNEL). When the kernel domain is modified from Client to Manager (via the __set_fs or in the __switch_to function), the XN (eXecute Never) bit is overridden and newer CPUs can speculatively prefetch the ioremap'ed memory. Linux performs the kernel domain switching to allow user-specific functions (copy_to/from_user, get/put_user etc.) to access kernel memory. In order for these functions to work with the kernel domain set to Client, the patch modifies the LDRT/STRT and related instructions to the LDR/STR ones. The user pages access rights are also modified for kernel read-only access rather than read/write so that the copy-on-write mechanism still works. CPU_USE_DOMAINS gets disabled only if HAS_TLS_REG is defined since writing the TLS value to the high vectors page isn't possible. The user addresses passed to the kernel are checked by the access_ok() function so that they do not point to the kernel space. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> --- arch/arm/include/asm/assembler.h | 13 +++--- arch/arm/include/asm/domain.h | 31 +++++++++++++- arch/arm/include/asm/futex.h | 9 ++-- arch/arm/include/asm/uaccess.h | 16 ++++--- arch/arm/kernel/entry-armv.S | 4 +- arch/arm/kernel/traps.c | 17 ++++++++ arch/arm/lib/getuser.S | 13 +++--- arch/arm/lib/putuser.S | 29 +++++++------ arch/arm/lib/uaccess.S | 83 +++++++++++++++++++------------------- arch/arm/mm/Kconfig | 8 ++++ arch/arm/mm/proc-macros.S | 7 +++ arch/arm/mm/proc-v7.S | 5 +- 12 files changed, 150 insertions(+), 85 deletions(-) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 6e8f05c..66db132 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -18,6 +18,7 @@ #endif #include <asm/ptrace.h> +#include <asm/domain.h> /* * Endian independent macros for shifting bytes within registers. @@ -183,12 +184,12 @@ */ #ifdef CONFIG_THUMB2_KERNEL - .macro usraccoff, instr, reg, ptr, inc, off, cond, abort + .macro usraccoff, instr, reg, ptr, inc, off, cond, abort, t=T() 9999: .if \inc == 1 - \instr\cond\()bt \reg, [\ptr, #\off] + \instr\cond\()b\()\t\().w \reg, [\ptr, #\off] .elseif \inc == 4 - \instr\cond\()t \reg, [\ptr, #\off] + \instr\cond\()\t\().w \reg, [\ptr, #\off] .else .error "Unsupported inc macro argument" .endif @@ -223,13 +224,13 @@ #else /* !CONFIG_THUMB2_KERNEL */ - .macro usracc, instr, reg, ptr, inc, cond, rept, abort + .macro usracc, instr, reg, ptr, inc, cond, rept, abort, t=T() .rept \rept 9999: .if \inc == 1 - \instr\cond\()bt \reg, [\ptr], #\inc + \instr\cond\()b\()\t \reg, [\ptr], #\inc .elseif \inc == 4 - \instr\cond\()t \reg, [\ptr], #\inc + \instr\cond\()\t \reg, [\ptr], #\inc .else .error "Unsupported inc macro argument" .endif diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h index cc7ef40..af18cea 100644 --- a/arch/arm/include/asm/domain.h +++ b/arch/arm/include/asm/domain.h @@ -45,13 +45,17 @@ */ #define DOMAIN_NOACCESS 0 #define DOMAIN_CLIENT 1 +#ifdef CONFIG_CPU_USE_DOMAINS #define DOMAIN_MANAGER 3 +#else +#define DOMAIN_MANAGER 1 +#endif #define domain_val(dom,type) ((type) << (2*(dom))) #ifndef __ASSEMBLY__ -#ifdef CONFIG_MMU +#ifdef CONFIG_CPU_USE_DOMAINS #define set_domain(x) \ do { \ __asm__ __volatile__( \ @@ -74,5 +78,28 @@ #define modify_domain(dom,type) do { } while (0) #endif +/* + * Generate the T (user) versions of the LDR/STR and related + * instructions (inline assembly) + */ +#ifdef CONFIG_CPU_USE_DOMAINS +#define T(instr) #instr "t" +#else +#define T(instr) #instr #endif -#endif /* !__ASSEMBLY__ */ + +#else /* __ASSEMBLY__ */ + +/* + * Generate the T (user) versions of the LDR/STR and related + * instructions + */ +#ifdef CONFIG_CPU_USE_DOMAINS +#define T(instr) instr ## t +#else +#define T(instr) instr +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* !__ASM_PROC_DOMAIN_H */ diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index 540a044..b33fe70 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h @@ -13,12 +13,13 @@ #include <linux/preempt.h> #include <linux/uaccess.h> #include <asm/errno.h> +#include <asm/domain.h> #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ __asm__ __volatile__( \ - "1: ldrt %1, [%2]\n" \ + "1: " T(ldr) " %1, [%2]\n" \ " " insn "\n" \ - "2: strt %0, [%2]\n" \ + "2: " T(str) " %0, [%2]\n" \ " mov %0, #0\n" \ "3:\n" \ " .pushsection __ex_table,\"a\"\n" \ @@ -97,10 +98,10 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) pagefault_disable(); /* implies preempt_disable() */ __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" - "1: ldrt %0, [%3]\n" + "1: " T(ldr) " %0, [%3]\n" " teq %0, %1\n" " it eq @ explicit IT needed for the 2b label\n" - "2: streqt %2, [%3]\n" + "2: " T(streq) " %2, [%3]\n" "3:\n" " .pushsection __ex_table,\"a\"\n" " .align 3\n" diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 33e4a48..b293616 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -227,7 +227,7 @@ do { \ #define __get_user_asm_byte(x,addr,err) \ __asm__ __volatile__( \ - "1: ldrbt %1,[%2]\n" \ + "1: " T(ldrb) " %1,[%2],#0\n" \ "2:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -263,7 +263,7 @@ do { \ #define __get_user_asm_word(x,addr,err) \ __asm__ __volatile__( \ - "1: ldrt %1,[%2]\n" \ + "1: " T(ldr) " %1,[%2],#0\n" \ "2:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -308,7 +308,7 @@ do { \ #define __put_user_asm_byte(x,__pu_addr,err) \ __asm__ __volatile__( \ - "1: strbt %1,[%2]\n" \ + "1: " T(strb) " %1,[%2],#0\n" \ "2:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -341,7 +341,7 @@ do { \ #define __put_user_asm_word(x,__pu_addr,err) \ __asm__ __volatile__( \ - "1: strt %1,[%2]\n" \ + "1: " T(str) " %1,[%2],#0\n" \ "2:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -366,10 +366,10 @@ do { \ #define __put_user_asm_dword(x,__pu_addr,err) \ __asm__ __volatile__( \ - ARM( "1: strt " __reg_oper1 ", [%1], #4\n" ) \ - ARM( "2: strt " __reg_oper0 ", [%1]\n" ) \ - THUMB( "1: strt " __reg_oper1 ", [%1]\n" ) \ - THUMB( "2: strt " __reg_oper0 ", [%1, #4]\n" ) \ + ARM( "1: " T(str) " " __reg_oper1 ", [%1], #4\n" ) \ + ARM( "2: " T(str) " " __reg_oper0 ", [%1]\n" ) \ + THUMB( "1: " T(str) " " __reg_oper1 ", [%1]\n" ) \ + THUMB( "2: " T(str) " " __reg_oper0 ", [%1, #4]\n" ) \ "3:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 7ee48e7..ba654fa 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -736,7 +736,7 @@ ENTRY(__switch_to) THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack THUMB( str sp, [ip], #4 ) THUMB( str lr, [ip], #4 ) -#ifdef CONFIG_MMU +#ifdef CONFIG_CPU_USE_DOMAINS ldr r6, [r2, #TI_CPU_DOMAIN] #endif #if defined(CONFIG_HAS_TLS_REG) @@ -745,7 +745,7 @@ ENTRY(__switch_to) mov r4, #0xffff0fff str r3, [r4, #-15] @ TLS val at 0xffff0ff0 #endif -#ifdef CONFIG_MMU +#ifdef CONFIG_CPU_USE_DOMAINS mcr p15, 0, r6, c3, c0, 0 @ Set domain register #endif mov r5, r0 diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 1621e53..6571e19 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -30,6 +30,7 @@ #include <asm/unistd.h> #include <asm/traps.h> #include <asm/unwind.h> +#include <asm/tlbflush.h> #include "ptrace.h" #include "signal.h" @@ -750,6 +751,16 @@ void __init early_trap_init(void) extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; int kuser_sz = __kuser_helper_end - __kuser_helper_start; +#if !defined(CONFIG_CPU_USE_DOMAINS) && defined(CONFIG_MMU) + pgd_t *pgd = pgd_offset_k(vectors); + pmd_t *pmd = pmd_offset(pgd, vectors); + pte_t *pte = pte_offset_kernel(pmd, vectors); + pte_t entry = *pte; + + /* allow writing to the vectors page */ + set_pte_ext(pte, pte_mkwrite(entry), 0); + local_flush_tlb_kernel_page(vectors); +#endif /* * Copy the vectors, stubs and kuser helpers (in entry-armv.S) @@ -769,6 +780,12 @@ void __init early_trap_init(void) memcpy((void *)KERN_RESTART_CODE, syscall_restart_code, sizeof(syscall_restart_code)); +#if !defined(CONFIG_CPU_USE_DOMAINS) && defined(CONFIG_MMU) + /* restore the vectors page permissions */ + set_pte_ext(pte, entry, 0); + local_flush_tlb_kernel_page(vectors); +#endif + flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); } diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index b1631a7..1b049cd 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -28,20 +28,21 @@ */ #include <linux/linkage.h> #include <asm/errno.h> +#include <asm/domain.h> ENTRY(__get_user_1) -1: ldrbt r2, [r0] +1: T(ldrb) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__get_user_1) ENTRY(__get_user_2) #ifdef CONFIG_THUMB2_KERNEL -2: ldrbt r2, [r0] -3: ldrbt r3, [r0, #1] +2: T(ldrb) r2, [r0] +3: T(ldrb) r3, [r0, #1] #else -2: ldrbt r2, [r0], #1 -3: ldrbt r3, [r0] +2: T(ldrb) r2, [r0], #1 +3: T(ldrb) r3, [r0] #endif #ifndef __ARMEB__ orr r2, r2, r3, lsl #8 @@ -53,7 +54,7 @@ ENTRY(__get_user_2) ENDPROC(__get_user_2) ENTRY(__get_user_4) -4: ldrt r2, [r0] +4: T(ldr) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__get_user_4) diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S index 5a01a23..c023fc1 100644 --- a/arch/arm/lib/putuser.S +++ b/arch/arm/lib/putuser.S @@ -28,9 +28,10 @@ */ #include <linux/linkage.h> #include <asm/errno.h> +#include <asm/domain.h> ENTRY(__put_user_1) -1: strbt r2, [r0] +1: T(strb) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__put_user_1) @@ -39,19 +40,19 @@ ENTRY(__put_user_2) mov ip, r2, lsr #8 #ifdef CONFIG_THUMB2_KERNEL #ifndef __ARMEB__ -2: strbt r2, [r0] -3: strbt ip, [r0, #1] +2: T(strb) r2, [r0] +3: T(strb) ip, [r0, #1] #else -2: strbt ip, [r0] -3: strbt r2, [r0, #1] +2: T(strb) ip, [r0] +3: T(strb) r2, [r0, #1] #endif #else /* !CONFIG_THUMB2_KERNEL */ #ifndef __ARMEB__ -2: strbt r2, [r0], #1 -3: strbt ip, [r0] +2: T(strb) r2, [r0], #1 +3: T(strb) ip, [r0] #else -2: strbt ip, [r0], #1 -3: strbt r2, [r0] +2: T(strb) ip, [r0], #1 +3: T(strb) r2, [r0] #endif #endif /* CONFIG_THUMB2_KERNEL */ mov r0, #0 @@ -59,18 +60,18 @@ ENTRY(__put_user_2) ENDPROC(__put_user_2) ENTRY(__put_user_4) -4: strt r2, [r0] +4: T(str) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__put_user_4) ENTRY(__put_user_8) #ifdef CONFIG_THUMB2_KERNEL -5: strt r2, [r0] -6: strt r3, [r0, #4] +5: T(str) r2, [r0] +6: T(str) r3, [r0, #4] #else -5: strt r2, [r0], #4 -6: strt r3, [r0] +5: T(str) r2, [r0], #4 +6: T(str) r3, [r0] #endif mov r0, #0 mov pc, lr diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S index fee9f6f..d0ece2a 100644 --- a/arch/arm/lib/uaccess.S +++ b/arch/arm/lib/uaccess.S @@ -14,6 +14,7 @@ #include <linux/linkage.h> #include <asm/assembler.h> #include <asm/errno.h> +#include <asm/domain.h> .text @@ -31,11 +32,11 @@ rsb ip, ip, #4 cmp ip, #2 ldrb r3, [r1], #1 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault ldrgtb r3, [r1], #1 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault sub r2, r2, ip b .Lc2u_dest_aligned @@ -58,7 +59,7 @@ ENTRY(__copy_to_user) addmi ip, r2, #4 bmi .Lc2u_0nowords ldr r3, [r1], #4 -USER( strt r3, [r0], #4) @ May fault +USER( T(str) r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -87,18 +88,18 @@ USER( strt r3, [r0], #4) @ May fault stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 ldrne r3, [r1], #4 - strnet r3, [r0], #4 @ Shouldnt fault + T(strne) r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .Lc2u_0fupi .Lc2u_0nowords: teq ip, #0 beq .Lc2u_finished .Lc2u_nowords: cmp ip, #2 ldrb r3, [r1], #1 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault ldrgtb r3, [r1], #1 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault b .Lc2u_finished .Lc2u_not_enough: @@ -119,7 +120,7 @@ USER( strgtbt r3, [r0], #1) @ May fault mov r3, r7, pull #8 ldr r7, [r1], #4 orr r3, r3, r7, push #24 -USER( strt r3, [r0], #4) @ May fault +USER( T(str) r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -154,18 +155,18 @@ USER( strt r3, [r0], #4) @ May fault movne r3, r7, pull #8 ldrne r7, [r1], #4 orrne r3, r3, r7, push #24 - strnet r3, [r0], #4 @ Shouldnt fault + T(strne) r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .Lc2u_1fupi .Lc2u_1nowords: mov r3, r7, get_byte_1 teq ip, #0 beq .Lc2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault movge r3, r7, get_byte_2 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault movgt r3, r7, get_byte_3 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault b .Lc2u_finished .Lc2u_2fupi: subs r2, r2, #4 @@ -174,7 +175,7 @@ USER( strgtbt r3, [r0], #1) @ May fault mov r3, r7, pull #16 ldr r7, [r1], #4 orr r3, r3, r7, push #16 -USER( strt r3, [r0], #4) @ May fault +USER( T(str) r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -209,18 +210,18 @@ USER( strt r3, [r0], #4) @ May fault movne r3, r7, pull #16 ldrne r7, [r1], #4 orrne r3, r3, r7, push #16 - strnet r3, [r0], #4 @ Shouldnt fault + T(strne) r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .Lc2u_2fupi .Lc2u_2nowords: mov r3, r7, get_byte_2 teq ip, #0 beq .Lc2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault movge r3, r7, get_byte_3 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault ldrgtb r3, [r1], #0 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault b .Lc2u_finished .Lc2u_3fupi: subs r2, r2, #4 @@ -229,7 +230,7 @@ USER( strgtbt r3, [r0], #1) @ May fault mov r3, r7, pull #24 ldr r7, [r1], #4 orr r3, r3, r7, push #8 -USER( strt r3, [r0], #4) @ May fault +USER( T(str) r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -264,18 +265,18 @@ USER( strt r3, [r0], #4) @ May fault movne r3, r7, pull #24 ldrne r7, [r1], #4 orrne r3, r3, r7, push #8 - strnet r3, [r0], #4 @ Shouldnt fault + T(strne) r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .Lc2u_3fupi .Lc2u_3nowords: mov r3, r7, get_byte_3 teq ip, #0 beq .Lc2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault ldrgtb r3, [r1], #0 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault b .Lc2u_finished ENDPROC(__copy_to_user) @@ -294,11 +295,11 @@ ENDPROC(__copy_to_user) .Lcfu_dest_not_aligned: rsb ip, ip, #4 cmp ip, #2 -USER( ldrbt r3, [r1], #1) @ May fault +USER( T(ldrb) r3, [r1], #1) @ May fault strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) @ May fault +USER( T(ldrgeb) r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) @ May fault +USER( T(ldrgtb) r3, [r1], #1) @ May fault strgtb r3, [r0], #1 sub r2, r2, ip b .Lcfu_dest_aligned @@ -321,7 +322,7 @@ ENTRY(__copy_from_user) .Lcfu_0fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .Lcfu_0nowords -USER( ldrt r3, [r1], #4) +USER( T(ldr) r3, [r1], #4) str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction rsb ip, ip, #0 @@ -350,18 +351,18 @@ USER( ldrt r3, [r1], #4) ldmneia r1!, {r3 - r4} @ Shouldnt fault stmneia r0!, {r3 - r4} tst ip, #4 - ldrnet r3, [r1], #4 @ Shouldnt fault + T(ldrne) r3, [r1], #4 @ Shouldnt fault strne r3, [r0], #4 ands ip, ip, #3 beq .Lcfu_0fupi .Lcfu_0nowords: teq ip, #0 beq .Lcfu_finished .Lcfu_nowords: cmp ip, #2 -USER( ldrbt r3, [r1], #1) @ May fault +USER( T(ldrb) r3, [r1], #1) @ May fault strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) @ May fault +USER( T(ldrgeb) r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) @ May fault +USER( T(ldrgtb) r3, [r1], #1) @ May fault strgtb r3, [r0], #1 b .Lcfu_finished @@ -374,7 +375,7 @@ USER( ldrgtbt r3, [r1], #1) @ May fault .Lcfu_src_not_aligned: bic r1, r1, #3 -USER( ldrt r7, [r1], #4) @ May fault +USER( T(ldr) r7, [r1], #4) @ May fault cmp ip, #2 bgt .Lcfu_3fupi beq .Lcfu_2fupi @@ -382,7 +383,7 @@ USER( ldrt r7, [r1], #4) @ May fault addmi ip, r2, #4 bmi .Lcfu_1nowords mov r3, r7, pull #8 -USER( ldrt r7, [r1], #4) @ May fault +USER( T(ldr) r7, [r1], #4) @ May fault orr r3, r3, r7, push #24 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -417,7 +418,7 @@ USER( ldrt r7, [r1], #4) @ May fault stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, pull #8 -USER( ldrnet r7, [r1], #4) @ May fault +USER( T(ldrne) r7, [r1], #4) @ May fault orrne r3, r3, r7, push #24 strne r3, [r0], #4 ands ip, ip, #3 @@ -437,7 +438,7 @@ USER( ldrnet r7, [r1], #4) @ May fault addmi ip, r2, #4 bmi .Lcfu_2nowords mov r3, r7, pull #16 -USER( ldrt r7, [r1], #4) @ May fault +USER( T(ldr) r7, [r1], #4) @ May fault orr r3, r3, r7, push #16 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -473,7 +474,7 @@ USER( ldrt r7, [r1], #4) @ May fault stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, pull #16 -USER( ldrnet r7, [r1], #4) @ May fault +USER( T(ldrne) r7, [r1], #4) @ May fault orrne r3, r3, r7, push #16 strne r3, [r0], #4 ands ip, ip, #3 @@ -485,7 +486,7 @@ USER( ldrnet r7, [r1], #4) @ May fault strb r3, [r0], #1 movge r3, r7, get_byte_3 strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #0) @ May fault +USER( T(ldrgtb) r3, [r1], #0) @ May fault strgtb r3, [r0], #1 b .Lcfu_finished @@ -493,7 +494,7 @@ USER( ldrgtbt r3, [r1], #0) @ May fault addmi ip, r2, #4 bmi .Lcfu_3nowords mov r3, r7, pull #24 -USER( ldrt r7, [r1], #4) @ May fault +USER( T(ldr) r7, [r1], #4) @ May fault orr r3, r3, r7, push #8 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -528,7 +529,7 @@ USER( ldrt r7, [r1], #4) @ May fault stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, pull #24 -USER( ldrnet r7, [r1], #4) @ May fault +USER( T(ldrne) r7, [r1], #4) @ May fault orrne r3, r3, r7, push #8 strne r3, [r0], #4 ands ip, ip, #3 @@ -538,9 +539,9 @@ USER( ldrnet r7, [r1], #4) @ May fault beq .Lcfu_finished cmp ip, #2 strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) @ May fault +USER( T(ldrgeb) r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) @ May fault +USER( T(ldrgtb) r3, [r1], #1) @ May fault strgtb r3, [r0], #1 b .Lcfu_finished ENDPROC(__copy_from_user) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 346ae14..f33c422 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -599,6 +599,14 @@ config CPU_CP15_MPU help Processor has the CP15 register, which has MPU related registers. +config CPU_USE_DOMAINS + bool + depends on MMU + default y if !HAS_TLS_REG + help + This option enables or disables the use of domain switching + via the set_fs() function. + # # CPU supports 36-bit I/O # diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 7d63bea..337f102 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -99,6 +99,10 @@ * 110x 0 1 0 r/w r/o * 11x0 0 1 0 r/w r/o * 1111 0 1 1 r/w r/w + * + * If !CONFIG_CPU_USE_DOMAINS, the following permissions are changed: + * 110x 1 1 1 r/o r/o + * 11x0 1 1 1 r/o r/o */ .macro armv6_mt_table pfx \pfx\()_mt_table: @@ -138,8 +142,11 @@ tst r1, #L_PTE_USER orrne r3, r3, #PTE_EXT_AP1 +#ifdef CONFIG_CPU_USE_DOMAINS + @ allow kernel read/write access to read-only user pages tstne r3, #PTE_EXT_APX bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 +#endif tst r1, #L_PTE_EXEC orreq r3, r3, #PTE_EXT_XN diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 7aaf88a..c1c3fe0 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -152,8 +152,11 @@ ENTRY(cpu_v7_set_pte_ext) tst r1, #L_PTE_USER orrne r3, r3, #PTE_EXT_AP1 +#ifdef CONFIG_CPU_USE_DOMAINS + @ allow kernel read/write access to read-only user pages tstne r3, #PTE_EXT_APX bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 +#endif tst r1, #L_PTE_EXEC orreq r3, r3, #PTE_EXT_XN @@ -240,8 +243,6 @@ __v7_setup: mcr p15, 0, r10, c2, c0, 2 @ TTB control register orr r4, r4, #TTB_FLAGS mcr p15, 0, r4, c2, c0, 1 @ load TTB1 - mov r10, #0x1f @ domains 0, 1 = manager - mcr p15, 0, r10, c3, c0, 0 @ load domain access register /* * Memory region attributes with SCTLR.TRE=1 * ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs 2010-05-20 14:30 ` [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs Catalin Marinas @ 2010-05-24 11:45 ` Russell King - ARM Linux 2010-05-24 13:25 ` Catalin Marinas 0 siblings, 1 reply; 23+ messages in thread From: Russell King - ARM Linux @ 2010-05-24 11:45 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 20, 2010 at 03:30:04PM +0100, Catalin Marinas wrote: > The user pages access rights are also modified for kernel read-only > access rather than read/write so that the copy-on-write mechanism still > works. CPU_USE_DOMAINS gets disabled only if HAS_TLS_REG is defined > since writing the TLS value to the high vectors page isn't possible. When FIQ handlers are installed/removed, the vector page is also written, so the above restriction is incompatible with FIQ support. Do we want to tell people that they can't use FIQs without domain support? ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs 2010-05-24 11:45 ` Russell King - ARM Linux @ 2010-05-24 13:25 ` Catalin Marinas 2010-05-24 13:52 ` Catalin Marinas 0 siblings, 1 reply; 23+ messages in thread From: Catalin Marinas @ 2010-05-24 13:25 UTC (permalink / raw) To: linux-arm-kernel On Mon, 2010-05-24 at 12:45 +0100, Russell King - ARM Linux wrote: > On Thu, May 20, 2010 at 03:30:04PM +0100, Catalin Marinas wrote: > > The user pages access rights are also modified for kernel read-only > > access rather than read/write so that the copy-on-write mechanism still > > works. CPU_USE_DOMAINS gets disabled only if HAS_TLS_REG is defined > > since writing the TLS value to the high vectors page isn't possible. > > When FIQ handlers are installed/removed, the vector page is also written, > so the above restriction is incompatible with FIQ support. > > Do we want to tell people that they can't use FIQs without domain support? They could still be used (with an additional patch). At first, I thought that we could do something similar to early_trap_init() but set_fiq_handler() could be called from a module at run-time and it may temporarily enable write access to the vectors page (without an additional L_PTE_ bit we can't make the vectors page user RO, kernel R/W and I wouldn't do this anyway, for other reasons). What about making a global vectors_page variable (initialised in devicemaps_init) that can be written directly when !CPU_USE_DOMAINS? On such CPUs, we have a non-aliasing VIPT cache anyway. -- Catalin ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs 2010-05-24 13:25 ` Catalin Marinas @ 2010-05-24 13:52 ` Catalin Marinas 2010-05-24 13:59 ` Russell King - ARM Linux 0 siblings, 1 reply; 23+ messages in thread From: Catalin Marinas @ 2010-05-24 13:52 UTC (permalink / raw) To: linux-arm-kernel On Mon, 2010-05-24 at 14:25 +0100, Catalin Marinas wrote: > On Mon, 2010-05-24 at 12:45 +0100, Russell King - ARM Linux wrote: > > On Thu, May 20, 2010 at 03:30:04PM +0100, Catalin Marinas wrote: > > > The user pages access rights are also modified for kernel read-only > > > access rather than read/write so that the copy-on-write mechanism still > > > works. CPU_USE_DOMAINS gets disabled only if HAS_TLS_REG is defined > > > since writing the TLS value to the high vectors page isn't possible. > > > > When FIQ handlers are installed/removed, the vector page is also written, > > so the above restriction is incompatible with FIQ support. > > > > Do we want to tell people that they can't use FIQs without domain support? > > They could still be used (with an additional patch). At first, I thought > that we could do something similar to early_trap_init() but > set_fiq_handler() could be called from a module at run-time and it may > temporarily enable write access to the vectors page (without an > additional L_PTE_ bit we can't make the vectors page user RO, kernel R/W > and I wouldn't do this anyway, for other reasons). > > What about making a global vectors_page variable (initialised in > devicemaps_init) that can be written directly when !CPU_USE_DOMAINS? On > such CPUs, we have a non-aliasing VIPT cache anyway. That's the additional diff which allows FIQs when !CPU_USE_DOMAINS (assuming VIPT non-aliasing caches). I also modified the early_trap_init() to make use of the vectors page rather than setting the PTE as in the original patch. diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h index 491960b..af5d5d1 100644 --- a/arch/arm/include/asm/traps.h +++ b/arch/arm/include/asm/traps.h @@ -27,4 +27,6 @@ static inline int in_exception_text(unsigned long ptr) extern void __init early_trap_init(void); extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame); +extern void *vectors_page; + #endif diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 6ff7919..fb1a640 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -45,6 +45,7 @@ #include <asm/fiq.h> #include <asm/irq.h> #include <asm/system.h> +#include <asm/traps.h> static unsigned long no_fiq_insn; @@ -77,7 +78,11 @@ int show_fiq_list(struct seq_file *p, void *v) void set_fiq_handler(void *start, unsigned int length) { +#if defined(CONFIG_CPU_USE_DOMAINS) memcpy((void *)0xffff001c, start, length); +#else + memcpy(vectors_page + 0x1c, start, length); +#endif flush_icache_range(0xffff001c, 0xffff001c + length); if (!vectors_high()) flush_icache_range(0x1c, 0x1c + length); diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 6571e19..6bc57c5 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -30,13 +30,14 @@ #include <asm/unistd.h> #include <asm/traps.h> #include <asm/unwind.h> -#include <asm/tlbflush.h> #include "ptrace.h" #include "signal.h" static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; +void *vectors_page; + #ifdef CONFIG_DEBUG_USER unsigned int user_debug; @@ -746,21 +747,15 @@ void __init trap_init(void) void __init early_trap_init(void) { +#if defined(CONFIG_CPU_USE_DOMAINS) unsigned long vectors = CONFIG_VECTORS_BASE; +#else + unsigned long vectors = (unsigned long)vectors_page; +#endif extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; int kuser_sz = __kuser_helper_end - __kuser_helper_start; -#if !defined(CONFIG_CPU_USE_DOMAINS) && defined(CONFIG_MMU) - pgd_t *pgd = pgd_offset_k(vectors); - pmd_t *pmd = pmd_offset(pgd, vectors); - pte_t *pte = pte_offset_kernel(pmd, vectors); - pte_t entry = *pte; - - /* allow writing to the vectors page */ - set_pte_ext(pte, pte_mkwrite(entry), 0); - local_flush_tlb_kernel_page(vectors); -#endif /* * Copy the vectors, stubs and kuser helpers (in entry-armv.S) @@ -775,16 +770,10 @@ void __init early_trap_init(void) * Copy signal return handlers into the vector page, and * set sigreturn to be a pointer to these. */ - memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, - sizeof(sigreturn_codes)); - memcpy((void *)KERN_RESTART_CODE, syscall_restart_code, - sizeof(syscall_restart_code)); - -#if !defined(CONFIG_CPU_USE_DOMAINS) && defined(CONFIG_MMU) - /* restore the vectors page permissions */ - set_pte_ext(pte, entry, 0); - local_flush_tlb_kernel_page(vectors); -#endif + memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), + sigreturn_codes, sizeof(sigreturn_codes)); + memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE), + syscall_restart_code, sizeof(syscall_restart_code)); flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 2858941..499e22d 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -25,6 +25,7 @@ #include <asm/smp_plat.h> #include <asm/tlb.h> #include <asm/highmem.h> +#include <asm/traps.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -935,12 +936,11 @@ static void __init devicemaps_init(struct machine_desc *mdesc) { struct map_desc map; unsigned long addr; - void *vectors; /* * Allocate the vector page early. */ - vectors = alloc_bootmem_low_pages(PAGE_SIZE); + vectors_page = alloc_bootmem_low_pages(PAGE_SIZE); for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) pmd_clear(pmd_off_k(addr)); @@ -980,7 +980,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc) * location (0xffff0000). If we aren't using high-vectors, also * create a mapping at the low-vectors virtual address. */ - map.pfn = __phys_to_pfn(virt_to_phys(vectors)); + map.pfn = __phys_to_pfn(virt_to_phys(vectors_page)); map.virtual = 0xffff0000; map.length = PAGE_SIZE; map.type = MT_HIGH_VECTORS; -- Catalin ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs 2010-05-24 13:52 ` Catalin Marinas @ 2010-05-24 13:59 ` Russell King - ARM Linux 2010-05-24 14:02 ` Catalin Marinas 0 siblings, 1 reply; 23+ messages in thread From: Russell King - ARM Linux @ 2010-05-24 13:59 UTC (permalink / raw) To: linux-arm-kernel On Mon, May 24, 2010 at 02:52:52PM +0100, Catalin Marinas wrote: > @@ -77,7 +78,11 @@ int show_fiq_list(struct seq_file *p, void *v) > > void set_fiq_handler(void *start, unsigned int length) > { > +#if defined(CONFIG_CPU_USE_DOMAINS) > memcpy((void *)0xffff001c, start, length); > +#else > + memcpy(vectors_page + 0x1c, start, length); > +#endif > flush_icache_range(0xffff001c, 0xffff001c + length); This is clearly buggy from an I/D coherency point of view. ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs 2010-05-24 13:59 ` Russell King - ARM Linux @ 2010-05-24 14:02 ` Catalin Marinas 0 siblings, 0 replies; 23+ messages in thread From: Catalin Marinas @ 2010-05-24 14:02 UTC (permalink / raw) To: linux-arm-kernel On Mon, 2010-05-24 at 14:59 +0100, Russell King - ARM Linux wrote: > On Mon, May 24, 2010 at 02:52:52PM +0100, Catalin Marinas wrote: > > @@ -77,7 +78,11 @@ int show_fiq_list(struct seq_file *p, void *v) > > > > void set_fiq_handler(void *start, unsigned int length) > > { > > +#if defined(CONFIG_CPU_USE_DOMAINS) > > memcpy((void *)0xffff001c, start, length); > > +#else > > + memcpy(vectors_page + 0x1c, start, length); > > +#endif > > flush_icache_range(0xffff001c, 0xffff001c + length); > > This is clearly buggy from an I/D coherency point of view. As I said, it only works on VIPT non-aliasing caches, which would be fine give the CPUs that this patch targets. If you think it's safer, we can restrict this patch for ARMv7 onwards. -- Catalin ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 2/4] ARM: Use lazy cache flushing on ARMv7 SMP systems 2010-05-20 14:29 [PATCH 0/4] Patches for -next Catalin Marinas 2010-05-20 14:30 ` [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs Catalin Marinas @ 2010-05-20 14:30 ` Catalin Marinas 2010-05-20 14:30 ` [PATCH 3/4] ARM: Assume new page cache pages have dirty D-cache Catalin Marinas ` (2 subsequent siblings) 4 siblings, 0 replies; 23+ messages in thread From: Catalin Marinas @ 2010-05-20 14:30 UTC (permalink / raw) To: linux-arm-kernel ARMv7 processors like Cortex-A9 broadcast the cache maintenance operations in hardware. This patch allows the flush_dcache_page/update_mmu_cache pair to work in lazy flushing mode similar to the UP case. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> --- arch/arm/include/asm/smp_plat.h | 4 ++++ arch/arm/mm/fault-armv.c | 2 -- arch/arm/mm/flush.c | 13 ++++--------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/arm/include/asm/smp_plat.h b/arch/arm/include/asm/smp_plat.h index e621530..963a338 100644 --- a/arch/arm/include/asm/smp_plat.h +++ b/arch/arm/include/asm/smp_plat.h @@ -13,9 +13,13 @@ static inline int tlb_ops_need_broadcast(void) return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2; } +#if !defined(CONFIG_SMP) || __LINUX_ARM_ARCH__ >= 7 +#define cache_ops_need_broadcast() 0 +#else static inline int cache_ops_need_broadcast(void) { return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 1; } +#endif #endif diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 9b906de..9d77d90 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -168,10 +168,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, return; mapping = page_mapping(page); -#ifndef CONFIG_SMP if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) __flush_dcache_page(mapping, page); -#endif if (mapping) { if (cache_is_vivt()) make_coherent(mapping, vma, addr, ptep, pfn); diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index c6844cb..5ad8711 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -17,6 +17,7 @@ #include <asm/smp_plat.h> #include <asm/system.h> #include <asm/tlbflush.h> +#include <asm/smp_plat.h> #include "mm.h" @@ -93,12 +94,10 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig #define flush_pfn_alias(pfn,vaddr) do { } while (0) #endif -#ifdef CONFIG_SMP static void flush_ptrace_access_other(void *args) { __flush_icache_all(); } -#endif static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, @@ -122,11 +121,9 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, if (vma->vm_flags & VM_EXEC) { unsigned long addr = (unsigned long)kaddr; __cpuc_coherent_kern_range(addr, addr + len); -#ifdef CONFIG_SMP if (cache_ops_need_broadcast()) smp_call_function(flush_ptrace_access_other, NULL, 1); -#endif } } @@ -246,12 +243,10 @@ void flush_dcache_page(struct page *page) mapping = page_mapping(page); -#ifndef CONFIG_SMP - if (!PageHighMem(page) && mapping && !mapping_mapped(mapping)) + if (!cache_ops_need_broadcast() && + !PageHighMem(page) && mapping && !mapping_mapped(mapping)) set_bit(PG_dcache_dirty, &page->flags); - else -#endif - { + else { __flush_dcache_page(mapping, page); if (mapping && cache_is_vivt()) __flush_dcache_aliases(mapping, page); ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 3/4] ARM: Assume new page cache pages have dirty D-cache 2010-05-20 14:29 [PATCH 0/4] Patches for -next Catalin Marinas 2010-05-20 14:30 ` [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs Catalin Marinas 2010-05-20 14:30 ` [PATCH 2/4] ARM: Use lazy cache flushing on ARMv7 SMP systems Catalin Marinas @ 2010-05-20 14:30 ` Catalin Marinas 2010-05-20 14:30 ` [PATCH 4/4] ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP Catalin Marinas 2010-05-21 5:59 ` [PATCH 0/4] Patches for -next Shilimkar, Santosh 4 siblings, 0 replies; 23+ messages in thread From: Catalin Marinas @ 2010-05-20 14:30 UTC (permalink / raw) To: linux-arm-kernel There are places in Linux where writes to newly allocated page cache pages happen without a subsequent call to flush_dcache_page() (several PIO drivers including USB HCD). This patch changes the meaning of PG_arch_1 to be PG_dcache_clean and always flush the D-cache for a newly mapped page in update_mmu_cache(). The patch also sets the PG_arch_1 bit in the DMA cache maintenance function to avoid additional cache flushing in update_mmu_cache(). Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> --- arch/arm/include/asm/cacheflush.h | 6 +++--- arch/arm/include/asm/tlbflush.h | 2 +- arch/arm/mm/copypage-v4mc.c | 2 +- arch/arm/mm/copypage-v6.c | 2 +- arch/arm/mm/copypage-xscale.c | 2 +- arch/arm/mm/dma-mapping.c | 6 ++++++ arch/arm/mm/fault-armv.c | 4 ++-- arch/arm/mm/flush.c | 2 +- 8 files changed, 16 insertions(+), 10 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 4656a24..d3730f0 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -137,10 +137,10 @@ #endif /* - * This flag is used to indicate that the page pointed to by a pte - * is dirty and requires cleaning before returning it to the user. + * This flag is used to indicate that the page pointed to by a pte is clean + * and does not require cleaning before returning it to the user. */ -#define PG_dcache_dirty PG_arch_1 +#define PG_dcache_clean PG_arch_1 /* * MM Cache Management diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index bd863d8..40a7092 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -552,7 +552,7 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); #endif /* - * if PG_dcache_dirty is set for the page, we need to ensure that any + * If PG_dcache_clean is not set for the page, we need to ensure that any * cache entries for the kernels virtual memory range are written * back to the page. */ diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index 598c51a..b806151 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -73,7 +73,7 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from, { void *kto = kmap_atomic(to, KM_USER1); - if (test_and_clear_bit(PG_dcache_dirty, &from->flags)) + if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); spin_lock(&minicache_lock); diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index f55fa10..bdba6c6 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -79,7 +79,7 @@ static void v6_copy_user_highpage_aliasing(struct page *to, unsigned int offset = CACHE_COLOUR(vaddr); unsigned long kfrom, kto; - if (test_and_clear_bit(PG_dcache_dirty, &from->flags)) + if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); /* FIXME: not highmem safe */ diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 9920c0a..649bbcd 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -95,7 +95,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from, { void *kto = kmap_atomic(to, KM_USER1); - if (test_and_clear_bit(PG_dcache_dirty, &from->flags)) + if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); spin_lock(&minicache_lock); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 13fa536..bb9b612 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -508,6 +508,12 @@ void ___dma_page_dev_to_cpu(struct page *page, unsigned long off, outer_inv_range(paddr, paddr + size); dma_cache_maint_page(page, off, size, dir, dmac_unmap_area); + + /* + * Mark the D-cache clean for this page to avoid extra flushing. + */ + if (dir != DMA_TO_DEVICE) + set_bit(PG_dcache_clean, &page->flags); } EXPORT_SYMBOL(___dma_page_dev_to_cpu); diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 9d77d90..91a691f 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -141,7 +141,7 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma, * a page table, or changing an existing PTE. Basically, there are two * things that we need to take care of: * - * 1. If PG_dcache_dirty is set for the page, we need to ensure + * 1. If PG_dcache_clean is not set for the page, we need to ensure * that any cache entries for the kernels virtual memory * range are written back to the page. * 2. If we have multiple shared mappings of the same space in @@ -168,7 +168,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, return; mapping = page_mapping(page); - if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) + if (!test_and_set_bit(PG_dcache_clean, &page->flags)) __flush_dcache_page(mapping, page); if (mapping) { if (cache_is_vivt()) diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 5ad8711..5abab9a 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -245,7 +245,7 @@ void flush_dcache_page(struct page *page) if (!cache_ops_need_broadcast() && !PageHighMem(page) && mapping && !mapping_mapped(mapping)) - set_bit(PG_dcache_dirty, &page->flags); + clear_bit(PG_dcache_clean, &page->flags); else { __flush_dcache_page(mapping, page); if (mapping && cache_is_vivt()) ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 4/4] ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP 2010-05-20 14:29 [PATCH 0/4] Patches for -next Catalin Marinas ` (2 preceding siblings ...) 2010-05-20 14:30 ` [PATCH 3/4] ARM: Assume new page cache pages have dirty D-cache Catalin Marinas @ 2010-05-20 14:30 ` Catalin Marinas 2010-05-21 5:59 ` [PATCH 0/4] Patches for -next Shilimkar, Santosh 4 siblings, 0 replies; 23+ messages in thread From: Catalin Marinas @ 2010-05-20 14:30 UTC (permalink / raw) To: linux-arm-kernel On SMP systems, there is a small chance of a PTE becoming visible to a different CPU before the cache maintenance operations in update_mmu_cache(). This patch clears the L_PTE_EXEC bit in set_pte_at() but sets it later in update_mmu_cache() if vm_flags & VM_EXEC. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> --- arch/arm/include/asm/pgtable.h | 12 ++++++++++++ arch/arm/mm/fault-armv.c | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index ab68cf1..c50691f 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -278,9 +278,21 @@ extern struct page *empty_zero_page; #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) +#ifndef CONFIG_SMP #define set_pte_at(mm,addr,ptep,pteval) do { \ set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \ } while (0) +#else +/* + * The L_PTE_EXEC attribute is later be set in update_mmu_cache() to avoid a + * race with SMP systems executing from the new mapping before the cache + * flushing took place. + */ +#define set_pte_at(mm,addr,ptep,pteval) do { \ + set_pte_ext(ptep, __pte(pte_val(pteval) & ~L_PTE_EXEC), \ + (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \ + } while (0) +#endif /* * The following only work if pte_present() is true. diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 91a691f..f2b2fa4 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -170,11 +170,18 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, mapping = page_mapping(page); if (!test_and_set_bit(PG_dcache_clean, &page->flags)) __flush_dcache_page(mapping, page); - if (mapping) { - if (cache_is_vivt()) - make_coherent(mapping, vma, addr, ptep, pfn); - else if (vma->vm_flags & VM_EXEC) - __flush_icache_all(); + if (!mapping) + return; + + if (cache_is_vivt()) + make_coherent(mapping, vma, addr, ptep, pfn); + else if (vma->vm_flags & VM_EXEC) { + __flush_icache_all(); +#ifdef CONFIG_SMP + set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), + addr >= TASK_SIZE ? 0 : PTE_EXT_NG); + flush_tlb_page(vma, addr); +#endif } } ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-20 14:29 [PATCH 0/4] Patches for -next Catalin Marinas ` (3 preceding siblings ...) 2010-05-20 14:30 ` [PATCH 4/4] ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP Catalin Marinas @ 2010-05-21 5:59 ` Shilimkar, Santosh 2010-05-21 6:06 ` Shilimkar, Santosh 2010-05-21 9:52 ` Catalin Marinas 4 siblings, 2 replies; 23+ messages in thread From: Shilimkar, Santosh @ 2010-05-21 5:59 UTC (permalink / raw) To: linux-arm-kernel Catalin, > -----Original Message----- > From: linux-arm-kernel-bounces at lists.infradead.org [mailto:linux-arm-kernel- > bounces at lists.infradead.org] On Behalf Of Catalin Marinas > Sent: Thursday, May 20, 2010 8:00 PM > To: linux-arm-kernel at lists.infradead.org > Subject: [PATCH 0/4] Patches for -next > > Hi, > > I would like to get these patches in the linux-next tree for this > release cycle and aim to submit them for upstream 2.6.36-rc1 (next > merging window). > > Please let me know if you have any objections. > > Thanks. > > > Catalin Marinas (4): > ARM: Remove the domain switching on ARMv6k/v7 CPUs > ARM: Use lazy cache flushing on ARMv7 SMP systems > ARM: Assume new page cache pages have dirty D-cache > ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP > > I just gave quick try with these patches on OMAP4 yesterday. "ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP" patch is creating regression when loading the module. Didn't get time to debug it but though if reporting it. ****************************************************************************** # insmod test_module.ko Unable to handle kernel paging request at virtual address bf005da8 pgd = dfe20000 [bf005da8] *pgd=9fede011, *pte=9fedf4df, *ppte=9fedf45f Internal error: Oops: 8000000f [#1] PREEMPT SMP last sysfs file: Modules linked in: g_zero(+) CPU: 1 Not tainted (2.6.34-00074-g8e3b656 #1) PC is at init+0x0/0x1c [g_zero] LR is at do_one_initcall+0x64/0x1bc pc : [<bf005da8>] lr : [<c002a51c>] psr: 60000013 sp : dfe9ff50 ip : c0356060 fp : dfe9ff7c r10: 00000000 r9 : dfe9e000 r8 : c002b2e8 r7 : 00000000 r6 : bf005da8 r5 : bf002304 r4 : 00000000 r3 : 00000000 r2 : dfe9e000 r1 : 00000000 r0 : bf005da8 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c53c7d Table: 9fe2004a DAC: 00000015 Process insmod (pid: 585, stack limit = 0xdfe9e2f8) Stack: (0xdfe9ff50 to 0xdfea0000) ff40: 40212008 c002b2e8 dfe9ff7c dfe9ff68 ff60: 00000000 bf002304 00092008 40212008 dfe9ffa4 dfe9ff80 c007a72c c002a4c4 ff80: 00000003 40212000 0008f6b0 00000002 00024c72 00000080 00000000 dfe9ffa8 ffa0: c002b140 c007a67c 0008f6b0 00000002 40212008 00024c72 00092008 00000140 ffc0: 0008f6b0 00000002 00024c72 00000080 0008f6b0 bef73f2b 0008f8a8 00000038 ffe0: bef73c60 bef73c50 00013ee4 401a7740 60000010 40212008 ffffffff 00000000 Backtrace: [<c002a4b8>] (do_one_initcall+0x0/0x1bc) from [<c007a72c>] (sys_init_module+0xbc/0x1ec) r7:40212008 r6:00092008 r5:bf002304 r4:00000000 [<c007a670>] (sys_init_module+0x0/0x1ec) from [<c002b140>] (ret_fast_syscall+0x0/0x30) r7:00000080 r6:00024c72 r5:00000002 r4:0008f6b0 Code: e89da800 bf002428 bf00205c bf001f47 (e1a0c00d) ---[ end trace 11affbcdd9483af2 ]--- Segmentation fault ****************************************************************************** ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-21 5:59 ` [PATCH 0/4] Patches for -next Shilimkar, Santosh @ 2010-05-21 6:06 ` Shilimkar, Santosh 2010-05-21 9:52 ` Catalin Marinas 1 sibling, 0 replies; 23+ messages in thread From: Shilimkar, Santosh @ 2010-05-21 6:06 UTC (permalink / raw) To: linux-arm-kernel One correction > -----Original Message----- > From: linux-arm-kernel-bounces at lists.infradead.org [mailto:linux-arm-kernel- > bounces at lists.infradead.org] On Behalf Of Shilimkar, Santosh > Sent: Friday, May 21, 2010 11:30 AM > To: Catalin Marinas > Cc: Russell King - ARM Linux; linux-arm-kernel at lists.infradead.org > Subject: RE: [PATCH 0/4] Patches for -next > > Catalin, > > -----Original Message----- > > From: linux-arm-kernel-bounces at lists.infradead.org [mailto:linux-arm-kernel- > > bounces at lists.infradead.org] On Behalf Of Catalin Marinas > > Sent: Thursday, May 20, 2010 8:00 PM > > To: linux-arm-kernel at lists.infradead.org > > Subject: [PATCH 0/4] Patches for -next > > > > Hi, > > > > I would like to get these patches in the linux-next tree for this > > release cycle and aim to submit them for upstream 2.6.36-rc1 (next > > merging window). > > > > Please let me know if you have any objections. > > > > Thanks. > > > > > > Catalin Marinas (4): > > ARM: Remove the domain switching on ARMv6k/v7 CPUs > > ARM: Use lazy cache flushing on ARMv7 SMP systems > > ARM: Assume new page cache pages have dirty D-cache > > ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP > > > > > I just gave quick try with these patches on OMAP4 yesterday. > "ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP" > patch is creating regression when loading the module. > > Didn't get time to debug it but though if reporting it. > > ****************************************************************************** > # insmod test_module.ko #insmod g_zero.ko > Unable to handle kernel paging request at virtual address bf005da8 > pgd = dfe20000 > [bf005da8] *pgd=9fede011, *pte=9fedf4df, *ppte=9fedf45f > Internal error: Oops: 8000000f [#1] PREEMPT SMP > last sysfs file: > Modules linked in: g_zero(+) > CPU: 1 Not tainted (2.6.34-00074-g8e3b656 #1) > PC is at init+0x0/0x1c [g_zero] > LR is at do_one_initcall+0x64/0x1bc > pc : [<bf005da8>] lr : [<c002a51c>] psr: 60000013 > sp : dfe9ff50 ip : c0356060 fp : dfe9ff7c > r10: 00000000 r9 : dfe9e000 r8 : c002b2e8 > r7 : 00000000 r6 : bf005da8 r5 : bf002304 r4 : 00000000 > r3 : 00000000 r2 : dfe9e000 r1 : 00000000 r0 : bf005da8 > Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user > Control: 10c53c7d Table: 9fe2004a DAC: 00000015 > Process insmod (pid: 585, stack limit = 0xdfe9e2f8) > Stack: (0xdfe9ff50 to 0xdfea0000) > ff40: 40212008 c002b2e8 dfe9ff7c > dfe9ff68 > ff60: 00000000 bf002304 00092008 40212008 dfe9ffa4 dfe9ff80 c007a72c > c002a4c4 > ff80: 00000003 40212000 0008f6b0 00000002 00024c72 00000080 00000000 > dfe9ffa8 > ffa0: c002b140 c007a67c 0008f6b0 00000002 40212008 00024c72 00092008 > 00000140 > ffc0: 0008f6b0 00000002 00024c72 00000080 0008f6b0 bef73f2b 0008f8a8 > 00000038 > ffe0: bef73c60 bef73c50 00013ee4 401a7740 60000010 40212008 ffffffff > 00000000 > Backtrace: > [<c002a4b8>] (do_one_initcall+0x0/0x1bc) from [<c007a72c>] > (sys_init_module+0xbc/0x1ec) > r7:40212008 r6:00092008 r5:bf002304 r4:00000000 > [<c007a670>] (sys_init_module+0x0/0x1ec) from [<c002b140>] > (ret_fast_syscall+0x0/0x30) > r7:00000080 r6:00024c72 r5:00000002 r4:0008f6b0 > Code: e89da800 bf002428 bf00205c bf001f47 (e1a0c00d) > ---[ end trace 11affbcdd9483af2 ]--- > Segmentation fault > ****************************************************************************** > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-21 5:59 ` [PATCH 0/4] Patches for -next Shilimkar, Santosh 2010-05-21 6:06 ` Shilimkar, Santosh @ 2010-05-21 9:52 ` Catalin Marinas 2010-05-21 10:57 ` Shilimkar, Santosh 2010-05-21 19:04 ` Russell King - ARM Linux 1 sibling, 2 replies; 23+ messages in thread From: Catalin Marinas @ 2010-05-21 9:52 UTC (permalink / raw) To: linux-arm-kernel Santosh, On Fri, 2010-05-21 at 06:59 +0100, Shilimkar, Santosh wrote: > > Catalin Marinas (4): > > ARM: Remove the domain switching on ARMv6k/v7 CPUs > > ARM: Use lazy cache flushing on ARMv7 SMP systems > > ARM: Assume new page cache pages have dirty D-cache > > ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP > > > > > I just gave quick try with these patches on OMAP4 yesterday. > "ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP" > patch is creating regression when loading the module. Thanks for testing and reporting this. I missed the fact the modules allocation uses set_pte_at(). Below is an updated patch which makes sure that L_PTE_EXEC is set for addresses greater than TASK_SIZE. We shouldn't have a race for modules as initialisation only happens on a single CPU. Could you please try the updated patch below? ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP From: Catalin Marinas <catalin.marinas@arm.com> On SMP systems, there is a small chance of a PTE becoming visible to a different CPU before the cache maintenance operations in update_mmu_cache(). This patch clears the L_PTE_EXEC bit in set_pte_at() but sets it later in update_mmu_cache() if vm_flags & VM_EXEC. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> --- arch/arm/include/asm/pgtable.h | 15 +++++++++++++++ arch/arm/mm/fault-armv.c | 17 ++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 1139768..ee8cc13 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -278,9 +278,24 @@ extern struct page *empty_zero_page; #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) +#ifndef CONFIG_SMP #define set_pte_at(mm,addr,ptep,pteval) do { \ set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \ } while (0) +#else +/* + * The L_PTE_EXEC attribute is later set in update_mmu_cache() to avoid a + * race with SMP systems executing from the new mapping before the cache + * flushing took place. + */ +#define set_pte_at(mm,addr,ptep,pteval) do { \ + if ((addr) >= TASK_SIZE) \ + set_pte_ext(ptep, pteval, 0); \ + else \ + set_pte_ext(ptep, __pte(pte_val(pteval) & ~L_PTE_EXEC), \ + PTE_EXT_NG); \ + } while (0) +#endif /* * The following only work if pte_present() is true. diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index f9e9cbb..c01356d 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -172,11 +172,18 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, mapping = page_mapping(page); if (!test_and_set_bit(PG_dcache_clean, &page->flags)) __flush_dcache_page(mapping, page); - if (mapping) { - if (cache_is_vivt()) - make_coherent(mapping, vma, addr, ptep, pfn); - else if (vma->vm_flags & VM_EXEC) - __flush_icache_all(); + if (!mapping) + return; + + if (cache_is_vivt()) + make_coherent(mapping, vma, addr, ptep, pfn); + else if (vma->vm_flags & VM_EXEC) { + __flush_icache_all(); +#ifdef CONFIG_SMP + set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), + addr >= TASK_SIZE ? 0 : PTE_EXT_NG); + flush_tlb_page(vma, addr); +#endif } } -- Catalin ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-21 9:52 ` Catalin Marinas @ 2010-05-21 10:57 ` Shilimkar, Santosh 2010-05-21 14:49 ` Catalin Marinas 2010-05-21 19:04 ` Russell King - ARM Linux 1 sibling, 1 reply; 23+ messages in thread From: Shilimkar, Santosh @ 2010-05-21 10:57 UTC (permalink / raw) To: linux-arm-kernel Catalin, > -----Original Message----- > From: Catalin Marinas [mailto:catalin.marinas at arm.com] > Sent: Friday, May 21, 2010 3:22 PM > To: Shilimkar, Santosh > Cc: Russell King - ARM Linux; linux-arm-kernel at lists.infradead.org > Subject: RE: [PATCH 0/4] Patches for -next > > Santosh, > > On Fri, 2010-05-21 at 06:59 +0100, Shilimkar, Santosh wrote: > > > Catalin Marinas (4): > > > ARM: Remove the domain switching on ARMv6k/v7 CPUs > > > ARM: Use lazy cache flushing on ARMv7 SMP systems > > > ARM: Assume new page cache pages have dirty D-cache > > > ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP > > > > > > > > I just gave quick try with these patches on OMAP4 yesterday. > > "ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP" > > patch is creating regression when loading the module. > > Thanks for testing and reporting this. I missed the fact the modules > allocation uses set_pte_at(). Below is an updated patch which makes sure > that L_PTE_EXEC is set for addresses greater than TASK_SIZE. We > shouldn't have a race for modules as initialisation only happens on a > single CPU. > > Could you please try the updated patch below? > This one works fine!! You can add, Tested-by: Santosh Shilimkar <Santosh.shilimkar@ti.com> > > ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP > > From: Catalin Marinas <catalin.marinas@arm.com> > > On SMP systems, there is a small chance of a PTE becoming visible to a > different CPU before the cache maintenance operations in > update_mmu_cache(). This patch clears the L_PTE_EXEC bit in set_pte_at() > but sets it later in update_mmu_cache() if vm_flags & VM_EXEC. > > Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> > --- > arch/arm/include/asm/pgtable.h | 15 +++++++++++++++ > arch/arm/mm/fault-armv.c | 17 ++++++++++++----- > 2 files changed, 27 insertions(+), 5 deletions(-) > > diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h > index 1139768..ee8cc13 100644 > --- a/arch/arm/include/asm/pgtable.h > +++ b/arch/arm/include/asm/pgtable.h > @@ -278,9 +278,24 @@ extern struct page *empty_zero_page; > > #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) > > +#ifndef CONFIG_SMP > #define set_pte_at(mm,addr,ptep,pteval) do { \ > set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \ > } while (0) > +#else > +/* > + * The L_PTE_EXEC attribute is later set in update_mmu_cache() to avoid a > + * race with SMP systems executing from the new mapping before the cache > + * flushing took place. > + */ > +#define set_pte_at(mm,addr,ptep,pteval) do { \ > + if ((addr) >= TASK_SIZE) \ > + set_pte_ext(ptep, pteval, 0); \ > + else \ > + set_pte_ext(ptep, __pte(pte_val(pteval) & ~L_PTE_EXEC), \ > + PTE_EXT_NG); \ > + } while (0) > +#endif > > /* > * The following only work if pte_present() is true. > diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c > index f9e9cbb..c01356d 100644 > --- a/arch/arm/mm/fault-armv.c > +++ b/arch/arm/mm/fault-armv.c > @@ -172,11 +172,18 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, > mapping = page_mapping(page); > if (!test_and_set_bit(PG_dcache_clean, &page->flags)) > __flush_dcache_page(mapping, page); > - if (mapping) { > - if (cache_is_vivt()) > - make_coherent(mapping, vma, addr, ptep, pfn); > - else if (vma->vm_flags & VM_EXEC) > - __flush_icache_all(); > + if (!mapping) > + return; > + > + if (cache_is_vivt()) > + make_coherent(mapping, vma, addr, ptep, pfn); > + else if (vma->vm_flags & VM_EXEC) { > + __flush_icache_all(); > +#ifdef CONFIG_SMP > + set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), > + addr >= TASK_SIZE ? 0 : PTE_EXT_NG); > + flush_tlb_page(vma, addr); > +#endif > } > } > > > > -- Regards, Santosh ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-21 10:57 ` Shilimkar, Santosh @ 2010-05-21 14:49 ` Catalin Marinas 2010-05-21 14:52 ` Shilimkar, Santosh 0 siblings, 1 reply; 23+ messages in thread From: Catalin Marinas @ 2010-05-21 14:49 UTC (permalink / raw) To: linux-arm-kernel On Fri, 2010-05-21 at 11:57 +0100, Shilimkar, Santosh wrote: > Catalin, > > > -----Original Message----- > > From: Catalin Marinas [mailto:catalin.marinas at arm.com] > > Sent: Friday, May 21, 2010 3:22 PM > > To: Shilimkar, Santosh > > Cc: Russell King - ARM Linux; linux-arm-kernel at lists.infradead.org > > Subject: RE: [PATCH 0/4] Patches for -next > > > > Santosh, > > > > On Fri, 2010-05-21 at 06:59 +0100, Shilimkar, Santosh wrote: > > > > Catalin Marinas (4): > > > > ARM: Remove the domain switching on ARMv6k/v7 CPUs > > > > ARM: Use lazy cache flushing on ARMv7 SMP systems > > > > ARM: Assume new page cache pages have dirty D-cache > > > > ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP > > > > > > > > > > > I just gave quick try with these patches on OMAP4 yesterday. > > > "ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP" > > > patch is creating regression when loading the module. > > > > Thanks for testing and reporting this. I missed the fact the modules > > allocation uses set_pte_at(). Below is an updated patch which makes sure > > that L_PTE_EXEC is set for addresses greater than TASK_SIZE. We > > shouldn't have a race for modules as initialisation only happens on a > > single CPU. > > > > Could you please try the updated patch below? > > > This one works fine!! > You can add, Tested-by: Santosh Shilimkar <Santosh.shilimkar@ti.com> Thanks for testing. Have you tried the whole series or just this one? -- Catalin ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-21 14:49 ` Catalin Marinas @ 2010-05-21 14:52 ` Shilimkar, Santosh 0 siblings, 0 replies; 23+ messages in thread From: Shilimkar, Santosh @ 2010-05-21 14:52 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Catalin Marinas [mailto:catalin.marinas at arm.com] > Sent: Friday, May 21, 2010 8:20 PM > To: Shilimkar, Santosh > Cc: Russell King - ARM Linux; linux-arm-kernel at lists.infradead.org > Subject: RE: [PATCH 0/4] Patches for -next > > On Fri, 2010-05-21 at 11:57 +0100, Shilimkar, Santosh wrote: > > Catalin, > > > > > -----Original Message----- > > > From: Catalin Marinas [mailto:catalin.marinas at arm.com] > > > Sent: Friday, May 21, 2010 3:22 PM > > > To: Shilimkar, Santosh > > > Cc: Russell King - ARM Linux; linux-arm-kernel at lists.infradead.org > > > Subject: RE: [PATCH 0/4] Patches for -next > > > > > > Santosh, > > > > > > On Fri, 2010-05-21 at 06:59 +0100, Shilimkar, Santosh wrote: > > > > > Catalin Marinas (4): > > > > > ARM: Remove the domain switching on ARMv6k/v7 CPUs > > > > > ARM: Use lazy cache flushing on ARMv7 SMP systems > > > > > ARM: Assume new page cache pages have dirty D-cache > > > > > ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP > > > > > > > > > > > > > > I just gave quick try with these patches on OMAP4 yesterday. > > > > "ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP" > > > > patch is creating regression when loading the module. > > > > > > Thanks for testing and reporting this. I missed the fact the modules > > > allocation uses set_pte_at(). Below is an updated patch which makes sure > > > that L_PTE_EXEC is set for addresses greater than TASK_SIZE. We > > > shouldn't have a race for modules as initialisation only happens on a > > > single CPU. > > > > > > Could you please try the updated patch below? > > > > > This one works fine!! > > You can add, Tested-by: Santosh Shilimkar <Santosh.shilimkar@ti.com> > > Thanks for testing. > > Have you tried the whole series or just this one? Whole series. Regards Santosh ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-21 9:52 ` Catalin Marinas 2010-05-21 10:57 ` Shilimkar, Santosh @ 2010-05-21 19:04 ` Russell King - ARM Linux 2010-05-24 11:31 ` Catalin Marinas 1 sibling, 1 reply; 23+ messages in thread From: Russell King - ARM Linux @ 2010-05-21 19:04 UTC (permalink / raw) To: linux-arm-kernel On Fri, May 21, 2010 at 10:52:21AM +0100, Catalin Marinas wrote: > + if (cache_is_vivt()) > + make_coherent(mapping, vma, addr, ptep, pfn); > + else if (vma->vm_flags & VM_EXEC) { > + __flush_icache_all(); > +#ifdef CONFIG_SMP > + set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), > + addr >= TASK_SIZE ? 0 : PTE_EXT_NG); You don't need this test - pages which have VMAs are userspace pages, and therefore the address is always < TASK_SIZE. Therefore, they're always non-global: set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), PTE_EXT_NG); ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-21 19:04 ` Russell King - ARM Linux @ 2010-05-24 11:31 ` Catalin Marinas 2010-05-24 12:08 ` Russell King - ARM Linux 0 siblings, 1 reply; 23+ messages in thread From: Catalin Marinas @ 2010-05-24 11:31 UTC (permalink / raw) To: linux-arm-kernel On Fri, 2010-05-21 at 20:04 +0100, Russell King - ARM Linux wrote: > On Fri, May 21, 2010 at 10:52:21AM +0100, Catalin Marinas wrote: > > + if (cache_is_vivt()) > > + make_coherent(mapping, vma, addr, ptep, pfn); > > + else if (vma->vm_flags & VM_EXEC) { > > + __flush_icache_all(); > > +#ifdef CONFIG_SMP > > + set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), > > + addr >= TASK_SIZE ? 0 : PTE_EXT_NG); > > You don't need this test - pages which have VMAs are userspace pages, > and therefore the address is always < TASK_SIZE. Therefore, they're > always non-global: > > set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), > PTE_EXT_NG); Good point. Thanks. So, are you ok for me to push these patches to -next? -- Catalin ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-24 11:31 ` Catalin Marinas @ 2010-05-24 12:08 ` Russell King - ARM Linux 2010-05-24 13:06 ` Catalin Marinas 0 siblings, 1 reply; 23+ messages in thread From: Russell King - ARM Linux @ 2010-05-24 12:08 UTC (permalink / raw) To: linux-arm-kernel On Mon, May 24, 2010 at 12:31:04PM +0100, Catalin Marinas wrote: > On Fri, 2010-05-21 at 20:04 +0100, Russell King - ARM Linux wrote: > > On Fri, May 21, 2010 at 10:52:21AM +0100, Catalin Marinas wrote: > > > + if (cache_is_vivt()) > > > + make_coherent(mapping, vma, addr, ptep, pfn); > > > + else if (vma->vm_flags & VM_EXEC) { > > > + __flush_icache_all(); > > > +#ifdef CONFIG_SMP > > > + set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), > > > + addr >= TASK_SIZE ? 0 : PTE_EXT_NG); > > > > You don't need this test - pages which have VMAs are userspace pages, > > and therefore the address is always < TASK_SIZE. Therefore, they're > > always non-global: > > > > set_pte_ext(ptep, __pte(pte_val(*ptep) | L_PTE_EXEC), > > PTE_EXT_NG); > > Good point. Thanks. > > So, are you ok for me to push these patches to -next? I don't think these patches are quite ready for -next just yet. Apart from my comment on patch 1, I think patch 4 is buggy in three other ways: 1. VIVT cached CPUs end up with L_PTE_EXEC clear on their mappings with this patch. Luckily for us, nothing tests for this (there used to be a pte_exec() helper for testing this, but I removed it as there were no users in the kernel) - but even so, I think it should be documented that this is the case. 2. L_PTE_EXEC is also forced-clear on non-page cache pages by this patch, even if executable permission was requested. I'm guessing this will be bad for tasks which generate code on the fly. 3. Kernel mappings are also created with set_pte_at(), and so module mappings will have L_PTE_EXEC cleared, resulting in kernel modules being non-executable - which is rather bad. Not sure what the right fix for this is at the moment - and if we're going to make set_pte_at() more complicated, it should be moved out of line. ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-24 12:08 ` Russell King - ARM Linux @ 2010-05-24 13:06 ` Catalin Marinas 2010-05-26 13:06 ` Catalin Marinas 0 siblings, 1 reply; 23+ messages in thread From: Catalin Marinas @ 2010-05-24 13:06 UTC (permalink / raw) To: linux-arm-kernel On Mon, 2010-05-24 at 13:08 +0100, Russell King - ARM Linux wrote: > On Mon, May 24, 2010 at 12:31:04PM +0100, Catalin Marinas wrote: > > So, are you ok for me to push these patches to -next? > > I don't think these patches are quite ready for -next just yet. Apart > from my comment on patch 1, I think patch 4 is buggy in three other > ways: > > 1. VIVT cached CPUs end up with L_PTE_EXEC clear on their mappings > with this patch. Luckily for us, nothing tests for this (there > used to be a pte_exec() helper for testing this, but I removed it > as there were no users in the kernel) - but even so, I think it > should be documented that this is the case. The L_PTE_EXEC is only cleared in set_pte_at() if SMP. We won't have any VIVT SMP system. I could add a comment for this. > 2. L_PTE_EXEC is also forced-clear on non-page cache pages by this > patch, even if executable permission was requested. I'm guessing > this will be bad for tasks which generate code on the fly. Attributes changing via sys_mprotect() won't be handled, so this would be a problem. > 3. Kernel mappings are also created with set_pte_at(), and so module > mappings will have L_PTE_EXEC cleared, resulting in kernel modules > being non-executable - which is rather bad. Yes, this was already pointed at by Santosh and fixed in the latest version of the patch (it checks for addr < TASK_SIZE). > Not sure what the right fix for this is at the moment - and if we're > going to make set_pte_at() more complicated, it should be moved out > of line. The only way I can think of is to do the cache flushing in set_pte_at(). It would have a similar approach with clearing the exec bit, flushing the cache and then setting it (since we may not always have a kernel mapping). The exec/no-exec would only be done for SMP. If we go this route, for UP and all the other cache types, should we move the lazy cache flushing out of update_mmu_cache() as well? A side-effect of such change is that mprotect(exec) may trigger a cache flush, which I think it's fine. Thanks. -- Catalin ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-24 13:06 ` Catalin Marinas @ 2010-05-26 13:06 ` Catalin Marinas 2010-05-26 18:28 ` Russell King - ARM Linux 0 siblings, 1 reply; 23+ messages in thread From: Catalin Marinas @ 2010-05-26 13:06 UTC (permalink / raw) To: linux-arm-kernel On Mon, 2010-05-24 at 14:06 +0100, Catalin Marinas wrote: > On Mon, 2010-05-24 at 13:08 +0100, Russell King - ARM Linux wrote: > > Not sure what the right fix for this is at the moment - and if we're > > going to make set_pte_at() more complicated, it should be moved out > > of line. > > The only way I can think of is to do the cache flushing in set_pte_at(). Here's a new variant dealing with cache flushing via set_pte_at(). It could be optimised to avoid whole I-cache flushing on non-aliasing VIPT (well, all SMP systems). We could even make this method the default for UP v6+ systems. If you are OK with this approach, I'll repost the patches I have for -next. Thanks. ARM: Synchronise the I and D caches via set_pte_at() on SMP systems From: Catalin Marinas <catalin.marinas@arm.com> On SMP systems, there is a small chance of a PTE becoming visible to a different CPU before the cache maintenance operations in update_mmu_cache(). This patch follows the IA-64 and PowerPC approach of synchronising the I and D caches via the set_pte_at() function. In this case, there is no need for update_mmu_cache() to be implemented since lazy cache flushing is already handled by the time this function is called. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> --- arch/arm/include/asm/pgtable.h | 21 ++++++++++++++++++--- arch/arm/include/asm/tlbflush.h | 10 +++++++++- arch/arm/mm/fault-armv.c | 2 ++ arch/arm/mm/flush.c | 13 +++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index ab68cf1..9043f60 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -278,9 +278,24 @@ extern struct page *empty_zero_page; #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) -#define set_pte_at(mm,addr,ptep,pteval) do { \ - set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \ - } while (0) +#ifndef CONFIG_SMP +static inline void __sync_icache_dcache(pte_t pteval) +{ +} +#else +extern void __sync_icache_dcache(pte_t pteval); +#endif + +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) +{ + if (addr >= TASK_SIZE) + set_pte_ext(ptep, pteval, 0); + else { + __sync_icache_dcache(pteval); + set_pte_ext(ptep, pteval, PTE_EXT_NG); + } +} /* * The following only work if pte_present() is true. diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index 40a7092..6aabedd 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -554,10 +554,18 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); /* * If PG_dcache_clean is not set for the page, we need to ensure that any * cache entries for the kernels virtual memory range are written - * back to the page. + * back to the page. On SMP systems, the cache coherency is handled in the + * set_pte_at() function. */ +#ifndef CONFIG_SMP extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep); +#else +static inline void update_mmu_cache(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ +} +#endif #endif diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 91a691f..030f1da 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -28,6 +28,7 @@ static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE; +#ifndef CONFIG_SMP /* * We take the easy way out of this problem - we make the * PTE uncacheable. However, we leave the write buffer on. @@ -177,6 +178,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, __flush_icache_all(); } } +#endif /* !CONFIG_SMP */ /* * Check whether the write buffer has physical address aliasing diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 6f55e36..90a6c60 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -212,6 +212,19 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p flush_dcache_mmap_unlock(mapping); } +#ifdef CONFIG_SMP +void __sync_icache_dcache(pte_t pteval) +{ + struct page *page = pte_page(pteval); + struct address_space *mapping = page_mapping(page); + + if (!test_and_set_bit(PG_dcache_clean, &page->flags)) + __flush_dcache_page(mapping, page); + if (pte_val(pteval) & L_PTE_EXEC) + __flush_icache_all(); +} +#endif + /* * Ensure cache coherency between kernel mapping and userspace mapping * of this page. -- Catalin ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-26 13:06 ` Catalin Marinas @ 2010-05-26 18:28 ` Russell King - ARM Linux 2010-05-27 11:04 ` Catalin Marinas 0 siblings, 1 reply; 23+ messages in thread From: Russell King - ARM Linux @ 2010-05-26 18:28 UTC (permalink / raw) To: linux-arm-kernel On Wed, May 26, 2010 at 02:06:35PM +0100, Catalin Marinas wrote: > +#ifdef CONFIG_SMP > +void __sync_icache_dcache(pte_t pteval) > +{ > + struct page *page = pte_page(pteval); > + struct address_space *mapping = page_mapping(page); Err. no. You're assuming that the physical page associated with the PTE always has a struct page. What if it's a device mapping? What if it's a mapping for some memory which isn't being handled by the kernel? You want this to be: unsigned long pfn = pte_pfn(pteval); if (pfn_valid(pfn)) { struct page *page = pfn_to_page(pfn); struct address_space *mapping = page_mapping(page); ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 0/4] Patches for -next 2010-05-26 18:28 ` Russell King - ARM Linux @ 2010-05-27 11:04 ` Catalin Marinas 0 siblings, 0 replies; 23+ messages in thread From: Catalin Marinas @ 2010-05-27 11:04 UTC (permalink / raw) To: linux-arm-kernel On Wed, 2010-05-26 at 19:28 +0100, Russell King - ARM Linux wrote: > On Wed, May 26, 2010 at 02:06:35PM +0100, Catalin Marinas wrote: > > +#ifdef CONFIG_SMP > > +void __sync_icache_dcache(pte_t pteval) > > +{ > > + struct page *page = pte_page(pteval); > > + struct address_space *mapping = page_mapping(page); > > Err. no. You're assuming that the physical page associated with the > PTE always has a struct page. What if it's a device mapping? What > if it's a mapping for some memory which isn't being handled by the > kernel? > > You want this to be: > > unsigned long pfn = pte_pfn(pteval); > > if (pfn_valid(pfn)) { > struct page *page = pfn_to_page(pfn); > struct address_space *mapping = page_mapping(page); BTW, if we only target non-aliasing VIPT hardware, is there a need for "mapping" above? See below for an updated patch. I got some ideas from IA-64 to do additional checks on pteval before deciding to flush the cache. With this change, the D-cache won't be flushed at all for a page cache page which is not mapped as executable (update_mmu_cache is a no-op). It shouldn't matter since we don't have aliases. ARM: Synchronise the I and D caches via set_pte_at() on SMP systems From: Catalin Marinas <catalin.marinas@arm.com> On SMP systems, there is a small chance of a PTE becoming visible to a different CPU before the cache maintenance operations in update_mmu_cache(). This patch follows the IA-64 and PowerPC approach of synchronising the I and D caches via the set_pte_at() function. In this case, there is no need for update_mmu_cache() to be implemented since lazy cache flushing is already handled by the time this function is called. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> --- arch/arm/include/asm/pgtable.h | 25 ++++++++++++++++++++++--- arch/arm/include/asm/tlbflush.h | 10 +++++++++- arch/arm/mm/fault-armv.c | 2 ++ arch/arm/mm/flush.c | 15 +++++++++++++++ 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index ab68cf1..a3752f5 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -278,9 +278,24 @@ extern struct page *empty_zero_page; #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) -#define set_pte_at(mm,addr,ptep,pteval) do { \ - set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \ - } while (0) +#ifndef CONFIG_SMP +static inline void __sync_icache_dcache(pte_t pteval) +{ +} +#else +extern void __sync_icache_dcache(pte_t pteval); +#endif + +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) +{ + if (addr >= TASK_SIZE) + set_pte_ext(ptep, pteval, 0); + else { + __sync_icache_dcache(pteval); + set_pte_ext(ptep, pteval, PTE_EXT_NG); + } +} /* * The following only work if pte_present() is true. @@ -292,6 +307,10 @@ extern struct page *empty_zero_page; #define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG) #define pte_special(pte) (0) +#define pte_present_exec_user(pte) \ + ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_EXEC | L_PTE_USER)) == \ + (L_PTE_PRESENT | L_PTE_EXEC | L_PTE_USER)) + #define PTE_BIT_FUNC(fn,op) \ static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index 40a7092..6aabedd 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -554,10 +554,18 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); /* * If PG_dcache_clean is not set for the page, we need to ensure that any * cache entries for the kernels virtual memory range are written - * back to the page. + * back to the page. On SMP systems, the cache coherency is handled in the + * set_pte_at() function. */ +#ifndef CONFIG_SMP extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep); +#else +static inline void update_mmu_cache(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ +} +#endif #endif diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 91a691f..030f1da 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -28,6 +28,7 @@ static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE; +#ifndef CONFIG_SMP /* * We take the easy way out of this problem - we make the * PTE uncacheable. However, we leave the write buffer on. @@ -177,6 +178,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, __flush_icache_all(); } } +#endif /* !CONFIG_SMP */ /* * Check whether the write buffer has physical address aliasing diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 6f55e36..2d08a5e 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -212,6 +212,21 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p flush_dcache_mmap_unlock(mapping); } +#ifdef CONFIG_SMP +void __sync_icache_dcache(pte_t pteval) +{ + unsigned long pfn = pte_pfn(pteval); + + if (pfn_valid(pfn) && pte_present_exec_user(pteval)) { + struct page *page = pfn_to_page(pfn); + + if (!test_and_set_bit(PG_dcache_clean, &page->flags)) + __flush_dcache_page(NULL, page); + __flush_icache_all(); + } +} +#endif + /* * Ensure cache coherency between kernel mapping and userspace mapping * of this page. -- Catalin ^ permalink raw reply related [flat|nested] 23+ messages in thread
end of thread, other threads:[~2010-05-27 11:04 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-05-20 14:29 [PATCH 0/4] Patches for -next Catalin Marinas 2010-05-20 14:30 ` [PATCH 1/4] ARM: Remove the domain switching on ARMv6k/v7 CPUs Catalin Marinas 2010-05-24 11:45 ` Russell King - ARM Linux 2010-05-24 13:25 ` Catalin Marinas 2010-05-24 13:52 ` Catalin Marinas 2010-05-24 13:59 ` Russell King - ARM Linux 2010-05-24 14:02 ` Catalin Marinas 2010-05-20 14:30 ` [PATCH 2/4] ARM: Use lazy cache flushing on ARMv7 SMP systems Catalin Marinas 2010-05-20 14:30 ` [PATCH 3/4] ARM: Assume new page cache pages have dirty D-cache Catalin Marinas 2010-05-20 14:30 ` [PATCH 4/4] ARM: Defer the L_PTE_EXEC flag setting to update_mmu_cache() on SMP Catalin Marinas 2010-05-21 5:59 ` [PATCH 0/4] Patches for -next Shilimkar, Santosh 2010-05-21 6:06 ` Shilimkar, Santosh 2010-05-21 9:52 ` Catalin Marinas 2010-05-21 10:57 ` Shilimkar, Santosh 2010-05-21 14:49 ` Catalin Marinas 2010-05-21 14:52 ` Shilimkar, Santosh 2010-05-21 19:04 ` Russell King - ARM Linux 2010-05-24 11:31 ` Catalin Marinas 2010-05-24 12:08 ` Russell King - ARM Linux 2010-05-24 13:06 ` Catalin Marinas 2010-05-26 13:06 ` Catalin Marinas 2010-05-26 18:28 ` Russell King - ARM Linux 2010-05-27 11:04 ` Catalin Marinas
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).