Skip to contentSkip to conversation

Yet another update for the Cortex-M3 series

PATCH Superseded Uwe Kleine-König 3 participants 11 messages Oct 17, 2012 – Jan 16, 2013

Subsystems (2)

v7 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v7 cover Yet another update for the Cortex-M3 series

Hello,

the only change since v6 is a rebase on top of v3.7-rc1 and so on Al Viro's changes to kernel_execve().

These patches merge just fine into today's next and I put them into my branch that Stephen will pick for the next next.

As before this doesn't make a functional M3 port as there are still some missing items. If you want to see the code live I also updated the efm32 branch in my repository to be based on these patches. This code works, but isn't suitable for mainline yet. You can run it on EnergyMicro's efm32 devboard.

Best regards
Uwe

Catalin Marinas (1):
Cortex-M3: Add base support for Cortex-M3

Uwe Kleine-K?nig (2):
ARM: make cr_alignment read-only #ifndef CONFIG_CPU_CP15
Cortex-M3: Add support for exception handling

 arch/arm/include/asm/assembler.h   |   13 ++-
 arch/arm/include/asm/cp15.h        |   11 ++-
 arch/arm/include/asm/cputype.h     |    3 +
 arch/arm/include/asm/glue-cache.h  |   25 ++++++
 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/processor.h   |    7 ++
 arch/arm/include/asm/ptrace.h      |    8 ++
 arch/arm/include/asm/system_info.h |    1 +
 arch/arm/include/uapi/asm/ptrace.h |   36 ++++++--
 arch/arm/kernel/asm-offsets.c      |    3 +
 arch/arm/kernel/entry-common.S     |    4 +
 arch/arm/kernel/entry-header.S     |  148 +++++++++++++++++++++++++++++++++
 arch/arm/kernel/entry-v7m.S        |  134 ++++++++++++++++++++++++++++++
 arch/arm/kernel/head-common.S      |    9 +-
 arch/arm/kernel/head-nommu.S       |    9 +-
 arch/arm/kernel/process.c          |    4 +
 arch/arm/kernel/ptrace.c           |    3 +
 arch/arm/kernel/setup.c            |   13 ++-
 arch/arm/kernel/traps.c            |    2 +
 arch/arm/mm/alignment.c            |    2 +
 arch/arm/mm/mmu.c                  |   17 ++++
 arch/arm/mm/nommu.c                |    2 +
 arch/arm/mm/proc-v7m.S             |  161 ++++++++++++++++++++++++++++++++++++
 25 files changed, 632 insertions(+), 22 deletions(-)
 create mode 100644 arch/arm/kernel/entry-v7m.S
 create mode 100644 arch/arm/mm/proc-v7m.S
Signature · 1 line
1.7.10.4
#1 lore raw

PATCH v7 1/3 ARM: make cr_alignment read-only #ifndef CONFIG_CPU_CP15

This makes cr_alignment a constant 0 to break code that tries to modify the value as it's likely that it's built on wrong assumption when CONFIG_CPU_CP15 isn't defined. For code that is only reading the value 0 is more or less a fine value to report.

---
unchanged since v6

 arch/arm/include/asm/cp15.h   |   11 ++++++++++-
 arch/arm/kernel/head-common.S |    9 +++++++--
 arch/arm/mm/alignment.c       |    2 ++
 arch/arm/mm/mmu.c             |   17 +++++++++++++++++
 4 files changed, 36 insertions(+), 3 deletions(-)
arch/arm/include/asm/cp15.h +10 -1
index 5ef4d80..d814435 100644
@@ -42,6 +42,8 @@
 #define vectors_high()	(0)
 #endif
 
+#ifdef CONFIG_CPU_CP15
+
 extern unsigned long cr_no_alignment;	/* defined in entry-armv.S */
 extern unsigned long cr_alignment;	/* defined in entry-armv.S */
 
@@ -82,6 +84,13 @@ static inline void set_copro_access(unsigned int val)
 	isb();
 }
 
