aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/sys-x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/sys-x86_64')
-rw-r--r--arch/um/sys-x86_64/signal.c56
1 files changed, 41 insertions, 15 deletions
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index fe1d065332b1..e75c4e1838b0 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -55,7 +55,8 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
55} 55}
56 56
57int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, 57int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
58 struct pt_regs *regs, unsigned long mask) 58 struct pt_regs *regs, unsigned long mask,
59 unsigned long sp)
59{ 60{
60 struct faultinfo * fi = &current->thread.arch.faultinfo; 61 struct faultinfo * fi = &current->thread.arch.faultinfo;
61 int err = 0; 62 int err = 0;
@@ -70,7 +71,11 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
70 err |= PUTREG(regs, RDI, to, rdi); 71 err |= PUTREG(regs, RDI, to, rdi);
71 err |= PUTREG(regs, RSI, to, rsi); 72 err |= PUTREG(regs, RSI, to, rsi);
72 err |= PUTREG(regs, RBP, to, rbp); 73 err |= PUTREG(regs, RBP, to, rbp);
73 err |= PUTREG(regs, RSP, to, rsp); 74 /* Must use orignal RSP, which is passed in, rather than what's in
75 * the pt_regs, because that's already been updated to point at the
76 * signal frame.
77 */
78 err |= __put_user(sp, &to->rsp);
74 err |= PUTREG(regs, RBX, to, rbx); 79 err |= PUTREG(regs, RBX, to, rbx);
75 err |= PUTREG(regs, RDX, to, rdx); 80 err |= PUTREG(regs, RDX, to, rdx);
76 err |= PUTREG(regs, RCX, to, rcx); 81 err |= PUTREG(regs, RCX, to, rcx);
@@ -102,7 +107,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
102 107
103#ifdef CONFIG_MODE_TT 108#ifdef CONFIG_MODE_TT
104int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, 109int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
105 int fpsize) 110 int fpsize)
106{ 111{
107 struct _fpstate *to_fp, *from_fp; 112 struct _fpstate *to_fp, *from_fp;
108 unsigned long sigs; 113 unsigned long sigs;
@@ -120,7 +125,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
120} 125}
121 126
122int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, 127int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
123 struct sigcontext *from, int fpsize) 128 struct sigcontext *from, int fpsize, unsigned long sp)
124{ 129{
125 struct _fpstate *to_fp, *from_fp; 130 struct _fpstate *to_fp, *from_fp;
126 int err; 131 int err;
@@ -128,11 +133,17 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
128 to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); 133 to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
129 from_fp = from->fpstate; 134 from_fp = from->fpstate;
130 err = copy_to_user(to, from, sizeof(*to)); 135 err = copy_to_user(to, from, sizeof(*to));
136 /* The SP in the sigcontext is the updated one for the signal
137 * delivery. The sp passed in is the original, and this needs
138 * to be restored, so we stick it in separately.
139 */
140 err |= copy_to_user(&SC_SP(to), sp, sizeof(sp));
141
131 if(from_fp != NULL){ 142 if(from_fp != NULL){
132 err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); 143 err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
133 err |= copy_to_user(to_fp, from_fp, fpsize); 144 err |= copy_to_user(to_fp, from_fp, fpsize);
134 } 145 }
135 return(err); 146 return err;
136} 147}
137 148
138#endif 149#endif
@@ -148,11 +159,12 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from)
148} 159}
149 160
150static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, 161static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
151 struct pt_regs *from, unsigned long mask) 162 struct pt_regs *from, unsigned long mask,
163 unsigned long sp)
152{ 164{
153 return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), 165 return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
154 sizeof(*fp)), 166 sizeof(*fp), sp),
155 copy_sc_to_user_skas(to, fp, from, mask))); 167 copy_sc_to_user_skas(to, fp, from, mask, sp)));
156} 168}
157 169
158struct rt_sigframe 170struct rt_sigframe
@@ -170,6 +182,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
170{ 182{
171 struct rt_sigframe __user *frame; 183 struct rt_sigframe __user *frame;
172 struct _fpstate __user *fp = NULL; 184 struct _fpstate __user *fp = NULL;
185 unsigned long save_sp = PT_REGS_RSP(regs);
173 int err = 0; 186 int err = 0;
174 struct task_struct *me = current; 187 struct task_struct *me = current;
175 188
@@ -193,14 +206,25 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
193 goto out; 206 goto out;
194 } 207 }
195 208
209 /* Update SP now because the page fault handler refuses to extend
210 * the stack if the faulting address is too far below the current
211 * SP, which frame now certainly is. If there's an error, the original
212 * value is restored on the way out.
213 * When writing the sigcontext to the stack, we have to write the
214 * original value, so that's passed to copy_sc_to_user, which does
215 * the right thing with it.
216 */
217 PT_REGS_RSP(regs) = (unsigned long) frame;
218
196 /* Create the ucontext. */ 219 /* Create the ucontext. */
197 err |= __put_user(0, &frame->uc.uc_flags); 220 err |= __put_user(0, &frame->uc.uc_flags);
198 err |= __put_user(0, &frame->uc.uc_link); 221 err |= __put_user(0, &frame->uc.uc_link);
199 err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); 222 err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
200 err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), 223 err |= __put_user(sas_ss_flags(save_sp),
201 &frame->uc.uc_stack.ss_flags); 224 &frame->uc.uc_stack.ss_flags);
202 err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); 225 err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
203 err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); 226 err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0],
227 save_sp);
204 err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); 228 err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
205 if (sizeof(*set) == 16) { 229 if (sizeof(*set) == 16) {
206 __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); 230 __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
@@ -217,10 +241,10 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
217 err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); 241 err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
218 else 242 else
219 /* could use a vstub here */ 243 /* could use a vstub here */
220 goto out; 244 goto restore_sp;
221 245
222 if (err) 246 if (err)
223 goto out; 247 goto restore_sp;
224 248
225 /* Set up registers for signal handler */ 249 /* Set up registers for signal handler */
226 { 250 {
@@ -238,10 +262,12 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
238 PT_REGS_RSI(regs) = (unsigned long) &frame->info; 262 PT_REGS_RSI(regs) = (unsigned long) &frame->info;
239 PT_REGS_RDX(regs) = (unsigned long) &frame->uc; 263 PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
240 PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; 264 PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
241
242 PT_REGS_RSP(regs) = (unsigned long) frame;
243 out: 265 out:
244 return(err); 266 return err;
267
268restore_sp:
269 PT_REGS_RSP(regs) = save_sp;
270 return err;
245} 271}
246 272
247long sys_rt_sigreturn(struct pt_regs *regs) 273long sys_rt_sigreturn(struct pt_regs *regs)