* [PATCH 0/2] Detect and handle I-cache aliases when D-cache is non-aliasing @ 2010-08-05 10:36 Will Deacon 2010-08-05 10:36 ` [PATCH 1/2] ARM: setup: detect aliasing I-cache " Will Deacon 2010-08-18 10:48 ` [PATCH 0/2] Detect and handle I-cache aliases when D-cache is non-aliasing Will Deacon 0 siblings, 2 replies; 4+ messages in thread From: Will Deacon @ 2010-08-05 10:36 UTC (permalink / raw) To: linux-arm-kernel Last month, I posted some patches to fix ptrace software breakpoints: http://lists.infradead.org/pipermail/linux-arm-kernel/2010-July/020649.html One of these patches added a workaround for a hardware erratum, so I have submitted that to the patch system. The other patch simply called __flush_icache_all() in flush_ptrace_access to avoid having to worry about I-cache aliases when cache_is_vipt_nonaliasing() is true. This isn't ideal if the debugger decides to insert lots of software breakpoints sequentially (for example, when single-stepping a number of times). These two patches add proper identification of aliasing I-caches when the D-cache is nonaliasing. flush_ptrace_access can then flush only the relevant I-cache lines instead of the entire cache. Cc: Russell King - ARM Linux <linux@arm.linux.org.uk> Cc: Catalin Marinas <catalin.marinas@arm.com> Will Deacon (2): ARM: setup: detect aliasing I-cache when D-cache is non-aliasing ARM: flush_ptrace_access: invalidate correct I-cache alias arch/arm/include/asm/cachetype.h | 8 ++++++-- arch/arm/kernel/setup.c | 38 +++++++++++++++++++++++++++++++++++--- arch/arm/mm/flush.c | 23 ++++++++++++++++++++--- 3 files changed, 61 insertions(+), 8 deletions(-) ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] ARM: setup: detect aliasing I-cache when D-cache is non-aliasing 2010-08-05 10:36 [PATCH 0/2] Detect and handle I-cache aliases when D-cache is non-aliasing Will Deacon @ 2010-08-05 10:36 ` Will Deacon 2010-08-05 10:36 ` [PATCH 2/2] ARM: flush_ptrace_access: invalidate correct I-cache alias Will Deacon 2010-08-18 10:48 ` [PATCH 0/2] Detect and handle I-cache aliases when D-cache is non-aliasing Will Deacon 1 sibling, 1 reply; 4+ messages in thread From: Will Deacon @ 2010-08-05 10:36 UTC (permalink / raw) To: linux-arm-kernel Currently, the Kernel assumes that if a CPU has a non-aliasing D-cache then the I-cache is also non-aliasing. This may not be true on ARM cores from v6 onwards, which may have aliasing I-caches but non-aliasing D-caches. This patch adds a cpu_has_aliasing_icache function, which is called from cacheid_init and adds CACHEID_VIPT_I_ALIASING to the cacheid when appropriate. A utility macro, icache_is_vipt_aliasing(), is also provided. Cc: Russell King - ARM Linux <linux@arm.linux.org.uk> Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/include/asm/cachetype.h | 8 ++++++-- arch/arm/kernel/setup.c | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/cachetype.h b/arch/arm/include/asm/cachetype.h index d3a4c2c..c023db0 100644 --- a/arch/arm/include/asm/cachetype.h +++ b/arch/arm/include/asm/cachetype.h @@ -6,6 +6,7 @@ #define CACHEID_VIPT_ALIASING (1 << 2) #define CACHEID_VIPT (CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING) #define CACHEID_ASID_TAGGED (1 << 3) +#define CACHEID_VIPT_I_ALIASING (1 << 4) extern unsigned int cacheid; @@ -14,15 +15,18 @@ extern unsigned int cacheid; #define cache_is_vipt_nonaliasing() cacheid_is(CACHEID_VIPT_NONALIASING) #define cache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_ALIASING) #define icache_is_vivt_asid_tagged() cacheid_is(CACHEID_ASID_TAGGED) +#define icache_is_vipt_aliasing() cacheid_is(CACHEID_VIPT_I_ALIASING) /* * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture * Mask out support which will never be present on newer CPUs. * - v6+ is never VIVT - * - v7+ VIPT never aliases + * - v7+ VIPT never aliases on D-side */ #if __LINUX_ARM_ARCH__ >= 7 -#define __CACHEID_ARCH_MIN (CACHEID_VIPT_NONALIASING | CACHEID_ASID_TAGGED) +#define __CACHEID_ARCH_MIN (CACHEID_VIPT_NONALIASING |\ + CACHEID_ASID_TAGGED |\ + CACHEID_VIPT_I_ALIASING) #elif __LINUX_ARM_ARCH__ >= 6 #define __CACHEID_ARCH_MIN (~CACHEID_VIVT) #else diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 122d999..cf8e590 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -233,6 +233,33 @@ int cpu_architecture(void) return cpu_arch; } +static int cpu_has_aliasing_icache(unsigned int arch) +{ + int aliasing_icache; + unsigned int id_reg, num_sets, line_size; + + /* arch specifies the register format */ + switch (arch) { + case CPU_ARCH_ARMv7: + asm("mcr p15, 2, %1, c0, c0, 0 @ set CSSELR\n" + "mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" + : "=r" (id_reg) + : "r" (1)); + line_size = 4 << ((id_reg & 0x7) + 2); + num_sets = ((id_reg >> 13) & 0x7fff) + 1; + aliasing_icache = (line_size * num_sets) > PAGE_SIZE; + break; + case CPU_ARCH_ARMv6: + aliasing_icache = read_cpuid_cachetype() & (1 << 11); + break; + default: + /* I-cache aliases will be handled by D-cache aliasing code */ + aliasing_icache = 0; + } + + return aliasing_icache; +} + static void __init cacheid_init(void) { unsigned int cachetype = read_cpuid_cachetype(); @@ -244,10 +271,15 @@ static void __init cacheid_init(void) cacheid = CACHEID_VIPT_NONALIASING; if ((cachetype & (3 << 14)) == 1 << 14) cacheid |= CACHEID_ASID_TAGGED; - } else if (cachetype & (1 << 23)) + else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7)) + cacheid |= CACHEID_VIPT_I_ALIASING; + } else if (cachetype & (1 << 23)) { cacheid = CACHEID_VIPT_ALIASING; - else + } else { cacheid = CACHEID_VIPT_NONALIASING; + if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6)) + cacheid |= CACHEID_VIPT_I_ALIASING; + } } else { cacheid = CACHEID_VIVT; } @@ -258,7 +290,7 @@ static void __init cacheid_init(void) cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown", cache_is_vivt() ? "VIVT" : icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : - cache_is_vipt_aliasing() ? "VIPT aliasing" : + icache_is_vipt_aliasing() ? "VIPT aliasing" : cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); } -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] ARM: flush_ptrace_access: invalidate correct I-cache alias 2010-08-05 10:36 ` [PATCH 1/2] ARM: setup: detect aliasing I-cache " Will Deacon @ 2010-08-05 10:36 ` Will Deacon 0 siblings, 0 replies; 4+ messages in thread From: Will Deacon @ 2010-08-05 10:36 UTC (permalink / raw) To: linux-arm-kernel copy_to_user_page can be used by access_process_vm to write to an executable page of a process using a mapping acquired by kmap. For systems with I-cache aliasing, flushing the I-cache using the Kernel mapping may leave stale data in the I-cache if the user mapping is of a different colour. This patch introduces a flush_icache_alias function to flush.c, which calls flush_icache_range with a mapping of the specified colour. flush_ptrace_access is then modified to call this new function instead of coherent_kern_range in the case of an aliasing I-cache and a non-aliasing D-cache. Cc: Russell King - ARM Linux <linux@arm.linux.org.uk> Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/mm/flush.c | 23 ++++++++++++++++++++--- 1 files changed, 20 insertions(+), 3 deletions(-) diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index c6844cb..25c771c 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -39,6 +39,18 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) : "cc"); } +static void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned long len) +{ + unsigned long colour = CACHE_COLOUR(vaddr); + unsigned long offset = vaddr & (PAGE_SIZE - 1); + unsigned long to; + + set_pte_ext(TOP_PTE(ALIAS_FLUSH_START) + colour, pfn_pte(pfn, PAGE_KERNEL), 0); + to = ALIAS_FLUSH_START + (colour << PAGE_SHIFT) + offset; + flush_tlb_kernel_page(to); + flush_icache_range(to, to + len); +} + void flush_cache_mm(struct mm_struct *mm) { if (cache_is_vivt()) { @@ -89,8 +101,10 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged()) __flush_icache_all(); } + #else -#define flush_pfn_alias(pfn,vaddr) do { } while (0) +#define flush_pfn_alias(pfn,vaddr) do { } while (0) +#define flush_icache_alias(pfn,vaddr,len) do { } while (0) #endif #ifdef CONFIG_SMP @@ -118,10 +132,13 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, return; } - /* VIPT non-aliasing cache */ + /* VIPT non-aliasing D-cache */ if (vma->vm_flags & VM_EXEC) { unsigned long addr = (unsigned long)kaddr; - __cpuc_coherent_kern_range(addr, addr + len); + if (icache_is_vipt_aliasing()) + flush_icache_alias(page_to_pfn(page), uaddr, len); + else + __cpuc_coherent_kern_range(addr, addr + len); #ifdef CONFIG_SMP if (cache_ops_need_broadcast()) smp_call_function(flush_ptrace_access_other, -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 0/2] Detect and handle I-cache aliases when D-cache is non-aliasing 2010-08-05 10:36 [PATCH 0/2] Detect and handle I-cache aliases when D-cache is non-aliasing Will Deacon 2010-08-05 10:36 ` [PATCH 1/2] ARM: setup: detect aliasing I-cache " Will Deacon @ 2010-08-18 10:48 ` Will Deacon 1 sibling, 0 replies; 4+ messages in thread From: Will Deacon @ 2010-08-18 10:48 UTC (permalink / raw) To: linux-arm-kernel Hi Russell, > Last month, I posted some patches to fix ptrace software breakpoints: > > http://lists.infradead.org/pipermail/linux-arm-kernel/2010-July/020649.html > > One of these patches added a workaround for a hardware erratum, so I > have submitted that to the patch system. The other patch simply called > __flush_icache_all() in flush_ptrace_access to avoid having to worry > about I-cache aliases when cache_is_vipt_nonaliasing() is true. This > isn't ideal if the debugger decides to insert lots of software breakpoints > sequentially (for example, when single-stepping a number of times). > > These two patches add proper identification of aliasing I-caches > when the D-cache is nonaliasing. flush_ptrace_access can then > flush only the relevant I-cache lines instead of the entire cache. > > Cc: Russell King - ARM Linux <linux@arm.linux.org.uk> > Cc: Catalin Marinas <catalin.marinas@arm.com> > > Will Deacon (2): > ARM: setup: detect aliasing I-cache when D-cache is non-aliasing > ARM: flush_ptrace_access: invalidate correct I-cache alias > > arch/arm/include/asm/cachetype.h | 8 ++++++-- > arch/arm/kernel/setup.c | 38 +++++++++++++++++++++++++++++++++++--- > arch/arm/mm/flush.c | 23 ++++++++++++++++++++--- > 3 files changed, 61 insertions(+), 8 deletions(-) Any thoughts on these patches? I prefer them to my previous approach but I'd like a second opinion. Thanks, Will ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2010-08-18 10:48 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-08-05 10:36 [PATCH 0/2] Detect and handle I-cache aliases when D-cache is non-aliasing Will Deacon 2010-08-05 10:36 ` [PATCH 1/2] ARM: setup: detect aliasing I-cache " Will Deacon 2010-08-05 10:36 ` [PATCH 2/2] ARM: flush_ptrace_access: invalidate correct I-cache alias Will Deacon 2010-08-18 10:48 ` [PATCH 0/2] Detect and handle I-cache aliases when D-cache is non-aliasing Will Deacon
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).