-#endif
+#else /* ifdef CONFIG_CPU_CP15 */
+
+#define cr_no_alignment	UL(0)
+#define cr_alignment	UL(0)
+
+#endif /* ifdef CONFIG_CPU_CP15 / else */
+
+#endif /* ifndef __ASSEMBLY__ */
 
 #endif
arch/arm/kernel/head-common.S +7 -2
index 854bd22..2f560c5 100644
@@ -98,8 +98,9 @@ __mmap_switched:
 	str	r9, [r4]			@ Save processor ID
 	str	r1, [r5]			@ Save machine type
 	str	r2, [r6]			@ Save atags pointer
-	bic	r4, r0, #CR_A			@ Clear 'A' bit
-	stmia	r7, {r0, r4}			@ Save control register values
+	cmp	r7, #0
+	bicne	r4, r0, #CR_A			@ Clear 'A' bit
+	stmneia	r7, {r0, r4}			@ Save control register values
 	b	start_kernel
 ENDPROC(__mmap_switched)
 
@@ -113,7 +114,11 @@ __mmap_switched_data:
 	.long	processor_id			@ r4
 	.long	__machine_arch_type		@ r5
 	.long	__atags_pointer			@ r6
+#ifdef CONFIG_CPU_CP15
 	.long	cr_alignment			@ r7
+#else
+	.long	0
+#endif
 	.long	init_thread_union + THREAD_START_SP @ sp
 	.size	__mmap_switched_data, . - __mmap_switched_data
 
arch/arm/mm/alignment.c +2 -0
index b9f60eb..5748094 100644
@@ -962,12 +962,14 @@ static int __init alignment_init(void)
 		return -ENOMEM;
 #endif
 
+#ifdef CONFIG_CPU_CP15
 	if (cpu_is_v6_unaligned()) {
 		cr_alignment &= ~CR_A;
 		cr_no_alignment &= ~CR_A;
 		set_cr(cr_alignment);
 		ai_usermode = safe_usermode(ai_usermode, false);
 	}
+#endif
 
 	hook_fault_code(FAULT_CODE_ALIGNMENT, do_alignment, SIGBUS, BUS_ADRALN,
 			"alignment exception");
arch/arm/mm/mmu.c +17 -0
index 941dfb9..b675918 100644
@@ -97,6 +97,7 @@ static struct cachepolicy cache_policies[] __initdata = {
 	}
 };
 
+#ifdef CONFIG_CPU_CP15
 /*
  * These are useful for identifying cache coherency
  * problems by allowing the cache or the cache and
@@ -195,6 +196,22 @@ void adjust_cr(unsigned long mask, unsigned long set)
 }
 #endif
 
+#else
+
+static int __init early_cachepolicy(char *p)
+{
+	pr_warning("cachepolicy kernel parameter not supported without cp15\n");
+}
+early_param("cachepolicy", early_cachepolicy);
+
+static int __init noalign_setup(char *__unused)
+{
+	pr_warning("noalign kernel parameter not supported without cp15\n");
+}
+__setup("noalign", noalign_setup);
+
+#endif
+
 #define PROT_PTE_DEVICE		L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN
 #define PROT_SECT_DEVICE	PMD_TYPE_SECT|PMD_SECT_AP_WRITE
 
Signature · 1 line
1.7.10.4
#2 lore raw

PATCH v7 1/3 ARM: make cr_alignment read-only #ifndef CONFIG_CPU_CP15

Hi Uwe,

Quoted 5 lines · Uwe Kleine-K?nig

This makes cr_alignment a constant 0 to break code that tries to modify the value as it's likely that it's built on wrong assumption when CONFIG_CPU_CP15 isn't defined. For code that is only reading the value 0 is more or less a fine value to report.

Without the context of some of the discussion that was had on the list about how/why to do this, this description is a bit confusing...

I found myself asking "Why do we not #ifdef out uses of cr_alignment based on CONFIG_CPU_CP15" - a question which it seems is answered by you and Nicolas here:

http://lists.infradead.org/pipermail/linux-arm-kernel/2012-March/089968.html

So, perhaps it would help to have a little bit more context in this commit message?

I know that the cr_alignment stuff is currently tied up with CONFIG_CPU_15, but I wonder if you looked at using the CCR.UNALIGN_TRP bit and wiring that in to alignment trapping code? Is it something you think would make sense for the work you're doing?

Also, see a couple of minor style/commenting points below...

Quoted 54 lines

---
unchanged since v6

  arch/arm/include/asm/cp15.h   |   11 ++++++++++-
  arch/arm/kernel/head-common.S |    9 +++++++--
  arch/arm/mm/alignment.c       |    2 ++
  arch/arm/mm/mmu.c             |   17 +++++++++++++++++
  4 files changed, 36 insertions(+), 3 deletions(-)
arch/arm/include/asm/cp15.h +10 -1
index 5ef4d80..d814435 100644
@@ -42,6 +42,8 @@
  #define vectors_high()	(0)
  #endif
 
+#ifdef CONFIG_CPU_CP15
+
  extern unsigned long cr_no_alignment;	/* defined in entry-armv.S */
  extern unsigned long cr_alignment;	/* defined in entry-armv.S */
 
