summaryrefslogtreecommitdiff
path: root/arch/s390/include/asm/ptrace.h
blob: 808da21235ab7ed5010d0d8eca5b5e51f2cc43e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/* SPDX-License-Identifier: GPL-2.0 */
/*
 *  S390 version
 *    Copyright IBM Corp. 1999, 2000
 *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
 */
#ifndef _S390_PTRACE_H
#define _S390_PTRACE_H

#include <linux/bits.h>
#include <uapi/asm/ptrace.h>
#include <asm/tpi.h>

#define PIF_SYSCALL		0	/* inside a system call */
#define PIF_SYSCALL_RESTART	1	/* restart the current system call */
#define PIF_SYSCALL_RET_SET	2	/* return value was set via ptrace */
#define PIF_GUEST_FAULT		3	/* indicates program check in sie64a */

#define _PIF_SYSCALL		BIT(PIF_SYSCALL)
#define _PIF_SYSCALL_RESTART	BIT(PIF_SYSCALL_RESTART)
#define _PIF_SYSCALL_RET_SET	BIT(PIF_SYSCALL_RET_SET)
#define _PIF_GUEST_FAULT	BIT(PIF_GUEST_FAULT)

#ifndef __ASSEMBLY__

#define PSW_KERNEL_BITS	(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_HOME | \
			 PSW_MASK_EA | PSW_MASK_BA)
#define PSW_USER_BITS	(PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
			 PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_MCHECK | \
			 PSW_MASK_PSTATE | PSW_ASC_PRIMARY)

struct psw_bits {
	unsigned long	     :	1;
	unsigned long per    :	1; /* PER-Mask */
	unsigned long	     :	3;
	unsigned long dat    :	1; /* DAT Mode */
	unsigned long io     :	1; /* Input/Output Mask */
	unsigned long ext    :	1; /* External Mask */
	unsigned long key    :	4; /* PSW Key */
	unsigned long	     :	1;
	unsigned long mcheck :	1; /* Machine-Check Mask */
	unsigned long wait   :	1; /* Wait State */
	unsigned long pstate :	1; /* Problem State */
	unsigned long as     :	2; /* Address Space Control */
	unsigned long cc     :	2; /* Condition Code */
	unsigned long pm     :	4; /* Program Mask */
	unsigned long ri     :	1; /* Runtime Instrumentation */
	unsigned long	     :	6;
	unsigned long eaba   :	2; /* Addressing Mode */
	unsigned long	     : 31;
	unsigned long ia     : 64; /* Instruction Address */
};

enum {
	PSW_BITS_AMODE_24BIT = 0,
	PSW_BITS_AMODE_31BIT = 1,
	PSW_BITS_AMODE_64BIT = 3
};

enum {
	PSW_BITS_AS_PRIMARY	= 0,
	PSW_BITS_AS_ACCREG	= 1,
	PSW_BITS_AS_SECONDARY	= 2,
	PSW_BITS_AS_HOME	= 3
};

#define psw_bits(__psw) (*({			\
	typecheck(psw_t, __psw);		\
	&(*(struct psw_bits *)(&(__psw)));	\
}))

#define PGM_INT_CODE_MASK	0x7f
#define PGM_INT_CODE_PER	0x80

/*
 * The pt_regs struct defines the way the registers are stored on
 * the stack during a system call.
 */
struct pt_regs 
{
	union {
		user_pt_regs user_regs;
		struct {
			unsigned long args[1];
			psw_t psw;
			unsigned long gprs[NUM_GPRS];
		};
	};
	unsigned long orig_gpr2;
	union {
		struct {
			unsigned int int_code;
			unsigned int int_parm;
			unsigned long int_parm_long;
		};
		struct tpi_info tpi_info;
	};
	unsigned long flags;
	unsigned long cr1;
};

/*
 * Program event recording (PER) register set.
 */
struct per_regs {
	unsigned long control;		/* PER control bits */
	unsigned long start;		/* PER starting address */
	unsigned long end;		/* PER ending address */
};

/*
 * PER event contains information about the cause of the last PER exception.
 */
struct per_event {
	unsigned short cause;		/* PER code, ATMID and AI */
	unsigned long address;		/* PER address */
	unsigned char paid;		/* PER access identification */
};

/*
 * Simplified per_info structure used to decode the ptrace user space ABI.
 */
struct per_struct_kernel {
	unsigned long cr9;		/* PER control bits */
	unsigned long cr10;		/* PER starting address */
	unsigned long cr11;		/* PER ending address */
	unsigned long bits;		/* Obsolete software bits */
	unsigned long starting_addr;	/* User specified start address */
	unsigned long ending_addr;	/* User specified end address */
	unsigned short perc_atmid;	/* PER trap ATMID */
	unsigned long address;		/* PER trap instruction address */
	unsigned char access_id;	/* PER trap access identification */
};

#define PER_EVENT_MASK			0xEB000000UL

#define PER_EVENT_BRANCH		0x80000000UL
#define PER_EVENT_IFETCH		0x40000000UL
#define PER_EVENT_STORE			0x20000000UL
#define PER_EVENT_STORE_REAL		0x08000000UL
#define PER_EVENT_TRANSACTION_END	0x02000000UL
#define PER_EVENT_NULLIFICATION		0x01000000UL

#define PER_CONTROL_MASK		0x00e00000UL

#define PER_CONTROL_BRANCH_ADDRESS	0x00800000UL
#define PER_CONTROL_SUSPENSION		0x00400000UL
#define PER_CONTROL_ALTERATION		0x00200000UL

static inline void set_pt_regs_flag(struct pt_regs *regs, int flag)
{
	regs->flags |= (1UL << flag);
}

static inline void clear_pt_regs_flag(struct pt_regs *regs, int flag)
{
	regs->flags &= ~(1UL << flag);
}

static inline int test_pt_regs_flag(struct pt_regs *regs, int flag)
{
	return !!(regs->flags & (1UL << flag));
}

static inline int test_and_clear_pt_regs_flag(struct pt_regs *regs, int flag)
{
	int ret = test_pt_regs_flag(regs, flag);

	clear_pt_regs_flag(regs, flag);
	return ret;
}

/*
 * These are defined as per linux/ptrace.h, which see.
 */
#define arch_has_single_step()	(1)
#define arch_has_block_step()	(1)

#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr)
#define user_stack_pointer(regs)((regs)->gprs[15])
#define profile_pc(regs) instruction_pointer(regs)

static inline long regs_return_value(struct pt_regs *regs)
{
	return regs->gprs[2];
}

static inline void instruction_pointer_set(struct pt_regs *regs,
					   unsigned long val)
{
	regs->psw.addr = val;
}

int regs_query_register_offset(const char *name);
const char *regs_query_register_name(unsigned int offset);
unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset);
unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n);

static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
{
	return regs->gprs[15];
}

static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
{
	regs->gprs[2] = rc;
}

#endif /* __ASSEMBLY__ */
#endif /* _S390_PTRACE_H */