aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2011-04-07 17:56:04 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-04-27 00:18:46 -0400
commitb91e136cdf88e19e998dbf4631ead266de4b80b5 (patch)
tree6f53decf9d389438a740f77f7e907f5abdf5581a /arch/powerpc/lib
parent9f0b079320ad1cc71ad7ea4e0ed0b64cd72bbd6d (diff)
powerpc: Use MSR_64BIT in sstep.c, fix kprobes on BOOK3E
We check MSR_SF a lot in sstep.c, to decide if we need to emulate the truncation of values when running in 32-bit mode. Factor out that code into a helper, and convert it and the other uses to use MSR_64BIT. This fixes a bug on BOOK3E where kprobes would end up returning to a 32-bit address, because regs->nip was truncated, because (msr & MSR_SF) was false. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/lib')
-rw-r--r--arch/powerpc/lib/sstep.c61
1 files changed, 27 insertions, 34 deletions
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index ae5189ab0049..0e5e540c7778 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -45,6 +45,18 @@ extern int do_stxvd2x(int rn, unsigned long ea);
45#endif 45#endif
46 46
47/* 47/*
48 * Emulate the truncation of 64 bit values in 32-bit mode.
49 */
50static unsigned long truncate_if_32bit(unsigned long msr, unsigned long val)
51{
52#ifdef __powerpc64__
53 if ((msr & MSR_64BIT) == 0)
54 val &= 0xffffffffUL;
55#endif
56 return val;
57}
58
59/*
48 * Determine whether a conditional branch instruction would branch. 60 * Determine whether a conditional branch instruction would branch.
49 */ 61 */
50static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs) 62static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs)
@@ -90,11 +102,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs
90 if (instr & 0x04000000) /* update forms */ 102 if (instr & 0x04000000) /* update forms */
91 regs->gpr[ra] = ea; 103 regs->gpr[ra] = ea;
92 } 104 }
93#ifdef __powerpc64__ 105
94 if (!(regs->msr & MSR_SF)) 106 return truncate_if_32bit(regs->msr, ea);
95 ea &= 0xffffffffUL;
96#endif
97 return ea;
98} 107}
99 108
100#ifdef __powerpc64__ 109#ifdef __powerpc64__
@@ -113,9 +122,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
113 if ((instr & 3) == 1) /* update forms */ 122 if ((instr & 3) == 1) /* update forms */
114 regs->gpr[ra] = ea; 123 regs->gpr[ra] = ea;
115 } 124 }
116 if (!(regs->msr & MSR_SF)) 125
117 ea &= 0xffffffffUL; 126 return truncate_if_32bit(regs->msr, ea);
118 return ea;
119} 127}
120#endif /* __powerpc64 */ 128#endif /* __powerpc64 */
121 129
@@ -136,11 +144,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs
136 if (do_update) /* update forms */ 144 if (do_update) /* update forms */
137 regs->gpr[ra] = ea; 145 regs->gpr[ra] = ea;
138 } 146 }
139#ifdef __powerpc64__ 147
140 if (!(regs->msr & MSR_SF)) 148 return truncate_if_32bit(regs->msr, ea);
141 ea &= 0xffffffffUL;
142#endif
143 return ea;
144} 149}
145 150
146/* 151/*
@@ -466,7 +471,7 @@ static void __kprobes set_cr0(struct pt_regs *regs, int rd)
466 471
467 regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); 472 regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);
468#ifdef __powerpc64__ 473#ifdef __powerpc64__
469 if (!(regs->msr & MSR_SF)) 474 if (!(regs->msr & MSR_64BIT))
470 val = (int) val; 475 val = (int) val;
471#endif 476#endif
472 if (val < 0) 477 if (val < 0)
@@ -487,7 +492,7 @@ static void __kprobes add_with_carry(struct pt_regs *regs, int rd,
487 ++val; 492 ++val;
488 regs->gpr[rd] = val; 493 regs->gpr[rd] = val;
489#ifdef __powerpc64__ 494#ifdef __powerpc64__
490 if (!(regs->msr & MSR_SF)) { 495 if (!(regs->msr & MSR_64BIT)) {
491 val = (unsigned int) val; 496 val = (unsigned int) val;
492 val1 = (unsigned int) val1; 497 val1 = (unsigned int) val1;
493 } 498 }
@@ -570,8 +575,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
570 if ((instr & 2) == 0) 575 if ((instr & 2) == 0)
571 imm += regs->nip; 576 imm += regs->nip;
572 regs->nip += 4; 577 regs->nip += 4;
573 if ((regs->msr & MSR_SF) == 0) 578 regs->nip = truncate_if_32bit(regs->msr, regs->nip);
574 regs->nip &= 0xffffffffUL;
575 if (instr & 1) 579 if (instr & 1)
576 regs->link = regs->nip; 580 regs->link = regs->nip;
577 if (branch_taken(instr, regs)) 581 if (branch_taken(instr, regs))
@@ -604,13 +608,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
604 imm -= 0x04000000; 608 imm -= 0x04000000;
605 if ((instr & 2) == 0) 609 if ((instr & 2) == 0)
606 imm += regs->nip; 610 imm += regs->nip;
607 if (instr & 1) { 611 if (instr & 1)
608 regs->link = regs->nip + 4; 612 regs->link = truncate_if_32bit(regs->msr, regs->nip + 4);
609 if ((regs->msr & MSR_SF) == 0) 613 imm = truncate_if_32bit(regs->msr, imm);
610 regs->link &= 0xffffffffUL;
611 }
612 if ((regs->msr & MSR_SF) == 0)
613 imm &= 0xffffffffUL;
614 regs->nip = imm; 614 regs->nip = imm;
615 return 1; 615 return 1;
616 case 19: 616 case 19:
@@ -618,11 +618,8 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
618 case 16: /* bclr */ 618 case 16: /* bclr */
619 case 528: /* bcctr */ 619 case 528: /* bcctr */
620 imm = (instr & 0x400)? regs->ctr: regs->link; 620 imm = (instr & 0x400)? regs->ctr: regs->link;
621 regs->nip += 4; 621 regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
622 if ((regs->msr & MSR_SF) == 0) { 622 imm = truncate_if_32bit(regs->msr, imm);
623 regs->nip &= 0xffffffffUL;
624 imm &= 0xffffffffUL;
625 }
626 if (instr & 1) 623 if (instr & 1)
627 regs->link = regs->nip; 624 regs->link = regs->nip;
628 if (branch_taken(instr, regs)) 625 if (branch_taken(instr, regs))
@@ -1616,11 +1613,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
1616 return 0; /* invoke DSI if -EFAULT? */ 1613 return 0; /* invoke DSI if -EFAULT? */
1617 } 1614 }
1618 instr_done: 1615 instr_done:
1619 regs->nip += 4; 1616 regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
1620#ifdef __powerpc64__
1621 if ((regs->msr & MSR_SF) == 0)
1622 regs->nip &= 0xffffffffUL;
1623#endif
1624 return 1; 1617 return 1;
1625 1618
1626 logical_done: 1619 logical_done: