Skip to content

Commit 7ce8716

Browse files
mjeansonstffrdhrn
authored andcommitted
openrisc: Add HAVE_REGS_AND_STACK_ACCESS_API support
Support for HAVE_REGS_AND_STACK_ACCESS_API needed for restartable sequences. The implementation has been copied from riscv and tested with the restartable sequences self tests. Note, pt-regs members are 'long' on openrisc which require casts for the api, someday we should try to update these to be 'unsigned long' as that's what they really are. Signed-off-by: Michael Jeanson <[email protected]> [stafford: Updated commit message] Signed-off-by: Stafford Horne <[email protected]>
1 parent 134502a commit 7ce8716

File tree

3 files changed

+169
-1
lines changed

3 files changed

+169
-1
lines changed

arch/openrisc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ config OPENRISC
2727
select HAVE_PCI
2828
select HAVE_UID16
2929
select HAVE_PAGE_SIZE_8KB
30+
select HAVE_REGS_AND_STACK_ACCESS_API
3031
select GENERIC_ATOMIC64
3132
select GENERIC_CLOCKEVENTS_BROADCAST
3233
select GENERIC_SMP_IDLE_THREAD

arch/openrisc/include/asm/ptrace.h

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <asm/spr_defs.h>
1919
#include <uapi/asm/ptrace.h>
20+
#include <linux/compiler.h>
2021

