diff options
| -rw-r--r-- | arch/arm/include/asm/ucontext.h | 23 | ||||
| -rw-r--r-- | arch/arm/include/asm/user.h | 12 | ||||
| -rw-r--r-- | arch/arm/kernel/signal.c | 93 |
3 files changed, 111 insertions, 17 deletions
diff --git a/arch/arm/include/asm/ucontext.h b/arch/arm/include/asm/ucontext.h index bf65e9f4525d..47f023aa8495 100644 --- a/arch/arm/include/asm/ucontext.h +++ b/arch/arm/include/asm/ucontext.h | |||
| @@ -59,23 +59,22 @@ struct iwmmxt_sigframe { | |||
| 59 | #endif /* CONFIG_IWMMXT */ | 59 | #endif /* CONFIG_IWMMXT */ |
| 60 | 60 | ||
| 61 | #ifdef CONFIG_VFP | 61 | #ifdef CONFIG_VFP |
| 62 | #if __LINUX_ARM_ARCH__ < 6 | ||
| 63 | /* For ARM pre-v6, we use fstmiax and fldmiax. This adds one extra | ||
| 64 | * word after the registers, and a word of padding at the end for | ||
| 65 | * alignment. */ | ||
| 66 | #define VFP_MAGIC 0x56465001 | 62 | #define VFP_MAGIC 0x56465001 |
| 67 | #define VFP_STORAGE_SIZE 152 | ||
| 68 | #else | ||
| 69 | #define VFP_MAGIC 0x56465002 | ||
| 70 | #define VFP_STORAGE_SIZE 144 | ||
| 71 | #endif | ||
| 72 | 63 | ||
| 73 | struct vfp_sigframe | 64 | struct vfp_sigframe |
| 74 | { | 65 | { |
| 75 | unsigned long magic; | 66 | unsigned long magic; |
| 76 | unsigned long size; | 67 | unsigned long size; |
| 77 | union vfp_state storage; | 68 | struct user_vfp ufp; |
| 78 | }; | 69 | struct user_vfp_exc ufp_exc; |
| 70 | } __attribute__((__aligned__(8))); | ||
| 71 | |||
| 72 | /* | ||
| 73 | * 8 byte for magic and size, 264 byte for ufp, 12 bytes for ufp_exc, | ||
| 74 | * 4 bytes padding. | ||
| 75 | */ | ||
| 76 | #define VFP_STORAGE_SIZE sizeof(struct vfp_sigframe) | ||
| 77 | |||
| 79 | #endif /* CONFIG_VFP */ | 78 | #endif /* CONFIG_VFP */ |
| 80 | 79 | ||
| 81 | /* | 80 | /* |
| @@ -91,7 +90,7 @@ struct aux_sigframe { | |||
| 91 | #ifdef CONFIG_IWMMXT | 90 | #ifdef CONFIG_IWMMXT |
| 92 | struct iwmmxt_sigframe iwmmxt; | 91 | struct iwmmxt_sigframe iwmmxt; |
| 93 | #endif | 92 | #endif |
| 94 | #if 0 && defined CONFIG_VFP /* Not yet saved. */ | 93 | #ifdef CONFIG_VFP |
| 95 | struct vfp_sigframe vfp; | 94 | struct vfp_sigframe vfp; |
| 96 | #endif | 95 | #endif |
| 97 | /* Something that isn't a valid magic number for any coprocessor. */ | 96 | /* Something that isn't a valid magic number for any coprocessor. */ |
diff --git a/arch/arm/include/asm/user.h b/arch/arm/include/asm/user.h index df95e050f9dd..05ac4b06876a 100644 --- a/arch/arm/include/asm/user.h +++ b/arch/arm/include/asm/user.h | |||
| @@ -83,11 +83,21 @@ struct user{ | |||
| 83 | 83 | ||
| 84 | /* | 84 | /* |
| 85 | * User specific VFP registers. If only VFPv2 is present, registers 16 to 31 | 85 | * User specific VFP registers. If only VFPv2 is present, registers 16 to 31 |
| 86 | * are ignored by the ptrace system call. | 86 | * are ignored by the ptrace system call and the signal handler. |
| 87 | */ | 87 | */ |
| 88 | struct user_vfp { | 88 | struct user_vfp { |
| 89 | unsigned long long fpregs[32]; | 89 | unsigned long long fpregs[32]; |
| 90 | unsigned long fpscr; | 90 | unsigned long fpscr; |
| 91 | }; | 91 | }; |
| 92 | 92 | ||
| 93 | /* | ||
| 94 | * VFP exception registers exposed to user space during signal delivery. | ||
| 95 | * Fields not relavant to the current VFP architecture are ignored. | ||
| 96 | */ | ||
| 97 | struct user_vfp_exc { | ||
| 98 | unsigned long fpexc; | ||
| 99 | unsigned long fpinst; | ||
| 100 | unsigned long fpinst2; | ||
| 101 | }; | ||
| 102 | |||
| 93 | #endif /* _ARM_USER_H */ | 103 | #endif /* _ARM_USER_H */ |
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 | ||
