1*84d9c625SLionel Sambuc /* $NetBSD: frame.h,v 1.36 2013/08/18 06:37:02 matt Exp $ */ 202222606SBen Gras 302222606SBen Gras /* 402222606SBen Gras * Copyright (c) 1994-1997 Mark Brinicombe. 502222606SBen Gras * Copyright (c) 1994 Brini. 602222606SBen Gras * All rights reserved. 702222606SBen Gras * 802222606SBen Gras * This code is derived from software written for Brini by Mark Brinicombe 902222606SBen Gras * 1002222606SBen Gras * Redistribution and use in source and binary forms, with or without 1102222606SBen Gras * modification, are permitted provided that the following conditions 1202222606SBen Gras * are met: 1302222606SBen Gras * 1. Redistributions of source code must retain the above copyright 1402222606SBen Gras * notice, this list of conditions and the following disclaimer. 1502222606SBen Gras * 2. Redistributions in binary form must reproduce the above copyright 1602222606SBen Gras * notice, this list of conditions and the following disclaimer in the 1702222606SBen Gras * documentation and/or other materials provided with the distribution. 1802222606SBen Gras * 3. All advertising materials mentioning features or use of this software 1902222606SBen Gras * must display the following acknowledgement: 2002222606SBen Gras * This product includes software developed by Brini. 2102222606SBen Gras * 4. The name of the company nor the name of the author may be used to 2202222606SBen Gras * endorse or promote products derived from this software without specific 2302222606SBen Gras * prior written permission. 2402222606SBen Gras * 2502222606SBen Gras * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 2602222606SBen Gras * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 2702222606SBen Gras * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2802222606SBen Gras * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 2902222606SBen Gras * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3002222606SBen Gras * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3102222606SBen Gras * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3202222606SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3302222606SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3402222606SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3502222606SBen Gras * SUCH DAMAGE. 3602222606SBen Gras * 3702222606SBen Gras * RiscBSD kernel project 3802222606SBen Gras * 3902222606SBen Gras * frame.h 4002222606SBen Gras * 4102222606SBen Gras * Stack frames structures 4202222606SBen Gras * 4302222606SBen Gras * Created : 30/09/94 4402222606SBen Gras */ 4502222606SBen Gras 4602222606SBen Gras #ifndef _ARM32_FRAME_H_ 4702222606SBen Gras #define _ARM32_FRAME_H_ 4802222606SBen Gras 4902222606SBen Gras #include <arm/frame.h> /* Common ARM stack frames */ 5002222606SBen Gras 5102222606SBen Gras #ifndef _LOCORE 5202222606SBen Gras 5302222606SBen Gras /* 5402222606SBen Gras * Switch frame. 5502222606SBen Gras * 5602222606SBen Gras * Should be a multiple of 8 bytes for dumpsys. 5702222606SBen Gras */ 5802222606SBen Gras 5902222606SBen Gras struct switchframe { 6002222606SBen Gras u_int sf_r4; 6102222606SBen Gras u_int sf_r5; 6202222606SBen Gras u_int sf_r6; 6302222606SBen Gras u_int sf_r7; 6402222606SBen Gras u_int sf_sp; 6502222606SBen Gras u_int sf_pc; 6602222606SBen Gras }; 6702222606SBen Gras 6802222606SBen Gras /* 69*84d9c625SLionel Sambuc * System stack frames. 70*84d9c625SLionel Sambuc */ 71*84d9c625SLionel Sambuc 72*84d9c625SLionel Sambuc struct clockframe { 73*84d9c625SLionel Sambuc struct trapframe cf_tf; 74*84d9c625SLionel Sambuc }; 75*84d9c625SLionel Sambuc 76*84d9c625SLionel Sambuc /* 7702222606SBen Gras * Stack frame. Used during stack traces (db_trace.c) 7802222606SBen Gras */ 7902222606SBen Gras struct frame { 8002222606SBen Gras u_int fr_fp; 8102222606SBen Gras u_int fr_sp; 8202222606SBen Gras u_int fr_lr; 8302222606SBen Gras u_int fr_pc; 8402222606SBen Gras }; 8502222606SBen Gras 8602222606SBen Gras #ifdef _KERNEL 8702222606SBen Gras void validate_trapframe(trapframe_t *, int); 8802222606SBen Gras #endif /* _KERNEL */ 8902222606SBen Gras 9002222606SBen Gras #else /* _LOCORE */ 9102222606SBen Gras 9202222606SBen Gras #include "opt_compat_netbsd.h" 9302222606SBen Gras #include "opt_execfmt.h" 9402222606SBen Gras #include "opt_multiprocessor.h" 9502222606SBen Gras #include "opt_cpuoptions.h" 9602222606SBen Gras #include "opt_arm_debug.h" 9702222606SBen Gras #include "opt_cputypes.h" 9802222606SBen Gras 99*84d9c625SLionel Sambuc #include <arm/locore.h> 10002222606SBen Gras 10102222606SBen Gras /* 10202222606SBen Gras * This macro is used by DO_AST_AND_RESTORE_ALIGNMENT_FAULTS to process 10302222606SBen Gras * any pending softints. 10402222606SBen Gras */ 105*84d9c625SLionel Sambuc #ifdef _ARM_ARCH_4T 106*84d9c625SLionel Sambuc #define B_CF_CONTROL(rX) ;\ 107*84d9c625SLionel Sambuc ldr ip, [rX, #CF_CONTROL] /* get function addr */ ;\ 108*84d9c625SLionel Sambuc bx ip /* branch to cpu_control */ 109*84d9c625SLionel Sambuc #else 110*84d9c625SLionel Sambuc #define B_CF_CONTROL(rX) ;\ 111*84d9c625SLionel Sambuc ldr pc, [rX, #CF_CONTROL] /* branch to cpu_control */ 112*84d9c625SLionel Sambuc #endif 113*84d9c625SLionel Sambuc #ifdef _ARM_ARCH_5T 114*84d9c625SLionel Sambuc #define BL_CF_CONTROL(rX) ;\ 115*84d9c625SLionel Sambuc ldr ip, [rX, #CF_CONTROL] /* get function addr */ ;\ 116*84d9c625SLionel Sambuc blx ip /* call cpu_control */ 117*84d9c625SLionel Sambuc #else 118*84d9c625SLionel Sambuc #define BL_CF_CONTROL(rX) ;\ 119*84d9c625SLionel Sambuc mov lr, pc ;\ 120*84d9c625SLionel Sambuc ldr pc, [rX, #CF_CONTROL] /* call cpu_control */ 121*84d9c625SLionel Sambuc #endif 12202222606SBen Gras #if defined(__HAVE_FAST_SOFTINTS) && !defined(__HAVE_PIC_FAST_SOFTINTS) 12302222606SBen Gras #define DO_PENDING_SOFTINTS \ 12402222606SBen Gras ldr r0, [r4, #CI_INTR_DEPTH]/* Get current intr depth */ ;\ 125*84d9c625SLionel Sambuc cmp r0, #0 /* Test for 0. */ ;\ 12602222606SBen Gras bne 10f /* skip softints if != 0 */ ;\ 12702222606SBen Gras ldr r0, [r4, #CI_CPL] /* Get current priority level */;\ 12802222606SBen Gras ldr r1, [r4, #CI_SOFTINTS] /* Get pending softint mask */ ;\ 12902222606SBen Gras lsrs r0, r1, r0 /* shift mask by cpl */ ;\ 13002222606SBen Gras blne _C_LABEL(dosoftints) /* dosoftints(void) */ ;\ 13102222606SBen Gras 10: 13202222606SBen Gras #else 13302222606SBen Gras #define DO_PENDING_SOFTINTS /* nothing */ 13402222606SBen Gras #endif 13502222606SBen Gras 13602222606SBen Gras #ifdef MULTIPROCESSOR 13702222606SBen Gras #define KERNEL_LOCK \ 13802222606SBen Gras mov r0, #1 ;\ 13902222606SBen Gras mov r1, #0 ;\ 14002222606SBen Gras bl _C_LABEL(_kernel_lock) 14102222606SBen Gras 14202222606SBen Gras #define KERNEL_UNLOCK \ 14302222606SBen Gras mov r0, #1 ;\ 14402222606SBen Gras mov r1, #0 ;\ 14502222606SBen Gras mov r2, #0 ;\ 14602222606SBen Gras bl _C_LABEL(_kernel_unlock) 14702222606SBen Gras #else 14802222606SBen Gras #define KERNEL_LOCK /* nothing */ 14902222606SBen Gras #define KERNEL_UNLOCK /* nothing */ 15002222606SBen Gras #endif 15102222606SBen Gras 15202222606SBen Gras #ifdef _ARM_ARCH_6 15302222606SBen Gras #define GET_CPSR(rb) /* nothing */ 15402222606SBen Gras #define CPSID_I(ra,rb) cpsid i 15502222606SBen Gras #define CPSIE_I(ra,rb) cpsie i 15602222606SBen Gras #else 15702222606SBen Gras #define GET_CPSR(rb) \ 15802222606SBen Gras mrs rb, cpsr /* fetch CPSR */ 15902222606SBen Gras 16002222606SBen Gras #define CPSID_I(ra,rb) \ 16102222606SBen Gras orr ra, rb, #(IF32_bits) ;\ 16202222606SBen Gras msr cpsr_c, ra /* Disable interrupts */ 16302222606SBen Gras 16402222606SBen Gras #define CPSIE_I(ra,rb) \ 16502222606SBen Gras bic ra, rb, #(IF32_bits) ;\ 16602222606SBen Gras msr cpsr_c, ra /* Restore interrupts */ 16702222606SBen Gras #endif 16802222606SBen Gras 16902222606SBen Gras /* 17002222606SBen Gras * AST_ALIGNMENT_FAULT_LOCALS and ENABLE_ALIGNMENT_FAULTS 17102222606SBen Gras * These are used in order to support dynamic enabling/disabling of 17202222606SBen Gras * alignment faults when executing old a.out ARM binaries. 17302222606SBen Gras * 17402222606SBen Gras * Note that when ENABLE_ALIGNMENTS_FAULTS finishes r4 will contain 17502222606SBen Gras * pointer to the cpu's cpu_info. DO_AST_AND_RESTORE_ALIGNMENT_FAULTS 17602222606SBen Gras * relies on r4 being preserved. 17702222606SBen Gras */ 17802222606SBen Gras #ifdef EXEC_AOUT 17902222606SBen Gras #define AST_ALIGNMENT_FAULT_LOCALS \ 18002222606SBen Gras .Laflt_cpufuncs: ;\ 18102222606SBen Gras .word _C_LABEL(cpufuncs) 18202222606SBen Gras 18302222606SBen Gras /* 18402222606SBen Gras * This macro must be invoked following PUSHFRAMEINSVC or PUSHFRAME at 18502222606SBen Gras * the top of interrupt/exception handlers. 18602222606SBen Gras * 18702222606SBen Gras * When invoked, r0 *must* contain the value of SPSR on the current 18802222606SBen Gras * trap/interrupt frame. This is always the case if ENABLE_ALIGNMENT_FAULTS 18902222606SBen Gras * is invoked immediately after PUSHFRAMEINSVC or PUSHFRAME. 19002222606SBen Gras */ 19102222606SBen Gras #define ENABLE_ALIGNMENT_FAULTS \ 19202222606SBen Gras and r7, r0, #(PSR_MODE) /* Test for USR32 mode */ ;\ 19302222606SBen Gras teq r7, #(PSR_USR32_MODE) ;\ 19402222606SBen Gras GET_CURCPU(r4) /* r4 = cpuinfo */ ;\ 19502222606SBen Gras bne 1f /* Not USR mode skip AFLT */ ;\ 19602222606SBen Gras ldr r1, [r4, #CI_CURLWP] /* get curlwp from cpu_info */ ;\ 19702222606SBen Gras ldr r1, [r1, #L_MD_FLAGS] /* Fetch l_md.md_flags */ ;\ 19802222606SBen Gras tst r1, #MDLWP_NOALIGNFLT ;\ 19902222606SBen Gras beq 1f /* AFLTs already enabled */ ;\ 20002222606SBen Gras ldr r2, .Laflt_cpufuncs ;\ 20102222606SBen Gras ldr r1, [r4, #CI_CTRL] /* Fetch control register */ ;\ 20202222606SBen Gras mov r0, #-1 ;\ 203*84d9c625SLionel Sambuc BL_CF_CONTROL(r2) /* Enable alignment faults */ ;\ 20402222606SBen Gras 1: KERNEL_LOCK 20502222606SBen Gras 20602222606SBen Gras /* 20702222606SBen Gras * This macro must be invoked just before PULLFRAMEFROMSVCANDEXIT or 20802222606SBen Gras * PULLFRAME at the end of interrupt/exception handlers. We know that 20902222606SBen Gras * r4 points to cpu_info since that is what ENABLE_ALIGNMENT_FAULTS did 21002222606SBen Gras * for use. 21102222606SBen Gras */ 21202222606SBen Gras #define DO_AST_AND_RESTORE_ALIGNMENT_FAULTS \ 21302222606SBen Gras DO_PENDING_SOFTINTS ;\ 21402222606SBen Gras GET_CPSR(r5) /* save CPSR */ ;\ 21502222606SBen Gras CPSID_I(r1, r5) /* Disable interrupts */ ;\ 21602222606SBen Gras teq r7, #(PSR_USR32_MODE) /* Returning to USR mode? */ ;\ 21702222606SBen Gras bne 3f /* Nope, get out now */ ;\ 21802222606SBen Gras 1: ldr r1, [r4, #CI_ASTPENDING] /* Pending AST? */ ;\ 21902222606SBen Gras teq r1, #0x00000000 ;\ 22002222606SBen Gras bne 2f /* Yup. Go deal with it */ ;\ 22102222606SBen Gras ldr r1, [r4, #CI_CURLWP] /* get curlwp from cpu_info */ ;\ 22202222606SBen Gras ldr r0, [r1, #L_MD_FLAGS] /* get md_flags from lwp */ ;\ 22302222606SBen Gras tst r0, #MDLWP_NOALIGNFLT ;\ 22402222606SBen Gras beq 3f /* Keep AFLTs enabled */ ;\ 22502222606SBen Gras ldr r1, [r4, #CI_CTRL] /* Fetch control register */ ;\ 22602222606SBen Gras ldr r2, .Laflt_cpufuncs ;\ 22702222606SBen Gras mov r0, #-1 ;\ 22802222606SBen Gras bic r1, r1, #CPU_CONTROL_AFLT_ENABLE /* Disable AFLTs */ ;\ 22902222606SBen Gras adr lr, 3f ;\ 230*84d9c625SLionel Sambuc B_CF_CONTROL(r2) /* Set new CTRL reg value */ ;\ 23102222606SBen Gras /* NOTREACHED */ \ 23202222606SBen Gras 2: mov r1, #0x00000000 ;\ 23302222606SBen Gras str r1, [r4, #CI_ASTPENDING] /* Clear astpending */ ;\ 23402222606SBen Gras CPSIE_I(r5, r5) /* Restore interrupts */ ;\ 23502222606SBen Gras mov r0, sp ;\ 23602222606SBen Gras bl _C_LABEL(ast) /* ast(frame) */ ;\ 23702222606SBen Gras CPSID_I(r0, r5) /* Disable interrupts */ ;\ 23802222606SBen Gras b 1b /* Back around again */ ;\ 23902222606SBen Gras 3: KERNEL_UNLOCK 24002222606SBen Gras 24102222606SBen Gras #else /* !EXEC_AOUT */ 24202222606SBen Gras 24302222606SBen Gras #define AST_ALIGNMENT_FAULT_LOCALS 24402222606SBen Gras 24502222606SBen Gras #define ENABLE_ALIGNMENT_FAULTS \ 24602222606SBen Gras and r7, r0, #(PSR_MODE) /* Test for USR32 mode */ ;\ 24702222606SBen Gras GET_CURCPU(r4) /* r4 = cpuinfo */ ;\ 24802222606SBen Gras KERNEL_LOCK 24902222606SBen Gras 25002222606SBen Gras #define DO_AST_AND_RESTORE_ALIGNMENT_FAULTS \ 25102222606SBen Gras DO_PENDING_SOFTINTS ;\ 25202222606SBen Gras GET_CPSR(r5) /* save CPSR */ ;\ 25302222606SBen Gras CPSID_I(r1, r5) /* Disable interrupts */ ;\ 25402222606SBen Gras teq r7, #(PSR_USR32_MODE) ;\ 25502222606SBen Gras bne 2f /* Nope, get out now */ ;\ 25602222606SBen Gras 1: ldr r1, [r4, #CI_ASTPENDING] /* Pending AST? */ ;\ 25702222606SBen Gras teq r1, #0x00000000 ;\ 25802222606SBen Gras beq 2f /* Nope. Just bail */ ;\ 25902222606SBen Gras mov r1, #0x00000000 ;\ 26002222606SBen Gras str r1, [r4, #CI_ASTPENDING] /* Clear astpending */ ;\ 26102222606SBen Gras CPSIE_I(r5, r5) /* Restore interrupts */ ;\ 26202222606SBen Gras mov r0, sp ;\ 26302222606SBen Gras bl _C_LABEL(ast) /* ast(frame) */ ;\ 26402222606SBen Gras CPSID_I(r0, r5) /* Disable interrupts */ ;\ 26502222606SBen Gras b 1b ;\ 26602222606SBen Gras 2: KERNEL_UNLOCK /* unlock the kernel */ 26702222606SBen Gras #endif /* EXEC_AOUT */ 26802222606SBen Gras 26902222606SBen Gras #ifndef _ARM_ARCH_6 27002222606SBen Gras #ifdef ARM_LOCK_CAS_DEBUG 27102222606SBen Gras #define LOCK_CAS_DEBUG_LOCALS \ 27202222606SBen Gras .L_lock_cas_restart: ;\ 27302222606SBen Gras .word _C_LABEL(_lock_cas_restart) 27402222606SBen Gras 27502222606SBen Gras #if defined(__ARMEB__) 27602222606SBen Gras #define LOCK_CAS_DEBUG_COUNT_RESTART \ 27702222606SBen Gras ble 99f ;\ 27802222606SBen Gras ldr r0, .L_lock_cas_restart ;\ 27902222606SBen Gras ldmia r0, {r1-r2} /* load ev_count */ ;\ 28002222606SBen Gras adds r2, r2, #1 /* 64-bit incr (lo) */ ;\ 28102222606SBen Gras adc r1, r1, #0 /* 64-bit incr (hi) */ ;\ 28202222606SBen Gras stmia r0, {r1-r2} /* store ev_count */ 28302222606SBen Gras #else /* __ARMEB__ */ 28402222606SBen Gras #define LOCK_CAS_DEBUG_COUNT_RESTART \ 28502222606SBen Gras ble 99f ;\ 28602222606SBen Gras ldr r0, .L_lock_cas_restart ;\ 28702222606SBen Gras ldmia r0, {r1-r2} /* load ev_count */ ;\ 28802222606SBen Gras adds r1, r1, #1 /* 64-bit incr (lo) */ ;\ 28902222606SBen Gras adc r2, r2, #0 /* 64-bit incr (hi) */ ;\ 29002222606SBen Gras stmia r0, {r1-r2} /* store ev_count */ 29102222606SBen Gras #endif /* __ARMEB__ */ 29202222606SBen Gras #else /* ARM_LOCK_CAS_DEBUG */ 29302222606SBen Gras #define LOCK_CAS_DEBUG_LOCALS /* nothing */ 29402222606SBen Gras #define LOCK_CAS_DEBUG_COUNT_RESTART /* nothing */ 29502222606SBen Gras #endif /* ARM_LOCK_CAS_DEBUG */ 29602222606SBen Gras 29702222606SBen Gras #define LOCK_CAS_CHECK_LOCALS \ 29802222606SBen Gras .L_lock_cas: ;\ 29902222606SBen Gras .word _C_LABEL(_lock_cas) ;\ 30002222606SBen Gras .L_lock_cas_end: ;\ 30102222606SBen Gras .word _C_LABEL(_lock_cas_end) ;\ 30202222606SBen Gras LOCK_CAS_DEBUG_LOCALS 30302222606SBen Gras 30402222606SBen Gras #define LOCK_CAS_CHECK \ 30502222606SBen Gras ldr r0, [sp] /* get saved PSR */ ;\ 30602222606SBen Gras and r0, r0, #(PSR_MODE) /* check for SVC32 mode */ ;\ 30702222606SBen Gras teq r0, #(PSR_SVC32_MODE) ;\ 30802222606SBen Gras bne 99f /* nope, get out now */ ;\ 30902222606SBen Gras ldr r0, [sp, #(TF_PC)] ;\ 31002222606SBen Gras ldr r1, .L_lock_cas_end ;\ 31102222606SBen Gras cmp r0, r1 ;\ 31202222606SBen Gras bge 99f ;\ 31302222606SBen Gras ldr r1, .L_lock_cas ;\ 31402222606SBen Gras cmp r0, r1 ;\ 31502222606SBen Gras strgt r1, [sp, #(TF_PC)] ;\ 31602222606SBen Gras LOCK_CAS_DEBUG_COUNT_RESTART ;\ 31702222606SBen Gras 99: 31802222606SBen Gras 31902222606SBen Gras #else 32002222606SBen Gras #define LOCK_CAS_CHECK /* nothing */ 32102222606SBen Gras #define LOCK_CAS_CHECK_LOCALS /* nothing */ 32202222606SBen Gras #endif 32302222606SBen Gras 32402222606SBen Gras /* 32502222606SBen Gras * ASM macros for pushing and pulling trapframes from the stack 32602222606SBen Gras * 32702222606SBen Gras * These macros are used to handle the trapframe structure defined above. 32802222606SBen Gras */ 32902222606SBen Gras 33002222606SBen Gras /* 33102222606SBen Gras * PUSHFRAME - macro to push a trap frame on the stack in the current mode 33202222606SBen Gras * Since the current mode is used, the SVC lr field is not defined. 33302222606SBen Gras */ 33402222606SBen Gras 33502222606SBen Gras #ifdef CPU_SA110 33602222606SBen Gras /* 33702222606SBen Gras * NOTE: r13 and r14 are stored separately as a work around for the 33802222606SBen Gras * SA110 rev 2 STM^ bug 33902222606SBen Gras */ 34002222606SBen Gras #define PUSHUSERREGS \ 34102222606SBen Gras stmia sp, {r0-r12}; /* Push the user mode registers */ \ 342*84d9c625SLionel Sambuc add r0, sp, #(TF_USR_SP-TF_R0); /* Adjust the stack pointer */ \ 34302222606SBen Gras stmia r0, {r13-r14}^ /* Push the user mode registers */ 34402222606SBen Gras #else 34502222606SBen Gras #define PUSHUSERREGS \ 34602222606SBen Gras stmia sp, {r0-r14}^ /* Push the user mode registers */ 34702222606SBen Gras #endif 34802222606SBen Gras 34902222606SBen Gras #define PUSHFRAME \ 35002222606SBen Gras str lr, [sp, #-4]!; /* Push the return address */ \ 351*84d9c625SLionel Sambuc sub sp, sp, #(TF_PC-TF_R0); /* Adjust the stack pointer */ \ 35202222606SBen Gras PUSHUSERREGS; /* Push the user mode registers */ \ 35302222606SBen Gras mov r0, r0; /* NOP for previous instruction */ \ 35402222606SBen Gras mrs r0, spsr_all; /* Get the SPSR */ \ 355*84d9c625SLionel Sambuc str r0, [sp, #-TF_R0]! /* Push the SPSR on the stack */ 356*84d9c625SLionel Sambuc 357*84d9c625SLionel Sambuc /* 358*84d9c625SLionel Sambuc * Push a minimal trapframe so we can dispatch an interrupt from the 359*84d9c625SLionel Sambuc * idle loop. The only reason the idle loop wakes up is to dispatch 360*84d9c625SLionel Sambuc * interrupts so why take the avoid of a full exception when we can do 361*84d9c625SLionel Sambuc * something minimal. 362*84d9c625SLionel Sambuc */ 363*84d9c625SLionel Sambuc #define PUSHIDLEFRAME \ 364*84d9c625SLionel Sambuc str lr, [sp, #-4]!; /* save SVC32 lr */ \ 365*84d9c625SLionel Sambuc str r6, [sp, #(TF_R6-TF_PC)]!; /* save callee-saved r6 */ \ 366*84d9c625SLionel Sambuc str r4, [sp, #(TF_R4-TF_R6)]!; /* save callee-saved r4 */ \ 367*84d9c625SLionel Sambuc mrs r0, cpsr_all; /* Get the CPSR */ \ 368*84d9c625SLionel Sambuc str r0, [sp, #(-TF_R4)]! /* Push the CPSR on the stack */ 369*84d9c625SLionel Sambuc 370*84d9c625SLionel Sambuc /* 371*84d9c625SLionel Sambuc * Push a trapframe to be used by cpu_switchto 372*84d9c625SLionel Sambuc */ 373*84d9c625SLionel Sambuc #define PUSHSWITCHFRAME(rX) \ 374*84d9c625SLionel Sambuc mov ip, sp; \ 375*84d9c625SLionel Sambuc sub sp, sp, #(TRAPFRAMESIZE-TF_R12); /* Adjust the stack pointer */ \ 376*84d9c625SLionel Sambuc push {r4-r11}; /* Push the callee saved registers */ \ 377*84d9c625SLionel Sambuc sub sp, sp, #TF_R4; /* reserve rest of trapframe */ \ 378*84d9c625SLionel Sambuc str ip, [sp, #TF_SVC_SP]; \ 379*84d9c625SLionel Sambuc str lr, [sp, #TF_SVC_LR]; \ 380*84d9c625SLionel Sambuc str lr, [sp, #TF_PC]; \ 381*84d9c625SLionel Sambuc mrs rX, cpsr_all; /* Get the CPSR */ \ 382*84d9c625SLionel Sambuc str rX, [sp, #TF_SPSR] /* save in trapframe */ 383*84d9c625SLionel Sambuc 384*84d9c625SLionel Sambuc #define PUSHSWITCHFRAME1 \ 385*84d9c625SLionel Sambuc mov ip, sp; \ 386*84d9c625SLionel Sambuc sub sp, sp, #(TRAPFRAMESIZE-TF_R8); /* Adjust the stack pointer */ \ 387*84d9c625SLionel Sambuc push {r4-r7}; /* Push some of the callee saved registers */ \ 388*84d9c625SLionel Sambuc sub sp, sp, #TF_R4; /* reserve rest of trapframe */ \ 389*84d9c625SLionel Sambuc str ip, [sp, #TF_SVC_SP]; \ 390*84d9c625SLionel Sambuc str lr, [sp, #TF_SVC_LR]; \ 391*84d9c625SLionel Sambuc str lr, [sp, #TF_PC] 392*84d9c625SLionel Sambuc 393*84d9c625SLionel Sambuc #if defined(_ARM_ARCH_DWORD_OK) && __ARM_EABI__ 394*84d9c625SLionel Sambuc #define PUSHSWITCHFRAME2 \ 395*84d9c625SLionel Sambuc strd r10, [sp, #TF_R10]; /* save r10 & r11 */ \ 396*84d9c625SLionel Sambuc strd r8, [sp, #TF_R8]; /* save r8 & r9 */ \ 397*84d9c625SLionel Sambuc mrs r0, cpsr_all; /* Get the CPSR */ \ 398*84d9c625SLionel Sambuc str r0, [sp, #TF_SPSR] /* save in trapframe */ 399*84d9c625SLionel Sambuc #else 400*84d9c625SLionel Sambuc #define PUSHSWITCHFRAME2 \ 401*84d9c625SLionel Sambuc add r0, sp, #TF_R8; /* get ptr to r8 and above */ \ 402*84d9c625SLionel Sambuc stmia r0, {r8-r11}; /* save rest of registers */ \ 403*84d9c625SLionel Sambuc mrs r0, cpsr_all; /* Get the CPSR */ \ 404*84d9c625SLionel Sambuc str r0, [sp, #TF_SPSR] /* save in trapframe */ 405*84d9c625SLionel Sambuc #endif 40602222606SBen Gras 40702222606SBen Gras /* 40802222606SBen Gras * PULLFRAME - macro to pull a trap frame from the stack in the current mode 40902222606SBen Gras * Since the current mode is used, the SVC lr field is ignored. 41002222606SBen Gras */ 41102222606SBen Gras 41202222606SBen Gras #define PULLFRAME \ 413*84d9c625SLionel Sambuc ldr r0, [sp], #TF_R0; /* Pop the SPSR from stack */ \ 41402222606SBen Gras msr spsr_all, r0; \ 41502222606SBen Gras ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 41602222606SBen Gras mov r0, r0; /* NOP for previous instruction */ \ 417*84d9c625SLionel Sambuc add sp, sp, #(TF_PC-TF_R0); /* Adjust the stack pointer */ \ 41802222606SBen Gras ldr lr, [sp], #0x0004 /* Pop the return address */ 41902222606SBen Gras 420*84d9c625SLionel Sambuc #define PULLIDLEFRAME \ 421*84d9c625SLionel Sambuc add sp, sp, #TF_R4; /* Adjust the stack pointer */ \ 422*84d9c625SLionel Sambuc ldr r4, [sp], #(TF_R6-TF_R4); /* restore callee-saved r4 */ \ 423*84d9c625SLionel Sambuc ldr r6, [sp], #(TF_PC-TF_R6); /* restore callee-saved r6 */ \ 424*84d9c625SLionel Sambuc ldr lr, [sp], #4 /* Pop the return address */ 425*84d9c625SLionel Sambuc 426*84d9c625SLionel Sambuc /* 427*84d9c625SLionel Sambuc * Pop a trapframe to be used by cpu_switchto (don't touch r0 & r1). 428*84d9c625SLionel Sambuc */ 429*84d9c625SLionel Sambuc #define PULLSWITCHFRAME \ 430*84d9c625SLionel Sambuc add sp, sp, #TF_R4; /* Adjust the stack pointer */ \ 431*84d9c625SLionel Sambuc pop {r4-r11}; /* pop the callee saved registers */ \ 432*84d9c625SLionel Sambuc add sp, sp, #(TF_PC-TF_R12); /* Adjust the stack pointer */ \ 433*84d9c625SLionel Sambuc ldr lr, [sp], #4; /* pop the return address */ 434*84d9c625SLionel Sambuc 43502222606SBen Gras /* 43602222606SBen Gras * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode 43702222606SBen Gras * This should only be used if the processor is not currently in SVC32 43802222606SBen Gras * mode. The processor mode is switched to SVC mode and the trap frame is 43902222606SBen Gras * stored. The SVC lr field is used to store the previous value of 44002222606SBen Gras * lr in SVC mode. 44102222606SBen Gras * 44202222606SBen Gras * NOTE: r13 and r14 are stored separately as a work around for the 44302222606SBen Gras * SA110 rev 2 STM^ bug 44402222606SBen Gras */ 44502222606SBen Gras 44602222606SBen Gras #ifdef _ARM_ARCH_6 44702222606SBen Gras #define SET_CPSR_MODE(tmp, mode) \ 44802222606SBen Gras cps #(mode) 44902222606SBen Gras #else 45002222606SBen Gras #define SET_CPSR_MODE(tmp, mode) \ 45102222606SBen Gras mrs tmp, cpsr; /* Get the CPSR */ \ 45202222606SBen Gras bic tmp, tmp, #(PSR_MODE); /* Fix for SVC mode */ \ 45302222606SBen Gras orr tmp, tmp, #(mode); \ 45402222606SBen Gras msr cpsr_c, tmp /* Punch into SVC mode */ 45502222606SBen Gras #endif 45602222606SBen Gras 45702222606SBen Gras #define PUSHFRAMEINSVC \ 45802222606SBen Gras stmdb sp, {r0-r3}; /* Save 4 registers */ \ 45902222606SBen Gras mov r0, lr; /* Save xxx32 r14 */ \ 46002222606SBen Gras mov r1, sp; /* Save xxx32 sp */ \ 46102222606SBen Gras mrs r3, spsr; /* Save xxx32 spsr */ \ 46202222606SBen Gras SET_CPSR_MODE(r2, PSR_SVC32_MODE); \ 46302222606SBen Gras bic r2, sp, #7; /* Align new SVC sp */ \ 46402222606SBen Gras str r0, [r2, #-4]!; /* Push return address */ \ 46502222606SBen Gras stmdb r2!, {sp, lr}; /* Push SVC sp, lr */ \ 46602222606SBen Gras mov sp, r2; /* Keep stack aligned */ \ 46702222606SBen Gras msr spsr_all, r3; /* Restore correct spsr */ \ 46802222606SBen Gras ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 469*84d9c625SLionel Sambuc sub sp, sp, #(TF_SVC_SP-TF_R0); /* Adjust the stack pointer */ \ 47002222606SBen Gras PUSHUSERREGS; /* Push the user mode registers */ \ 47102222606SBen Gras mov r0, r0; /* NOP for previous instruction */ \ 47202222606SBen Gras mrs r0, spsr_all; /* Get the SPSR */ \ 473*84d9c625SLionel Sambuc str r0, [sp, #-TF_R0]! /* Push the SPSR onto the stack */ 47402222606SBen Gras 47502222606SBen Gras /* 47602222606SBen Gras * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack 47702222606SBen Gras * in SVC32 mode and restore the saved processor mode and PC. 47802222606SBen Gras * This should be used when the SVC lr register needs to be restored on 47902222606SBen Gras * exit. 48002222606SBen Gras */ 48102222606SBen Gras 48202222606SBen Gras #define PULLFRAMEFROMSVCANDEXIT \ 48302222606SBen Gras ldr r0, [sp], #0x0008; /* Pop the SPSR from stack */ \ 48402222606SBen Gras msr spsr_all, r0; /* restore SPSR */ \ 48502222606SBen Gras ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 48602222606SBen Gras mov r0, r0; /* NOP for previous instruction */ \ 487*84d9c625SLionel Sambuc add sp, sp, #(TF_SVC_SP-TF_R0); /* Adjust the stack pointer */ \ 48802222606SBen Gras ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 48902222606SBen Gras 49002222606SBen Gras #endif /* _LOCORE */ 49102222606SBen Gras 49202222606SBen Gras #endif /* _ARM32_FRAME_H_ */ 493