1*81621933Sguenther /* $OpenBSD: frame.h,v 1.14 2022/12/08 01:25:44 guenther Exp $ */ 2e1e4f5b1Sdrahn /* $NetBSD: frame.h,v 1.9 2003/12/01 08:48:33 scw Exp $ */ 3e1e4f5b1Sdrahn 4e1e4f5b1Sdrahn /* 5e1e4f5b1Sdrahn * Copyright (c) 1994-1997 Mark Brinicombe. 6e1e4f5b1Sdrahn * Copyright (c) 1994 Brini. 7e1e4f5b1Sdrahn * All rights reserved. 8e1e4f5b1Sdrahn * 9e1e4f5b1Sdrahn * This code is derived from software written for Brini by Mark Brinicombe 10e1e4f5b1Sdrahn * 11e1e4f5b1Sdrahn * Redistribution and use in source and binary forms, with or without 12e1e4f5b1Sdrahn * modification, are permitted provided that the following conditions 13e1e4f5b1Sdrahn * are met: 14e1e4f5b1Sdrahn * 1. Redistributions of source code must retain the above copyright 15e1e4f5b1Sdrahn * notice, this list of conditions and the following disclaimer. 16e1e4f5b1Sdrahn * 2. Redistributions in binary form must reproduce the above copyright 17e1e4f5b1Sdrahn * notice, this list of conditions and the following disclaimer in the 18e1e4f5b1Sdrahn * documentation and/or other materials provided with the distribution. 19e1e4f5b1Sdrahn * 3. All advertising materials mentioning features or use of this software 20e1e4f5b1Sdrahn * must display the following acknowledgement: 21e1e4f5b1Sdrahn * This product includes software developed by Brini. 22e1e4f5b1Sdrahn * 4. The name of the company nor the name of the author may be used to 23e1e4f5b1Sdrahn * endorse or promote products derived from this software without specific 24e1e4f5b1Sdrahn * prior written permission. 25e1e4f5b1Sdrahn * 26e1e4f5b1Sdrahn * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 27e1e4f5b1Sdrahn * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28e1e4f5b1Sdrahn * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29e1e4f5b1Sdrahn * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 30e1e4f5b1Sdrahn * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31e1e4f5b1Sdrahn * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32e1e4f5b1Sdrahn * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33e1e4f5b1Sdrahn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34e1e4f5b1Sdrahn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35e1e4f5b1Sdrahn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36e1e4f5b1Sdrahn * SUCH DAMAGE. 37e1e4f5b1Sdrahn * 38e1e4f5b1Sdrahn * RiscBSD kernel project 39e1e4f5b1Sdrahn * 40e1e4f5b1Sdrahn * frame.h 41e1e4f5b1Sdrahn * 42e1e4f5b1Sdrahn * Stack frames structures 43e1e4f5b1Sdrahn * 44e1e4f5b1Sdrahn * Created : 30/09/94 45e1e4f5b1Sdrahn */ 46e1e4f5b1Sdrahn 47e1e4f5b1Sdrahn #ifndef _ARM_FRAME_H_ 48e1e4f5b1Sdrahn #define _ARM_FRAME_H_ 49e1e4f5b1Sdrahn 50e1e4f5b1Sdrahn #ifndef _LOCORE 51e1e4f5b1Sdrahn 52e1e4f5b1Sdrahn #include <sys/signal.h> 53e1e4f5b1Sdrahn 54e1e4f5b1Sdrahn /* 55e1e4f5b1Sdrahn * Trap frame. Pushed onto the kernel stack on a trap (synchronous exception). 56e1e4f5b1Sdrahn */ 57e1e4f5b1Sdrahn 58e1e4f5b1Sdrahn typedef struct trapframe { 595ab58429Smiod register_t tf_spsr; 60e1e4f5b1Sdrahn register_t tf_r0; 61e1e4f5b1Sdrahn register_t tf_r1; 62e1e4f5b1Sdrahn register_t tf_r2; 63e1e4f5b1Sdrahn register_t tf_r3; 64e1e4f5b1Sdrahn register_t tf_r4; 65e1e4f5b1Sdrahn register_t tf_r5; 66e1e4f5b1Sdrahn register_t tf_r6; 67e1e4f5b1Sdrahn register_t tf_r7; 68e1e4f5b1Sdrahn register_t tf_r8; 69e1e4f5b1Sdrahn register_t tf_r9; 70e1e4f5b1Sdrahn register_t tf_r10; 71e1e4f5b1Sdrahn register_t tf_r11; 72e1e4f5b1Sdrahn register_t tf_r12; 73e1e4f5b1Sdrahn register_t tf_usr_sp; 74e1e4f5b1Sdrahn register_t tf_usr_lr; 755ab58429Smiod register_t tf_svc_sp; 765ab58429Smiod register_t tf_svc_lr; 77e1e4f5b1Sdrahn register_t tf_pc; 7857ef8d3bSpatrick register_t tf_pad; 79e1e4f5b1Sdrahn } trapframe_t; 80e1e4f5b1Sdrahn 81e1e4f5b1Sdrahn /* Register numbers */ 82e1e4f5b1Sdrahn #define tf_r13 tf_usr_sp 83e1e4f5b1Sdrahn #define tf_r14 tf_usr_lr 84e1e4f5b1Sdrahn #define tf_r15 tf_pc 85e1e4f5b1Sdrahn 86c73c9118Spatrick /* Determine if a fault came from user mode */ 87c73c9118Spatrick #define TRAP_USERMODE(tf) ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE) 88c73c9118Spatrick 89e1e4f5b1Sdrahn /* 90e1e4f5b1Sdrahn * Signal frame. Pushed onto user stack before calling sigcode. 91e1e4f5b1Sdrahn */ 92e1e4f5b1Sdrahn 93e1e4f5b1Sdrahn struct sigframe { 94e1e4f5b1Sdrahn int sf_signum; 95e1e4f5b1Sdrahn siginfo_t *sf_sip; 96e1e4f5b1Sdrahn struct sigcontext *sf_scp; 97e1e4f5b1Sdrahn sig_t sf_handler; 98e1e4f5b1Sdrahn struct sigcontext sf_sc; 99e1e4f5b1Sdrahn siginfo_t sf_si; 100e1e4f5b1Sdrahn }; 101e1e4f5b1Sdrahn 1025ab58429Smiod /* the pointers are used in the trampoline code to locate the ucontext */ 103e1e4f5b1Sdrahn #if 0 104e1e4f5b1Sdrahn struct sigframe_siginfo { 105e1e4f5b1Sdrahn siginfo_t sf_si; /* actual saved siginfo */ 106e1e4f5b1Sdrahn ucontext_t sf_uc; /* actual saved ucontext */ 107e1e4f5b1Sdrahn }; 108e1e4f5b1Sdrahn #endif 109e1e4f5b1Sdrahn 110e1e4f5b1Sdrahn #if 0 111e1e4f5b1Sdrahn #ifdef _KERNEL 112e1e4f5b1Sdrahn void sendsig_sigcontext(const ksiginfo_t *, const sigset_t *); 113e1e4f5b1Sdrahn #endif 114e1e4f5b1Sdrahn #endif 115e1e4f5b1Sdrahn 116e1e4f5b1Sdrahn #endif /* _LOCORE */ 117e1e4f5b1Sdrahn 118e1e4f5b1Sdrahn #ifndef _LOCORE 119e1e4f5b1Sdrahn 120e1e4f5b1Sdrahn /* 121e1e4f5b1Sdrahn * System stack frames. 122e1e4f5b1Sdrahn */ 123e1e4f5b1Sdrahn 124e1e4f5b1Sdrahn typedef struct irqframe { 125e1e4f5b1Sdrahn unsigned int if_spsr; 126e1e4f5b1Sdrahn unsigned int if_r0; 127e1e4f5b1Sdrahn unsigned int if_r1; 128e1e4f5b1Sdrahn unsigned int if_r2; 129e1e4f5b1Sdrahn unsigned int if_r3; 130e1e4f5b1Sdrahn unsigned int if_r4; 131e1e4f5b1Sdrahn unsigned int if_r5; 132e1e4f5b1Sdrahn unsigned int if_r6; 133e1e4f5b1Sdrahn unsigned int if_r7; 134e1e4f5b1Sdrahn unsigned int if_r8; 135e1e4f5b1Sdrahn unsigned int if_r9; 136e1e4f5b1Sdrahn unsigned int if_r10; 137e1e4f5b1Sdrahn unsigned int if_r11; 138e1e4f5b1Sdrahn unsigned int if_r12; 139e1e4f5b1Sdrahn unsigned int if_usr_sp; 140e1e4f5b1Sdrahn unsigned int if_usr_lr; 141e1e4f5b1Sdrahn unsigned int if_svc_sp; 142e1e4f5b1Sdrahn unsigned int if_svc_lr; 143e1e4f5b1Sdrahn unsigned int if_pc; 14457ef8d3bSpatrick unsigned int if_pad; 145e1e4f5b1Sdrahn } irqframe_t; 146e1e4f5b1Sdrahn 147e1e4f5b1Sdrahn #define clockframe irqframe 148e1e4f5b1Sdrahn 149e1e4f5b1Sdrahn /* 150e1e4f5b1Sdrahn * Switch frame 151e1e4f5b1Sdrahn */ 152e1e4f5b1Sdrahn 153e1e4f5b1Sdrahn struct switchframe { 15457ef8d3bSpatrick u_int sf_pad; 155e1e4f5b1Sdrahn u_int sf_r4; 156e1e4f5b1Sdrahn u_int sf_r5; 157e1e4f5b1Sdrahn u_int sf_r6; 158e1e4f5b1Sdrahn u_int sf_r7; 159e1e4f5b1Sdrahn u_int sf_pc; 160e1e4f5b1Sdrahn }; 161e1e4f5b1Sdrahn 162e1e4f5b1Sdrahn /* 163e1e4f5b1Sdrahn * Stack frame. Used during stack traces (db_trace.c) 164e1e4f5b1Sdrahn */ 165e1e4f5b1Sdrahn struct frame { 166e1e4f5b1Sdrahn u_int fr_fp; 167e1e4f5b1Sdrahn u_int fr_sp; 168e1e4f5b1Sdrahn u_int fr_lr; 169e1e4f5b1Sdrahn u_int fr_pc; 170e1e4f5b1Sdrahn }; 171e1e4f5b1Sdrahn 172e1e4f5b1Sdrahn #else /* _LOCORE */ 173e1e4f5b1Sdrahn 1745ab58429Smiod #define AST_LOCALS \ 175e1e4f5b1Sdrahn .Laflt_astpending: ;\ 176*81621933Sguenther .word astpending 177e1e4f5b1Sdrahn 1785ab58429Smiod #define DO_AST \ 179e1e4f5b1Sdrahn ldr r0, [sp] /* Get the SPSR from stack */ ;\ 180e1e4f5b1Sdrahn mrs r4, cpsr /* save CPSR */ ;\ 181e1e4f5b1Sdrahn and r0, r0, #(PSR_MODE) /* Returning to USR mode? */ ;\ 182e1e4f5b1Sdrahn teq r0, #(PSR_USR32_MODE) ;\ 183e1e4f5b1Sdrahn ldreq r5, .Laflt_astpending ;\ 184e1e4f5b1Sdrahn bne 2f /* Nope, get out now */ ;\ 185ebd24745Sjsg bic r4, r4, #(PSR_I) ;\ 186ebd24745Sjsg 1: orr r0, r4, #(PSR_I) /* Disable IRQs */ ;\ 187e1e4f5b1Sdrahn msr cpsr_c, r0 ;\ 188e1e4f5b1Sdrahn ldr r1, [r5] /* Pending AST? */ ;\ 189e1e4f5b1Sdrahn teq r1, #0x00000000 ;\ 190e1e4f5b1Sdrahn beq 2f /* Nope. Just bail */ ;\ 191e1e4f5b1Sdrahn mov r1, #0x00000000 ;\ 192e1e4f5b1Sdrahn str r1, [r5] /* Clear astpending */ ;\ 193e1e4f5b1Sdrahn msr cpsr_c, r4 /* Restore interrupts */ ;\ 194e1e4f5b1Sdrahn mov r0, sp ;\ 195e1e4f5b1Sdrahn adr lr, 1b ;\ 196*81621933Sguenther b ast /* ast(frame) */ ;\ 197e1e4f5b1Sdrahn 2: 198e1e4f5b1Sdrahn 199e1e4f5b1Sdrahn /* 200e1e4f5b1Sdrahn * ASM macros for pushing and pulling trapframes from the stack 201e1e4f5b1Sdrahn * 202e1e4f5b1Sdrahn * These macros are used to handle the irqframe and trapframe structures 203e1e4f5b1Sdrahn * defined above. 204e1e4f5b1Sdrahn */ 205e1e4f5b1Sdrahn 206e1e4f5b1Sdrahn /* 207570b3570Spatrick * CLREX - On ARMv7 machines that support atomic instructions, we need 208570b3570Spatrick * to clear the exclusive monitors on kernel exit, so that a userland 209570b3570Spatrick * atomic store can't succeed due to an unrelated outstanding atomic 210570b3570Spatrick * operation. ARM also highly recommends clearing the monitor on data 211570b3570Spatrick * aborts, as the monitor state after taking a data abort is unknown. 212570b3570Spatrick * Issuing a clrex on kernel entry and on kernel exit is the easiest 213570b3570Spatrick * way to take care of both issues and to make sure that the kernel 214570b3570Spatrick * and userland do not leave any outstanding reserves active. 215570b3570Spatrick */ 216570b3570Spatrick 217570b3570Spatrick /* 218e1e4f5b1Sdrahn * PUSHFRAME - macro to push a trap frame on the stack in the current mode 219e1e4f5b1Sdrahn * Since the current mode is used, the SVC lr field is not defined. 220e1e4f5b1Sdrahn */ 221e1e4f5b1Sdrahn 222e1e4f5b1Sdrahn #define PUSHFRAME \ 22304e4a795Sjsg clrex; \ 22457ef8d3bSpatrick sub sp, sp, #4; /* Align the stack */ \ 225e1e4f5b1Sdrahn str lr, [sp, #-4]!; /* Push the return address */ \ 226e1e4f5b1Sdrahn sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 2275ab58429Smiod stmia sp, {r0-r14}^; /* Push the user mode registers */ \ 228e1e4f5b1Sdrahn mov r0, r0; /* NOP for previous instruction */ \ 22930335e0aSjsg mrs r0, spsr; /* Put the SPSR on the stack */ \ 230e1e4f5b1Sdrahn str r0, [sp, #-4]! 231e1e4f5b1Sdrahn 232e1e4f5b1Sdrahn /* 233e1e4f5b1Sdrahn * PULLFRAME - macro to pull a trap frame from the stack in the current mode 234e1e4f5b1Sdrahn * Since the current mode is used, the SVC lr field is ignored. 235e1e4f5b1Sdrahn */ 236e1e4f5b1Sdrahn 237e1e4f5b1Sdrahn #define PULLFRAME \ 23804e4a795Sjsg clrex; \ 239e1e4f5b1Sdrahn ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 2403a5a1032Sjsg msr spsr_fsxc, r0; \ 241e1e4f5b1Sdrahn ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 242e1e4f5b1Sdrahn mov r0, r0; /* NOP for previous instruction */ \ 243e1e4f5b1Sdrahn add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 24457ef8d3bSpatrick ldr lr, [sp], #0x0004; /* Pull the return address */ \ 24557ef8d3bSpatrick add sp, sp, #4 /* Align the stack */ 246e1e4f5b1Sdrahn 247e1e4f5b1Sdrahn /* 248e1e4f5b1Sdrahn * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode 249e1e4f5b1Sdrahn * This should only be used if the processor is not currently in SVC32 250e1e4f5b1Sdrahn * mode. The processor mode is switched to SVC mode and the trap frame is 251e1e4f5b1Sdrahn * stored. The SVC lr field is used to store the previous value of 252e1e4f5b1Sdrahn * lr in SVC mode. 253e1e4f5b1Sdrahn */ 254e1e4f5b1Sdrahn 255e1e4f5b1Sdrahn #define PUSHFRAMEINSVC \ 25604e4a795Sjsg clrex; \ 257e1e4f5b1Sdrahn stmdb sp, {r0-r3}; /* Save 4 registers */ \ 258e1e4f5b1Sdrahn mov r0, lr; /* Save xxx32 r14 */ \ 259e1e4f5b1Sdrahn mov r1, sp; /* Save xxx32 sp */ \ 260e1e4f5b1Sdrahn mrs r3, spsr; /* Save xxx32 spsr */ \ 261e1e4f5b1Sdrahn mrs r2, cpsr; /* Get the CPSR */ \ 262e1e4f5b1Sdrahn bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 263e1e4f5b1Sdrahn orr r2, r2, #(PSR_SVC32_MODE); \ 264e1e4f5b1Sdrahn msr cpsr_c, r2; /* Punch into SVC mode */ \ 265e1e4f5b1Sdrahn mov r2, sp; /* Save SVC sp */ \ 26657ef8d3bSpatrick bic sp, sp, #7; /* Align sp to an 8-byte address */ \ 26757ef8d3bSpatrick sub sp, sp, #4; /* Pad trapframe to keep alignment */ \ 268e1e4f5b1Sdrahn str r0, [sp, #-4]!; /* Push return address */ \ 269e1e4f5b1Sdrahn str lr, [sp, #-4]!; /* Push SVC lr */ \ 270e1e4f5b1Sdrahn str r2, [sp, #-4]!; /* Push SVC sp */ \ 2713a5a1032Sjsg msr spsr_fsxc, r3; /* Restore correct spsr */ \ 272e1e4f5b1Sdrahn ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 273e1e4f5b1Sdrahn sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 2745ab58429Smiod stmia sp, {r0-r14}^; /* Push the user mode registers */ \ 275e1e4f5b1Sdrahn mov r0, r0; /* NOP for previous instruction */ \ 27630335e0aSjsg mrs r0, spsr; /* Put the SPSR on the stack */ \ 277e1e4f5b1Sdrahn str r0, [sp, #-4]! 278e1e4f5b1Sdrahn 279e1e4f5b1Sdrahn /* 280e1e4f5b1Sdrahn * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack 281e1e4f5b1Sdrahn * in SVC32 mode and restore the saved processor mode and PC. 282e1e4f5b1Sdrahn * This should be used when the SVC lr register needs to be restored on 283e1e4f5b1Sdrahn * exit. 284e1e4f5b1Sdrahn */ 285e1e4f5b1Sdrahn 286e1e4f5b1Sdrahn #define PULLFRAMEFROMSVCANDEXIT \ 28704e4a795Sjsg clrex; \ 288e1e4f5b1Sdrahn ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \ 2893a5a1032Sjsg msr spsr_fsxc, r0; /* restore SPSR */ \ 290e1e4f5b1Sdrahn ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 291e1e4f5b1Sdrahn mov r0, r0; /* NOP for previous instruction */ \ 292e1e4f5b1Sdrahn add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 293e1e4f5b1Sdrahn ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 294e1e4f5b1Sdrahn 295e1e4f5b1Sdrahn #endif /* _LOCORE */ 296e1e4f5b1Sdrahn 297e1e4f5b1Sdrahn #endif /* _ARM_FRAME_H_ */ 298