put_user()和get_user()用户空间传递数据
一、往用户空间传递数据
1.传递单个数据
put_user()可以向用户空间传递单个数据。单个数据并不是指一个字节数据,对ARM而言, put_user一次性可传递一个char , short或者int型的数据,即1、2或者4字节。用put_user比用copy_to_user要快:
1 | int put_user(x,p) |
- x 为内核空间的数据,
- p 为用户空间的指针。
- 传递成功,返回 0,否则返回-EFAULT。
put_user 一般在 ioctl 方法中使用,假如要往用户空间传递一个 32 位的数据,可以这样实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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()可以一次性向用户空间传递一个数据块,函数原型如下:
1 | 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 个数据送往用户空间,可以这样实现:
1 2 3 4 5 6 7 8 9 10 11 | 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要快:
1 | int get_user(x,p) |
- x为内核空间的数据
- p为用户空间的指针。
- 获取成功,返回0,否则返回-EFAULT.
get_user()一般也用在ioctl方法中。假如驱动需要从用户空间获取一个32位数,然后写到某个寄存器中,可以这样实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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()可以一次性从用户空间获取一个数据块。
函数原型如下:
1 | 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字节数据,用于操作设备,可以这样实现:
1 2 3 4 5 6 7 8 9 10 | 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 是没有进行地址验证的版本。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2019-12-27 DVB-C\DVB-S\DVB-T知识介绍
2019-12-27 广播与电视波段频率划分表