v2.4.3 -> v2.4.3.1
[opensuse:kernel.git] / arch / ia64 / kernel / gate.S
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-2001 Hewlett-Packard Co
6  * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
7  */
8
9 #include <asm/asmmacro.h>
10 #include <asm/offsets.h>
11 #include <asm/sigcontext.h>
12 #include <asm/system.h>
13 #include <asm/unistd.h>
14 #include <asm/page.h>
15
16         .section .text.gate,"ax"
17
18         .align PAGE_SIZE
19
20 #       define SIGINFO_OFF      16
21 #       define SIGCONTEXT_OFF   (SIGINFO_OFF + ((IA64_SIGINFO_SIZE + 15) & ~15))
22 #       define FLAGS_OFF        IA64_SIGCONTEXT_FLAGS_OFFSET
23 #       define CFM_OFF          IA64_SIGCONTEXT_CFM_OFFSET
24 #       define FR6_OFF          IA64_SIGCONTEXT_FR6_OFFSET
25 #       define BSP_OFF          IA64_SIGCONTEXT_AR_BSP_OFFSET
26 #       define RNAT_OFF         IA64_SIGCONTEXT_AR_RNAT_OFFSET
27 #       define base0            r2
28 #       define base1            r3
29         /*
30          * When we get here, the memory stack looks like this:
31          *
32          *   +===============================+
33          *   |                               |
34          *   //     struct sigcontext        //
35          *   |                               |
36          *   +===============================+ <-- sp+SIGCONTEXT_OFF
37          *   |                               |
38          *   //     rest of siginfo          //
39          *   |                               |
40          *   +               +---------------+
41          *   |               | siginfo.code  |
42          *   +---------------+---------------+
43          *   | siginfo.errno | siginfo.signo |
44          *   +-------------------------------+ <-- sp+SIGINFO_OFF
45          *   |      16 byte of scratch       |
46          *   |            space              |
47          *   +-------------------------------+ <-- sp
48          *
49          * The register stack looks _exactly_ the way it looked at the time the signal
50          * occurred.  In other words, we're treading on a potential mine-field: each
51          * incoming general register may be a NaT value (including sp, in which case the
52          * process ends up dying with a SIGSEGV).
53          *
54          * The first need to do is a cover to get the registers onto the backing store.
55          * Once that is done, we invoke the signal handler which may modify some of the
56          * machine state.  After returning from the signal handler, we return control to
57          * the previous context by executing a sigreturn system call.  A signal handler
58          * may call the rt_sigreturn() function to directly return to a given sigcontext.
59          * However, the user-level sigreturn() needs to do much more than calling the
60          * rt_sigreturn() system call as it needs to unwind the stack to restore preserved
61          * registers that may have been saved on the signal handler's call stack.
62          *
63          * On entry:
64          *      r2      = signal number
65          *      r3      = plabel of signal handler
66          *      r15     = new register backing store
67          *      [sp+16] = sigframe
68          */
69
70 GLOBAL_ENTRY(ia64_sigtramp)
71         ld8 r10=[r3],8                          // get signal handler entry point
72         br.call.sptk.many rp=invoke_sighandler
73 END(ia64_sigtramp)
74
75 ENTRY(invoke_sighandler)
76         ld8 gp=[r3]                     // get signal handler's global pointer
77         mov b6=r10
78         cover                           // push args in interrupted frame onto backing store
79         ;;
80         alloc r8=ar.pfs,0,0,3,0         // get CFM0, EC0, and CPL0 into r8
81         ;;
82         mov r17=ar.bsp                  // fetch ar.bsp
83         cmp.ne p8,p0=r15,r0             // do we need to switch the rbs?
84         mov out0=r2                     // signal number
85 (p8)    br.cond.spnt.few setup_rbs      // yup -> (clobbers r14 and r16)
86 back_from_setup_rbs:
87         adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
88         ;;
89         st8 [base0]=r17,(CFM_OFF-BSP_OFF)       // save sc_ar_bsp
90         dep r8=0,r8,38,26               // clear EC0, CPL0 and reserved bits
91         adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
92         ;;
93
94         st8 [base0]=r8                          // save CFM0
95         adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
96         ;;
97         stf.spill [base0]=f6,32
98         stf.spill [base1]=f7,32
99         ;;
100         stf.spill [base0]=f8,32
101         stf.spill [base1]=f9,32
102         ;;
103         stf.spill [base0]=f10,32
104         stf.spill [base1]=f11,32
105         adds out1=SIGINFO_OFF,sp        // siginfo pointer
106         ;;
107         stf.spill [base0]=f12,32
108         stf.spill [base1]=f13,32
109         adds out2=SIGCONTEXT_OFF,sp     // sigcontext pointer
110         ;;
111         stf.spill [base0]=f14,32
112         stf.spill [base1]=f15,32
113         br.call.sptk.few rp=b6                  // call the signal handler
114 .ret0:  adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
115         ;;
116         ld8 r15=[base0],(CFM_OFF-BSP_OFF)       // fetch sc_ar_bsp and advance to CFM_OFF
117         mov r14=ar.bsp
118         ;;
119         ld8 r8=[base0]                          // restore (perhaps modified) CFM0, EC0, and CPL0
120         cmp.ne p8,p0=r14,r15                    // do we need to restore the rbs?
121 (p8)    br.cond.spnt.few restore_rbs            // yup -> (clobbers r14 and r16)
122         ;;
123 back_from_restore_rbs:
124         adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
125         adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
126         ;;
127         ldf.fill f6=[base0],32
128         ldf.fill f7=[base1],32
129         ;;
130         ldf.fill f8=[base0],32
131         ldf.fill f9=[base1],32
132         ;;
133         ldf.fill f10=[base0],32
134         ldf.fill f11=[base1],32
135         ;;
136         ldf.fill f12=[base0],32
137         ldf.fill f13=[base1],32
138         ;;
139         ldf.fill f14=[base0],32
140         ldf.fill f15=[base1],32
141         mov r15=__NR_rt_sigreturn
142         break __BREAK_SYSCALL
143 END(invoke_sighandler)
144
145 ENTRY(setup_rbs)
146         flushrs                                 // must be first in insn
147         mov ar.rsc=0                            // put RSE into enforced lazy mode
148         adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
149         ;;
150         mov r14=ar.rnat                         // get rnat as updated by flushrs
151         mov ar.bspstore=r15                     // set new register backing store area
152         ;;
153         st8 [r16]=r14                           // save sc_ar_rnat
154         mov ar.rsc=0xf                          // set RSE into eager mode, pl 3
155         invala                                  // invalidate ALAT
156         br.cond.sptk.many back_from_setup_rbs
157 END(setup_rbs)
158
159 ENTRY(restore_rbs)
160         flushrs
161         mov ar.rsc=0                            // put RSE into enforced lazy mode
162         adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
163         ;;
164         ld8 r14=[r16]                           // get new rnat
165         mov ar.bspstore=r15                     // set old register backing store area
166         ;;
167         mov ar.rnat=r14                         // establish new rnat
168         mov ar.rsc=0xf                          // (will be restored later on from sc_ar_rsc)
169         // invala not necessary as that will happen when returning to user-mode
170         br.cond.sptk.many back_from_restore_rbs
171 END(restore_rbs)