1 /* $NetBSD: frame.h,v 1.6 2003/10/05 19:44:58 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 1994-1997 Mark Brinicombe. 5 * Copyright (c) 1994 Brini. 6 * All rights reserved. 7 * 8 * This code is derived from software written for Brini by Mark Brinicombe 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Brini. 21 * 4. The name of the company nor the name of the author may be used to 22 * endorse or promote products derived from this software without specific 23 * prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * $FreeBSD$ 38 */ 39 40 #ifndef _MACHINE_ASMACROS_H_ 41 #define _MACHINE_ASMACROS_H_ 42 43 #include <machine/asm.h> 44 45 #ifdef _KERNEL 46 47 #ifdef LOCORE 48 #include "opt_global.h" 49 50 /* 51 * ASM macros for pushing and pulling trapframes from the stack 52 * 53 * These macros are used to handle the irqframe and trapframe structures 54 * defined above. 55 */ 56 57 /* 58 * PUSHFRAME - macro to push a trap frame on the stack in the current mode 59 * Since the current mode is used, the SVC lr field is not defined. 60 * 61 * NOTE: r13 and r14 are stored separately as a work around for the 62 * SA110 rev 2 STM^ bug 63 */ 64 #ifdef ARM_TP_ADDRESS 65 #define PUSHFRAME \ 66 sub sp, sp, #4; /* Align the stack */ \ 67 str lr, [sp, #-4]!; /* Push the return address */ \ 68 sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 69 stmia sp, {r0-r12}; /* Push the user mode registers */ \ 70 add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 71 stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 72 mov r0, r0; /* NOP for previous instruction */ \ 73 mrs r0, spsr_all; /* Put the SPSR on the stack */ \ 74 str r0, [sp, #-4]!; \ 75 ldr r0, =ARM_RAS_START; \ 76 mov r1, #0; \ 77 str r1, [r0]; \ 78 mov r1, #0xffffffff; \ 79 str r1, [r0, #4]; 80 #else 81 #define PUSHFRAME \ 82 sub sp, sp, #4; /* Align the stack */ \ 83 str lr, [sp, #-4]!; /* Push the return address */ \ 84 sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 85 stmia sp, {r0-r12}; /* Push the user mode registers */ \ 86 add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 87 stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 88 mov r0, r0; /* NOP for previous instruction */ \ 89 mrs r0, spsr_all; /* Put the SPSR on the stack */ \ 90 str r0, [sp, #-4]!; 91 #endif 92 93 /* 94 * PULLFRAME - macro to pull a trap frame from the stack in the current mode 95 * Since the current mode is used, the SVC lr field is ignored. 96 */ 97 98 #ifdef ARM_TP_ADDRESS 99 #define PULLFRAME \ 100 ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 101 msr spsr_all, r0; \ 102 ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 103 mov r0, r0; /* NOP for previous instruction */ \ 104 add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 105 ldr lr, [sp], #0x0004; /* Pull the return address */ \ 106 add sp, sp, #4 /* Align the stack */ 107 #else 108 #define PULLFRAME \ 109 ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 110 msr spsr_all, r0; \ 111 clrex; \ 112 ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 113 mov r0, r0; /* NOP for previous instruction */ \ 114 add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 115 ldr lr, [sp], #0x0004; /* Pull the return address */ \ 116 add sp, sp, #4 /* Align the stack */ 117 #endif 118 119 /* 120 * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode 121 * This should only be used if the processor is not currently in SVC32 122 * mode. The processor mode is switched to SVC mode and the trap frame is 123 * stored. The SVC lr field is used to store the previous value of 124 * lr in SVC mode. 125 * 126 * NOTE: r13 and r14 are stored separately as a work around for the 127 * SA110 rev 2 STM^ bug 128 */ 129 #ifdef ARM_TP_ADDRESS 130 #define PUSHFRAMEINSVC \ 131 stmdb sp, {r0-r3}; /* Save 4 registers */ \ 132 mov r0, lr; /* Save xxx32 r14 */ \ 133 mov r1, sp; /* Save xxx32 sp */ \ 134 mrs r3, spsr; /* Save xxx32 spsr */ \ 135 mrs r2, cpsr; /* Get the CPSR */ \ 136 bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 137 orr r2, r2, #(PSR_SVC32_MODE); \ 138 msr cpsr_c, r2; /* Punch into SVC mode */ \ 139 mov r2, sp; /* Save SVC sp */ \ 140 bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ 141 sub sp, sp, #4; /* Pad trapframe to keep alignment */ \ 142 str r0, [sp, #-4]!; /* Push return address */ \ 143 str lr, [sp, #-4]!; /* Push SVC lr */ \ 144 str r2, [sp, #-4]!; /* Push SVC sp */ \ 145 msr spsr_all, r3; /* Restore correct spsr */ \ 146 ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 147 sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 148 stmia sp, {r0-r12}; /* Push the user mode registers */ \ 149 add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 150 stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 151 mov r0, r0; /* NOP for previous instruction */ \ 152 ldr r5, =ARM_RAS_START; /* Check if there's any RAS */ \ 153 ldr r4, [r5, #4]; /* reset it to point at the */ \ 154 cmp r4, #0xffffffff; /* end of memory if necessary; */ \ 155 movne r1, #0xffffffff; /* leave value in r4 for later */ \ 156 strne r1, [r5, #4]; /* comparision against PC. */ \ 157 ldr r3, [r5]; /* Retrieve global RAS_START */ \ 158 cmp r3, #0; /* and reset it if non-zero. */ \ 159 movne r1, #0; /* If non-zero RAS_START and */ \ 160 strne r1, [r5]; /* PC was lower than RAS_END, */ \ 161 ldrne r1, [r0, #16]; /* adjust the saved PC so that */ \ 162 cmpne r4, r1; /* execution later resumes at */ \ 163 strhi r3, [r0, #16]; /* the RAS_START location. */ \ 164 mrs r0, spsr_all; \ 165 str r0, [sp, #-4]! 166 #else 167 #define PUSHFRAMEINSVC \ 168 stmdb sp, {r0-r3}; /* Save 4 registers */ \ 169 mov r0, lr; /* Save xxx32 r14 */ \ 170 mov r1, sp; /* Save xxx32 sp */ \ 171 mrs r3, spsr; /* Save xxx32 spsr */ \ 172 mrs r2, cpsr; /* Get the CPSR */ \ 173 bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 174 orr r2, r2, #(PSR_SVC32_MODE); \ 175 msr cpsr_c, r2; /* Punch into SVC mode */ \ 176 mov r2, sp; /* Save SVC sp */ \ 177 bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ 178 sub sp, sp, #4; /* Pad trapframe to keep alignment */ \ 179 str r0, [sp, #-4]!; /* Push return address */ \ 180 str lr, [sp, #-4]!; /* Push SVC lr */ \ 181 str r2, [sp, #-4]!; /* Push SVC sp */ \ 182 msr spsr_all, r3; /* Restore correct spsr */ \ 183 ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 184 sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 185 stmia sp, {r0-r12}; /* Push the user mode registers */ \ 186 add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 187 stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 188 mov r0, r0; /* NOP for previous instruction */ \ 189 mrs r0, spsr_all; /* Put the SPSR on the stack */ \ 190 str r0, [sp, #-4]! 191 #endif 192 193 /* 194 * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack 195 * in SVC32 mode and restore the saved processor mode and PC. 196 * This should be used when the SVC lr register needs to be restored on 197 * exit. 198 */ 199 200 #ifdef ARM_TP_ADDRESS 201 #define PULLFRAMEFROMSVCANDEXIT \ 202 ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 203 msr spsr_all, r0; /* restore SPSR */ \ 204 ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 205 mov r0, r0; /* NOP for previous instruction */ \ 206 add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 207 ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 208 #else 209 #define PULLFRAMEFROMSVCANDEXIT \ 210 ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 211 msr spsr_all, r0; /* restore SPSR */ \ 212 clrex; \ 213 ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 214 mov r0, r0; /* NOP for previous instruction */ \ 215 add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 216 ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 217 #endif 218 #if defined(__ARM_EABI__) 219 #define UNWINDSVCFRAME \ 220 .pad #(4); /* Skip stack alignment */ \ 221 .save {r13-r15}; /* Restore sp, lr, pc */ \ 222 .pad #(2*4); /* Skip user sp and lr */ \ 223 .save {r0-r12}; /* Restore r0-r12 */ \ 224 .pad #(4) /* Skip spsr */ 225 #else 226 #define UNWINDSVCFRAME 227 #endif 228 229 #define DATA(name) \ 230 .data ; \ 231 _ALIGN_DATA ; \ 232 .globl name ; \ 233 .type name, %object ; \ 234 name: 235 236 #ifdef _ARM_ARCH_6 237 #define AST_LOCALS 238 #define GET_CURTHREAD_PTR(tmp) \ 239 mrc p15, 0, tmp, c13, c0, 4; \ 240 add tmp, tmp, #(PC_CURTHREAD) 241 #else 242 #define AST_LOCALS ;\ 243 .Lcurthread: ;\ 244 .word _C_LABEL(__pcpu) + PC_CURTHREAD 245 246 #define GET_CURTHREAD_PTR(tmp) \ 247 ldr tmp, .Lcurthread 248 #endif 249 250 #define DO_AST \ 251 ldr r0, [sp] /* Get the SPSR from stack */ ;\ 252 mrs r4, cpsr /* save CPSR */ ;\ 253 orr r1, r4, #(I32_bit|F32_bit) ;\ 254 msr cpsr_c, r1 /* Disable interrupts */ ;\ 255 and r0, r0, #(PSR_MODE) /* Returning to USR mode? */ ;\ 256 teq r0, #(PSR_USR32_MODE) ;\ 257 bne 2f /* Nope, get out now */ ;\ 258 bic r4, r4, #(I32_bit|F32_bit) ;\ 259 1: GET_CURTHREAD_PTR(r5) ;\ 260 ldr r5, [r5] ;\ 261 ldr r1, [r5, #(TD_FLAGS)] ;\ 262 and r1, r1, #(TDF_ASTPENDING|TDF_NEEDRESCHED) ;\ 263 teq r1, #0x00000000 ;\ 264 beq 2f /* Nope. Just bail */ ;\ 265 msr cpsr_c, r4 /* Restore interrupts */ ;\ 266 mov r0, sp ;\ 267 bl _C_LABEL(ast) /* ast(frame) */ ;\ 268 orr r0, r4, #(I32_bit|F32_bit) ;\ 269 msr cpsr_c, r0 ;\ 270 b 1b ;\ 271 2: 272 273 #endif /* LOCORE */ 274 275 #endif /* _KERNEL */ 276 277 #endif /* !_MACHINE_ASMACROS_H_ */ 278