Commit b91e136c authored by Michael Ellerman's avatar Michael Ellerman Committed by Benjamin Herrenschmidt

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: default avatarMichael Ellerman <michael@ellerman.id.au>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 9f0b0793
...@@ -44,6 +44,18 @@ extern int do_lxvd2x(int rn, unsigned long ea); ...@@ -44,6 +44,18 @@ extern int do_lxvd2x(int rn, unsigned long ea);
extern int do_stxvd2x(int rn, unsigned long ea); extern int do_stxvd2x(int rn, unsigned long ea);
#endif #endif
/*
* Emulate the truncation of 64 bit values in 32-bit mode.
*/
static unsigned long truncate_if_32bit(unsigned long msr, unsigned long val)
{
#ifdef __powerpc64__
if ((msr & MSR_64BIT) == 0)
val &= 0xffffffffUL;
#endif
return val;
}
/* /*
* Determine whether a conditional branch instruction would branch. * Determine whether a conditional branch instruction would branch.
*/ */
...@@ -90,11 +102,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs ...@@ -90,11 +102,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs
if (instr & 0x04000000) /* update forms */ if (instr & 0x04000000) /* update forms */
regs->gpr[ra] = ea; regs->gpr[ra] = ea;
} }
#ifdef __powerpc64__
if (!(regs->msr & MSR_SF)) return truncate_if_32bit(regs->msr, ea);
ea &= 0xffffffffUL;
#endif
return ea;
} }
#ifdef __powerpc64__ #ifdef __powerpc64__
...@@ -113,9 +122,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg ...@@ -113,9 +122,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
if ((instr & 3) == 1) /* update forms */ if ((instr & 3) == 1) /* update forms */
regs->gpr[ra] = ea; regs->gpr[ra] = ea;
} }
if (!(regs->msr & MSR_SF))
ea &= 0xffffffffUL; return truncate_if_32bit(regs->msr, ea);
return ea;
} }
#endif /* __powerpc64 */ #endif /* __powerpc64 */
...@@ -136,11 +144,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs ...@@ -136,11 +144,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs
if (do_update) /* update forms */ if (do_update) /* update forms */
regs->gpr[ra] = ea; regs->gpr[ra] = ea;
} }
#ifdef __powerpc64__
if (!(regs->msr & MSR_SF)) return truncate_if_32bit(regs->msr, ea);
ea &= 0xffffffffUL;
#endif
return ea;
} }
/* /*
...@@ -466,7 +471,7 @@ static void __kprobes set_cr0(struct pt_regs *regs, int rd) ...@@ -466,7 +471,7 @@ static void __kprobes set_cr0(struct pt_regs *regs, int rd)
regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);
#ifdef __powerpc64__ #ifdef __powerpc64__
if (!(regs->msr & MSR_SF)) if (!(regs->msr & MSR_64BIT))
val = (int) val; val = (int) val;
#endif #endif
if (val < 0) if (val < 0)
...@@ -487,7 +492,7 @@ static void __kprobes add_with_carry(struct pt_regs *regs, int rd, ...@@ -487,7 +492,7 @@ static void __kprobes add_with_carry(struct pt_regs *regs, int rd,
++val; ++val;
regs->gpr[rd] = val; regs->gpr[rd] = val;
#ifdef __powerpc64__ #ifdef __powerpc64__
if (!(regs->msr & MSR_SF)) { if (!(regs->msr & MSR_64BIT)) {
val = (unsigned int) val; val = (unsigned int) val;
val1 = (unsigned int) val1; val1 = (unsigned int) val1;
} }
...@@ -570,8 +575,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) ...@@ -570,8 +575,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
if ((instr & 2) == 0) if ((instr & 2) == 0)
imm += regs->nip; imm += regs->nip;
regs->nip += 4; regs->nip += 4;
if ((regs->msr & MSR_SF) == 0) regs->nip = truncate_if_32bit(regs->msr, regs->nip);
regs->nip &= 0xffffffffUL;
if (instr & 1) if (instr & 1)
regs->link = regs->nip; regs->link = regs->nip;
if (branch_taken(instr, regs)) if (branch_taken(instr, regs))
...@@ -604,13 +608,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) ...@@ -604,13 +608,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
imm -= 0x04000000; imm -= 0x04000000;
if ((instr & 2) == 0) if ((instr & 2) == 0)
imm += regs->nip; imm += regs->nip;
if (instr & 1) { if (instr & 1)
regs->link = regs->nip + 4; regs->link = truncate_if_32bit(regs->msr, regs->nip + 4);
if ((regs->msr & MSR_SF) == 0) imm = truncate_if_32bit(regs->msr, imm);
regs->link &= 0xffffffffUL;
}
if ((regs->msr & MSR_SF) == 0)
imm &= 0xffffffffUL;
regs->nip = imm; regs->nip = imm;
return 1; return 1;
case 19: case 19:
...@@ -618,11 +618,8 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) ...@@ -618,11 +618,8 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
case 16: /* bclr */ case 16: /* bclr */
case 528: /* bcctr */ case 528: /* bcctr */
imm = (instr & 0x400)? regs->ctr: regs->link; imm = (instr & 0x400)? regs->ctr: regs->link;
regs->nip += 4; regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
if ((regs->msr & MSR_SF) == 0) { imm = truncate_if_32bit(regs->msr, imm);
regs->nip &= 0xffffffffUL;
imm &= 0xffffffffUL;
}
if (instr & 1) if (instr & 1)
regs->link = regs->nip; regs->link = regs->nip;
if (branch_taken(instr, regs)) if (branch_taken(instr, regs))
...@@ -1616,11 +1613,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) ...@@ -1616,11 +1613,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
return 0; /* invoke DSI if -EFAULT? */ return 0; /* invoke DSI if -EFAULT? */
} }
instr_done: instr_done:
regs->nip += 4; regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
#ifdef __powerpc64__
if ((regs->msr & MSR_SF) == 0)
regs->nip &= 0xffffffffUL;
#endif
return 1; return 1;
logical_done: logical_done:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment