mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 00:21:32 +00:00
Merge branch 'for-next' of git://git.pengutronix.de/git/ukl/linux into devel-stable
Pull ARM-v7M support from Uwe Kleine-König:
"All but the last patch were in next since next-20130418 without issues.
The last patch fixes a problem in combination with
8164f7a
(ARM: 7680/1: Detect support for SDIV/UDIV from ISAR0 register)
which triggers a WARN_ON without an implemented read_cpuid_ext.
The branch merges fine into v3.10-rc1 and I'd be happy if you pulled it
for 3.11-rc1. The only missing piece to be able to run a Cortex-M3 is
the irqchip driver that will go in via Thomas Gleixner and platform
specific stuff."
This commit is contained in:
commit
f150abe101
@ -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
|
||||
@ -1585,7 +1585,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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -10,6 +10,22 @@
|
||||
#define CPUID_TLBTYPE 3
|
||||
#define CPUID_MPIDR 5
|
||||
|
||||
#ifdef CONFIG_CPU_V7M
|
||||
#define CPUID_EXT_PFR0 0x40
|
||||
#define CPUID_EXT_PFR1 0x44
|
||||
#define CPUID_EXT_DFR0 0x48
|
||||
#define CPUID_EXT_AFR0 0x4c
|
||||
#define CPUID_EXT_MMFR0 0x50
|
||||
#define CPUID_EXT_MMFR1 0x54
|
||||
#define CPUID_EXT_MMFR2 0x58
|
||||
#define CPUID_EXT_MMFR3 0x5c
|
||||
#define CPUID_EXT_ISAR0 0x60
|
||||
#define CPUID_EXT_ISAR1 0x64
|
||||
#define CPUID_EXT_ISAR2 0x68
|
||||
#define CPUID_EXT_ISAR3 0x6c
|
||||
#define CPUID_EXT_ISAR4 0x70
|
||||
#define CPUID_EXT_ISAR5 0x74
|
||||
#else
|
||||
#define CPUID_EXT_PFR0 "c1, 0"
|
||||
#define CPUID_EXT_PFR1 "c1, 1"
|
||||
#define CPUID_EXT_DFR0 "c1, 2"
|
||||
@ -24,6 +40,7 @@
|
||||
#define CPUID_EXT_ISAR3 "c2, 3"
|
||||
#define CPUID_EXT_ISAR4 "c2, 4"
|
||||
#define CPUID_EXT_ISAR5 "c2, 5"
|
||||
#endif
|
||||
|
||||
#define MPIDR_SMP_BITMASK (0x3 << 30)
|
||||
#define MPIDR_SMP_VALUE (0x2 << 30)
|
||||
@ -79,7 +96,23 @@ extern unsigned int processor_id;
|
||||
__val; \
|
||||
})
|
||||
|
||||
#else /* ifdef CONFIG_CPU_CP15 */
|
||||
#elif defined(CONFIG_CPU_V7M)
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/v7m.h>
|
||||
|
||||
#define read_cpuid(reg) \
|
||||
({ \
|
||||
WARN_ON_ONCE(1); \
|
||||
0; \
|
||||
})
|
||||
|
||||
static inline unsigned int __attribute_const__ read_cpuid_ext(unsigned offset)
|
||||
{
|
||||
return readl(BASEADDR_V7M_SCB + offset);
|
||||
}
|
||||
|
||||
#else /* ifdef CONFIG_CPU_CP15 / elif defined (CONFIG_CPU_V7M) */
|
||||
|
||||
/*
|
||||
* read_cpuid and read_cpuid_ext should only ever be called on machines that
|
||||
@ -106,7 +139,14 @@ 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)
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -117,10 +117,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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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__
|
||||
|
||||
|
44
arch/arm/include/asm/v7m.h
Normal file
44
arch/arm/include/asm/v7m.h
Normal file
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -350,6 +350,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 )
|
||||
@ -360,6 +363,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
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
@ -165,6 +276,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
|
||||
@ -181,6 +304,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
|
||||
|
143
arch/arm/kernel/entry-v7m.S
Normal file
143
arch/arm/kernel/entry-v7m.S
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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
|
||||
sub r0, #16
|
||||
mov r1, sp
|
||||
stmdb sp!, {lr}
|
||||
@ routine called with r0 = irq number, r1 = struct pt_regs *
|
||||
bl nvic_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
|
@ -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)?
|
||||
|
@ -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 */
|
||||
@ -392,6 +403,7 @@ static void __init feat_v6_fixup(void)
|
||||
*/
|
||||
void notrace cpu_init(void)
|
||||
{
|
||||
#ifndef CONFIG_CPU_V7M
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct stack *stk = &stacks[cpu];
|
||||
|
||||
@ -442,6 +454,7 @@ void notrace 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];
|
||||
|
@ -812,6 +812,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[];
|
||||
@ -843,4 +844,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
|
||||
}
|
||||
|
@ -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
|
||||
@ -491,6 +503,9 @@ config CPU_CACHE_V6
|
||||
config CPU_CACHE_V7
|
||||
bool
|
||||
|
||||
config CPU_CACHE_NOP
|
||||
bool
|
||||
|
||||
config CPU_CACHE_VIVT
|
||||
bool
|
||||
|
||||
@ -613,7 +628,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
|
||||
|
@ -39,6 +39,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
|
||||
@ -87,6 +88,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
|
||||
|
50
arch/arm/mm/cache-nop.S
Normal file
50
arch/arm/mm/cache-nop.S
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 "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
|
@ -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)
|
||||
|
157
arch/arm/mm/proc-v7m.S
Normal file
157
arch/arm/mm/proc-v7m.S
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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>
|
||||
#include "proc-macros.S"
|
||||
|
||||
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)
|
||||
|
||||
.globl cpu_v7m_suspend_size
|
||||
.equ cpu_v7m_suspend_size, 0
|
||||
|
||||
#ifdef CONFIG_ARM_CPU_SUSPEND
|
||||
ENTRY(cpu_v7m_do_suspend)
|
||||
mov pc, lr
|
||||
ENDPROC(cpu_v7m_do_suspend)
|
||||
|
||||
ENTRY(cpu_v7m_do_resume)
|
||||
mov pc, lr
|
||||
ENDPROC(cpu_v7m_do_resume)
|
||||
#endif
|
||||
|
||||
.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)
|
||||
|
||||
define_processor_functions v7m, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1
|
||||
|
||||
.section ".rodata"
|
||||
string cpu_arch_name, "armv7m"
|
||||
string cpu_elf_name "v7m"
|
||||
string cpu_v7m_name "ARMv7-M"
|
||||
|
||||
.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
|
||||
.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:
|
Loading…
Reference in New Issue
Block a user