Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * User-mode machine state access
4 : *
5 : * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
6 : *
7 : * Red Hat Author: Roland McGrath.
8 : */
9 :
10 : #ifndef _LINUX_REGSET_H
11 : #define _LINUX_REGSET_H 1
12 :
13 : #include <linux/compiler.h>
14 : #include <linux/types.h>
15 : #include <linux/bug.h>
16 : #include <linux/uaccess.h>
17 : struct task_struct;
18 : struct user_regset;
19 :
20 : struct membuf {
21 : void *p;
22 : size_t left;
23 : };
24 :
25 : static inline int membuf_zero(struct membuf *s, size_t size)
26 : {
27 : if (s->left) {
28 : if (size > s->left)
29 : size = s->left;
30 : memset(s->p, 0, size);
31 : s->p += size;
32 : s->left -= size;
33 : }
34 : return s->left;
35 : }
36 :
37 0 : static inline int membuf_write(struct membuf *s, const void *v, size_t size)
38 : {
39 0 : if (s->left) {
40 0 : if (size > s->left)
41 : size = s->left;
42 0 : memcpy(s->p, v, size);
43 0 : s->p += size;
44 0 : s->left -= size;
45 : }
46 0 : return s->left;
47 : }
48 :
49 : static inline struct membuf membuf_at(const struct membuf *s, size_t offs)
50 : {
51 : struct membuf n = *s;
52 :
53 : if (offs > n.left)
54 : offs = n.left;
55 : n.p += offs;
56 : n.left -= offs;
57 :
58 : return n;
59 : }
60 :
61 : /* current s->p must be aligned for v; v must be a scalar */
62 : #define membuf_store(s, v) \
63 : ({ \
64 : struct membuf *__s = (s); \
65 : if (__s->left) { \
66 : typeof(v) __v = (v); \
67 : size_t __size = sizeof(__v); \
68 : if (unlikely(__size > __s->left)) { \
69 : __size = __s->left; \
70 : memcpy(__s->p, &__v, __size); \
71 : } else { \
72 : *(typeof(__v + 0) *)__s->p = __v; \
73 : } \
74 : __s->p += __size; \
75 : __s->left -= __size; \
76 : } \
77 : __s->left;})
78 :
79 : /**
80 : * user_regset_active_fn - type of @active function in &struct user_regset
81 : * @target: thread being examined
82 : * @regset: regset being examined
83 : *
84 : * Return -%ENODEV if not available on the hardware found.
85 : * Return %0 if no interesting state in this thread.
86 : * Return >%0 number of @size units of interesting state.
87 : * Any get call fetching state beyond that number will
88 : * see the default initialization state for this data,
89 : * so a caller that knows what the default state is need
90 : * not copy it all out.
91 : * This call is optional; the pointer is %NULL if there
92 : * is no inexpensive check to yield a value < @n.
93 : */
94 : typedef int user_regset_active_fn(struct task_struct *target,
95 : const struct user_regset *regset);
96 :
97 : typedef int user_regset_get2_fn(struct task_struct *target,
98 : const struct user_regset *regset,
99 : struct membuf to);
100 :
101 : /**
102 : * user_regset_set_fn - type of @set function in &struct user_regset
103 : * @target: thread being examined
104 : * @regset: regset being examined
105 : * @pos: offset into the regset data to access, in bytes
106 : * @count: amount of data to copy, in bytes
107 : * @kbuf: if not %NULL, a kernel-space pointer to copy from
108 : * @ubuf: if @kbuf is %NULL, a user-space pointer to copy from
109 : *
110 : * Store register values. Return %0 on success; -%EIO or -%ENODEV
111 : * are usual failure returns. The @pos and @count values are in
112 : * bytes, but must be properly aligned. If @kbuf is non-null, that
113 : * buffer is used and @ubuf is ignored. If @kbuf is %NULL, then
114 : * ubuf gives a userland pointer to access directly, and an -%EFAULT
115 : * return value is possible.
116 : */
117 : typedef int user_regset_set_fn(struct task_struct *target,
118 : const struct user_regset *regset,
119 : unsigned int pos, unsigned int count,
120 : const void *kbuf, const void __user *ubuf);
121 :
122 : /**
123 : * user_regset_writeback_fn - type of @writeback function in &struct user_regset
124 : * @target: thread being examined
125 : * @regset: regset being examined
126 : * @immediate: zero if writeback at completion of next context switch is OK
127 : *
128 : * This call is optional; usually the pointer is %NULL. When
129 : * provided, there is some user memory associated with this regset's
130 : * hardware, such as memory backing cached register data on register
131 : * window machines; the regset's data controls what user memory is
132 : * used (e.g. via the stack pointer value).
133 : *
134 : * Write register data back to user memory. If the @immediate flag
135 : * is nonzero, it must be written to the user memory so uaccess or
136 : * access_process_vm() can see it when this call returns; if zero,
137 : * then it must be written back by the time the task completes a
138 : * context switch (as synchronized with wait_task_inactive()).
139 : * Return %0 on success or if there was nothing to do, -%EFAULT for
140 : * a memory problem (bad stack pointer or whatever), or -%EIO for a
141 : * hardware problem.
142 : */
143 : typedef int user_regset_writeback_fn(struct task_struct *target,
144 : const struct user_regset *regset,
145 : int immediate);
146 :
147 : /**
148 : * struct user_regset - accessible thread CPU state
149 : * @n: Number of slots (registers).
150 : * @size: Size in bytes of a slot (register).
151 : * @align: Required alignment, in bytes.
152 : * @bias: Bias from natural indexing.
153 : * @core_note_type: ELF note @n_type value used in core dumps.
154 : * @get: Function to fetch values.
155 : * @set: Function to store values.
156 : * @active: Function to report if regset is active, or %NULL.
157 : * @writeback: Function to write data back to user memory, or %NULL.
158 : *
159 : * This data structure describes a machine resource we call a register set.
160 : * This is part of the state of an individual thread, not necessarily
161 : * actual CPU registers per se. A register set consists of a number of
162 : * similar slots, given by @n. Each slot is @size bytes, and aligned to
163 : * @align bytes (which is at least @size). For dynamically-sized
164 : * regsets, @n must contain the maximum possible number of slots for the
165 : * regset.
166 : *
167 : * For backward compatibility, the @get and @set methods must pad to, or
168 : * accept, @n * @size bytes, even if the current regset size is smaller.
169 : * The precise semantics of these operations depend on the regset being
170 : * accessed.
171 : *
172 : * The functions to which &struct user_regset members point must be
173 : * called only on the current thread or on a thread that is in
174 : * %TASK_STOPPED or %TASK_TRACED state, that we are guaranteed will not
175 : * be woken up and return to user mode, and that we have called
176 : * wait_task_inactive() on. (The target thread always might wake up for
177 : * SIGKILL while these functions are working, in which case that
178 : * thread's user_regset state might be scrambled.)
179 : *
180 : * The @pos argument must be aligned according to @align; the @count
181 : * argument must be a multiple of @size. These functions are not
182 : * responsible for checking for invalid arguments.
183 : *
184 : * When there is a natural value to use as an index, @bias gives the
185 : * difference between the natural index and the slot index for the
186 : * register set. For example, x86 GDT segment descriptors form a regset;
187 : * the segment selector produces a natural index, but only a subset of
188 : * that index space is available as a regset (the TLS slots); subtracting
189 : * @bias from a segment selector index value computes the regset slot.
190 : *
191 : * If nonzero, @core_note_type gives the n_type field (NT_* value)
192 : * of the core file note in which this regset's data appears.
193 : * NT_PRSTATUS is a special case in that the regset data starts at
194 : * offsetof(struct elf_prstatus, pr_reg) into the note data; that is
195 : * part of the per-machine ELF formats userland knows about. In
196 : * other cases, the core file note contains exactly the whole regset
197 : * (@n * @size) and nothing else. The core file note is normally
198 : * omitted when there is an @active function and it returns zero.
199 : */
200 : struct user_regset {
201 : user_regset_get2_fn *regset_get;
202 : user_regset_set_fn *set;
203 : user_regset_active_fn *active;
204 : user_regset_writeback_fn *writeback;
205 : unsigned int n;
206 : unsigned int size;
207 : unsigned int align;
208 : unsigned int bias;
209 : unsigned int core_note_type;
210 : };
211 :
212 : /**
213 : * struct user_regset_view - available regsets
214 : * @name: Identifier, e.g. UTS_MACHINE string.
215 : * @regsets: Array of @n regsets available in this view.
216 : * @n: Number of elements in @regsets.
217 : * @e_machine: ELF header @e_machine %EM_* value written in core dumps.
218 : * @e_flags: ELF header @e_flags value written in core dumps.
219 : * @ei_osabi: ELF header @e_ident[%EI_OSABI] value written in core dumps.
220 : *
221 : * A regset view is a collection of regsets (&struct user_regset,
222 : * above). This describes all the state of a thread that can be seen
223 : * from a given architecture/ABI environment. More than one view might
224 : * refer to the same &struct user_regset, or more than one regset
225 : * might refer to the same machine-specific state in the thread. For
226 : * example, a 32-bit thread's state could be examined from the 32-bit
227 : * view or from the 64-bit view. Either method reaches the same thread
228 : * register state, doing appropriate widening or truncation.
229 : */
230 : struct user_regset_view {
231 : const char *name;
232 : const struct user_regset *regsets;
233 : unsigned int n;
234 : u32 e_flags;
235 : u16 e_machine;
236 : u8 ei_osabi;
237 : };
238 :
239 : /*
240 : * This is documented here rather than at the definition sites because its
241 : * implementation is machine-dependent but its interface is universal.
242 : */
243 : /**
244 : * task_user_regset_view - Return the process's native regset view.
245 : * @tsk: a thread of the process in question
246 : *
247 : * Return the &struct user_regset_view that is native for the given process.
248 : * For example, what it would access when it called ptrace().
249 : * Throughout the life of the process, this only changes at exec.
250 : */
251 : const struct user_regset_view *task_user_regset_view(struct task_struct *tsk);
252 :
253 0 : static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
254 : const void **kbuf,
255 : const void __user **ubuf, void *data,
256 : const int start_pos, const int end_pos)
257 : {
258 0 : if (*count == 0)
259 : return 0;
260 0 : BUG_ON(*pos < start_pos);
261 0 : if (end_pos < 0 || *pos < end_pos) {
262 0 : unsigned int copy = (end_pos < 0 ? *count
263 0 : : min(*count, end_pos - *pos));
264 0 : data += *pos - start_pos;
265 0 : if (*kbuf) {
266 0 : memcpy(data, *kbuf, copy);
267 0 : *kbuf += copy;
268 0 : } else if (__copy_from_user(data, *ubuf, copy))
269 : return -EFAULT;
270 : else
271 0 : *ubuf += copy;
272 0 : *pos += copy;
273 0 : *count -= copy;
274 : }
275 : return 0;
276 : }
277 :
278 : static inline int user_regset_copyin_ignore(unsigned int *pos,
279 : unsigned int *count,
280 : const void **kbuf,
281 : const void __user **ubuf,
282 : const int start_pos,
283 : const int end_pos)
284 : {
285 : if (*count == 0)
286 : return 0;
287 : BUG_ON(*pos < start_pos);
288 : if (end_pos < 0 || *pos < end_pos) {
289 : unsigned int copy = (end_pos < 0 ? *count
290 : : min(*count, end_pos - *pos));
291 : if (*kbuf)
292 : *kbuf += copy;
293 : else
294 : *ubuf += copy;
295 : *pos += copy;
296 : *count -= copy;
297 : }
298 : return 0;
299 : }
300 :
301 : extern int regset_get(struct task_struct *target,
302 : const struct user_regset *regset,
303 : unsigned int size, void *data);
304 :
305 : extern int regset_get_alloc(struct task_struct *target,
306 : const struct user_regset *regset,
307 : unsigned int size,
308 : void **data);
309 :
310 : extern int copy_regset_to_user(struct task_struct *target,
311 : const struct user_regset_view *view,
312 : unsigned int setno, unsigned int offset,
313 : unsigned int size, void __user *data);
314 :
315 : /**
316 : * copy_regset_from_user - store into thread's user_regset data from user memory
317 : * @target: thread to be examined
318 : * @view: &struct user_regset_view describing user thread machine state
319 : * @setno: index in @view->regsets
320 : * @offset: offset into the regset data, in bytes
321 : * @size: amount of data to copy, in bytes
322 : * @data: user-mode pointer to copy from
323 : */
324 0 : static inline int copy_regset_from_user(struct task_struct *target,
325 : const struct user_regset_view *view,
326 : unsigned int setno,
327 : unsigned int offset, unsigned int size,
328 : const void __user *data)
329 : {
330 0 : const struct user_regset *regset = &view->regsets[setno];
331 :
332 0 : if (!regset->set)
333 : return -EOPNOTSUPP;
334 :
335 0 : if (!access_ok(data, size))
336 : return -EFAULT;
337 :
338 0 : return regset->set(target, regset, offset, size, NULL, data);
339 : }
340 :
341 : #endif /* <linux/regset.h> */
|