lkml.org 
[lkml]   [2007]   [Dec]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH -mm 04/43] user_regset helpers
    Date
    This adds some inlines to linux/regset.h intended for arch code to use in
    its user_regset get and set functions. These make it pretty easy to deal
    with the interface's optional kernel-space or user-space pointers and its
    generalized access to a part of the register data at a time.

    In simple cases where the internal data structure matches the exported
    layout (core dump format), a get function can be nothing but a call to
    user_regset_copyout, and a set function a call to user_regset_copyin.

    In other cases the exported layout is usually made up of a few pieces each
    stored contiguously in a different internal data structure. These helpers
    make it straightforward to write a get or set function by processing each
    contiguous chunk of the data in order. The start_pos and end_pos arguments
    are always constants, so these inlines collapse to a small amount of code.

    Signed-off-by: Roland McGrath <roland@redhat.com>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    ---
    include/linux/regset.h | 116 ++++++++++++++++++++++++++++++++++++++++++++++++
    1 files changed, 116 insertions(+), 0 deletions(-)

    diff --git a/include/linux/regset.h b/include/linux/regset.h
    index 85d0fb0..761c931 100644
    --- a/include/linux/regset.h
    +++ b/include/linux/regset.h
    @@ -15,6 +15,7 @@

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

    @@ -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> */
    --
    1.5.3.6


    \
     
     \ /
      Last update: 2007-12-20 12:59    [W:0.030 / U:60.236 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site