linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [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).