1*0a6a1f1dSLionel Sambuc /* $NetBSD: frame.h,v 1.42 2015/04/17 17:28:33 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 /* 6984d9c625SLionel Sambuc * System stack frames. 7084d9c625SLionel Sambuc */ 7184d9c625SLionel Sambuc 7284d9c625SLionel Sambuc struct clockframe { 7384d9c625SLionel Sambuc struct trapframe cf_tf; 7484d9c625SLionel Sambuc }; 7584d9c625SLionel Sambuc 7684d9c625SLionel 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 9984d9c625SLionel 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 */ 10584d9c625SLionel Sambuc #ifdef _ARM_ARCH_4T 10684d9c625SLionel Sambuc #define B_CF_CONTROL(rX) ;\ 10784d9c625SLionel Sambuc ldr ip, [rX, #CF_CONTROL] /* get function addr */ ;\ 10884d9c625SLionel Sambuc bx ip /* branch to cpu_control */ 10984d9c625SLionel Sambuc #else 11084d9c625SLionel Sambuc #define B_CF_CONTROL(rX) ;\ 11184d9c625SLionel Sambuc ldr pc, [rX, #CF_CONTROL] /* branch to cpu_control */ 11284d9c625SLionel Sambuc #endif 11384d9c625SLionel Sambuc #ifdef _ARM_ARCH_5T 11484d9c625SLionel Sambuc #define BL_CF_CONTROL(rX) ;\ 11584d9c625SLionel Sambuc ldr ip, [rX, #CF_CONTROL] /* get function addr */ ;\ 11684d9c625SLionel Sambuc blx ip /* call cpu_control */ 11784d9c625SLionel Sambuc #else 11884d9c625SLionel Sambuc #define BL_CF_CONTROL(rX) ;\ 11984d9c625SLionel Sambuc mov lr, pc ;\ 12084d9c625SLionel Sambuc ldr pc, [rX, #CF_CONTROL] /* call cpu_control */ 12184d9c625SLionel 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 */ ;\ 12584d9c625SLionel 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 _ARM_ARCH_6 13702222606SBen Gras #define GET_CPSR(rb) /* nothing */ 13802222606SBen Gras #define CPSID_I(ra,rb) cpsid i 13902222606SBen Gras #define CPSIE_I(ra,rb) cpsie i 14002222606SBen Gras #else 14102222606SBen Gras #define GET_CPSR(rb) \ 14202222606SBen Gras mrs rb, cpsr /* fetch CPSR */ 14302222606SBen Gras 14402222606SBen Gras #define CPSID_I(ra,rb) \ 14502222606SBen Gras orr ra, rb, #(IF32_bits) ;\ 14602222606SBen Gras msr cpsr_c, ra /* Disable interrupts */ 14702222606SBen Gras 14802222606SBen Gras #define CPSIE_I(ra,rb) \ 14902222606SBen Gras bic ra, rb, #(IF32_bits) ;\ 15002222606SBen Gras msr cpsr_c, ra /* Restore interrupts */ 15102222606SBen Gras #endif 15202222606SBen Gras 153*0a6a1f1dSLionel Sambuc #ifdef __HAVE_PREEMPTION 154*0a6a1f1dSLionel Sambuc #define DO_CLEAR_ASTPENDING \ 155*0a6a1f1dSLionel Sambuc mvn r1, #1 /* complement of 1 */ ;\ 156*0a6a1f1dSLionel Sambuc add r0, r4, #CI_ASTPENDING /* address of astpending */ ;\ 157*0a6a1f1dSLionel Sambuc bl _C_LABEL(atomic_and_uint) /* clear AST */ 158*0a6a1f1dSLionel Sambuc #else 159*0a6a1f1dSLionel Sambuc #define DO_CLEAR_ASTPENDING \ 160*0a6a1f1dSLionel Sambuc mov r0, #0 ;\ 161*0a6a1f1dSLionel Sambuc str r0, [r4, #CI_ASTPENDING] /* clear AST */ 162*0a6a1f1dSLionel Sambuc #endif 163*0a6a1f1dSLionel Sambuc 164*0a6a1f1dSLionel Sambuc #define DO_PENDING_AST(lbl) ;\ 165*0a6a1f1dSLionel Sambuc 1: ldr r1, [r4, #CI_ASTPENDING] /* Pending AST? */ ;\ 166*0a6a1f1dSLionel Sambuc tst r1, #0x00000001 ;\ 167*0a6a1f1dSLionel Sambuc beq lbl /* Nope. Just bail */ ;\ 168*0a6a1f1dSLionel Sambuc DO_CLEAR_ASTPENDING ;\ 169*0a6a1f1dSLionel Sambuc CPSIE_I(r5, r5) /* Restore interrupts */ ;\ 170*0a6a1f1dSLionel Sambuc mov r0, sp ;\ 171*0a6a1f1dSLionel Sambuc bl _C_LABEL(ast) /* ast(frame) */ ;\ 172*0a6a1f1dSLionel Sambuc CPSID_I(r0, r5) /* Disable interrupts */ ;\ 173*0a6a1f1dSLionel Sambuc b 1b /* test again */ 174*0a6a1f1dSLionel Sambuc 17502222606SBen Gras /* 17602222606SBen Gras * AST_ALIGNMENT_FAULT_LOCALS and ENABLE_ALIGNMENT_FAULTS 17702222606SBen Gras * These are used in order to support dynamic enabling/disabling of 17802222606SBen Gras * alignment faults when executing old a.out ARM binaries. 17902222606SBen Gras * 18002222606SBen Gras * Note that when ENABLE_ALIGNMENTS_FAULTS finishes r4 will contain 18102222606SBen Gras * pointer to the cpu's cpu_info. DO_AST_AND_RESTORE_ALIGNMENT_FAULTS 18202222606SBen Gras * relies on r4 being preserved. 18302222606SBen Gras */ 18402222606SBen Gras #ifdef EXEC_AOUT 18502222606SBen Gras #define AST_ALIGNMENT_FAULT_LOCALS \ 18602222606SBen Gras .Laflt_cpufuncs: ;\ 18702222606SBen Gras .word _C_LABEL(cpufuncs) 18802222606SBen Gras 18902222606SBen Gras /* 19002222606SBen Gras * This macro must be invoked following PUSHFRAMEINSVC or PUSHFRAME at 19102222606SBen Gras * the top of interrupt/exception handlers. 19202222606SBen Gras * 19302222606SBen Gras * When invoked, r0 *must* contain the value of SPSR on the current 19402222606SBen Gras * trap/interrupt frame. This is always the case if ENABLE_ALIGNMENT_FAULTS 19502222606SBen Gras * is invoked immediately after PUSHFRAMEINSVC or PUSHFRAME. 19602222606SBen Gras */ 19702222606SBen Gras #define ENABLE_ALIGNMENT_FAULTS \ 19802222606SBen Gras and r7, r0, #(PSR_MODE) /* Test for USR32 mode */ ;\ 199*0a6a1f1dSLionel Sambuc cmp r7, #(PSR_USR32_MODE) ;\ 20002222606SBen Gras GET_CURCPU(r4) /* r4 = cpuinfo */ ;\ 20102222606SBen Gras bne 1f /* Not USR mode skip AFLT */ ;\ 20202222606SBen Gras ldr r1, [r4, #CI_CURLWP] /* get curlwp from cpu_info */ ;\ 20302222606SBen Gras ldr r1, [r1, #L_MD_FLAGS] /* Fetch l_md.md_flags */ ;\ 20402222606SBen Gras tst r1, #MDLWP_NOALIGNFLT ;\ 20502222606SBen Gras beq 1f /* AFLTs already enabled */ ;\ 20602222606SBen Gras ldr r2, .Laflt_cpufuncs ;\ 20702222606SBen Gras ldr r1, [r4, #CI_CTRL] /* Fetch control register */ ;\ 20802222606SBen Gras mov r0, #-1 ;\ 20984d9c625SLionel Sambuc BL_CF_CONTROL(r2) /* Enable alignment faults */ ;\ 210*0a6a1f1dSLionel Sambuc 1: /* done */ 21102222606SBen Gras 21202222606SBen Gras /* 21302222606SBen Gras * This macro must be invoked just before PULLFRAMEFROMSVCANDEXIT or 21402222606SBen Gras * PULLFRAME at the end of interrupt/exception handlers. We know that 21502222606SBen Gras * r4 points to cpu_info since that is what ENABLE_ALIGNMENT_FAULTS did 21602222606SBen Gras * for use. 21702222606SBen Gras */ 21802222606SBen Gras #define DO_AST_AND_RESTORE_ALIGNMENT_FAULTS \ 21902222606SBen Gras DO_PENDING_SOFTINTS ;\ 22002222606SBen Gras GET_CPSR(r5) /* save CPSR */ ;\ 22102222606SBen Gras CPSID_I(r1, r5) /* Disable interrupts */ ;\ 222*0a6a1f1dSLionel Sambuc cmp r7, #(PSR_USR32_MODE) /* Returning to USR mode? */ ;\ 22302222606SBen Gras bne 3f /* Nope, get out now */ ;\ 224*0a6a1f1dSLionel Sambuc DO_PENDING_AST(2f) /* Pending AST? */ ;\ 225*0a6a1f1dSLionel Sambuc 2: ldr r1, [r4, #CI_CURLWP] /* get curlwp from cpu_info */ ;\ 22602222606SBen Gras ldr r0, [r1, #L_MD_FLAGS] /* get md_flags from lwp */ ;\ 22702222606SBen Gras tst r0, #MDLWP_NOALIGNFLT ;\ 22802222606SBen Gras beq 3f /* Keep AFLTs enabled */ ;\ 22902222606SBen Gras ldr r1, [r4, #CI_CTRL] /* Fetch control register */ ;\ 23002222606SBen Gras ldr r2, .Laflt_cpufuncs ;\ 23102222606SBen Gras mov r0, #-1 ;\ 23202222606SBen Gras bic r1, r1, #CPU_CONTROL_AFLT_ENABLE /* Disable AFLTs */ ;\ 233*0a6a1f1dSLionel Sambuc BL_CF_CONTROL(r2) /* Set new CTRL reg value */ ;\ 234*0a6a1f1dSLionel Sambuc 3: /* done */ 23502222606SBen Gras 23602222606SBen Gras #else /* !EXEC_AOUT */ 23702222606SBen Gras 23802222606SBen Gras #define AST_ALIGNMENT_FAULT_LOCALS 23902222606SBen Gras 24002222606SBen Gras #define ENABLE_ALIGNMENT_FAULTS \ 24102222606SBen Gras and r7, r0, #(PSR_MODE) /* Test for USR32 mode */ ;\ 242*0a6a1f1dSLionel Sambuc GET_CURCPU(r4) /* r4 = cpuinfo */ 243*0a6a1f1dSLionel Sambuc 24402222606SBen Gras 24502222606SBen Gras #define DO_AST_AND_RESTORE_ALIGNMENT_FAULTS \ 24602222606SBen Gras DO_PENDING_SOFTINTS ;\ 24702222606SBen Gras GET_CPSR(r5) /* save CPSR */ ;\ 24802222606SBen Gras CPSID_I(r1, r5) /* Disable interrupts */ ;\ 249*0a6a1f1dSLionel Sambuc cmp r7, #(PSR_USR32_MODE) ;\ 25002222606SBen Gras bne 2f /* Nope, get out now */ ;\ 251*0a6a1f1dSLionel Sambuc DO_PENDING_AST(2f) /* Pending AST? */ ;\ 252*0a6a1f1dSLionel Sambuc 2: /* done */ 25302222606SBen Gras #endif /* EXEC_AOUT */ 25402222606SBen Gras 25502222606SBen Gras #ifndef _ARM_ARCH_6 25602222606SBen Gras #ifdef ARM_LOCK_CAS_DEBUG 25702222606SBen Gras #define LOCK_CAS_DEBUG_LOCALS \ 25802222606SBen Gras .L_lock_cas_restart: ;\ 25902222606SBen Gras .word _C_LABEL(_lock_cas_restart) 26002222606SBen Gras 26102222606SBen Gras #if defined(__ARMEB__) 26202222606SBen Gras #define LOCK_CAS_DEBUG_COUNT_RESTART \ 26302222606SBen Gras ble 99f ;\ 26402222606SBen Gras ldr r0, .L_lock_cas_restart ;\ 26502222606SBen Gras ldmia r0, {r1-r2} /* load ev_count */ ;\ 26602222606SBen Gras adds r2, r2, #1 /* 64-bit incr (lo) */ ;\ 26702222606SBen Gras adc r1, r1, #0 /* 64-bit incr (hi) */ ;\ 26802222606SBen Gras stmia r0, {r1-r2} /* store ev_count */ 26902222606SBen Gras #else /* __ARMEB__ */ 27002222606SBen Gras #define LOCK_CAS_DEBUG_COUNT_RESTART \ 27102222606SBen Gras ble 99f ;\ 27202222606SBen Gras ldr r0, .L_lock_cas_restart ;\ 27302222606SBen Gras ldmia r0, {r1-r2} /* load ev_count */ ;\ 27402222606SBen Gras adds r1, r1, #1 /* 64-bit incr (lo) */ ;\ 27502222606SBen Gras adc r2, r2, #0 /* 64-bit incr (hi) */ ;\ 27602222606SBen Gras stmia r0, {r1-r2} /* store ev_count */ 27702222606SBen Gras #endif /* __ARMEB__ */ 27802222606SBen Gras #else /* ARM_LOCK_CAS_DEBUG */ 27902222606SBen Gras #define LOCK_CAS_DEBUG_LOCALS /* nothing */ 28002222606SBen Gras #define LOCK_CAS_DEBUG_COUNT_RESTART /* nothing */ 28102222606SBen Gras #endif /* ARM_LOCK_CAS_DEBUG */ 28202222606SBen Gras 28302222606SBen Gras #define LOCK_CAS_CHECK_LOCALS \ 28402222606SBen Gras .L_lock_cas: ;\ 28502222606SBen Gras .word _C_LABEL(_lock_cas) ;\ 28602222606SBen Gras .L_lock_cas_end: ;\ 28702222606SBen Gras .word _C_LABEL(_lock_cas_end) ;\ 28802222606SBen Gras LOCK_CAS_DEBUG_LOCALS 28902222606SBen Gras 29002222606SBen Gras #define LOCK_CAS_CHECK \ 29102222606SBen Gras ldr r0, [sp] /* get saved PSR */ ;\ 29202222606SBen Gras and r0, r0, #(PSR_MODE) /* check for SVC32 mode */ ;\ 293*0a6a1f1dSLionel Sambuc cmp r0, #(PSR_SVC32_MODE) ;\ 29402222606SBen Gras bne 99f /* nope, get out now */ ;\ 29502222606SBen Gras ldr r0, [sp, #(TF_PC)] ;\ 29602222606SBen Gras ldr r1, .L_lock_cas_end ;\ 29702222606SBen Gras cmp r0, r1 ;\ 29802222606SBen Gras bge 99f ;\ 29902222606SBen Gras ldr r1, .L_lock_cas ;\ 30002222606SBen Gras cmp r0, r1 ;\ 30102222606SBen Gras strgt r1, [sp, #(TF_PC)] ;\ 30202222606SBen Gras LOCK_CAS_DEBUG_COUNT_RESTART ;\ 30302222606SBen Gras 99: 30402222606SBen Gras 30502222606SBen Gras #else 30602222606SBen Gras #define LOCK_CAS_CHECK /* nothing */ 30702222606SBen Gras #define LOCK_CAS_CHECK_LOCALS /* nothing */ 30802222606SBen Gras #endif 30902222606SBen Gras 31002222606SBen Gras /* 31102222606SBen Gras * ASM macros for pushing and pulling trapframes from the stack 31202222606SBen Gras * 31302222606SBen Gras * These macros are used to handle the trapframe structure defined above. 31402222606SBen Gras */ 31502222606SBen Gras 31602222606SBen Gras /* 31702222606SBen Gras * PUSHFRAME - macro to push a trap frame on the stack in the current mode 31802222606SBen Gras * Since the current mode is used, the SVC lr field is not defined. 31902222606SBen Gras */ 32002222606SBen Gras 32102222606SBen Gras #ifdef CPU_SA110 32202222606SBen Gras /* 32302222606SBen Gras * NOTE: r13 and r14 are stored separately as a work around for the 32402222606SBen Gras * SA110 rev 2 STM^ bug 32502222606SBen Gras */ 32602222606SBen Gras #define PUSHUSERREGS \ 32702222606SBen Gras stmia sp, {r0-r12}; /* Push the user mode registers */ \ 32884d9c625SLionel Sambuc add r0, sp, #(TF_USR_SP-TF_R0); /* Adjust the stack pointer */ \ 32902222606SBen Gras stmia r0, {r13-r14}^ /* Push the user mode registers */ 33002222606SBen Gras #else 33102222606SBen Gras #define PUSHUSERREGS \ 33202222606SBen Gras stmia sp, {r0-r14}^ /* Push the user mode registers */ 33302222606SBen Gras #endif 33402222606SBen Gras 33502222606SBen Gras #define PUSHFRAME \ 33602222606SBen Gras str lr, [sp, #-4]!; /* Push the return address */ \ 33784d9c625SLionel Sambuc sub sp, sp, #(TF_PC-TF_R0); /* Adjust the stack pointer */ \ 33802222606SBen Gras PUSHUSERREGS; /* Push the user mode registers */ \ 33902222606SBen Gras mov r0, r0; /* NOP for previous instruction */ \ 340*0a6a1f1dSLionel Sambuc mrs r0, spsr; /* Get the SPSR */ \ 34184d9c625SLionel Sambuc str r0, [sp, #-TF_R0]! /* Push the SPSR on the stack */ 34284d9c625SLionel Sambuc 34384d9c625SLionel Sambuc /* 34484d9c625SLionel Sambuc * Push a minimal trapframe so we can dispatch an interrupt from the 34584d9c625SLionel Sambuc * idle loop. The only reason the idle loop wakes up is to dispatch 34684d9c625SLionel Sambuc * interrupts so why take the avoid of a full exception when we can do 34784d9c625SLionel Sambuc * something minimal. 34884d9c625SLionel Sambuc */ 34984d9c625SLionel Sambuc #define PUSHIDLEFRAME \ 35084d9c625SLionel Sambuc str lr, [sp, #-4]!; /* save SVC32 lr */ \ 35184d9c625SLionel Sambuc str r6, [sp, #(TF_R6-TF_PC)]!; /* save callee-saved r6 */ \ 35284d9c625SLionel Sambuc str r4, [sp, #(TF_R4-TF_R6)]!; /* save callee-saved r4 */ \ 353*0a6a1f1dSLionel Sambuc mrs r0, cpsr; /* Get the CPSR */ \ 35484d9c625SLionel Sambuc str r0, [sp, #(-TF_R4)]! /* Push the CPSR on the stack */ 35584d9c625SLionel Sambuc 35684d9c625SLionel Sambuc /* 35784d9c625SLionel Sambuc * Push a trapframe to be used by cpu_switchto 35884d9c625SLionel Sambuc */ 35984d9c625SLionel Sambuc #define PUSHSWITCHFRAME(rX) \ 36084d9c625SLionel Sambuc mov ip, sp; \ 36184d9c625SLionel Sambuc sub sp, sp, #(TRAPFRAMESIZE-TF_R12); /* Adjust the stack pointer */ \ 36284d9c625SLionel Sambuc push {r4-r11}; /* Push the callee saved registers */ \ 36384d9c625SLionel Sambuc sub sp, sp, #TF_R4; /* reserve rest of trapframe */ \ 36484d9c625SLionel Sambuc str ip, [sp, #TF_SVC_SP]; \ 36584d9c625SLionel Sambuc str lr, [sp, #TF_SVC_LR]; \ 36684d9c625SLionel Sambuc str lr, [sp, #TF_PC]; \ 367*0a6a1f1dSLionel Sambuc mrs rX, cpsr; /* Get the CPSR */ \ 36884d9c625SLionel Sambuc str rX, [sp, #TF_SPSR] /* save in trapframe */ 36984d9c625SLionel Sambuc 37084d9c625SLionel Sambuc #define PUSHSWITCHFRAME1 \ 37184d9c625SLionel Sambuc mov ip, sp; \ 37284d9c625SLionel Sambuc sub sp, sp, #(TRAPFRAMESIZE-TF_R8); /* Adjust the stack pointer */ \ 37384d9c625SLionel Sambuc push {r4-r7}; /* Push some of the callee saved registers */ \ 37484d9c625SLionel Sambuc sub sp, sp, #TF_R4; /* reserve rest of trapframe */ \ 37584d9c625SLionel Sambuc str ip, [sp, #TF_SVC_SP]; \ 37684d9c625SLionel Sambuc str lr, [sp, #TF_SVC_LR]; \ 37784d9c625SLionel Sambuc str lr, [sp, #TF_PC] 37884d9c625SLionel Sambuc 37984d9c625SLionel Sambuc #if defined(_ARM_ARCH_DWORD_OK) && __ARM_EABI__ 38084d9c625SLionel Sambuc #define PUSHSWITCHFRAME2 \ 38184d9c625SLionel Sambuc strd r10, [sp, #TF_R10]; /* save r10 & r11 */ \ 38284d9c625SLionel Sambuc strd r8, [sp, #TF_R8]; /* save r8 & r9 */ \ 383*0a6a1f1dSLionel Sambuc mrs r0, cpsr; /* Get the CPSR */ \ 38484d9c625SLionel Sambuc str r0, [sp, #TF_SPSR] /* save in trapframe */ 38584d9c625SLionel Sambuc #else 38684d9c625SLionel Sambuc #define PUSHSWITCHFRAME2 \ 38784d9c625SLionel Sambuc add r0, sp, #TF_R8; /* get ptr to r8 and above */ \ 38884d9c625SLionel Sambuc stmia r0, {r8-r11}; /* save rest of registers */ \ 389*0a6a1f1dSLionel Sambuc mrs r0, cpsr; /* Get the CPSR */ \ 39084d9c625SLionel Sambuc str r0, [sp, #TF_SPSR] /* save in trapframe */ 39184d9c625SLionel Sambuc #endif 39202222606SBen Gras 39302222606SBen Gras /* 39402222606SBen Gras * PULLFRAME - macro to pull a trap frame from the stack in the current mode 39502222606SBen Gras * Since the current mode is used, the SVC lr field is ignored. 39602222606SBen Gras */ 39702222606SBen Gras 39802222606SBen Gras #define PULLFRAME \ 39984d9c625SLionel Sambuc ldr r0, [sp], #TF_R0; /* Pop the SPSR from stack */ \ 400*0a6a1f1dSLionel Sambuc msr spsr_fsxc, r0; \ 40102222606SBen Gras ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 40202222606SBen Gras mov r0, r0; /* NOP for previous instruction */ \ 40384d9c625SLionel Sambuc add sp, sp, #(TF_PC-TF_R0); /* Adjust the stack pointer */ \ 40402222606SBen Gras ldr lr, [sp], #0x0004 /* Pop the return address */ 40502222606SBen Gras 40684d9c625SLionel Sambuc #define PULLIDLEFRAME \ 40784d9c625SLionel Sambuc add sp, sp, #TF_R4; /* Adjust the stack pointer */ \ 40884d9c625SLionel Sambuc ldr r4, [sp], #(TF_R6-TF_R4); /* restore callee-saved r4 */ \ 40984d9c625SLionel Sambuc ldr r6, [sp], #(TF_PC-TF_R6); /* restore callee-saved r6 */ \ 41084d9c625SLionel Sambuc ldr lr, [sp], #4 /* Pop the return address */ 41184d9c625SLionel Sambuc 41284d9c625SLionel Sambuc /* 41384d9c625SLionel Sambuc * Pop a trapframe to be used by cpu_switchto (don't touch r0 & r1). 41484d9c625SLionel Sambuc */ 41584d9c625SLionel Sambuc #define PULLSWITCHFRAME \ 41684d9c625SLionel Sambuc add sp, sp, #TF_R4; /* Adjust the stack pointer */ \ 41784d9c625SLionel Sambuc pop {r4-r11}; /* pop the callee saved registers */ \ 41884d9c625SLionel Sambuc add sp, sp, #(TF_PC-TF_R12); /* Adjust the stack pointer */ \ 41984d9c625SLionel Sambuc ldr lr, [sp], #4; /* pop the return address */ 42084d9c625SLionel Sambuc 42102222606SBen Gras /* 42202222606SBen Gras * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode 42302222606SBen Gras * This should only be used if the processor is not currently in SVC32 42402222606SBen Gras * mode. The processor mode is switched to SVC mode and the trap frame is 42502222606SBen Gras * stored. The SVC lr field is used to store the previous value of 42602222606SBen Gras * lr in SVC mode. 42702222606SBen Gras * 42802222606SBen Gras * NOTE: r13 and r14 are stored separately as a work around for the 42902222606SBen Gras * SA110 rev 2 STM^ bug 43002222606SBen Gras */ 43102222606SBen Gras 43202222606SBen Gras #ifdef _ARM_ARCH_6 43302222606SBen Gras #define SET_CPSR_MODE(tmp, mode) \ 43402222606SBen Gras cps #(mode) 43502222606SBen Gras #else 43602222606SBen Gras #define SET_CPSR_MODE(tmp, mode) \ 43702222606SBen Gras mrs tmp, cpsr; /* Get the CPSR */ \ 43802222606SBen Gras bic tmp, tmp, #(PSR_MODE); /* Fix for SVC mode */ \ 43902222606SBen Gras orr tmp, tmp, #(mode); \ 44002222606SBen Gras msr cpsr_c, tmp /* Punch into SVC mode */ 44102222606SBen Gras #endif 44202222606SBen Gras 44302222606SBen Gras #define PUSHFRAMEINSVC \ 44402222606SBen Gras stmdb sp, {r0-r3}; /* Save 4 registers */ \ 44502222606SBen Gras mov r0, lr; /* Save xxx32 r14 */ \ 44602222606SBen Gras mov r1, sp; /* Save xxx32 sp */ \ 44702222606SBen Gras mrs r3, spsr; /* Save xxx32 spsr */ \ 44802222606SBen Gras SET_CPSR_MODE(r2, PSR_SVC32_MODE); \ 44902222606SBen Gras bic r2, sp, #7; /* Align new SVC sp */ \ 45002222606SBen Gras str r0, [r2, #-4]!; /* Push return address */ \ 45102222606SBen Gras stmdb r2!, {sp, lr}; /* Push SVC sp, lr */ \ 45202222606SBen Gras mov sp, r2; /* Keep stack aligned */ \ 453*0a6a1f1dSLionel Sambuc msr spsr_fsxc, r3; /* Restore correct spsr */ \ 45402222606SBen Gras ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 45584d9c625SLionel Sambuc sub sp, sp, #(TF_SVC_SP-TF_R0); /* Adjust the stack pointer */ \ 45602222606SBen Gras PUSHUSERREGS; /* Push the user mode registers */ \ 45702222606SBen Gras mov r0, r0; /* NOP for previous instruction */ \ 458*0a6a1f1dSLionel Sambuc mrs r0, spsr; /* Get the SPSR */ \ 45984d9c625SLionel Sambuc str r0, [sp, #-TF_R0]! /* Push the SPSR onto the stack */ 46002222606SBen Gras 46102222606SBen Gras /* 46202222606SBen Gras * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack 46302222606SBen Gras * in SVC32 mode and restore the saved processor mode and PC. 46402222606SBen Gras * This should be used when the SVC lr register needs to be restored on 46502222606SBen Gras * exit. 46602222606SBen Gras */ 46702222606SBen Gras 46802222606SBen Gras #define PULLFRAMEFROMSVCANDEXIT \ 46902222606SBen Gras ldr r0, [sp], #0x0008; /* Pop the SPSR from stack */ \ 470*0a6a1f1dSLionel Sambuc msr spsr_fsxc, r0; /* restore SPSR */ \ 47102222606SBen Gras ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 47202222606SBen Gras mov r0, r0; /* NOP for previous instruction */ \ 47384d9c625SLionel Sambuc add sp, sp, #(TF_SVC_SP-TF_R0); /* Adjust the stack pointer */ \ 47402222606SBen Gras ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 47502222606SBen Gras 47602222606SBen Gras #endif /* _LOCORE */ 47702222606SBen Gras 47802222606SBen Gras #endif /* _ARM32_FRAME_H_ */ 479