diff options
author | David S. Miller <davem@davemloft.net> | 2005-08-19 18:55:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-08-19 18:55:33 -0400 |
commit | a3f9985843b674cbcb58f39fab8416675e7ab842 (patch) | |
tree | aa869cd04ff618d018c5f39b7a3b0070d5e3957d | |
parent | 8d5290149ee1c6a4cea5f5146d64e2a0d48f4988 (diff) |
[SPARC64]: Move kernel unaligned trap handlers into assembler file.
GCC 4.x really dislikes the games we are playing in
unaligned.c, and the cleanest way to fix this is to
move things into assembler.
Noted by Al Viro.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc64/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/sparc64/kernel/traps.c | 3 | ||||
-rw-r--r-- | arch/sparc64/kernel/una_asm.S | 153 | ||||
-rw-r--r-- | arch/sparc64/kernel/unaligned.c | 261 | ||||
-rw-r--r-- | include/asm-sparc64/thread_info.h | 5 |
5 files changed, 221 insertions, 203 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 093281bdf85f..6f00ab8b9d23 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile | |||
@@ -8,7 +8,7 @@ EXTRA_CFLAGS := -Werror | |||
8 | extra-y := head.o init_task.o vmlinux.lds | 8 | extra-y := head.o init_task.o vmlinux.lds |
9 | 9 | ||
10 | obj-y := process.o setup.o cpu.o idprom.o \ | 10 | obj-y := process.o setup.o cpu.o idprom.o \ |
11 | traps.o devices.o auxio.o \ | 11 | traps.o devices.o auxio.o una_asm.o \ |
12 | irq.o ptrace.o time.o sys_sparc.o signal.o \ | 12 | irq.o ptrace.o time.o sys_sparc.o signal.o \ |
13 | unaligned.o central.o pci.o starfire.o semaphore.o \ | 13 | unaligned.o central.o pci.o starfire.o semaphore.o \ |
14 | power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o | 14 | power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o |
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 100b0107c4be..0c9e54b2f0c8 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c | |||
@@ -2127,6 +2127,9 @@ void __init trap_init(void) | |||
2127 | TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) || | 2127 | TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) || |
2128 | TI_NEW_CHILD != offsetof(struct thread_info, new_child) || | 2128 | TI_NEW_CHILD != offsetof(struct thread_info, new_child) || |
2129 | TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) || | 2129 | TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) || |
2130 | TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) || | ||
2131 | TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) || | ||
2132 | TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) || | ||
2130 | TI_FPREGS != offsetof(struct thread_info, fpregs) || | 2133 | TI_FPREGS != offsetof(struct thread_info, fpregs) || |
2131 | (TI_FPREGS & (64 - 1))) | 2134 | (TI_FPREGS & (64 - 1))) |
2132 | thread_info_offsets_are_bolixed_dave(); | 2135 | thread_info_offsets_are_bolixed_dave(); |
diff --git a/arch/sparc64/kernel/una_asm.S b/arch/sparc64/kernel/una_asm.S new file mode 100644 index 000000000000..cbb40585253c --- /dev/null +++ b/arch/sparc64/kernel/una_asm.S | |||
@@ -0,0 +1,153 @@ | |||
1 | /* una_asm.S: Kernel unaligned trap assembler helpers. | ||
2 | * | ||
3 | * Copyright (C) 1996,2005 David S. Miller (davem@davemloft.net) | ||
4 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
5 | */ | ||
6 | |||
7 | .text | ||
8 | |||
9 | kernel_unaligned_trap_fault: | ||
10 | call kernel_mna_trap_fault | ||
11 | nop | ||
12 | retl | ||
13 | nop | ||
14 | .size kern_unaligned_trap_fault, .-kern_unaligned_trap_fault | ||
15 | |||
16 | .globl __do_int_store | ||
17 | __do_int_store: | ||
18 | rd %asi, %o4 | ||
19 | wr %o3, 0, %asi | ||
20 | ldx [%o2], %g3 | ||
21 | cmp %o1, 2 | ||
22 | be,pn %icc, 2f | ||
23 | cmp %o1, 4 | ||
24 | be,pt %icc, 1f | ||
25 | srlx %g3, 24, %g2 | ||
26 | srlx %g3, 56, %g1 | ||
27 | srlx %g3, 48, %g7 | ||
28 | 4: stba %g1, [%o0] %asi | ||
29 | srlx %g3, 40, %g1 | ||
30 | 5: stba %g7, [%o0 + 1] %asi | ||
31 | srlx %g3, 32, %g7 | ||
32 | 6: stba %g1, [%o0 + 2] %asi | ||
33 | 7: stba %g7, [%o0 + 3] %asi | ||
34 | srlx %g3, 16, %g1 | ||
35 | 8: stba %g2, [%o0 + 4] %asi | ||
36 | srlx %g3, 8, %g7 | ||
37 | 9: stba %g1, [%o0 + 5] %asi | ||
38 | 10: stba %g7, [%o0 + 6] %asi | ||
39 | ba,pt %xcc, 0f | ||
40 | 11: stba %g3, [%o0 + 7] %asi | ||
41 | 1: srl %g3, 16, %g7 | ||
42 | 12: stba %g2, [%o0] %asi | ||
43 | srl %g3, 8, %g2 | ||
44 | 13: stba %g7, [%o0 + 1] %asi | ||
45 | 14: stba %g2, [%o0 + 2] %asi | ||
46 | ba,pt %xcc, 0f | ||
47 | 15: stba %g3, [%o0 + 3] %asi | ||
48 | 2: srl %g3, 8, %g2 | ||
49 | 16: stba %g2, [%o0] %asi | ||
50 | 17: stba %g3, [%o0 + 1] %asi | ||
51 | 0: | ||
52 | wr %o4, 0x0, %asi | ||
53 | retl | ||
54 | nop | ||
55 | .size __do_int_store, .-__do_int_store | ||
56 | |||
57 | .section __ex_table | ||
58 | .word 4b, kernel_unaligned_trap_fault | ||
59 | .word 5b, kernel_unaligned_trap_fault | ||
60 | .word 6b, kernel_unaligned_trap_fault | ||
61 | .word 7b, kernel_unaligned_trap_fault | ||
62 | .word 8b, kernel_unaligned_trap_fault | ||
63 | .word 9b, kernel_unaligned_trap_fault | ||
64 | .word 10b, kernel_unaligned_trap_fault | ||
65 | .word 11b, kernel_unaligned_trap_fault | ||
66 | .word 12b, kernel_unaligned_trap_fault | ||
67 | .word 13b, kernel_unaligned_trap_fault | ||
68 | .word 14b, kernel_unaligned_trap_fault | ||
69 | .word 15b, kernel_unaligned_trap_fault | ||
70 | .word 16b, kernel_unaligned_trap_fault | ||
71 | .word 17b, kernel_unaligned_trap_fault | ||
72 | .previous | ||
73 | |||
74 | .globl do_int_load | ||
75 | do_int_load: | ||
76 | rd %asi, %o5 | ||
77 | wr %o4, 0, %asi | ||
78 | cmp %o1, 8 | ||
79 | bge,pn %icc, 9f | ||
80 | cmp %o1, 4 | ||
81 | be,pt %icc, 6f | ||
82 | 4: lduba [%o2] %asi, %g2 | ||
83 | 5: lduba [%o2 + 1] %asi, %g3 | ||
84 | sll %g2, 8, %g2 | ||
85 | brz,pt %o3, 3f | ||
86 | add %g2, %g3, %g2 | ||
87 | sllx %g2, 48, %g2 | ||
88 | srax %g2, 48, %g2 | ||
89 | 3: ba,pt %xcc, 0f | ||
90 | stx %g2, [%o0] | ||
91 | 6: lduba [%o2 + 1] %asi, %g3 | ||
92 | sll %g2, 24, %g2 | ||
93 | 7: lduba [%o2 + 2] %asi, %g7 | ||
94 | sll %g3, 16, %g3 | ||
95 | 8: lduba [%o2 + 3] %asi, %g1 | ||
96 | sll %g7, 8, %g7 | ||
97 | or %g2, %g3, %g2 | ||
98 | or %g7, %g1, %g7 | ||
99 | or %g2, %g7, %g2 | ||
100 | brnz,a,pt %o3, 3f | ||
101 | sra %g2, 0, %g2 | ||
102 | 3: ba,pt %xcc, 0f | ||
103 | stx %g2, [%o0] | ||
104 | 9: lduba [%o2] %asi, %g2 | ||
105 | 10: lduba [%o2 + 1] %asi, %g3 | ||
106 | sllx %g2, 56, %g2 | ||
107 | 11: lduba [%o2 + 2] %asi, %g7 | ||
108 | sllx %g3, 48, %g3 | ||
109 | 12: lduba [%o2 + 3] %asi, %g1 | ||
110 | sllx %g7, 40, %g7 | ||
111 | sllx %g1, 32, %g1 | ||
112 | or %g2, %g3, %g2 | ||
113 | or %g7, %g1, %g7 | ||
114 | 13: lduba [%o2 + 4] %asi, %g3 | ||
115 | or %g2, %g7, %g7 | ||
116 | 14: lduba [%o2 + 5] %asi, %g1 | ||
117 | sllx %g3, 24, %g3 | ||
118 | 15: lduba [%o2 + 6] %asi, %g2 | ||
119 | sllx %g1, 16, %g1 | ||
120 | or %g7, %g3, %g7 | ||
121 | 16: lduba [%o2 + 7] %asi, %g3 | ||
122 | sllx %g2, 8, %g2 | ||
123 | or %g7, %g1, %g7 | ||
124 | or %g2, %g3, %g2 | ||
125 | or %g7, %g2, %g7 | ||
126 | cmp %o1, 8 | ||
127 | be,a,pt %icc, 0f | ||
128 | stx %g7, [%o0] | ||
129 | srlx %g7, 32, %g2 | ||
130 | sra %g7, 0, %g7 | ||
131 | stx %g2, [%o0] | ||
132 | stx %g7, [%o0 + 8] | ||
133 | 0: | ||
134 | wr %o5, 0x0, %asi | ||
135 | retl | ||
136 | nop | ||
137 | .size __do_int_load, .-__do_int_load | ||
138 | |||
139 | .section __ex_table | ||
140 | .word 4b, kernel_unaligned_trap_fault | ||
141 | .word 5b, kernel_unaligned_trap_fault | ||
142 | .word 6b, kernel_unaligned_trap_fault | ||
143 | .word 7b, kernel_unaligned_trap_fault | ||
144 | .word 8b, kernel_unaligned_trap_fault | ||
145 | .word 9b, kernel_unaligned_trap_fault | ||
146 | .word 10b, kernel_unaligned_trap_fault | ||
147 | .word 11b, kernel_unaligned_trap_fault | ||
148 | .word 12b, kernel_unaligned_trap_fault | ||
149 | .word 13b, kernel_unaligned_trap_fault | ||
150 | .word 14b, kernel_unaligned_trap_fault | ||
151 | .word 15b, kernel_unaligned_trap_fault | ||
152 | .word 16b, kernel_unaligned_trap_fault | ||
153 | .previous | ||
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 4372bf32ecf6..11c3e88732e4 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c | |||
@@ -180,169 +180,28 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs) | |||
180 | die_if_kernel(str, regs); | 180 | die_if_kernel(str, regs); |
181 | } | 181 | } |
182 | 182 | ||
183 | #define do_integer_load(dest_reg, size, saddr, is_signed, asi, errh) ({ \ | 183 | extern void do_int_load(unsigned long *dest_reg, int size, |
184 | __asm__ __volatile__ ( \ | 184 | unsigned long *saddr, int is_signed, int asi); |
185 | "wr %4, 0, %%asi\n\t" \ | ||
186 | "cmp %1, 8\n\t" \ | ||
187 | "bge,pn %%icc, 9f\n\t" \ | ||
188 | " cmp %1, 4\n\t" \ | ||
189 | "be,pt %%icc, 6f\n" \ | ||
190 | "4:\t" " lduba [%2] %%asi, %%l1\n" \ | ||
191 | "5:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ | ||
192 | "sll %%l1, 8, %%l1\n\t" \ | ||
193 | "brz,pt %3, 3f\n\t" \ | ||
194 | " add %%l1, %%l2, %%l1\n\t" \ | ||
195 | "sllx %%l1, 48, %%l1\n\t" \ | ||
196 | "srax %%l1, 48, %%l1\n" \ | ||
197 | "3:\t" "ba,pt %%xcc, 0f\n\t" \ | ||
198 | " stx %%l1, [%0]\n" \ | ||
199 | "6:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ | ||
200 | "sll %%l1, 24, %%l1\n" \ | ||
201 | "7:\t" "lduba [%2 + 2] %%asi, %%g7\n\t" \ | ||
202 | "sll %%l2, 16, %%l2\n" \ | ||
203 | "8:\t" "lduba [%2 + 3] %%asi, %%g1\n\t" \ | ||
204 | "sll %%g7, 8, %%g7\n\t" \ | ||
205 | "or %%l1, %%l2, %%l1\n\t" \ | ||
206 | "or %%g7, %%g1, %%g7\n\t" \ | ||
207 | "or %%l1, %%g7, %%l1\n\t" \ | ||
208 | "brnz,a,pt %3, 3f\n\t" \ | ||
209 | " sra %%l1, 0, %%l1\n" \ | ||
210 | "3:\t" "ba,pt %%xcc, 0f\n\t" \ | ||
211 | " stx %%l1, [%0]\n" \ | ||
212 | "9:\t" "lduba [%2] %%asi, %%l1\n" \ | ||
213 | "10:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ | ||
214 | "sllx %%l1, 56, %%l1\n" \ | ||
215 | "11:\t" "lduba [%2 + 2] %%asi, %%g7\n\t" \ | ||
216 | "sllx %%l2, 48, %%l2\n" \ | ||
217 | "12:\t" "lduba [%2 + 3] %%asi, %%g1\n\t" \ | ||
218 | "sllx %%g7, 40, %%g7\n\t" \ | ||
219 | "sllx %%g1, 32, %%g1\n\t" \ | ||
220 | "or %%l1, %%l2, %%l1\n\t" \ | ||
221 | "or %%g7, %%g1, %%g7\n" \ | ||
222 | "13:\t" "lduba [%2 + 4] %%asi, %%l2\n\t" \ | ||
223 | "or %%l1, %%g7, %%g7\n" \ | ||
224 | "14:\t" "lduba [%2 + 5] %%asi, %%g1\n\t" \ | ||
225 | "sllx %%l2, 24, %%l2\n" \ | ||
226 | "15:\t" "lduba [%2 + 6] %%asi, %%l1\n\t" \ | ||
227 | "sllx %%g1, 16, %%g1\n\t" \ | ||
228 | "or %%g7, %%l2, %%g7\n" \ | ||
229 | "16:\t" "lduba [%2 + 7] %%asi, %%l2\n\t" \ | ||
230 | "sllx %%l1, 8, %%l1\n\t" \ | ||
231 | "or %%g7, %%g1, %%g7\n\t" \ | ||
232 | "or %%l1, %%l2, %%l1\n\t" \ | ||
233 | "or %%g7, %%l1, %%g7\n\t" \ | ||
234 | "cmp %1, 8\n\t" \ | ||
235 | "be,a,pt %%icc, 0f\n\t" \ | ||
236 | " stx %%g7, [%0]\n\t" \ | ||
237 | "srlx %%g7, 32, %%l1\n\t" \ | ||
238 | "sra %%g7, 0, %%g7\n\t" \ | ||
239 | "stx %%l1, [%0]\n\t" \ | ||
240 | "stx %%g7, [%0 + 8]\n" \ | ||
241 | "0:\n\t" \ | ||
242 | "wr %%g0, %5, %%asi\n\n\t" \ | ||
243 | ".section __ex_table\n\t" \ | ||
244 | ".word 4b, " #errh "\n\t" \ | ||
245 | ".word 5b, " #errh "\n\t" \ | ||
246 | ".word 6b, " #errh "\n\t" \ | ||
247 | ".word 7b, " #errh "\n\t" \ | ||
248 | ".word 8b, " #errh "\n\t" \ | ||
249 | ".word 9b, " #errh "\n\t" \ | ||
250 | ".word 10b, " #errh "\n\t" \ | ||
251 | ".word 11b, " #errh "\n\t" \ | ||
252 | ".word 12b, " #errh "\n\t" \ | ||
253 | ".word 13b, " #errh "\n\t" \ | ||
254 | ".word 14b, " #errh "\n\t" \ | ||
255 | ".word 15b, " #errh "\n\t" \ | ||
256 | ".word 16b, " #errh "\n\n\t" \ | ||
257 | ".previous\n\t" \ | ||
258 | : : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed), \ | ||
259 | "r" (asi), "i" (ASI_AIUS) \ | ||
260 | : "l1", "l2", "g7", "g1", "cc"); \ | ||
261 | }) | ||
262 | 185 | ||
263 | #define store_common(dst_addr, size, src_val, asi, errh) ({ \ | 186 | extern void __do_int_store(unsigned long *dst_addr, int size, |
264 | __asm__ __volatile__ ( \ | 187 | unsigned long *src_val, int asi); |
265 | "wr %3, 0, %%asi\n\t" \ | 188 | |
266 | "ldx [%2], %%l1\n" \ | 189 | static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, |
267 | "cmp %1, 2\n\t" \ | 190 | struct pt_regs *regs, int asi) |
268 | "be,pn %%icc, 2f\n\t" \ | 191 | { |
269 | " cmp %1, 4\n\t" \ | 192 | unsigned long zero = 0; |
270 | "be,pt %%icc, 1f\n\t" \ | 193 | unsigned long *src_val = &zero; |
271 | " srlx %%l1, 24, %%l2\n\t" \ | 194 | |
272 | "srlx %%l1, 56, %%g1\n\t" \ | 195 | if (size == 16) { |
273 | "srlx %%l1, 48, %%g7\n" \ | 196 | size = 8; |
274 | "4:\t" "stba %%g1, [%0] %%asi\n\t" \ | 197 | zero = (((long)(reg_num ? |
275 | "srlx %%l1, 40, %%g1\n" \ | 198 | (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | |
276 | "5:\t" "stba %%g7, [%0 + 1] %%asi\n\t" \ | 199 | (unsigned)fetch_reg(reg_num + 1, regs); |
277 | "srlx %%l1, 32, %%g7\n" \ | 200 | } else if (reg_num) { |
278 | "6:\t" "stba %%g1, [%0 + 2] %%asi\n" \ | 201 | src_val = fetch_reg_addr(reg_num, regs); |
279 | "7:\t" "stba %%g7, [%0 + 3] %%asi\n\t" \ | 202 | } |
280 | "srlx %%l1, 16, %%g1\n" \ | 203 | __do_int_store(dst_addr, size, src_val, asi); |
281 | "8:\t" "stba %%l2, [%0 + 4] %%asi\n\t" \ | 204 | } |
282 | "srlx %%l1, 8, %%g7\n" \ | ||
283 | "9:\t" "stba %%g1, [%0 + 5] %%asi\n" \ | ||
284 | "10:\t" "stba %%g7, [%0 + 6] %%asi\n\t" \ | ||
285 | "ba,pt %%xcc, 0f\n" \ | ||
286 | "11:\t" " stba %%l1, [%0 + 7] %%asi\n" \ | ||
287 | "1:\t" "srl %%l1, 16, %%g7\n" \ | ||
288 | "12:\t" "stba %%l2, [%0] %%asi\n\t" \ | ||
289 | "srl %%l1, 8, %%l2\n" \ | ||
290 | "13:\t" "stba %%g7, [%0 + 1] %%asi\n" \ | ||
291 | "14:\t" "stba %%l2, [%0 + 2] %%asi\n\t" \ | ||
292 | "ba,pt %%xcc, 0f\n" \ | ||
293 | "15:\t" " stba %%l1, [%0 + 3] %%asi\n" \ | ||
294 | "2:\t" "srl %%l1, 8, %%l2\n" \ | ||
295 | "16:\t" "stba %%l2, [%0] %%asi\n" \ | ||
296 | "17:\t" "stba %%l1, [%0 + 1] %%asi\n" \ | ||
297 | "0:\n\t" \ | ||
298 | "wr %%g0, %4, %%asi\n\n\t" \ | ||
299 | ".section __ex_table\n\t" \ | ||
300 | ".word 4b, " #errh "\n\t" \ | ||
301 | ".word 5b, " #errh "\n\t" \ | ||
302 | ".word 6b, " #errh "\n\t" \ | ||
303 | ".word 7b, " #errh "\n\t" \ | ||
304 | ".word 8b, " #errh "\n\t" \ | ||
305 | ".word 9b, " #errh "\n\t" \ | ||
306 | ".word 10b, " #errh "\n\t" \ | ||
307 | ".word 11b, " #errh "\n\t" \ | ||
308 | ".word 12b, " #errh "\n\t" \ | ||
309 | ".word 13b, " #errh "\n\t" \ | ||
310 | ".word 14b, " #errh "\n\t" \ | ||
311 | ".word 15b, " #errh "\n\t" \ | ||
312 | ".word 16b, " #errh "\n\t" \ | ||
313 | ".word 17b, " #errh "\n\n\t" \ | ||
314 | ".previous\n\t" \ | ||
315 | : : "r" (dst_addr), "r" (size), "r" (src_val), "r" (asi), "i" (ASI_AIUS)\ | ||
316 | : "l1", "l2", "g7", "g1", "cc"); \ | ||
317 | }) | ||
318 | |||
319 | #define do_integer_store(reg_num, size, dst_addr, regs, asi, errh) ({ \ | ||
320 | unsigned long zero = 0; \ | ||
321 | unsigned long *src_val = &zero; \ | ||
322 | \ | ||
323 | if (size == 16) { \ | ||
324 | size = 8; \ | ||
325 | zero = (((long)(reg_num ? \ | ||
326 | (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | \ | ||
327 | (unsigned)fetch_reg(reg_num + 1, regs); \ | ||
328 | } else if (reg_num) src_val = fetch_reg_addr(reg_num, regs); \ | ||
329 | store_common(dst_addr, size, src_val, asi, errh); \ | ||
330 | }) | ||
331 | |||
332 | extern void smp_capture(void); | ||
333 | extern void smp_release(void); | ||
334 | |||
335 | #define do_atomic(srcdest_reg, mem, errh) ({ \ | ||
336 | unsigned long flags, tmp; \ | ||
337 | \ | ||
338 | smp_capture(); \ | ||
339 | local_irq_save(flags); \ | ||
340 | tmp = *srcdest_reg; \ | ||
341 | do_integer_load(srcdest_reg, 4, mem, 0, errh); \ | ||
342 | store_common(mem, 4, &tmp, errh); \ | ||
343 | local_irq_restore(flags); \ | ||
344 | smp_release(); \ | ||
345 | }) | ||
346 | 205 | ||
347 | static inline void advance(struct pt_regs *regs) | 206 | static inline void advance(struct pt_regs *regs) |
348 | { | 207 | { |
@@ -364,24 +223,29 @@ static inline int ok_for_kernel(unsigned int insn) | |||
364 | return !floating_point_load_or_store_p(insn); | 223 | return !floating_point_load_or_store_p(insn); |
365 | } | 224 | } |
366 | 225 | ||
367 | void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("kernel_mna_trap_fault"); | 226 | void kernel_mna_trap_fault(void) |
368 | |||
369 | void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) | ||
370 | { | 227 | { |
371 | unsigned long g2 = regs->u_regs [UREG_G2]; | 228 | struct pt_regs *regs = current_thread_info()->kern_una_regs; |
229 | unsigned int insn = current_thread_info()->kern_una_insn; | ||
230 | unsigned long g2 = regs->u_regs[UREG_G2]; | ||
372 | unsigned long fixup = search_extables_range(regs->tpc, &g2); | 231 | unsigned long fixup = search_extables_range(regs->tpc, &g2); |
373 | 232 | ||
374 | if (!fixup) { | 233 | if (!fixup) { |
375 | unsigned long address = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); | 234 | unsigned long address; |
235 | |||
236 | address = compute_effective_address(regs, insn, | ||
237 | ((insn >> 25) & 0x1f)); | ||
376 | if (address < PAGE_SIZE) { | 238 | if (address < PAGE_SIZE) { |
377 | printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler"); | 239 | printk(KERN_ALERT "Unable to handle kernel NULL " |
240 | "pointer dereference in mna handler"); | ||
378 | } else | 241 | } else |
379 | printk(KERN_ALERT "Unable to handle kernel paging request in mna handler"); | 242 | printk(KERN_ALERT "Unable to handle kernel paging " |
243 | "request in mna handler"); | ||
380 | printk(KERN_ALERT " at virtual address %016lx\n",address); | 244 | printk(KERN_ALERT " at virtual address %016lx\n",address); |
381 | printk(KERN_ALERT "current->{mm,active_mm}->context = %016lx\n", | 245 | printk(KERN_ALERT "current->{active_,}mm->context = %016lx\n", |
382 | (current->mm ? CTX_HWBITS(current->mm->context) : | 246 | (current->mm ? CTX_HWBITS(current->mm->context) : |
383 | CTX_HWBITS(current->active_mm->context))); | 247 | CTX_HWBITS(current->active_mm->context))); |
384 | printk(KERN_ALERT "current->{mm,active_mm}->pgd = %016lx\n", | 248 | printk(KERN_ALERT "current->{active_,}mm->pgd = %016lx\n", |
385 | (current->mm ? (unsigned long) current->mm->pgd : | 249 | (current->mm ? (unsigned long) current->mm->pgd : |
386 | (unsigned long) current->active_mm->pgd)); | 250 | (unsigned long) current->active_mm->pgd)); |
387 | die_if_kernel("Oops", regs); | 251 | die_if_kernel("Oops", regs); |
@@ -400,48 +264,41 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u | |||
400 | enum direction dir = decode_direction(insn); | 264 | enum direction dir = decode_direction(insn); |
401 | int size = decode_access_size(insn); | 265 | int size = decode_access_size(insn); |
402 | 266 | ||
267 | current_thread_info()->kern_una_regs = regs; | ||
268 | current_thread_info()->kern_una_insn = insn; | ||
269 | |||
403 | if (!ok_for_kernel(insn) || dir == both) { | 270 | if (!ok_for_kernel(insn) || dir == both) { |
404 | printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n", | 271 | printk("Unsupported unaligned load/store trap for kernel " |
405 | regs->tpc); | 272 | "at <%016lx>.\n", regs->tpc); |
406 | unaligned_panic("Kernel does fpu/atomic unaligned load/store.", regs); | 273 | unaligned_panic("Kernel does fpu/atomic " |
407 | 274 | "unaligned load/store.", regs); | |
408 | __asm__ __volatile__ ("\n" | 275 | |
409 | "kernel_unaligned_trap_fault:\n\t" | 276 | kernel_mna_trap_fault(); |
410 | "mov %0, %%o0\n\t" | ||
411 | "call kernel_mna_trap_fault\n\t" | ||
412 | " mov %1, %%o1\n\t" | ||
413 | : | ||
414 | : "r" (regs), "r" (insn) | ||
415 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", | ||
416 | "g1", "g2", "g3", "g4", "g7", "cc"); | ||
417 | } else { | 277 | } else { |
418 | unsigned long addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); | 278 | unsigned long addr; |
419 | 279 | ||
280 | addr = compute_effective_address(regs, insn, | ||
281 | ((insn >> 25) & 0x1f)); | ||
420 | #ifdef DEBUG_MNA | 282 | #ifdef DEBUG_MNA |
421 | printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] retpc[%016lx]\n", | 283 | printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] " |
422 | regs->tpc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]); | 284 | "retpc[%016lx]\n", |
285 | regs->tpc, dirstrings[dir], addr, size, | ||
286 | regs->u_regs[UREG_RETPC]); | ||
423 | #endif | 287 | #endif |
424 | switch (dir) { | 288 | switch (dir) { |
425 | case load: | 289 | case load: |
426 | do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs), | 290 | do_int_load(fetch_reg_addr(((insn>>25)&0x1f), regs), |
427 | size, (unsigned long *) addr, | 291 | size, (unsigned long *) addr, |
428 | decode_signedness(insn), decode_asi(insn, regs), | 292 | decode_signedness(insn), |
429 | kernel_unaligned_trap_fault); | 293 | decode_asi(insn, regs)); |
430 | break; | 294 | break; |
431 | 295 | ||
432 | case store: | 296 | case store: |
433 | do_integer_store(((insn>>25)&0x1f), size, | 297 | do_int_store(((insn>>25)&0x1f), size, |
434 | (unsigned long *) addr, regs, | 298 | (unsigned long *) addr, regs, |
435 | decode_asi(insn, regs), | 299 | decode_asi(insn, regs)); |
436 | kernel_unaligned_trap_fault); | ||
437 | break; | ||
438 | #if 0 /* unsupported */ | ||
439 | case both: | ||
440 | do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs), | ||
441 | (unsigned long *) addr, | ||
442 | kernel_unaligned_trap_fault); | ||
443 | break; | 300 | break; |
444 | #endif | 301 | |
445 | default: | 302 | default: |
446 | panic("Impossible kernel unaligned trap."); | 303 | panic("Impossible kernel unaligned trap."); |
447 | /* Not reached... */ | 304 | /* Not reached... */ |
diff --git a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h index 352d9943661a..c94d8b3991bd 100644 --- a/include/asm-sparc64/thread_info.h +++ b/include/asm-sparc64/thread_info.h | |||
@@ -68,6 +68,9 @@ struct thread_info { | |||
68 | 68 | ||
69 | struct restart_block restart_block; | 69 | struct restart_block restart_block; |
70 | 70 | ||
71 | struct pt_regs *kern_una_regs; | ||
72 | unsigned int kern_una_insn; | ||
73 | |||
71 | unsigned long fpregs[0] __attribute__ ((aligned(64))); | 74 | unsigned long fpregs[0] __attribute__ ((aligned(64))); |
72 | }; | 75 | }; |
73 | 76 | ||
@@ -103,6 +106,8 @@ struct thread_info { | |||
103 | #define TI_PCR 0x00000490 | 106 | #define TI_PCR 0x00000490 |
104 | #define TI_CEE_STUFF 0x00000498 | 107 | #define TI_CEE_STUFF 0x00000498 |
105 | #define TI_RESTART_BLOCK 0x000004a0 | 108 | #define TI_RESTART_BLOCK 0x000004a0 |
109 | #define TI_KUNA_REGS 0x000004c8 | ||
110 | #define TI_KUNA_INSN 0x000004d0 | ||
106 | #define TI_FPREGS 0x00000500 | 111 | #define TI_FPREGS 0x00000500 |
107 | 112 | ||
108 | /* We embed this in the uppermost byte of thread_info->flags */ | 113 | /* We embed this in the uppermost byte of thread_info->flags */ |