linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v9 0/3] ARM: ARMv7 (i.e. Cortex-M3) support
@ 2013-03-21 21:28 Uwe Kleine-König
  2013-03-21 21:28 ` [PATCH v9 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
                   ` (3 more replies)
  0 siblings, 4 replies; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-21 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

this is a new round of my Cortex-M3 patches. I think I addressed all of
Jonny's comments. Of course I'm still open for more feedback. I'd like
to see this series in next for some time.

To be usable these three patches depend on a few patches already sitting
in Russell's devel-stable plus support for the nvic irq controller that
I sent to this list with Message-Id:
1363612826-15623-1-git-send-email-u.kleine-koenig at pengutronix.de.
And platform support is missing of course.

I have platform support for Energy Micro's DK3750 development board that
can be found at

	git://git.pengutronix.de/git/ukl/linux.git efm32

. There is also a public BSP available. Just join #efm32 on freenode if
you're interested.

The individual patches have their own list of changes since v8. I'm not
sure they are complete, though.

Thanks for reading
Uwe

Catalin Marinas (1):
  ARM: Add base support for ARMv7-M

Uwe Kleine-K?nig (2):
  ARM: ARMv7-M: Add support for exception handling
  ARM: ARMv7-M: Allow the building of new kernel port

 arch/arm/Kconfig                   |   4 +-
 arch/arm/Kconfig-nommu             |   2 +-
 arch/arm/Makefile                  |   1 +
 arch/arm/include/asm/assembler.h   |  17 +++-
 arch/arm/include/asm/cputype.h     |  12 ++-
 arch/arm/include/asm/glue-cache.h  |  27 ++++++
 arch/arm/include/asm/glue-df.h     |   8 ++
 arch/arm/include/asm/glue-proc.h   |   9 ++
 arch/arm/include/asm/irqflags.h    |  22 +++--
 arch/arm/include/asm/ptrace.h      |   4 +
 arch/arm/include/asm/system_info.h |   1 +
 arch/arm/include/asm/v7m.h         |  47 +++++++++++
 arch/arm/include/uapi/asm/ptrace.h |  35 ++++++--
 arch/arm/kernel/Makefile           |   8 +-
 arch/arm/kernel/entry-common.S     |   4 +
 arch/arm/kernel/entry-header.S     | 120 ++++++++++++++++++++++++++
 arch/arm/kernel/entry-v7m.S        | 142 +++++++++++++++++++++++++++++++
 arch/arm/kernel/head-nommu.S       |  10 ++-
 arch/arm/kernel/setup.c            |  17 +++-
 arch/arm/kernel/traps.c            |   2 +
 arch/arm/mm/Kconfig                |  22 ++++-
 arch/arm/mm/Makefile               |   2 +
 arch/arm/mm/cache-nop.S            |  53 ++++++++++++
 arch/arm/mm/nommu.c                |   2 +
 arch/arm/mm/proc-v7m.S             | 167 +++++++++++++++++++++++++++++++++++++
 25 files changed, 712 insertions(+), 26 deletions(-)
 create mode 100644 arch/arm/include/asm/v7m.h
 create mode 100644 arch/arm/kernel/entry-v7m.S
 create mode 100644 arch/arm/mm/cache-nop.S
 create mode 100644 arch/arm/mm/proc-v7m.S

-- 
1.8.2.rc2

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v9 1/3] ARM: Add base support for ARMv7-M
  2013-03-21 21:28 [PATCH v9 0/3] ARM: ARMv7 (i.e. Cortex-M3) support Uwe Kleine-König