@@ -82,6 +84,13 @@ static inline void set_copro_access(unsigned int val)
  	isb();
  }
 
-#endif
+#else /* ifdef CONFIG_CPU_CP15 */
+
+#define cr_no_alignment	UL(0)
+#define cr_alignment	UL(0)
+
+#endif /* ifdef CONFIG_CPU_CP15 / else */
+
+#endif /* ifndef __ASSEMBLY__ */
 
  #endif
arch/arm/kernel/head-common.S +3 -2
index 854bd22..2f560c5 100644
@@ -98,8 +98,9 @@ __mmap_switched:
  	str	r9, [r4]			@ Save processor ID
  	str	r1, [r5]			@ Save machine type
  	str	r2, [r6]			@ Save atags pointer
-	bic	r4, r0, #CR_A			@ Clear 'A' bit
-	stmia	r7, {r0, r4}			@ Save control register values
+	cmp	r7, #0
+	bicne	r4, r0, #CR_A			@ Clear 'A' bit
+	stmneia	r7, {r0, r4}			@ Save control register values
  	b	start_kernel
  ENDPROC(__mmap_switched)
 

arch/arm/kernel/head-common.S __mmap_switched_data: · line 120

Quoted 7 lines
arch/arm/kernel/head-common.S +3 -0
@@ -113,7 +114,11 @@ __mmap_switched_data:
  	.long	processor_id			@ r4
  	.long	__machine_arch_type		@ r5
  	.long	__atags_pointer			@ r6
+#ifdef CONFIG_CPU_CP15
  	.long	cr_alignment			@ r7
+#else
+	.long	0

This value still gets loaded in to r7, so it might be worth keeping the comments going... They certainly help when reading the code.

Quoted 36 lines
arch/arm/kernel/head-common.S +1 -0
+#endif
  	.long	init_thread_union + THREAD_START_SP @ sp
  	.size	__mmap_switched_data, . - __mmap_switched_data
 
arch/arm/mm/alignment.c +2 -0
index b9f60eb..5748094 100644
@@ -962,12 +962,14 @@ static int __init alignment_init(void)
  		return -ENOMEM;
  #endif
 
+#ifdef CONFIG_CPU_CP15
  	if (cpu_is_v6_unaligned()) {
  		cr_alignment &= ~CR_A;
  		cr_no_alignment &= ~CR_A;
  		set_cr(cr_alignment);
  		ai_usermode = safe_usermode(ai_usermode, false);
  	}
+#endif
 
  	hook_fault_code(FAULT_CODE_ALIGNMENT, do_alignment, SIGBUS, BUS_ADRALN,
  			"alignment exception");
