Back to home page

LXR

 
 

    


0001 /*
0002  * This file contains the code that gets mapped at the upper end of each task's text
0003  * region.  For now, it contains the signal trampoline code only.
0004  *
0005  * Copyright (C) 1999-2003 Hewlett-Packard Co
0006  *  David Mosberger-Tang <davidm@hpl.hp.com>
0007  */
0008 
0009 
0010 #include <asm/asmmacro.h>
0011 #include <asm/errno.h>
0012 #include <asm/asm-offsets.h>
0013 #include <asm/sigcontext.h>
0014 #include <asm/unistd.h>
0015 #include <asm/kregs.h>
0016 #include <asm/page.h>
0017 #include <asm/native/inst.h>
0018 
0019 /*
0020  * We can't easily refer to symbols inside the kernel.  To avoid full runtime relocation,
0021  * complications with the linker (which likes to create PLT stubs for branches
0022  * to targets outside the shared object) and to avoid multi-phase kernel builds, we
0023  * simply create minimalistic "patch lists" in special ELF sections.
0024  */
0025     .section ".data..patch.fsyscall_table", "a"
0026     .previous
0027 #define LOAD_FSYSCALL_TABLE(reg)            \
0028 [1:]    movl reg=0;                 \
0029     .xdata4 ".data..patch.fsyscall_table", 1b-.
0030 
0031     .section ".data..patch.brl_fsys_bubble_down", "a"
0032     .previous
0033 #define BRL_COND_FSYS_BUBBLE_DOWN(pr)           \
0034 [1:](pr)brl.cond.sptk 0;                \
0035     ;;                      \
0036     .xdata4 ".data..patch.brl_fsys_bubble_down", 1b-.
0037 
0038 GLOBAL_ENTRY(__kernel_syscall_via_break)
0039     .prologue
0040     .altrp b6
0041     .body
0042     /*
0043      * Note: for (fast) syscall restart to work, the break instruction must be
0044      *   the first one in the bundle addressed by syscall_via_break.
0045      */
0046 { .mib
0047     break 0x100000
0048     nop.i 0
0049     br.ret.sptk.many b6
0050 }
0051 END(__kernel_syscall_via_break)
0052 
0053 #   define ARG0_OFF     (16 + IA64_SIGFRAME_ARG0_OFFSET)
0054 #   define ARG1_OFF     (16 + IA64_SIGFRAME_ARG1_OFFSET)
0055 #   define ARG2_OFF     (16 + IA64_SIGFRAME_ARG2_OFFSET)
0056 #   define SIGHANDLER_OFF   (16 + IA64_SIGFRAME_HANDLER_OFFSET)
0057 #   define SIGCONTEXT_OFF   (16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET)
0058 
0059 #   define FLAGS_OFF    IA64_SIGCONTEXT_FLAGS_OFFSET
0060 #   define CFM_OFF      IA64_SIGCONTEXT_CFM_OFFSET
0061 #   define FR6_OFF      IA64_SIGCONTEXT_FR6_OFFSET
0062 #   define BSP_OFF      IA64_SIGCONTEXT_AR_BSP_OFFSET
0063 #   define RNAT_OFF     IA64_SIGCONTEXT_AR_RNAT_OFFSET
0064 #   define UNAT_OFF     IA64_SIGCONTEXT_AR_UNAT_OFFSET
0065 #   define FPSR_OFF     IA64_SIGCONTEXT_AR_FPSR_OFFSET
0066 #   define PR_OFF       IA64_SIGCONTEXT_PR_OFFSET
0067 #   define RP_OFF       IA64_SIGCONTEXT_IP_OFFSET
0068 #   define SP_OFF       IA64_SIGCONTEXT_R12_OFFSET
0069 #   define RBS_BASE_OFF IA64_SIGCONTEXT_RBS_BASE_OFFSET
0070 #   define LOADRS_OFF   IA64_SIGCONTEXT_LOADRS_OFFSET
0071 #   define base0        r2
0072 #   define base1        r3
0073     /*
0074      * When we get here, the memory stack looks like this:
0075      *
0076      *   +===============================+
0077          *   |                   |
0078          *   //     struct sigframe          //
0079          *   |                   |
0080      *   +-------------------------------+ <-- sp+16
0081      *   |      16 byte of scratch       |
0082      *   |            space              |
0083      *   +-------------------------------+ <-- sp
0084      *
0085      * The register stack looks _exactly_ the way it looked at the time the signal
0086      * occurred.  In other words, we're treading on a potential mine-field: each
0087      * incoming general register may be a NaT value (including sp, in which case the
0088      * process ends up dying with a SIGSEGV).
0089      *
0090      * The first thing need to do is a cover to get the registers onto the backing
0091      * store.  Once that is done, we invoke the signal handler which may modify some
0092      * of the machine state.  After returning from the signal handler, we return
0093      * control to the previous context by executing a sigreturn system call.  A signal
0094      * handler may call the rt_sigreturn() function to directly return to a given
0095      * sigcontext.  However, the user-level sigreturn() needs to do much more than
0096      * calling the rt_sigreturn() system call as it needs to unwind the stack to
0097      * restore preserved registers that may have been saved on the signal handler's
0098      * call stack.
0099      */
0100 
0101 #define SIGTRAMP_SAVES                                      \
0102     .unwabi 3, 's';     /* mark this as a sigtramp handler (saves scratch regs) */  \
0103     .unwabi @svr4, 's'; /* backwards compatibility with old unwinders (remove in v2.7) */   \
0104     .savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF;                       \
0105     .savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF;                       \
0106     .savesp pr, PR_OFF+SIGCONTEXT_OFF;                              \
0107     .savesp rp, RP_OFF+SIGCONTEXT_OFF;                          \
0108     .savesp ar.pfs, CFM_OFF+SIGCONTEXT_OFF;                         \
0109     .vframesp SP_OFF+SIGCONTEXT_OFF
0110 
0111 GLOBAL_ENTRY(__kernel_sigtramp)
0112     // describe the state that is active when we get here:
0113     .prologue
0114     SIGTRAMP_SAVES
0115     .body
0116 
0117     .label_state 1
0118 
0119     adds base0=SIGHANDLER_OFF,sp
0120     adds base1=RBS_BASE_OFF+SIGCONTEXT_OFF,sp
0121     br.call.sptk.many rp=1f
0122 1:
0123     ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF)   // get pointer to signal handler's plabel
0124     ld8 r15=[base1]                 // get address of new RBS base (or NULL)
0125     cover               // push args in interrupted frame onto backing store
0126     ;;
0127     cmp.ne p1,p0=r15,r0     // do we need to switch rbs? (note: pr is saved by kernel)
0128     mov.m r9=ar.bsp         // fetch ar.bsp
0129     .spillsp.p p1, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
0130 (p1)    br.cond.spnt setup_rbs      // yup -> (clobbers p8, r14-r16, and r18-r20)
0131 back_from_setup_rbs:
0132     alloc r8=ar.pfs,0,0,3,0
0133     ld8 out0=[base0],16     // load arg0 (signum)
0134     adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1
0135     ;;
0136     ld8 out1=[base1]        // load arg1 (siginfop)
0137     ld8 r10=[r17],8         // get signal handler entry point
0138     ;;
0139     ld8 out2=[base0]        // load arg2 (sigcontextp)
0140     ld8 gp=[r17]            // get signal handler's global pointer
0141     adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
0142     ;;
0143     .spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF
0144     st8 [base0]=r9          // save sc_ar_bsp
0145     adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
0146     adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
0147     ;;
0148     stf.spill [base0]=f6,32
0149     stf.spill [base1]=f7,32
0150     ;;
0151     stf.spill [base0]=f8,32
0152     stf.spill [base1]=f9,32
0153     mov b6=r10
0154     ;;
0155     stf.spill [base0]=f10,32
0156     stf.spill [base1]=f11,32
0157     ;;
0158     stf.spill [base0]=f12,32
0159     stf.spill [base1]=f13,32
0160     ;;
0161     stf.spill [base0]=f14,32
0162     stf.spill [base1]=f15,32
0163     br.call.sptk.many rp=b6         // call the signal handler
0164 .ret0:  adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
0165     ;;
0166     ld8 r15=[base0]             // fetch sc_ar_bsp
0167     mov r14=ar.bsp
0168     ;;
0169     cmp.ne p1,p0=r14,r15            // do we need to restore the rbs?
0170 (p1)    br.cond.spnt restore_rbs        // yup -> (clobbers r14-r18, f6 & f7)
0171     ;;
0172 back_from_restore_rbs:
0173     adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
0174     adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
0175     ;;
0176     ldf.fill f6=[base0],32
0177     ldf.fill f7=[base1],32
0178     ;;
0179     ldf.fill f8=[base0],32
0180     ldf.fill f9=[base1],32
0181     ;;
0182     ldf.fill f10=[base0],32
0183     ldf.fill f11=[base1],32
0184     ;;
0185     ldf.fill f12=[base0],32
0186     ldf.fill f13=[base1],32
0187     ;;
0188     ldf.fill f14=[base0],32
0189     ldf.fill f15=[base1],32
0190     mov r15=__NR_rt_sigreturn
0191     .restore sp             // pop .prologue
0192     break __BREAK_SYSCALL
0193 
0194     .prologue
0195     SIGTRAMP_SAVES
0196 setup_rbs:
0197     mov ar.rsc=0                // put RSE into enforced lazy mode
0198     ;;
0199     .save ar.rnat, r19
0200     mov r19=ar.rnat             // save RNaT before switching backing store area
0201     adds r14=(RNAT_OFF+SIGCONTEXT_OFF),sp
0202 
0203     mov r18=ar.bspstore
0204     mov ar.bspstore=r15         // switch over to new register backing store area
0205     ;;
0206 
0207     .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
0208     st8 [r14]=r19               // save sc_ar_rnat
0209     .body
0210     mov.m r16=ar.bsp            // sc_loadrs <- (new bsp - new bspstore) << 16
0211     adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp
0212     ;;
0213     invala
0214     sub r15=r16,r15
0215     extr.u r20=r18,3,6
0216     ;;
0217     mov ar.rsc=0xf              // set RSE into eager mode, pl 3
0218     cmp.eq p8,p0=63,r20
0219     shl r15=r15,16
0220     ;;
0221     st8 [r14]=r15               // save sc_loadrs
0222 (p8)    st8 [r18]=r19       // if bspstore points at RNaT slot, store RNaT there now
0223     .restore sp             // pop .prologue
0224     br.cond.sptk back_from_setup_rbs
0225 
0226     .prologue
0227     SIGTRAMP_SAVES
0228     .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
0229     .body
0230 restore_rbs:
0231     // On input:
0232     //  r14 = bsp1 (bsp at the time of return from signal handler)
0233     //  r15 = bsp0 (bsp at the time the signal occurred)
0234     //
0235     // Here, we need to calculate bspstore0, the value that ar.bspstore needs
0236     // to be set to, based on bsp0 and the size of the dirty partition on
0237     // the alternate stack (sc_loadrs >> 16).  This can be done with the
0238     // following algorithm:
0239     //
0240     //  bspstore0 = rse_skip_regs(bsp0, -rse_num_regs(bsp1 - (loadrs >> 19), bsp1));
0241     //
0242     // This is what the code below does.
0243     //
0244     alloc r2=ar.pfs,0,0,0,0         // alloc null frame
0245     adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp
0246     adds r18=(RNAT_OFF+SIGCONTEXT_OFF),sp
0247     ;;
0248     ld8 r17=[r16]
0249     ld8 r16=[r18]           // get new rnat
0250     extr.u r18=r15,3,6  // r18 <- rse_slot_num(bsp0)
0251     ;;
0252     mov ar.rsc=r17          // put RSE into enforced lazy mode
0253     shr.u r17=r17,16
0254     ;;
0255     sub r14=r14,r17     // r14 (bspstore1) <- bsp1 - (sc_loadrs >> 16)
0256     shr.u r17=r17,3     // r17 <- (sc_loadrs >> 19)
0257     ;;
0258     loadrs          // restore dirty partition
0259     extr.u r14=r14,3,6  // r14 <- rse_slot_num(bspstore1)
0260     ;;
0261     add r14=r14,r17     // r14 <- rse_slot_num(bspstore1) + (sc_loadrs >> 19)
0262     ;;
0263     shr.u r14=r14,6     // r14 <- (rse_slot_num(bspstore1) + (sc_loadrs >> 19))/0x40
0264     ;;
0265     sub r14=r14,r17     // r14 <- -rse_num_regs(bspstore1, bsp1)
0266     movl r17=0x8208208208208209
0267     ;;
0268     add r18=r18,r14     // r18 (delta) <- rse_slot_num(bsp0) - rse_num_regs(bspstore1,bsp1)
0269     setf.sig f7=r17
0270     cmp.lt p7,p0=r14,r0 // p7 <- (r14 < 0)?
0271     ;;
0272 (p7)    adds r18=-62,r18    // delta -= 62
0273     ;;
0274     setf.sig f6=r18
0275     ;;
0276     xmpy.h f6=f6,f7
0277     ;;
0278     getf.sig r17=f6
0279     ;;
0280     add r17=r17,r18
0281     shr r18=r18,63
0282     ;;
0283     shr r17=r17,5
0284     ;;
0285     sub r17=r17,r18     // r17 = delta/63
0286     ;;
0287     add r17=r14,r17     // r17 <- delta/63 - rse_num_regs(bspstore1, bsp1)
0288     ;;
0289     shladd r15=r17,3,r15    // r15 <- bsp0 + 8*(delta/63 - rse_num_regs(bspstore1, bsp1))
0290     ;;
0291     mov ar.bspstore=r15         // switch back to old register backing store area
0292     ;;
0293     mov ar.rnat=r16             // restore RNaT
0294     mov ar.rsc=0xf              // (will be restored later on from sc_ar_rsc)
0295     // invala not necessary as that will happen when returning to user-mode
0296     br.cond.sptk back_from_restore_rbs
0297 END(__kernel_sigtramp)
0298 
0299 /*
0300  * On entry:
0301  *  r11 = saved ar.pfs
0302  *  r15 = system call #
0303  *  b0  = saved return address
0304  *  b6  = return address
0305  * On exit:
0306  *  r11 = saved ar.pfs
0307  *  r15 = system call #
0308  *  b0  = saved return address
0309  *  all other "scratch" registers:  undefined
0310  *  all "preserved" registers:  same as on entry
0311  */
0312 
0313 GLOBAL_ENTRY(__kernel_syscall_via_epc)
0314     .prologue
0315     .altrp b6
0316     .body
0317 {
0318     /*
0319      * Note: the kernel cannot assume that the first two instructions in this
0320      * bundle get executed.  The remaining code must be safe even if
0321      * they do not get executed.
0322      */
0323     adds r17=-1024,r15          // A
0324     mov r10=0               // A    default to successful syscall execution
0325     epc                 // B    causes split-issue
0326 }
0327     ;;
0328     RSM_PSR_BE_I(r20, r22)          // M2 (5 cyc to srlz.d)
0329     LOAD_FSYSCALL_TABLE(r14)        // X
0330     ;;
0331     mov r16=IA64_KR(CURRENT)        // M2 (12 cyc)
0332     shladd r18=r17,3,r14            // A
0333     mov r19=NR_syscalls-1           // A
0334     ;;
0335     lfetch [r18]                // M0|1
0336     MOV_FROM_PSR(p0, r29, r8)       // M2 (12 cyc)
0337     // If r17 is a NaT, p6 will be zero
0338     cmp.geu p6,p7=r19,r17           // A    (sysnr > 0 && sysnr < 1024+NR_syscalls)?
0339     ;;
0340     mov r21=ar.fpsr             // M2 (12 cyc)
0341     tnat.nz p10,p9=r15          // I0
0342     mov.i r26=ar.pfs            // I0 (would stall anyhow due to srlz.d...)
0343     ;;
0344     srlz.d                  // M0 (forces split-issue) ensure PSR.BE==0
0345 (p6)    ld8 r18=[r18]               // M0|1
0346     nop.i 0
0347     ;;
0348     nop.m 0
0349 (p6)    tbit.z.unc p8,p0=r18,0          // I0 (dual-issues with "mov b7=r18"!)
0350     nop.i 0
0351     ;;
0352     SSM_PSR_I(p8, p14, r25)
0353 (p6)    mov b7=r18              // I0
0354 (p8)    br.dptk.many b7             // B
0355 
0356     mov r27=ar.rsc              // M2 (12 cyc)
0357 /*
0358  * brl.cond doesn't work as intended because the linker would convert this branch
0359  * into a branch to a PLT.  Perhaps there will be a way to avoid this with some
0360  * future version of the linker.  In the meantime, we just use an indirect branch
0361  * instead.
0362  */
0363 #ifdef CONFIG_ITANIUM
0364 (p6)    add r14=-8,r14              // r14 <- addr of fsys_bubble_down entry
0365     ;;
0366 (p6)    ld8 r14=[r14]               // r14 <- fsys_bubble_down
0367     ;;
0368 (p6)    mov b7=r14
0369 (p6)    br.sptk.many b7
0370 #else
0371     BRL_COND_FSYS_BUBBLE_DOWN(p6)
0372 #endif
0373     SSM_PSR_I(p0, p14, r10)
0374     mov r10=-1
0375 (p10)   mov r8=EINVAL
0376 (p9)    mov r8=ENOSYS
0377     FSYS_RETURN
0378 
0379 END(__kernel_syscall_via_epc)