• put_user()和get_user()用户空间传递数据


    一、往用户空间传递数据

    1.传递单个数据

    put_user()可以向用户空间传递单个数据。单个数据并不是指一个字节数据,对ARM而言, put_user一次性可传递一个char , short或者int型的数据,即1、2或者4字节。用put_user比用copy_to_user要快:

    int put_user(x,p)
    • x 为内核空间的数据,
    • p 为用户空间的指针。
    • 传递成功,返回 0,否则返回-EFAULT

    put_user 一般在 ioctl 方法中使用,假如要往用户空间传递一个 32 位的数据,可以这样实现:

    static int char_cdev_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
    {
      int ret;
      u32 dat,
      switch(cmd)
      {
        case CHAR_CDEV_READ:
        ...其它操作
        dat = 数据;
        if (put_user(dat, (u32 *)arg) ) {
          printk("put_user err\n");
          return -EFAULT;
        }
      }
      ...其它操作
      return ret;
    }

    __put_user 是没有进行地址验证的版本。

    2.传递多个数据

    copy_to_user()可以一次性向用户空间传递一个数据块,函数原型如下:

    static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n);
    • to 是内核空间缓冲区地址,
    • from 是用户空间地址,
    • n 是数据字节数,
    • 返回值是不能被复制的字节数,返回 0 表示全部复制成功。

    copy_to_user()一般在 read 方法中使用。假如驱动要将从设备读到的 count 个数据送往用户空间,可以这样实现:

    static ssize_t char_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
    {
        unsigned char data[256] = {0};
        ....从设备获取数据
        if (copy_to_user((void *)buf, data, count)) {
            printk("copy_to_user err\n");
        return -EFAULT;
    
        }
        return count;
    }

    __copy_to_user 是没有进行地址验证的版本。

     

    二、从用户空间获取数据

    1.获取单个数据

    调用get_user()可以从用户空间获取单个数据,单个数据并不是指一个字节数据,对ARM而言,get_user一次性可获取一个char、short或者 int型的数据,即1、2或者4字节。用get_user比用get_from_user要快:

    int get_user(x,p)
    • x为内核空间的数据
    • p为用户空间的指针。
    • 获取成功,返回0,否则返回-EFAULT.

    get_user()一般也用在ioctl方法中。假如驱动需要从用户空间获取一个32位数,然后写到某个寄存器中,可以这样实现:

    static int char_cdev_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
    {
      int ret;
      u32 dat,
    switch(cmd)
    {
      case CHAR_CDEV_WRITE:
      if (get_user(dat, (u32 *)arg) ) {
      printk("get_user err\n");
      return -EFAULT;
    }
      CHAR_CDEV_REG = dat;
      ...其它操作
    }
      ...其它操作
      return ret;
    }

    __get_user 是没有进行地址验证的版本。

     

    2.获取多个数据

    copy_from_user()可以一次性从用户空间获取一个数据块。
    函数原型如下:

    static inline unsigned long _must_ check copy_from_user(void *to, const void_user*from, unsigned long n);
    • to是内核空间缓冲区地址,
    • from是用户空间地址
    • n是数据字节数
    • 返回值是不能被复制的字节数,返回0表示全部复制成功。

    copy_from_user()常用在 write方法中。如果驱动需要从用户空间获取count字节数据,用于操作设备,可以这样实现:

    static ssize_t char_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
    {
        unsigned char data[256];
    
        if (copy_from_user(&data, buf, 256) ) {
        printk("copy_from_user err\n");
        return -EFAULT;
        }
        ...
    }

    __copy_from_user 是没有进行地址验证的版本。

  • 相关阅读:
    POJ 1966 Cable TV Network
    POJ 3204 Ikki's Story I
    Codeforces Round #388 (Div. 2)
    BZOJ 后缀自动机四·重复旋律7
    扩展欧几里得 exGCD
    网络流模板 NetworkFlow
    BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊
    BZOJ 3224: Tyvj 1728 普通平衡树
    BZOJ 1070: [SCOI2007]修车
    BZOJ 4552: [Tjoi2016&Heoi2016]排序
  • 原文地址:https://www.cnblogs.com/yuanqiangfei/p/15735530.html
Copyright © 2020-2023  润新知