1#include <linux/init.h> 2#include <linux/linkage.h> 3 4#include <asm/assembler.h> 5#include <asm/asm-offsets.h> 6#include <asm/errno.h> 7#include <asm/thread_info.h> 8 9@ Bad Abort numbers 10@ ----------------- 11@ 12#define BAD_PREFETCH 0 13#define BAD_DATA 1 14#define BAD_ADDREXCPTN 2 15#define BAD_IRQ 3 16#define BAD_UNDEFINSTR 4 17 18@ 19@ Most of the stack format comes from struct pt_regs, but with 20@ the addition of 8 bytes for storing syscall args 5 and 6. 21@ This _must_ remain a multiple of 8 for EABI. 22@ 23#define S_OFF 8 24 25/* 26 * The SWI code relies on the fact that R0 is at the bottom of the stack 27 * (due to slow/fast restore user regs). 28 */ 29#if S_R0 != 0 30#error "Please fix" 31#endif 32 33 .macro zero_fp 34#ifdef CONFIG_FRAME_POINTER 35 mov fp, #0 36#endif 37 .endm 38 39 .macro alignment_trap, rtemp 40#ifdef CONFIG_ALIGNMENT_TRAP 41 ldr \rtemp, .LCcralign 42 ldr \rtemp, [\rtemp] 43 mcr p15, 0, \rtemp, c1, c0 44#endif 45 .endm 46 47 @ 48 @ Store/load the USER SP and LR registers by switching to the SYS 49 @ mode. Useful in Thumb-2 mode where "stm/ldm rd, {sp, lr}^" is not 50 @ available. Should only be called from SVC mode 51 @ 52 .macro store_user_sp_lr, rd, rtemp, offset = 0 53 mrs \rtemp, cpsr 54 eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE) 55 msr cpsr_c, \rtemp @ switch to the SYS mode 56 57 str sp, [\rd, #\offset] @ save sp_usr 58 str lr, [\rd, #\offset + 4] @ save lr_usr 59 60 eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE) 61 msr cpsr_c, \rtemp @ switch back to the SVC mode 62 .endm 63 64 .macro load_user_sp_lr, rd, rtemp, offset = 0 65 mrs \rtemp, cpsr 66 eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE) 67 msr cpsr_c, \rtemp @ switch to the SYS mode 68 69 ldr sp, [\rd, #\offset] @ load sp_usr 70 ldr lr, [\rd, #\offset + 4] @ load lr_usr 71 72 eor \rtemp, \rtemp, #(SVC_MODE ^ SYSTEM_MODE) 73 msr cpsr_c, \rtemp @ switch back to the SVC mode 74 .endm 75 76#ifndef CONFIG_THUMB2_KERNEL 77 .macro svc_exit, rpsr 78 msr spsr_cxsf, \rpsr 79#if defined(CONFIG_CPU_V6) 80 ldr r0, [sp] 81 strex r1, r2, [sp] @ clear the exclusive monitor 82 ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr 83#elif defined(CONFIG_CPU_32v6K) 84 clrex @ clear the exclusive monitor 85 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr 86#else 87 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr 88#endif 89 .endm 90 91 .macro restore_user_regs, fast = 0, offset = 0 92 ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr 93 ldr lr, [sp, #\offset + S_PC]! @ get pc 94 msr spsr_cxsf, r1 @ save in spsr_svc 95#if defined(CONFIG_CPU_V6) 96 strex r1, r2, [sp] @ clear the exclusive monitor 97#elif defined(CONFIG_CPU_32v6K) 98 clrex @ clear the exclusive monitor 99#endif 100 .if \fast 101 ldmdb sp, {r1 - lr}^ @ get calling r1 - lr 102 .else 103 ldmdb sp, {r0 - lr}^ @ get calling r0 - lr 104 .endif 105 mov r0, r0 @ ARMv5T and earlier require a nop 106 @ after ldm {}^ 107 add sp, sp, #S_FRAME_SIZE - S_PC 108 movs pc, lr @ return & move spsr_svc into cpsr 109 .endm 110 111 .macro get_thread_info, rd 112 mov \rd, sp, lsr #13 113 mov \rd, \rd, lsl #13 114 .endm 115 116 @ 117 @ 32-bit wide "mov pc, reg" 118 @ 119 .macro movw_pc, reg 120 mov pc, \reg 121 .endm 122#else /* CONFIG_THUMB2_KERNEL */ 123 .macro svc_exit, rpsr 124 ldr lr, [sp, #S_SP] @ top of the stack 125 ldrd r0, r1, [sp, #S_LR] @ calling lr and pc 126 clrex @ clear the exclusive monitor 127 stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context 128 ldmia sp, {r0 - r12} 129 mov sp, lr 130 ldr lr, [sp], #4 131 rfeia sp! 132 .endm 133 134 .macro restore_user_regs, fast = 0, offset = 0 135 clrex @ clear the exclusive monitor 136 mov r2, sp 137 load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr 138 ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr 139 ldr lr, [sp, #\offset + S_PC] @ get pc 140 add sp, sp, #\offset + S_SP 141 msr spsr_cxsf, r1 @ save in spsr_svc 142 .if \fast 143 ldmdb sp, {r1 - r12} @ get calling r1 - r12 144 .else 145 ldmdb sp, {r0 - r12} @ get calling r0 - r12 146 .endif 147 add sp, sp, #S_FRAME_SIZE - S_SP 148 movs pc, lr @ return & move spsr_svc into cpsr 149 .endm 150 151 .macro get_thread_info, rd 152 mov \rd, sp 153 lsr \rd, \rd, #13 154 mov \rd, \rd, lsl #13 155 .endm 156 157 @ 158 @ 32-bit wide "mov pc, reg" 159 @ 160 .macro movw_pc, reg 161 mov pc, \reg 162 nop 163 .endm 164#endif /* !CONFIG_THUMB2_KERNEL */ 165 166/* 167 * These are the registers used in the syscall handler, and allow us to 168 * have in theory up to 7 arguments to a function - r0 to r6. 169 * 170 * r7 is reserved for the system call number for thumb mode. 171 * 172 * Note that tbl == why is intentional. 173 * 174 * We must set at least "tsk" and "why" when calling ret_with_reschedule. 175 */ 176scno .req r7 @ syscall number 177tbl .req r8 @ syscall table pointer 178why .req r8 @ Linux syscall (!= 0) 179tsk .req r9 @ current thread_info 180