From 053d9d0f117f5b3112eb17f2224b36447abbdc5c Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 23 Jun 2009 18:16:03 +0100 Subject: Cortex-M3: Add base support for Cortex-M3 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. Signed-off-by: Catalin Marinas --- arch/arm/boot/compressed/head.S | 18 ++-- arch/arm/include/asm/assembler.h | 13 ++- arch/arm/include/asm/cacheflush.h | 24 +++++ arch/arm/include/asm/cputype.h | 2 + arch/arm/include/asm/glue.h | 8 ++ arch/arm/include/asm/irqflags.h | 41 +++++++++ arch/arm/include/asm/proc-fns.h | 8 ++ arch/arm/include/asm/processor.h | 10 ++- arch/arm/include/asm/ptrace.h | 38 +++++++- arch/arm/include/asm/system.h | 3 + arch/arm/kernel/armksyms.c | 4 + arch/arm/kernel/asm-offsets.c | 4 + arch/arm/kernel/head-common.S | 4 + arch/arm/kernel/head-nommu.S | 9 +- arch/arm/kernel/setup.c | 15 ++++ arch/arm/kernel/signal.c | 2 + arch/arm/kernel/traps.c | 2 + arch/arm/lib/backtrace.S | 2 +- arch/arm/mm/abort-ev7m.S | 9 ++ arch/arm/mm/nommu.c | 2 + arch/arm/mm/proc-v7m.S | 184 ++++++++++++++++++++++++++++++++++++++ 21 files changed, 390 insertions(+), 12 deletions(-) create mode 100644 arch/arm/mm/abort-ev7m.S create mode 100644 arch/arm/mm/proc-v7m.S (limited to 'arch') diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index c7b8109fb412..6e20b2ed0c1f 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -130,6 +130,7 @@ start: 1: mov r7, r1 @ save architecture ID mov r8, r2 @ save atags pointer +#ifndef CONFIG_CPU_V7M #ifndef __ARM_ARCH_2__ /* * Booting from Angel - need to enter SVC mode and disable @@ -148,6 +149,7 @@ not_angel: msr cpsr_c, r2 #else teqp pc, #0x0c000003 @ turn off interrupts +#endif #endif /* @@ -568,16 +570,20 @@ call_kernel: bl cache_clean_flush * r12 = corrupted */ -call_cache_fn: adr r12, proc_types +call_cache_fn: + adr r12, proc_types #ifdef CONFIG_CPU_CP15 mrc p15, 0, r6, c0, c0 @ get processor ID +#elif defined(CONFIG_CPU_V7M) + ldr r6, =0xe000ed00 @ CPUID register address + ldr r6, [r6] #else ldr r6, =CONFIG_PROCESSOR_ID #endif -1: ldr r1, [r12, #0] @ get value - ldr r2, [r12, #4] @ get mask - eor r1, r1, r6 @ (real ^ match) - tst r1, r2 @ & mask +1: ldr r2, [r12, #4] @ get mask + ldr r1, [r12, #0] @ get value + and r2, r6, r2 @ keep the relevant bits + teq r1, r2 @ match with the value itt eq ARM( addeq pc, r12, r3 ) @ call cache function THUMB( addeq r12, r3 ) @@ -702,11 +708,13 @@ proc_types: W(b) __armv4_mmu_cache_off W(b) __armv6_mmu_cache_flush +#ifndef CONFIG_CPU_V7M .word 0x000f0000 @ new CPU Id .word 0x000f0000 W(b) __armv7_mmu_cache_on W(b) __armv7_mmu_cache_off W(b) __armv7_mmu_cache_flush +#endif .word 0 @ unrecognised type .word 0 diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 550cdcfb1f1c..2539d254caa7 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -96,7 +96,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 @@ -105,7 +109,11 @@ * guarantee that this will preserve the flags. */ .macro restore_irqs, oldcpsr +#ifdef CONFIG_CPU_V7M + msr primask, \oldcpsr +#else msr cpsr_c, \oldcpsr +#endif .endm #define USER(x...) \ @@ -115,7 +123,10 @@ .long 9999b,9001f; \ .previous -#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 diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index a8076bfdead4..91aec141aa15 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -115,6 +115,14 @@ //# endif #endif +#if defined(CONFIG_CPU_V7M) +# ifdef _CACHE +# error "Multi-cache not supported on ARMv7-M" +# else +# define _CACHE v7m +# endif +#endif + #if !defined(_CACHE) && !defined(MULTI_CACHE) #error Unknown cache maintainence model #endif @@ -235,6 +243,22 @@ extern struct cpu_cache_fns cpu_cache; #else +#ifdef CONFIG_CPU_V7M + +static inline void v7m_flush_kern_all(void) { } +static inline void v7m_flush_user_all(void) { } +static inline void v7m_flush_user_range(unsigned long a, unsigned long b, unsigned int c) { } + +static inline void v7m_coherent_kern_range(unsigned long a, unsigned long b) { } +static inline void v7m_coherent_user_range(unsigned long a, unsigned long b) { } +static inline void v7m_flush_kern_dcache_page(void *a) { } + +static inline void v7m_dma_inv_range(const void *a, const void *b) { } +static inline void v7m_dma_clean_range(const void *a, const void *b) { } +static inline void v7m_dma_flush_range(const void *a, const void *b) { } + +#endif + #define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all) #define __cpuc_flush_user_all __glue(_CACHE,_flush_user_cache_all) #define __cpuc_flush_user_range __glue(_CACHE,_flush_user_cache_range) diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index b3e656c6fb78..c2fe374fcb7f 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -42,6 +42,8 @@ : "cc"); \ __val; \ }) +#elif defined(CONFIG_CPU_V7M) +#define read_cpuid(reg) (*(unsigned int *)0xe000ed00) #else extern unsigned int processor_id; #define read_cpuid(reg) (processor_id) diff --git a/arch/arm/include/asm/glue.h b/arch/arm/include/asm/glue.h index a0e39d5d00c9..0a3bb3d8fab6 100644 --- a/arch/arm/include/asm/glue.h +++ b/arch/arm/include/asm/glue.h @@ -115,6 +115,14 @@ # endif #endif +#ifdef CONFIG_CPU_ABRT_EV7M +# ifdef CPU_DABORT_HANDLER +# define MULTI_DABORT 1 +# else +# define CPU_DABORT_HANDLER v7m_early_abort +# endif +#endif + #ifndef CPU_DABORT_HANDLER #error Unknown data abort handler type #endif diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h index 6d09974e6646..5dbb6de221ce 100644 --- a/arch/arm/include/asm/irqflags.h +++ b/arch/arm/include/asm/irqflags.h @@ -10,6 +10,15 @@ */ #if __LINUX_ARM_ARCH__ >= 6 +#ifdef CONFIG_CPU_V7M +#define raw_local_irq_save(x) \ + ({ \ + __asm__ __volatile__( \ + "mrs %0, primask @ local_irq_save\n" \ + "cpsid i" \ + : "=r" (x) : : "memory", "cc"); \ + }) +#else #define raw_local_irq_save(x) \ ({ \ __asm__ __volatile__( \ @@ -17,6 +26,7 @@ "cpsid i" \ : "=r" (x) : : "memory", "cc"); \ }) +#endif #define raw_local_irq_enable() __asm__("cpsie i @ __sti" : : : "memory", "cc") #define raw_local_irq_disable() __asm__("cpsid i @ __cli" : : : "memory", "cc") @@ -103,6 +113,35 @@ #endif +#ifdef CONFIG_CPU_V7M + +/* + * Save the current interrupt enable state. + */ +#define raw_local_save_flags(x) \ + ({ \ + __asm__ __volatile__( \ + "mrs %0, primask @ local_save_flags" \ + : "=r" (x) : : "memory", "cc"); \ + }) + +/* + * restore saved IRQ & FIQ state + */ +#define raw_local_irq_restore(x) \ + __asm__ __volatile__( \ + "msr primask, %0 @ local_irq_restore\n" \ + : \ + : "r" (x) \ + : "memory", "cc") + +#define raw_irqs_disabled_flags(flags) \ +({ \ + (int)((flags) & 1); \ +}) + +#else + /* * Save the current interrupt enable state. */ @@ -128,5 +167,7 @@ (int)((flags) & PSR_I_BIT); \ }) +#endif /* CONFIG_CPU_V7M */ + #endif #endif diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index db80203b68e0..d9faa2b32dfb 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h @@ -209,6 +209,14 @@ # define CPU_NAME cpu_v7 # endif # endif +# ifdef CONFIG_CPU_V7M +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME cpu_v7m +# endif +# endif #endif #ifndef __ASSEMBLY__ diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index 0b3478c3010d..64409f343381 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h @@ -57,7 +57,15 @@ 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_sp -= 32; /* exception return state */ \ + regs->ARM_EXC_lr = 0xfffffffdL; /* exception lr */ \ +} while (0) +#endif #endif #define start_thread(regs,pc,sp) \ @@ -72,7 +80,7 @@ struct thread_struct { if (elf_hwcap & HWCAP_THUMB && pc & 1) \ regs->ARM_cpsr |= PSR_T_BIT; \ regs->ARM_cpsr |= PSR_ENDSTATE; \ - regs->ARM_pc = pc & ~1; /* pc */ \ + regs->ARM_pc = pc /*& ~1*/; /* pc */ \ regs->ARM_sp = sp; /* sp */ \ regs->ARM_r2 = stack[2]; /* r2 (envp) */ \ regs->ARM_r1 = stack[1]; /* r1 (argv) */ \ diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index bbecccda76d0..1f7419c9fcc0 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -37,16 +37,25 @@ #define FIQ26_MODE 0x00000001 #define IRQ26_MODE 0x00000002 #define SVC26_MODE 0x00000003 +#ifndef CONFIG_CPU_V7M #define USR_MODE 0x00000010 +#define SVC_MODE 0x00000013 +#else +#define USR_MODE 0x00000000 +#define SVC_MODE 0x00000000 +#endif #define FIQ_MODE 0x00000011 #define IRQ_MODE 0x00000012 -#define SVC_MODE 0x00000013 #define ABT_MODE 0x00000017 #define UND_MODE 0x0000001b #define SYSTEM_MODE 0x0000001f #define MODE32_BIT 0x00000010 #define MODE_MASK 0x0000001f +#ifndef CONFIG_CPU_V7M #define PSR_T_BIT 0x00000020 +#else +#define PSR_T_BIT 0x01000000 +#endif #define PSR_F_BIT 0x00000040 #define PSR_I_BIT 0x00000080 #define PSR_A_BIT 0x00000100 @@ -101,6 +110,28 @@ struct pt_regs { long uregs[18]; }; +#ifdef CONFIG_CPU_V7M +/* Automatically saved registers */ +#define ARM_cpsr uregs[17] +#define ARM_pc uregs[16] +#define ARM_lr uregs[15] +#define ARM_ip uregs[14] +#define ARM_r3 uregs[13] +#define ARM_r2 uregs[12] +#define ARM_r1 uregs[11] +#define ARM_r0 uregs[10] +/* saved by the exception entry code */ +#define ARM_EXC_lr uregs[9] +#define ARM_sp uregs[8] +#define ARM_fp uregs[7] +#define ARM_r10 uregs[6] +#define ARM_r9 uregs[5] +#define ARM_r8 uregs[4] +#define ARM_r7 uregs[3] +#define ARM_r6 uregs[2] +#define ARM_r5 uregs[1] +#define ARM_r4 uregs[0] +#else #define ARM_cpsr uregs[16] #define ARM_pc uregs[15] #define ARM_lr uregs[14] @@ -119,6 +150,7 @@ struct pt_regs { #define ARM_r1 uregs[1] #define ARM_r0 uregs[0] #define ARM_ORIG_r0 uregs[17] +#endif #ifdef __KERNEL__ @@ -150,6 +182,7 @@ struct pt_regs { */ static inline int valid_user_regs(struct pt_regs *regs) { +#ifndef CONFIG_CPU_V7M if (user_mode(regs) && (regs->ARM_cpsr & PSR_I_BIT) == 0) { regs->ARM_cpsr &= ~(PSR_F_BIT | PSR_A_BIT); return 1; @@ -163,6 +196,9 @@ static inline int valid_user_regs(struct pt_regs *regs) regs->ARM_cpsr |= USR_MODE; return 0; +#else + return 1; +#endif } #define instruction_pointer(regs) (regs)->ARM_pc diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index a6367611cd70..4851e9d0eba5 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -15,6 +15,7 @@ #define CPU_ARCH_ARMv5TEJ 7 #define CPU_ARCH_ARMv6 8 #define CPU_ARCH_ARMv7 9 +#define CPU_ARCH_ARMv7M 10 /* * CR1 bits (CP#15 CR1) @@ -200,7 +201,9 @@ static inline void set_copro_access(unsigned int val) * so enable interrupts over the context switch to avoid high * latency. */ +#ifndef CONFIG_CPU_V7M #define __ARCH_WANT_INTERRUPTS_ON_CTXSW +#endif /* * switch_to(prev, next) should switch from task `prev' to `next' diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 23af3c972c9a..76e8b036306c 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -46,8 +46,10 @@ extern void __aeabi_uidiv(void); extern void __aeabi_uidivmod(void); extern void __aeabi_ulcmp(void); +#ifndef CONFIG_CPU_V7M extern void fpundefinstr(void); extern void fp_enter(void); +#endif /* * This has a special calling convention; it doesn't @@ -65,7 +67,9 @@ extern void fp_enter(void); * floating point math emulator support. * These symbols will never change their calling convention... */ +#ifndef CONFIG_CPU_V7M EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter); +#endif EXPORT_SYMBOL_ALIAS(fp_printk,printk); EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig); diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 4a881258bb17..009c1a126c05 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -79,7 +79,11 @@ int main(void) DEFINE(S_LR, offsetof(struct pt_regs, ARM_lr)); DEFINE(S_PC, offsetof(struct pt_regs, ARM_pc)); DEFINE(S_PSR, offsetof(struct pt_regs, ARM_cpsr)); +#ifdef CONFIG_CPU_V7M + DEFINE(S_EXC_LR, offsetof(struct pt_regs, ARM_EXC_lr)); +#else DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0)); +#endif DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); BLANK(); #ifdef CONFIG_CPU_HAS_ASID diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index b409417e6110..1b6a85751b8c 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S @@ -25,7 +25,11 @@ __switch_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 @ r7 +#endif .long init_thread_union + THREAD_START_SP @ sp /* diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index e5dfc2895e24..07a0fa7bb7bd 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -36,10 +36,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)? diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 4ae74ae59f9c..e38ca7038168 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -198,6 +198,12 @@ static const char *proc_arch[] = { "?(17)", }; +#ifdef CONFIG_CPU_V7M +int cpu_architecture(void) +{ + return CPU_ARCH_ARMv7M; +} +#else int cpu_architecture(void) { int cpu_arch; @@ -230,6 +236,7 @@ int cpu_architecture(void) return cpu_arch; } +#endif EXPORT_SYMBOL(cpu_architecture); static void __init cacheid_init(void) @@ -299,9 +306,15 @@ static void __init setup_processor(void) cpu_cache = *list->cache; #endif +#ifdef CONFIG_CPU_V7M + printk("CPU: %s [%08x] revision %d (ARMv%sM)\n", + cpu_name, processor_id, (int)processor_id & 15, + proc_arch[cpu_architecture()]); +#else printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", cpu_name, read_cpuid_id(), read_cpuid_id() & 15, proc_arch[cpu_architecture()], cr_alignment); +#endif sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); @@ -339,6 +352,7 @@ void cpu_init(void) #define PLC "I" #endif +#ifndef CONFIG_CPU_V7M /* * setup stacks for re-entrant exception handlers */ @@ -363,6 +377,7 @@ void cpu_init(void) "I" (offsetof(struct stack, und[0])), PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) : "r14"); +#endif } static struct machine_desc * __init setup_machine(unsigned int nr) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 442b87476f97..48487cc8284d 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -538,7 +538,9 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, static inline void restart_syscall(struct pt_regs *regs) { +#ifndef CONFIG_CPU_V7M regs->ARM_r0 = regs->ARM_ORIG_r0; +#endif regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; } diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 219fc282f3bf..6977342aa139 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -729,6 +729,7 @@ void __init trap_init(void) void __init early_trap_init(void) { +#ifndef CONFIG_CPU_V7M unsigned long vectors = CONFIG_VECTORS_BASE; extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; @@ -753,4 +754,5 @@ void __init early_trap_init(void) flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); +#endif } diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S index 42e62dd54188..41c4d3561b8f 100644 --- a/arch/arm/lib/backtrace.S +++ b/arch/arm/lib/backtrace.S @@ -28,7 +28,7 @@ ENTRY(__backtrace) ENTRY(c_backtrace) -#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) +#if defined(CONFIG_THUMB2_KERNEL) || !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) mov pc, lr ENDPROC(__backtrace) ENDPROC(c_backtrace) diff --git a/arch/arm/mm/abort-ev7m.S b/arch/arm/mm/abort-ev7m.S new file mode 100644 index 000000000000..083e85b27850 --- /dev/null +++ b/arch/arm/mm/abort-ev7m.S @@ -0,0 +1,9 @@ +#include +#include +/* + * Function: v7m_early_abort + */ + .align 5 +ENTRY(v7m_early_abort) + mov pc, lr +ENDPROC(v7m_early_abort) diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index fd26a44e9f33..869e4ef5bed0 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -33,6 +33,7 @@ void __init reserve_node_zero(pg_data_t *pgdat) BOOTMEM_DEFAULT); #endif +#ifndef CONFIG_CPU_V7M /* * Register the exception vector page. * some architectures which the DRAM is the exception vector to trap, @@ -40,6 +41,7 @@ void __init reserve_node_zero(pg_data_t *pgdat) */ reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE, BOOTMEM_DEFAULT); +#endif } static void __init sanity_check_meminfo(struct meminfo *mi) diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S new file mode 100644 index 000000000000..ff97c011ae60 --- /dev/null +++ b/arch/arm/mm/proc-v7m.S @@ -0,0 +1,184 @@ +/* + * 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 +#include + +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 + * + * It is assumed that: + */ + .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) + +/* + * cpu_v7m_switch_mm(pgd_phys, tsk) + * + * Set the translation table base pointer to be pgd_phys + * + * - pgd_phys - physical address of new TTB + * + * It is assumed that: + * - we are not using split page tables + */ +ENTRY(cpu_v7m_switch_mm) + mov pc, lr +ENDPROC(cpu_v7m_switch_mm) + +ENTRY(cpu_v7m_set_pte_ext) + mov pc, lr +ENDPROC(cpu_v7m_set_pte_ext) + +cpu_v7m_name: + .ascii "ARMv7-M Processor" + .align + + .section ".text.init", #alloc, #execinstr + +/* + * __v7m_setup + * + * Initialise TLB, Caches, and MMU state ready to switch the MMU + * on. Return in r0 the new CP15 C1 control register setting. + * + * We automatically detect if we have a Harvard cache, and use the + * Harvard cache control instructions insead of the unified cache + * control instructions. + * + * This should be able to cover all ARMv7-M cores. + * + * It is assumed that: + * - cache type register is implemented + */ +__v7m_setup: + @ Configure the vector table base address + ldr r0, =0xe000ed08 @ vector table base address + ldr r12, =vector_table + str r12, [r0] + + @ Lower the priority of the SVC and PendSV exceptions + ldr r0, =0xe000ed1c + mov r5, #0x80000000 + str r5, [r0] @ set SVC priority + ldr r0, =0xe000ed20 + 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, =0xe000ed14 @ system control register + ldr r12, [r0] + orr r12, #1 << 9 @ STKALIGN + str r12, [r0] + mov pc, lr +ENDPROC(__v7m_setup) + + .align 2 + .type v7m_processor_functions, #object +ENTRY(v7m_processor_functions) + .word v7m_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 cpu_v7m_set_pte_ext + .word pabort_noifar + .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 0 @ proc_info_list.cache + .size __v7m_proc_info, . - __v7m_proc_info + +__v7m_setup_stack: + .space 4 * 8 @ 8 registers +__v7m_setup_stack_top: -- cgit v1.2.3