1/* 2 * This file contains the code that gets mapped at the upper end of each task's text 3 * region. For now, it contains the signal trampoline code only. 4 * 5 * Copyright (C) 1999-2003 Hewlett-Packard Co 6 * David Mosberger-Tang <davidm@hpl.hp.com> 7 */ 8 9 10#include <asm/asmmacro.h> 11#include <asm/errno.h> 12#include <asm/asm-offsets.h> 13#include <asm/sigcontext.h> 14#include <asm/system.h> 15#include <asm/unistd.h> 16 17/* 18 * We can't easily refer to symbols inside the kernel. To avoid full runtime relocation, 19 * complications with the linker (which likes to create PLT stubs for branches 20 * to targets outside the shared object) and to avoid multi-phase kernel builds, we 21 * simply create minimalistic "patch lists" in special ELF sections. 22 */ 23 .section ".data.patch.fsyscall_table", "a" 24 .previous 25#define LOAD_FSYSCALL_TABLE(reg) \ 26[1:] movl reg=0; \ 27 .xdata4 ".data.patch.fsyscall_table", 1b-. 28 29 .section ".data.patch.brl_fsys_bubble_down", "a" 30 .previous 31#define BRL_COND_FSYS_BUBBLE_DOWN(pr) \ 32[1:](pr)brl.cond.sptk 0; \ 33 .xdata4 ".data.patch.brl_fsys_bubble_down", 1b-. 34 35GLOBAL_ENTRY(__kernel_syscall_via_break) 36 .prologue 37 .altrp b6 38 .body 39 /* 40 * Note: for (fast) syscall restart to work, the break instruction must be 41 * the first one in the bundle addressed by syscall_via_break. 42 */ 43{ .mib 44 break 0x100000 45 nop.i 0 46 br.ret.sptk.many b6 47} 48END(__kernel_syscall_via_break) 49 50/* 51 * On entry: 52 * r11 = saved ar.pfs 53 * r15 = system call # 54 * b0 = saved return address 55 * b6 = return address 56 * On exit: 57 * r11 = saved ar.pfs 58 * r15 = system call # 59 * b0 = saved return address 60 * all other "scratch" registers: undefined 61 * all "preserved" registers: same as on entry 62 */ 63 64GLOBAL_ENTRY(__kernel_syscall_via_epc) 65 .prologue 66 .altrp b6 67 .body 68{ 69 /* 70 * Note: the kernel cannot assume that the first two instructions in this 71 * bundle get executed. The remaining code must be safe even if 72 * they do not get executed. 73 */ 74 adds r17=-1024,r15 // A 75 mov r10=0 // A default to successful syscall execution 76 epc // B causes split-issue 77} 78 ;; 79 rsm psr.be | psr.i // M2 (5 cyc to srlz.d) 80 LOAD_FSYSCALL_TABLE(r14) // X 81 ;; 82 mov r16=IA64_KR(CURRENT) // M2 (12 cyc) 83 shladd r18=r17,3,r14 // A 84 mov r19=NR_syscalls-1 // A 85 ;; 86 lfetch [r18] // M0|1 87 mov r29=psr // M2 (12 cyc) 88 // If r17 is a NaT, p6 will be zero 89 cmp.geu p6,p7=r19,r17 // A (sysnr > 0 && sysnr < 1024+NR_syscalls)? 90 ;; 91 mov r21=ar.fpsr // M2 (12 cyc) 92 tnat.nz p10,p9=r15 // I0 93 mov.i r26=ar.pfs // I0 (would stall anyhow due to srlz.d...) 94 ;; 95 srlz.d // M0 (forces split-issue) ensure PSR.BE==0 96(p6) ld8 r18=[r18] // M0|1 97 nop.i 0 98 ;; 99 nop.m 0 100(p6) tbit.z.unc p8,p0=r18,0 // I0 (dual-issues with "mov b7=r18"!) 101 nop.i 0 102 ;; 103(p8) ssm psr.i 104(p6) mov b7=r18 // I0 105(p8) br.dptk.many b7 // B 106 107 mov r27=ar.rsc // M2 (12 cyc) 108/* 109 * brl.cond doesn't work as intended because the linker would convert this branch 110 * into a branch to a PLT. Perhaps there will be a way to avoid this with some 111 * future version of the linker. In the meantime, we just use an indirect branch 112 * instead. 113 */ 114#ifdef CONFIG_ITANIUM 115(p6) add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry 116 ;; 117(p6) ld8 r14=[r14] // r14 <- fsys_bubble_down 118 ;; 119(p6) mov b7=r14 120(p6) br.sptk.many b7 121#else 122 BRL_COND_FSYS_BUBBLE_DOWN(p6) 123#endif 124 ssm psr.i 125 mov r10=-1 126(p10) mov r8=EINVAL 127(p9) mov r8=ENOSYS 128 FSYS_RETURN 129END(__kernel_syscall_via_epc) 130 131# define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET) 132# define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET) 133# define ARG2_OFF (16 + IA64_SIGFRAME_ARG2_OFFSET) 134# define SIGHANDLER_OFF (16 + IA64_SIGFRAME_HANDLER_OFFSET) 135# define SIGCONTEXT_OFF (16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET) 136 137# define FLAGS_OFF IA64_SIGCONTEXT_FLAGS_OFFSET 138# define CFM_OFF IA64_SIGCONTEXT_CFM_OFFSET 139# define FR6_OFF IA64_SIGCONTEXT_FR6_OFFSET 140# define BSP_OFF IA64_SIGCONTEXT_AR_BSP_OFFSET 141# define RNAT_OFF IA64_SIGCONTEXT_AR_RNAT_OFFSET 142# define UNAT_OFF IA64_SIGCONTEXT_AR_UNAT_OFFSET 143# define FPSR_OFF IA64_SIGCONTEXT_AR_FPSR_OFFSET 144# define PR_OFF IA64_SIGCONTEXT_PR_OFFSET 145# define RP_OFF IA64_SIGCONTEXT_IP_OFFSET 146# define SP_OFF IA64_SIGCONTEXT_R12_OFFSET 147# define RBS_BASE_OFF IA64_SIGCONTEXT_RBS_BASE_OFFSET 148# define LOADRS_OFF IA64_SIGCONTEXT_LOADRS_OFFSET 149# define base0 r2 150# define base1 r3 151 /* 152 * When we get here, the memory stack looks like this: 153 * 154 * +===============================+ 155 * | | 156 * // struct sigframe // 157 * | | 158 * +-------------------------------+ <-- sp+16 159 * | 16 byte of scratch | 160 * | space | 161 * +-------------------------------+ <-- sp 162 * 163 * The register stack looks _exactly_ the way it looked at the time the signal 164 * occurred. In other words, we're treading on a potential mine-field: each 165 * incoming general register may be a NaT value (including sp, in which case the 166 * process ends up dying with a SIGSEGV). 167 * 168 * The first thing need to do is a cover to get the registers onto the backing 169 * store. Once that is done, we invoke the signal handler which may modify some 170 * of the machine state. After returning from the signal handler, we return 171 * control to the previous context by executing a sigreturn system call. A signal 172 * handler may call the rt_sigreturn() function to directly return to a given 173 * sigcontext. However, the user-level sigreturn() needs to do much more than 174 * calling the rt_sigreturn() system call as it needs to unwind the stack to 175 * restore preserved registers that may have been saved on the signal handler's 176 * call stack. 177 */ 178 179#define SIGTRAMP_SAVES \ 180 .unwabi 3, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \ 181 .unwabi @svr4, 's'; /* backwards compatibility with old unwinders (remove in v2.7) */ \ 182 .savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF; \ 183 .savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF; \ 184 .savesp pr, PR_OFF+SIGCONTEXT_OFF; \ 185 .savesp rp, RP_OFF+SIGCONTEXT_OFF; \ 186 .savesp ar.pfs, CFM_OFF+SIGCONTEXT_OFF; \ 187 .vframesp SP_OFF+SIGCONTEXT_OFF 188 189GLOBAL_ENTRY(__kernel_sigtramp) 190 // describe the state that is active when we get here: 191 .prologue 192 SIGTRAMP_SAVES 193 .body 194 195 .label_state 1 196 197 adds base0=SIGHANDLER_OFF,sp 198 adds base1=RBS_BASE_OFF+SIGCONTEXT_OFF,sp 199 br.call.sptk.many rp=1f 2001: 201 ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF) // get pointer to signal handler's plabel 202 ld8 r15=[base1] // get address of new RBS base (or NULL) 203 cover // push args in interrupted frame onto backing store 204 ;; 205 cmp.ne p1,p0=r15,r0 // do we need to switch rbs? (note: pr is saved by kernel) 206 mov.m r9=ar.bsp // fetch ar.bsp 207 .spillsp.p p1, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF 208(p1) br.cond.spnt setup_rbs // yup -> (clobbers p8, r14-r16, and r18-r20) 209back_from_setup_rbs: 210 alloc r8=ar.pfs,0,0,3,0 211 ld8 out0=[base0],16 // load arg0 (signum) 212 adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1 213 ;; 214 ld8 out1=[base1] // load arg1 (siginfop) 215 ld8 r10=[r17],8 // get signal handler entry point 216 ;; 217 ld8 out2=[base0] // load arg2 (sigcontextp) 218 ld8 gp=[r17] // get signal handler's global pointer 219 adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp 220 ;; 221 .spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF 222 st8 [base0]=r9 // save sc_ar_bsp 223 adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp 224 adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp 225 ;; 226 stf.spill [base0]=f6,32 227 stf.spill [base1]=f7,32 228 ;; 229 stf.spill [base0]=f8,32 230 stf.spill [base1]=f9,32 231 mov b6=r10 232 ;; 233 stf.spill [base0]=f10,32 234 stf.spill [base1]=f11,32 235 ;; 236 stf.spill [base0]=f12,32 237 stf.spill [base1]=f13,32 238 ;; 239 stf.spill [base0]=f14,32 240 stf.spill [base1]=f15,32 241 br.call.sptk.many rp=b6 // call the signal handler 242.ret0: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp 243 ;; 244 ld8 r15=[base0] // fetch sc_ar_bsp 245 mov r14=ar.bsp 246 ;; 247 cmp.ne p1,p0=r14,r15 // do we need to restore the rbs? 248(p1) br.cond.spnt restore_rbs // yup -> (clobbers r14-r18, f6 & f7) 249 ;; 250back_from_restore_rbs: 251 adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp 252 adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp 253 ;; 254 ldf.fill f6=[base0],32 255 ldf.fill f7=[base1],32 256 ;; 257 ldf.fill f8=[base0],32 258 ldf.fill f9=[base1],32 259 ;; 260 ldf.fill f10=[base0],32 261 ldf.fill f11=[base1],32 262 ;; 263 ldf.fill f12=[base0],32 264 ldf.fill f13=[base1],32 265 ;; 266 ldf.fill f14=[base0],32 267 ldf.fill f15=[base1],32 268 mov r15=__NR_rt_sigreturn 269 .restore sp // pop .prologue 270 break __BREAK_SYSCALL 271 272 .prologue 273 SIGTRAMP_SAVES 274setup_rbs: 275 mov ar.rsc=0 // put RSE into enforced lazy mode 276 ;; 277 .save ar.rnat, r19 278 mov r19=ar.rnat // save RNaT before switching backing store area 279 adds r14=(RNAT_OFF+SIGCONTEXT_OFF),sp 280 281 mov r18=ar.bspstore 282 mov ar.bspstore=r15 // switch over to new register backing store area 283 ;; 284 285 .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF 286 st8 [r14]=r19 // save sc_ar_rnat 287 .body 288 mov.m r16=ar.bsp // sc_loadrs <- (new bsp - new bspstore) << 16 289 adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp 290 ;; 291 invala 292 sub r15=r16,r15 293 extr.u r20=r18,3,6 294 ;; 295 mov ar.rsc=0xf // set RSE into eager mode, pl 3 296 cmp.eq p8,p0=63,r20 297 shl r15=r15,16 298 ;; 299 st8 [r14]=r15 // save sc_loadrs 300(p8) st8 [r18]=r19 // if bspstore points at RNaT slot, store RNaT there now 301 .restore sp // pop .prologue 302 br.cond.sptk back_from_setup_rbs 303 304 .prologue 305 SIGTRAMP_SAVES 306 .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF 307 .body 308restore_rbs: 309 // On input: 310 // r14 = bsp1 (bsp at the time of return from signal handler) 311 // r15 = bsp0 (bsp at the time the signal occurred) 312 // 313 // Here, we need to calculate bspstore0, the value that ar.bspstore needs 314 // to be set to, based on bsp0 and the size of the dirty partition on 315 // the alternate stack (sc_loadrs >> 16). This can be done with the 316 // following algorithm: 317 // 318 // bspstore0 = rse_skip_regs(bsp0, -rse_num_regs(bsp1 - (loadrs >> 19), bsp1)); 319 // 320 // This is what the code below does. 321 // 322 alloc r2=ar.pfs,0,0,0,0 // alloc null frame 323 adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp 324 adds r18=(RNAT_OFF+SIGCONTEXT_OFF),sp 325 ;; 326 ld8 r17=[r16] 327 ld8 r16=[r18] // get new rnat 328 extr.u r18=r15,3,6 // r18 <- rse_slot_num(bsp0) 329 ;; 330 mov ar.rsc=r17 // put RSE into enforced lazy mode 331 shr.u r17=r17,16 332 ;; 333 sub r14=r14,r17 // r14 (bspstore1) <- bsp1 - (sc_loadrs >> 16) 334 shr.u r17=r17,3 // r17 <- (sc_loadrs >> 19) 335 ;; 336 loadrs // restore dirty partition 337 extr.u r14=r14,3,6 // r14 <- rse_slot_num(bspstore1) 338 ;; 339 add r14=r14,r17 // r14 <- rse_slot_num(bspstore1) + (sc_loadrs >> 19) 340 ;; 341 shr.u r14=r14,6 // r14 <- (rse_slot_num(bspstore1) + (sc_loadrs >> 19))/0x40 342 ;; 343 sub r14=r14,r17 // r14 <- -rse_num_regs(bspstore1, bsp1) 344 movl r17=0x8208208208208209 345 ;; 346 add r18=r18,r14 // r18 (delta) <- rse_slot_num(bsp0) - rse_num_regs(bspstore1,bsp1) 347 setf.sig f7=r17 348 cmp.lt p7,p0=r14,r0 // p7 <- (r14 < 0)? 349 ;; 350(p7) adds r18=-62,r18 // delta -= 62 351 ;; 352 setf.sig f6=r18 353 ;; 354 xmpy.h f6=f6,f7 355 ;; 356 getf.sig r17=f6 357 ;; 358 add r17=r17,r18 359 shr r18=r18,63 360 ;; 361 shr r17=r17,5 362 ;; 363 sub r17=r17,r18 // r17 = delta/63 364 ;; 365 add r17=r14,r17 // r17 <- delta/63 - rse_num_regs(bspstore1, bsp1) 366 ;; 367 shladd r15=r17,3,r15 // r15 <- bsp0 + 8*(delta/63 - rse_num_regs(bspstore1, bsp1)) 368 ;; 369 mov ar.bspstore=r15 // switch back to old register backing store area 370 ;; 371 mov ar.rnat=r16 // restore RNaT 372 mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) 373 // invala not necessary as that will happen when returning to user-mode 374 br.cond.sptk back_from_restore_rbs 375END(__kernel_sigtramp) 376