diff options
Diffstat (limited to 'arch/powerpc/lib/sstep.c')
-rw-r--r-- | arch/powerpc/lib/sstep.c | 70 |
1 files changed, 36 insertions, 34 deletions
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index e0a9858d537e..9a52349874ee 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/kprobes.h> | 12 | #include <linux/kprobes.h> |
13 | #include <linux/ptrace.h> | 13 | #include <linux/ptrace.h> |
14 | #include <linux/prefetch.h> | ||
14 | #include <asm/sstep.h> | 15 | #include <asm/sstep.h> |
15 | #include <asm/processor.h> | 16 | #include <asm/processor.h> |
16 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
@@ -30,6 +31,7 @@ extern char system_call_common[]; | |||
30 | #define XER_OV 0x40000000U | 31 | #define XER_OV 0x40000000U |
31 | #define XER_CA 0x20000000U | 32 | #define XER_CA 0x20000000U |
32 | 33 | ||
34 | #ifdef CONFIG_PPC_FPU | ||
33 | /* | 35 | /* |
34 | * Functions in ldstfp.S | 36 | * Functions in ldstfp.S |
35 | */ | 37 | */ |
@@ -41,6 +43,19 @@ extern int do_lvx(int rn, unsigned long ea); | |||
41 | extern int do_stvx(int rn, unsigned long ea); | 43 | extern int do_stvx(int rn, unsigned long ea); |
42 | extern int do_lxvd2x(int rn, unsigned long ea); | 44 | extern int do_lxvd2x(int rn, unsigned long ea); |
43 | extern int do_stxvd2x(int rn, unsigned long ea); | 45 | extern int do_stxvd2x(int rn, unsigned long ea); |
46 | #endif | ||
47 | |||
48 | /* | ||
49 | * Emulate the truncation of 64 bit values in 32-bit mode. | ||
50 | */ | ||
51 | static unsigned long truncate_if_32bit(unsigned long msr, unsigned long val) | ||
52 | { | ||
53 | #ifdef __powerpc64__ | ||
54 | if ((msr & MSR_64BIT) == 0) | ||
55 | val &= 0xffffffffUL; | ||
56 | #endif | ||
57 | return val; | ||
58 | } | ||
44 | 59 | ||
45 | /* | 60 | /* |
46 | * Determine whether a conditional branch instruction would branch. | 61 | * Determine whether a conditional branch instruction would branch. |
@@ -88,11 +103,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs | |||
88 | if (instr & 0x04000000) /* update forms */ | 103 | if (instr & 0x04000000) /* update forms */ |
89 | regs->gpr[ra] = ea; | 104 | regs->gpr[ra] = ea; |
90 | } | 105 | } |
91 | #ifdef __powerpc64__ | 106 | |
92 | if (!(regs->msr & MSR_SF)) | 107 | return truncate_if_32bit(regs->msr, ea); |
93 | ea &= 0xffffffffUL; | ||
94 | #endif | ||
95 | return ea; | ||
96 | } | 108 | } |
97 | 109 | ||
98 | #ifdef __powerpc64__ | 110 | #ifdef __powerpc64__ |
@@ -111,9 +123,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg | |||
111 | if ((instr & 3) == 1) /* update forms */ | 123 | if ((instr & 3) == 1) /* update forms */ |
112 | regs->gpr[ra] = ea; | 124 | regs->gpr[ra] = ea; |
113 | } | 125 | } |
114 | if (!(regs->msr & MSR_SF)) | 126 | |
115 | ea &= 0xffffffffUL; | 127 | return truncate_if_32bit(regs->msr, ea); |
116 | return ea; | ||
117 | } | 128 | } |
118 | #endif /* __powerpc64 */ | 129 | #endif /* __powerpc64 */ |
119 | 130 | ||
@@ -134,11 +145,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs | |||
134 | if (do_update) /* update forms */ | 145 | if (do_update) /* update forms */ |
135 | regs->gpr[ra] = ea; | 146 | regs->gpr[ra] = ea; |
136 | } | 147 | } |
137 | #ifdef __powerpc64__ | 148 | |
138 | if (!(regs->msr & MSR_SF)) | 149 | return truncate_if_32bit(regs->msr, ea); |
139 | ea &= 0xffffffffUL; | ||
140 | #endif | ||
141 | return ea; | ||
142 | } | 150 | } |
143 | 151 | ||
144 | /* | 152 | /* |
@@ -290,6 +298,7 @@ static int __kprobes write_mem(unsigned long val, unsigned long ea, int nb, | |||
290 | return write_mem_unaligned(val, ea, nb, regs); | 298 | return write_mem_unaligned(val, ea, nb, regs); |
291 | } | 299 | } |
292 | 300 | ||
301 | #ifdef CONFIG_PPC_FPU | ||
293 | /* | 302 | /* |
294 | * Check the address and alignment, and call func to do the actual | 303 | * Check the address and alignment, and call func to do the actual |
295 | * load or store. | 304 | * load or store. |
@@ -351,6 +360,7 @@ static int __kprobes do_fp_store(int rn, int (*func)(int, unsigned long), | |||
351 | } | 360 | } |
352 | return err; | 361 | return err; |
353 | } | 362 | } |
363 | #endif | ||
354 | 364 | ||
355 | #ifdef CONFIG_ALTIVEC | 365 | #ifdef CONFIG_ALTIVEC |
356 | /* For Altivec/VMX, no need to worry about alignment */ | 366 | /* For Altivec/VMX, no need to worry about alignment */ |
@@ -462,7 +472,7 @@ static void __kprobes set_cr0(struct pt_regs *regs, int rd) | |||
462 | 472 | ||
463 | regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); | 473 | regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); |
464 | #ifdef __powerpc64__ | 474 | #ifdef __powerpc64__ |
465 | if (!(regs->msr & MSR_SF)) | 475 | if (!(regs->msr & MSR_64BIT)) |
466 | val = (int) val; | 476 | val = (int) val; |
467 | #endif | 477 | #endif |
468 | if (val < 0) | 478 | if (val < 0) |
@@ -483,7 +493,7 @@ static void __kprobes add_with_carry(struct pt_regs *regs, int rd, | |||
483 | ++val; | 493 | ++val; |
484 | regs->gpr[rd] = val; | 494 | regs->gpr[rd] = val; |
485 | #ifdef __powerpc64__ | 495 | #ifdef __powerpc64__ |
486 | if (!(regs->msr & MSR_SF)) { | 496 | if (!(regs->msr & MSR_64BIT)) { |
487 | val = (unsigned int) val; | 497 | val = (unsigned int) val; |
488 | val1 = (unsigned int) val1; | 498 | val1 = (unsigned int) val1; |
489 | } | 499 | } |
@@ -566,8 +576,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
566 | if ((instr & 2) == 0) | 576 | if ((instr & 2) == 0) |
567 | imm += regs->nip; | 577 | imm += regs->nip; |
568 | regs->nip += 4; | 578 | regs->nip += 4; |
569 | if ((regs->msr & MSR_SF) == 0) | 579 | regs->nip = truncate_if_32bit(regs->msr, regs->nip); |
570 | regs->nip &= 0xffffffffUL; | ||
571 | if (instr & 1) | 580 | if (instr & 1) |
572 | regs->link = regs->nip; | 581 | regs->link = regs->nip; |
573 | if (branch_taken(instr, regs)) | 582 | if (branch_taken(instr, regs)) |
@@ -600,13 +609,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
600 | imm -= 0x04000000; | 609 | imm -= 0x04000000; |
601 | if ((instr & 2) == 0) | 610 | if ((instr & 2) == 0) |
602 | imm += regs->nip; | 611 | imm += regs->nip; |
603 | if (instr & 1) { | 612 | if (instr & 1) |
604 | regs->link = regs->nip + 4; | 613 | regs->link = truncate_if_32bit(regs->msr, regs->nip + 4); |
605 | if ((regs->msr & MSR_SF) == 0) | 614 | imm = truncate_if_32bit(regs->msr, imm); |
606 | regs->link &= 0xffffffffUL; | ||
607 | } | ||
608 | if ((regs->msr & MSR_SF) == 0) | ||
609 | imm &= 0xffffffffUL; | ||
610 | regs->nip = imm; | 615 | regs->nip = imm; |
611 | return 1; | 616 | return 1; |
612 | case 19: | 617 | case 19: |
@@ -614,11 +619,8 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
614 | case 16: /* bclr */ | 619 | case 16: /* bclr */ |
615 | case 528: /* bcctr */ | 620 | case 528: /* bcctr */ |
616 | imm = (instr & 0x400)? regs->ctr: regs->link; | 621 | imm = (instr & 0x400)? regs->ctr: regs->link; |
617 | regs->nip += 4; | 622 | regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4); |
618 | if ((regs->msr & MSR_SF) == 0) { | 623 | imm = truncate_if_32bit(regs->msr, imm); |
619 | regs->nip &= 0xffffffffUL; | ||
620 | imm &= 0xffffffffUL; | ||
621 | } | ||
622 | if (instr & 1) | 624 | if (instr & 1) |
623 | regs->link = regs->nip; | 625 | regs->link = regs->nip; |
624 | if (branch_taken(instr, regs)) | 626 | if (branch_taken(instr, regs)) |
@@ -1393,6 +1395,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
1393 | regs->gpr[rd] = byterev_4(val); | 1395 | regs->gpr[rd] = byterev_4(val); |
1394 | goto ldst_done; | 1396 | goto ldst_done; |
1395 | 1397 | ||
1398 | #ifdef CONFIG_PPC_CPU | ||
1396 | case 535: /* lfsx */ | 1399 | case 535: /* lfsx */ |
1397 | case 567: /* lfsux */ | 1400 | case 567: /* lfsux */ |
1398 | if (!(regs->msr & MSR_FP)) | 1401 | if (!(regs->msr & MSR_FP)) |
@@ -1424,6 +1427,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
1424 | ea = xform_ea(instr, regs, u); | 1427 | ea = xform_ea(instr, regs, u); |
1425 | err = do_fp_store(rd, do_stfd, ea, 8, regs); | 1428 | err = do_fp_store(rd, do_stfd, ea, 8, regs); |
1426 | goto ldst_done; | 1429 | goto ldst_done; |
1430 | #endif | ||
1427 | 1431 | ||
1428 | #ifdef __powerpc64__ | 1432 | #ifdef __powerpc64__ |
1429 | case 660: /* stdbrx */ | 1433 | case 660: /* stdbrx */ |
@@ -1534,6 +1538,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
1534 | } while (++rd < 32); | 1538 | } while (++rd < 32); |
1535 | goto instr_done; | 1539 | goto instr_done; |
1536 | 1540 | ||
1541 | #ifdef CONFIG_PPC_FPU | ||
1537 | case 48: /* lfs */ | 1542 | case 48: /* lfs */ |
1538 | case 49: /* lfsu */ | 1543 | case 49: /* lfsu */ |
1539 | if (!(regs->msr & MSR_FP)) | 1544 | if (!(regs->msr & MSR_FP)) |
@@ -1565,6 +1570,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
1565 | ea = dform_ea(instr, regs); | 1570 | ea = dform_ea(instr, regs); |
1566 | err = do_fp_store(rd, do_stfd, ea, 8, regs); | 1571 | err = do_fp_store(rd, do_stfd, ea, 8, regs); |
1567 | goto ldst_done; | 1572 | goto ldst_done; |
1573 | #endif | ||
1568 | 1574 | ||
1569 | #ifdef __powerpc64__ | 1575 | #ifdef __powerpc64__ |
1570 | case 58: /* ld[u], lwa */ | 1576 | case 58: /* ld[u], lwa */ |
@@ -1608,11 +1614,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) | |||
1608 | return 0; /* invoke DSI if -EFAULT? */ | 1614 | return 0; /* invoke DSI if -EFAULT? */ |
1609 | } | 1615 | } |
1610 | instr_done: | 1616 | instr_done: |
1611 | regs->nip += 4; | 1617 | regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4); |
1612 | #ifdef __powerpc64__ | ||
1613 | if ((regs->msr & MSR_SF) == 0) | ||
1614 | regs->nip &= 0xffffffffUL; | ||
1615 | #endif | ||
1616 | return 1; | 1618 | return 1; |
1617 | 1619 | ||
1618 | logical_done: | 1620 | logical_done: |