linux-headers/arch/e2k/include/asm/ptrace.h

829 lines
22 KiB
C

#ifndef _E2K_PTRACE_H
#define _E2K_PTRACE_H
#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <linux/threads.h>
#include <asm/current.h>
#endif /* __ASSEMBLY__ */
#include <asm/page.h>
#ifndef __ASSEMBLY__
#include <asm/e2k_api.h>
#include <asm/cpu_regs.h>
#include <asm/glob_regs.h>
#include <asm/stacks.h>
#include <asm/mmu_types.h>
#include <asm/mmu_regs_types.h>
#ifdef CONFIG_USE_AAU
#include <asm/aau_regs.h>
#endif /* CONFIG_USE_AAU */
#include <asm/mlt.h>
#include <asm/ptrace-abi.h>
#endif /* __ASSEMBLY__ */
#include <uapi/asm/ptrace.h>
#include <asm/pv_info.h>
#define TASK_TOP TASK_SIZE
/*
* User process size in MA32 mode.
*/
#define TASK32_SIZE (0xf0000000UL)
#ifndef __ASSEMBLY__
#ifdef CONFIG_KERNEL_TIMES_ACCOUNT
#include <asm/clock_info.h>
#endif /* CONFIG_KERNEL_TIMES_ACCOUNT */
#include <asm/siginfo.h>
#include <linux/signal_types.h>
struct mm_struct;
typedef struct pt_regs ptregs_t;
typedef struct sw_regs sw_regs_t;
struct e2k_greg {
union {
u64 xreg[2]; /* extended register */
struct {
u64 base; /* main part of value */
u64 ext; /* extended part of floating point */
/* value */
};
};
} __aligned(16); /* must be aligned for stgdq/stqp/ldqp to work */
#ifdef CONFIG_GREGS_CONTEXT
typedef struct global_regs {
struct e2k_greg g[E2K_GLOBAL_REGS_NUM];
e2k_bgr_t bgr;
} global_regs_t;
/* Sometimes we only want to save %g16-%g31 (so called "local" gregs) */
typedef struct local_gregs {
struct e2k_greg g[LOCAL_GREGS_NUM];
e2k_bgr_t bgr;
} local_gregs_t;
/* gN and gN+1 global registers hold pointers to current in kernel, */
/* gN+2 and gN+3 are used for per-cpu data pointer and current cpu id. */
/* Now N = 16 (see real numbers at asm/glob_regs.h) */
typedef struct kernel_gregs {
struct e2k_greg g[KERNEL_GREGS_NUM];
} kernel_gregs_t;
#endif /* CONFIG_GREGS_CONTEXT */
#define HW_TC_SIZE 7
/* trap_pt_regs->flags */
#define TRAP_PCSP_FILL_ADJUSTED 0x0001
#define TRAP_PSP_FILL_ADJUSTED 0x0002
#define TRAP_SRP_FLAG 0x0004
#define TRAP_RP_FLAG 0x0008
typedef struct trap_pt_regs {
u64 TIR_hi; /* Trap info registers */
u64 TIR_lo;
int TIR_no; /* current handled TIRs # */
s8 nr_TIRs;
s8 tc_count;
s8 curr_cnt;
char ignore_user_tc;
char tc_called;
char from_sigreturn;
bool is_intc; /* intercept page fault */
u8 nr_trap; /* number of trap */
u8 nr_page_fault_exc; /* number of page fault trap */
int prev_state;
int flags;
e2k_addr_t srp_ip;
e2k_tir_t TIRs[TIR_NUM];
trap_cellar_t tcellar[HW_TC_SIZE];
u64 *sbbp;
#ifdef CONFIG_SECONDARY_SPACE_SUPPORT
e2k_mlt_t mlt_state; /* MLT state for binco */
#endif
} trap_pt_regs_t;
union pt_regs_flags {
struct {
/* execute_mmu_operations() is working */
u32 exec_mmu_op : 1;
/* nested exception appeared while
* execute_mmu_operations() was working */
u32 exec_mmu_op_nested : 1;
/* A signal's handler will be called upon return to userspace */
u32 sig_call_handler : 1;
/* System call should be restarted after signal's handler */
u32 sig_restart_syscall : 1;
/* Used to distinguish between entry8 and entry10 for protected syscalls */
u32 protected_entry10 : 1;
/* From hardware guest interception */
u32 kvm_hw_intercept : 1;
/* trap or system call is on or from guest */
u32 trap_as_intc_emul : 1;
/* Trap occurred in light hypercall */
u32 light_hypercall : 1;
};
u32 word;
};
typedef struct pt_regs {
struct pt_regs *next; /* the previous regs structure */
struct trap_pt_regs *trap;
#ifdef CONFIG_USE_AAU
e2k_aau_t *aau_context; /* aau registers */
#endif
e2k_stacks_t stacks; /* current state of all stacks */
/* registers */
e2k_mem_crs_t crs; /* current chain window regs state */
e2k_wd_t wd; /* current window descriptor */
int sys_num; /* to restart sys_call */
int kernel_entry;
union pt_regs_flags flags;
e2k_ctpr_t ctpr1; /* CTPRj for control transfer */
e2k_ctpr_t ctpr2;
e2k_ctpr_t ctpr3;
e2k_ctpr_hi_t ctpr1_hi;
e2k_ctpr_hi_t ctpr2_hi;
e2k_ctpr_hi_t ctpr3_hi;
u64 lsr; /* loops */
u64 ilcr; /* initial loop value */
u64 lsr1;
u64 ilcr1;
int interrupt_vector;
#ifdef CONFIG_EPIC
unsigned int epic_core_priority;
#endif
long sys_rval;
long args[13]; /* unused, arg1, ... arg12 */
long tags;
long rval1;
long rval2;
int return_desk;
int rv1_tag;
int rv2_tag;
#ifdef CONFIG_CLW_ENABLE
int clw_cpu;
int clw_count;
int clw_first;
clw_reg_t us_cl_m[CLW_MASK_WORD_NUM];
clw_reg_t us_cl_up;
clw_reg_t us_cl_b;
#endif /* CONFIG_CLW_ENABLE */
/* for bin_comp */
u64 rpr_lo;
u64 rpr_hi;
#ifdef CONFIG_VIRTUALIZATION
u64 sys_func; /* need only for guest */
e2k_stacks_t g_stacks; /* current state of guest kernel */
/* stacks registers */
bool g_stacks_valid; /* the state of guest kernel stacks */
/* registers is valid */
bool g_stacks_active; /* the guest kernel stacks */
/* registers is in active work */
bool stack_regs_saved; /* stack state regs was already */
/* saved */
bool need_inject; /* flag for unconditional injection */
/* trap to guest to avoid acces to */
/* guest user space in trap context */
bool in_hypercall; /* trap is occured in hypercall */
bool is_guest_user; /* trap/system call on/from guest */
/* user */
unsigned long traps_to_guest; /* mask of traps passed to guest */
/* and are not yet handled by guest */
/* need only for host */
#ifdef CONFIG_KVM_GUEST_KERNEL
/* only for guest kernel */
/* already copyed back part of guest user hardware stacks */
/* spilled to guest kernel stacks */
struct {
e2k_size_t ps_size; /* procedure stack copyed size */
e2k_size_t pcs_size; /* chain stack copyesd size */
/* The frames injected to support 'signal stack' */
/* and trampolines to return from user to kernel */
e2k_size_t pcs_injected_frames_size;
} copyed;
#endif /* CONFIG_KVM_GUEST_KERNEL */
#endif /* CONFIG_VIRTUALIZATION */
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_GUEST_KERNEL)
e2k_svd_gregs_t guest_vcpu_state_greg;
#endif /* CONFIG_KVM || CONFIG_KVM_GUEST_KERNEL */
#ifdef CONFIG_KERNEL_TIMES_ACCOUNT
scall_times_t *scall_times;
#endif /* CONFIG_KERNEL_TIMES_ACCOUNT */
} pt_regs_t;
static inline struct trap_pt_regs *
pt_regs_to_trap_regs(struct pt_regs *regs)
{
return PTR_ALIGN((void *) regs + sizeof(*regs), 8);
}
#ifdef CONFIG_USE_AAU
static inline e2k_aau_t *
pt_regs_to_aau_regs(struct pt_regs *regs)
{
struct trap_pt_regs *trap;
trap = pt_regs_to_trap_regs(regs);
return PTR_ALIGN((void *) trap + sizeof(*trap), 8);
}
#else /* ! CONFIG_USE_AAU */
static inline e2k_aau_t *
pt_regs_to_aau_regs(struct pt_regs *regs)
{
return NULL;
}
#endif
static inline bool
is_sys_call_pt_regs(struct pt_regs *regs)
{
return regs->trap == NULL && regs->kernel_entry != 0;
}
static inline bool
is_trap_pt_regs(struct pt_regs *regs)
{
return regs->trap != NULL && regs->kernel_entry == 0;
}
typedef struct sw_regs {
e2k_mem_crs_t crs;
e2k_addr_t top; /* top of all user data stacks */
e2k_usd_lo_t usd_lo;
e2k_usd_hi_t usd_hi;
e2k_psp_lo_t psp_lo; /* procedure stack pointer(as empty)*/
e2k_psp_hi_t psp_hi;
e2k_pcsp_lo_t pcsp_lo; /* procedure chaine stack pointer */
e2k_pcsp_hi_t pcsp_hi; /* (as empty) */
e2k_upsr_t upsr;
e2k_fpcr_t fpcr;
e2k_fpsr_t fpsr;
e2k_pfpfr_t pfpfr;
e2k_cutd_t cutd;
#ifdef CONFIG_VIRTUALIZATION
struct task_struct *prev_task; /* task switch to current from */
#endif /* CONFIG_VIRTUALIZATION */
#ifdef CONFIG_GREGS_CONTEXT
struct global_regs gregs;
#endif
/*
* These two are shared by monitors and breakpoints. Monitors
* are accessed by userspace directly through sys_ptrace and
* breakpoints are accessed through CONFIG_HW_BREAKPOINT layer
* (i.e. ptrace does not write directly to breakpoint registers).
*
* For this reason breakpoints related registers are moved out
* from sw_regs as they are managed by arch-independent layer
* instead of arch-dependent switch_to() function. For dibsr and
* ddbsr only monitors-related fields are accessed in switch_to().
*/
e2k_dibsr_t dibsr;
e2k_ddbsr_t ddbsr;
u64 dimar0;
u64 dimar1;
e2k_dimcr_t dimcr;
u64 ddmar0;
u64 ddmar1;
e2k_ddmcr_t ddmcr;
e2k_dimtp_t dimtp;
/*
* in the case we switch from/to a BINCO task, we
* need to backup/restore these registers in task switching
*/
u64 cs_lo;
u64 cs_hi;
u64 ds_lo;
u64 ds_hi;
u64 es_lo;
u64 es_hi;
u64 fs_lo;
u64 fs_hi;
u64 gs_lo;
u64 gs_hi;
u64 ss_lo;
u64 ss_hi;
/* Additional registers for BINCO */
u64 rpr_lo;
u64 rpr_hi;
#ifdef CONFIG_TC_STORAGE
u64 tcd;
#endif
} sw_regs_t;
typedef struct jmp_info {
u64 sigmask;
u64 ip;
u64 cr1lo;
u64 pcsplo;
u64 pcsphi;
u32 pcshtp;
u32 br;
u64 usd_lo;
u32 reserved;
u32 wd_hi32;
} e2k_jmp_info_t;
#define __HAVE_ARCH_KSTACK_END
static inline int kstack_end(void *addr)
{
return (e2k_addr_t)addr >= READ_SBR_REG_VALUE();
}
#define NATIVE_SAVE_DAM(__dam) \
do { \
int i; \
e2k_addr_t addr = (REG_DAM_TYPE << REG_DAM_TYPE_SHIFT); \
for (i = 0; i < DAM_ENTRIES_NUM; i++) \
(__dam)[i] = NATIVE_READ_DAM_REG(addr | \
(i << REG_DAM_N_SHIFT)); \
} while (0)
/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
/* e2k extentions */
#define PTRACE_PEEKPTR 0x100
#define PTRACE_POKEPTR 0x101
#define PTRACE_PEEKTAG 0x120
#define PTRACE_POKETAG 0x121
#define PTRACE_EXPAND_STACK 0x130
#define from_trap(regs) ((regs)->trap != NULL)
#define from_syscall(regs) (!from_trap(regs))
static inline u64 user_stack_pointer(struct pt_regs *regs)
{
e2k_usd_lo_t usd_lo = regs->stacks.usd_lo;
u64 sp;
if (!AS(usd_lo).p) {
sp = AS(usd_lo).base;
} else {
e2k_pusd_lo_t pusd_lo;
AW(pusd_lo) = AW(usd_lo);
sp = AS(pusd_lo).base + (regs->stacks.top & ~0xffffffffULL);
}
return sp;
}
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
{
return AS(regs->stacks.usd_lo).base;
}
static inline void native_atomic_load_osgd_to_gd(void)
{
E2K_LOAD_OSGD_TO_GD();
}
/**
* regs_get_kernel_stack_nth() - get Nth entry of the stack
* @regs: pt_regs which contains kernel stack pointer.
* @n: stack entry number.
*
* regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
* is specified by @regs. If the @n th entry is NOT in the kernel stack,
* this returns 0.
*/
static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
unsigned int n)
{
unsigned long addr = kernel_stack_pointer(regs);
addr += n * sizeof(unsigned long);
if (addr >= kernel_stack_pointer(regs) && addr < regs->stacks.top)
return *(unsigned long *) addr;
else
return 0;
}
/* Query offset/name of register from its name/offset */
extern int regs_query_register_offset(const char *name);
extern const char *regs_query_register_name(unsigned int offset);
#define REGS_B_REGISTER_FLAG (1 << 30)
#define REGS_PRED_REGISTER_FLAG (1 << 29)
#define REGS_TIR1_REGISTER_FLAG (1 << 28)
extern unsigned long regs_get_register(const struct pt_regs *regs,
unsigned int offset);
#define from_trap(regs) ((regs)->trap != NULL)
#define from_syscall(regs) (!from_trap(regs))
static inline unsigned long regs_return_value(struct pt_regs *regs)
{
/* System call audit case: %b[0] is not ready yet */
if (from_syscall(regs))
return regs->sys_rval;
/* kretprobe case - get %b[0] */
return regs_get_register(regs, 0 | REGS_B_REGISTER_FLAG);
}
static inline e2k_addr_t
native_check_is_user_address(struct task_struct *task, e2k_addr_t address)
{
if (likely(address < NATIVE_TASK_SIZE))
return 0;
pr_err("Address 0x%016lx is native kernel address\n",
address);
return -1;
}
#define NATIVE_IS_GUEST_USER_ADDRESS_TO_PVA(task, address) \
false /* native kernel has not guests */
#define NATIVE_IS_GUEST_ADDRESS_TO_HOST(address) \
false /* native kernel has not guests */
/* guest page table is pseudo PT and only host PT is used */
/* to translate any guest addresses */
static inline void
native_print_host_user_address_ptes(struct mm_struct *mm, e2k_addr_t address)
{
/* this function is actual only for guest */
/* native kernel can not be guest kernel */
}
/**
* calculate_e2k_dstack_parameters - get user data stack free area parameters
* @stacks: stack registers
* @sp: stack pointer will be returned here
* @stack_size: free area size will be returned here
* @top: stack area top will be returned here
*/
static inline void calculate_e2k_dstack_parameters(
const struct e2k_stacks *stacks,
u64 *sp, u64 *stack_size, u64 *top)
{
e2k_usd_lo_t usd_lo = stacks->usd_lo;
e2k_usd_hi_t usd_hi = stacks->usd_hi;
unsigned long sbr = stacks->top;
if (top)
*top = sbr;
if (AS(usd_lo).p) {
e2k_pusd_lo_t pusd_lo;
e2k_pusd_hi_t pusd_hi;
unsigned long usbr;
usbr = sbr & ~E2K_PROTECTED_STACK_BASE_MASK;
AW(pusd_lo) = AW(usd_lo);
AW(pusd_hi) = AW(usd_hi);
*sp = usbr + (AS(pusd_lo).base & ~E2K_ALIGN_PUSTACK_MASK);
*stack_size = AS(pusd_hi).size & ~E2K_ALIGN_PUSTACK_MASK;
} else {
*sp = AS(usd_lo).base;
*stack_size = AS(usd_hi).size;
}
}
/* virtualization support */
#include <asm/kvm/ptrace.h>
typedef struct signal_stack_context {
struct pt_regs regs;
struct trap_pt_regs trap;
struct k_sigaction sigact;
e2k_aau_t aau_regs;
#ifdef CONFIG_GREGS_CONTEXT
struct local_gregs l_gregs;
#endif
u64 sbbp[SBBP_ENTRIES_NUM];
struct pv_vcpu_ctxt vcpu_ctxt;
} signal_stack_context_t;
#define __signal_pt_regs_last(ti) \
({ \
struct pt_regs __user *__sig_regs; \
if (ti->signal_stack.used) { \
__sig_regs = &((struct signal_stack_context __user *) \
(ti->signal_stack.base))->regs; \
} else { \
__sig_regs = NULL; \
} \
__sig_regs; \
})
#define signal_pt_regs_last() __signal_pt_regs_last(current_thread_info())
#define signal_pt_regs_first() \
({ \
struct pt_regs __user *__sig_regs; \
if (current_thread_info()->signal_stack.used) { \
__sig_regs = &((struct signal_stack_context __user *) \
(current_thread_info()->signal_stack.base + \
current_thread_info()->signal_stack.used - \
sizeof(struct signal_stack_context)))->regs; \
} else { \
__sig_regs = NULL; \
} \
__sig_regs; \
})
#define signal_pt_regs_for_each(__regs) \
for (__regs = signal_pt_regs_first(); \
__regs && (u64) __regs >= \
current_thread_info()->signal_stack.base; \
__regs = (struct pt_regs __user *) ((void *) __regs - \
sizeof(struct signal_stack_context)))
/**
* signal_pt_regs_to_trap - to be used inside of signal_pt_regs_for_each();
* will return trap_pt_regs pointer corresponding
* to the passed pt_regs structure.
* @__u_regs: pt_regs pointer returned by signal_pt_regs_for_each()
*
* EXAMPLE:
* signal_pt_regs_for_each(u_regs) {
* struct trap_pt_regs __user *u_trap = signal_pt_regs_to_trap(u_regs);
* if (IS_ERR(u_trap))
* ;// Caught -EFAULT from get_user()
* if (IS_NULL(u_trap))
* ;// Not interrupt pt_regs
*/
#define signal_pt_regs_to_trap(__u_regs) \
({ \
struct pt_regs __user *__spr_u_regs = (__u_regs); \
struct trap_pt_regs __user *u_trap; \
\
if (__get_user(u_trap, &__spr_u_regs->trap)) {\
u_trap = ERR_PTR(-EFAULT); \
} else if (u_trap) { \
u_trap = (struct trap_pt_regs __user *) \
((void __user *) __spr_u_regs - \
offsetof(struct signal_stack_context, regs) + \
offsetof(struct signal_stack_context, trap)); \
} \
u_trap; \
})
#define arch_ptrace_stop_needed(...) (true)
/* current->thread_info->pt_regs may be zero if ptrace_stop()
* was called from load_elf_binary() (it happens if gdb has
* set PTRACE_O_TRACEEXEC flag). */
#define arch_ptrace_stop(...) \
do { \
struct pt_regs *__pt_regs = current_thread_info()->pt_regs; \
if (__pt_regs) { \
if (!test_ts_flag(TS_USER_EXECVE)) \
user_hw_stacks_copy_full(&__pt_regs->stacks, \
__pt_regs, NULL); \
SAVE_AAU_REGS_FOR_PTRACE(__pt_regs, current_thread_info()); \
if (!paravirt_enabled()) { \
/* FIXME: it need implement for guest kernel */ \
NATIVE_SAVE_BINCO_REGS_FOR_PTRACE(__pt_regs); \
} \
} \
} while (0)
static inline int syscall_from_kernel(const struct pt_regs *regs)
{
return from_syscall(regs) && !user_mode(regs);
}
static inline int syscall_from_user(const struct pt_regs *regs)
{
return from_syscall(regs) && user_mode(regs);
}
static inline int trap_from_kernel(const struct pt_regs *regs)
{
return from_trap(regs) && !user_mode(regs);
}
static inline int trap_from_user(const struct pt_regs *regs)
{
return from_trap(regs) && user_mode(regs);
}
static inline void instruction_pointer_set(struct pt_regs *regs,
unsigned long val)
{
AS(regs->crs.cr0_hi).ip = val >> 3;
}
/* IMPORTANT: this only works after parse_TIR_registers()
* has set trap->TIR_lo. So this doesn't work for NMIs. */
static inline unsigned long get_trap_ip(const struct pt_regs *regs)
{
e2k_tir_lo_t tir_lo;
tir_lo.TIR_lo_reg = regs->trap->TIR_lo;
return tir_lo.TIR_lo_ip;
}
static inline unsigned long get_return_ip(const struct pt_regs *regs)
{
return (unsigned long) (AS(regs->crs.cr0_hi).ip << 3);
}
static inline unsigned long instruction_pointer(const struct pt_regs *regs)
{
return get_return_ip(regs);
}
#ifdef CONFIG_DEBUG_PT_REGS
#define CHECK_PT_REGS_LOOP(regs) \
({ \
if ((regs) != NULL) { \
if ((regs)->next == (regs)) { \
pr_err("LOOP in regs list: regs 0x%px next 0x%px\n", \
(regs), (regs)->next); \
dump_stack(); \
} \
} \
})
#define CHECK_PT_REGS_CHAIN(regs, bottom, top) \
({ \
pt_regs_t *next_regs = (regs); \
pt_regs_t *prev_regs = (pt_regs_t *)(bottom); \
while ((next_regs) != NULL) { \
if ((bottom) < TASK_SIZE) \
break; \
if ((e2k_addr_t)next_regs > (e2k_addr_t)((top) - sizeof(pt_regs_t))) { \
pr_err("%s(): next regs %px above top 0x%llx\n", \
__func__, next_regs, \
(top) - sizeof(pt_regs_t)); \
print_pt_regs(next_regs); \
WARN_ON(true); \
} else if ((e2k_addr_t)next_regs == (e2k_addr_t)prev_regs) { \
pr_err("%s(): next regs %px is same as previous %px\n", \
__func__, next_regs, prev_regs); \
print_pt_regs(next_regs); \
BUG_ON(true); \
} else if ((e2k_addr_t)next_regs < (e2k_addr_t)prev_regs) { \
pr_err("%s(): next regs %px below previous %px\n", \
__func__, next_regs, prev_regs); \
print_pt_regs(next_regs); \
BUG_ON(true); \
} \
prev_regs = next_regs; \
next_regs = next_regs->next; \
} \
})
/*
* The hook to find 'ct' command ( return to user)
* be interrapted with cloused interrupt / HARDWARE problem #59886/
*/
#define CHECK_CT_INTERRUPTED(regs) \
({ \
struct pt_regs *__regs = regs; \
do { \
if (__call_from_user(__regs) || __trap_from_user(__regs)) \
break; \
__regs = __regs->next; \
} while (__regs); \
if (!__regs) { \
printk(" signal delivery started on kernel instruction" \
" top = 0x%lx TIR_lo=0x%lx " \
" crs.cr0_hi.ip << 3 = 0x%lx\n", \
(regs)->stacks.top, (regs)->TIR_lo, \
instruction_pointer(regs)); \
dump_stack(); \
} \
})
#else /* ! CONFIG_DEBUG_PT_REGS */
#define CHECK_PT_REGS_LOOP(regs) /* nothing */
#define CHECK_PT_REGS_CHAIN(regs, bottom, top)
#define CHECK_CT_INTERRUPTED(regs)
#endif /* CONFIG_DEBUG_PT_REGS */
static inline struct pt_regs *find_user_regs(const struct pt_regs *regs)
{
do {
CHECK_PT_REGS_LOOP(regs);
if (user_mode(regs) && !regs->flags.kvm_hw_intercept)
break;
regs = regs->next;
} while (regs);
return (struct pt_regs *) regs;
}
/*
* Finds the first pt_regs corresponding to the kernel entry
* (i.e. user mode pt_regs) if this is a user thread.
*
* Finds the first pt_regs structure if this is a kernel thread.
*/
static inline struct pt_regs *find_entry_regs(const struct pt_regs *regs)
{
const struct pt_regs *prev_regs;
do {
CHECK_PT_REGS_LOOP(regs);
if (user_mode(regs) && !regs->flags.kvm_hw_intercept)
goto found;
prev_regs = regs;
regs = regs->next;
} while (regs);
/* Return the first pt_regs structure for kernel threads */
regs = prev_regs;
found:
return (struct pt_regs *) regs;
}
static inline struct pt_regs *find_host_regs(const struct pt_regs *regs)
{
while (regs) {
CHECK_PT_REGS_LOOP(regs);
if (likely(!regs->flags.kvm_hw_intercept))
break;
regs = regs->next;
};
return (struct pt_regs *) regs;
}
static inline struct pt_regs *find_trap_host_regs(const struct pt_regs *regs)
{
while (regs) {
CHECK_PT_REGS_LOOP(regs);
if (from_trap(regs) && !regs->flags.kvm_hw_intercept)
break;
regs = regs->next;
};
return (struct pt_regs *) regs;
}
#define count_trap_regs(regs) \
({ \
struct pt_regs *__regs = regs; \
int traps = 0; \
while (__regs) { \
if (from_trap(regs)) \
traps++; \
__regs = __regs->next; \
} \
traps; \
})
#define current_is_in_trap() \
(count_trap_regs(current_thread_info()->pt_regs) > 0)
#define count_user_regs(regs) \
({ \
struct pt_regs *__regs = regs; \
int regs_num = 0; \
while (__regs) { \
CHECK_PT_REGS_LOOP(__regs); \
if (user_mode(regs)) \
regs_num++; \
__regs = __regs->next; \
} \
regs_num; \
})
#if defined(CONFIG_SMP)
extern unsigned long profile_pc(struct pt_regs *regs);
#else
#define profile_pc(regs) instruction_pointer(regs)
#endif
extern void show_regs(struct pt_regs *);
extern int syscall_trace_entry(struct pt_regs *regs);
extern void syscall_trace_leave(struct pt_regs *regs);
#define arch_has_single_step() (1)
extern long common_ptrace(struct task_struct *child, long request, unsigned long addr,
unsigned long data, bool compat);
#endif /* __ASSEMBLY__ */
#endif /* _E2K_PTRACE_H */