aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Musta <tommusta@gmail.com>2013-10-18 15:44:17 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-10-30 01:01:36 -0400
commitdbc2fbd7c29a78724e761711d516930246c0e1c2 (patch)
treeda410fc25920bad6355d2cc121ef31f9faa5a1d8
parent6506b4718bb59c5d4e59235b81b5e13ea5d3c49a (diff)
powerpc: Fix Unaligned LE Floating Point Loads and Stores
This patch addresses unaligned single precision floating point loads and stores in the single-step code. The old implementation improperly treated an 8 byte structure as an array of two 4 byte words, which is a classic little endian bug. Signed-off-by: Tom Musta <tmusta@gmail.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/lib/sstep.c52
1 files changed, 40 insertions, 12 deletions
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 0121d2140ab9..c0511c27a733 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -355,22 +355,36 @@ static int __kprobes do_fp_load(int rn, int (*func)(int, unsigned long),
355 struct pt_regs *regs) 355 struct pt_regs *regs)
356{ 356{
357 int err; 357 int err;
358 unsigned long val[sizeof(double) / sizeof(long)]; 358 union {
359 double dbl;
360 unsigned long ul[2];
361 struct {
362#ifdef __BIG_ENDIAN__
363 unsigned _pad_;
364 unsigned word;
365#endif
366#ifdef __LITTLE_ENDIAN__
367 unsigned word;
368 unsigned _pad_;
369#endif
370 } single;
371 } data;
359 unsigned long ptr; 372 unsigned long ptr;
360 373
361 if (!address_ok(regs, ea, nb)) 374 if (!address_ok(regs, ea, nb))
362 return -EFAULT; 375 return -EFAULT;
363 if ((ea & 3) == 0) 376 if ((ea & 3) == 0)
364 return (*func)(rn, ea); 377 return (*func)(rn, ea);
365 ptr = (unsigned long) &val[0]; 378 ptr = (unsigned long) &data.ul;
366 if (sizeof(unsigned long) == 8 || nb == 4) { 379 if (sizeof(unsigned long) == 8 || nb == 4) {
367 err = read_mem_unaligned(&val[0], ea, nb, regs); 380 err = read_mem_unaligned(&data.ul[0], ea, nb, regs);
368 ptr += sizeof(unsigned long) - nb; 381 if (nb == 4)
382 ptr = (unsigned long)&(data.single.word);
369 } else { 383 } else {
370 /* reading a double on 32-bit */ 384 /* reading a double on 32-bit */
371 err = read_mem_unaligned(&val[0], ea, 4, regs); 385 err = read_mem_unaligned(&data.ul[0], ea, 4, regs);
372 if (!err) 386 if (!err)
373 err = read_mem_unaligned(&val[1], ea + 4, 4, regs); 387 err = read_mem_unaligned(&data.ul[1], ea + 4, 4, regs);
374 } 388 }
375 if (err) 389 if (err)
376 return err; 390 return err;
@@ -382,28 +396,42 @@ static int __kprobes do_fp_store(int rn, int (*func)(int, unsigned long),
382 struct pt_regs *regs) 396 struct pt_regs *regs)
383{ 397{
384 int err; 398 int err;
385 unsigned long val[sizeof(double) / sizeof(long)]; 399 union {
400 double dbl;
401 unsigned long ul[2];
402 struct {
403#ifdef __BIG_ENDIAN__
404 unsigned _pad_;
405 unsigned word;
406#endif
407#ifdef __LITTLE_ENDIAN__
408 unsigned word;
409 unsigned _pad_;
410#endif
411 } single;
412 } data;
386 unsigned long ptr; 413 unsigned long ptr;
387 414
388 if (!address_ok(regs, ea, nb)) 415 if (!address_ok(regs, ea, nb))
389 return -EFAULT; 416 return -EFAULT;
390 if ((ea & 3) == 0) 417 if ((ea & 3) == 0)
391 return (*func)(rn, ea); 418 return (*func)(rn, ea);
392 ptr = (unsigned long) &val[0]; 419 ptr = (unsigned long) &data.ul[0];
393 if (sizeof(unsigned long) == 8 || nb == 4) { 420 if (sizeof(unsigned long) == 8 || nb == 4) {
394 ptr += sizeof(unsigned long) - nb; 421 if (nb == 4)
422 ptr = (unsigned long)&(data.single.word);
395 err = (*func)(rn, ptr); 423 err = (*func)(rn, ptr);
396 if (err) 424 if (err)
397 return err; 425 return err;
398 err = write_mem_unaligned(val[0], ea, nb, regs); 426 err = write_mem_unaligned(data.ul[0], ea, nb, regs);
399 } else { 427 } else {
400 /* writing a double on 32-bit */ 428 /* writing a double on 32-bit */
401 err = (*func)(rn, ptr); 429 err = (*func)(rn, ptr);
402 if (err) 430 if (err)
403 return err; 431 return err;
404 err = write_mem_unaligned(val[0], ea, 4, regs); 432 err = write_mem_unaligned(data.ul[0], ea, 4, regs);
405 if (!err) 433 if (!err)
406 err = write_mem_unaligned(val[1], ea + 4, 4, regs); 434 err = write_mem_unaligned(data.ul[1], ea + 4, 4, regs);
407 } 435 }
408 return err; 436 return err;
409} 437}