嵌入式驱动学习第一周——Linux错误码以及 IS_ERR、ERR_PTR、PTR_ERR

前言

   本节来学习Linux错误码,因为内核中的函数常常返回指针,如果出错,也希望能够通过返回的指针体现出来。

   嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关注本博主并订阅本专栏,一起讨论一起学习。现在关注就是老粉啦!

内核返回的指针

   在介绍之前,我们需要理解一下内核空间最大的错误码。对于一个64位的系统而言,内核空间占用(0x0000000000000000 ~ 0xffffffffffffffff)的虚拟地址。其中Linux采用分页机制管理内存,而CPU访问的是线性地址需要通过页表转化成物理地址。所以内核就约定留出最后一页4k(fffffffffffff000 ~ 0xffffffffffffffff)用来记录内核空间的错误指针。

   因此所谓的错误指针已经指向了内核空间的最后一页

   指针一般有三种:合法指针、错误指针、NULL指针。

合法指针:内核返回的指针一般是指向页面的边界,即ptr & 0xfff == 0
非法指针:不指向任何有效内存地址
错误指针:错误指针是指指向无效、未定义或未分配内存的指针

IS_ERR()

   将传入的值与(unsigned long)-MAX_ERRNO的值进行比较,在Linux中,定义了MAX_ERRNO的定义为4095,其含义就是最大错误号。

   -4096的二进制是补码,其值为0xfffff001,即大于等于0xfffff001的指针为非法指针。而这一部分正好是Linux内核的最后一页,存储的错误码,对应的值就是错误类型。

   IS_ERR()的结果:

有效指针、空指针返回false
错误指针返回true

IS_ERR_OR_NULL()

   和IS_ERR()的区别在于其NULL也返回true

有效指针返回false
错误指针、空指针返回true

PTR_ERR()

   将传入的void *类型指针强转为long类型,并返回。用于将错误指针转为long类型值,从而返回出错误类型

ERR_PTR()

   将传入的long类型强转为void *类型指针,并返回

使用案例

imx6uirq.class = class_create(THIS_MODULE, IMX6UIRQ_NAME);
if (IS_ERR(imx6uirq.class)) {
	return PTR_ERR(imx6uirq.class);
}

imx6uirq.device = device_create(imx6uirq.class, NULL, imx6uirq.devid, NULL, IMX6UIRQ_NAME);
if (IS_ERR(imx6uirq.device)) {
	return PTR_ERR(imx6uirq.device);
}

   现在我们利用class_create()函数和device_create()函数创建了相应的设备节点,返回的是一个指针,我们需要对指针的合法性进行判断,因此就会使用IS_ERR()函数判断,如果是无效的就会调用PTR_ERR()函数将错误码返回。

附录:Linux错误码大全

   注意: 返回错误码的时候一般加个负号,如-EIO

#define EPERM        1  /* Operation not permitted */  
#define ENOENT       2  /* No such file or directory */  
#define ESRCH        3  /* No such process */  
#define EINTR        4  /* Interrupted system call */  
#define EIO       5  /* I/O error */  
#define ENXIO        6  /* No such device or address */  
#define E2BIG        7  /* Argument list too long */  
#define ENOEXEC      8  /* Exec format error */  
#define EBADF        9  /* Bad file number */  
#define ECHILD      10  /* No child processes */  
#define EAGAIN      11  /* Try again */  
#define ENOMEM      12  /* Out of memory */  
#define EACCES      13  /* Permission denied */  
#define EFAULT      14  /* Bad address */  
#define ENOTBLK     15  /* Block device required */  
#define EBUSY       16  /* Device or resource busy */  
#define EEXIST      17  /* File exists */  
#define EXDEV       18  /* Cross-device link */  
#define ENODEV      19  /* No such device */  
#define ENOTDIR     20  /* Not a directory */  
#define EISDIR      21  /* Is a directory */  
#define EINVAL      22  /* Invalid argument */  
#define ENFILE      23  /* File table overflow */  
#define EMFILE      24  /* Too many open files */  
#define ENOTTY      25  /* Not a typewriter */  
#define ETXTBSY     26  /* Text file busy */  
#define EFBIG       27  /* File too large */  
#define ENOSPC      28  /* No space left on device */  
#define ESPIPE      29  /* Illegal seek */  
#define EROFS       30  /* Read-only file system */  
#define EMLINK      31  /* Too many links */  
#define EPIPE       32  /* Broken pipe */  
#define EDOM        33  /* Math argument out of domain of func */  
#define ERANGE      34  /* Math result not representable */ 

参考资料

[1] ERR_PTR,PTR_ERR还有IS_ERR函数详解

[2] 如何理解Linux内核IS_ERR、ERR_PTR、PTR_ERR

[3] linux内核中的IS_ERR()、PTR_ERR()、ERR_PTR()

[4] 内核IS_ERR、PTR_ERR、ERR_PTR宏

  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值