/*
* Single-step support.
*
* Copyright (C) 2004 Paul Mackerras <paulus@au.ibm.com>, IBM
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include <linux/prefetch.h>
#include <asm/sstep.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/cputable.h>
extern char system_call_common[];
#ifdef CONFIG_PPC64
/* Bits in SRR1 that are copied from MSR */
#define MSR_MASK 0xffffffff87c0ffffUL
#else
#define MSR_MASK 0x87c0ffff
#endif
/* Bits in XER */
#define XER_SO 0x80000000U
#define XER_OV 0x40000000U
#define XER_CA 0x20000000U
#ifdef CONFIG_PPC_FPU
/*
* Functions in ldstfp.S
*/
extern int do_lfs(int rn, unsigned long ea);
extern int do_lfd(int rn, unsigned long ea);
extern int do_stfs(int rn, unsigned long ea);
extern int do_stfd(int rn, unsigned long ea);
extern int do_lvx(int rn, unsigned long ea);
extern int do_stvx(int rn, unsigned long ea);
extern int do_lxvd2x(int rn, unsigned long ea);
extern int do_stxvd2x(int rn, unsigned long ea);
#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.
*/
static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs)
{
unsigned int bo = (instr >> 21) & 0x1f;
unsigned int bi;
if ((bo & 4) == 0) {
/* decrement counter */
--regs->ctr;
if (((bo >> 1) & 1) ^ (regs->ctr == 0))
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 long __kprobes address_ok(struct pt_regs *regs, unsigned long ea, int nb)
{
if (!user_mode(regs))
return 1;
return __access_ok(ea, nb, USER_DS);
}
/*
* Calculate effective address for a D-form instruction
*/
static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs)
{
int ra;
unsigned long ea;
ra = (instr >> 16) & 0x1f;
ea = (signed short) instr; /* sign-extend */
if (ra) {
ea += regs->gpr[ra];
if (instr & 0x04000000) /* update forms */
regs->gpr[ra] = ea;
}
return truncate_if_32bit(regs->msr, ea);
}
#ifdef __powerpc64__
/*
* Calculate effective address for a DS-form instruction
*/
static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *regs)
{
int ra;
unsigned long ea;
ra = (instr >> 16) & 0x1f;
ea = (signed short) (instr & ~3); /* sign-extend */
if (ra) {
ea += regs->gpr[ra];
if ((instr & 3) == 1) /* update forms */
regs->gpr[ra] = ea;
}
return truncate_if_32bit(regs->msr, ea);
}
#endif /* __powerpc64 */
/*
* Calculate effective address for an X-form instruction
*/
static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs,
int do_update)
{
int ra, rb;
unsigned long ea;
ra = (instr >> 16) & 0x1f;
rb = (instr >> 11) & 0x1f;
ea = regs->gpr[rb];
if (ra) {
ea += regs->gpr[ra];
if (do_update) /* update forms */
regs->gpr[ra] = ea;
}
return truncate_if_32bit(regs->msr, ea);
}
/*
* Return the largest power of 2, not greater than sizeof(unsigned long),
* such that x is a multiple of it.
*/
static inline unsigned long max_align(unsigned long x)
{
x |= sizeof(unsigned long);
return x & -x; /* isolates rightmost bit */
}
static inline unsigned long byterev_2(unsigned long x)
{
return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
}
static inline unsigned long byterev_4(unsigned long x)
{
return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) |
((x & 0xff00) << 8) | ((x & 0xff) << 24);
}
#ifdef __powerpc64__
static inline unsigned long byterev_8(unsigned long x)
{
return (byterev_4(x) << 32) | b
|