ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux设备驱动程序 之 ioctl

2019-10-29 19:03:15  阅读:222  来源: 互联网

标签:驱动程序 用户 ioctl 参数 user Linux IOC


ioctl

除了读取和写入设备之外,大部分驱动程序还需要另外一种能力,即通过设备驱动程序执行各种类型的硬件控制,通常这种需求使用ioctl方法支持,该方法实现了同名的系统调用;

在用户空间,ioctl系统调用的原型如下:

1 int ioctl(int d, int request, ...);

原型中的可变参数不是数目不定的一串参数,而只是一个可选参数;可选参数的具体格式依赖于控制命令,也就是第二个参数;某些控制命令不需要参数,某些需要一个整数参数,某些需要一个指针参数;使用指针参数可以向ioctl传递任意数据,这样设备可以与用户空间交换任意数量的数据;

ioctl系统调用内核中的定义如下:

1 SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)

ioctl在file_operations中的函数原型如下:

1 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
2 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

大多数ioctl的实现都包含了一个switch语句来根据cmd参数选择对应的操作;不同的命令被赋予不同的数值,为了简化代码,通常会在代码中使用符号名代替数值,这些符号名由c语言的预处理语句定义,订制设备驱动程序通常会在它们的头文件中声明这些符号;

选择ioctl命令

ioctl命令号码定义使用了4个为字段,其含义如下:

type:幻数;选择一个号码,并在整个驱动程序中使用这个号码;这个字段是8位宽(_IOC_TYPEBITS);通常使用一个英文字母;比如#define MY_IOC_MAGIC ‘k’;需要注意避免命令号冲突;

number:序数(顺序编号);是8位宽(_IOC_NRBITS);通常从0开始顺序编号;

direction:如果命令涉及到数据的传输,则该位字段定义数据传输的方向;可以使用的值包括_IOC_NONE(没有数据传输)、_IOC_READ、_IOC_WRITE、_IOC_READ|_IOC_WRITE(双向传输);数据传输是从应用程序的角度来看的,也就是说,IOC_READ意味着从设备中读取数据,所以驱动程序必须向用户空间写入数据;注意,该字段是一个位掩码,因此可以使用逻辑AND操作从中分解出_IOC_READ和_IOC_WRITE;

size:所涉及的用户数据大小;这个字段的宽度与体系结构有关,通常是13或者14位,具体可以通过宏_IOC_SIZEBIT找到针对特定体系结构的具体数值;系统并不强制只用这个字段,也就是说,内核不会检查这个字段;对该字段的正确使用可以帮助我们检测用户程序的错误,并且如果我们从不改变相关的数据项大小的话,这个位字段哈可以帮我们实现向后的兼容性;但是,如果需要很大的数据传输,则可以忽略这个位字段;

 

用于构造命令编号的宏如下,其中type和number位字段通过参数传入,而size位字段通过对datatype参数取sizeof获取的;

_IO(type,nr)用于构造无参数的命令编号;

_IOR(type,nr,size)用于构造从驱动程序读取数据的命令编号;

_IOW(type,nr,size)用于构造用用户空间写入数据的命令;

_IOWR(type,nr,size)用于双向传输;

 

用于解开位字段的宏如下:

_IOC_DIR(nr)、_IOC_TYPE(nr)、_IOC_NR(nr)、_IOC_SIZE(nr);

返回值

ioctl实现通常就是一个基于命令号的switch语句;当命令号不合法时,有些内核函数返回-ENVAL(非法参数);POSIX标准规定,应该返回-ENOTTY,C库将这个错误码解释为不合适的设备ioctl;但是普遍做法是返回-EINVAL;

使用ioctl参数

ioctl的附加参数,如果是个整数,直接使用就可以了,如果是个指针,就需要注意一些问题;

当用一个指针指向用户空间时,必须确保指向的用户空间是合法的;对未验证的用户空间指针的访问,可能导致内核oops,系统崩溃或者安全问题;驱动程序应该负责对每个用到的用户空间地址做适当的检查,如果是非法地址则应该返回一个错误;

copy_from_user和copy_to_user可以安全的与用户空间交换数据,这两个函数也可以在ioctl中使用,但是因为ioctl通常涉及较小的数据项,因此可以通过其他方法更有效的操作;为此,我们首先要通过access_ok函数验证地址,而不传输数据,函数声明如下:<asm-generic/uaccess.h>

1 #define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size))

第一个参数type应是VERIFY_READ或者VERIFY_RIWTE,取决于要执行的动作是读取还是写入用户空间内存区;addr参数是一个用户空间地址,size是字节数,如ioctl要从用户空间读取一个整数,则size是sizeof(int);如果在指定地址处既要读取又要写入,则应该用VERIFY_WRITE,因为它是VERIFY_READ的超集;

与大多数函数不同,access_ok返回1标识成功,0标识失败;如果返回失败,则通常需要返回-EFAULT给调用者;

关于该函数,需要注意两点:第一,它并没有完成验证内存的全部工作,而只是检查了所引用的内存是否位于进程有对应访问权限的区域中,特别是要确保访问的地址没有指向内核空间的内存区;第二,大多数驱动程序代码中都不需要真正调用access_ok,因为内存管理程序会处理它;

数据传送

除了copy_from_user和copy_to_user函数之外,内核还提供了常用的数据大小为1,2,4,8字节优化过的一组函数;

1 #define put_user(x, ptr)
2 #define __put_user(x, ptr)
3 
4 #define get_user(x, ptr)
5 #define __get_user(x, ptr)

其中put_user函数把数据x写到用户空间;它们相对比较快,当需要传递单个数据时,使用这些宏而不是用copy_to_user;由于这些宏在展开时不做类型检查,所以可以传递给put_user任意类型的指针,只要是个用户空间地址就行;传递数据大小依赖于ptr参数的类型,在编译时由编译器的内建指令sizeof和typeof确定;总之,若ptr是一个字符指针,就传递1个字节,2,4,8字节的情况类似;

put_user已经进行了检查确保进程可以写入指定的内存地址,并在成功时返回0,出错是返回-EFAULT;__put_user则做的检查少些,它不调用access_ok,但是如果地址指向的用户不能写入内存,会出现操作失败,因为__put_user要在已经使用过access_ok检查后使用;

get_user从用户空间接收一个数据,接收的数值保存在局部变量x中,返回值指明了操作是否成功;通用,__get_user应该在操作地址已经被access_ok检查通过后使用;

如果是不满足上述的传递大小的数值,则必须使用copy_to_user和copy_from_user;

权能与受限操作

权限相关的定义在<uapi/linux/capability.h>中,其中包含了系统能够理解的所有权能;不修改内核源码,驱动程序无法定义新的权能;对驱动程序开发来讲有意义的权能如下:

CAP_DAC_OVERRIDE

越过文件或者目录的访问限制的能力;

CAP_NET_ADMIN

执行网络管理任务的能力,包括哪些能影响网络接口的任务;

CAP_SYS_MODULE

载入或者卸载内核模块的能力

CAP_SYS_RAWIO

执行裸IO操作的能力,例如,访问设备端口或者直接与USB设备通信;

CAP_SYS_ADMIN

截获的能力,它提供了访问许多系统管理操作的途径;

在执行某项特权操作之前,需要检查调用进程是否有合适的权能;如果不进行这类检查,将导致用户进程执行非授权操作,从而影响系统稳定性和安全性;权能检查通过capable实现;在<linux/capability.h>中;

1 bool capable(int cap);

 

标签:驱动程序,用户,ioctl,参数,user,Linux,IOC
来源: https://www.cnblogs.com/wanpengcoder/p/11760785.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有