aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/sys-x86_64/signal.c
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-10-16 04:27:15 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:07 -0400
commita5f6096c805e6d2fa03ee932f8c70af34cee41a0 (patch)
treec74d984c0e2fc2958425df65605dd3451adc6520 /arch/um/sys-x86_64/signal.c
parent189872f968def833727b6bfef83ebd7440c538e6 (diff)
uml: floating point signal delivery fixes
Handle floating point state in across signals correctly. UML/i386 needs to know whether the host does PTRACE_[GS]ETFPXREGS, so an arch_init_registers hook is added, which on x86_64 does nothing. UML doesn't save and restore floating point registers on kernel entry and exit, so they need to be copied between the host process and the sigcontext. save_fpx_registers and restore_fpx_registers are added for this purpose. save_fp_registers and restore_fp_registers already exist. There was a bunch of floating point state conversion code in arch/um/sys-i386/ptrace.c which isn't needed there, but is needed in signal.c, so it is moved over. The i386 code now distinguishes between fp and fpx state and handles them correctly. The x86_64 code just needs to copy state as-is between the host process and the stack. There are also some fixes there to pass the correct address of the floating point state around. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um/sys-x86_64/signal.c')
-rw-r--r--arch/um/sys-x86_64/signal.c53
1 files changed, 39 insertions, 14 deletions
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index c98dd7f31396..a8e5fd7b2adb 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -42,8 +42,10 @@ void copy_sc(struct uml_pt_regs *regs, void *from)
42} 42}
43 43
44static int copy_sc_from_user(struct pt_regs *regs, 44static int copy_sc_from_user(struct pt_regs *regs,
45 struct sigcontext __user *from) 45 struct sigcontext __user *from,
46 struct _fpstate __user *fpp)
46{ 47{
48 struct user_i387_struct fp;
47 int err = 0; 49 int err = 0;
48 50
49#define GETREG(regs, regno, sc, regname) \ 51#define GETREG(regs, regno, sc, regname) \
@@ -69,10 +71,25 @@ static int copy_sc_from_user(struct pt_regs *regs,
69 err |= GETREG(regs, RIP, from, rip); 71 err |= GETREG(regs, RIP, from, rip);
70 err |= GETREG(regs, EFLAGS, from, eflags); 72 err |= GETREG(regs, EFLAGS, from, eflags);
71 err |= GETREG(regs, CS, from, cs); 73 err |= GETREG(regs, CS, from, cs);
74 if (err)
75 return 1;
72 76
73#undef GETREG 77#undef GETREG
74 78
75 return err; 79 err = copy_from_user(&fp, fpp, sizeof(struct user_i387_struct));
80 if (err)
81 return 1;
82
83 err = restore_fp_registers(userspace_pid[current_thread->cpu],
84 (unsigned long *) &fp);
85 if (err < 0) {
86 printk(KERN_ERR "copy_sc_from_user - "
87 "restore_fp_registers failed, errno = %d\n",
88 -err);
89 return 1;
90 }
91
92 return 0;
76} 93}
77 94
78static int copy_sc_to_user(struct sigcontext __user *to, 95static int copy_sc_to_user(struct sigcontext __user *to,
@@ -80,6 +97,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
80 unsigned long mask, unsigned long sp) 97 unsigned long mask, unsigned long sp)
81{ 98{
82 struct faultinfo * fi = &current->thread.arch.faultinfo; 99 struct faultinfo * fi = &current->thread.arch.faultinfo;
100 struct user_i387_struct fp;
83 int err = 0; 101 int err = 0;
84 102
85 err |= __put_user(0, &to->gs); 103 err |= __put_user(0, &to->gs);
@@ -120,6 +138,19 @@ static int copy_sc_to_user(struct sigcontext __user *to,
120#undef PUTREG 138#undef PUTREG
121 139
122 err |= __put_user(mask, &to->oldmask); 140 err |= __put_user(mask, &to->oldmask);
141 if (err)
142 return 1;
143
144 err = save_fp_registers(userspace_pid[current_thread->cpu],
145 (unsigned long *) &fp);
146 if (err < 0) {
147 printk(KERN_ERR "copy_sc_from_user - restore_fp_registers "
148 "failed, errno = %d\n", -err);
149 return 1;
150 }
151
152 if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct)))
153 return 1;
123 154
124 return(err); 155 return(err);
125} 156}
@@ -129,6 +160,7 @@ struct rt_sigframe
129 char __user *pretcode; 160 char __user *pretcode;
130 struct ucontext uc; 161 struct ucontext uc;
131 struct siginfo info; 162 struct siginfo info;
163 struct _fpstate fpstate;
132}; 164};
133 165
134#define round_down(m, n) (((m) / (n)) * (n)) 166#define round_down(m, n) (((m) / (n)) * (n))
@@ -138,7 +170,6 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
138 siginfo_t *info, sigset_t *set) 170 siginfo_t *info, sigset_t *set)
139{ 171{
140 struct rt_sigframe __user *frame; 172 struct rt_sigframe __user *frame;
141 struct _fpstate __user *fp = NULL;
142 unsigned long save_sp = PT_REGS_RSP(regs); 173 unsigned long save_sp = PT_REGS_RSP(regs);
143 int err = 0; 174 int err = 0;
144 struct task_struct *me = current; 175 struct task_struct *me = current;
@@ -148,13 +179,6 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
148 /* Subtract 128 for a red zone and 8 for proper alignment */ 179 /* Subtract 128 for a red zone and 8 for proper alignment */
149 frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8); 180 frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8);
150 181
151 if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
152 goto out;
153
154#if 0 /* XXX */
155 if (save_i387(fp) < 0)
156 err |= -1;
157#endif
158 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) 182 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
159 goto out; 183 goto out;
160 184
@@ -181,9 +205,9 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
181 err |= __put_user(sas_ss_flags(save_sp), 205 err |= __put_user(sas_ss_flags(save_sp),
182 &frame->uc.uc_stack.ss_flags); 206 &frame->uc.uc_stack.ss_flags);
183 err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); 207 err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
184 err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0], 208 err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs,
185 save_sp); 209 set->sig[0], save_sp);
186 err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); 210 err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
187 if (sizeof(*set) == 16) { 211 if (sizeof(*set) == 16) {
188 __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); 212 __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
189 __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); 213 __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
@@ -246,7 +270,8 @@ long sys_rt_sigreturn(struct pt_regs *regs)
246 recalc_sigpending(); 270 recalc_sigpending();
247 spin_unlock_irq(&current->sighand->siglock); 271 spin_unlock_irq(&current->sighand->siglock);
248 272
249 if (copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext)) 273 if (copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext,
274 &frame->fpstate))
250 goto segfault; 275 goto segfault;
251 276
252 /* Avoid ERESTART handling */ 277 /* Avoid ERESTART handling */