aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/include/asm/ptrace.h
blob: 8bae33ab320ac154fc6cb28a537877b90cfd8e0d (plain) (blame)
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/* 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_EXECVE_PGSTE_RESTART	1	/* restart execve for PGSTE binaries */
#define PIF_SYSCALL_RET_SET		2	/* return value was set via ptrace */
#define PIF_GUEST_FAULT			3	/* indicates program check in sie64a */
#define PIF_FTRACE_FULL_REGS		4	/* all register contents valid (ftrace) */

#define _PIF_SYSCALL			BIT(PIF_SYSCALL)
#define _PIF_EXECVE_PGSTE_RESTART	BIT(PIF_EXECVE_PGSTE_RESTART)
#define _PIF_SYSCALL_RET_SET		BIT(PIF_SYSCALL_RET_SET)
#define _PIF_GUEST_FAULT		BIT(PIF_GUEST_FAULT)
#define _PIF_FTRACE_FULL_REGS		BIT(PIF_FTRACE_FULL_REGS)

#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 PSW32_MASK_PER		0x40000000UL
#define PSW32_MASK_DAT		0x04000000UL
#define PSW32_MASK_IO		0x02000000UL
#define PSW32_MASK_EXT		0x01000000UL
#define PSW32_MASK_KEY		0x00F00000UL
#define PSW32_MASK_BASE		0x00080000UL	/* Always one */
#define PSW32_MASK_MCHECK	0x00040000UL
#define PSW32_MASK_WAIT		0x00020000UL
#define PSW32_MASK_PSTATE	0x00010000UL
#define PSW32_MASK_ASC		0x0000C000UL
#define PSW32_MASK_CC		0x00003000UL
#define PSW32_MASK_PM		0x00000f00UL
#define PSW32_MASK_RI		0x00000080UL

#define PSW32_ADDR_AMODE	0x80000000UL
#define PSW32_ADDR_INSN		0x7FFFFFFFUL

#define PSW32_DEFAULT_KEY	(((u32)PAGE_DEFAULT_ACC) << 20)

#define PSW32_ASC_PRIMARY	0x00000000UL
#define PSW32_ASC_ACCREG	0x00004000UL
#define PSW32_ASC_SECONDARY	0x00008000UL
#define PSW32_ASC_HOME		0x0000C000UL

typedef struct {
	unsigned int mask;
	unsigned int addr;
} psw_t32 __aligned(8);

#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;
	unsigned long last_break;
};

/*
 * 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);

/**
 * regs_get_kernel_argument() - get Nth function argument in kernel
 * @regs:	pt_regs of that context
 * @n:		function argument number (start from 0)
 *
 * regs_get_kernel_argument() returns @n th argument of the function call.
 */
static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
						     unsigned int n)
{
	unsigned int argoffset = STACK_FRAME_OVERHEAD / sizeof(long);

#define NR_REG_ARGUMENTS 5
	if (n < NR_REG_ARGUMENTS)
		return regs_get_register(regs, 2 + n);
	n -= NR_REG_ARGUMENTS;
	return regs_get_kernel_stack_nth(regs, argoffset + 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 */