arch/arm/mm/mmu.c +1 -0
index 941dfb9..b675918 100644
@@ -97,6 +97,7 @@ static struct cachepolicy cache_policies[] __initdata = {
  	}
  };
 
+#ifdef CONFIG_CPU_CP15
  /*
   * These are useful for identifying cache coherency
   * problems by allowing the cache or the cache and

arch/arm/mm/mmu.c void adjust_cr(unsigned long mask, unsigned long set) · line 199

Quoted 4 lines
arch/arm/mm/mmu.c +1 -0
@@ -195,6 +196,22 @@ void adjust_cr(unsigned long mask, unsigned long set)
  }
  #endif
 
+#else

When you read this file in its complete form there's a lot of code (including more preprocessor stuff) between the #ifdef and the #else.

Could you add

#else /* ifdef CONFIG_CPU_CP15 */

like you have in the other cases?

Jonny

#3 lore raw

PATCH v7 1/3 ARM: make cr_alignment read-only #ifndef CONFIG_CPU_CP15

Hello Jonny,

Quoted 17 lines · Jonathan Austin
Quoted 5 lines · Uwe Kleine-K?nig

This makes cr_alignment a constant 0 to break code that tries to modify the value as it's likely that it's built on wrong assumption when CONFIG_CPU_CP15 isn't defined. For code that is only reading the value 0 is more or less a fine value to report.

Without the context of some of the discussion that was had on the list about how/why to do this, this description is a bit confusing...

I found myself asking "Why do we not #ifdef out uses of cr_alignment based on CONFIG_CPU_CP15" - a question which it seems is answered by you and Nicolas here:

http://lists.infradead.org/pipermail/linux-arm-kernel/2012-March/089968.html

Quoted 8 lines

So, perhaps it would help to have a little bit more context in this commit message?

I know that the cr_alignment stuff is currently tied up with CONFIG_CPU_15, but I wonder if you looked at using the CCR.UNALIGN_TRP bit and wiring that in to alignment trapping code? Is it something you think would make sense for the work you're doing?

I didn't, because I focus on getting the machine up and add bells and whistles later.

Quoted 7 lines

arch/arm/kernel/head-common.S __mmap_switched_data: · line 120

Quoted 4 lines
arch/arm/kernel/head-common.S +3 -0
+#ifdef CONFIG_CPU_CP15
 	.long	cr_alignment			@ r7
+#else
+	.long	0

This value still gets loaded in to r7, so it might be worth keeping the comments going... They certainly help when reading the code.

ok

Quoted 20 lines
Quoted 11 lines
arch/arm/mm/mmu.c +1 -0
@@ -97,6 +97,7 @@ static struct cachepolicy cache_policies[] __initdata = {
 	}
 };
 
+#ifdef CONFIG_CPU_CP15
 /*
  * These are useful for identifying cache coherency
  * problems by allowing the cache or the cache and

arch/arm/mm/mmu.c void adjust_cr(unsigned long mask, unsigned long set) · line 199

Quoted 4 lines
arch/arm/mm/mmu.c +1 -0
@@ -195,6 +196,22 @@ void adjust_cr(unsigned long mask, unsigned long set)
 }
 #endif
 
+#else

When you read this file in its complete form there's a lot of code (including more preprocessor stuff) between the #ifdef and the #else.

Quoted 5 lines

Could you add

#else /* ifdef CONFIG_CPU_CP15 */

like you have in the other cases?

also ok.

Will fix up after lunch.

Best regards
Uwe

Signature · 2 lines
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
#4 lore raw

PATCH v7 2/3 Cortex-M3: Add base support for Cortex-M3

In reply to Uwe Kleine-König

From: Catalin Marinas <[email protected]>

This patch adds the base support for the Cortex-M3 processor (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]

