diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2011-04-07 17:56:04 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-04-27 00:18:46 -0400 |
commit | b91e136cdf88e19e998dbf4631ead266de4b80b5 (patch) | |
tree | 6f53decf9d389438a740f77f7e907f5abdf5581a /arch/powerpc/lib | |
parent | 9f0b079320ad1cc71ad7ea4e0ed0b64cd72bbd6d (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.c | 61 |
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 | */ | ||
50 | static 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 | */ |
50 | static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs) | 62 | static 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: |