diff options
Diffstat (limited to 'arch/arm/kernel')
| -rw-r--r-- | arch/arm/kernel/signal.c | 93 |
1 files changed, 89 insertions, 4 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index e7714f367eb8..907d5a620bca 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <asm/cacheflush.h> | 18 | #include <asm/cacheflush.h> |
| 19 | #include <asm/ucontext.h> | 19 | #include <asm/ucontext.h> |
| 20 | #include <asm/unistd.h> | 20 | #include <asm/unistd.h> |
| 21 | #include <asm/vfp.h> | ||
| 21 | 22 | ||
| 22 | #include "ptrace.h" | 23 | #include "ptrace.h" |
| 23 | #include "signal.h" | 24 | #include "signal.h" |
| @@ -175,6 +176,90 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) | |||
| 175 | 176 | ||
| 176 | #endif | 177 | #endif |
| 177 | 178 | ||
| 179 | #ifdef CONFIG_VFP | ||
| 180 | |||
| 181 | static int preserve_vfp_context(struct vfp_sigframe __user *frame) | ||
| 182 | { | ||
| 183 | struct thread_info *thread = current_thread_info(); | ||
| 184 | struct vfp_hard_struct *h = &thread->vfpstate.hard; | ||
| 185 | const unsigned long magic = VFP_MAGIC; | ||
| 186 | const unsigned long size = VFP_STORAGE_SIZE; | ||
| 187 | int err = 0; | ||
| 188 | |||
| 189 | vfp_sync_hwstate(thread); | ||
| 190 | __put_user_error(magic, &frame->magic, err); | ||
| 191 | __put_user_error(size, &frame->size, err); | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Copy the floating point registers. There can be unused | ||
| 195 | * registers see asm/hwcap.h for details. | ||
| 196 | */ | ||
| 197 | err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs, | ||
| 198 | sizeof(h->fpregs)); | ||
| 199 | /* | ||
| 200 | * Copy the status and control register. | ||
| 201 | */ | ||
| 202 | __put_user_error(h->fpscr, &frame->ufp.fpscr, err); | ||
| 203 | |||
| 204 | /* | ||
| 205 | * Copy the exception registers. | ||
| 206 | */ | ||
| 207 | __put_user_error(h->fpexc, &frame->ufp_exc.fpexc, err); | ||
| 208 | __put_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); | ||
| 209 | __put_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); | ||
| 210 | |||
| 211 | return err ? -EFAULT : 0; | ||
| 212 | } | ||
| 213 | |||
| 214 | static int restore_vfp_context(struct vfp_sigframe __user *frame) | ||
| 215 | { | ||
| 216 | struct thread_info *thread = current_thread_info(); | ||
| 217 | struct vfp_hard_struct *h = &thread->vfpstate.hard; | ||
| 218 | unsigned long magic; | ||
| 219 | unsigned long size; | ||
| 220 | unsigned long fpexc; | ||
| 221 | int err = 0; | ||
| 222 | |||
| 223 | __get_user_error(magic, &frame->magic, err); | ||
| 224 | __get_user_error(size, &frame->size, err); | ||
| 225 | |||
| 226 | if (err) | ||
| 227 | return -EFAULT; | ||
| 228 | if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) | ||
| 229 | return -EINVAL; | ||
| 230 | |||
| 231 | /* | ||
| 232 | * Copy the floating point registers. There can be unused | ||
| 233 | * registers see asm/hwcap.h for details. | ||
| 234 | */ | ||
| 235 | err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs, | ||
| 236 | sizeof(h->fpregs)); | ||
| 237 | /* | ||
| 238 | * Copy the status and control register. | ||
| 239 | */ | ||
| 240 | __get_user_error(h->fpscr, &frame->ufp.fpscr, err); | ||
| 241 | |||
| 242 | /* | ||
| 243 | * Sanitise and restore the exception registers. | ||
| 244 | */ | ||
| 245 | __get_user_error(fpexc, &frame->ufp_exc.fpexc, err); | ||
| 246 | /* Ensure the VFP is enabled. */ | ||
| 247 | fpexc |= FPEXC_EN; | ||
| 248 | /* Ensure FPINST2 is invalid and the exception flag is cleared. */ | ||
| 249 | fpexc &= ~(FPEXC_EX | FPEXC_FP2V); | ||
| 250 | h->fpexc = fpexc; | ||
| 251 | |||
| 252 | __get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); | ||
| 253 | __get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); | ||
| 254 | |||
| 255 | if (!err) | ||
| 256 | vfp_flush_hwstate(thread); | ||
| 257 | |||
| 258 | return err ? -EFAULT : 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | #endif | ||
| 262 | |||
| 178 | /* | 263 | /* |
| 179 | * Do a signal return; undo the signal stack. These are aligned to 64-bit. | 264 | * Do a signal return; undo the signal stack. These are aligned to 64-bit. |
| 180 | */ | 265 | */ |
| @@ -233,8 +318,8 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) | |||
| 233 | err |= restore_iwmmxt_context(&aux->iwmmxt); | 318 | err |= restore_iwmmxt_context(&aux->iwmmxt); |
| 234 | #endif | 319 | #endif |
| 235 | #ifdef CONFIG_VFP | 320 | #ifdef CONFIG_VFP |
| 236 | // if (err == 0) | 321 | if (err == 0) |
| 237 | // err |= vfp_restore_state(&sf->aux.vfp); | 322 | err |= restore_vfp_context(&aux->vfp); |
| 238 | #endif | 323 | #endif |
| 239 | 324 | ||
| 240 | return err; | 325 | return err; |
| @@ -348,8 +433,8 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) | |||
| 348 | err |= preserve_iwmmxt_context(&aux->iwmmxt); | 433 | err |= preserve_iwmmxt_context(&aux->iwmmxt); |
| 349 | #endif | 434 | #endif |
| 350 | #ifdef CONFIG_VFP | 435 | #ifdef CONFIG_VFP |
| 351 | // if (err == 0) | 436 | if (err == 0) |
| 352 | // err |= vfp_save_state(&sf->aux.vfp); | 437 | err |= preserve_vfp_context(&aux->vfp); |
| 353 | #endif | 438 | #endif |
| 354 | __put_user_error(0, &aux->end_magic, err); | 439 | __put_user_error(0, &aux->end_magic, err); |
| 355 | 440 | ||