---
changes since v6:
- trivially rebased on v3.7-rc1

 arch/arm/include/asm/assembler.h   |   13 ++-
 arch/arm/include/asm/cputype.h     |    3 +
 arch/arm/include/asm/glue-cache.h  |   25 ++++++
 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/processor.h   |    7 ++
 arch/arm/include/asm/ptrace.h      |    8 ++
 arch/arm/include/asm/system_info.h |    1 +
 arch/arm/include/uapi/asm/ptrace.h |   36 ++++++--
 arch/arm/kernel/asm-offsets.c      |    3 +
 arch/arm/kernel/head-nommu.S       |    9 +-
 arch/arm/kernel/setup.c            |   13 ++-
 arch/arm/kernel/traps.c            |    2 +
 arch/arm/mm/nommu.c                |    2 +
 arch/arm/mm/proc-v7m.S             |  161 ++++++++++++++++++++++++++++++++++++
 16 files changed, 303 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm/mm/proc-v7m.S
arch/arm/include/asm/assembler.h +12 -1
index 2ef9581..ab7c02c 100644
@@ -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,10 @@
 #endif
 	.endm
 
-#ifdef CONFIG_THUMB2_KERNEL
+#if defined(CONFIG_CPU_V7M)
+	.macro	setmode, mode, reg
+	.endm
+#elif defined(CONFIG_THUMB2_KERNEL)
 	.macro	setmode, mode, reg
 	mov	\reg, #\mode
 	msr	cpsr_c, \reg
arch/arm/include/asm/cputype.h +3 -0
index cb47d28..5bd8cb6 100644
@@ -46,6 +46,9 @@ extern unsigned int processor_id;
 		    : "cc");						\
 		__val;							\
 	})
+#elif defined(CONFIG_CPU_V7M)
+#define read_cpuid(reg) (*(unsigned int *)0xe000ed00)
+#define read_cpuid_ext(reg) 0
 #else
 #define read_cpuid(reg) (processor_id)
 #define read_cpuid_ext(reg) 0
arch/arm/include/asm/glue-cache.h +25 -0
index cca9f15..ea98658 100644
@@ -125,10 +125,35 @@
 # endif
 #endif
 
+#if defined(CONFIG_CPU_V7M)
+# ifdef _CACHE
+#  error "Multi-cache not supported on ARMv7-M"
+# else
+#  define _CACHE nop
+# endif
+#endif
+
 #if !defined(_CACHE) && !defined(MULTI_CACHE)
 #error Unknown cache maintenance model
 #endif
 
+#ifndef __ASSEMBLER__
+static inline void nop_flush_icache_all(void) { }
+static inline void nop_flush_kern_cache_all(void) { }
+static inline void nop_flush_kern_cache_louis(void) { }
+static inline void nop_flush_user_cache_all(void) { }
+static inline void nop_flush_user_cache_range(unsigned long a, unsigned long b, unsigned int c) { }
+
+static inline void nop_coherent_kern_range(unsigned long a, unsigned long b) { }
+static inline int nop_coherent_user_range(unsigned long a, unsigned long b) { return 0; }
+static inline void nop_flush_kern_dcache_area(void *a, size_t s) { }
+
+static inline void nop_dma_flush_range(const void *a, const void *b) { }
+
+static inline void nop_dma_map_area(const void *s, size_t l, int f) { }
+static 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)
arch/arm/include/asm/glue-df.h +8 -0
index 8cacbcd..1f2339c 100644
@@ -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
arch/arm/include/asm/glue-proc.h +9 -0
index ac1dd54..f2f39bc 100644
@@ -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)
arch/arm/include/asm/irqflags.h +16 -6
index 1e6cca5..3b763d6 100644
@@ -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 */
arch/arm/include/asm/processor.h +7 -0
index 06e7d50..5e61b88 100644
@@ -49,7 +49,14 @@ struct thread_struct {
 #ifdef CONFIG_MMU
 #define nommu_start_thread(regs) do { } while (0)
 #else
+#ifndef CONFIG_CPU_V7M
 #define nommu_start_thread(regs) regs->ARM_r10 = current->mm->start_data
+#else
+#define nommu_start_thread(regs) do {					\
+	regs->ARM_r10 = current->mm->start_data;			\
+	regs->ARM_EXC_RET = 0xfffffffdL;				\
+} while (0)
+#endif
 #endif
 
 #define start_thread(regs,pc,sp)					\
