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