1129198Scognet/* $NetBSD: frame.h,v 1.6 2003/10/05 19:44:58 matt Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 1994-1997 Mark Brinicombe. 5129198Scognet * Copyright (c) 1994 Brini. 6129198Scognet * All rights reserved. 7129198Scognet * 8129198Scognet * This code is derived from software written for Brini by Mark Brinicombe 9129198Scognet * 10129198Scognet * Redistribution and use in source and binary forms, with or without 11129198Scognet * modification, are permitted provided that the following conditions 12129198Scognet * are met: 13129198Scognet * 1. Redistributions of source code must retain the above copyright 14129198Scognet * notice, this list of conditions and the following disclaimer. 15129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 16129198Scognet * notice, this list of conditions and the following disclaimer in the 17129198Scognet * documentation and/or other materials provided with the distribution. 18129198Scognet * 3. All advertising materials mentioning features or use of this software 19129198Scognet * must display the following acknowledgement: 20129198Scognet * This product includes software developed by Brini. 21129198Scognet * 4. The name of the company nor the name of the author may be used to 22129198Scognet * endorse or promote products derived from this software without specific 23129198Scognet * prior written permission. 24129198Scognet * 25129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 26129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28129198Scognet * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35129198Scognet * SUCH DAMAGE. 36129198Scognet * 37129198Scognet * $FreeBSD$ 38129198Scognet */ 39129198Scognet 40129198Scognet#ifndef _MACHINE_ASMACROS_H_ 41129198Scognet#define _MACHINE_ASMACROS_H_ 42129198Scognet 43239268Sgonzo#include <machine/asm.h> 44239268Sgonzo 45129198Scognet#ifdef _KERNEL 46129198Scognet 47129198Scognet#ifdef LOCORE 48239268Sgonzo#include "opt_global.h" 49129198Scognet 50129198Scognet/* 51129198Scognet * ASM macros for pushing and pulling trapframes from the stack 52129198Scognet * 53129198Scognet * These macros are used to handle the irqframe and trapframe structures 54129198Scognet * defined above. 55129198Scognet */ 56129198Scognet 57129198Scognet/* 58129198Scognet * PUSHFRAME - macro to push a trap frame on the stack in the current mode 59129198Scognet * Since the current mode is used, the SVC lr field is not defined. 60129198Scognet * 61129198Scognet * NOTE: r13 and r14 are stored separately as a work around for the 62129198Scognet * SA110 rev 2 STM^ bug 63129198Scognet */ 64239268Sgonzo#ifdef ARM_TP_ADDRESS 65129198Scognet#define PUSHFRAME \ 66253968Sandrew sub sp, sp, #4; /* Align the stack */ \ 67129198Scognet str lr, [sp, #-4]!; /* Push the return address */ \ 68129198Scognet sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 69129198Scognet stmia sp, {r0-r12}; /* Push the user mode registers */ \ 70129198Scognet add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 71129198Scognet stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 72129198Scognet mov r0, r0; /* NOP for previous instruction */ \ 73129198Scognet mrs r0, spsr_all; /* Put the SPSR on the stack */ \ 74174170Scognet str r0, [sp, #-4]!; \ 75175982Sraj ldr r0, =ARM_RAS_START; \ 76174170Scognet mov r1, #0; \ 77174170Scognet str r1, [r0]; \ 78174170Scognet mov r1, #0xffffffff; \ 79226443Scognet str r1, [r0, #4]; 80239268Sgonzo#else 81239268Sgonzo#define PUSHFRAME \ 82253968Sandrew sub sp, sp, #4; /* Align the stack */ \ 83239268Sgonzo str lr, [sp, #-4]!; /* Push the return address */ \ 84239268Sgonzo sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 85239268Sgonzo stmia sp, {r0-r12}; /* Push the user mode registers */ \ 86239268Sgonzo add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 87239268Sgonzo stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 88239268Sgonzo mov r0, r0; /* NOP for previous instruction */ \ 89239268Sgonzo mrs r0, spsr_all; /* Put the SPSR on the stack */ \ 90239268Sgonzo str r0, [sp, #-4]!; 91239268Sgonzo#endif 92129198Scognet 93129198Scognet/* 94129198Scognet * PULLFRAME - macro to pull a trap frame from the stack in the current mode 95129198Scognet * Since the current mode is used, the SVC lr field is ignored. 96129198Scognet */ 97129198Scognet 98239268Sgonzo#ifdef ARM_TP_ADDRESS 99129198Scognet#define PULLFRAME \ 100129198Scognet ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 101129198Scognet msr spsr_all, r0; \ 102129198Scognet ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 103129198Scognet mov r0, r0; /* NOP for previous instruction */ \ 104129198Scognet add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 105253968Sandrew ldr lr, [sp], #0x0004; /* Pull the return address */ \ 106253968Sandrew add sp, sp, #4 /* Align the stack */ 107239268Sgonzo#else 108239268Sgonzo#define PULLFRAME \ 109239268Sgonzo ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 110239268Sgonzo msr spsr_all, r0; \ 111239268Sgonzo clrex; \ 112239268Sgonzo ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 113239268Sgonzo mov r0, r0; /* NOP for previous instruction */ \ 114239268Sgonzo add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 115253968Sandrew ldr lr, [sp], #0x0004; /* Pull the return address */ \ 116253968Sandrew add sp, sp, #4 /* Align the stack */ 117239268Sgonzo#endif 118129198Scognet 119129198Scognet/* 120129198Scognet * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode 121129198Scognet * This should only be used if the processor is not currently in SVC32 122129198Scognet * mode. The processor mode is switched to SVC mode and the trap frame is 123129198Scognet * stored. The SVC lr field is used to store the previous value of 124236992Simp * lr in SVC mode. 125129198Scognet * 126129198Scognet * NOTE: r13 and r14 are stored separately as a work around for the 127129198Scognet * SA110 rev 2 STM^ bug 128129198Scognet */ 129239268Sgonzo#ifdef ARM_TP_ADDRESS 130129198Scognet#define PUSHFRAMEINSVC \ 131129198Scognet stmdb sp, {r0-r3}; /* Save 4 registers */ \ 132129198Scognet mov r0, lr; /* Save xxx32 r14 */ \ 133129198Scognet mov r1, sp; /* Save xxx32 sp */ \ 134129198Scognet mrs r3, spsr; /* Save xxx32 spsr */ \ 135129198Scognet mrs r2, cpsr; /* Get the CPSR */ \ 136129198Scognet bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 137129198Scognet orr r2, r2, #(PSR_SVC32_MODE); \ 138129198Scognet msr cpsr_c, r2; /* Punch into SVC mode */ \ 139129198Scognet mov r2, sp; /* Save SVC sp */ \ 140253968Sandrew bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ 141253968Sandrew sub sp, sp, #4; /* Pad trapframe to keep alignment */ \ 142129198Scognet str r0, [sp, #-4]!; /* Push return address */ \ 143129198Scognet str lr, [sp, #-4]!; /* Push SVC lr */ \ 144129198Scognet str r2, [sp, #-4]!; /* Push SVC sp */ \ 145129198Scognet msr spsr_all, r3; /* Restore correct spsr */ \ 146129198Scognet ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 147129198Scognet sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 148129198Scognet stmia sp, {r0-r12}; /* Push the user mode registers */ \ 149129198Scognet add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 150129198Scognet stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 151129198Scognet mov r0, r0; /* NOP for previous instruction */ \ 152175982Sraj ldr r5, =ARM_RAS_START; /* Check if there's any RAS */ \ 153226443Scognet ldr r4, [r5, #4]; /* reset it to point at the */ \ 154226443Scognet cmp r4, #0xffffffff; /* end of memory if necessary; */ \ 155226443Scognet movne r1, #0xffffffff; /* leave value in r4 for later */ \ 156226443Scognet strne r1, [r5, #4]; /* comparision against PC. */ \ 157226443Scognet ldr r3, [r5]; /* Retrieve global RAS_START */ \ 158226443Scognet cmp r3, #0; /* and reset it if non-zero. */ \ 159226443Scognet movne r1, #0; /* If non-zero RAS_START and */ \ 160226443Scognet strne r1, [r5]; /* PC was lower than RAS_END, */ \ 161226443Scognet ldrne r1, [r0, #16]; /* adjust the saved PC so that */ \ 162226443Scognet cmpne r4, r1; /* execution later resumes at */ \ 163226443Scognet strhi r3, [r0, #16]; /* the RAS_START location. */ \ 164226443Scognet mrs r0, spsr_all; \ 165226443Scognet str r0, [sp, #-4]! 166239268Sgonzo#else 167239268Sgonzo#define PUSHFRAMEINSVC \ 168239268Sgonzo stmdb sp, {r0-r3}; /* Save 4 registers */ \ 169239268Sgonzo mov r0, lr; /* Save xxx32 r14 */ \ 170239268Sgonzo mov r1, sp; /* Save xxx32 sp */ \ 171239268Sgonzo mrs r3, spsr; /* Save xxx32 spsr */ \ 172239268Sgonzo mrs r2, cpsr; /* Get the CPSR */ \ 173239268Sgonzo bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 174239268Sgonzo orr r2, r2, #(PSR_SVC32_MODE); \ 175239268Sgonzo msr cpsr_c, r2; /* Punch into SVC mode */ \ 176239268Sgonzo mov r2, sp; /* Save SVC sp */ \ 177253968Sandrew bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ 178253968Sandrew sub sp, sp, #4; /* Pad trapframe to keep alignment */ \ 179239268Sgonzo str r0, [sp, #-4]!; /* Push return address */ \ 180239268Sgonzo str lr, [sp, #-4]!; /* Push SVC lr */ \ 181239268Sgonzo str r2, [sp, #-4]!; /* Push SVC sp */ \ 182239268Sgonzo msr spsr_all, r3; /* Restore correct spsr */ \ 183239268Sgonzo ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 184239268Sgonzo sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 185239268Sgonzo stmia sp, {r0-r12}; /* Push the user mode registers */ \ 186239268Sgonzo add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 187239268Sgonzo stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 188239268Sgonzo mov r0, r0; /* NOP for previous instruction */ \ 189239268Sgonzo mrs r0, spsr_all; /* Put the SPSR on the stack */ \ 190239268Sgonzo str r0, [sp, #-4]! 191239268Sgonzo#endif 192129198Scognet 193129198Scognet/* 194129198Scognet * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack 195129198Scognet * in SVC32 mode and restore the saved processor mode and PC. 196129198Scognet * This should be used when the SVC lr register needs to be restored on 197129198Scognet * exit. 198129198Scognet */ 199129198Scognet 200239268Sgonzo#ifdef ARM_TP_ADDRESS 201129198Scognet#define PULLFRAMEFROMSVCANDEXIT \ 202129198Scognet ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 203129198Scognet msr spsr_all, r0; /* restore SPSR */ \ 204129198Scognet ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 205129198Scognet mov r0, r0; /* NOP for previous instruction */ \ 206129198Scognet add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 207129198Scognet ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 208239268Sgonzo#else 209239268Sgonzo#define PULLFRAMEFROMSVCANDEXIT \ 210239268Sgonzo ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 211239268Sgonzo msr spsr_all, r0; /* restore SPSR */ \ 212239268Sgonzo clrex; \ 213239268Sgonzo ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 214239268Sgonzo mov r0, r0; /* NOP for previous instruction */ \ 215239268Sgonzo add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 216239268Sgonzo ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 217252311Sandrew#endif 218252311Sandrew#if defined(__ARM_EABI__) 219252311Sandrew#define UNWINDSVCFRAME \ 220253968Sandrew .pad #(4); /* Skip stack alignment */ \ 221252311Sandrew .save {r13-r15}; /* Restore sp, lr, pc */ \ 222252311Sandrew .pad #(2*4); /* Skip user sp and lr */ \ 223252311Sandrew .save {r0-r12}; /* Restore r0-r12 */ \ 224252311Sandrew .pad #(4) /* Skip spsr */ 225252311Sandrew#else 226252311Sandrew#define UNWINDSVCFRAME 227252311Sandrew#endif 228129198Scognet 229129198Scognet#define DATA(name) \ 230129198Scognet .data ; \ 231129198Scognet _ALIGN_DATA ; \ 232129198Scognet .globl name ; \ 233129198Scognet .type name, %object ; \ 234129198Scognetname: 235129198Scognet 236239268Sgonzo#ifdef _ARM_ARCH_6 237239268Sgonzo#define AST_LOCALS 238239268Sgonzo#define GET_CURTHREAD_PTR(tmp) \ 239239268Sgonzo mrc p15, 0, tmp, c13, c0, 4; \ 240239268Sgonzo add tmp, tmp, #(PC_CURTHREAD) 241239268Sgonzo#else 242239268Sgonzo#define AST_LOCALS ;\ 243239268Sgonzo.Lcurthread: ;\ 244239268Sgonzo .word _C_LABEL(__pcpu) + PC_CURTHREAD 245129198Scognet 246239268Sgonzo#define GET_CURTHREAD_PTR(tmp) \ 247239268Sgonzo ldr tmp, .Lcurthread 248239268Sgonzo#endif 249239268Sgonzo 250135649Scognet#define DO_AST \ 251129198Scognet ldr r0, [sp] /* Get the SPSR from stack */ ;\ 252129198Scognet mrs r4, cpsr /* save CPSR */ ;\ 253157725Scognet orr r1, r4, #(I32_bit|F32_bit) ;\ 254135649Scognet msr cpsr_c, r1 /* Disable interrupts */ ;\ 255129198Scognet and r0, r0, #(PSR_MODE) /* Returning to USR mode? */ ;\ 256129198Scognet teq r0, #(PSR_USR32_MODE) ;\ 257129198Scognet bne 2f /* Nope, get out now */ ;\ 258157725Scognet bic r4, r4, #(I32_bit|F32_bit) ;\ 259239268Sgonzo1: GET_CURTHREAD_PTR(r5) ;\ 260129198Scognet ldr r5, [r5] ;\ 261135649Scognet ldr r1, [r5, #(TD_FLAGS)] ;\ 262135649Scognet and r1, r1, #(TDF_ASTPENDING|TDF_NEEDRESCHED) ;\ 263135649Scognet teq r1, #0x00000000 ;\ 264129198Scognet beq 2f /* Nope. Just bail */ ;\ 265129198Scognet msr cpsr_c, r4 /* Restore interrupts */ ;\ 266129198Scognet mov r0, sp ;\ 267135649Scognet bl _C_LABEL(ast) /* ast(frame) */ ;\ 268157725Scognet orr r0, r4, #(I32_bit|F32_bit) ;\ 269135649Scognet msr cpsr_c, r0 ;\ 270135649Scognet b 1b ;\ 271129198Scognet2: 272129198Scognet 273129198Scognet#endif /* LOCORE */ 274129198Scognet 275129198Scognet#endif /* _KERNEL */ 276129198Scognet 277129198Scognet#endif /* !_MACHINE_ASMACROS_H_ */ 278