arch/arm/include/asm/ptrace.h +8 -0
index 3d52ee1..67661e8 100644
@@ -14,7 +14,11 @@
 
 #ifndef __ASSEMBLY__
 struct pt_regs {
+#ifdef CONFIG_CPU_V7M
+	unsigned long uregs[20];
+#else
 	unsigned long uregs[18];
+#endif
 };
 
 #define user_mode(regs)	\
@@ -45,6 +49,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 +72,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)
arch/arm/include/asm/system_info.h +1 -0
index dfd386d..720ea03 100644
@@ -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__
 
arch/arm/include/uapi/asm/ptrace.h +28 -8
index 96ee092..2ae7d1b 100644
@@ -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
@@ -125,6 +144,7 @@ struct pt_regs {
 #define ARM_r1		uregs[1]
 #define ARM_r0		uregs[0]
 #define ARM_ORIG_r0	uregs[17]
+#define ARM_EXC_RET    uregs[18]
 
 /*
  * The size of the user-visible VFP state as seen by PTRACE_GET/SETVFPREGS
arch/arm/kernel/asm-offsets.c +3 -0
index c985b48..5fe9ace 100644
@@ -93,6 +93,9 @@ int main(void)
   DEFINE(S_PC,			offsetof(struct pt_regs, ARM_pc));
   DEFINE(S_PSR,			offsetof(struct pt_regs, ARM_cpsr));
   DEFINE(S_OLD_R0,		offsetof(struct pt_regs, ARM_ORIG_r0));
+#ifdef CONFIG_CPU_V7M
+  DEFINE(S_EXC_RET,		offsetof(struct pt_regs, ARM_EXC_RET));
+#endif
   DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
   BLANK();
 #ifdef CONFIG_CACHE_L2X0
arch/arm/kernel/head-nommu.S +6 -3
index 278cfc1..c391c05 100644
@@ -44,10 +44,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, =0xe000ed00			@ CPUID register address
+	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)?
arch/arm/kernel/setup.c +12 -1
index da1d1aa..3cca0c8 100644
@@ -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)
 {
@@ -375,6 +384,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];
 
@@ -419,6 +429,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];
arch/arm/kernel/traps.c +2 -0
index b0179b8..12d976b 100644
@@ -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
 }
arch/arm/mm/nommu.c +2 -0
index d51225f..4bc8ae5 100644
@@ -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)
arch/arm/mm/proc-v7m.S new file +161 -0

161 lines not on this page · raw message

Signature · 1 line
1.7.10.4
#5 lore raw

PATCH v7 3/3 Cortex-M3: Add support for exception handling

In reply to Uwe Kleine-König

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.

---
Changes since v6:
- not so trivially rebased on v3.7-rc1 because of Al Viro's kernel_execve patches

 arch/arm/kernel/entry-common.S |    4 ++
 arch/arm/kernel/entry-header.S |  148 ++++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/entry-v7m.S    |  134 ++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/process.c      |    4 ++
 arch/arm/kernel/ptrace.c       |    3 +
 5 files changed, 293 insertions(+)
 create mode 100644 arch/arm/kernel/entry-v7m.S
arch/arm/kernel/entry-common.S +4 -0
index 3471175..48d8dc0 100644
@@ -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
 
 	/*
arch/arm/kernel/entry-header.S +148 -0

166 lines not on this page · raw message

arch/arm/kernel/entry-v7m.S new file +134 -0

134 lines not on this page · raw message

arch/arm/kernel/process.c +4 -0
index 90084a6..3d745d4 100644
@@ -387,6 +387,10 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
 		*childregs = *regs;
 		childregs->ARM_r0 = 0;
 		childregs->ARM_sp = stack_start;
+#if defined CONFIG_CPU_V7M
+		/* Return to Thread mode with Process stack */
+		childregs->ARM_EXC_RET = 0xfffffffdUL;
+#endif
 	} else {
 		memset(childregs, 0, sizeof(struct pt_regs));
 		thread->cpu_context.r4 = stk_sz;
arch/arm/kernel/ptrace.c +3 -0
index 739db3a..55df1d5 100644
@@ -87,6 +87,9 @@ static const struct pt_regs_offset regoffset_table[] = {
 	REG_OFFSET_NAME(pc),
 	REG_OFFSET_NAME(cpsr),
 	REG_OFFSET_NAME(ORIG_r0),
+#ifdef CONFIG_CPU_V7M
+	REG_OFFSET_NAME(EXC_RET),
+#endif
 	REG_OFFSET_END,
 };
 
Signature · 1 line
1.7.10.4
#6 lore raw

PATCH v7 3/3 Cortex-M3: Add support for exception handling

Hello,

Quoted 14 lines · Uwe Kleine-K?nig
arch/arm/kernel/entry-v7m.S new file +14 -0
+/*
+ * 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

arch/arm/kernel/entry-v7m.S line 108

Quoted 10 lines
arch/arm/kernel/entry-v7m.S new file +10 -0
+	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], #4
+	ldr	pc, [ip]
+	.fnend
+ENDPROC(__switch_to)

this code triggers a warning

This instruction may be unpredictable if executed on M-profile cores with interrupts enabled.

with newer toolchains (seen with gcc 4.7.2) because of errata 752419 (Interrupted loads to SP can cause erroneous behaviour) which badly affects the following instructions:

	ldr	sp,[Rn],#imm
	ldr	sp,[Rn,#imm]!

I think it's not a problem here as irqs are off during task switching, but when changing

	ldr	sp, [ip], #4
	ldr	pc, [ip]

to

	ldr	sp, [ip]
	ldr	pc, [ip, #4]!

the result is equivalent and gcc is happy.

I fixed that accordingly in my for-next branch.

Best regards
Uwe

Signature · 2 lines
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
#7 lore raw

PATCH v7 3/3 Cortex-M3: Add support for exception handling

Quoted 32 lines · Uwe Kleine-K?nig

Hello,

Quoted 14 lines · Uwe Kleine-K?nig
arch/arm/kernel/entry-v7m.S new file +14 -0
+/*
+ * 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

arch/arm/kernel/entry-v7m.S line 108

Quoted 10 lines
arch/arm/kernel/entry-v7m.S new file +10 -0
+	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], #4
+	ldr	pc, [ip]
+	.fnend
+ENDPROC(__switch_to)

this code triggers a warning

This instruction may be unpredictable if executed on M-profile cores with interrupts enabled.

Quoted 6 lines

with newer toolchains (seen with gcc 4.7.2) because of errata 752419 (Interrupted loads to SP can cause erroneous behaviour) which badly affects the following instructions:

	ldr	sp,[Rn],#imm
	ldr	sp,[Rn,#imm]!

Wonder if that means we need to fix it in entry-armv.S too, as it uses the same sequence for Thumb:

 THUMB( ldr     sp, [ip], #4               )
 THUMB( ldr     pc, [ip]                   )

and, of course, M-profile stuff is also Thumb.

#8 lore raw

PATCH v7 3/3 Cortex-M3: Add support for exception handling

Hello Russell,

Quoted 40 lines · Russell King - ARM Linux
Quoted 32 lines · Uwe Kleine-K?nig

Hello,

Quoted 14 lines · Uwe Kleine-K?nig
arch/arm/kernel/entry-v7m.S new file +14 -0
+/*
+ * 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

arch/arm/kernel/entry-v7m.S line 108

Quoted 10 lines
arch/arm/kernel/entry-v7m.S new file +10 -0
+	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], #4
+	ldr	pc, [ip]
+	.fnend
+ENDPROC(__switch_to)

this code triggers a warning

This instruction may be unpredictable if executed on M-profile cores with interrupts enabled.

Quoted 6 lines

with newer toolchains (seen with gcc 4.7.2) because of errata 752419 (Interrupted loads to SP can cause erroneous behaviour) which badly affects the following instructions:

	ldr	sp,[Rn],#imm
	ldr	sp,[Rn,#imm]!
Quoted 7 lines

Wonder if that means we need to fix it in entry-armv.S too, as it uses the same sequence for Thumb:

 THUMB( ldr     sp, [ip], #4               )
 THUMB( ldr     pc, [ip]                   )

and, of course, M-profile stuff is also Thumb.

entry-armv.S is not affected as this code snipplet is for switching from ARM to THUMB mode on kernel entry. The M-profile CPUs don't have a ARM mode, so this code isn't active for them anyhow. (I have a patch in my queue to allow entry in Thumb mode for thumb-only CPUs.)

Best regards and thanks for your heedfulness,
Uwe

Signature · 2 lines
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
#9 lore raw

PATCH v7 3/3 Cortex-M3: Add support for exception handling

Hello Russell,

Quoted 44 lines · Uwe Kleine-K?nig
Quoted 43 lines · Russell King - ARM Linux
Quoted 32 lines · Uwe Kleine-K?nig

Hello,

Quoted 14 lines · Uwe Kleine-K?nig
arch/arm/kernel/entry-v7m.S new file +14 -0
+/*
+ * 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

arch/arm/kernel/entry-v7m.S line 108

Quoted 10 lines
arch/arm/kernel/entry-v7m.S new file +10 -0
+	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], #4
+	ldr	pc, [ip]
+	.fnend
+ENDPROC(__switch_to)

this code triggers a warning

This instruction may be unpredictable if executed on M-profile cores with interrupts enabled.

Quoted 6 lines

with newer toolchains (seen with gcc 4.7.2) because of errata 752419 (Interrupted loads to SP can cause erroneous behaviour) which badly affects the following instructions:

	ldr	sp,[Rn],#imm
	ldr	sp,[Rn,#imm]!

Wonder if that means we need to fix it in entry-armv.S too, as it uses the same sequence for Thumb:

Quoted 8 lines
Quoted 4 lines
 THUMB( ldr     sp, [ip], #4               )
 THUMB( ldr     pc, [ip]                   )

and, of course, M-profile stuff is also Thumb.

entry-armv.S is not affected as this code snipplet is for switching from ARM to THUMB mode on kernel entry. The M-profile CPUs don't have a ARM mode, so this code isn't active for them anyhow. (I have a patch in my queue to allow entry in Thumb mode for thumb-only CPUs.)

This is wrong, it's not in initial switching to Thumb mode but in __switch_to. Still this code isn't used for Cortex-M3 CPUs.

Best regards
Uwe

Signature · 2 lines
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
#10 lore raw

v7 cover Yet another update for the Cortex-M3 series

In reply to Uwe Kleine-König

Hello Russell,

Quoted 15 lines · Uwe Kleine-K?nig

the only change since v6 is a rebase on top of v3.7-rc1 and so on Al Viro's changes to kernel_execve().

These patches merge just fine into today's next and I put them into my branch that Stephen will pick for the next next.

As before this doesn't make a functional M3 port as there are still some missing items. If you want to see the code live I also updated the efm32 branch in my repository to be based on these patches. This code works, but isn't suitable for mainline yet. You can run it on EnergyMicro's efm32 devboard.

Best regards
Uwe

Quoted 6 lines

Catalin Marinas (1):
Cortex-M3: Add base support for Cortex-M3

Uwe Kleine-K?nig (2):
ARM: make cr_alignment read-only #ifndef CONFIG_CPU_CP15
Cortex-M3: Add support for exception handling

These patches are in next since next-20121018 without any reported problems. What do you think about inclusion for 3.9-rc1?

They are based on 3.7-rc1 and I'm currently porting my tree to 3.8-rc3 to test there.

Best regards
Uwe

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