Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
regset.h
Go to the documentation of this file.
1 /*
2  * User-mode machine state access
3  *
4  * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
5  *
6  * This copyrighted material is made available to anyone wishing to use,
7  * modify, copy, or redistribute it subject to the terms and conditions
8  * of the GNU General Public License v.2.
9  *
10  * Red Hat Author: Roland McGrath.
11  */
12 
13 #ifndef _LINUX_REGSET_H
14 #define _LINUX_REGSET_H 1
15 
16 #include <linux/compiler.h>
17 #include <linux/types.h>
18 #include <linux/bug.h>
19 #include <linux/uaccess.h>
20 struct task_struct;
21 struct user_regset;
22 
23 
40  const struct user_regset *regset);
41 
59  const struct user_regset *regset,
60  unsigned int pos, unsigned int count,
61  void *kbuf, void __user *ubuf);
62 
80  const struct user_regset *regset,
81  unsigned int pos, unsigned int count,
82  const void *kbuf, const void __user *ubuf);
83 
106  const struct user_regset *regset,
107  int immediate);
108 
154 struct user_regset {
159  unsigned int n;
160  unsigned int size;
161  unsigned int align;
162  unsigned int bias;
163  unsigned int core_note_type;
164 };
165 
185  const char *name;
186  const struct user_regset *regsets;
187  unsigned int n;
191 };
192 
193 /*
194  * This is documented here rather than at the definition sites because its
195  * implementation is machine-dependent but its interface is universal.
196  */
205 const struct user_regset_view *task_user_regset_view(struct task_struct *tsk);
206 
207 
208 /*
209  * These are helpers for writing regset get/set functions in arch code.
210  * Because @start_pos and @end_pos are always compile-time constants,
211  * these are inlined into very little code though they look large.
212  *
213  * Use one or more calls sequentially for each chunk of regset data stored
214  * contiguously in memory. Call with constants for @start_pos and @end_pos,
215  * giving the range of byte positions in the regset that data corresponds
216  * to; @end_pos can be -1 if this chunk is at the end of the regset layout.
217  * Each call updates the arguments to point past its chunk.
218  */
219 
220 static inline int user_regset_copyout(unsigned int *pos, unsigned int *count,
221  void **kbuf,
222  void __user **ubuf, const void *data,
223  const int start_pos, const int end_pos)
224 {
225  if (*count == 0)
226  return 0;
227  BUG_ON(*pos < start_pos);
228  if (end_pos < 0 || *pos < end_pos) {
229  unsigned int copy = (end_pos < 0 ? *count
230  : min(*count, end_pos - *pos));
231  data += *pos - start_pos;
232  if (*kbuf) {
233  memcpy(*kbuf, data, copy);
234  *kbuf += copy;
235  } else if (__copy_to_user(*ubuf, data, copy))
236  return -EFAULT;
237  else
238  *ubuf += copy;
239  *pos += copy;
240  *count -= copy;
241  }
242  return 0;
243 }
244 
245 static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
246  const void **kbuf,
247  const void __user **ubuf, void *data,
248  const int start_pos, const int end_pos)
249 {
250  if (*count == 0)
251  return 0;
252  BUG_ON(*pos < start_pos);
253  if (end_pos < 0 || *pos < end_pos) {
254  unsigned int copy = (end_pos < 0 ? *count
255  : min(*count, end_pos - *pos));
256  data += *pos - start_pos;
257  if (*kbuf) {
258  memcpy(data, *kbuf, copy);
259  *kbuf += copy;
260  } else if (__copy_from_user(data, *ubuf, copy))
261  return -EFAULT;
262  else
263  *ubuf += copy;
264  *pos += copy;
265  *count -= copy;
266  }
267  return 0;
268 }
269 
270 /*
271  * These two parallel the two above, but for portions of a regset layout
272  * that always read as all-zero or for which writes are ignored.
273  */
274 static inline int user_regset_copyout_zero(unsigned int *pos,
275  unsigned int *count,
276  void **kbuf, void __user **ubuf,
277  const int start_pos,
278  const int end_pos)
279 {
280  if (*count == 0)
281  return 0;
282  BUG_ON(*pos < start_pos);
283  if (end_pos < 0 || *pos < end_pos) {
284  unsigned int copy = (end_pos < 0 ? *count
285  : min(*count, end_pos - *pos));
286  if (*kbuf) {
287  memset(*kbuf, 0, copy);
288  *kbuf += copy;
289  } else if (__clear_user(*ubuf, copy))
290  return -EFAULT;
291  else
292  *ubuf += copy;
293  *pos += copy;
294  *count -= copy;
295  }
296  return 0;
297 }
298 
299 static inline int user_regset_copyin_ignore(unsigned int *pos,
300  unsigned int *count,
301  const void **kbuf,
302  const void __user **ubuf,
303  const int start_pos,
304  const int end_pos)
305 {
306  if (*count == 0)
307  return 0;
308  BUG_ON(*pos < start_pos);
309  if (end_pos < 0 || *pos < end_pos) {
310  unsigned int copy = (end_pos < 0 ? *count
311  : min(*count, end_pos - *pos));
312  if (*kbuf)
313  *kbuf += copy;
314  else
315  *ubuf += copy;
316  *pos += copy;
317  *count -= copy;
318  }
319  return 0;
320 }
321 
331 static inline int copy_regset_to_user(struct task_struct *target,
332  const struct user_regset_view *view,
333  unsigned int setno,
334  unsigned int offset, unsigned int size,
335  void __user *data)
336 {
337  const struct user_regset *regset = &view->regsets[setno];
338 
339  if (!regset->get)
340  return -EOPNOTSUPP;
341 
342  if (!access_ok(VERIFY_WRITE, data, size))
343  return -EFAULT;
344 
345  return regset->get(target, regset, offset, size, NULL, data);
346 }
347 
357 static inline int copy_regset_from_user(struct task_struct *target,
358  const struct user_regset_view *view,
359  unsigned int setno,
360  unsigned int offset, unsigned int size,
361  const void __user *data)
362 {
363  const struct user_regset *regset = &view->regsets[setno];
364 
365  if (!regset->set)
366  return -EOPNOTSUPP;
367 
368  if (!access_ok(VERIFY_READ, data, size))
369  return -EFAULT;
370 
371  return regset->set(target, regset, offset, size, NULL, data);
372 }
373 
374 
375 #endif /* <linux/regset.h> */