Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 80055
b: refs/heads/master
c: bae3f7c
h: refs/heads/master
i:
  80053: 85fa1a2
  80051: 33d9d53
  80047: 0666626
v: v3
  • Loading branch information
Roland McGrath authored and Ingo Molnar committed Jan 30, 2008
1 parent 2352240 commit 8b2b27a
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4206d3aa1978e44f58bfa4e1c9d8d35cbf19c187
refs/heads/master: bae3f7c39dee5951bcbedeaedb6744f882a00173
116 changes: 116 additions & 0 deletions trunk/include/linux/regset.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/uaccess.h>
struct task_struct;
struct user_regset;

Expand Down Expand Up @@ -203,4 +204,119 @@ struct user_regset_view {
const struct user_regset_view *task_user_regset_view(struct task_struct *tsk);


/*
* These are helpers for writing regset get/set functions in arch code.
* Because @start_pos and @end_pos are always compile-time constants,
* these are inlined into very little code though they look large.
*
* Use one or more calls sequentially for each chunk of regset data stored
* contiguously in memory. Call with constants for @start_pos and @end_pos,
* giving the range of byte positions in the regset that data corresponds
* to; @end_pos can be -1 if this chunk is at the end of the regset layout.
* Each call updates the arguments to point past its chunk.
*/

static inline int user_regset_copyout(unsigned int *pos, unsigned int *count,
void **kbuf,
void __user **ubuf, const void *data,
const int start_pos, const int end_pos)
{
if (*count == 0)
return 0;
BUG_ON(*pos < start_pos);
if (end_pos < 0 || *pos < end_pos) {
unsigned int copy = (end_pos < 0 ? *count
: min(*count, end_pos - *pos));
data += *pos - start_pos;
if (*kbuf) {
memcpy(*kbuf, data, copy);
*kbuf += copy;
} else if (__copy_to_user(*ubuf, data, copy))
return -EFAULT;
else
*ubuf += copy;
*pos += copy;
*count -= copy;
}
return 0;
}

static inline int user_regset_copyin(unsigned int *pos, unsigned int *count,
const void **kbuf,
const void __user **ubuf, void *data,
const int start_pos, const int end_pos)
{
if (*count == 0)
return 0;
BUG_ON(*pos < start_pos);
if (end_pos < 0 || *pos < end_pos) {
unsigned int copy = (end_pos < 0 ? *count
: min(*count, end_pos - *pos));
data += *pos - start_pos;
if (*kbuf) {
memcpy(data, *kbuf, copy);
*kbuf += copy;
} else if (__copy_from_user(data, *ubuf, copy))
return -EFAULT;
else
*ubuf += copy;
*pos += copy;
*count -= copy;
}
return 0;
}

/*
* These two parallel the two above, but for portions of a regset layout
* that always read as all-zero or for which writes are ignored.
*/
static inline int user_regset_copyout_zero(unsigned int *pos,
unsigned int *count,
void **kbuf, void __user **ubuf,
const int start_pos,
const int end_pos)
{
if (*count == 0)
return 0;
BUG_ON(*pos < start_pos);
if (end_pos < 0 || *pos < end_pos) {
unsigned int copy = (end_pos < 0 ? *count
: min(*count, end_pos - *pos));
if (*kbuf) {
memset(*kbuf, 0, copy);
*kbuf += copy;
} else if (__clear_user(*ubuf, copy))
return -EFAULT;
else
*ubuf += copy;
*pos += copy;
*count -= copy;
}
return 0;
}

static inline int user_regset_copyin_ignore(unsigned int *pos,
unsigned int *count,
const void **kbuf,
const void __user **ubuf,
const int start_pos,
const int end_pos)
{
if (*count == 0)
return 0;
BUG_ON(*pos < start_pos);
if (end_pos < 0 || *pos < end_pos) {
unsigned int copy = (end_pos < 0 ? *count
: min(*count, end_pos - *pos));
if (*kbuf)
*kbuf += copy;
else
*ubuf += copy;
*pos += copy;
*count -= copy;
}
return 0;
}


#endif /* <linux/regset.h> */

0 comments on commit 8b2b27a

Please sign in to comment.