Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+27 −34
Original line number Original line Diff line number Diff line
@@ -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
		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
		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
		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)


	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,
		++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)
		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)
			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)
		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)
		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: