diff options
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap-psp-2.6.32/0032-ARM-VFP-preserve-the-HW-context-when-calling-signal-.patch')
-rw-r--r-- | extras/recipes-kernel/linux/linux-omap-psp-2.6.32/0032-ARM-VFP-preserve-the-HW-context-when-calling-signal-.patch | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap-psp-2.6.32/0032-ARM-VFP-preserve-the-HW-context-when-calling-signal-.patch b/extras/recipes-kernel/linux/linux-omap-psp-2.6.32/0032-ARM-VFP-preserve-the-HW-context-when-calling-signal-.patch new file mode 100644 index 00000000..f2571306 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-psp-2.6.32/0032-ARM-VFP-preserve-the-HW-context-when-calling-signal-.patch | |||
@@ -0,0 +1,211 @@ | |||
1 | From 1be18045f852e78bf78d2042a5210c53d830f81b Mon Sep 17 00:00:00 2001 | ||
2 | From: Imre Deak <imre.deak@nokia.com> | ||
3 | Date: Thu, 4 Feb 2010 21:38:30 +0200 | ||
4 | Subject: [PATCH 32/45] ARM: VFP: preserve the HW context when calling signal handlers | ||
5 | |||
6 | ARM: VFP: preserve the HW context when calling signal handlers | ||
7 | |||
8 | Signal handlers can use floating point, so prevent them to corrupt | ||
9 | the main thread's VFP context. So far there were two signal stack | ||
10 | frame formats defined based on the VFP implementation, but the user | ||
11 | struct used for ptrace covers all posibilities, so use it for the | ||
12 | signal stack too. This patch extends the user struct and leaves | ||
13 | its magic number the same, in the hope that user space code does | ||
14 | not depend on its size and can parse the original regs w/o | ||
15 | problems. | ||
16 | |||
17 | Support to save / restore the exception registers was added by | ||
18 | Will Deacon. | ||
19 | |||
20 | Signed-off-by: Imre Deak <imre.deak@nokia.com> | ||
21 | Signed-off-by: Will Deacon <will.deacon@arm.com> | ||
22 | Signed-off-by: Bryan Wu <bryan.wu@canonical.com> | ||
23 | --- | ||
24 | arch/arm/include/asm/ucontext.h | 19 +++----- | ||
25 | arch/arm/include/asm/user.h | 3 + | ||
26 | arch/arm/kernel/signal.c | 91 +++++++++++++++++++++++++++++++++++++-- | ||
27 | 3 files changed, 97 insertions(+), 16 deletions(-) | ||
28 | |||
29 | diff --git a/arch/arm/include/asm/ucontext.h b/arch/arm/include/asm/ucontext.h | ||
30 | index bf65e9f..1c3236b 100644 | ||
31 | --- a/arch/arm/include/asm/ucontext.h | ||
32 | +++ b/arch/arm/include/asm/ucontext.h | ||
33 | @@ -59,23 +59,18 @@ struct iwmmxt_sigframe { | ||
34 | #endif /* CONFIG_IWMMXT */ | ||
35 | |||
36 | #ifdef CONFIG_VFP | ||
37 | -#if __LINUX_ARM_ARCH__ < 6 | ||
38 | -/* For ARM pre-v6, we use fstmiax and fldmiax. This adds one extra | ||
39 | - * word after the registers, and a word of padding at the end for | ||
40 | - * alignment. */ | ||
41 | #define VFP_MAGIC 0x56465001 | ||
42 | -#define VFP_STORAGE_SIZE 152 | ||
43 | -#else | ||
44 | -#define VFP_MAGIC 0x56465002 | ||
45 | -#define VFP_STORAGE_SIZE 144 | ||
46 | -#endif | ||
47 | |||
48 | struct vfp_sigframe | ||
49 | { | ||
50 | unsigned long magic; | ||
51 | unsigned long size; | ||
52 | - union vfp_state storage; | ||
53 | -}; | ||
54 | + struct user_vfp ufp; | ||
55 | +} __attribute__((__aligned__(8))); | ||
56 | + | ||
57 | +/* 8 byte for magic and size, 272 byte for ufp */ | ||
58 | +#define VFP_STORAGE_SIZE sizeof(struct vfp_sigframe) | ||
59 | + | ||
60 | #endif /* CONFIG_VFP */ | ||
61 | |||
62 | /* | ||
63 | @@ -91,7 +86,7 @@ struct aux_sigframe { | ||
64 | #ifdef CONFIG_IWMMXT | ||
65 | struct iwmmxt_sigframe iwmmxt; | ||
66 | #endif | ||
67 | -#if 0 && defined CONFIG_VFP /* Not yet saved. */ | ||
68 | +#ifdef CONFIG_VFP | ||
69 | struct vfp_sigframe vfp; | ||
70 | #endif | ||
71 | /* Something that isn't a valid magic number for any coprocessor. */ | ||
72 | diff --git a/arch/arm/include/asm/user.h b/arch/arm/include/asm/user.h | ||
73 | index df95e05..ea7e44d 100644 | ||
74 | --- a/arch/arm/include/asm/user.h | ||
75 | +++ b/arch/arm/include/asm/user.h | ||
76 | @@ -88,6 +88,9 @@ struct user{ | ||
77 | struct user_vfp { | ||
78 | unsigned long long fpregs[32]; | ||
79 | unsigned long fpscr; | ||
80 | + unsigned long fpexc; | ||
81 | + unsigned long fpinst; | ||
82 | + unsigned long fpinst2; | ||
83 | }; | ||
84 | |||
85 | #endif /* _ARM_USER_H */ | ||
86 | diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c | ||
87 | index e7714f3..6a36851 100644 | ||
88 | --- a/arch/arm/kernel/signal.c | ||
89 | +++ b/arch/arm/kernel/signal.c | ||
90 | @@ -18,6 +18,7 @@ | ||
91 | #include <asm/cacheflush.h> | ||
92 | #include <asm/ucontext.h> | ||
93 | #include <asm/unistd.h> | ||
94 | +#include <asm/vfp.h> | ||
95 | |||
96 | #include "ptrace.h" | ||
97 | #include "signal.h" | ||
98 | @@ -175,6 +176,88 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) | ||
99 | |||
100 | #endif | ||
101 | |||
102 | +#ifdef CONFIG_VFP | ||
103 | + | ||
104 | +static int preserve_vfp_context(struct vfp_sigframe __user *frame) | ||
105 | +{ | ||
106 | + struct thread_info *thread = current_thread_info(); | ||
107 | + struct vfp_hard_struct *h = &thread->vfpstate.hard; | ||
108 | + const unsigned long magic = VFP_MAGIC; | ||
109 | + const unsigned long size = VFP_STORAGE_SIZE; | ||
110 | + int err = 0; | ||
111 | + | ||
112 | + vfp_sync_state(thread); | ||
113 | + __put_user_error(magic, &frame->magic, err); | ||
114 | + __put_user_error(size, &frame->size, err); | ||
115 | + | ||
116 | + /* | ||
117 | + * Copy the floating point registers. There can be unused | ||
118 | + * registers see asm/hwcap.h for details. | ||
119 | + */ | ||
120 | + err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs, | ||
121 | + sizeof(h->fpregs)); | ||
122 | + /* | ||
123 | + * Copy the status and control register. | ||
124 | + */ | ||
125 | + __put_user_error(h->fpscr, &frame->ufp.fpscr, err); | ||
126 | + | ||
127 | + /* | ||
128 | + * Copy the exception registers. | ||
129 | + */ | ||
130 | + __put_user_error(h->fpexc, &frame->ufp.fpexc, err); | ||
131 | + __put_user_error(h->fpinst, &frame->ufp.fpinst, err); | ||
132 | + __put_user_error(h->fpinst2, &frame->ufp.fpinst2, err); | ||
133 | + | ||
134 | + return err ? -EFAULT : 0; | ||
135 | +} | ||
136 | + | ||
137 | +static int restore_vfp_context(struct vfp_sigframe __user *frame) | ||
138 | +{ | ||
139 | + struct thread_info *thread = current_thread_info(); | ||
140 | + struct vfp_hard_struct *h = &thread->vfpstate.hard; | ||
141 | + unsigned long magic; | ||
142 | + unsigned long size; | ||
143 | + unsigned long fpexc; | ||
144 | + int err = 0; | ||
145 | + | ||
146 | + vfp_sync_state(thread); | ||
147 | + __get_user_error(magic, &frame->magic, err); | ||
148 | + __get_user_error(size, &frame->size, err); | ||
149 | + | ||
150 | + if (err) | ||
151 | + return -EFAULT; | ||
152 | + if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) | ||
153 | + return -EINVAL; | ||
154 | + | ||
155 | + /* | ||
156 | + * Copy the floating point registers. There can be unused | ||
157 | + * registers see asm/hwcap.h for details. | ||
158 | + */ | ||
159 | + err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs, | ||
160 | + sizeof(h->fpregs)); | ||
161 | + /* | ||
162 | + * Copy the status and control register. | ||
163 | + */ | ||
164 | + __get_user_error(h->fpscr, &frame->ufp.fpscr, err); | ||
165 | + | ||
166 | + /* | ||
167 | + * Sanitise and restore the exception registers. | ||
168 | + */ | ||
169 | + __get_user_error(fpexc, &frame->ufp.fpexc, err); | ||
170 | + /* Ensure the VFP is enabled. */ | ||
171 | + fpexc |= FPEXC_EN; | ||
172 | + /* Ensure FPINST2 is invalid and the exception flag is cleared. */ | ||
173 | + fpexc &= ~(FPEXC_EX | FPEXC_FP2V); | ||
174 | + h->fpexc = fpexc; | ||
175 | + | ||
176 | + __get_user_error(h->fpinst, &frame->ufp.fpinst, err); | ||
177 | + __get_user_error(h->fpinst2, &frame->ufp.fpinst2, err); | ||
178 | + | ||
179 | + return err ? -EFAULT : 0; | ||
180 | +} | ||
181 | + | ||
182 | +#endif | ||
183 | + | ||
184 | /* | ||
185 | * Do a signal return; undo the signal stack. These are aligned to 64-bit. | ||
186 | */ | ||
187 | @@ -233,8 +316,8 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) | ||
188 | err |= restore_iwmmxt_context(&aux->iwmmxt); | ||
189 | #endif | ||
190 | #ifdef CONFIG_VFP | ||
191 | -// if (err == 0) | ||
192 | -// err |= vfp_restore_state(&sf->aux.vfp); | ||
193 | + if (err == 0) | ||
194 | + err |= restore_vfp_context(&aux->vfp); | ||
195 | #endif | ||
196 | |||
197 | return err; | ||
198 | @@ -348,8 +431,8 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) | ||
199 | err |= preserve_iwmmxt_context(&aux->iwmmxt); | ||
200 | #endif | ||
201 | #ifdef CONFIG_VFP | ||
202 | -// if (err == 0) | ||
203 | -// err |= vfp_save_state(&sf->aux.vfp); | ||
204 | + if (err == 0) | ||
205 | + err |= preserve_vfp_context(&aux->vfp); | ||
206 | #endif | ||
207 | __put_user_error(0, &aux->end_magic, err); | ||
208 | |||
209 | -- | ||
210 | 1.6.6.1 | ||
211 | |||