/* * Emulate the truncation of 64 bit values in 32-bit mode.
*/ static nokprobe_inline unsignedlong truncate_if_32bit(unsignedlong msr, unsignedlong val)
{ if ((msr & MSR_64BIT) == 0)
val &= 0xffffffffUL; return val;
}
/* * Determine whether a conditional branch instruction would branch.
*/ static nokprobe_inline int branch_taken(unsignedint instr, conststruct pt_regs *regs, struct instruction_op *op)
{ unsignedint bo = (instr >> 21) & 0x1f; unsignedint bi;
if ((bo & 4) == 0) { /* decrement counter */
op->type |= DECCTR; if (((bo >> 1) & 1) ^ (regs->ctr == 1)) return 0;
} if ((bo & 0x10) == 0) { /* check bit from CR */
bi = (instr >> 16) & 0x1f; if (((regs->ccr >> (31 - bi)) & 1) != ((bo >> 3) & 1)) return 0;
} return 1;
}
static nokprobe_inline long address_ok(struct pt_regs *regs, unsignedlong ea, int nb)
{ if (!user_mode(regs)) return 1; if (access_ok((void __user *)ea, nb)) return 1; if (access_ok((void __user *)ea, 1)) /* Access overlaps the end of the user region */
regs->dar = TASK_SIZE_MAX - 1; else
regs->dar = ea; return 0;
}
/* * Calculate effective address for a D-form instruction
*/ static nokprobe_inline unsignedlong dform_ea(unsignedint instr, conststruct pt_regs *regs)
{ int ra; unsignedlong ea;
ra = (instr >> 16) & 0x1f;
ea = (signedshort) instr; /* sign-extend */ if (ra)
ea += regs->gpr[ra];
return ea;
}
#ifdef __powerpc64__ /* * Calculate effective address for a DS-form instruction
*/ static nokprobe_inline unsignedlong dsform_ea(unsignedint instr, conststruct pt_regs *regs)
{ int ra; unsignedlong ea;
ra = (instr >> 16) & 0x1f;
ea = (signedshort) (instr & ~3); /* sign-extend */ if (ra)
ea += regs->gpr[ra];
return ea;
}
/* * Calculate effective address for a DQ-form instruction
*/ static nokprobe_inline unsignedlong dqform_ea(unsignedint instr, conststruct pt_regs *regs)
{ int ra; unsignedlong ea;
ra = (instr >> 16) & 0x1f;
ea = (signedshort) (instr & ~0xf); /* sign-extend */ if (ra)
ea += regs->gpr[ra];
return ea;
} #endif/* __powerpc64 */
/* * Calculate effective address for an X-form instruction
*/ static nokprobe_inline unsignedlong xform_ea(unsignedint instr, conststruct pt_regs *regs)
{ int ra, rb; unsignedlong ea;
ra = (instr >> 16) & 0x1f;
rb = (instr >> 11) & 0x1f;
ea = regs->gpr[rb]; if (ra)
ea += regs->gpr[ra];
/* * sign extend a 34 bit number
*/
dd = (unsignedint)(d >> 2);
ea = (signedint)dd;
ea = (ea << 2) | (d & 0x3);
if (!prefix_r && ra)
ea += regs->gpr[ra]; elseif (!prefix_r && !ra)
; /* Leave ea as is */ elseif (prefix_r)
ea += regs->nip;
/* * (prefix_r && ra) is an invalid form. Should already be * checked for by caller!
*/
return ea;
}
/* * Return the largest power of 2, not greater than sizeof(unsigned long), * such that x is a multiple of it.
*/ static nokprobe_inline unsignedlong max_align(unsignedlong x)
{
x |= sizeof(unsignedlong); return x & -x; /* isolates rightmost bit */
}
/* * Copy from userspace to a buffer, using the largest possible * aligned accesses, up to sizeof(long).
*/ static __always_inline int __copy_mem_in(u8 *dest, unsignedlong ea, int nb, struct pt_regs *regs)
{ int c;
for (; nb > 0; nb -= c) {
c = max_align(ea); if (c > nb)
c = max_align(nb); switch (c) { case 1:
unsafe_get_user(*dest, (u8 __user *)ea, Efault); break; case 2:
unsafe_get_user(*(u16 *)dest, (u16 __user *)ea, Efault); break; case 4:
unsafe_get_user(*(u32 *)dest, (u32 __user *)ea, Efault); break; #ifdef __powerpc64__ case 8:
unsafe_get_user(*(u64 *)dest, (u64 __user *)ea, Efault); break; #endif
}
dest += c;
ea += c;
} return 0;
Efault:
regs->dar = ea; return -EFAULT;
}
static nokprobe_inline int copy_mem_in(u8 *dest, unsignedlong ea, int nb, struct pt_regs *regs)
{ int err;
if (is_kernel_addr(ea)) return __copy_mem_in(dest, ea, nb, regs);
static nokprobe_inline int read_mem_unaligned(unsignedlong *dest, unsignedlong ea, int nb, struct pt_regs *regs)
{ union { unsignedlong ul;
u8 b[sizeof(unsignedlong)];
} u; int i; int err;
u.ul = 0;
i = IS_BE ? sizeof(unsignedlong) - nb : 0;
err = copy_mem_in(&u.b[i], ea, nb, regs); if (!err)
*dest = u.ul; return err;
}
/* * Read memory at address ea for nb bytes, return 0 for success * or -EFAULT if an error occurred. N.B. nb must be 1, 2, 4 or 8. * If nb < sizeof(long), the result is right-justified on BE systems.
*/ staticint read_mem(unsignedlong *dest, unsignedlong ea, int nb, struct pt_regs *regs)
{ if (!address_ok(regs, ea, nb)) return -EFAULT; if ((ea & (nb - 1)) == 0) return read_mem_aligned(dest, ea, nb, regs); return read_mem_unaligned(dest, ea, nb, regs);
}
NOKPROBE_SYMBOL(read_mem);
static __always_inline int
__write_mem_aligned(unsignedlong val, unsignedlong ea, int nb, struct pt_regs *regs)
{ switch (nb) { case 1:
unsafe_put_user(val, (unsignedchar __user *)ea, Efault); break; case 2:
unsafe_put_user(val, (unsignedshort __user *)ea, Efault); break; case 4:
unsafe_put_user(val, (unsignedint __user *)ea, Efault); break; #ifdef __powerpc64__ case 8:
unsafe_put_user(val, (unsignedlong __user *)ea, Efault); break; #endif
} return 0;
Efault:
regs->dar = ea; return -EFAULT;
}
static nokprobe_inline int
write_mem_aligned(unsignedlong val, unsignedlong ea, int nb, struct pt_regs *regs)
{ int err;
if (is_kernel_addr(ea)) return __write_mem_aligned(val, ea, nb, regs);
/* * Copy from a buffer to userspace, using the largest possible * aligned accesses, up to sizeof(long).
*/ static __always_inline int __copy_mem_out(u8 *dest, unsignedlong ea, int nb, struct pt_regs *regs)
{ int c;
for (; nb > 0; nb -= c) {
c = max_align(ea); if (c > nb)
c = max_align(nb); switch (c) { case 1:
unsafe_put_user(*dest, (u8 __user *)ea, Efault); break; case 2:
unsafe_put_user(*(u16 *)dest, (u16 __user *)ea, Efault); break; case 4:
unsafe_put_user(*(u32 *)dest, (u32 __user *)ea, Efault); break; #ifdef __powerpc64__ case 8:
unsafe_put_user(*(u64 *)dest, (u64 __user *)ea, Efault); break; #endif
}
dest += c;
ea += c;
} return 0;
Efault:
regs->dar = ea; return -EFAULT;
}
static nokprobe_inline int copy_mem_out(u8 *dest, unsignedlong ea, int nb, struct pt_regs *regs)
{ int err;
if (is_kernel_addr(ea)) return __copy_mem_out(dest, ea, nb, regs);
static nokprobe_inline int write_mem_unaligned(unsignedlong val, unsignedlong ea, int nb, struct pt_regs *regs)
{ union { unsignedlong ul;
u8 b[sizeof(unsignedlong)];
} u; int i;
u.ul = val;
i = IS_BE ? sizeof(unsignedlong) - nb : 0; return copy_mem_out(&u.b[i], ea, nb, regs);
}
/* * Write memory at address ea for nb bytes, return 0 for success * or -EFAULT if an error occurred. N.B. nb must be 1, 2, 4 or 8.
*/ staticint write_mem(unsignedlong val, unsignedlong ea, int nb, struct pt_regs *regs)
{ if (!address_ok(regs, ea, nb)) return -EFAULT; if ((ea & (nb - 1)) == 0) return write_mem_aligned(val, ea, nb, regs); return write_mem_unaligned(val, ea, nb, regs);
}
NOKPROBE_SYMBOL(write_mem);
#ifdef CONFIG_PPC_FPU /* * These access either the real FP register or the image in the * thread_struct, depending on regs->msr & MSR_FP.
*/ staticint do_fp_load(struct instruction_op *op, unsignedlong ea, struct pt_regs *regs, bool cross_endian)
{ int err, rn, nb; union { int i; unsignedint u; float f; double d[2]; unsignedlong l[2];
u8 b[2 * sizeof(double)];
} u;
nb = GETSIZE(op->type); if (nb > sizeof(u)) return -EINVAL; if (!address_ok(regs, ea, nb)) return -EFAULT;
rn = op->reg;
err = copy_mem_in(u.b, ea, nb, regs); if (err) return err; if (unlikely(cross_endian)) {
do_byte_reverse(u.b, min(nb, 8)); if (nb == 16)
do_byte_reverse(&u.b[8], 8);
}
preempt_disable(); if (nb == 4) { if (op->type & FPCONV)
conv_sp_to_dp(&u.f, &u.d[0]); elseif (op->type & SIGNEXT)
u.l[0] = u.i; else
u.l[0] = u.u;
} if (regs->msr & MSR_FP)
put_fpr(rn, &u.d[0]); else
current->thread.TS_FPR(rn) = u.l[0]; if (nb == 16) { /* lfdp */
rn |= 1; if (regs->msr & MSR_FP)
put_fpr(rn, &u.d[1]); else
current->thread.TS_FPR(rn) = u.l[1];
}
preempt_enable(); return 0;
}
NOKPROBE_SYMBOL(do_fp_load);
nb = GETSIZE(op->type); if (nb > sizeof(u)) return -EINVAL; if (!address_ok(regs, ea, nb)) return -EFAULT;
rn = op->reg;
preempt_disable(); if (regs->msr & MSR_FP)
get_fpr(rn, &u.d[0]); else
u.l[0] = current->thread.TS_FPR(rn); if (nb == 4) { if (op->type & FPCONV)
conv_dp_to_sp(&u.d[0], &u.f); else
u.u = u.l[0];
} if (nb == 16) {
rn |= 1; if (regs->msr & MSR_FP)
get_fpr(rn, &u.d[1]); else
u.l[1] = current->thread.TS_FPR(rn);
}
preempt_enable(); if (unlikely(cross_endian)) {
do_byte_reverse(u.b, min(nb, 8)); if (nb == 16)
do_byte_reverse(&u.b[8], 8);
} return copy_mem_out(u.b, ea, nb, regs);
}
NOKPROBE_SYMBOL(do_fp_store); #endif
#ifdef CONFIG_ALTIVEC /* For Altivec/VMX, no need to worry about alignment */ static nokprobe_inline int do_vec_load(int rn, unsignedlong ea, int size, struct pt_regs *regs, bool cross_endian)
{ int err; union {
__vector128 v;
u8 b[sizeof(__vector128)];
} u = {};
if (size > sizeof(u)) return -EINVAL;
if (!address_ok(regs, ea & ~0xfUL, 16)) return -EFAULT; /* align to multiple of size */
ea &= ~(size - 1);
err = copy_mem_in(&u.b[ea & 0xf], ea, size, regs); if (err) return err; if (unlikely(cross_endian))
do_byte_reverse(&u.b[ea & 0xf], min_t(size_t, size, sizeof(u)));
preempt_disable(); if (regs->msr & MSR_VEC)
put_vr(rn, &u.v); else
current->thread.vr_state.vr[rn] = u.v;
preempt_enable(); return 0;
}
static nokprobe_inline int do_vec_store(int rn, unsignedlong ea, int size, struct pt_regs *regs, bool cross_endian)
{ union {
__vector128 v;
u8 b[sizeof(__vector128)];
} u;
if (size > sizeof(u)) return -EINVAL;
if (!address_ok(regs, ea & ~0xfUL, 16)) return -EFAULT; /* align to multiple of size */
ea &= ~(size - 1);
perm = 0; for (i = 0; i < 8; i++) {
idx = (v1 >> (i * 8)) & 0xff; if (idx < 64) if (v2 & PPC_BIT(idx))
perm |= 1 << i;
}
op->val = perm;
} #endif/* CONFIG_PPC64 */ /* * The size parameter adjusts the equivalent prty instruction. * prtyw = 32, prtyd = 64
*/ static nokprobe_inline void do_prty(conststruct pt_regs *regs, struct instruction_op *op, unsignedlong v, int size)
{ unsignedlonglong res = v ^ (v >> 8);
res ^= res >> 16; if (size == 32) { /* prtyw */
op->val = res & 0x0000000100000001ULL; return;
}
res ^= res >> 32;
op->val = res & 1; /*prtyd */
}
static nokprobe_inline int trap_compare(long v1, long v2)
{ int ret = 0;
if (v1 < v2)
ret |= 0x10; elseif (v1 > v2)
ret |= 0x08; else
ret |= 0x04; if ((unsignedlong)v1 < (unsignedlong)v2)
ret |= 0x02; elseif ((unsignedlong)v1 > (unsignedlong)v2)
ret |= 0x01; return ret;
}
/* * Decode an instruction, and return information about it in *op * without changing *regs. * Integer arithmetic and logical instructions, branches, and barrier * instructions can be emulated just using the information in *op. * * Return value is 1 if the instruction can be emulated just by * updating *regs with the information in *op, -1 if we need the * GPRs but *regs doesn't contain the full register set, or 0 * otherwise.
*/ int analyse_instr(struct instruction_op *op, conststruct pt_regs *regs,
ppc_inst_t instr)
{ #ifdef CONFIG_PPC64 unsignedint suffixopcode, prefixtype, prefix_r; #endif unsignedint opcode, ra, rb, rc, rd, spr, u; unsignedlongint imm; unsignedlongint val, val2; unsignedint mb, me, sh; unsignedint word, suffix; long ival;
word = ppc_inst_val(instr);
suffix = ppc_inst_suffix(instr);
#ifdef __powerpc64__ case 4: /* * There are very many instructions with this primary opcode * introduced in the ISA as early as v2.03. However, the ones * we currently emulate were all introduced with ISA 3.0
*/ if (!cpu_has_feature(CPU_FTR_ARCH_300)) goto unknown_opcode;
switch ((word >> 1) & 0x3ff) { case 4: /* tw */ if (rd == 0x1f ||
(rd & trap_compare((int)regs->gpr[ra],
(int)regs->gpr[rb]))) goto trap; return 1; #ifdef __powerpc64__ case 68: /* td */ if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb])) goto trap; return 1; #endif case 83: /* mfmsr */ if (user_mode(regs)) goto priv;
op->type = MFMSR;
op->reg = rd; return 0; case 146: /* mtmsr */ if (user_mode(regs)) goto priv;
op->type = MTMSR;
op->reg = rd;
op->val = 0xffffffff & ~(MSR_ME | MSR_LE); return 0; #ifdef CONFIG_PPC64 case 178: /* mtmsrd */ if (user_mode(regs)) goto priv;
op->type = MTMSR;
op->reg = rd; /* only MSR_EE and MSR_RI get changed if bit 15 set */ /* mtmsrd doesn't change MSR_HV, MSR_ME or MSR_LE */
imm = (word & 0x10000)? 0x8002: 0xefffffffffffeffeUL;
op->val = imm; return 0; #endif
case 19: /* mfcr */
imm = 0xffffffffUL; if ((word >> 20) & 1) {
imm = 0xf0000000UL; for (sh = 0; sh < 8; ++sh) { if (word & (0x80000 >> sh)) break;
imm >>= 4;
}
}
op->val = regs->ccr & imm; goto compute_done;
case 128: /* setb */ if (!cpu_has_feature(CPU_FTR_ARCH_300)) goto unknown_opcode; /* * 'ra' encodes the CR field number (bfa) in the top 3 bits. * Since each CR field is 4 bits, * we can simply mask off the bottom two bits (bfa * 4) * to yield the first bit in the CR field.
*/
ra = ra & ~0x3; /* 'val' stores bits of the CR field (bfa) */
val = regs->ccr >> (CR0_SHIFT - ra); /* checks if the LT bit of CR field (bfa) is set */ if (val & 8)
op->val = -1; /* checks if the GT bit of CR field (bfa) is set */ elseif (val & 4)
op->val = 1; else
op->val = 0; goto compute_done;
case 144: /* mtcrf */
op->type = COMPUTE + SETCC;
imm = 0xf0000000UL;
val = regs->gpr[rd];
op->ccval = regs->ccr; for (sh = 0; sh < 8; ++sh) { if (word & (0x80000 >> sh))
op->ccval = (op->ccval & ~imm) |
(val & imm);
imm >>= 4;
} return 1;
case 276: /* lqarx */ if (!((rd & 1) || rd == ra || rd == rb))
op->type = MKOP(LARX, 0, 16); break;
case 182: /* stqcx. */ if (!(rd & 1))
op->type = MKOP(STCX, 0, 16); break; #endif
case 23: /* lwzx */ case 55: /* lwzux */
op->type = MKOP(LOAD, u, 4); break;
case 87: /* lbzx */ case 119: /* lbzux */
op->type = MKOP(LOAD, u, 1); break;
#ifdef CONFIG_ALTIVEC /* * Note: for the load/store vector element instructions, * bits of the EA say which field of the VMX register to use.
*/ case 7: /* lvebx */
op->type = MKOP(LOAD_VMX, 0, 1);
op->element_size = 1; break;
if (OP_IS_LOAD_STORE(op->type) && (op->type & UPDATE)) { switch (GETTYPE(op->type)) { case LOAD: if (ra == rd) goto unknown_opcode;
fallthrough; case STORE: case LOAD_FP: case STORE_FP: if (ra == 0) goto unknown_opcode;
}
}
/* * For PPC32 we always use stwu with r1 to change the stack pointer. * So this emulated store may corrupt the exception frame, now we * have to provide the exception frame trampoline, which is pushed * below the kprobed function stack. So we only update gpr[1] but * don't emulate the real store operation. We will do real store * operation safely in exception return code by checking this flag.
*/ static nokprobe_inline int handle_stack_update(unsignedlong ea, struct pt_regs *regs)
{ /* * Check if we already set since that means we'll * lose the previous value.
*/
WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE));
set_thread_flag(TIF_EMULATE_STACK_STORE); return 0;
}
static nokprobe_inline void do_signext(unsignedlong *valp, int size)
{ switch (size) { case 2:
*valp = (signedshort) *valp; break; case 4:
*valp = (signedint) *valp; break;
}
}
static nokprobe_inline void do_byterev(unsignedlong *valp, int size)
{ switch (size) { case 2:
*valp = byterev_2(*valp); break; case 4:
*valp = byterev_4(*valp); break; #ifdef __powerpc64__ case 8:
*valp = byterev_8(*valp); break; #endif
}
}
/* * Emulate an instruction that can be executed just by updating * fields in *regs.
*/ void emulate_update_regs(struct pt_regs *regs, struct instruction_op *op)
{ unsignedlong next_pc;
next_pc = truncate_if_32bit(regs->msr, regs->nip + GETLENGTH(op->type)); switch (GETTYPE(op->type)) { case COMPUTE: if (op->type & SETREG)
regs->gpr[op->reg] = op->val; if (op->type & SETCC)
regs->ccr = op->ccval; if (op->type & SETXER)
regs->xer = op->xerval; break;
case BRANCH: if (op->type & SETLK)
regs->link = next_pc; if (op->type & BRTAKEN)
next_pc = op->val; if (op->type & DECCTR)
--regs->ctr; break;
case BARRIER: switch (op->type & BARRIER_MASK) { case BARRIER_SYNC:
mb(); break; case BARRIER_ISYNC:
isync(); break; case BARRIER_EIEIO:
eieio(); break; #ifdef CONFIG_PPC64 case BARRIER_LWSYNC: asmvolatile("lwsync" : : : "memory"); break; case BARRIER_PTESYNC: asmvolatile("ptesync" : : : "memory"); break; #endif
} break;
case MFSPR: switch (op->spr) { case SPRN_XER:
regs->gpr[op->reg] = regs->xer & 0xffffffffUL; break; case SPRN_LR:
regs->gpr[op->reg] = regs->link; break; case SPRN_CTR:
regs->gpr[op->reg] = regs->ctr; break; default:
WARN_ON_ONCE(1);
} break;
case MTSPR: switch (op->spr) { case SPRN_XER:
regs->xer = op->val & 0xffffffffUL; break; case SPRN_LR:
regs->link = op->val; break; case SPRN_CTR:
regs->ctr = op->val; break; default:
WARN_ON_ONCE(1);
} break;
case LOAD: #ifdef __powerpc64__ if (size == 16) {
err = emulate_lq(regs, ea, op->reg, cross_endian); break;
} #endif
err = read_mem(®s->gpr[op->reg], ea, size, regs); if (!err) { if (op->type & SIGNEXT)
do_signext(®s->gpr[op->reg], size); if ((op->type & BYTEREV) == (cross_endian ? 0 : BYTEREV))
do_byterev(®s->gpr[op->reg], size);
} break;
#ifdef CONFIG_PPC_FPU case LOAD_FP: /* * If the instruction is in userspace, we can emulate it even * if the VMX state is not live, because we have the state * stored in the thread_struct. If the instruction is in * the kernel, we must not touch the state in the thread_struct.
*/ if (!user_mode(regs) && !(regs->msr & MSR_FP)) return 0;
err = do_fp_load(op, ea, regs, cross_endian); break; #endif #ifdef CONFIG_ALTIVEC case LOAD_VMX: if (!user_mode(regs) && !(regs->msr & MSR_VEC)) return 0;
err = do_vec_load(op->reg, ea, size, regs, cross_endian); break; #endif #ifdef CONFIG_VSX case LOAD_VSX: { unsignedlong msrbit = MSR_VSX;
/* * Some VSX instructions check the MSR_VEC bit rather than MSR_VSX * when the target of the instruction is a vector register.
*/ if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC))
msrbit = MSR_VEC; if (!user_mode(regs) && !(regs->msr & msrbit)) return 0;
err = do_vsx_load(op, ea, regs, cross_endian); break;
} #endif case LOAD_MULTI: if (!address_ok(regs, ea, size)) return -EFAULT;
rd = op->reg; for (i = 0; i < size; i += 4) { unsignedint v32 = 0;
nb = size - i; if (nb > 4)
nb = 4;
err = copy_mem_in((u8 *) &v32, ea, nb, regs); if (err) break; if (unlikely(cross_endian))
v32 = byterev_4(v32);
regs->gpr[rd] = v32;
ea += 4; /* reg number wraps from 31 to 0 for lsw[ix] */
rd = (rd + 1) & 0x1f;
} break;
#ifdef CONFIG_PPC_FPU case STORE_FP: if (!user_mode(regs) && !(regs->msr & MSR_FP)) return 0;
err = do_fp_store(op, ea, regs, cross_endian); break; #endif #ifdef CONFIG_ALTIVEC case STORE_VMX: if (!user_mode(regs) && !(regs->msr & MSR_VEC)) return 0;
err = do_vec_store(op->reg, ea, size, regs, cross_endian); break; #endif #ifdef CONFIG_VSX case STORE_VSX: { unsignedlong msrbit = MSR_VSX;
/* * Some VSX instructions check the MSR_VEC bit rather than MSR_VSX * when the target of the instruction is a vector register.
*/ if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC))
msrbit = MSR_VEC; if (!user_mode(regs) && !(regs->msr & msrbit)) return 0;
err = do_vsx_store(op, ea, regs, cross_endian); break;
} #endif case STORE_MULTI: if (!address_ok(regs, ea, size)) return -EFAULT;
rd = op->reg; for (i = 0; i < size; i += 4) { unsignedint v32 = regs->gpr[rd];
nb = size - i; if (nb > 4)
nb = 4; if (unlikely(cross_endian))
v32 = byterev_4(v32);
err = copy_mem_out((u8 *) &v32, ea, nb, regs); if (err) break;
ea += 4; /* reg number wraps from 31 to 0 for stsw[ix] */
rd = (rd + 1) & 0x1f;
} break;
default: return -EINVAL;
}
if (err) return err;
if (op->type & UPDATE)
regs->gpr[op->update_reg] = op->ea;
return 0;
}
NOKPROBE_SYMBOL(emulate_loadstore);
/* * Emulate instructions that cause a transfer of control, * loads and stores, and a few other instructions. * Returns 1 if the step was emulated, 0 if not, * or -1 if the instruction is one that should not be stepped, * such as an rfid, or a mtmsrd that would clear MSR_RI.
*/ int emulate_step(struct pt_regs *regs, ppc_inst_t instr)
{ struct instruction_op op; int r, err, type; unsignedlong val; unsignedlong ea;
r = analyse_instr(&op, regs, instr); if (r < 0) return r; if (r > 0) {
emulate_update_regs(regs, &op); return 1;
}
err = 0;
type = GETTYPE(op.type);
if (OP_IS_LOAD_STORE(type)) {
err = emulate_loadstore(regs, &op); if (err) return 0; goto instr_done;
}
switch (type) { case CACHEOP:
ea = truncate_if_32bit(regs->msr, op.ea); if (!address_ok(regs, ea, 8)) return 0; switch (op.type & CACHEOP_MASK) { case DCBST:
__cacheop_user_asmx(ea, err, "dcbst"); break; case DCBF:
__cacheop_user_asmx(ea, err, "dcbf"); break; case DCBTST: if (op.reg == 0)
prefetchw((void *) ea); break; case DCBT: if (op.reg == 0)
prefetch((void *) ea); break; case ICBI:
__cacheop_user_asmx(ea, err, "icbi"); break; case DCBZ:
err = emulate_dcbz(ea, regs); break;
} if (err) {
regs->dar = ea; return 0;
} goto instr_done;
case MFMSR:
regs->gpr[op.reg] = regs->msr & MSR_MASK; goto instr_done;
case MTMSR:
val = regs->gpr[op.reg]; if ((val & MSR_RI) == 0) /* can't step mtmsr[d] that would clear MSR_RI */ return -1; /* here op.val is the mask of bits to change */
regs_set_return_msr(regs, (regs->msr & ~op.val) | (val & op.val)); goto instr_done;
case SYSCALL: /* sc */ /* * Per ISA v3.1, section 7.5.15 'Trace Interrupt', we can't * single step a system call instruction: * * Successful completion for an instruction means that the * instruction caused no other interrupt. Thus a Trace * interrupt never occurs for a System Call or System Call * Vectored instruction, or for a Trap instruction that * traps.
*/ return -1; case SYSCALL_VECTORED_0: /* scv 0 */ return -1; case RFI: return -1;
} return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.