2122
/*
2223
* Make kernel PTrace/register structures opaque to userspace... userspace can
@@ -42,6 +43,36 @@ struct pt_regs {
4243
/* Named registers */
4344
long sr; /* Stored in place of r0 */
4445
long sp; /* r1 */
46+
long gpr2;
47+
long gpr3;
48+
long gpr4;
49+
long gpr5;
50+
long gpr6;
51+
long gpr7;
52+
long gpr8;
53+
long gpr9;
54+
long gpr10;
55+
long gpr11;
56+
long gpr12;
57+
long gpr13;
58+
long gpr14;
59+
long gpr15;
60+
long gpr16;
61+
long gpr17;
62+
long gpr18;
63+
long gpr19;
64+
long gpr20;
65+
long gpr21;
66+
long gpr22;
67+
long gpr23;
68+
long gpr24;
69+
long gpr25;
70+
long gpr26;
71+
long gpr27;
72+
long gpr28;
73+
long gpr29;
74+
long gpr30;
75+
long gpr31;
4576
};
4677
struct {
4778
/* Old style */
@@ -66,16 +97,56 @@ struct pt_regs {
6697
/* TODO: Rename this to REDZONE because that's what it is */
6798
#define STACK_FRAME_OVERHEAD 128 /* size of minimum stack frame */
6899

69-
#define instruction_pointer(regs) ((regs)->pc)
100+
#define MAX_REG_OFFSET offsetof(struct pt_regs, orig_gpr11)
101+
102+
/* Helpers for working with the instruction pointer */
103+
static inline unsigned long instruction_pointer(struct pt_regs *regs)
104+
{
105+
return (unsigned long)regs->pc;
106+
}
107+
static inline void instruction_pointer_set(struct pt_regs *regs,
108+
unsigned long val)
109+
{
110+
regs->pc = val;
111+
}
112+
70113
#define user_mode(regs) (((regs)->sr & SPR_SR_SM) == 0)
71114
#define user_stack_pointer(regs) ((unsigned long)(regs)->sp)
72115
#define profile_pc(regs) instruction_pointer(regs)
73116

117+
/* Valid only for Kernel mode traps. */
118+
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
119+
{
120+
return (unsigned long)regs->sp;
121+
}
122+
74123
static inline long regs_return_value(struct pt_regs *regs)
75124
{
76125
return regs->gpr[11];
77126
}
78127

128+
extern int regs_query_register_offset(const char *name);
129+
extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
130+
unsigned int n);
131+
132+
/**
133+
* regs_get_register() - get register value from its offset
134+
* @regs: pt_regs from which register value is gotten
135+
* @offset: offset of the register.
136+
*
137+
* regs_get_register returns the value of a register whose offset from @regs.
138+
* The @offset is the offset of the register in struct pt_regs.
139+
* If @offset is bigger than MAX_REG_OFFSET, this returns 0.
140+
*/
141+
static inline unsigned long regs_get_register(struct pt_regs *regs,
142+
unsigned int offset)
143+
{
144+
if (unlikely(offset > MAX_REG_OFFSET))
145+
return 0;
146+
147+
return *(unsigned long *)((unsigned long)regs + offset);
148+
}
149+
79150
#endif /* __ASSEMBLY__ */
80151

81152
/*

arch/openrisc/kernel/ptrace.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,102 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
160160
* in exit.c or in signal.c.
161161
*/
162162

163+
struct pt_regs_offset {
164+
const char *name;
165+
int offset;
166+
};
167+
168+
#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
169+
#define REG_OFFSET_END {.name = NULL, .offset = 0}
170+
171+
static const struct pt_regs_offset regoffset_table[] = {
172+
REG_OFFSET_NAME(sr),
173+
REG_OFFSET_NAME(sp),
174+
REG_OFFSET_NAME(gpr2),
175+
REG_OFFSET_NAME(gpr3),
176+
REG_OFFSET_NAME(gpr4),
177+
REG_OFFSET_NAME(gpr5),
178+
REG_OFFSET_NAME(gpr6),
179+
REG_OFFSET_NAME(gpr7),
180+
REG_OFFSET_NAME(gpr8),
181+
REG_OFFSET_NAME(gpr9),
182+
REG_OFFSET_NAME(gpr10),
183+
REG_OFFSET_NAME(gpr11),
184+
REG_OFFSET_NAME(gpr12),
185+
REG_OFFSET_NAME(gpr13),
186+
REG_OFFSET_NAME(gpr14),
187+
REG_OFFSET_NAME(gpr15),
188+
REG_OFFSET_NAME(gpr16),
189+
REG_OFFSET_NAME(gpr17),
190+
REG_OFFSET_NAME(gpr18),
191+
REG_OFFSET_NAME(gpr19),
192+
REG_OFFSET_NAME(gpr20),
193+
REG_OFFSET_NAME(gpr21),
194+
REG_OFFSET_NAME(gpr22),
195+
REG_OFFSET_NAME(gpr23),
196+
REG_OFFSET_NAME(gpr24),
197+
REG_OFFSET_NAME(gpr25),
198+
REG_OFFSET_NAME(gpr26),
199+
REG_OFFSET_NAME(gpr27),
200+
REG_OFFSET_NAME(gpr28),
201+
REG_OFFSET_NAME(gpr29),
202+
REG_OFFSET_NAME(gpr30),
203+
REG_OFFSET_NAME(gpr31),
204+
REG_OFFSET_NAME(pc),
205+
REG_OFFSET_NAME(orig_gpr11),
206+
REG_OFFSET_END,
207+
};
208+
209+
/**
210+
* regs_query_register_offset() - query register offset from its name
211+
* @name: the name of a register
212+
*
213+
* regs_query_register_offset() returns the offset of a register in struct
214+
* pt_regs from its name. If the name is invalid, this returns -EINVAL;
215+
*/
216+
int regs_query_register_offset(const char *name)
217+
{
218+
const struct pt_regs_offset *roff;
219+
220+
for (roff = regoffset_table; roff->name != NULL; roff++)
221+
if (!strcmp(roff->name, name))
222+
return roff->offset;
223+
return -EINVAL;
224+
}
225+
226+
/**
227+
* regs_within_kernel_stack() - check the address in the stack
228+
* @regs: pt_regs which contains kernel stack pointer.
229+
* @addr: address which is checked.
230+
*
231+
* regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
232+
* If @addr is within the kernel stack, it returns true. If not, returns false.
233+
*/
234+
static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
235+
{
236+
return (addr & ~(THREAD_SIZE - 1)) ==
237+
(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
238+
}
239+
240+
/**
241+
* regs_get_kernel_stack_nth() - get Nth entry of the stack
242+
* @regs: pt_regs which contains kernel stack pointer.
243+
* @n: stack entry number.
244+
*
245+
* regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
246+
* is specified by @regs. If the @n th entry is NOT in the kernel stack,
247+
* this returns 0.
248+
*/
249+
unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
250+
{
251+
unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
252+
253+
addr += n;
254+
if (regs_within_kernel_stack(regs, (unsigned long)addr))
255+
return *addr;
256+
else
257+
return 0;
258+
}
163259

164260
/*
165261
* Called by kernel/ptrace.c when detaching..

0 commit comments

Comments
 (0)