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 /arch/sparc64/kernel/unaligned.c | |
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>
Diffstat (limited to 'arch/sparc64/kernel/unaligned.c')
-rw-r--r-- | arch/sparc64/kernel/unaligned.c | 261 |
1 files changed, 59 insertions, 202 deletions
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... */ |