@ 2013-03-21 21:28 ` Uwe Kleine-König
  2013-03-22 18:42   ` Jonathan Austin
  2013-03-21 21:28 ` [PATCH v9 2/3] ARM: ARMv7-M: Add support for exception handling Uwe Kleine-König
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-21 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

From: Catalin Marinas <catalin.marinas@arm.com>

This patch adds the base support for the ARMv7-M
architecture. It consists of the corresponding arch/arm/mm/ files and
various #ifdef's around the kernel. Exception handling is implemented by
a subsequent patch.

[ukleinek: squash in some changes originating from commit

b5717ba (Cortex-M3: Add support for the Microcontroller Prototyping System)

from the v2.6.33-arm1 patch stack, port to post 3.6, drop zImage
support, drop reorganisation of pt_regs, assert CONFIG_V7M doesn't leak
into installed headers and a few cosmetic changes]

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
Changes since v8,
id:1358413196-5609-3-git-send-email-u.kleine-koenig at pengutronix.de:

 - rebase
 - use more named constants
 - add comment about setmode being empty
 - add more (yet unused) v7m register defines
 - enable UsageFault, BusFault and MemManage fault at boot time
 - make nop multi-cache-able
---
 arch/arm/include/asm/assembler.h   |  17 +++-
 arch/arm/include/asm/cputype.h     |  12 ++-
 arch/arm/include/asm/glue-cache.h  |  27 ++++++
 arch/arm/include/asm/glue-df.h     |   8 ++
 arch/arm/include/asm/glue-proc.h   |   9 ++
 arch/arm/include/asm/irqflags.h    |  22 +++--
 arch/arm/include/asm/ptrace.h      |   4 +
 arch/arm/include/asm/system_info.h |   1 +
 arch/arm/include/asm/v7m.h         |  47 +++++++++++
 arch/arm/include/uapi/asm/ptrace.h |  35 ++++++--
 arch/arm/kernel/head-nommu.S       |  10 ++-
 arch/arm/kernel/setup.c            |  17 +++-
 arch/arm/kernel/traps.c            |   2 +
 arch/arm/mm/cache-nop.S            |  53 ++++++++++++
 arch/arm/mm/nommu.c                |   2 +
 arch/arm/mm/proc-v7m.S             | 167 +++++++++++++++++++++++++++++++++++++
 16 files changed, 412 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm/include/asm/v7m.h
 create mode 100644 arch/arm/mm/cache-nop.S
 create mode 100644 arch/arm/mm/proc-v7m.S

diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 05ee9ee..a5fef71 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -136,7 +136,11 @@
  * assumes FIQs are enabled, and that the processor is in SVC mode.
  */
 	.macro	save_and_disable_irqs, oldcpsr
+#ifdef CONFIG_CPU_V7M
+	mrs	\oldcpsr, primask
+#else
 	mrs	\oldcpsr, cpsr
+#endif
 	disable_irq
 	.endm
 
@@ -150,7 +154,11 @@
  * guarantee that this will preserve the flags.
  */
 	.macro	restore_irqs_notrace, oldcpsr
+#ifdef CONFIG_CPU_V7M
+	msr	primask, \oldcpsr
+#else
 	msr	cpsr_c, \oldcpsr
+#endif
 	.endm
 
 	.macro restore_irqs, oldcpsr
@@ -229,7 +237,14 @@
 #endif
 	.endm
 
-#ifdef CONFIG_THUMB2_KERNEL
+#if defined(CONFIG_CPU_V7M)
+	/*
+	 * setmode is used to assert to be in svc mode during boot. For v7-M
+	 * this is done in __v7m_setup, so setmode can be empty here.
+	 */
+	.macro	setmode, mode, reg
+	.endm
+#elif defined(CONFIG_THUMB2_KERNEL)
 	.macro	setmode, mode, reg
 	mov	\reg, #\mode
 	msr	cpsr_c, \reg
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index 7652712..d7eb0fb 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -106,7 +106,17 @@ static inline unsigned int __attribute_const__ read_cpuid_id(void)
 	return read_cpuid(CPUID_ID);
 }
 
-#else /* ifdef CONFIG_CPU_CP15 */
+#elif defined(CONFIG_CPU_V7M)
+
+#include <asm/io.h>
+#include <asm/v7m.h>
+
+static inline unsigned int __attribute_const__ read_cpuid_id(void)
+{
+	return readl(V7M_SCS_CPUID);
+}
+
+#else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */
 
 static inline unsigned int __attribute_const__ read_cpuid_id(void)
 {
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index cca9f15..65c9faf 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -125,10 +125,37 @@
 # endif
 #endif
 
+#if defined(CONFIG_CPU_V7M)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE nop
+# endif
+#endif
+
 #if !defined(_CACHE) && !defined(MULTI_CACHE)
 #error Unknown cache maintenance model
 #endif
 
+#ifndef __ASSEMBLER__
+extern inline void nop_flush_icache_all(void) { }
+extern inline void nop_flush_kern_cache_all(void) { }
+extern inline void nop_flush_kern_cache_louis(void) { }
+extern inline void nop_flush_user_cache_all(void) { }
+extern inline void nop_flush_user_cache_range(unsigned long a,
+		unsigned long b, unsigned int c) { }
+
+extern inline void nop_coherent_kern_range(unsigned long a, unsigned long b) { }
+extern inline int nop_coherent_user_range(unsigned long a,
+		unsigned long b) { return 0; }
+extern inline void nop_flush_kern_dcache_area(void *a, size_t s) { }
+
+extern inline void nop_dma_flush_range(const void *a, const void *b) { }
+
+extern inline void nop_dma_map_area(const void *s, size_t l, int f) { }
+extern inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
+#endif
+
 #ifndef MULTI_CACHE
 #define __cpuc_flush_icache_all		__glue(_CACHE,_flush_icache_all)
 #define __cpuc_flush_kern_all		__glue(_CACHE,_flush_kern_cache_all)
diff --git a/arch/arm/include/asm/glue-df.h b/arch/arm/include/asm/glue-df.h
index b6e9f2c..6b70f1b 100644
--- a/arch/arm/include/asm/glue-df.h
+++ b/arch/arm/include/asm/glue-df.h
@@ -95,6 +95,14 @@
 # endif
 #endif
 
+#ifdef CONFIG_CPU_ABRT_NOMMU
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER nommu_early_abort
+# endif
+#endif
+
 #ifndef CPU_DABORT_HANDLER
 #error Unknown data abort handler type
 #endif
diff --git a/arch/arm/include/asm/glue-proc.h b/arch/arm/include/asm/glue-proc.h
index ac1dd54..f2f39bc 100644
--- a/arch/arm/include/asm/glue-proc.h
+++ b/arch/arm/include/asm/glue-proc.h
@@ -230,6 +230,15 @@
 # endif
 #endif
 
+#ifdef CONFIG_CPU_V7M
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_v7m
+# endif
+#endif
+
 #ifndef MULTI_CPU
 #define cpu_proc_init			__glue(CPU_NAME,_proc_init)
 #define cpu_proc_fin			__glue(CPU_NAME,_proc_fin)
diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h
index 1e6cca5..3b763d6 100644
--- a/arch/arm/include/asm/irqflags.h
+++ b/arch/arm/include/asm/irqflags.h
@@ -8,6 +8,16 @@
 /*
  * CPU interrupt mask handling.
  */
+#ifdef CONFIG_CPU_V7M
+#define IRQMASK_REG_NAME_R "primask"
+#define IRQMASK_REG_NAME_W "primask"
+#define IRQMASK_I_BIT	1
+#else
+#define IRQMASK_REG_NAME_R "cpsr"
+#define IRQMASK_REG_NAME_W "cpsr_c"
+#define IRQMASK_I_BIT	PSR_I_BIT
+#endif
+
 #if __LINUX_ARM_ARCH__ >= 6
 
 static inline unsigned long arch_local_irq_save(void)
@@ -15,7 +25,7 @@ static inline unsigned long arch_local_irq_save(void)
 	unsigned long flags;
 
 	asm volatile(
-		"	mrs	%0, cpsr	@ arch_local_irq_save\n"
+		"	mrs	%0, " IRQMASK_REG_NAME_R "	@ arch_local_irq_save\n"
 		"	cpsid	i"
 		: "=r" (flags) : : "memory", "cc");
 	return flags;
@@ -129,7 +139,7 @@ static inline unsigned long arch_local_save_flags(void)
 {
 	unsigned long flags;
 	asm volatile(
-		"	mrs	%0, cpsr	@ local_save_flags"
+		"	mrs	%0, " IRQMASK_REG_NAME_R "	@ local_save_flags"
 		: "=r" (flags) : : "memory", "cc");
 	return flags;
 }
@@ -140,7 +150,7 @@ static inline unsigned long arch_local_save_flags(void)
 static inline void arch_local_irq_restore(unsigned long flags)
 {
 	asm volatile(
-		"	msr	cpsr_c, %0	@ local_irq_restore"
+		"	msr	" IRQMASK_REG_NAME_W ", %0	@ local_irq_restore"
 		:
 		: "r" (flags)
 		: "memory", "cc");
@@ -148,8 +158,8 @@ static inline void arch_local_irq_restore(unsigned long flags)
 
 static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
-	return flags & PSR_I_BIT;
+	return flags & IRQMASK_I_BIT;
 }
 
-#endif
-#endif
+#endif /* ifdef __KERNEL__ */
+#endif /* ifndef __ASM_ARM_IRQFLAGS_H */
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 3d52ee1..04c99f3 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -45,6 +45,7 @@ struct pt_regs {
  */
 static inline int valid_user_regs(struct pt_regs *regs)
 {
+#ifndef CONFIG_CPU_V7M
 	unsigned long mode = regs->ARM_cpsr & MODE_MASK;
 
 	/*
@@ -67,6 +68,9 @@ static inline int valid_user_regs(struct pt_regs *regs)
 		regs->ARM_cpsr |= USR_MODE;
 
 	return 0;
+#else /* ifndef CONFIG_CPU_V7M */
+	return 1;
+#endif
 }
 
 static inline long regs_return_value(struct pt_regs *regs)
diff --git a/arch/arm/include/asm/system_info.h b/arch/arm/include/asm/system_info.h
index dfd386d..720ea03 100644
--- a/arch/arm/include/asm/system_info.h
+++ b/arch/arm/include/asm/system_info.h
@@ -11,6 +11,7 @@
 #define CPU_ARCH_ARMv5TEJ	7
 #define CPU_ARCH_ARMv6		8
 #define CPU_ARCH_ARMv7		9
+#define CPU_ARCH_ARMv7M		10
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/arm/include/asm/v7m.h b/arch/arm/include/asm/v7m.h
new file mode 100644
index 0000000..e12b887
--- /dev/null
+++ b/arch/arm/include/asm/v7m.h
@@ -0,0 +1,47 @@
+/*
+ * Common defines for v7m cpus
+ */
+#define V7M_SCS_ICTR	IOMEM(0xe000e004)
+#define V7M_SCS_ICTR_INTLINESNUM_MASK		0x0000000f
+
+#define V7M_SCS_CPUID	IOMEM(0xe000ed00)
+
+#define V7M_SCS_ICSR	IOMEM(0xe000ed04)
+#define V7M_SCS_ICSR_PENDSVSET			(1 << 28)
+#define V7M_SCS_ICSR_PENDSVCLR			(1 << 27)
+#define V7M_SCS_ICSR_RETTOBASE			(1 << 11)
+
+#define V7M_SCS_VTOR	IOMEM(0xe000ed08)
+
+#define V7M_SCS_SCR	IOMEM(0xe000ed10)
+#define V7M_SCS_SCR_SLEEPDEEP			(1 << 2)
+
+#define V7M_SCS_CCR	IOMEM(0xe000ed14)
+#define V7M_SCS_CCR_STKALIGN			(1 << 9)
+
+#define V7M_SCS_SHPR2	IOMEM(0xe000ed1c)
+#define V7M_SCS_SHPR3	IOMEM(0xe000ed20)
+
+#define V7M_SCS_SHCSR	IOMEM(0xe000ed24)
+#define V7M_SCS_SHCSR_USGFAULTENA		(1 << 18)
+#define V7M_SCS_SHCSR_BUSFAULTENA		(1 << 17)
+#define V7M_SCS_SHCSR_MEMFAULTENA		(1 << 16)
+
+#define V7M_xPSR_FPALIGN			0x00000200
+
+#define EXC_RET_SBOP				0xffffffe1
+#define EXC_RET_FRAMETYPE_MASK			0x00000010
+#define EXC_RET_FRAMETYPE__BASIC		0x00000010
+#define EXC_RET_MODE_MASK			0x00000008
+#define EXC_RET_MODE__HANDLER			0x00000000
+#define EXC_RET_MODE__THREAD			0x00000008
+#define EXC_RET_STACK_MASK			0x00000004
+#define EXC_RET_STACK__MAIN			0x00000000
+#define EXC_RET_STACK__PROCESS			0x00000004
+
+#define EXC_RET_HANDLERMODE_MAINSTACK	\
+	(EXC_RET_SBOP | EXC_RET_FRAMETYPE__BASIC | EXC_RET_MODE__HANDLER | EXC_RET_STACK__MAIN)
+#define EXC_RET_THREADMODE_MAINSTACK	\
+	(EXC_RET_SBOP | EXC_RET_FRAMETYPE__BASIC | EXC_RET_MODE__THREAD | EXC_RET_STACK__MAIN)
+#define EXC_RET_THREADMODE_PROCESSSTACK	\
+	(EXC_RET_SBOP | EXC_RET_FRAMETYPE__BASIC | EXC_RET_MODE__THREAD | EXC_RET_STACK__PROCESS)
diff --git a/arch/arm/include/uapi/asm/ptrace.h b/arch/arm/include/uapi/asm/ptrace.h
index 96ee092..5af0ed1 100644
--- a/arch/arm/include/uapi/asm/ptrace.h
+++ b/arch/arm/include/uapi/asm/ptrace.h
@@ -34,28 +34,47 @@
 
 /*
  * PSR bits
+ * Note on V7M there is no mode contained in the PSR
  */
 #define USR26_MODE	0x00000000
 #define FIQ26_MODE	0x00000001
 #define IRQ26_MODE	0x00000002
 #define SVC26_MODE	0x00000003
+#if defined(__KERNEL__) && defined(CONFIG_CPU_V7M)
+/*
+ * Use 0 here to get code right that creates a userspace
+ * or kernel space thread.
+ */
+#define USR_MODE	0x00000000
+#define SVC_MODE	0x00000000
+#else
 #define USR_MODE	0x00000010
+#define SVC_MODE	0x00000013
+#endif
 #define FIQ_MODE	0x00000011
 #define IRQ_MODE	0x00000012
-#define SVC_MODE	0x00000013
 #define ABT_MODE	0x00000017
 #define HYP_MODE	0x0000001a
 #define UND_MODE	0x0000001b
 #define SYSTEM_MODE	0x0000001f
 #define MODE32_BIT	0x00000010
 #define MODE_MASK	0x0000001f
-#define PSR_T_BIT	0x00000020
-#define PSR_F_BIT	0x00000040
-#define PSR_I_BIT	0x00000080
-#define PSR_A_BIT	0x00000100
-#define PSR_E_BIT	0x00000200
-#define PSR_J_BIT	0x01000000
-#define PSR_Q_BIT	0x08000000
+
+#define V4_PSR_T_BIT	0x00000020	/* >= V4T, but not V7M */
+#define V7M_PSR_T_BIT	0x01000000
+#if defined(__KERNEL__) && defined(CONFIG_CPU_V7M)
+#define PSR_T_BIT	V7M_PSR_T_BIT
+#else
+/* for compatibility */
+#define PSR_T_BIT	V4_PSR_T_BIT
+#endif
+
+#define PSR_F_BIT	0x00000040	/* >= V4, but not V7M */
+#define PSR_I_BIT	0x00000080	/* >= V4, but not V7M */
+#define PSR_A_BIT	0x00000100	/* >= V6, but not V7M */
+#define PSR_E_BIT	0x00000200	/* >= V6, but not V7M */
+#define PSR_J_BIT	0x01000000	/* >= V5J, but not V7M */
+#define PSR_Q_BIT	0x08000000	/* >= V5E, including V7M */
 #define PSR_V_BIT	0x10000000
 #define PSR_C_BIT	0x20000000
 #define PSR_Z_BIT	0x40000000
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 6a2e09c..e2988bb 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -19,6 +19,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/cp15.h>
 #include <asm/thread_info.h>
+#include <asm/v7m.h>
 
 /*
  * Kernel startup entry point.
@@ -50,10 +51,13 @@ ENTRY(stext)
 
 	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
 						@ and irqs disabled
-#ifndef CONFIG_CPU_CP15
-	ldr	r9, =CONFIG_PROCESSOR_ID
-#else
+#if defined(CONFIG_CPU_CP15)
 	mrc	p15, 0, r9, c0, c0		@ get processor id
+#elif defined(CONFIG_CPU_V7M)
+	ldr	r9, =V7M_SCS_CPUID
+	ldr	r9, [r9]
+#else
+	ldr	r9, =CONFIG_PROCESSOR_ID
 #endif
 	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
 	movs	r10, r5				@ invalid processor (r5=0)?
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 1cc9e17..8291245 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -128,7 +128,9 @@ struct stack {
 	u32 und[3];
 } ____cacheline_aligned;
 
+#ifndef CONFIG_CPU_V7M
 static struct stack stacks[NR_CPUS];
+#endif
 
 char elf_platform[ELF_PLATFORM_SIZE];
 EXPORT_SYMBOL(elf_platform);
@@ -207,7 +209,7 @@ static const char *proc_arch[] = {
 	"5TEJ",
 	"6TEJ",
 	"7",
-	"?(11)",
+	"7M",
 	"?(12)",
 	"?(13)",
 	"?(14)",
@@ -216,6 +218,12 @@ static const char *proc_arch[] = {
 	"?(17)",
 };
 
+#ifdef CONFIG_CPU_V7M
+static int __get_cpu_architecture(void)
+{
+	return CPU_ARCH_ARMv7M;
+}
+#else
 static int __get_cpu_architecture(void)
 {
 	int cpu_arch;
@@ -248,6 +256,7 @@ static int __get_cpu_architecture(void)
 
 	return cpu_arch;
 }
+#endif
 
 int __pure cpu_architecture(void)
 {
@@ -293,7 +302,9 @@ static void __init cacheid_init(void)
 {
 	unsigned int arch = cpu_architecture();
 
-	if (arch >= CPU_ARCH_ARMv6) {
+	if (arch == CPU_ARCH_ARMv7M) {
+		cacheid = 0;
+	} else if (arch >= CPU_ARCH_ARMv6) {
 		unsigned int cachetype = read_cpuid_cachetype();
 		if ((cachetype & (7 << 29)) == 4 << 29) {
 			/* ARMv7 register format */
@@ -375,6 +386,7 @@ static void __init feat_v6_fixup(void)
  */
 void cpu_init(void)
 {
+#ifndef CONFIG_CPU_V7M
 	unsigned int cpu = smp_processor_id();
 	struct stack *stk = &stacks[cpu];
 
@@ -425,6 +437,7 @@ void cpu_init(void)
 	      "I" (offsetof(struct stack, und[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
+#endif
 }
 
 int __cpu_logical_map[NR_CPUS];
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 1c08911..3990eaa 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -819,6 +819,7 @@ static void __init kuser_get_tls_init(unsigned long vectors)
 
 void __init early_trap_init(void *vectors_base)
 {
+#ifndef CONFIG_CPU_V7M
 	unsigned long vectors = (unsigned long)vectors_base;
 	extern char __stubs_start[], __stubs_end[];
 	extern char __vectors_start[], __vectors_end[];
@@ -850,4 +851,5 @@ void __init early_trap_init(void *vectors_base)
 
 	flush_icache_range(vectors, vectors + PAGE_SIZE);
 	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
+#endif
 }
diff --git a/arch/arm/mm/cache-nop.S b/arch/arm/mm/cache-nop.S
new file mode 100644
index 0000000..543b930
--- /dev/null
+++ b/arch/arm/mm/cache-nop.S
@@ -0,0 +1,53 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+#include <asm/unwind.h>
+
+#include "proc-macros.S"
+
+ENTRY(nop_flush_icache_all)
+	mov	pc, lr
+ENDPROC(nop_flush_icache_all)
+
+	.globl nop_flush_kern_cache_all
+	.equ nop_flush_kern_cache_all, nop_flush_icache_all
+
+	.globl nop_flush_kern_cache_louis
+	.equ nop_flush_kern_cache_louis, nop_flush_icache_all
+
+	.globl nop_flush_user_cache_all
+	.equ nop_flush_user_cache_all, nop_flush_icache_all
+
+	.globl nop_flush_user_cache_range
+	.equ nop_flush_user_cache_range, nop_flush_icache_all
+
+	.globl nop_coherent_kern_range
+	.equ nop_coherent_kern_range, nop_flush_icache_all
+
+ENTRY(nop_coherent_user_range)
+	mov	r0, 0
+	mov	pc, lr
+ENDPROC(nop_coherent_user_range)
+
+	.globl nop_flush_kern_dcache_area
+	.equ nop_flush_kern_dcache_area, nop_flush_icache_all
+
+	.globl nop_dma_flush_range
+	.equ nop_dma_flush_range, nop_flush_icache_all
+
+	.globl nop_dma_map_area
+	.equ nop_dma_map_area, nop_flush_icache_all
+
+	.globl nop_dma_unmap_area
+	.equ nop_dma_unmap_area, nop_flush_icache_all
+
+	__INITDATA
+
+	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
+	define_cache_functions nop
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index d51225f..4bc8ae5 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -20,12 +20,14 @@
 
 void __init arm_mm_memblock_reserve(void)
 {
+#ifndef CONFIG_CPU_V7M
 	/*
 	 * Register the exception vector page.
 	 * some architectures which the DRAM is the exception vector to trap,
 	 * alloc_page breaks with error, although it is not NULL, but "0."
 	 */
 	memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE);
+#endif
 }
 
 void __init sanity_check_meminfo(void)
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
new file mode 100644
index 0000000..c2b68d3
--- /dev/null
+++ b/arch/arm/mm/proc-v7m.S
@@ -0,0 +1,167 @@
+/*
+ *  linux/arch/arm/mm/proc-v7m.S
+ *
+ *  Copyright (C) 2008 ARM Ltd.
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  This is the "shell" of the ARMv7-M processor support.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/v7m.h>
+
+ENTRY(cpu_v7m_proc_init)
+	mov	pc, lr
+ENDPROC(cpu_v7m_proc_init)
+
+ENTRY(cpu_v7m_proc_fin)
+	mov	pc, lr
+ENDPROC(cpu_v7m_proc_fin)
+
+/*
+ *	cpu_v7m_reset(loc)
+ *
+ *	Perform a soft reset of the system.  Put the CPU into the
+ *	same state as it would be if it had been reset, and branch
+ *	to what would be the reset vector.
+ *
+ *	- loc   - location to jump to for soft reset
+ */
+	.align	5
+ENTRY(cpu_v7m_reset)
+	mov	pc, r0
+ENDPROC(cpu_v7m_reset)
+
+/*
+ *	cpu_v7m_do_idle()
+ *
+ *	Idle the processor (eg, wait for interrupt).
+ *
+ *	IRQs are already disabled.
+ */
+ENTRY(cpu_v7m_do_idle)
+	wfi
+	mov	pc, lr
+ENDPROC(cpu_v7m_do_idle)
+
+ENTRY(cpu_v7m_dcache_clean_area)
+	mov	pc, lr
+ENDPROC(cpu_v7m_dcache_clean_area)
+
+/*
+ * There is no MMU, so here is nothing to do.
+ */
+ENTRY(cpu_v7m_switch_mm)
+	mov	pc, lr
+ENDPROC(cpu_v7m_switch_mm)
+
+cpu_v7m_name:
+	.ascii	"ARMv7-M Processor"
+	.align
+
+	.section ".text.init", #alloc, #execinstr
+
+/*
+ *	__v7m_setup
+ *
+ *	This should be able to cover all ARMv7-M cores.
+ */
+__v7m_setup:
+	@ Configure the vector table base address
+	ldr	r0, =V7M_SCS_VTOR	@ vector table base address
+	ldr	r12, =vector_table
+	str	r12, [r0]
+
+	@ enable UsageFault, BusFault and MemManage fault.
+	ldr	r5, [r0, #(V7M_SCS_SHCSR - V7M_SCS_VTOR)]
+	orr	r5, #(V7M_SCS_SHCSR_USGFAULTENA | V7M_SCS_SHCSR_BUSFAULTENA | V7M_SCS_SHCSR_MEMFAULTENA)
+	str	r5, [r0, #(V7M_SCS_SHCSR - V7M_SCS_VTOR)]
+
+	@ Lower the priority of the SVC and PendSV exceptions
+	ldr	r0, =V7M_SCS_SHPR2
+	mov	r5, #0x80000000
+	str	r5, [r0]		@ set SVC priority
+	ldr	r0, =V7M_SCS_SHPR3
+	mov	r5, #0x00800000
+	str	r5, [r0]		@ set PendSV priority
+
+	@ SVC to run the kernel in this mode
+	adr	r0, BSYM(1f)
+	ldr	r5, [r12, #11 * 4]	@ read the SVC vector entry
+	str	r0, [r12, #11 * 4]	@ write the temporary SVC vector entry
+	mov	r6, lr			@ save LR
+	mov	r7, sp			@ save SP
+	ldr	sp, =__v7m_setup_stack_top
+	cpsie	i
+	svc	#0
+1:	cpsid	i
+	str	r5, [r12, #11 * 4]	@ restore the original SVC vector entry
+	mov	lr, r6			@ restore LR
+	mov	sp, r7			@ restore SP
+
+	@ Special-purpose control register
+	mov	r0, #1
+	msr	control, r0		@ Thread mode has unpriviledged access
+
+	@ Configure the System Control Register
+	ldr	r0, =V7M_SCS_CCR	@ system control register
+	ldr	r12, [r0]
+	orr	r12, #V7M_SCS_CCR_STKALIGN
+	str	r12, [r0]
+	mov	pc, lr
+ENDPROC(__v7m_setup)
+
+	.align	2
+	.type	v7m_processor_functions, #object
+ENTRY(v7m_processor_functions)
+	.word	nommu_early_abort
+	.word	cpu_v7m_proc_init
+	.word	cpu_v7m_proc_fin
+	.word	cpu_v7m_reset
+	.word	cpu_v7m_do_idle
+	.word	cpu_v7m_dcache_clean_area
+	.word	cpu_v7m_switch_mm
+	.word	0			@ cpu_v7m_set_pte_ext
+	.word	legacy_pabort
+	.size	v7m_processor_functions, . - v7m_processor_functions
+
+	.type	cpu_arch_name, #object
+cpu_arch_name:
+	.asciz	"armv7m"
+	.size	cpu_arch_name, . - cpu_arch_name
+
+	.type	cpu_elf_name, #object
+cpu_elf_name:
+	.asciz	"v7m"
+	.size	cpu_elf_name, . - cpu_elf_name
+	.align
+
+	.section ".proc.info.init", #alloc, #execinstr
+
+	/*
+	 * Match any ARMv7-M processor core.
+	 */
+	.type	__v7m_proc_info, #object
+__v7m_proc_info:
+	.long	0x000f0000		@ Required ID value
+	.long	0x000f0000		@ Mask for ID
+	.long   0			@ proc_info_list.__cpu_mm_mmu_flags
+	.long   0			@ proc_info_list.__cpu_io_mmu_flags
+	b	__v7m_setup		@ proc_info_list.__cpu_flush
+	.long	cpu_arch_name
+	.long	cpu_elf_name
+	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+	.long	cpu_v7m_name
+	.long	v7m_processor_functions	@ proc_info_list.proc
+	.long	0			@ proc_info_list.tlb
+	.long	0			@ proc_info_list.user
+	.long	nop_cache_fns		@ proc_info_list.cache
+	.size	__v7m_proc_info, . - __v7m_proc_info
+
+__v7m_setup_stack:
+	.space	4 * 8				@ 8 registers
+__v7m_setup_stack_top:
-- 
1.8.2.rc2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v9 2/3] ARM: ARMv7-M: Add support for exception handling
  2013-03-21 21:28 [PATCH v9 0/3] ARM: ARMv7 (i.e. Cortex-M3) support Uwe Kleine-König
  2013-03-21 21:28 ` [PATCH v9 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
@ 2013-03-21 21:28 ` Uwe Kleine-König
  2013-03-25 18:50   ` Jonathan Austin
  2013-03-21 21:28 ` [PATCH v9 3/3] ARM: ARMv7-M: Allow the building of new kernel port Uwe Kleine-König
  2013-03-27 10:54 ` [PATCH v10 0/3] ARM: ARMv7-M (i.e. Cortex-M3) support Uwe Kleine-König
  3 siblings, 1 reply; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-21 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patch implements the exception handling for the ARMv7-M
architecture (pretty different from the A or R profiles).

It bases on work done earlier by Catalin for 2.6.33 but was nearly
completely rewritten to use a pt_regs layout compatible to the A
profile.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
Note there is one open issue in this patch that Jonny raised. He
wondered if we need a clrex in the return path to user space. I'm not
sure it's needed as in ARMv7-M, the local monitor is changed to Open
Access automatically as part of an exception entry or exit sequence.
For now I think it's not critical and can be addressed later.

Changes since v8, sent with
Message-id: <1358413196-5609-4-git-send-email-u.kleine-koenig@pengutronix.de>:

 - inline v7m_exception_fast_exit
 - use more symbolic names
 - use ICSR.RETTOBASE instead of EXC_RET & 8 to determine return mode
 - don't save EXC_RET to into pt_regs
 - drop handling of FP extention
---
 arch/arm/kernel/entry-common.S |   4 ++
 arch/arm/kernel/entry-header.S | 120 ++++++++++++++++++++++++++++++++++
 arch/arm/kernel/entry-v7m.S    | 142 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 266 insertions(+)
 create mode 100644 arch/arm/kernel/entry-v7m.S

diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 3248cde..c45e002 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -339,6 +339,9 @@ ENDPROC(ftrace_stub)
 
 	.align	5
 ENTRY(vector_swi)
+#ifdef CONFIG_CPU_V7M
+	v7m_exception_entry
+#else
 	sub	sp, sp, #S_FRAME_SIZE
 	stmia	sp, {r0 - r12}			@ Calling r0 - r12
  ARM(	add	r8, sp, #S_PC		)
@@ -349,6 +352,7 @@ ENTRY(vector_swi)
 	str	lr, [sp, #S_PC]			@ Save calling PC
 	str	r8, [sp, #S_PSR]		@ Save CPSR
 	str	r0, [sp, #S_OLD_R0]		@ Save OLD_R0
+#endif
 	zero_fp
 
 	/*
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 9a8531e..4caccb4 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -5,6 +5,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/errno.h>
 #include <asm/thread_info.h>
+#include <asm/v7m.h>
 
 @ Bad Abort numbers
 @ -----------------
@@ -44,6 +45,115 @@
 #endif
 	.endm
 
+#ifdef CONFIG_CPU_V7M
+/*
+ * ARMv7-M exception entry/exit macros.
+ *
+ * xPSR, ReturnAddress(), LR (R14), R12, R3, R2, R1, and R0 are
+ * automatically saved on the current stack (32 words) before
+ * switching to the exception stack (SP_main).
+ *
+ * If exception is taken while in user mode, SP_main is
+ * empty. Otherwise, SP_main is aligned to 64 bit automatically
+ * (CCR.STKALIGN set).
+ *
+ * Linux assumes that the interrupts are disabled when entering an
+ * exception handler and it may BUG if this is not the case. Interrupts
+ * are disabled during entry and reenabled in the exit macro.
+ *
+ * v7m_exception_slow_exit is used when returning from SVC or PendSV.
+ * When returning to kernel mode, we don't return from exception.
+ */
+	.macro	v7m_exception_entry
+	@ determine the location of the registers saved by the core during
+	@ exception entry. Depending on the mode the cpu was in when the
+	@ exception happend that is either on the main or the process stack.
+	@ Bit 2 of EXC_RETURN stored in the lr register specifies which stack
+	@ was used.
+	tst	lr, #EXC_RET_STACK_MASK
+	mrsne	r12, psp
+	moveq	r12, sp
+
+	@ we cannot rely on r0-r3 and r12 matching the value saved in the
+	@ exception frame because of tail-chaining. So these have to be
+	@ reloaded.
+	ldmia	r12!, {r0-r3}
+
+	@ Linux expects to have irqs off. Do it here before taking stack space
+	cpsid	i
+
+	sub	sp, #S_FRAME_SIZE-S_IP
+	stmdb	sp!, {r0-r11}
+
+	@ load saved r12, lr, return address and xPSR.
+	@ r0-r7 are used for signals and never touched from now on. Clobbering
+	@ r8-r12 is OK.
+	mov	r9, r12
+	ldmia	r9!, {r8, r10-r12}
+
+	@ calculate the original stack pointer value.
+	@ r9 currently points to the memory location just above the auto saved
+	@ xPSR.
+	@ The cpu might automatically 8-byte align the stack. Bit 9
+	@ of the saved xPSR specifies if stack aligning took place. In this case
+	@ another 32-bit value is included in the stack.
+
+	tst	r12, V7M_xPSR_FPALIGN
+	addne	r9, r9, #4
+
+	@ store saved r12 using str to have a register to hold the base for stm
+	str	r8, [sp, #S_IP]
+	add	r8, sp, #S_SP
+	@ store r13-r15, xPSR
+	stmia	r8!, {r9-r12}
+	@ store old_r0
+	str	r0, [r8]
+	.endm
+
+
+/*
+ * We won't return to kernel space here because a kernel thread runs in SVCALL
+ * context and so cannot be preempted by PENDSV.
+ */
+	.macro	v7m_exception_slow_exit ret_r0
+	cpsid	i
+	ldr	lr, =EXC_RET_THREADMODE_PROCESSSTACK
+
+	@ read original r12, sp, lr, pc and xPSR
+	add	r12, sp, #S_IP
+	ldmia	r12, {r1-r5}
+
+	@ an exception frame is always 8-byte aligned. To tell the hardware if
+	@ the sp to be restored is aligned or not set bit 9 of the saved xPSR
+	@ accordingly.
+	tst	r2, #4
+	subne	r2, r2, #4
+	orrne	r5, V7M_xPSR_FPALIGN
+	biceq	r5, V7M_xPSR_FPALIGN
+
+	@ write basic exception frame
+	stmdb	r2!, {r1, r3-r5}
+	ldmia	sp, {r1, r3-r5}
+	.if	\ret_r0
+	stmdb	r2!, {r0, r3-r5}
+	.else
+	stmdb	r2!, {r1, r3-r5}
+	.endif
+
+	@ restore process sp
+	msr	psp, r2
+
+	@ restore original r4-r11
+	ldmia	sp!, {r0-r11}
+
+	@ restore main sp
+	add	sp, sp, #S_FRAME_SIZE-S_IP
+
+	cpsie	i
+	bx	lr
+	.endm
+#endif	/* CONFIG_CPU_V7M */
+
 	@
 	@ Store/load the USER SP and LR registers by switching to the SYS
 	@ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not
@@ -131,6 +241,15 @@
 	rfeia	sp!
 	.endm
 
+#ifdef CONFIG_CPU_V7M
+	.macro	restore_user_regs, fast = 0, offset = 0
+	@ XXX: clrex?
+	.if	\offset
+	add	sp, #\offset
+	.endif
+	v7m_exception_slow_exit ret_r0 = \fast
+	.endm
+#else	/* ifdef CONFIG_CPU_V7M */
 	.macro	restore_user_regs, fast = 0, offset = 0
 	clrex					@ clear the exclusive monitor
 	mov	r2, sp
@@ -147,6 +266,7 @@
 	add	sp, sp, #S_FRAME_SIZE - S_SP
 	movs	pc, lr				@ return & move spsr_svc into cpsr
 	.endm
+#endif	/* ifdef CONFIG_CPU_V7M / else */
 
 	.macro	get_thread_info, rd
 	mov	\rd, sp
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
new file mode 100644
index 0000000..9518c96
--- /dev/null
+++ b/arch/arm/kernel/entry-v7m.S
@@ -0,0 +1,142 @@
+/*
+ * linux/arch/arm/kernel/entry-v7m.S
+ *
+ * Copyright (C) 2008 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Low-level vector interface routines for the ARMv7-M architecture
+ */
+#include <asm/memory.h>
+#include <asm/glue.h>
+#include <asm/thread_notify.h>
+#include <asm/v7m.h>
+
+#include <mach/entry-macro.S>
+
+#include "entry-header.S"
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+#error "CONFIG_TRACE_IRQFLAGS not supported on the current ARMv7M implementation"
+#endif
+
+__invalid_entry:
+	v7m_exception_entry
+	adr	r0, strerr
+	mrs	r1, ipsr
+	mov	r2, lr
+	bl	printk
+	mov	r0, sp
+	bl	show_regs
+1:	b	1b
+ENDPROC(__invalid_entry)
+
+strerr:	.asciz	"\nUnhandled exception: IPSR = %08lx LR = %08lx\n"
+
+	.align	2
+__irq_entry:
+	v7m_exception_entry
+
+	@
+	@ Invoke the IRQ handler
+	@
+	mrs	r0, ipsr
+	ldr	r1, =0x1ff
+	and	r0, r1
+	mov	r1, sp
+	stmdb	sp!, {lr}
+	@ routine called with r0 = irq number, r1 = struct pt_regs *
+	bl	asm_do_IRQ
+
+	pop	{lr}
+	@
+	@ Check for any pending work if returning to user
+	@
+	ldr	r1, =V7M_SCS_ICSR
+	ldr	r0, [r1]
+	tst	r0, V7M_SCS_ICSR_RETTOBASE
+	beq	2f
+
+	get_thread_info tsk
+	ldr	r2, [tsk, #TI_FLAGS]
+	tst	r2, #_TIF_WORK_MASK
+	beq	2f			@ no work pending
+	mov	r0, #V7M_SCS_ICSR_PENDSVSET
+	str	r0, [r1]		@ raise PendSV
+
+2:
+	@ registers r0-r3 and r12 are automatically restored on exception
+	@ return. r4-r7 were not clobbered in v7m_exception_entry so for
+	@ correctness they don't need to be restored. So only r8-r11 must be
+	@ restored here. The easiest way to do so is to restore r0-r7, too.
+	ldmia	sp!, {r0-r11}
+	add	sp, #S_FRAME_SIZE-S_IP
+	cpsie	i
+	bx	lr
+ENDPROC(__irq_entry)
+
+__pendsv_entry:
+	v7m_exception_entry
+
+	ldr	r1, =V7M_SCS_ICSR
+	mov	r0, #V7M_SCS_ICSR_PENDSVCLR
+	str	r0, [r1]		@ clear PendSV
+
+	@ execute the pending work, including reschedule
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user
+ENDPROC(__pendsv_entry)
+
+/*
+ * Register switch for ARMv7-M processors.
+ * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
+ * previous and next are guaranteed not to be the same.
+ */
+ENTRY(__switch_to)
+	.fnstart
+	.cantunwind
+	add	ip, r1, #TI_CPU_SAVE
+	stmia	ip!, {r4 - r11}		@ Store most regs on stack
+	str	sp, [ip], #4
+	str	lr, [ip], #4
+	mov	r5, r0
+	add	r4, r2, #TI_CPU_SAVE
+	ldr	r0, =thread_notify_head
+	mov	r1, #THREAD_NOTIFY_SWITCH
+	bl	atomic_notifier_call_chain
+	mov	ip, r4
+	mov	r0, r5
+	ldmia	ip!, {r4 - r11}		@ Load all regs saved previously
+	ldr	sp, [ip]
+	ldr	pc, [ip, #4]!
+	.fnend
+ENDPROC(__switch_to)
+
+	.data
+	.align	8
+/*
+ * Vector table (64 words => 256 bytes natural alignment)
+ */
+ENTRY(vector_table)
+	.long	0			@ 0 - Reset stack pointer
+	.long	__invalid_entry		@ 1 - Reset
+	.long	__invalid_entry		@ 2 - NMI
+	.long	__invalid_entry		@ 3 - HardFault
+	.long	__invalid_entry		@ 4 - MemManage
+	.long	__invalid_entry		@ 5 - BusFault
+	.long	__invalid_entry		@ 6 - UsageFault
+	.long	__invalid_entry		@ 7 - Reserved
+	.long	__invalid_entry		@ 8 - Reserved
+	.long	__invalid_entry		@ 9 - Reserved
+	.long	__invalid_entry		@ 10 - Reserved
+	.long	vector_swi		@ 11 - SVCall
+	.long	__invalid_entry		@ 12 - Debug Monitor
+	.long	__invalid_entry		@ 13 - Reserved
+	.long	__pendsv_entry		@ 14 - PendSV
+	.long	__invalid_entry		@ 15 - SysTick
+	.rept	64 - 16
+	.long	__irq_entry		@ 16..64 - External Interrupts
+	.endr
-- 
1.8.2.rc2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v9 3/3] ARM: ARMv7-M: Allow the building of new kernel port
  2013-03-21 21:28 [PATCH v9 0/3] ARM: ARMv7 (i.e. Cortex-M3) support Uwe Kleine-König
  2013-03-21 21:28 ` [PATCH v9 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
  2013-03-21 21:28 ` [PATCH v9 2/3] ARM: ARMv7-M: Add support for exception handling Uwe Kleine-König
@ 2013-03-21 21:28 ` Uwe Kleine-König
  2013-03-27 10:37   ` Jonathan Austin
  2013-03-27 10:54 ` [PATCH v10 0/3] ARM: ARMv7-M (i.e. Cortex-M3) support Uwe Kleine-König
  3 siblings, 1 reply; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-21 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patch modifies the required Kconfig and Makefile files to allow the
building of kernel for Cortex-M3.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
 arch/arm/Kconfig         |  4 ++--
 arch/arm/Kconfig-nommu   |  2 +-
 arch/arm/Makefile        |  1 +
 arch/arm/kernel/Makefile |  8 +++++++-
 arch/arm/mm/Kconfig      | 22 +++++++++++++++++++++-
 arch/arm/mm/Makefile     |  2 ++
 6 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index dedf02b..7c8c607 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -9,7 +9,7 @@ config ARM
 	select BUILDTIME_EXTABLE_SORT if MMU
 	select CPU_PM if (SUSPEND || CPU_IDLE)
 	select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN && MMU
-	select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
+	select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
 	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
 	select GENERIC_IRQ_PROBE
 	select GENERIC_IRQ_SHOW
@@ -1685,7 +1685,7 @@ config SCHED_HRTICK
 
 config THUMB2_KERNEL
 	bool "Compile the kernel in Thumb-2 mode" if !CPU_THUMBONLY
-	depends on CPU_V7 && !CPU_V6 && !CPU_V6K
+	depends on (CPU_V7 || CPU_V7M) && !CPU_V6 && !CPU_V6K
 	default y if CPU_THUMBONLY
 	select AEABI
 	select ARM_ASM_UNIFIED
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 2cef8e1..c859495 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -28,7 +28,7 @@ config FLASH_SIZE
 config PROCESSOR_ID
 	hex 'Hard wire the processor ID'
 	default 0x00007700
-	depends on !CPU_CP15
+	depends on !(CPU_CP15 || CPU_V7M)
 	help
 	  If processor has no CP15 register, this processor ID is
 	  used instead of the auto-probing which utilizes the register.
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..f11b8da 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -59,6 +59,7 @@ comma = ,
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7M)	:=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
 arch-$(CONFIG_CPU_32v7)		:=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
 arch-$(CONFIG_CPU_32v6)		:=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
 # Only override the compiler option if ARMv6. The ARMv6K extensions are
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 5f3338e..00d703c 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -15,7 +15,7 @@ CFLAGS_REMOVE_return_address.o = -pg
 
 # Object file lists.
 
-obj-y		:= elf.o entry-armv.o entry-common.o irq.o opcodes.o \
+obj-y		:= elf.o entry-common.o irq.o opcodes.o \
 		   process.o ptrace.o return_address.o sched_clock.o \
 		   setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
 
@@ -23,6 +23,12 @@ obj-$(CONFIG_ATAGS)		+= atags_parse.o
 obj-$(CONFIG_ATAGS_PROC)	+= atags_proc.o
 obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
 
+ifeq ($(CONFIG_CPU_V7M),y)
+obj-y		+= entry-v7m.o
+else
+obj-y		+= entry-armv.o
+endif
+
 obj-$(CONFIG_OC_ETM)		+= etm.o
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index cb812a1..9c3eac4 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -397,6 +397,16 @@ config CPU_V7
 	select CPU_PABRT_V7
 	select CPU_TLB_V7 if MMU
 
+# ARMv7M
+config CPU_V7M
+	bool
+	select CPU_32v7M
+	select CPU_ABRT_NOMMU
+	select CPU_CACHE_NOP
+	select CPU_CACHE_VIPT
+	select CPU_PABRT_LEGACY
+	select CPU_THUMBONLY
+
 config CPU_THUMBONLY
 	bool
 	# There are no CPUs available with MMU that don't implement an ARM ISA:
@@ -441,6 +451,9 @@ config CPU_32v6K
 config CPU_32v7
 	bool
 
+config CPU_32v7M
+	bool
+
 # The abort model
 config CPU_ABRT_NOMMU
 	bool
@@ -494,6 +507,9 @@ config CPU_CACHE_V6
 config CPU_CACHE_V7
 	bool
 
+config CPU_CACHE_NOP
+	bool
+
 config CPU_CACHE_VIVT
 	bool
 
@@ -616,7 +632,11 @@ config ARCH_DMA_ADDR_T_64BIT
 
 config ARM_THUMB
 	bool "Support Thumb user binaries" if !CPU_THUMBONLY
-	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || CPU_V7 || CPU_FEROCEON
+	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || \
+		CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || \
+		CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || \
+		CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || \
+		CPU_V7 || CPU_FEROCEON || CPU_V7M
 	default y
 	help
 	  Say Y if you want to include kernel support for running user space
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 4e333fa..317b575 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_CPU_CACHE_V4WB)	+= cache-v4wb.o
 obj-$(CONFIG_CPU_CACHE_V6)	+= cache-v6.o
 obj-$(CONFIG_CPU_CACHE_V7)	+= cache-v7.o
 obj-$(CONFIG_CPU_CACHE_FA)	+= cache-fa.o
+obj-$(CONFIG_CPU_CACHE_NOP)	+= cache-nop.o
 
 AFLAGS_cache-v6.o	:=-Wa,-march=armv6
 AFLAGS_cache-v7.o	:=-Wa,-march=armv7-a
@@ -88,6 +89,7 @@ obj-$(CONFIG_CPU_FEROCEON)	+= proc-feroceon.o
 obj-$(CONFIG_CPU_V6)		+= proc-v6.o
 obj-$(CONFIG_CPU_V6K)		+= proc-v6.o
 obj-$(CONFIG_CPU_V7)		+= proc-v7.o
+obj-$(CONFIG_CPU_V7M)		+= proc-v7m.o
 
 AFLAGS_proc-v6.o	:=-Wa,-march=armv6
 AFLAGS_proc-v7.o	:=-Wa,-march=armv7-a
-- 
1.8.2.rc2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v9 1/3] ARM: Add base support for ARMv7-M
  2013-03-21 21:28 ` [PATCH v9 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
@ 2013-03-22 18:42   ` Jonathan Austin
  2013-03-22 21:48     ` Uwe Kleine-König
  0 siblings, 1 reply; 16+ messages in thread
From: Jonathan Austin @ 2013-03-22 18:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

This looks like a good set of changes! Things are much cleaner now - 
just a question about the nop cache functions and a few other things 
below - some of them are just tiny little things...

On 21/03/13 21:28, Uwe Kleine-K?nig wrote:
> From: Catalin Marinas <catalin.marinas@arm.com>
>
> This patch adds the base support for the ARMv7-M
> architecture. It consists of the corresponding arch/arm/mm/ files and
> various #ifdef's around the kernel. Exception handling is implemented by
> a subsequent patch.
>
> [ukleinek: squash in some changes originating from commit
>
> b5717ba (Cortex-M3: Add support for the Microcontroller Prototyping System)
>
> from the v2.6.33-arm1 patch stack, port to post 3.6, drop zImage
> support, drop reorganisation of pt_regs, assert CONFIG_V7M doesn't leak
> into installed headers and a few cosmetic changes]
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
> ---
> Changes since v8,
> id:1358413196-5609-3-git-send-email-u.kleine-koenig at pengutronix.de:
>
>   - rebase
>   - use more named constants
>   - add comment about setmode being empty
>   - add more (yet unused) v7m register defines
>   - enable UsageFault, BusFault and MemManage fault at boot time
>   - make nop multi-cache-able
> ---
>   arch/arm/include/asm/assembler.h   |  17 +++-
>   arch/arm/include/asm/cputype.h     |  12 ++-
>   arch/arm/include/asm/glue-cache.h  |  27 ++++++
>   arch/arm/include/asm/glue-df.h     |   8 ++
>   arch/arm/include/asm/glue-proc.h   |   9 ++
>   arch/arm/include/asm/irqflags.h    |  22 +++--
>   arch/arm/include/asm/ptrace.h      |   4 +
>   arch/arm/include/asm/system_info.h |   1 +
>   arch/arm/include/asm/v7m.h         |  47 +++++++++++
>   arch/arm/include/uapi/asm/ptrace.h |  35 ++++++--
>   arch/arm/kernel/head-nommu.S       |  10 ++-
>   arch/arm/kernel/setup.c            |  17 +++-
>   arch/arm/kernel/traps.c            |   2 +
>   arch/arm/mm/cache-nop.S            |  53 ++++++++++++
>   arch/arm/mm/nommu.c                |   2 +
>   arch/arm/mm/proc-v7m.S             | 167 +++++++++++++++++++++++++++++++++++++
>   16 files changed, 412 insertions(+), 21 deletions(-)
>   create mode 100644 arch/arm/include/asm/v7m.h
>   create mode 100644 arch/arm/mm/cache-nop.S
>   create mode 100644 arch/arm/mm/proc-v7m.S
>
> diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
> index 05ee9ee..a5fef71 100644
> --- a/arch/arm/include/asm/assembler.h
> +++ b/arch/arm/include/asm/assembler.h
> @@ -136,7 +136,11 @@
>    * assumes FIQs are enabled, and that the processor is in SVC mode.
>    */
>          .macro  save_and_disable_irqs, oldcpsr
> +#ifdef CONFIG_CPU_V7M
> +       mrs     \oldcpsr, primask
> +#else
>          mrs     \oldcpsr, cpsr
> +#endif
>          disable_irq
>          .endm
>
> @@ -150,7 +154,11 @@
>    * guarantee that this will preserve the flags.
>    */
>          .macro  restore_irqs_notrace, oldcpsr
> +#ifdef CONFIG_CPU_V7M
> +       msr     primask, \oldcpsr
> +#else
>          msr     cpsr_c, \oldcpsr
> +#endif
>          .endm
>
>          .macro restore_irqs, oldcpsr
> @@ -229,7 +237,14 @@
>   #endif
>          .endm
>
> -#ifdef CONFIG_THUMB2_KERNEL
> +#if defined(CONFIG_CPU_V7M)
> +       /*
> +        * setmode is used to assert to be in svc mode during boot. For v7-M
> +        * this is done in __v7m_setup, so setmode can be empty here.
> +        */
> +       .macro  setmode, mode, reg
> +       .endm
> +#elif defined(CONFIG_THUMB2_KERNEL)
>          .macro  setmode, mode, reg
>          mov     \reg, #\mode
>          msr     cpsr_c, \reg
> diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
> index 7652712..d7eb0fb 100644
> --- a/arch/arm/include/asm/cputype.h
> +++ b/arch/arm/include/asm/cputype.h
> @@ -106,7 +106,17 @@ static inline unsigned int __attribute_const__ read_cpuid_id(void)
>          return read_cpuid(CPUID_ID);
>   }
>
> -#else /* ifdef CONFIG_CPU_CP15 */
> +#elif defined(CONFIG_CPU_V7M)
> +
> +#include <asm/io.h>
> +#include <asm/v7m.h>
> +
> +static inline unsigned int __attribute_const__ read_cpuid_id(void)
> +{
> +       return readl(V7M_SCS_CPUID);
> +}
> +
> +#else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */
>
>   static inline unsigned int __attribute_const__ read_cpuid_id(void)
>   {
> diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
> index cca9f15..65c9faf 100644
> --- a/arch/arm/include/asm/glue-cache.h
> +++ b/arch/arm/include/asm/glue-cache.h
> @@ -125,10 +125,37 @@
>   # endif
>   #endif
>
> +#if defined(CONFIG_CPU_V7M)
> +# ifdef _CACHE
> +#  define MULTI_CACHE 1
> +# else
> +#  define _CACHE nop
> +# endif
> +#endif
> +
>   #if !defined(_CACHE) && !defined(MULTI_CACHE)
>   #error Unknown cache maintenance model
>   #endif
>
> +#ifndef __ASSEMBLER__
> +extern inline void nop_flush_icache_all(void) { }
> +extern inline void nop_flush_kern_cache_all(void) { }
> +extern inline void nop_flush_kern_cache_louis(void) { }
> +extern inline void nop_flush_user_cache_all(void) { }
> +extern inline void nop_flush_user_cache_range(unsigned long a,
> +               unsigned long b, unsigned int c) { }
> +
> +extern inline void nop_coherent_kern_range(unsigned long a, unsigned long b) { }
> +extern inline int nop_coherent_user_range(unsigned long a,
> +               unsigned long b) { return 0; }
> +extern inline void nop_flush_kern_dcache_area(void *a, size_t s) { }
> +
> +extern inline void nop_dma_flush_range(const void *a, const void *b) { }
> +
> +extern inline void nop_dma_map_area(const void *s, size_t l, int f) { }
> +extern inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
> +#endif
> +


Now that you've added the arch/arm/mm/cache-nop.S do we really need 
these defines? I just tried removing them and it still builds - is there 
a use-case for these I missed?


>   #ifndef MULTI_CACHE
>   #define __cpuc_flush_icache_all                __glue(_CACHE,_flush_icache_all)
>   #define __cpuc_flush_kern_all          __glue(_CACHE,_flush_kern_cache_all)
> diff --git a/arch/arm/include/asm/glue-df.h b/arch/arm/include/asm/glue-df.h
> index b6e9f2c..6b70f1b 100644
> --- a/arch/arm/include/asm/glue-df.h
> +++ b/arch/arm/include/asm/glue-df.h
> @@ -95,6 +95,14 @@
>   # endif
>   #endif
>
> +#ifdef CONFIG_CPU_ABRT_NOMMU
> +# ifdef CPU_DABORT_HANDLER
> +#  define MULTI_DABORT 1
> +# else
> +#  define CPU_DABORT_HANDLER nommu_early_abort
> +# endif
> +#endif
> +
>   #ifndef CPU_DABORT_HANDLER
>   #error Unknown data abort handler type
>   #endif
> diff --git a/arch/arm/include/asm/glue-proc.h b/arch/arm/include/asm/glue-proc.h
> index ac1dd54..f2f39bc 100644
> --- a/arch/arm/include/asm/glue-proc.h
> +++ b/arch/arm/include/asm/glue-proc.h
> @@ -230,6 +230,15 @@
>   # endif
>   #endif
>
> +#ifdef CONFIG_CPU_V7M
> +# ifdef CPU_NAME
> +#  undef  MULTI_CPU
> +#  define MULTI_CPU
> +# else
> +#  define CPU_NAME cpu_v7m
> +# endif
> +#endif
> +
>   #ifndef MULTI_CPU
>   #define cpu_proc_init                  __glue(CPU_NAME,_proc_init)
>   #define cpu_proc_fin                   __glue(CPU_NAME,_proc_fin)
> diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h
> index 1e6cca5..3b763d6 100644
> --- a/arch/arm/include/asm/irqflags.h
> +++ b/arch/arm/include/asm/irqflags.h
> @@ -8,6 +8,16 @@
>   /*
>    * CPU interrupt mask handling.
>    */
> +#ifdef CONFIG_CPU_V7M
> +#define IRQMASK_REG_NAME_R "primask"
> +#define IRQMASK_REG_NAME_W "primask"
> +#define IRQMASK_I_BIT  1
> +#else
> +#define IRQMASK_REG_NAME_R "cpsr"
> +#define IRQMASK_REG_NAME_W "cpsr_c"
> +#define IRQMASK_I_BIT  PSR_I_BIT
> +#endif
> +
>   #if __LINUX_ARM_ARCH__ >= 6
>
>   static inline unsigned long arch_local_irq_save(void)
> @@ -15,7 +25,7 @@ static inline unsigned long arch_local_irq_save(void)
>          unsigned long flags;
>
>          asm volatile(
> -               "       mrs     %0, cpsr        @ arch_local_irq_save\n"
> +               "       mrs     %0, " IRQMASK_REG_NAME_R "      @ arch_local_irq_save\n"
>                  "       cpsid   i"
>                  : "=r" (flags) : : "memory", "cc");
>          return flags;
> @@ -129,7 +139,7 @@ static inline unsigned long arch_local_save_flags(void)
>   {
>          unsigned long flags;
>          asm volatile(
> -               "       mrs     %0, cpsr        @ local_save_flags"
> +               "       mrs     %0, " IRQMASK_REG_NAME_R "      @ local_save_flags"
>                  : "=r" (flags) : : "memory", "cc");
>          return flags;
>   }
> @@ -140,7 +150,7 @@ static inline unsigned long arch_local_save_flags(void)
>   static inline void arch_local_irq_restore(unsigned long flags)
>   {
>          asm volatile(
> -               "       msr     cpsr_c, %0      @ local_irq_restore"
> +               "       msr     " IRQMASK_REG_NAME_W ", %0      @ local_irq_restore"
>                  :
>                  : "r" (flags)
>                  : "memory", "cc");
> @@ -148,8 +158,8 @@ static inline void arch_local_irq_restore(unsigned long flags)
>
>   static inline int arch_irqs_disabled_flags(unsigned long flags)
>   {
> -       return flags & PSR_I_BIT;
> +       return flags & IRQMASK_I_BIT;
>   }
>
> -#endif
> -#endif
> +#endif /* ifdef __KERNEL__ */
> +#endif /* ifndef __ASM_ARM_IRQFLAGS_H */
> diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
> index 3d52ee1..04c99f3 100644
> --- a/arch/arm/include/asm/ptrace.h
> +++ b/arch/arm/include/asm/ptrace.h
> @@ -45,6 +45,7 @@ struct pt_regs {
>    */
>   static inline int valid_user_regs(struct pt_regs *regs)
>   {
> +#ifndef CONFIG_CPU_V7M
>          unsigned long mode = regs->ARM_cpsr & MODE_MASK;
>
>          /*
> @@ -67,6 +68,9 @@ static inline int valid_user_regs(struct pt_regs *regs)
>                  regs->ARM_cpsr |= USR_MODE;
>
>          return 0;
> +#else /* ifndef CONFIG_CPU_V7M */
> +       return 1;
> +#endif
>   }
>
>   static inline long regs_return_value(struct pt_regs *regs)
> diff --git a/arch/arm/include/asm/system_info.h b/arch/arm/include/asm/system_info.h
> index dfd386d..720ea03 100644
> --- a/arch/arm/include/asm/system_info.h
> +++ b/arch/arm/include/asm/system_info.h
> @@ -11,6 +11,7 @@
>   #define CPU_ARCH_ARMv5TEJ      7
>   #define CPU_ARCH_ARMv6         8
>   #define CPU_ARCH_ARMv7         9
> +#define CPU_ARCH_ARMv7M                10
>
>   #ifndef __ASSEMBLY__
>
> diff --git a/arch/arm/include/asm/v7m.h b/arch/arm/include/asm/v7m.h
> new file mode 100644
> index 0000000..e12b887
> --- /dev/null
> +++ b/arch/arm/include/asm/v7m.h
> @@ -0,0 +1,47 @@
> +/*
> + * Common defines for v7m cpus
> + */
> +#define V7M_SCS_ICTR   IOMEM(0xe000e004)
> +#define V7M_SCS_ICTR_INTLINESNUM_MASK          0x0000000f
> +
> +#define V7M_SCS_CPUID  IOMEM(0xe000ed00)
> +

This is really the CPUID_BASE register, not the 'CPUID' register.

> +#define V7M_SCS_ICSR   IOMEM(0xe000ed04)
> +#define V7M_SCS_ICSR_PENDSVSET                 (1 << 28)
> +#define V7M_SCS_ICSR_PENDSVCLR                 (1 << 27)
> +#define V7M_SCS_ICSR_RETTOBASE                 (1 << 11)
> +
> +#define V7M_SCS_VTOR   IOMEM(0xe000ed08)
> +
> +#define V7M_SCS_SCR    IOMEM(0xe000ed10)
> +#define V7M_SCS_SCR_SLEEPDEEP                  (1 << 2)
> +
> +#define V7M_SCS_CCR    IOMEM(0xe000ed14)
> +#define V7M_SCS_CCR_STKALIGN                   (1 << 9)
> +
> +#define V7M_SCS_SHPR2  IOMEM(0xe000ed1c)
> +#define V7M_SCS_SHPR3  IOMEM(0xe000ed20)

This is just a minor nit, but when reading these it is confusing not to 
have the IOMEM(...) lines aligned with the bitfields...

Did you have some reasons for doing it this way?

If not, I'd like to see them all lined up (and you can remove one 
tabstop too ;-)

> +
> +#define V7M_SCS_SHCSR  IOMEM(0xe000ed24)
> +#define V7M_SCS_SHCSR_USGFAULTENA              (1 << 18)
> +#define V7M_SCS_SHCSR_BUSFAULTENA              (1 << 17)
> +#define V7M_SCS_SHCSR_MEMFAULTENA              (1 << 16)
> +
> +#define V7M_xPSR_FPALIGN                       0x00000200
> +
> +#define EXC_RET_SBOP                           0xffffffe1
> +#define EXC_RET_FRAMETYPE_MASK                 0x00000010
> +#define EXC_RET_FRAMETYPE__BASIC               0x00000010
> +#define EXC_RET_MODE_MASK                      0x00000008
> +#define EXC_RET_MODE__HANDLER                  0x00000000
> +#define EXC_RET_MODE__THREAD                   0x00000008
> +#define EXC_RET_STACK_MASK                     0x00000004
> +#define EXC_RET_STACK__MAIN                    0x00000000
> +#define EXC_RET_STACK__PROCESS                 0x00000004

I grep'd around the source tree looking for a precedent for this double 
underscore behaviour and couldn't find anything.

I presume that you're trying to denote that these are values 'served by' 
the mask above?

I think the double underscore looks weird - made me think it was a 
typo... I think you could safely stick with just one, or if you're 
really concerned about the extra distinction, use EXC_RET_STACK_VAL_MAIN 
etc.

> +
> +#define EXC_RET_HANDLERMODE_MAINSTACK  \
> +       (EXC_RET_SBOP | EXC_RET_FRAMETYPE__BASIC | EXC_RET_MODE__HANDLER | EXC_RET_STACK__MAIN)
> +#define EXC_RET_THREADMODE_MAINSTACK   \
> +       (EXC_RET_SBOP | EXC_RET_FRAMETYPE__BASIC | EXC_RET_MODE__THREAD | EXC_RET_STACK__MAIN)

Do we ever use these two? I can't find any places where we do in 
uwe/efm32. If not, I think perhaps this is a bit over-engineered... If 
you plan to extend the kernel port in the future to use the extra modes, 
by all means keep them in, but couldn't we just define 
EXC_RET_THREADMODE_PROCESSSTACK? (or even call it EXC_RET_THREAD_PROCESS?)

> +#define EXC_RET_THREADMODE_PROCESSSTACK        \
> +       (EXC_RET_SBOP | EXC_RET_FRAMETYPE__BASIC | EXC_RET_MODE__THREAD | EXC_RET_STACK__PROCESS)
> diff --git a/arch/arm/include/uapi/asm/ptrace.h b/arch/arm/include/uapi/asm/ptrace.h
> index 96ee092..5af0ed1 100644
> --- a/arch/arm/include/uapi/asm/ptrace.h
> +++ b/arch/arm/include/uapi/asm/ptrace.h
> @@ -34,28 +34,47 @@
>
>   /*
>    * PSR bits
> + * Note on V7M there is no mode contained in the PSR
>    */
>   #define USR26_MODE     0x00000000
>   #define FIQ26_MODE     0x00000001
>   #define IRQ26_MODE     0x00000002
>   #define SVC26_MODE     0x00000003
> +#if defined(__KERNEL__) && defined(CONFIG_CPU_V7M)
> +/*
> + * Use 0 here to get code right that creates a userspace
> + * or kernel space thread.
> + */
> +#define USR_MODE       0x00000000
> +#define SVC_MODE       0x00000000
> +#else
>   #define USR_MODE       0x00000010
> +#define SVC_MODE       0x00000013
> +#endif
>   #define FIQ_MODE       0x00000011
>   #define IRQ_MODE       0x00000012
> -#define SVC_MODE       0x00000013
>   #define ABT_MODE       0x00000017
>   #define HYP_MODE       0x0000001a
>   #define UND_MODE       0x0000001b
>   #define SYSTEM_MODE    0x0000001f
>   #define MODE32_BIT     0x00000010
>   #define MODE_MASK      0x0000001f
> -#define PSR_T_BIT      0x00000020
> -#define PSR_F_BIT      0x00000040
> -#define PSR_I_BIT      0x00000080
> -#define PSR_A_BIT      0x00000100
> -#define PSR_E_BIT      0x00000200
> -#define PSR_J_BIT      0x01000000
> -#define PSR_Q_BIT      0x08000000
> +
> +#define V4_PSR_T_BIT   0x00000020      /* >= V4T, but not V7M */
> +#define V7M_PSR_T_BIT  0x01000000
> +#if defined(__KERNEL__) && defined(CONFIG_CPU_V7M)
> +#define PSR_T_BIT      V7M_PSR_T_BIT
> +#else
> +/* for compatibility */
> +#define PSR_T_BIT      V4_PSR_T_BIT
> +#endif
> +
> +#define PSR_F_BIT      0x00000040      /* >= V4, but not V7M */
> +#define PSR_I_BIT      0x00000080      /* >= V4, but not V7M */
> +#define PSR_A_BIT      0x00000100      /* >= V6, but not V7M */
> +#define PSR_E_BIT      0x00000200      /* >= V6, but not V7M */
> +#define PSR_J_BIT      0x01000000      /* >= V5J, but not V7M */
> +#define PSR_Q_BIT      0x08000000      /* >= V5E, including V7M */
>   #define PSR_V_BIT      0x10000000
>   #define PSR_C_BIT      0x20000000
>   #define PSR_Z_BIT      0x40000000
> diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
> index 6a2e09c..e2988bb 100644
> --- a/arch/arm/kernel/head-nommu.S
> +++ b/arch/arm/kernel/head-nommu.S
> @@ -19,6 +19,7 @@
>   #include <asm/asm-offsets.h>
>   #include <asm/cp15.h>
>   #include <asm/thread_info.h>
> +#include <asm/v7m.h>
>
>   /*
>    * Kernel startup entry point.
> @@ -50,10 +51,13 @@ ENTRY(stext)
>
>          setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
>                                                  @ and irqs disabled
> -#ifndef CONFIG_CPU_CP15
> -       ldr     r9, =CONFIG_PROCESSOR_ID
> -#else
> +#if defined(CONFIG_CPU_CP15)
>          mrc     p15, 0, r9, c0, c0              @ get processor id
> +#elif defined(CONFIG_CPU_V7M)
> +       ldr     r9, =V7M_SCS_CPUID

If you do choose to rename to CPUID_BASE then fix this up too :)

> +       ldr     r9, [r9]
> +#else
> +       ldr     r9, =CONFIG_PROCESSOR_ID
>   #endif
>          bl      __lookup_processor_type         @ r5=procinfo r9=cpuid
>          movs    r10, r5                         @ invalid processor (r5=0)?
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index 1cc9e17..8291245 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -128,7 +128,9 @@ struct stack {
>          u32 und[3];
>   } ____cacheline_aligned;
>
> +#ifndef CONFIG_CPU_V7M
>   static struct stack stacks[NR_CPUS];
> +#endif
>
>   char elf_platform[ELF_PLATFORM_SIZE];
>   EXPORT_SYMBOL(elf_platform);
> @@ -207,7 +209,7 @@ static const char *proc_arch[] = {
>          "5TEJ",
>          "6TEJ",
>          "7",
> -       "?(11)",
> +       "7M",
>          "?(12)",
>          "?(13)",
>          "?(14)",
> @@ -216,6 +218,12 @@ static const char *proc_arch[] = {
>          "?(17)",
>   };
>
> +#ifdef CONFIG_CPU_V7M
> +static int __get_cpu_architecture(void)
> +{
> +       return CPU_ARCH_ARMv7M;
> +}
> +#else
>   static int __get_cpu_architecture(void)
>   {
>          int cpu_arch;
> @@ -248,6 +256,7 @@ static int __get_cpu_architecture(void)
>
>          return cpu_arch;
>   }
> +#endif
>
>   int __pure cpu_architecture(void)
>   {
> @@ -293,7 +302,9 @@ static void __init cacheid_init(void)
>   {
>          unsigned int arch = cpu_architecture();
>
> -       if (arch >= CPU_ARCH_ARMv6) {
> +       if (arch == CPU_ARCH_ARMv7M) {
> +               cacheid = 0;
> +       } else if (arch >= CPU_ARCH_ARMv6) {
>                  unsigned int cachetype = read_cpuid_cachetype();
>                  if ((cachetype & (7 << 29)) == 4 << 29) {
>                          /* ARMv7 register format */
> @@ -375,6 +386,7 @@ static void __init feat_v6_fixup(void)
>    */
>   void cpu_init(void)
>   {
> +#ifndef CONFIG_CPU_V7M
>          unsigned int cpu = smp_processor_id();
>          struct stack *stk = &stacks[cpu];
>
> @@ -425,6 +437,7 @@ void cpu_init(void)
>                "I" (offsetof(struct stack, und[0])),
>                PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
>              : "r14");
> +#endif
>   }
>
>   int __cpu_logical_map[NR_CPUS];
> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
> index 1c08911..3990eaa 100644
> --- a/arch/arm/kernel/traps.c
> +++ b/arch/arm/kernel/traps.c
> @@ -819,6 +819,7 @@ static void __init kuser_get_tls_init(unsigned long vectors)
>
>   void __init early_trap_init(void *vectors_base)
>   {
> +#ifndef CONFIG_CPU_V7M

I think a comment would be nice, just so as not to scare people who 
expect us to need to copy the vector table somewhere.

/* V7M allows us to use the vector_table in the kernel image */

Or similar.
>          unsigned long vectors = (unsigned long)vectors_base;
>          extern char __stubs_start[], __stubs_end[];
>          extern char __vectors_start[], __vectors_end[];
> @@ -850,4 +851,5 @@ void __init early_trap_init(void *vectors_base)
>
>          flush_icache_range(vectors, vectors + PAGE_SIZE);
>          modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
> +#endif
>   }
> diff --git a/arch/arm/mm/cache-nop.S b/arch/arm/mm/cache-nop.S
> new file mode 100644
> index 0000000..543b930
> --- /dev/null
> +++ b/arch/arm/mm/cache-nop.S
> @@ -0,0 +1,53 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <linux/linkage.h>
> +#include <linux/init.h>
> +#include <asm/assembler.h>
> +#include <asm/errno.h>
> +#include <asm/unwind.h>
> +
> +#include "proc-macros.S"
> +
> +ENTRY(nop_flush_icache_all)
> +       mov     pc, lr
> +ENDPROC(nop_flush_icache_all)
> +
> +       .globl nop_flush_kern_cache_all
> +       .equ nop_flush_kern_cache_all, nop_flush_icache_all
> +
> +       .globl nop_flush_kern_cache_louis
> +       .equ nop_flush_kern_cache_louis, nop_flush_icache_all
> +
> +       .globl nop_flush_user_cache_all
> +       .equ nop_flush_user_cache_all, nop_flush_icache_all
> +
> +       .globl nop_flush_user_cache_range
> +       .equ nop_flush_user_cache_range, nop_flush_icache_all
> +
> +       .globl nop_coherent_kern_range
> +       .equ nop_coherent_kern_range, nop_flush_icache_all
> +
> +ENTRY(nop_coherent_user_range)
> +       mov     r0, 0
> +       mov     pc, lr
> +ENDPROC(nop_coherent_user_range)
> +
> +       .globl nop_flush_kern_dcache_area
> +       .equ nop_flush_kern_dcache_area, nop_flush_icache_all
> +
> +       .globl nop_dma_flush_range
> +       .equ nop_dma_flush_range, nop_flush_icache_all
> +
> +       .globl nop_dma_map_area
> +       .equ nop_dma_map_area, nop_flush_icache_all
> +
> +       .globl nop_dma_unmap_area
> +       .equ nop_dma_unmap_area, nop_flush_icache_all
> +
> +       __INITDATA
> +
> +       @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
> +       define_cache_functions nop
> diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
> index d51225f..4bc8ae5 100644
> --- a/arch/arm/mm/nommu.c
> +++ b/arch/arm/mm/nommu.c
> @@ -20,12 +20,14 @@
>
>   void __init arm_mm_memblock_reserve(void)
>   {
> +#ifndef CONFIG_CPU_V7M

Same deal here about a comment explain V7M's differences
>          /*
>           * Register the exception vector page.
>           * some architectures which the DRAM is the exception vector to trap,
>           * alloc_page breaks with error, although it is not NULL, but "0."
>           */
>          memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE);
> +#endif
>   }
>
>   void __init sanity_check_meminfo(void)
> diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
> new file mode 100644
> index 0000000..c2b68d3
> --- /dev/null
> +++ b/arch/arm/mm/proc-v7m.S
> @@ -0,0 +1,167 @@
> +/*
> + *  linux/arch/arm/mm/proc-v7m.S
> + *
> + *  Copyright (C) 2008 ARM Ltd.
> + *  Copyright (C) 2001 Deep Blue Solutions Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + *  This is the "shell" of the ARMv7-M processor support.
> + */
> +#include <linux/linkage.h>
> +#include <asm/assembler.h>
> +#include <asm/v7m.h>
> +
> +ENTRY(cpu_v7m_proc_init)
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_proc_init)
> +
> +ENTRY(cpu_v7m_proc_fin)
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_proc_fin)
> +
> +/*
> + *     cpu_v7m_reset(loc)
> + *
> + *     Perform a soft reset of the system.  Put the CPU into the
> + *     same state as it would be if it had been reset, and branch
> + *     to what would be the reset vector.
> + *
> + *     - loc   - location to jump to for soft reset
> + */
> +       .align  5
> +ENTRY(cpu_v7m_reset)
> +       mov     pc, r0
> +ENDPROC(cpu_v7m_reset)
> +
> +/*
> + *     cpu_v7m_do_idle()
> + *
> + *     Idle the processor (eg, wait for interrupt).
> + *
> + *     IRQs are already disabled.
> + */
> +ENTRY(cpu_v7m_do_idle)
> +       wfi
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_do_idle)
> +
> +ENTRY(cpu_v7m_dcache_clean_area)
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_dcache_clean_area)
> +
> +/*
> + * There is no MMU, so here is nothing to do.
> + */
> +ENTRY(cpu_v7m_switch_mm)
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_switch_mm)
> +
> +cpu_v7m_name:
> +       .ascii  "ARMv7-M Processor"
> +       .align
> +
> +       .section ".text.init", #alloc, #execinstr
> +
> +/*
> + *     __v7m_setup
> + *
> + *     This should be able to cover all ARMv7-M cores.
> + */
> +__v7m_setup:
> +       @ Configure the vector table base address
> +       ldr     r0, =V7M_SCS_VTOR       @ vector table base address
> +       ldr     r12, =vector_table
> +       str     r12, [r0]
> +
> +       @ enable UsageFault, BusFault and MemManage fault.
> +       ldr     r5, [r0, #(V7M_SCS_SHCSR - V7M_SCS_VTOR)]
> +       orr     r5, #(V7M_SCS_SHCSR_USGFAULTENA | V7M_SCS_SHCSR_BUSFAULTENA | V7M_SCS_SHCSR_MEMFAULTENA)
> +       str     r5, [r0, #(V7M_SCS_SHCSR - V7M_SCS_VTOR)]

This looks weird and is confusing - it makes it seem like there is some 
relationship between SCS_SHCSR and SCS_VTOR, which there isn't at all - 
the only link is that we just loaded SCS_VTOR in to r0 and now we want 
V7M_SCS_SHCSR - right?

Why not do the "ldr r0, =V7M_SCS_SHCS"? Is it to save the one 
instruction? Or save an entry in the literal pool?

I don't think for a single instruction/word it is worth the confusing 
way of writing it...

But then, perhaps I'm missing something?

> +
> +       @ Lower the priority of the SVC and PendSV exceptions
> +       ldr     r0, =V7M_SCS_SHPR2
> +       mov     r5, #0x80000000
> +       str     r5, [r0]                @ set SVC priority
> +       ldr     r0, =V7M_SCS_SHPR3
> +       mov     r5, #0x00800000
> +       str     r5, [r0]                @ set PendSV priority
> +
> +       @ SVC to run the kernel in this mode
> +       adr     r0, BSYM(1f)
> +       ldr     r5, [r12, #11 * 4]      @ read the SVC vector entry
> +       str     r0, [r12, #11 * 4]      @ write the temporary SVC vector entry
> +       mov     r6, lr                  @ save LR
> +       mov     r7, sp                  @ save SP
> +       ldr     sp, =__v7m_setup_stack_top
> +       cpsie   i
> +       svc     #0
> +1:     cpsid   i
> +       str     r5, [r12, #11 * 4]      @ restore the original SVC vector entry
> +       mov     lr, r6                  @ restore LR
> +       mov     sp, r7                  @ restore SP
> +
> +       @ Special-purpose control register
> +       mov     r0, #1
> +       msr     control, r0             @ Thread mode has unpriviledged access
> +
> +       @ Configure the System Control Register

Can we be a bit more specific here?

@Configure the System Control Register to ensure 8-byte stack alignment

> +       ldr     r0, =V7M_SCS_CCR        @ system control register
> +       ldr     r12, [r0]
> +       orr     r12, #V7M_SCS_CCR_STKALIGN

Whether this bit is RO or RW is implementation defined - sorry I didn't 
notice this with earlier responses...

As we always check the stack alignment on exception entry/return I think 
this isn't an issue - but does leave me asking why we bother with this 
if we always do the check?

> +       str     r12, [r0]
> +       mov     pc, lr
> +ENDPROC(__v7m_setup)
> +
> +       .align  2
> +       .type   v7m_processor_functions, #object
> +ENTRY(v7m_processor_functions)
> +       .word   nommu_early_abort
> +       .word   cpu_v7m_proc_init
> +       .word   cpu_v7m_proc_fin
> +       .word   cpu_v7m_reset
> +       .word   cpu_v7m_do_idle
> +       .word   cpu_v7m_dcache_clean_area
> +       .word   cpu_v7m_switch_mm
> +       .word   0                       @ cpu_v7m_set_pte_ext

The fact that we lack a stub function here will mean that compiling with 
module support won't work.

Do you expect modules to work?
If not, can we therefore make V7M and CONFIG_MODULES mutually exclusive.
If so, we should fix this.

> +       .word   legacy_pabort
> +       .size   v7m_processor_functions, . - v7m_processor_functions
> +
> +       .type   cpu_arch_name, #object
> +cpu_arch_name:
> +       .asciz  "armv7m"
> +       .size   cpu_arch_name, . - cpu_arch_name
> +
> +       .type   cpu_elf_name, #object
> +cpu_elf_name:
> +       .asciz  "v7m"
> +       .size   cpu_elf_name, . - cpu_elf_name
> +       .align
> +
> +       .section ".proc.info.init", #alloc, #execinstr
> +
> +       /*
> +        * Match any ARMv7-M processor core.
> +        */
> +       .type   __v7m_proc_info, #object
> +__v7m_proc_info:
> +       .long   0x000f0000              @ Required ID value
> +       .long   0x000f0000              @ Mask for ID
> +       .long   0                       @ proc_info_list.__cpu_mm_mmu_flags
> +       .long   0                       @ proc_info_list.__cpu_io_mmu_flags
> +       b       __v7m_setup             @ proc_info_list.__cpu_flush
> +       .long   cpu_arch_name
> +       .long   cpu_elf_name
> +       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP

I don't think M3 has SWP and EDSP...

based on V7M ARMARM:
(For SWP)
"For synchronization, ARMv7-M only supports the byte, halfword, and word 
versions of the load and store exclusive instructions. ARMv7-R also 
supports the doubleword versions of these instructions, and the legacy 
swap instructions"
(For EDSP)
None of the instructions listed as coming from the DSP extensions are 
listed in the M3 TRM (eg PKHTB, SXTAB)


> +       .long   cpu_v7m_name
> +       .long   v7m_processor_functions @ proc_info_list.proc
> +       .long   0                       @ proc_info_list.tlb
> +       .long   0                       @ proc_info_list.user
> +       .long   nop_cache_fns           @ proc_info_list.cache
> +       .size   __v7m_proc_info, . - __v7m_proc_info
> +
> +__v7m_setup_stack:
> +       .space  4 * 8                           @ 8 registers
> +__v7m_setup_stack_top:
> --
> 1.8.2.rc2
>
>

Hope they are useful comments,
Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v9 1/3] ARM: Add base support for ARMv7-M
  2013-03-22 18:42   ` Jonathan Austin
@ 2013-03-22 21:48     ` Uwe Kleine-König
  0 siblings, 0 replies; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-22 21:48 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jonathan,

On Fri, Mar 22, 2013 at 06:42:53PM +0000, Jonathan Austin wrote:
> This looks like a good set of changes! Things are much cleaner now -
> just a question about the nop cache functions and a few other things
> below - some of them are just tiny little things...
Thanks

> On 21/03/13 21:28, Uwe Kleine-K?nig wrote:
> ...
> >--- a/arch/arm/include/asm/glue-cache.h
> >+++ b/arch/arm/include/asm/glue-cache.h
> >@@ -125,10 +125,37 @@
> >  # endif
> >  #endif
> >
> >+#if defined(CONFIG_CPU_V7M)
> >+# ifdef _CACHE
> >+#  define MULTI_CACHE 1
> >+# else
> >+#  define _CACHE nop
> >+# endif
> >+#endif
> >+
> >  #if !defined(_CACHE) && !defined(MULTI_CACHE)
> >  #error Unknown cache maintenance model
> >  #endif
> >
> >+#ifndef __ASSEMBLER__
> >+extern inline void nop_flush_icache_all(void) { }
> >+extern inline void nop_flush_kern_cache_all(void) { }
> >+extern inline void nop_flush_kern_cache_louis(void) { }
> >+extern inline void nop_flush_user_cache_all(void) { }
> >+extern inline void nop_flush_user_cache_range(unsigned long a,
> >+               unsigned long b, unsigned int c) { }
> >+
> >+extern inline void nop_coherent_kern_range(unsigned long a, unsigned long b) { }
> >+extern inline int nop_coherent_user_range(unsigned long a,
> >+               unsigned long b) { return 0; }
> >+extern inline void nop_flush_kern_dcache_area(void *a, size_t s) { }
> >+
> >+extern inline void nop_dma_flush_range(const void *a, const void *b) { }
> >+
> >+extern inline void nop_dma_map_area(const void *s, size_t l, int f) { }
> >+extern inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
> >+#endif
> >+
> 
> 
> Now that you've added the arch/arm/mm/cache-nop.S do we really need
> these defines? I just tried removing them and it still builds - is
> there a use-case for these I missed?
Well, they still make a difference. With the definitions I get:

	$ objdump -d vmlinux | sed -n '/__soft_restart/,/^$/p'
	8c000e8a <__soft_restart>:
	8c000e8a:	b510      	push	{r4, lr}
	8c000e8c:	4604      	mov	r4, r0
	8c000e8e:	f002 f8f6 	bl	8c00307e <setup_mm_for_reboot>
	8c000e92:	f002 f947 	bl	8c003124 <cpu_v7m_proc_fin>
	8c000e96:	4620      	mov	r0, r4
	8c000e98:	f002 f952 	bl	8c003140 <cpu_v7m_reset>

compared to the following when removing them:

	$ objdump -d vmlinux | sed -n '/__soft_restart/,/^$/p'
	8c000e8a <__soft_restart>:
	8c000e8a:	b510      	push	{r4, lr}
	8c000e8c:	4604      	mov	r4, r0
	8c000e8e:	f002 f929 	bl	8c0030e4 <setup_mm_for_reboot>
	8c000e92:	f002 f985 	bl	8c0031a0 <nop_coherent_kern_range>
	8c000e96:	f002 f995 	bl	8c0031c4 <cpu_v7m_proc_fin>
	8c000e9a:	f002 f981 	bl	8c0031a0 <nop_coherent_kern_range>
	8c000e9e:	4620      	mov	r0, r4
	8c000ea0:	f002 f99e 	bl	8c0031e0 <cpu_v7m_reset>

(Just picked out the first function using the caching functions.) I
think it's worth to keep them.

> >--- /dev/null
> >+++ b/arch/arm/include/asm/v7m.h
> >@@ -0,0 +1,47 @@
> >+/*
> >+ * Common defines for v7m cpus
> >+ */
> >+#define V7M_SCS_ICTR   IOMEM(0xe000e004)
> >+#define V7M_SCS_ICTR_INTLINESNUM_MASK          0x0000000f
> >+
> >+#define V7M_SCS_CPUID  IOMEM(0xe000ed00)
> >+
> 
> This is really the CPUID_BASE register, not the 'CPUID' register.
In "my" ARMARMv7M Table B3-4 calls it CPUID only. The description calls
it "CPUID Base Register" but still I think that CPUID is the right
mnemonic.

> >+#define V7M_SCS_ICSR   IOMEM(0xe000ed04)
> >+#define V7M_SCS_ICSR_PENDSVSET                 (1 << 28)
> >+#define V7M_SCS_ICSR_PENDSVCLR                 (1 << 27)
> >+#define V7M_SCS_ICSR_RETTOBASE                 (1 << 11)
> >+
> >+#define V7M_SCS_VTOR   IOMEM(0xe000ed08)
> >+
> >+#define V7M_SCS_SCR    IOMEM(0xe000ed10)
> >+#define V7M_SCS_SCR_SLEEPDEEP                  (1 << 2)
> >+
> >+#define V7M_SCS_CCR    IOMEM(0xe000ed14)
> >+#define V7M_SCS_CCR_STKALIGN                   (1 << 9)
> >+
> >+#define V7M_SCS_SHPR2  IOMEM(0xe000ed1c)
> >+#define V7M_SCS_SHPR3  IOMEM(0xe000ed20)
> 
> This is just a minor nit, but when reading these it is confusing not
> to have the IOMEM(...) lines aligned with the bitfields...
> 
> Did you have some reasons for doing it this way?
Yes, I consider it confusing if they are aligned. :-)

> If not, I'd like to see them all lined up (and you can remove one
> tabstop too ;-)
> 
> >+
> >+#define V7M_SCS_SHCSR  IOMEM(0xe000ed24)
> >+#define V7M_SCS_SHCSR_USGFAULTENA              (1 << 18)
> >+#define V7M_SCS_SHCSR_BUSFAULTENA              (1 << 17)
> >+#define V7M_SCS_SHCSR_MEMFAULTENA              (1 << 16)
> >+
> >+#define V7M_xPSR_FPALIGN                       0x00000200
> >+
> >+#define EXC_RET_SBOP                           0xffffffe1
> >+#define EXC_RET_FRAMETYPE_MASK                 0x00000010
> >+#define EXC_RET_FRAMETYPE__BASIC               0x00000010
> >+#define EXC_RET_MODE_MASK                      0x00000008
> >+#define EXC_RET_MODE__HANDLER                  0x00000000
> >+#define EXC_RET_MODE__THREAD                   0x00000008
> >+#define EXC_RET_STACK_MASK                     0x00000004
> >+#define EXC_RET_STACK__MAIN                    0x00000000
> >+#define EXC_RET_STACK__PROCESS                 0x00000004
> 
> I grep'd around the source tree looking for a precedent for this
> double underscore behaviour and couldn't find anything.
> 
> I presume that you're trying to denote that these are values 'served
> by' the mask above?
Yes, that's the motivation.

> I think the double underscore looks weird - made me think it was a
> typo... I think you could safely stick with just one, or if you're
> really concerned about the extra distinction, use
> EXC_RET_STACK_VAL_MAIN etc.
I don't like VAL. (But note I don't really like that double underscore
either.) I'll go with

	#define EXC_RET_FRAMETYPE		0x00000010
	#define EXC_RET_FRAMETYPE_BASIC		0x00000010

in the next iteration. So no suffix means it's a mask and with a suffix
it's the corresponding value. Sounds better?

> >+
> >+#define EXC_RET_HANDLERMODE_MAINSTACK  \
> >+       (EXC_RET_SBOP | EXC_RET_FRAMETYPE__BASIC | EXC_RET_MODE__HANDLER | EXC_RET_STACK__MAIN)
> >+#define EXC_RET_THREADMODE_MAINSTACK   \
> >+       (EXC_RET_SBOP | EXC_RET_FRAMETYPE__BASIC | EXC_RET_MODE__THREAD | EXC_RET_STACK__MAIN)
> 
> Do we ever use these two? I can't find any places where we do in
> uwe/efm32. If not, I think perhaps this is a bit over-engineered...
> If you plan to extend the kernel port in the future to use the extra
> modes, by all means keep them in, but couldn't we just define
> EXC_RET_THREADMODE_PROCESSSTACK? (or even call it
> EXC_RET_THREAD_PROCESS?)
I'd really like to see kernel threads run in priviledged thread mode.
But don't know if we'll come to that point. Dropping them is fine for
now because readding them later when (and if) they are needed won't
create much churn I guess.

> ...
> >--- a/arch/arm/kernel/head-nommu.S
> >+++ b/arch/arm/kernel/head-nommu.S
> >@@ -19,6 +19,7 @@
> >  #include <asm/asm-offsets.h>
> >  #include <asm/cp15.h>
> >  #include <asm/thread_info.h>
> >+#include <asm/v7m.h>
> >
> >  /*
> >   * Kernel startup entry point.
> >@@ -50,10 +51,13 @@ ENTRY(stext)
> >
> >         setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
> >                                                 @ and irqs disabled
> >-#ifndef CONFIG_CPU_CP15
> >-       ldr     r9, =CONFIG_PROCESSOR_ID
> >-#else
> >+#if defined(CONFIG_CPU_CP15)
> >         mrc     p15, 0, r9, c0, c0              @ get processor id
> >+#elif defined(CONFIG_CPU_V7M)
> >+       ldr     r9, =V7M_SCS_CPUID
> 
> If you do choose to rename to CPUID_BASE then fix this up too :)
And if not, I don't :-)

> ...
> >--- a/arch/arm/kernel/traps.c
> >+++ b/arch/arm/kernel/traps.c
> >@@ -819,6 +819,7 @@ static void __init kuser_get_tls_init(unsigned long vectors)
> >
> >  void __init early_trap_init(void *vectors_base)
> >  {
> >+#ifndef CONFIG_CPU_V7M
> 
> I think a comment would be nice, just so as not to scare people who
> expect us to need to copy the vector table somewhere.
> 
> /* V7M allows us to use the vector_table in the kernel image */
> 
> Or similar.
good idea

> ...
> >+__v7m_setup:
> >+       @ Configure the vector table base address
> >+       ldr     r0, =V7M_SCS_VTOR       @ vector table base address
> >+       ldr     r12, =vector_table
> >+       str     r12, [r0]
> >+
> >+       @ enable UsageFault, BusFault and MemManage fault.
> >+       ldr     r5, [r0, #(V7M_SCS_SHCSR - V7M_SCS_VTOR)]
> >+       orr     r5, #(V7M_SCS_SHCSR_USGFAULTENA | V7M_SCS_SHCSR_BUSFAULTENA | V7M_SCS_SHCSR_MEMFAULTENA)
> >+       str     r5, [r0, #(V7M_SCS_SHCSR - V7M_SCS_VTOR)]
> 
> This looks weird and is confusing - it makes it seem like there is
> some relationship between SCS_SHCSR and SCS_VTOR, which there isn't
> at all - the only link is that we just loaded SCS_VTOR in to r0 and
> now we want V7M_SCS_SHCSR - right?
> 
> Why not do the "ldr r0, =V7M_SCS_SHCS"? Is it to save the one
> instruction? Or save an entry in the literal pool?
> 
> I don't think for a single instruction/word it is worth the
> confusing way of writing it...
> 
> But then, perhaps I'm missing something?
I think you don't. As this isn't a hot path the few more bytes probably
don't harm.

> ...
> >+       @ Configure the System Control Register
> 
> Can we be a bit more specific here?
> 
> @Configure the System Control Register to ensure 8-byte stack alignment
> 
> >+       ldr     r0, =V7M_SCS_CCR        @ system control register
> >+       ldr     r12, [r0]
> >+       orr     r12, #V7M_SCS_CCR_STKALIGN
> 
> Whether this bit is RO or RW is implementation defined - sorry I
> didn't notice this with earlier responses...
IIRC 8-byte stack alignment is a requirement of EABI. I didn't find out
why yet, but maybe someone can comment here? Russell? Nico?

Section B1.5.7 of ARMARMv7 specifies that if the bit is RO it is also
RAO. So maybe apart from a comment I think this is fine.

> As we always check the stack alignment on exception entry/return I
> think this isn't an issue - but does leave me asking why we bother
> with this if we always do the check?
I don't know why EABI requires an 8-byte aligned stack. See above.

> >+       str     r12, [r0]
> >+       mov     pc, lr
> >+ENDPROC(__v7m_setup)
> >+
> >+       .align  2
> >+       .type   v7m_processor_functions, #object
> >+ENTRY(v7m_processor_functions)
> >+       .word   nommu_early_abort
> >+       .word   cpu_v7m_proc_init
> >+       .word   cpu_v7m_proc_fin
> >+       .word   cpu_v7m_reset
> >+       .word   cpu_v7m_do_idle
> >+       .word   cpu_v7m_dcache_clean_area
> >+       .word   cpu_v7m_switch_mm
> >+       .word   0                       @ cpu_v7m_set_pte_ext
> 
> The fact that we lack a stub function here will mean that compiling
> with module support won't work.
AFAIK no-MMU and modules is always a problematic combination. We have
the kernel run xip from the efm32's flash at address 0x8c000000 and RAM
starts at 0x88000000. That means that a branch from a module (that lives
in RAM) to core kernel code might well be bigger than possible for a
branch instruction.
 
> Do you expect modules to work?
> If not, can we therefore make V7M and CONFIG_MODULES mutually exclusive.
> If so, we should fix this.
the MODULES symbol is defined in init/Kconfig without any preconditions.
Not sure people would welcome me adding a

	depends !ARM || MMU

there ...

> ...
> >+       /*
> >+        * Match any ARMv7-M processor core.
> >+        */
> >+       .type   __v7m_proc_info, #object
> >+__v7m_proc_info:
> >+       .long   0x000f0000              @ Required ID value
> >+       .long   0x000f0000              @ Mask for ID
> >+       .long   0                       @ proc_info_list.__cpu_mm_mmu_flags
> >+       .long   0                       @ proc_info_list.__cpu_io_mmu_flags
> >+       b       __v7m_setup             @ proc_info_list.__cpu_flush
> >+       .long   cpu_arch_name
> >+       .long   cpu_elf_name
> >+       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
> 
> I don't think M3 has SWP and EDSP...
> 
> based on V7M ARMARM:
> (For SWP)
> "For synchronization, ARMv7-M only supports the byte, halfword, and
> word versions of the load and store exclusive instructions. ARMv7-R
> also supports the doubleword versions of these instructions, and the
> legacy swap instructions"
> (For EDSP)
> None of the instructions listed as coming from the DSP extensions
> are listed in the M3 TRM (eg PKHTB, SXTAB)
Ok. I didn't question these.

Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v9 2/3] ARM: ARMv7-M: Add support for exception handling
  2013-03-21 21:28 ` [PATCH v9 2/3] ARM: ARMv7-M: Add support for exception handling Uwe Kleine-König
@ 2013-03-25 18:50   ` Jonathan Austin
  2013-03-26 10:15     ` Uwe Kleine-König
  0 siblings, 1 reply; 16+ messages in thread
From: Jonathan Austin @ 2013-03-25 18:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi again Uwe,

On 21/03/13 21:28, Uwe Kleine-K?nig wrote:
> This patch implements the exception handling for the ARMv7-M
> architecture (pretty different from the A or R profiles).
>
> It bases on work done earlier by Catalin for 2.6.33 but was nearly
> completely rewritten to use a pt_regs layout compatible to the A
> profile.
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
> ---
> Note there is one open issue in this patch that Jonny raised. He
> wondered if we need a clrex in the return path to user space. I'm not
> sure it's needed as in ARMv7-M, the local monitor is changed to Open
> Access automatically as part of an exception entry or exit sequence.
> For now I think it's not critical and can be addressed later.
>

I'd rather just be sure now what the situation is :)

Before we had three possible return paths, and one didn't have a 'real' 
exception return.

In your latest patches, we always have a proper 'exception return' 
before returning to userspace, so the case I was describing won't arise. 
As you note, A3.4.4 in the V7M ARMARM promises us that the monitor will 
be changed to Open Access by exception entry and exit.

So, I believe we don't need an explicit clrex in the exception return path.

> Changes since v8, sent with
> Message-id: <1358413196-5609-4-git-send-email-u.kleine-koenig@pengutronix.de>:
>
>   - inline v7m_exception_fast_exit
>   - use more symbolic names
>   - use ICSR.RETTOBASE instead of EXC_RET & 8 to determine return mode
>   - don't save EXC_RET to into pt_regs
>   - drop handling of FP extention
> ---
>   arch/arm/kernel/entry-common.S |   4 ++
>   arch/arm/kernel/entry-header.S | 120 ++++++++++++++++++++++++++++++++++
>   arch/arm/kernel/entry-v7m.S    | 142 +++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 266 insertions(+)
>   create mode 100644 arch/arm/kernel/entry-v7m.S
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index 3248cde..c45e002 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -339,6 +339,9 @@ ENDPROC(ftrace_stub)
>
>   	.align	5
>   ENTRY(vector_swi)
> +#ifdef CONFIG_CPU_V7M
> +	v7m_exception_entry
> +#else
>   	sub	sp, sp, #S_FRAME_SIZE
>   	stmia	sp, {r0 - r12}			@ Calling r0 - r12
>    ARM(	add	r8, sp, #S_PC		)
> @@ -349,6 +352,7 @@ ENTRY(vector_swi)
>   	str	lr, [sp, #S_PC]			@ Save calling PC
>   	str	r8, [sp, #S_PSR]		@ Save CPSR
>   	str	r0, [sp, #S_OLD_R0]		@ Save OLD_R0
> +#endif
>   	zero_fp
>
>   	/*
> diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
> index 9a8531e..4caccb4 100644
> --- a/arch/arm/kernel/entry-header.S
> +++ b/arch/arm/kernel/entry-header.S
> @@ -5,6 +5,7 @@
>   #include <asm/asm-offsets.h>
>   #include <asm/errno.h>
>   #include <asm/thread_info.h>
> +#include <asm/v7m.h>
>
>   @ Bad Abort numbers
>   @ -----------------
> @@ -44,6 +45,115 @@
>   #endif
>   	.endm
>
> +#ifdef CONFIG_CPU_V7M
> +/*
> + * ARMv7-M exception entry/exit macros.
> + *
> + * xPSR, ReturnAddress(), LR (R14), R12, R3, R2, R1, and R0 are
> + * automatically saved on the current stack (32 words) before
> + * switching to the exception stack (SP_main).
> + *
> + * If exception is taken while in user mode, SP_main is
> + * empty. Otherwise, SP_main is aligned to 64 bit automatically
> + * (CCR.STKALIGN set).
> + *
> + * Linux assumes that the interrupts are disabled when entering an
> + * exception handler and it may BUG if this is not the case. Interrupts
> + * are disabled during entry and reenabled in the exit macro.
> + *
> + * v7m_exception_slow_exit is used when returning from SVC or PendSV.
> + * When returning to kernel mode, we don't return from exception.
> + */
> +	.macro	v7m_exception_entry
> +	@ determine the location of the registers saved by the core during
> +	@ exception entry. Depending on the mode the cpu was in when the
> +	@ exception happend that is either on the main or the process stack.
> +	@ Bit 2 of EXC_RETURN stored in the lr register specifies which stack
> +	@ was used.
> +	tst	lr, #EXC_RET_STACK_MASK
> +	mrsne	r12, psp
> +	moveq	r12, sp
> +
> +	@ we cannot rely on r0-r3 and r12 matching the value saved in the
> +	@ exception frame because of tail-chaining. So these have to be
> +	@ reloaded.
> +	ldmia	r12!, {r0-r3}
> +
> +	@ Linux expects to have irqs off. Do it here before taking stack space
> +	cpsid	i
> +
> +	sub	sp, #S_FRAME_SIZE-S_IP
> +	stmdb	sp!, {r0-r11}
> +
> +	@ load saved r12, lr, return address and xPSR.
> +	@ r0-r7 are used for signals and never touched from now on. Clobbering
> +	@ r8-r12 is OK.
> +	mov	r9, r12
> +	ldmia	r9!, {r8, r10-r12}
> +
> +	@ calculate the original stack pointer value.
> +	@ r9 currently points to the memory location just above the auto saved
> +	@ xPSR.
> +	@ The cpu might automatically 8-byte align the stack. Bit 9
> +	@ of the saved xPSR specifies if stack aligning took place. In this case
> +	@ another 32-bit value is included in the stack.
> +
> +	tst	r12, V7M_xPSR_FPALIGN

Minor nit, but we should explain the relationship to FP and bit 9 of the 
xPSR if we're going to call it this... (see B1.5.7 --Note--)

Otherwise the casual reader is confused by why FP suddenly ended up in 
here :)

> +	addne	r9, r9, #4
> +
> +	@ store saved r12 using str to have a register to hold the base for stm
> +	str	r8, [sp, #S_IP]
> +	add	r8, sp, #S_SP
> +	@ store r13-r15, xPSR
> +	stmia	r8!, {r9-r12}
> +	@ store old_r0
> +	str	r0, [r8]
> +	.endm
> +
> +
> +/*
> + * We won't return to kernel space here because a kernel thread runs in SVCALL
> + * context and so cannot be preempted by PENDSV.
> + */

The reason we can't return to kernel space isn't the context we're in, 
but rather the priority we set for the exceptions... (both at the same 
priority => can't preempt each other)

> +	.macro	v7m_exception_slow_exit ret_r0
> +	cpsid	i
> +	ldr	lr, =EXC_RET_THREADMODE_PROCESSSTACK
> +
> +	@ read original r12, sp, lr, pc and xPSR
> +	add	r12, sp, #S_IP
> +	ldmia	r12, {r1-r5}
> +
> +	@ an exception frame is always 8-byte aligned. To tell the hardware if
> +	@ the sp to be restored is aligned or not set bit 9 of the saved xPSR
> +	@ accordingly.

Does this comment make sense? I can't make much of it, because it says 
that the exception frame is always 8-byte aligned by then checks to see 
if it is...

> +	tst	r2, #4
> +	subne	r2, r2, #4
> +	orrne	r5, V7M_xPSR_FPALIGN
> +	biceq	r5, V7M_xPSR_FPALIGN
> +

As we've discussed a bit already on IRC, I don't think we need to test 
the stack pointer here and modify r5, we should be able to use the saved 
xPSR value. This is a pretty hot path and I think we're better tp have 
fewer instructions!

As far as I can see, if sp's alignment here is different to what it was 
when we took the exception, we either have a bug (some code hasn't 
respected the stack), or someone's interfered externally and is about to 
cause a bug.

What use cases do you think we are adding this test for? If it is just 
people manually modifying sp with debuggers then I'd really rather not 
have it.

> +	@ write basic exception frame
> +	stmdb	r2!, {r1, r3-r5}
> +	ldmia	sp, {r1, r3-r5}
> +	.if	\ret_r0
> +	stmdb	r2!, {r0, r3-r5}
> +	.else
> +	stmdb	r2!, {r1, r3-r5}
> +	.endif
> +
> +	@ restore process sp
> +	msr	psp, r2
> +
> +	@ restore original r4-r11
> +	ldmia	sp!, {r0-r11}
> +
> +	@ restore main sp
> +	add	sp, sp, #S_FRAME_SIZE-S_IP
> +
> +	cpsie	i
> +	bx	lr
> +	.endm
> +#endif	/* CONFIG_CPU_V7M */
> +
>   	@
>   	@ Store/load the USER SP and LR registers by switching to the SYS
>   	@ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not
> @@ -131,6 +241,15 @@
>   	rfeia	sp!
>   	.endm
>
> +#ifdef CONFIG_CPU_V7M
> +	.macro	restore_user_regs, fast = 0, offset = 0
> +	@ XXX: clrex?

As we've discussed, above, I don't think this is required... It is also 
fine to have it, but definitely remove the @XXX before putting in next.

Also perhaps replace this XXX comment with one explaining that exception 
return guarantees the monitor is cleared? Otherwise someone reading the 
code and comparing V7M with V7 might wonder where the clrex went.

> +	.if	\offset
> +	add	sp, #\offset
> +	.endif
> +	v7m_exception_slow_exit ret_r0 = \fast
> +	.endm
> +#else	/* ifdef CONFIG_CPU_V7M */
>   	.macro	restore_user_regs, fast = 0, offset = 0
>   	clrex					@ clear the exclusive monitor
>   	mov	r2, sp
> @@ -147,6 +266,7 @@
>   	add	sp, sp, #S_FRAME_SIZE - S_SP
>   	movs	pc, lr				@ return & move spsr_svc into cpsr
>   	.endm
> +#endif	/* ifdef CONFIG_CPU_V7M / else */
>
>   	.macro	get_thread_info, rd
>   	mov	\rd, sp
> diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
> new file mode 100644
> index 0000000..9518c96
> --- /dev/null
> +++ b/arch/arm/kernel/entry-v7m.S
> @@ -0,0 +1,142 @@
> +/*
> + * linux/arch/arm/kernel/entry-v7m.S
> + *
> + * Copyright (C) 2008 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Low-level vector interface routines for the ARMv7-M architecture
> + */
> +#include <asm/memory.h>
> +#include <asm/glue.h>
> +#include <asm/thread_notify.h>
> +#include <asm/v7m.h>
> +
> +#include <mach/entry-macro.S>
> +
> +#include "entry-header.S"
> +
> +#ifdef CONFIG_TRACE_IRQFLAGS
> +#error "CONFIG_TRACE_IRQFLAGS not supported on the current ARMv7M implementation"
> +#endif
> +
> +__invalid_entry:
> +	v7m_exception_entry
> +	adr	r0, strerr
> +	mrs	r1, ipsr
> +	mov	r2, lr
> +	bl	printk
> +	mov	r0, sp
> +	bl	show_regs
> +1:	b	1b
> +ENDPROC(__invalid_entry)
> +
> +strerr:	.asciz	"\nUnhandled exception: IPSR = %08lx LR = %08lx\n"
> +
> +	.align	2
> +__irq_entry:
> +	v7m_exception_entry
> +
> +	@
> +	@ Invoke the IRQ handler
> +	@
> +	mrs	r0, ipsr
> +	ldr	r1, =0x1ff

Did this mask not get defined in v7m.h for a reason?

> +	and	r0, r1
> +	mov	r1, sp
> +	stmdb	sp!, {lr}
> +	@ routine called with r0 = irq number, r1 = struct pt_regs *
> +	bl	asm_do_IRQ
> +
> +	pop	{lr}
> +	@
> +	@ Check for any pending work if returning to user
> +	@
> +	ldr	r1, =V7M_SCS_ICSR
> +	ldr	r0, [r1]
> +	tst	r0, V7M_SCS_ICSR_RETTOBASE
> +	beq	2f
> +
> +	get_thread_info tsk
> +	ldr	r2, [tsk, #TI_FLAGS]
> +	tst	r2, #_TIF_WORK_MASK
> +	beq	2f			@ no work pending
> +	mov	r0, #V7M_SCS_ICSR_PENDSVSET
> +	str	r0, [r1]		@ raise PendSV
> +
> +2:
> +	@ registers r0-r3 and r12 are automatically restored on exception
> +	@ return. r4-r7 were not clobbered in v7m_exception_entry so for
> +	@ correctness they don't need to be restored. So only r8-r11 must be
> +	@ restored here. The easiest way to do so is to restore r0-r7, too.
> +	ldmia	sp!, {r0-r11}
> +	add	sp, #S_FRAME_SIZE-S_IP
> +	cpsie	i
> +	bx	lr
> +ENDPROC(__irq_entry)
> +
> +__pendsv_entry:
> +	v7m_exception_entry
> +
> +	ldr	r1, =V7M_SCS_ICSR
> +	mov	r0, #V7M_SCS_ICSR_PENDSVCLR
> +	str	r0, [r1]		@ clear PendSV
> +
> +	@ execute the pending work, including reschedule
> +	get_thread_info tsk
> +	mov	why, #0
> +	b	ret_to_user
> +ENDPROC(__pendsv_entry)
> +
> +/*
> + * Register switch for ARMv7-M processors.
> + * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
> + * previous and next are guaranteed not to be the same.
> + */
> +ENTRY(__switch_to)
> +	.fnstart
> +	.cantunwind
> +	add	ip, r1, #TI_CPU_SAVE
> +	stmia	ip!, {r4 - r11}		@ Store most regs on stack
> +	str	sp, [ip], #4
> +	str	lr, [ip], #4
> +	mov	r5, r0
> +	add	r4, r2, #TI_CPU_SAVE
> +	ldr	r0, =thread_notify_head
> +	mov	r1, #THREAD_NOTIFY_SWITCH
> +	bl	atomic_notifier_call_chain
> +	mov	ip, r4
> +	mov	r0, r5
> +	ldmia	ip!, {r4 - r11}		@ Load all regs saved previously
> +	ldr	sp, [ip]
> +	ldr	pc, [ip, #4]!
> +	.fnend
> +ENDPROC(__switch_to)
> +
> +	.data
> +	.align	8
> +/*
> + * Vector table (64 words => 256 bytes natural alignment)
> + */
> +ENTRY(vector_table)
> +	.long	0			@ 0 - Reset stack pointer
> +	.long	__invalid_entry		@ 1 - Reset
> +	.long	__invalid_entry		@ 2 - NMI
> +	.long	__invalid_entry		@ 3 - HardFault
> +	.long	__invalid_entry		@ 4 - MemManage
> +	.long	__invalid_entry		@ 5 - BusFault
> +	.long	__invalid_entry		@ 6 - UsageFault
> +	.long	__invalid_entry		@ 7 - Reserved
> +	.long	__invalid_entry		@ 8 - Reserved
> +	.long	__invalid_entry		@ 9 - Reserved
> +	.long	__invalid_entry		@ 10 - Reserved
> +	.long	vector_swi		@ 11 - SVCall
> +	.long	__invalid_entry		@ 12 - Debug Monitor
> +	.long	__invalid_entry		@ 13 - Reserved
> +	.long	__pendsv_entry		@ 14 - PendSV
> +	.long	__invalid_entry		@ 15 - SysTick
> +	.rept	64 - 16
> +	.long	__irq_entry		@ 16..64 - External Interrupts
> +	.endr
>

Thanks,

Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v9 2/3] ARM: ARMv7-M: Add support for exception handling
  2013-03-25 18:50   ` Jonathan Austin
@ 2013-03-26 10:15     ` Uwe Kleine-König
  2013-03-26 11:56       ` Jonathan Austin
  0 siblings, 1 reply; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-26 10:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jonny,

On Mon, Mar 25, 2013 at 06:50:43PM +0000, Jonathan Austin wrote:
> On 21/03/13 21:28, Uwe Kleine-K?nig wrote:
> >This patch implements the exception handling for the ARMv7-M
> >architecture (pretty different from the A or R profiles).
> >
> >It bases on work done earlier by Catalin for 2.6.33 but was nearly
> >completely rewritten to use a pt_regs layout compatible to the A
> >profile.
> >
> >Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> >Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
> >---
> >Note there is one open issue in this patch that Jonny raised. He
> >wondered if we need a clrex in the return path to user space. I'm not
> >sure it's needed as in ARMv7-M, the local monitor is changed to Open
> >Access automatically as part of an exception entry or exit sequence.
> >For now I think it's not critical and can be addressed later.
> >
> 
> I'd rather just be sure now what the situation is :)
> 
> Before we had three possible return paths, and one didn't have a
> 'real' exception return.
> 
> In your latest patches, we always have a proper 'exception return'
> before returning to userspace, so the case I was describing won't
> arise. As you note, A3.4.4 in the V7M ARMARM promises us that the
> monitor will be changed to Open Access by exception entry and exit.
> 
> So, I believe we don't need an explicit clrex in the exception return path.
ok, will drop it now that we agree.

> ...
> >+#ifdef CONFIG_CPU_V7M
> >+/*
> >+ * ARMv7-M exception entry/exit macros.
> >+ *
> >+ * xPSR, ReturnAddress(), LR (R14), R12, R3, R2, R1, and R0 are
> >+ * automatically saved on the current stack (32 words) before
> >+ * switching to the exception stack (SP_main).
> >+ *
> >+ * If exception is taken while in user mode, SP_main is
> >+ * empty. Otherwise, SP_main is aligned to 64 bit automatically
> >+ * (CCR.STKALIGN set).
> >+ *
> >+ * Linux assumes that the interrupts are disabled when entering an
> >+ * exception handler and it may BUG if this is not the case. Interrupts
> >+ * are disabled during entry and reenabled in the exit macro.
> >+ *
> >+ * v7m_exception_slow_exit is used when returning from SVC or PendSV.
> >+ * When returning to kernel mode, we don't return from exception.
> >+ */
> >+	.macro	v7m_exception_entry
> >+	@ determine the location of the registers saved by the core during
> >+	@ exception entry. Depending on the mode the cpu was in when the
> >+	@ exception happend that is either on the main or the process stack.
> >+	@ Bit 2 of EXC_RETURN stored in the lr register specifies which stack
> >+	@ was used.
> >+	tst	lr, #EXC_RET_STACK_MASK
> >+	mrsne	r12, psp
> >+	moveq	r12, sp
> >+
> >+	@ we cannot rely on r0-r3 and r12 matching the value saved in the
> >+	@ exception frame because of tail-chaining. So these have to be
> >+	@ reloaded.
> >+	ldmia	r12!, {r0-r3}
> >+
> >+	@ Linux expects to have irqs off. Do it here before taking stack space
> >+	cpsid	i
> >+
> >+	sub	sp, #S_FRAME_SIZE-S_IP
> >+	stmdb	sp!, {r0-r11}
> >+
> >+	@ load saved r12, lr, return address and xPSR.
> >+	@ r0-r7 are used for signals and never touched from now on. Clobbering
> >+	@ r8-r12 is OK.
> >+	mov	r9, r12
> >+	ldmia	r9!, {r8, r10-r12}
> >+
> >+	@ calculate the original stack pointer value.
> >+	@ r9 currently points to the memory location just above the auto saved
> >+	@ xPSR.
> >+	@ The cpu might automatically 8-byte align the stack. Bit 9
> >+	@ of the saved xPSR specifies if stack aligning took place. In this case
> >+	@ another 32-bit value is included in the stack.
> >+
> >+	tst	r12, V7M_xPSR_FPALIGN
> 
> Minor nit, but we should explain the relationship to FP and bit 9 of
> the xPSR if we're going to call it this... (see B1.5.7 --Note--)
This doesn't have anything to do with FP as in floating point. In
ARMARMv7M I didn't fine a mnemonic for this bit, so I used FPALIGN
modelled after the variable "frameptralign" in the PushStack()
pseudocode function. Maybe better use V7M_xPSR_FRAMEPTRALIGN? Or does
there exist an official name that I just didn't manage to find?

> Otherwise the casual reader is confused by why FP suddenly ended up
> in here :)
> 
> >+	addne	r9, r9, #4
> >+
> >+	@ store saved r12 using str to have a register to hold the base for stm
> >+	str	r8, [sp, #S_IP]
> >+	add	r8, sp, #S_SP
> >+	@ store r13-r15, xPSR
> >+	stmia	r8!, {r9-r12}
> >+	@ store old_r0
> >+	str	r0, [r8]
> >+	.endm
> >+
> >+
> >+/*
> >+ * We won't return to kernel space here because a kernel thread runs in SVCALL
> >+ * context and so cannot be preempted by PENDSV.
> >+ */
> 
> The reason we can't return to kernel space isn't the context we're
> in, but rather the priority we set for the exceptions... (both at
> the same priority => can't preempt each other)
Well, it's both isn't it? A kernel thread has execution priority of
SVCALL. As PENDSV and SVCALL are configured to the same priority a
kernel thread is never preempted. I'll make it:

	/*
	 * PENDSV and SVCALL have the same exception priorities. As a
	 * kernel thread runs at SVCALL execution priority it can never
	 * be preempted and so we will never have to return to a kernel
	 * thread here.
	 */
	
Better?

> >+	.macro	v7m_exception_slow_exit ret_r0
> >+	cpsid	i
> >+	ldr	lr, =EXC_RET_THREADMODE_PROCESSSTACK
> >+
> >+	@ read original r12, sp, lr, pc and xPSR
> >+	add	r12, sp, #S_IP
> >+	ldmia	r12, {r1-r5}
> >+
> >+	@ an exception frame is always 8-byte aligned. To tell the hardware if
> >+	@ the sp to be restored is aligned or not set bit 9 of the saved xPSR
> >+	@ accordingly.
> 
> Does this comment make sense? I can't make much of it, because it
> says that the exception frame is always 8-byte aligned by then
> checks to see if it is...
The exception frame must be aligned, the restored value of sp not
necessarily. Depending on bit 9 of the xPSR saved in the exception frame
sp is restored to point to either directly over the exception frame or
if there is an additional reserved word. See B1.5.7.

> >+	tst	r2, #4
> >+	subne	r2, r2, #4
> >+	orrne	r5, V7M_xPSR_FPALIGN
> >+	biceq	r5, V7M_xPSR_FPALIGN
> >+
> 
> As we've discussed a bit already on IRC, I don't think we need to
> test the stack pointer here and modify r5, we should be able to use
> the saved xPSR value. This is a pretty hot path and I think we're
> better tp have fewer instructions!
> 
> As far as I can see, if sp's alignment here is different to what it
> was when we took the exception, we either have a bug (some code
> hasn't respected the stack), or someone's interfered externally and
> is about to cause a bug.
> 
> What use cases do you think we are adding this test for? If it is
> just people manually modifying sp with debuggers then I'd really
> rather not have it.
I don't really have a scenario in mind that makes this fix here
necessary. It's more that I think the two instructions are cheap enough
to stick to a defensive coding style.
 
> ...
> >+#ifdef CONFIG_CPU_V7M
> >+	.macro	restore_user_regs, fast = 0, offset = 0
> >+	@ XXX: clrex?
> 
> As we've discussed, above, I don't think this is required... It is
> also fine to have it, but definitely remove the @XXX before putting
> in next.
> 
> Also perhaps replace this XXX comment with one explaining that
> exception return guarantees the monitor is cleared? Otherwise
> someone reading the code and comparing V7M with V7 might wonder
> where the clrex went.
ack

> ...
> >+	.align	2
> >+__irq_entry:
> >+	v7m_exception_entry
> >+
> >+	@
> >+	@ Invoke the IRQ handler
> >+	@
> >+	mrs	r0, ipsr
> >+	ldr	r1, =0x1ff
> 
> Did this mask not get defined in v7m.h for a reason?
Yeah, the reason is I missed it :-) Will fix that for the next
iteration.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v9 2/3] ARM: ARMv7-M: Add support for exception handling
  2013-03-26 10:15     ` Uwe Kleine-König
@ 2013-03-26 11:56       ` Jonathan Austin
  0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Austin @ 2013-03-26 11:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

On 26/03/13 10:15, Uwe Kleine-K?nig wrote:
> Hi Jonny,
>
> On Mon, Mar 25, 2013 at 06:50:43PM +0000, Jonathan Austin wrote:
>> On 21/03/13 21:28, Uwe Kleine-K?nig wrote:
>>> This patch implements the exception handling for the ARMv7-M
>>> architecture (pretty different from the A or R profiles).
>>>
[...]
>>> +	ldmia	r9!, {r8, r10-r12}
>>> +
>>> +	@ calculate the original stack pointer value.
>>> +	@ r9 currently points to the memory location just above the auto saved
>>> +	@ xPSR.
>>> +	@ The cpu might automatically 8-byte align the stack. Bit 9
>>> +	@ of the saved xPSR specifies if stack aligning took place. In this case
>>> +	@ another 32-bit value is included in the stack.
>>> +
>>> +	tst	r12, V7M_xPSR_FPALIGN
>>
>> Minor nit, but we should explain the relationship to FP and bit 9 of
>> the xPSR if we're going to call it this... (see B1.5.7 --Note--)
> This doesn't have anything to do with FP as in floating point. In
> ARMARMv7M I didn't fine a mnemonic for this bit, so I used FPALIGN
> modelled after the variable "frameptralign" in the PushStack()
> pseudocode function. Maybe better use V7M_xPSR_FRAMEPTRALIGN? Or does
> there exist an official name that I just didn't manage to find?

Heh, I read this
"On an implementation that includes the FP extension, if software 
enables automatic FP state preservation on exception entry, that state 
preservation enforces 8-byte stack alignment, ignoring the CCR.STKALIGN
bit value"

and assumed you had said "Floating point stack saving guarantees 8-byte 
alignment so when it is 8-byte aligned it is like the floating-point 
case" :)

So, I'd definitely use FRAMEPTRALIGN!


>
>> Otherwise the casual reader is confused by why FP suddenly ended up
>> in here :)
>>
>>> +	addne	r9, r9, #4
>>> +
>>> +	@ store saved r12 using str to have a register to hold the base for stm
>>> +	str	r8, [sp, #S_IP]
>>> +	add	r8, sp, #S_SP
>>> +	@ store r13-r15, xPSR
>>> +	stmia	r8!, {r9-r12}
>>> +	@ store old_r0
>>> +	str	r0, [r8]
>>> +	.endm
>>> +
>>> +
>>> +/*
>>> + * We won't return to kernel space here because a kernel thread runs in SVCALL
>>> + * context and so cannot be preempted by PENDSV.
>>> + */
>>
>> The reason we can't return to kernel space isn't the context we're
>> in, but rather the priority we set for the exceptions... (both at
>> the same priority => can't preempt each other)
> Well, it's both isn't it? A kernel thread has execution priority of
> SVCALL. As PENDSV and SVCALL are configured to the same priority a
> kernel thread is never preempted. I'll make it:
>
> 	/*
> 	 * PENDSV and SVCALL have the same exception priorities. As a
> 	 * kernel thread runs at SVCALL execution priority it can never
> 	 * be preempted and so we will never have to return to a kernel
> 	 * thread here.
> 	 */
> 	
> Better?

Yea, perhaps just tweak to add that we *control* the priorities - IE it 
is us that have set them to be the same...

>
>>> +	.macro	v7m_exception_slow_exit ret_r0
>>> +	cpsid	i
>>> +	ldr	lr, =EXC_RET_THREADMODE_PROCESSSTACK
>>> +
>>> +	@ read original r12, sp, lr, pc and xPSR
>>> +	add	r12, sp, #S_IP
>>> +	ldmia	r12, {r1-r5}
>>> +
>>> +	@ an exception frame is always 8-byte aligned. To tell the hardware if
>>> +	@ the sp to be restored is aligned or not set bit 9 of the saved xPSR
>>> +	@ accordingly.
>>
>> Does this comment make sense? I can't make much of it, because it
>> says that the exception frame is always 8-byte aligned by then
>> checks to see if it is...
> The exception frame must be aligned, the restored value of sp not
> necessarily. Depending on bit 9 of the xPSR saved in the exception frame
> sp is restored to point to either directly over the exception frame or
> if there is an additional reserved word. See B1.5.7.
>

Yea, that full explanation is better.
The ARM ARM has quite a clear description, actually:

On an exception return when CCR.STKALIGN is set to 1, the processor uses 
the value of bit [9] of the PSR value popped from the stack to determine 
whether it must adjust the stack pointer alignment. This reverses any 
forced stack alignment performed on the exception entry.

Something of that going in to your comment would be good.

>>> +	tst	r2, #4
>>> +	subne	r2, r2, #4
>>> +	orrne	r5, V7M_xPSR_FPALIGN
>>> +	biceq	r5, V7M_xPSR_FPALIGN
>>> +
>>
>> As we've discussed a bit already on IRC, I don't think we need to
>> test the stack pointer here and modify r5, we should be able to use
>> the saved xPSR value. This is a pretty hot path and I think we're
>> better tp have fewer instructions!
>>
>> As far as I can see, if sp's alignment here is different to what it
>> was when we took the exception, we either have a bug (some code
>> hasn't respected the stack), or someone's interfered externally and
>> is about to cause a bug.
>>
>> What use cases do you think we are adding this test for? If it is
>> just people manually modifying sp with debuggers then I'd really
>> rather not have it.
> I don't really have a scenario in mind that makes this fix here
> necessary. It's more that I think the two instructions are cheap enough
> to stick to a defensive coding style.

I've just talked through this with Catalin in detail. If we don't modify 
r5 we can just bic r2 in order to ensure alignment (either it was 
aligned before, the bic does nothing and r5 is already correct, or it 
wasn't aligned before, we make it aligned and r5 is also still correct)

Does that seem right to you? It still gives you the chance to have the 
sp modified by some debug stuff, but assumes that nothing will modify 
the saved version of xPSR on the stack, which I think is a safe assumption.

>
>> ...
>>> +#ifdef CONFIG_CPU_V7M
>>> +	.macro	restore_user_regs, fast = 0, offset = 0
>>> +	@ XXX: clrex?
>>
>> As we've discussed, above, I don't think this is required... It is
>> also fine to have it, but definitely remove the @XXX before putting
>> in next.
>>
>> Also perhaps replace this XXX comment with one explaining that
>> exception return guarantees the monitor is cleared? Otherwise
>> someone reading the code and comparing V7M with V7 might wonder
>> where the clrex went.
> ack
>
>> ...
>>> +	.align	2
>>> +__irq_entry:
>>> +	v7m_exception_entry
>>> +
>>> +	@
>>> +	@ Invoke the IRQ handler
>>> +	@
>>> +	mrs	r0, ipsr
>>> +	ldr	r1, =0x1ff
>>
>> Did this mask not get defined in v7m.h for a reason?
> Yeah, the reason is I missed it :-) Will fix that for the next
> iteration.
>

Cool - looking forward to it...

Thanks,
Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v9 3/3] ARM: ARMv7-M: Allow the building of new kernel port
  2013-03-21 21:28 ` [PATCH v9 3/3] ARM: ARMv7-M: Allow the building of new kernel port Uwe Kleine-König
@ 2013-03-27 10:37   ` Jonathan Austin
  2013-03-27 10:58     ` Uwe Kleine-König
  0 siblings, 1 reply; 16+ messages in thread
From: Jonathan Austin @ 2013-03-27 10:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

Just a few comments below,

On 21/03/13 21:28, Uwe Kleine-K?nig wrote:
> This patch modifies the required Kconfig and Makefile files to allow the
> building of kernel for Cortex-M3.
>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
> ---
>   arch/arm/Kconfig         |  4 ++--
>   arch/arm/Kconfig-nommu   |  2 +-
>   arch/arm/Makefile        |  1 +
>   arch/arm/kernel/Makefile |  8 +++++++-
>   arch/arm/mm/Kconfig      | 22 +++++++++++++++++++++-
>   arch/arm/mm/Makefile     |  2 ++
>   6 files changed, 34 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index dedf02b..7c8c607 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -9,7 +9,7 @@ config ARM
>   	select BUILDTIME_EXTABLE_SORT if MMU
>   	select CPU_PM if (SUSPEND || CPU_IDLE)
>   	select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN && MMU
> -	select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
> +	select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
>   	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
>   	select GENERIC_IRQ_PROBE
>   	select GENERIC_IRQ_SHOW
> @@ -1685,7 +1685,7 @@ config SCHED_HRTICK
>
>   config THUMB2_KERNEL
>   	bool "Compile the kernel in Thumb-2 mode" if !CPU_THUMBONLY
> -	depends on CPU_V7 && !CPU_V6 && !CPU_V6K
> +	depends on (CPU_V7 || CPU_V7M) && !CPU_V6 && !CPU_V6K
>   	default y if CPU_THUMBONLY
>   	select AEABI
>   	select ARM_ASM_UNIFIED
> diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
> index 2cef8e1..c859495 100644
> --- a/arch/arm/Kconfig-nommu
> +++ b/arch/arm/Kconfig-nommu
> @@ -28,7 +28,7 @@ config FLASH_SIZE
>   config PROCESSOR_ID
>   	hex 'Hard wire the processor ID'
>   	default 0x00007700
> -	depends on !CPU_CP15
> +	depends on !(CPU_CP15 || CPU_V7M)
>   	help
>   	  If processor has no CP15 register, this processor ID is
>   	  used instead of the auto-probing which utilizes the register.
> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> index ee4605f..f11b8da 100644
> --- a/arch/arm/Makefile
> +++ b/arch/arm/Makefile
> @@ -59,6 +59,7 @@ comma = ,
>   # Note that GCC does not numerically define an architecture version
>   # macro, but instead defines a whole series of macros which makes
>   # testing for a specific architecture or later rather impossible.
> +arch-$(CONFIG_CPU_32v7M)	:=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
>   arch-$(CONFIG_CPU_32v7)		:=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
>   arch-$(CONFIG_CPU_32v6)		:=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
>   # Only override the compiler option if ARMv6. The ARMv6K extensions are
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index 5f3338e..00d703c 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -15,7 +15,7 @@ CFLAGS_REMOVE_return_address.o = -pg
>
>   # Object file lists.
>
> -obj-y		:= elf.o entry-armv.o entry-common.o irq.o opcodes.o \
> +obj-y		:= elf.o entry-common.o irq.o opcodes.o \
>   		   process.o ptrace.o return_address.o sched_clock.o \
>   		   setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
>
> @@ -23,6 +23,12 @@ obj-$(CONFIG_ATAGS)		+= atags_parse.o
>   obj-$(CONFIG_ATAGS_PROC)	+= atags_proc.o
>   obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
>
> +ifeq ($(CONFIG_CPU_V7M),y)
> +obj-y		+= entry-v7m.o
> +else
> +obj-y		+= entry-armv.o
> +endif
> +
>   obj-$(CONFIG_OC_ETM)		+= etm.o
>   obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
>   obj-$(CONFIG_ISA_DMA_API)	+= dma.o
> diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
> index cb812a1..9c3eac4 100644
> --- a/arch/arm/mm/Kconfig
> +++ b/arch/arm/mm/Kconfig
> @@ -397,6 +397,16 @@ config CPU_V7
>   	select CPU_PABRT_V7
>   	select CPU_TLB_V7 if MMU
>
> +# ARMv7M
> +config CPU_V7M
> +	bool
> +	select CPU_32v7M
> +	select CPU_ABRT_NOMMU
> +	select CPU_CACHE_NOP
> +	select CPU_CACHE_VIPT

What's the deal with VIPT here? I presume something left over?

> +	select CPU_PABRT_LEGACY
> +	select CPU_THUMBONLY
> +
>   config CPU_THUMBONLY
>   	bool
>   	# There are no CPUs available with MMU that don't implement an ARM ISA:
> @@ -441,6 +451,9 @@ config CPU_32v6K
>   config CPU_32v7
>   	bool
>
> +config CPU_32v7M
> +	bool
> +

What is this config option for?

>   # The abort model
>   config CPU_ABRT_NOMMU
>   	bool
> @@ -494,6 +507,9 @@ config CPU_CACHE_V6
>   config CPU_CACHE_V7
>   	bool
>
> +config CPU_CACHE_NOP
> +	bool
> +
>   config CPU_CACHE_VIVT
>   	bool
>
> @@ -616,7 +632,11 @@ config ARCH_DMA_ADDR_T_64BIT
>
>   config ARM_THUMB
>   	bool "Support Thumb user binaries" if !CPU_THUMBONLY
> -	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || CPU_V7 || CPU_FEROCEON
> +	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || \
> +		CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || \
> +		CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || \
> +		CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || \
> +		CPU_V7 || CPU_FEROCEON || CPU_V7M

It looks like there has been a rough attempt to order this list...

Can V7M go before FEROCEON please?

>   	default y
>   	help
>   	  Say Y if you want to include kernel support for running user space
> diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
> index 4e333fa..317b575 100644
> --- a/arch/arm/mm/Makefile
> +++ b/arch/arm/mm/Makefile
> @@ -40,6 +40,7 @@ obj-$(CONFIG_CPU_CACHE_V4WB)	+= cache-v4wb.o
>   obj-$(CONFIG_CPU_CACHE_V6)	+= cache-v6.o
>   obj-$(CONFIG_CPU_CACHE_V7)	+= cache-v7.o
>   obj-$(CONFIG_CPU_CACHE_FA)	+= cache-fa.o
> +obj-$(CONFIG_CPU_CACHE_NOP)	+= cache-nop.o
>
>   AFLAGS_cache-v6.o	:=-Wa,-march=armv6
>   AFLAGS_cache-v7.o	:=-Wa,-march=armv7-a
> @@ -88,6 +89,7 @@ obj-$(CONFIG_CPU_FEROCEON)	+= proc-feroceon.o
>   obj-$(CONFIG_CPU_V6)		+= proc-v6.o
>   obj-$(CONFIG_CPU_V6K)		+= proc-v6.o
>   obj-$(CONFIG_CPU_V7)		+= proc-v7.o
> +obj-$(CONFIG_CPU_V7M)		+= proc-v7m.o
>
>   AFLAGS_proc-v6.o	:=-Wa,-march=armv6
>   AFLAGS_proc-v7.o	:=-Wa,-march=armv7-a
>

Thanks!

Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v10 0/3] ARM: ARMv7-M (i.e. Cortex-M3) support
  2013-03-21 21:28 [PATCH v9 0/3] ARM: ARMv7 (i.e. Cortex-M3) support Uwe Kleine-König
                   ` (2 preceding siblings ...)
  2013-03-21 21:28 ` [PATCH v9 3/3] ARM: ARMv7-M: Allow the building of new kernel port Uwe Kleine-König
@ 2013-03-27 10:54 ` Uwe Kleine-König
  2013-03-27 10:54   ` [PATCH v10 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
                     ` (2 more replies)
  3 siblings, 3 replies; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-27 10:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

this is the next iteration of the Cortex-M3 support series. This reroll
addresses Jonny's comments. The only thing that I didn't take (I think)
is the sp alignment stuff on exception return. The facts are described
below, I'd be happy to read a few more thoughts on it.

This series still bases on the same commit as before, i.e. Russell's
devel-stable at that time.

I updated my tree

	git://git.pengutronix.de/git/ukl/linux.git efm32

to be based on this version of the patch set.

Now about the sp alignment during exception entry/return:

When an exception occurs the currently used stack pointer is 8-byte
aligned and than an exception frame is written to the stack. Depending
on sp being already aligned or not a bit is set in the exception frame
or not. On exception return this effect is reversed by the hardware,
i.e. if the bit is set in the frame it adds 4 to sp.

Now Jonny argues that there is no need to recheck if I need
to set or clear the bit on exception return because the hardware did it
right on exception entry. While this saves some overhead (three
instructions) during exception return it feels wrong (IMHO) because then
sp isn't necessarily restored to the value saved in pt_regs but to

	(pt_regs.sp & ~4) | (sp_on_exceptionentry & 4)

I think in practise there isn't any difference, but I claim to know all
ways how pt_regs.sp could change. So I prefer to recheck if I need to
set this bit or not to get more robust and maximally correct code.

The bit in question is saved to the xPSR value but this location is
reserved in the actual register. That means that this bit is never
really set in xPSR and is only valid in the exception frame. That made
me wonder if the cleanest approach is to even clear the bit in pt_regs
(and then necessarily recalculate it on exception return).

What do you think?

Best regards
Uwe


Catalin Marinas (1):
  ARM: Add base support for ARMv7-M

Uwe Kleine-K?nig (2):
  ARM: ARMv7-M: Add support for exception handling
  ARM: ARMv7-M: Allow the building of new kernel port

 arch/arm/Kconfig                   |   4 +-
 arch/arm/Kconfig-nommu             |   2 +-
 arch/arm/Makefile                  |   1 +
 arch/arm/include/asm/assembler.h   |  17 +++-
 arch/arm/include/asm/cputype.h     |  12 ++-
 arch/arm/include/asm/glue-cache.h  |  27 ++++++
 arch/arm/include/asm/glue-df.h     |   8 ++
 arch/arm/include/asm/glue-proc.h   |   9 ++
 arch/arm/include/asm/irqflags.h    |  22 +++--
 arch/arm/include/asm/ptrace.h      |   4 +
 arch/arm/include/asm/system_info.h |   1 +
 arch/arm/include/asm/v7m.h         |  44 ++++++++++
 arch/arm/include/uapi/asm/ptrace.h |  35 ++++++--
 arch/arm/kernel/Makefile           |   8 +-
 arch/arm/kernel/entry-common.S     |   4 +
 arch/arm/kernel/entry-header.S     | 124 ++++++++++++++++++++++++++++
 arch/arm/kernel/entry-v7m.S        | 142 +++++++++++++++++++++++++++++++
 arch/arm/kernel/head-nommu.S       |  10 ++-
 arch/arm/kernel/setup.c            |  17 +++-
 arch/arm/kernel/traps.c            |   8 ++
 arch/arm/mm/Kconfig                |  21 ++++-
 arch/arm/mm/Makefile               |   2 +
 arch/arm/mm/cache-nop.S            |  53 ++++++++++++
 arch/arm/mm/nommu.c                |   7 ++
 arch/arm/mm/proc-v7m.S             | 165 +++++++++++++++++++++++++++++++++++++
 25 files changed, 721 insertions(+), 26 deletions(-)
 create mode 100644 arch/arm/include/asm/v7m.h
 create mode 100644 arch/arm/kernel/entry-v7m.S
 create mode 100644 arch/arm/mm/cache-nop.S
 create mode 100644 arch/arm/mm/proc-v7m.S

-- 
1.8.2.rc2

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v10 1/3] ARM: Add base support for ARMv7-M
  2013-03-27 10:54 ` [PATCH v10 0/3] ARM: ARMv7-M (i.e. Cortex-M3) support Uwe Kleine-König
@ 2013-03-27 10:54   ` Uwe Kleine-König
  2013-04-12 16:25     ` Jonathan Austin
  2013-03-27 10:54   ` [PATCH v10 2/3] ARM: ARMv7-M: Add support for exception handling Uwe Kleine-König
  2013-03-27 10:54   ` [PATCH v10 3/3] ARM: ARMv7-M: Allow the building of new kernel port Uwe Kleine-König
  2 siblings, 1 reply; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-27 10:54 UTC (permalink / raw)
  To: linux-arm-kernel

From: Catalin Marinas <catalin.marinas@arm.com>

This patch adds the base support for the ARMv7-M
architecture. It consists of the corresponding arch/arm/mm/ files and
various #ifdef's around the kernel. Exception handling is implemented by
a subsequent patch.

[ukleinek: squash in some changes originating from commit

b5717ba (Cortex-M3: Add support for the Microcontroller Prototyping System)

from the v2.6.33-arm1 patch stack, port to post 3.6, drop zImage
support, drop reorganisation of pt_regs, assert CONFIG_V7M doesn't leak
into installed headers and a few cosmetic changes]

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
Changes since v9, sent with
Message-id:1363901310-9474-2-git-send-email-u.kleine-koenig at pengutronix.de

 - use relative offsets for V7M_SCB
 - drop unused constants for EXC_RET_... and add a comment instead
 - several new and expanded comments
 - drop HWCAP_SWP and HWCAP_EDSP, add HWCAP_IDIVT
---
 arch/arm/include/asm/assembler.h   |  17 +++-
 arch/arm/include/asm/cputype.h     |  12 ++-
 arch/arm/include/asm/glue-cache.h  |  27 ++++++
 arch/arm/include/asm/glue-df.h     |   8 ++
 arch/arm/include/asm/glue-proc.h   |   9 ++
 arch/arm/include/asm/irqflags.h    |  22 +++--
 arch/arm/include/asm/ptrace.h      |   4 +
 arch/arm/include/asm/system_info.h |   1 +
 arch/arm/include/asm/v7m.h         |  44 ++++++++++
 arch/arm/include/uapi/asm/ptrace.h |  35 ++++++--
 arch/arm/kernel/head-nommu.S       |  10 ++-
 arch/arm/kernel/setup.c            |  17 +++-
 arch/arm/kernel/traps.c            |   8 ++
 arch/arm/mm/cache-nop.S            |  53 ++++++++++++
 arch/arm/mm/nommu.c                |   7 ++
 arch/arm/mm/proc-v7m.S             | 165 +++++++++++++++++++++++++++++++++++++
 16 files changed, 418 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm/include/asm/v7m.h
 create mode 100644 arch/arm/mm/cache-nop.S
 create mode 100644 arch/arm/mm/proc-v7m.S

diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 05ee9ee..a5fef71 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -136,7 +136,11 @@
  * assumes FIQs are enabled, and that the processor is in SVC mode.
  */
 	.macro	save_and_disable_irqs, oldcpsr
+#ifdef CONFIG_CPU_V7M
+	mrs	\oldcpsr, primask
+#else
 	mrs	\oldcpsr, cpsr
+#endif
 	disable_irq
 	.endm
 
@@ -150,7 +154,11 @@
  * guarantee that this will preserve the flags.
  */
 	.macro	restore_irqs_notrace, oldcpsr
+#ifdef CONFIG_CPU_V7M
+	msr	primask, \oldcpsr
+#else
 	msr	cpsr_c, \oldcpsr
+#endif
 	.endm
 
 	.macro restore_irqs, oldcpsr
@@ -229,7 +237,14 @@
 #endif
 	.endm
 
-#ifdef CONFIG_THUMB2_KERNEL
+#if defined(CONFIG_CPU_V7M)
+	/*
+	 * setmode is used to assert to be in svc mode during boot. For v7-M
+	 * this is done in __v7m_setup, so setmode can be empty here.
+	 */
+	.macro	setmode, mode, reg
+	.endm
+#elif defined(CONFIG_THUMB2_KERNEL)
 	.macro	setmode, mode, reg
 	mov	\reg, #\mode
 	msr	cpsr_c, \reg
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index 7652712..4eb94a3 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -106,7 +106,17 @@ static inline unsigned int __attribute_const__ read_cpuid_id(void)
 	return read_cpuid(CPUID_ID);
 }
 
-#else /* ifdef CONFIG_CPU_CP15 */
+#elif defined(CONFIG_CPU_V7M)
+
+#include <asm/io.h>
+#include <asm/v7m.h>
+
+static inline unsigned int __attribute_const__ read_cpuid_id(void)
+{
+	return readl(BASEADDR_V7M_SCB + V7M_SCB_CPUID);
+}
+
+#else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */
 
 static inline unsigned int __attribute_const__ read_cpuid_id(void)
 {
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index cca9f15..65c9faf 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -125,10 +125,37 @@
 # endif
 #endif
 
+#if defined(CONFIG_CPU_V7M)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE nop
+# endif
+#endif
+
 #if !defined(_CACHE) && !defined(MULTI_CACHE)
 #error Unknown cache maintenance model
 #endif
 
+#ifndef __ASSEMBLER__
+extern inline void nop_flush_icache_all(void) { }
+extern inline void nop_flush_kern_cache_all(void) { }
+extern inline void nop_flush_kern_cache_louis(void) { }
+extern inline void nop_flush_user_cache_all(void) { }
+extern inline void nop_flush_user_cache_range(unsigned long a,
+		unsigned long b, unsigned int c) { }
+
+extern inline void nop_coherent_kern_range(unsigned long a, unsigned long b) { }
+extern inline int nop_coherent_user_range(unsigned long a,
+		unsigned long b) { return 0; }
+extern inline void nop_flush_kern_dcache_area(void *a, size_t s) { }
+
+extern inline void nop_dma_flush_range(const void *a, const void *b) { }
+
+extern inline void nop_dma_map_area(const void *s, size_t l, int f) { }
+extern inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
+#endif
+
 #ifndef MULTI_CACHE
 #define __cpuc_flush_icache_all		__glue(_CACHE,_flush_icache_all)
 #define __cpuc_flush_kern_all		__glue(_CACHE,_flush_kern_cache_all)
diff --git a/arch/arm/include/asm/glue-df.h b/arch/arm/include/asm/glue-df.h
index b6e9f2c..6b70f1b 100644
--- a/arch/arm/include/asm/glue-df.h
+++ b/arch/arm/include/asm/glue-df.h
@@ -95,6 +95,14 @@
 # endif
 #endif
 
+#ifdef CONFIG_CPU_ABRT_NOMMU
+# ifdef CPU_DABORT_HANDLER
+#  define MULTI_DABORT 1
+# else
+#  define CPU_DABORT_HANDLER nommu_early_abort
+# endif
+#endif
+
 #ifndef CPU_DABORT_HANDLER
 #error Unknown data abort handler type
 #endif
diff --git a/arch/arm/include/asm/glue-proc.h b/arch/arm/include/asm/glue-proc.h
index ac1dd54..f2f39bc 100644
--- a/arch/arm/include/asm/glue-proc.h
+++ b/arch/arm/include/asm/glue-proc.h
@@ -230,6 +230,15 @@
 # endif
 #endif
 
+#ifdef CONFIG_CPU_V7M
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_v7m
+# endif
+#endif
+
 #ifndef MULTI_CPU
 #define cpu_proc_init			__glue(CPU_NAME,_proc_init)
 #define cpu_proc_fin			__glue(CPU_NAME,_proc_fin)
diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h
index 1e6cca5..3b763d6 100644
--- a/arch/arm/include/asm/irqflags.h
+++ b/arch/arm/include/asm/irqflags.h
@@ -8,6 +8,16 @@
 /*
  * CPU interrupt mask handling.
  */
+#ifdef CONFIG_CPU_V7M
+#define IRQMASK_REG_NAME_R "primask"
+#define IRQMASK_REG_NAME_W "primask"
+#define IRQMASK_I_BIT	1
+#else
+#define IRQMASK_REG_NAME_R "cpsr"
+#define IRQMASK_REG_NAME_W "cpsr_c"
+#define IRQMASK_I_BIT	PSR_I_BIT
+#endif
+
 #if __LINUX_ARM_ARCH__ >= 6
 
 static inline unsigned long arch_local_irq_save(void)
@@ -15,7 +25,7 @@ static inline unsigned long arch_local_irq_save(void)
 	unsigned long flags;
 
 	asm volatile(
-		"	mrs	%0, cpsr	@ arch_local_irq_save\n"
+		"	mrs	%0, " IRQMASK_REG_NAME_R "	@ arch_local_irq_save\n"
 		"	cpsid	i"
 		: "=r" (flags) : : "memory", "cc");
 	return flags;
@@ -129,7 +139,7 @@ static inline unsigned long arch_local_save_flags(void)
 {
 	unsigned long flags;
 	asm volatile(
-		"	mrs	%0, cpsr	@ local_save_flags"
+		"	mrs	%0, " IRQMASK_REG_NAME_R "	@ local_save_flags"
 		: "=r" (flags) : : "memory", "cc");
 	return flags;
 }
@@ -140,7 +150,7 @@ static inline unsigned long arch_local_save_flags(void)
 static inline void arch_local_irq_restore(unsigned long flags)
 {
 	asm volatile(
-		"	msr	cpsr_c, %0	@ local_irq_restore"
+		"	msr	" IRQMASK_REG_NAME_W ", %0	@ local_irq_restore"
 		:
 		: "r" (flags)
 		: "memory", "cc");
@@ -148,8 +158,8 @@ static inline void arch_local_irq_restore(unsigned long flags)
 
 static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
-	return flags & PSR_I_BIT;
+	return flags & IRQMASK_I_BIT;
 }
 
-#endif
-#endif
+#endif /* ifdef __KERNEL__ */
+#endif /* ifndef __ASM_ARM_IRQFLAGS_H */
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 3d52ee1..04c99f3 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -45,6 +45,7 @@ struct pt_regs {
  */
 static inline int valid_user_regs(struct pt_regs *regs)
 {
+#ifndef CONFIG_CPU_V7M
 	unsigned long mode = regs->ARM_cpsr & MODE_MASK;
 
 	/*
@@ -67,6 +68,9 @@ static inline int valid_user_regs(struct pt_regs *regs)
 		regs->ARM_cpsr |= USR_MODE;
 
 	return 0;
+#else /* ifndef CONFIG_CPU_V7M */
+	return 1;
+#endif
 }
 
 static inline long regs_return_value(struct pt_regs *regs)
diff --git a/arch/arm/include/asm/system_info.h b/arch/arm/include/asm/system_info.h
index dfd386d..720ea03 100644
--- a/arch/arm/include/asm/system_info.h
+++ b/arch/arm/include/asm/system_info.h
@@ -11,6 +11,7 @@
 #define CPU_ARCH_ARMv5TEJ	7
 #define CPU_ARCH_ARMv6		8
 #define CPU_ARCH_ARMv7		9
+#define CPU_ARCH_ARMv7M		10
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/arm/include/asm/v7m.h b/arch/arm/include/asm/v7m.h
new file mode 100644
index 0000000..fa88d09
--- /dev/null
+++ b/arch/arm/include/asm/v7m.h
@@ -0,0 +1,44 @@
+/*
+ * Common defines for v7m cpus
+ */
+#define V7M_SCS_ICTR			IOMEM(0xe000e004)
+#define V7M_SCS_ICTR_INTLINESNUM_MASK		0x0000000f
+
+#define BASEADDR_V7M_SCB		IOMEM(0xe000ed00)
+
+#define V7M_SCB_CPUID			0x00
+
+#define V7M_SCB_ICSR			0x04
+#define V7M_SCB_ICSR_PENDSVSET			(1 << 28)
+#define V7M_SCB_ICSR_PENDSVCLR			(1 << 27)
+#define V7M_SCB_ICSR_RETTOBASE			(1 << 11)
+
+#define V7M_SCB_VTOR			0x08
+
+#define V7M_SCB_SCR			0x10
+#define V7M_SCB_SCR_SLEEPDEEP			(1 << 2)
+
+#define V7M_SCB_CCR			0x14
+#define V7M_SCB_CCR_STKALIGN			(1 << 9)
+
+#define V7M_SCB_SHPR2			0x1c
+#define V7M_SCB_SHPR3			0x20
+
+#define V7M_SCB_SHCSR			0x24
+#define V7M_SCB_SHCSR_USGFAULTENA		(1 << 18)
+#define V7M_SCB_SHCSR_BUSFAULTENA		(1 << 17)
+#define V7M_SCB_SHCSR_MEMFAULTENA		(1 << 16)
+
+#define V7M_xPSR_FRAMEPTRALIGN			0x00000200
+#define V7M_xPSR_EXCEPTIONNO			0x000001ff
+
+/*
+ * When branching to an address that has bits [31:28] == 0xf an exception return
+ * occurs. Bits [27:5] are reserved (SBOP). If the processor implements the FP
+ * extension Bit [4] defines if the exception frame has space allocated for FP
+ * state information, SBOP otherwise. Bit [3] defines the mode that is returned
+ * to (0 -> handler mode; 1 -> thread mode). Bit [2] defines which sp is used
+ * (0 -> msp; 1 -> psp). Bits [1:0] are fixed to 0b01.
+ */
+#define EXC_RET_STACK_MASK			0x00000004
+#define EXC_RET_THREADMODE_PROCESSSTACK		0xfffffffd
diff --git a/arch/arm/include/uapi/asm/ptrace.h b/arch/arm/include/uapi/asm/ptrace.h
index 96ee092..5af0ed1 100644
--- a/arch/arm/include/uapi/asm/ptrace.h
+++ b/arch/arm/include/uapi/asm/ptrace.h
@@ -34,28 +34,47 @@
 
 /*
  * PSR bits
+ * Note on V7M there is no mode contained in the PSR
  */
 #define USR26_MODE	0x00000000
 #define FIQ26_MODE	0x00000001
 #define IRQ26_MODE	0x00000002
 #define SVC26_MODE	0x00000003
+#if defined(__KERNEL__) && defined(CONFIG_CPU_V7M)
+/*
+ * Use 0 here to get code right that creates a userspace
+ * or kernel space thread.
+ */
+#define USR_MODE	0x00000000
+#define SVC_MODE	0x00000000
+#else
 #define USR_MODE	0x00000010
+#define SVC_MODE	0x00000013
+#endif
 #define FIQ_MODE	0x00000011
 #define IRQ_MODE	0x00000012
-#define SVC_MODE	0x00000013
 #define ABT_MODE	0x00000017
 #define HYP_MODE	0x0000001a
 #define UND_MODE	0x0000001b
 #define SYSTEM_MODE	0x0000001f
 #define MODE32_BIT	0x00000010
 #define MODE_MASK	0x0000001f
-#define PSR_T_BIT	0x00000020
-#define PSR_F_BIT	0x00000040
-#define PSR_I_BIT	0x00000080
-#define PSR_A_BIT	0x00000100
-#define PSR_E_BIT	0x00000200
-#define PSR_J_BIT	0x01000000
-#define PSR_Q_BIT	0x08000000
+
+#define V4_PSR_T_BIT	0x00000020	/* >= V4T, but not V7M */
+#define V7M_PSR_T_BIT	0x01000000
+#if defined(__KERNEL__) && defined(CONFIG_CPU_V7M)
+#define PSR_T_BIT	V7M_PSR_T_BIT
+#else
+/* for compatibility */
+#define PSR_T_BIT	V4_PSR_T_BIT
+#endif
+
+#define PSR_F_BIT	0x00000040	/* >= V4, but not V7M */
+#define PSR_I_BIT	0x00000080	/* >= V4, but not V7M */
+#define PSR_A_BIT	0x00000100	/* >= V6, but not V7M */
+#define PSR_E_BIT	0x00000200	/* >= V6, but not V7M */
+#define PSR_J_BIT	0x01000000	/* >= V5J, but not V7M */
+#define PSR_Q_BIT	0x08000000	/* >= V5E, including V7M */
 #define PSR_V_BIT	0x10000000
 #define PSR_C_BIT	0x20000000
 #define PSR_Z_BIT	0x40000000
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 6a2e09c..8812ce8 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -19,6 +19,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/cp15.h>
 #include <asm/thread_info.h>
+#include <asm/v7m.h>
 
 /*
  * Kernel startup entry point.
@@ -50,10 +51,13 @@ ENTRY(stext)
 
 	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
 						@ and irqs disabled
-#ifndef CONFIG_CPU_CP15
-	ldr	r9, =CONFIG_PROCESSOR_ID
-#else
+#if defined(CONFIG_CPU_CP15)
 	mrc	p15, 0, r9, c0, c0		@ get processor id
+#elif defined(CONFIG_CPU_V7M)
+	ldr	r9, =BASEADDR_V7M_SCB
+	ldr	r9, [r9, V7M_SCB_CPUID]
+#else
+	ldr	r9, =CONFIG_PROCESSOR_ID
 #endif
 	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
 	movs	r10, r5				@ invalid processor (r5=0)?
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 1cc9e17..8291245 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -128,7 +128,9 @@ struct stack {
 	u32 und[3];
 } ____cacheline_aligned;
 
+#ifndef CONFIG_CPU_V7M
 static struct stack stacks[NR_CPUS];
+#endif
 
 char elf_platform[ELF_PLATFORM_SIZE];
 EXPORT_SYMBOL(elf_platform);
@@ -207,7 +209,7 @@ static const char *proc_arch[] = {
 	"5TEJ",
 	"6TEJ",
 	"7",
-	"?(11)",
+	"7M",
 	"?(12)",
 	"?(13)",
 	"?(14)",
@@ -216,6 +218,12 @@ static const char *proc_arch[] = {
 	"?(17)",
 };
 
+#ifdef CONFIG_CPU_V7M
+static int __get_cpu_architecture(void)
+{
+	return CPU_ARCH_ARMv7M;
+}
+#else
 static int __get_cpu_architecture(void)
 {
 	int cpu_arch;
@@ -248,6 +256,7 @@ static int __get_cpu_architecture(void)
 
 	return cpu_arch;
 }
+#endif
 
 int __pure cpu_architecture(void)
 {
@@ -293,7 +302,9 @@ static void __init cacheid_init(void)
 {
 	unsigned int arch = cpu_architecture();
 
-	if (arch >= CPU_ARCH_ARMv6) {
+	if (arch == CPU_ARCH_ARMv7M) {
+		cacheid = 0;
+	} else if (arch >= CPU_ARCH_ARMv6) {
 		unsigned int cachetype = read_cpuid_cachetype();
 		if ((cachetype & (7 << 29)) == 4 << 29) {
 			/* ARMv7 register format */
@@ -375,6 +386,7 @@ static void __init feat_v6_fixup(void)
  */
 void cpu_init(void)
 {
+#ifndef CONFIG_CPU_V7M
 	unsigned int cpu = smp_processor_id();
 	struct stack *stk = &stacks[cpu];
 
@@ -425,6 +437,7 @@ void cpu_init(void)
 	      "I" (offsetof(struct stack, und[0])),
 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
 	    : "r14");
+#endif
 }
 
 int __cpu_logical_map[NR_CPUS];
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 1c08911..ec645714 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -819,6 +819,7 @@ static void __init kuser_get_tls_init(unsigned long vectors)
 
 void __init early_trap_init(void *vectors_base)
 {
+#ifndef CONFIG_CPU_V7M
 	unsigned long vectors = (unsigned long)vectors_base;
 	extern char __stubs_start[], __stubs_end[];
 	extern char __vectors_start[], __vectors_end[];
@@ -850,4 +851,11 @@ void __init early_trap_init(void *vectors_base)
 
 	flush_icache_range(vectors, vectors + PAGE_SIZE);
 	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
+#else /* ifndef CONFIG_CPU_V7M */
+	/*
+	 * on V7-M there is no need to copy the vector table to a dedicated
+	 * memory area. The address is configurable and so a table in the kernel
+	 * image can be used.
+	 */
+#endif
 }
diff --git a/arch/arm/mm/cache-nop.S b/arch/arm/mm/cache-nop.S
new file mode 100644
index 0000000..543b930
--- /dev/null
+++ b/arch/arm/mm/cache-nop.S
@@ -0,0 +1,53 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+#include <asm/unwind.h>
+
+#include "proc-macros.S"
+
+ENTRY(nop_flush_icache_all)
+	mov	pc, lr
+ENDPROC(nop_flush_icache_all)
+
+	.globl nop_flush_kern_cache_all
+	.equ nop_flush_kern_cache_all, nop_flush_icache_all
+
+	.globl nop_flush_kern_cache_louis
+	.equ nop_flush_kern_cache_louis, nop_flush_icache_all
+
+	.globl nop_flush_user_cache_all
+	.equ nop_flush_user_cache_all, nop_flush_icache_all
+
+	.globl nop_flush_user_cache_range
+	.equ nop_flush_user_cache_range, nop_flush_icache_all
+
+	.globl nop_coherent_kern_range
+	.equ nop_coherent_kern_range, nop_flush_icache_all
+
+ENTRY(nop_coherent_user_range)
+	mov	r0, 0
+	mov	pc, lr
+ENDPROC(nop_coherent_user_range)
+
+	.globl nop_flush_kern_dcache_area
+	.equ nop_flush_kern_dcache_area, nop_flush_icache_all
+
+	.globl nop_dma_flush_range
+	.equ nop_dma_flush_range, nop_flush_icache_all
+
+	.globl nop_dma_map_area
+	.equ nop_dma_map_area, nop_flush_icache_all
+
+	.globl nop_dma_unmap_area
+	.equ nop_dma_unmap_area, nop_flush_icache_all
+
+	__INITDATA
+
+	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
+	define_cache_functions nop
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index d51225f..dd3a6c6 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -20,12 +20,19 @@
 
 void __init arm_mm_memblock_reserve(void)
 {
+#ifndef CONFIG_CPU_V7M
 	/*
 	 * Register the exception vector page.
 	 * some architectures which the DRAM is the exception vector to trap,
 	 * alloc_page breaks with error, although it is not NULL, but "0."
 	 */
 	memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE);
+#else /* ifndef CONFIG_CPU_V7M */
+	/*
+	 * There is no dedicated vector page on V7-M. So nothing needs to be
+	 * reserved here.
+	 */
+#endif
 }
 
 void __init sanity_check_meminfo(void)
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
new file mode 100644
index 0000000..b18e3ba
--- /dev/null
+++ b/arch/arm/mm/proc-v7m.S
@@ -0,0 +1,165 @@
+/*
+ *  linux/arch/arm/mm/proc-v7m.S
+ *
+ *  Copyright (C) 2008 ARM Ltd.
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  This is the "shell" of the ARMv7-M processor support.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/v7m.h>
+
+ENTRY(cpu_v7m_proc_init)
+	mov	pc, lr
+ENDPROC(cpu_v7m_proc_init)
+
+ENTRY(cpu_v7m_proc_fin)
+	mov	pc, lr
+ENDPROC(cpu_v7m_proc_fin)
+
+/*
+ *	cpu_v7m_reset(loc)
+ *
+ *	Perform a soft reset of the system.  Put the CPU into the
+ *	same state as it would be if it had been reset, and branch
+ *	to what would be the reset vector.
+ *
+ *	- loc   - location to jump to for soft reset
+ */
+	.align	5
+ENTRY(cpu_v7m_reset)
+	mov	pc, r0
+ENDPROC(cpu_v7m_reset)
+
+/*
+ *	cpu_v7m_do_idle()
+ *
+ *	Idle the processor (eg, wait for interrupt).
+ *
+ *	IRQs are already disabled.
+ */
+ENTRY(cpu_v7m_do_idle)
+	wfi
+	mov	pc, lr
+ENDPROC(cpu_v7m_do_idle)
+
+ENTRY(cpu_v7m_dcache_clean_area)
+	mov	pc, lr
+ENDPROC(cpu_v7m_dcache_clean_area)
+
+/*
+ * There is no MMU, so here is nothing to do.
+ */
+ENTRY(cpu_v7m_switch_mm)
+	mov	pc, lr
+ENDPROC(cpu_v7m_switch_mm)
+
+cpu_v7m_name:
+	.ascii	"ARMv7-M Processor"
+	.align
+
+	.section ".text.init", #alloc, #execinstr
+
+/*
+ *	__v7m_setup
+ *
+ *	This should be able to cover all ARMv7-M cores.
+ */
+__v7m_setup:
+	@ Configure the vector table base address
+	ldr	r0, =BASEADDR_V7M_SCB
+	ldr	r12, =vector_table
+	str	r12, [r0, V7M_SCB_VTOR]
+
+	@ enable UsageFault, BusFault and MemManage fault.
+	ldr	r5, [r0, #V7M_SCB_SHCSR]
+	orr	r5, #(V7M_SCB_SHCSR_USGFAULTENA | V7M_SCB_SHCSR_BUSFAULTENA | V7M_SCB_SHCSR_MEMFAULTENA)
+	str	r5, [r0, #V7M_SCB_SHCSR]
+
+	@ Lower the priority of the SVC and PendSV exceptions
+	mov	r5, #0x80000000
+	str	r5, [r0, V7M_SCB_SHPR2]	@ set SVC priority
+	mov	r5, #0x00800000
+	str	r5, [r0, V7M_SCB_SHPR3]	@ set PendSV priority
+
+	@ SVC to run the kernel in this mode
+	adr	r1, BSYM(1f)
+	ldr	r5, [r12, #11 * 4]	@ read the SVC vector entry
+	str	r1, [r12, #11 * 4]	@ write the temporary SVC vector entry
+	mov	r6, lr			@ save LR
+	mov	r7, sp			@ save SP
+	ldr	sp, =__v7m_setup_stack_top
+	cpsie	i
+	svc	#0
+1:	cpsid	i
+	str	r5, [r12, #11 * 4]	@ restore the original SVC vector entry
+	mov	lr, r6			@ restore LR
+	mov	sp, r7			@ restore SP
+
+	@ Special-purpose control register
+	mov	r1, #1
+	msr	control, r1		@ Thread mode has unpriviledged access
+
+	@ Configure the System Control Register to ensure 8-byte stack alignment
+	@ Note the STKALIGN bit is either RW or RAO.
+	ldr	r12, [r0, V7M_SCB_CCR]	@ system control register
+	orr	r12, #V7M_SCB_CCR_STKALIGN
+	str	r12, [r0, V7M_SCB_CCR]
+	mov	pc, lr
+ENDPROC(__v7m_setup)
+
+	.align	2
+	.type	v7m_processor_functions, #object
+ENTRY(v7m_processor_functions)
+	.word	nommu_early_abort
+	.word	cpu_v7m_proc_init
+	.word	cpu_v7m_proc_fin
+	.word	cpu_v7m_reset
+	.word	cpu_v7m_do_idle
+	.word	cpu_v7m_dcache_clean_area
+	.word	cpu_v7m_switch_mm
+	.word	0			@ cpu_v7m_set_pte_ext
+	.word	legacy_pabort
+	.size	v7m_processor_functions, . - v7m_processor_functions
+
+	.type	cpu_arch_name, #object
+cpu_arch_name:
+	.asciz	"armv7m"
+	.size	cpu_arch_name, . - cpu_arch_name
+
+	.type	cpu_elf_name, #object
+cpu_elf_name:
+	.asciz	"v7m"
+	.size	cpu_elf_name, . - cpu_elf_name
+	.align
+
+	.section ".proc.info.init", #alloc, #execinstr
+
+	/*
+	 * Match any ARMv7-M processor core.
+	 */
+	.type	__v7m_proc_info, #object
+__v7m_proc_info:
+	.long	0x000f0000		@ Required ID value
+	.long	0x000f0000		@ Mask for ID
+	.long   0			@ proc_info_list.__cpu_mm_mmu_flags
+	.long   0			@ proc_info_list.__cpu_io_mmu_flags
+	b	__v7m_setup		@ proc_info_list.__cpu_flush
+	.long	cpu_arch_name
+	.long	cpu_elf_name
+	.long	HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_IDIVT
+	.long	cpu_v7m_name
+	.long	v7m_processor_functions	@ proc_info_list.proc
+	.long	0			@ proc_info_list.tlb
+	.long	0			@ proc_info_list.user
+	.long	nop_cache_fns		@ proc_info_list.cache
+	.size	__v7m_proc_info, . - __v7m_proc_info
+
+__v7m_setup_stack:
+	.space	4 * 8				@ 8 registers
+__v7m_setup_stack_top:
-- 
1.8.2.rc2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v10 2/3] ARM: ARMv7-M: Add support for exception handling
  2013-03-27 10:54 ` [PATCH v10 0/3] ARM: ARMv7-M (i.e. Cortex-M3) support Uwe Kleine-König
  2013-03-27 10:54   ` [PATCH v10 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
@ 2013-03-27 10:54   ` Uwe Kleine-König
  2013-03-27 10:54   ` [PATCH v10 3/3] ARM: ARMv7-M: Allow the building of new kernel port Uwe Kleine-König
  2 siblings, 0 replies; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-27 10:54 UTC (permalink / raw)
  To: linux-arm-kernel

This patch implements the exception handling for the ARMv7-M
architecture (pretty different from the A or R profiles).

It bases on work done earlier by Catalin for 2.6.33 but was nearly
completely rewritten to use a pt_regs layout compatible to the A
profile.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
Changes since v9, sent with
Message-id:1363901310-9474-3-git-send-email-u.kleine-koenig at pengutronix.de:

 - s/V7M_xPSR_FPALIGN/V7M_xPSR_FRAMEPTRALIGN/
 - expand comments
 - drop XXX item about clrex
 - make 0x1ff a #define
 - followup changes for changes in previous
---
 arch/arm/kernel/entry-common.S |   4 ++
 arch/arm/kernel/entry-header.S | 124 +++++++++++++++++++++++++++++++++++
 arch/arm/kernel/entry-v7m.S    | 142 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 270 insertions(+)
 create mode 100644 arch/arm/kernel/entry-v7m.S

diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 3248cde..c45e002 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -339,6 +339,9 @@ ENDPROC(ftrace_stub)
 
 	.align	5
 ENTRY(vector_swi)
+#ifdef CONFIG_CPU_V7M
+	v7m_exception_entry
+#else
 	sub	sp, sp, #S_FRAME_SIZE
 	stmia	sp, {r0 - r12}			@ Calling r0 - r12
  ARM(	add	r8, sp, #S_PC		)
@@ -349,6 +352,7 @@ ENTRY(vector_swi)
 	str	lr, [sp, #S_PC]			@ Save calling PC
 	str	r8, [sp, #S_PSR]		@ Save CPSR
 	str	r0, [sp, #S_OLD_R0]		@ Save OLD_R0
+#endif
 	zero_fp
 
 	/*
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 9a8531e..b02e139 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -5,6 +5,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/errno.h>
 #include <asm/thread_info.h>
+#include <asm/v7m.h>
 
 @ Bad Abort numbers
 @ -----------------
@@ -44,6 +45,116 @@
 #endif
 	.endm
 
+#ifdef CONFIG_CPU_V7M
+/*
+ * ARMv7-M exception entry/exit macros.
+ *
+ * xPSR, ReturnAddress(), LR (R14), R12, R3, R2, R1, and R0 are
+ * automatically saved on the current stack (32 words) before
+ * switching to the exception stack (SP_main).
+ *
+ * If exception is taken while in user mode, SP_main is
+ * empty. Otherwise, SP_main is aligned to 64 bit automatically
+ * (CCR.STKALIGN set).
+ *
+ * Linux assumes that the interrupts are disabled when entering an
+ * exception handler and it may BUG if this is not the case. Interrupts
+ * are disabled during entry and reenabled in the exit macro.
+ *
+ * v7m_exception_slow_exit is used when returning from SVC or PendSV.
+ * When returning to kernel mode, we don't return from exception.
+ */
+	.macro	v7m_exception_entry
+	@ determine the location of the registers saved by the core during
+	@ exception entry. Depending on the mode the cpu was in when the
+	@ exception happend that is either on the main or the process stack.
+	@ Bit 2 of EXC_RETURN stored in the lr register specifies which stack
+	@ was used.
+	tst	lr, #EXC_RET_STACK_MASK
+	mrsne	r12, psp
+	moveq	r12, sp
+
+	@ we cannot rely on r0-r3 and r12 matching the value saved in the
+	@ exception frame because of tail-chaining. So these have to be
+	@ reloaded.
+	ldmia	r12!, {r0-r3}
+
+	@ Linux expects to have irqs off. Do it here before taking stack space
+	cpsid	i
+
+	sub	sp, #S_FRAME_SIZE-S_IP
+	stmdb	sp!, {r0-r11}
+
+	@ load saved r12, lr, return address and xPSR.
+	@ r0-r7 are used for signals and never touched from now on. Clobbering
+	@ r8-r12 is OK.
+	mov	r9, r12
+	ldmia	r9!, {r8, r10-r12}
+
+	@ calculate the original stack pointer value.
+	@ r9 currently points to the memory location just above the auto saved
+	@ xPSR.
+	@ The cpu might automatically 8-byte align the stack. Bit 9
+	@ of the saved xPSR specifies if stack aligning took place. In this case
+	@ another 32-bit value is included in the stack.
+
+	tst	r12, V7M_xPSR_FRAMEPTRALIGN
+	addne	r9, r9, #4
+
+	@ store saved r12 using str to have a register to hold the base for stm
+	str	r8, [sp, #S_IP]
+	add	r8, sp, #S_SP
+	@ store r13-r15, xPSR
+	stmia	r8!, {r9-r12}
+	@ store old_r0
+	str	r0, [r8]
+	.endm
+
+        /*
+	 * PENDSV and SVCALL are configured to have the same exception
+	 * priorities. As a kernel thread runs at SVCALL execution priority it
+	 * can never be preempted and so we will never have to return to a
+	 * kernel thread here.
+         */
+	.macro	v7m_exception_slow_exit ret_r0
+	cpsid	i
+	ldr	lr, =EXC_RET_THREADMODE_PROCESSSTACK
+
+	@ read original r12, sp, lr, pc and xPSR
+	add	r12, sp, #S_IP
+	ldmia	r12, {r1-r5}
+
+	@ an exception frame is always 8-byte aligned. To tell the hardware if
+	@ the sp to be restored is aligned or not set bit 9 of the saved xPSR
+	@ accordingly.
+	tst	r2, #4
+	subne	r2, r2, #4
+	orrne	r5, V7M_xPSR_FRAMEPTRALIGN
+	biceq	r5, V7M_xPSR_FRAMEPTRALIGN
+
+	@ write basic exception frame
+	stmdb	r2!, {r1, r3-r5}
+	ldmia	sp, {r1, r3-r5}
+	.if	\ret_r0
+	stmdb	r2!, {r0, r3-r5}
+	.else
+	stmdb	r2!, {r1, r3-r5}
+	.endif
+
+	@ restore process sp
+	msr	psp, r2
+
+	@ restore original r4-r11
+	ldmia	sp!, {r0-r11}
+
+	@ restore main sp
+	add	sp, sp, #S_FRAME_SIZE-S_IP
+
+	cpsie	i
+	bx	lr
+	.endm
+#endif	/* CONFIG_CPU_V7M */
+
 	@
 	@ Store/load the USER SP and LR registers by switching to the SYS
 	@ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not
@@ -131,6 +242,18 @@
 	rfeia	sp!
 	.endm
 
+#ifdef CONFIG_CPU_V7M
+	/*
+	 * Note we don't need to do clrex here as clearing the local monitor is
+	 * part of each exception entry and exit sequence.
+	 */
+	.macro	restore_user_regs, fast = 0, offset = 0
+	.if	\offset
+	add	sp, #\offset
+	.endif
+	v7m_exception_slow_exit ret_r0 = \fast
+	.endm
+#else	/* ifdef CONFIG_CPU_V7M */
 	.macro	restore_user_regs, fast = 0, offset = 0
 	clrex					@ clear the exclusive monitor
 	mov	r2, sp
@@ -147,6 +270,7 @@
 	add	sp, sp, #S_FRAME_SIZE - S_SP
 	movs	pc, lr				@ return & move spsr_svc into cpsr
 	.endm
+#endif	/* ifdef CONFIG_CPU_V7M / else */
 
 	.macro	get_thread_info, rd
 	mov	\rd, sp
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
new file mode 100644
index 0000000..f261463
--- /dev/null
+++ b/arch/arm/kernel/entry-v7m.S
@@ -0,0 +1,142 @@
+/*
+ * linux/arch/arm/kernel/entry-v7m.S
+ *
+ * Copyright (C) 2008 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Low-level vector interface routines for the ARMv7-M architecture
+ */
+#include <asm/memory.h>
+#include <asm/glue.h>
+#include <asm/thread_notify.h>
+#include <asm/v7m.h>
+
+#include <mach/entry-macro.S>
+
+#include "entry-header.S"
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+#error "CONFIG_TRACE_IRQFLAGS not supported on the current ARMv7M implementation"
+#endif
+
+__invalid_entry:
+	v7m_exception_entry
+	adr	r0, strerr
+	mrs	r1, ipsr
+	mov	r2, lr
+	bl	printk
+	mov	r0, sp
+	bl	show_regs
+1:	b	1b
+ENDPROC(__invalid_entry)
+
+strerr:	.asciz	"\nUnhandled exception: IPSR = %08lx LR = %08lx\n"
+
+	.align	2
+__irq_entry:
+	v7m_exception_entry
+
+	@
+	@ Invoke the IRQ handler
+	@
+	mrs	r0, ipsr
+	ldr	r1, =V7M_xPSR_EXCEPTIONNO
+	and	r0, r1
+	mov	r1, sp
+	stmdb	sp!, {lr}
+	@ routine called with r0 = irq number, r1 = struct pt_regs *
+	bl	asm_do_IRQ
+
+	pop	{lr}
+	@
+	@ Check for any pending work if returning to user
+	@
+	ldr	r1, =BASEADDR_V7M_SCB
+	ldr	r0, [r1, V7M_SCB_ICSR]
+	tst	r0, V7M_SCB_ICSR_RETTOBASE
+	beq	2f
+
+	get_thread_info tsk
+	ldr	r2, [tsk, #TI_FLAGS]
+	tst	r2, #_TIF_WORK_MASK
+	beq	2f			@ no work pending
+	mov	r0, #V7M_SCB_ICSR_PENDSVSET
+	str	r0, [r1, V7M_SCB_ICSR]	@ raise PendSV
+
+2:
+	@ registers r0-r3 and r12 are automatically restored on exception
+	@ return. r4-r7 were not clobbered in v7m_exception_entry so for
+	@ correctness they don't need to be restored. So only r8-r11 must be
+	@ restored here. The easiest way to do so is to restore r0-r7, too.
+	ldmia	sp!, {r0-r11}
+	add	sp, #S_FRAME_SIZE-S_IP
+	cpsie	i
+	bx	lr
+ENDPROC(__irq_entry)
+
+__pendsv_entry:
+	v7m_exception_entry
+
+	ldr	r1, =BASEADDR_V7M_SCB
+	mov	r0, #V7M_SCB_ICSR_PENDSVCLR
+	str	r0, [r1, V7M_SCB_ICSR]	@ clear PendSV
+
+	@ execute the pending work, including reschedule
+	get_thread_info tsk
+	mov	why, #0
+	b	ret_to_user
+ENDPROC(__pendsv_entry)
+
+/*
+ * Register switch for ARMv7-M processors.
+ * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
+ * previous and next are guaranteed not to be the same.
+ */
+ENTRY(__switch_to)
+	.fnstart
+	.cantunwind
+	add	ip, r1, #TI_CPU_SAVE
+	stmia	ip!, {r4 - r11}		@ Store most regs on stack
+	str	sp, [ip], #4
+	str	lr, [ip], #4
+	mov	r5, r0
+	add	r4, r2, #TI_CPU_SAVE
+	ldr	r0, =thread_notify_head
+	mov	r1, #THREAD_NOTIFY_SWITCH
+	bl	atomic_notifier_call_chain
+	mov	ip, r4
+	mov	r0, r5
+	ldmia	ip!, {r4 - r11}		@ Load all regs saved previously
+	ldr	sp, [ip]
+	ldr	pc, [ip, #4]!
+	.fnend
+ENDPROC(__switch_to)
+
+	.data
+	.align	8
+/*
+ * Vector table (64 words => 256 bytes natural alignment)
+ */
+ENTRY(vector_table)
+	.long	0			@ 0 - Reset stack pointer
+	.long	__invalid_entry		@ 1 - Reset
+	.long	__invalid_entry		@ 2 - NMI
+	.long	__invalid_entry		@ 3 - HardFault
+	.long	__invalid_entry		@ 4 - MemManage
+	.long	__invalid_entry		@ 5 - BusFault
+	.long	__invalid_entry		@ 6 - UsageFault
+	.long	__invalid_entry		@ 7 - Reserved
+	.long	__invalid_entry		@ 8 - Reserved
+	.long	__invalid_entry		@ 9 - Reserved
+	.long	__invalid_entry		@ 10 - Reserved
+	.long	vector_swi		@ 11 - SVCall
+	.long	__invalid_entry		@ 12 - Debug Monitor
+	.long	__invalid_entry		@ 13 - Reserved
+	.long	__pendsv_entry		@ 14 - PendSV
+	.long	__invalid_entry		@ 15 - SysTick
+	.rept	64 - 16
+	.long	__irq_entry		@ 16..64 - External Interrupts
+	.endr
-- 
1.8.2.rc2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v10 3/3] ARM: ARMv7-M: Allow the building of new kernel port
  2013-03-27 10:54 ` [PATCH v10 0/3] ARM: ARMv7-M (i.e. Cortex-M3) support Uwe Kleine-König
  2013-03-27 10:54   ` [PATCH v10 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
  2013-03-27 10:54   ` [PATCH v10 2/3] ARM: ARMv7-M: Add support for exception handling Uwe Kleine-König
@ 2013-03-27 10:54   ` Uwe Kleine-König
  2 siblings, 0 replies; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-27 10:54 UTC (permalink / raw)
  To: linux-arm-kernel

This patch modifies the required Kconfig and Makefile files to allow the
building of kernel for Cortex-M3.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
Changes since v9, sent with
Message-id:1363901310-9474-4-git-send-email-u.kleine-koenig at pengutronix.de:

 - drop selecting CPU_CACHE_VIPT
---
 arch/arm/Kconfig         |  4 ++--
 arch/arm/Kconfig-nommu   |  2 +-
 arch/arm/Makefile        |  1 +
 arch/arm/kernel/Makefile |  8 +++++++-
 arch/arm/mm/Kconfig      | 21 ++++++++++++++++++++-
 arch/arm/mm/Makefile     |  2 ++
 6 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index dedf02b..7c8c607 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -9,7 +9,7 @@ config ARM
 	select BUILDTIME_EXTABLE_SORT if MMU
 	select CPU_PM if (SUSPEND || CPU_IDLE)
 	select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN && MMU
-	select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
+	select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
 	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
 	select GENERIC_IRQ_PROBE
 	select GENERIC_IRQ_SHOW
@@ -1685,7 +1685,7 @@ config SCHED_HRTICK
 
 config THUMB2_KERNEL
 	bool "Compile the kernel in Thumb-2 mode" if !CPU_THUMBONLY
-	depends on CPU_V7 && !CPU_V6 && !CPU_V6K
+	depends on (CPU_V7 || CPU_V7M) && !CPU_V6 && !CPU_V6K
 	default y if CPU_THUMBONLY
 	select AEABI
 	select ARM_ASM_UNIFIED
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index 2cef8e1..c859495 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -28,7 +28,7 @@ config FLASH_SIZE
 config PROCESSOR_ID
 	hex 'Hard wire the processor ID'
 	default 0x00007700
-	depends on !CPU_CP15
+	depends on !(CPU_CP15 || CPU_V7M)
 	help
 	  If processor has no CP15 register, this processor ID is
 	  used instead of the auto-probing which utilizes the register.
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..f11b8da 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -59,6 +59,7 @@ comma = ,
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7M)	:=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
 arch-$(CONFIG_CPU_32v7)		:=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
 arch-$(CONFIG_CPU_32v6)		:=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
 # Only override the compiler option if ARMv6. The ARMv6K extensions are
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 5f3338e..00d703c 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -15,7 +15,7 @@ CFLAGS_REMOVE_return_address.o = -pg
 
 # Object file lists.
 
-obj-y		:= elf.o entry-armv.o entry-common.o irq.o opcodes.o \
+obj-y		:= elf.o entry-common.o irq.o opcodes.o \
 		   process.o ptrace.o return_address.o sched_clock.o \
 		   setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
 
@@ -23,6 +23,12 @@ obj-$(CONFIG_ATAGS)		+= atags_parse.o
 obj-$(CONFIG_ATAGS_PROC)	+= atags_proc.o
 obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
 
+ifeq ($(CONFIG_CPU_V7M),y)
+obj-y		+= entry-v7m.o
+else
+obj-y		+= entry-armv.o
+endif
+
 obj-$(CONFIG_OC_ETM)		+= etm.o
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index cb812a1..cce78b0 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -397,6 +397,15 @@ config CPU_V7
 	select CPU_PABRT_V7
 	select CPU_TLB_V7 if MMU
 
+# ARMv7M
+config CPU_V7M
+	bool
+	select CPU_32v7M
+	select CPU_ABRT_NOMMU
+	select CPU_CACHE_NOP
+	select CPU_PABRT_LEGACY
+	select CPU_THUMBONLY
+
 config CPU_THUMBONLY
 	bool
 	# There are no CPUs available with MMU that don't implement an ARM ISA:
@@ -441,6 +450,9 @@ config CPU_32v6K
 config CPU_32v7
 	bool
 
+config CPU_32v7M
+	bool
+
 # The abort model
 config CPU_ABRT_NOMMU
 	bool
@@ -494,6 +506,9 @@ config CPU_CACHE_V6
 config CPU_CACHE_V7
 	bool
 
+config CPU_CACHE_NOP
+	bool
+
 config CPU_CACHE_VIVT
 	bool
 
@@ -616,7 +631,11 @@ config ARCH_DMA_ADDR_T_64BIT
 
 config ARM_THUMB
 	bool "Support Thumb user binaries" if !CPU_THUMBONLY
-	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || CPU_V7 || CPU_FEROCEON
+	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || \
+		CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || \
+		CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || \
+		CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || \
+		CPU_V7 || CPU_FEROCEON || CPU_V7M
 	default y
 	help
 	  Say Y if you want to include kernel support for running user space
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 4e333fa..317b575 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_CPU_CACHE_V4WB)	+= cache-v4wb.o
 obj-$(CONFIG_CPU_CACHE_V6)	+= cache-v6.o
 obj-$(CONFIG_CPU_CACHE_V7)	+= cache-v7.o
 obj-$(CONFIG_CPU_CACHE_FA)	+= cache-fa.o
+obj-$(CONFIG_CPU_CACHE_NOP)	+= cache-nop.o
 
 AFLAGS_cache-v6.o	:=-Wa,-march=armv6
 AFLAGS_cache-v7.o	:=-Wa,-march=armv7-a
@@ -88,6 +89,7 @@ obj-$(CONFIG_CPU_FEROCEON)	+= proc-feroceon.o
 obj-$(CONFIG_CPU_V6)		+= proc-v6.o
 obj-$(CONFIG_CPU_V6K)		+= proc-v6.o
 obj-$(CONFIG_CPU_V7)		+= proc-v7.o
+obj-$(CONFIG_CPU_V7M)		+= proc-v7m.o
 
 AFLAGS_proc-v6.o	:=-Wa,-march=armv6
 AFLAGS_proc-v7.o	:=-Wa,-march=armv7-a
-- 
1.8.2.rc2

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v9 3/3] ARM: ARMv7-M: Allow the building of new kernel port
  2013-03-27 10:37   ` Jonathan Austin
@ 2013-03-27 10:58     ` Uwe Kleine-König
  0 siblings, 0 replies; 16+ messages in thread
From: Uwe Kleine-König @ 2013-03-27 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jonny,

On Wed, Mar 27, 2013 at 10:37:30AM +0000, Jonathan Austin wrote:
> >+# ARMv7M
> >+config CPU_V7M
> >+	bool
> >+	select CPU_32v7M
> >+	select CPU_ABRT_NOMMU
> >+	select CPU_CACHE_NOP
> >+	select CPU_CACHE_VIPT
> 
> What's the deal with VIPT here? I presume something left over?
Right, this was dropped for v10 (as you already pointed it out via irc).

> >+	select CPU_PABRT_LEGACY
> >+	select CPU_THUMBONLY
> >+
> >  config CPU_THUMBONLY
> >  	bool
> >  	# There are no CPUs available with MMU that don't implement an ARM ISA:
> >@@ -441,6 +451,9 @@ config CPU_32v6K
> >  config CPU_32v7
> >  	bool
> >
> >+config CPU_32v7M
> >+	bool
> >+
> 
> What is this config option for?
Just for completeness. There is no use for it (yet).
 
> >  # The abort model
> >  config CPU_ABRT_NOMMU
> >  	bool
> >@@ -494,6 +507,9 @@ config CPU_CACHE_V6
> >  config CPU_CACHE_V7
> >  	bool
> >
> >+config CPU_CACHE_NOP
> >+	bool
> >+
> >  config CPU_CACHE_VIVT
> >  	bool
> >
> >@@ -616,7 +632,11 @@ config ARCH_DMA_ADDR_T_64BIT
> >
> >  config ARM_THUMB
> >  	bool "Support Thumb user binaries" if !CPU_THUMBONLY
> >-	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || CPU_V7 || CPU_FEROCEON
> >+	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || \
> >+		CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || \
> >+		CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || \
> >+		CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || \
> >+		CPU_V7 || CPU_FEROCEON || CPU_V7M
> 
> It looks like there has been a rough attempt to order this list...
> 
> Can V7M go before FEROCEON please?
I missed that because I only saw your mail when I sent out v10. :-\

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v10 1/3] ARM: Add base support for ARMv7-M
  2013-03-27 10:54   ` [PATCH v10 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
@ 2013-04-12 16:25     ` Jonathan Austin
  0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Austin @ 2013-04-12 16:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

I've just noticed an issue with this patch that we haven't seen because 
we're not using MULTI_CPU, but I *think* if we were to do that things 
wouldn't work out.

On 27/03/13 10:54, Uwe Kleine-K?nig wrote:
> From: Catalin Marinas <catalin.marinas@arm.com>
>

Aggressive snip...

> index 0000000..b18e3ba
> --- /dev/null
> +++ b/arch/arm/mm/proc-v7m.S
> @@ -0,0 +1,165 @@
> +/*
> + *  linux/arch/arm/mm/proc-v7m.S
> + *
> + *  Copyright (C) 2008 ARM Ltd.
> + *  Copyright (C) 2001 Deep Blue Solutions Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + *  This is the "shell" of the ARMv7-M processor support.
> + */
> +#include <linux/linkage.h>
> +#include <asm/assembler.h>
> +#include <asm/v7m.h>
> +
> +ENTRY(cpu_v7m_proc_init)
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_proc_init)
> +
> +ENTRY(cpu_v7m_proc_fin)
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_proc_fin)
> +
> +/*
> + *     cpu_v7m_reset(loc)
> + *
> + *     Perform a soft reset of the system.  Put the CPU into the
> + *     same state as it would be if it had been reset, and branch
> + *     to what would be the reset vector.
> + *
> + *     - loc   - location to jump to for soft reset
> + */
> +       .align  5
> +ENTRY(cpu_v7m_reset)
> +       mov     pc, r0
> +ENDPROC(cpu_v7m_reset)
> +
> +/*
> + *     cpu_v7m_do_idle()
> + *
> + *     Idle the processor (eg, wait for interrupt).
> + *
> + *     IRQs are already disabled.
> + */
> +ENTRY(cpu_v7m_do_idle)
> +       wfi
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_do_idle)
> +
> +ENTRY(cpu_v7m_dcache_clean_area)
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_dcache_clean_area)
> +
> +/*
> + * There is no MMU, so here is nothing to do.
> + */
> +ENTRY(cpu_v7m_switch_mm)
> +       mov     pc, lr
> +ENDPROC(cpu_v7m_switch_mm)
> +
> +cpu_v7m_name:
> +       .ascii  "ARMv7-M Processor"
> +       .align
> +
> +       .section ".text.init", #alloc, #execinstr
> +
> +/*
> + *     __v7m_setup
> + *
> + *     This should be able to cover all ARMv7-M cores.
> + */
> +__v7m_setup:
> +       @ Configure the vector table base address
> +       ldr     r0, =BASEADDR_V7M_SCB
> +       ldr     r12, =vector_table
> +       str     r12, [r0, V7M_SCB_VTOR]
> +
> +       @ enable UsageFault, BusFault and MemManage fault.
> +       ldr     r5, [r0, #V7M_SCB_SHCSR]
> +       orr     r5, #(V7M_SCB_SHCSR_USGFAULTENA | V7M_SCB_SHCSR_BUSFAULTENA | V7M_SCB_SHCSR_MEMFAULTENA)
> +       str     r5, [r0, #V7M_SCB_SHCSR]
> +
> +       @ Lower the priority of the SVC and PendSV exceptions
> +       mov     r5, #0x80000000
> +       str     r5, [r0, V7M_SCB_SHPR2] @ set SVC priority
> +       mov     r5, #0x00800000
> +       str     r5, [r0, V7M_SCB_SHPR3] @ set PendSV priority
> +
> +       @ SVC to run the kernel in this mode
> +       adr     r1, BSYM(1f)
> +       ldr     r5, [r12, #11 * 4]      @ read the SVC vector entry
> +       str     r1, [r12, #11 * 4]      @ write the temporary SVC vector entry
> +       mov     r6, lr                  @ save LR
> +       mov     r7, sp                  @ save SP
> +       ldr     sp, =__v7m_setup_stack_top
> +       cpsie   i
> +       svc     #0
> +1:     cpsid   i
> +       str     r5, [r12, #11 * 4]      @ restore the original SVC vector entry
> +       mov     lr, r6                  @ restore LR
> +       mov     sp, r7                  @ restore SP
> +
> +       @ Special-purpose control register
> +       mov     r1, #1
> +       msr     control, r1             @ Thread mode has unpriviledged access
> +
> +       @ Configure the System Control Register to ensure 8-byte stack alignment
> +       @ Note the STKALIGN bit is either RW or RAO.
> +       ldr     r12, [r0, V7M_SCB_CCR]  @ system control register
> +       orr     r12, #V7M_SCB_CCR_STKALIGN
> +       str     r12, [r0, V7M_SCB_CCR]
> +       mov     pc, lr
> +ENDPROC(__v7m_setup)
> +
> +       .align  2
> +       .type   v7m_processor_functions, #object
> +ENTRY(v7m_processor_functions)
> +       .word   nommu_early_abort
 > +       .word   cpu_v7m_proc_init
 > +       .word   cpu_v7m_proc_fin

This seems *not* to align with the struct processor defined in

arch/arm/include/asm/proc-fns.h:

...
extern struct processor {
	/* MISC
	 * get data abort address/flags
	 */
	void (*_data_abort)(unsigned long pc);
	/*
	 * Retrieve prefetch fault address
	 */
	unsigned long (*_prefetch_abort)(unsigned long lr);
	/*
	 * Set up any processor specifics
	 */
	void (*_proc_init)(void);
	/*
	 * Disable any processor specifics
	 */
...

So what's the deal? I presume this is because when Catalin originally 
did the very first M3 stuff it happened before this commit:

48d7927bdf Add a prefetch abort handler

And as we weren't using MULTI_CPU nobody noticed the bug when things got 
updated?


Jonny

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2013-04-12 16:25 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-21 21:28 [PATCH v9 0/3] ARM: ARMv7 (i.e. Cortex-M3) support Uwe Kleine-König
2013-03-21 21:28 ` [PATCH v9 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
2013-03-22 18:42   ` Jonathan Austin
2013-03-22 21:48     ` Uwe Kleine-König
2013-03-21 21:28 ` [PATCH v9 2/3] ARM: ARMv7-M: Add support for exception handling Uwe Kleine-König
2013-03-25 18:50   ` Jonathan Austin
2013-03-26 10:15     ` Uwe Kleine-König
2013-03-26 11:56       ` Jonathan Austin
2013-03-21 21:28 ` [PATCH v9 3/3] ARM: ARMv7-M: Allow the building of new kernel port Uwe Kleine-König
2013-03-27 10:37   ` Jonathan Austin
2013-03-27 10:58     ` Uwe Kleine-König
2013-03-27 10:54 ` [PATCH v10 0/3] ARM: ARMv7-M (i.e. Cortex-M3) support Uwe Kleine-König
2013-03-27 10:54   ` [PATCH v10 1/3] ARM: Add base support for ARMv7-M Uwe Kleine-König
2013-04-12 16:25     ` Jonathan Austin
2013-03-27 10:54   ` [PATCH v10 2/3] ARM: ARMv7-M: Add support for exception handling Uwe Kleine-König
2013-03-27 10:54   ` [PATCH v10 3/3] ARM: ARMv7-M: Allow the building of new kernel port Uwe Kleine-König

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).