IS_ERR_VALUE等宏的理解

一、关于Linux内核非法地址(网上搜加自己总结)

  1、对任何一个指针,必然有三种情况:一种是有效指针,一种是NULL,空指针,一种是错误指针,或者说无效指针

  2、32位CPU,内核空间占用虚拟地址(0xc0000000~0xffffffff)3~4G虚拟地址(线性地址?)

  3、其中最后一个page(假设4K大小)的地址为(0xfffff000~0xffffffff)为预留地址,指向这个地址的指针都是非法指针
二、错误码跟非法指针啥关系

  1、 中规定了通用错误码1-34 中定义了 #define MAX_ERRNO  4095 最大错误码为4095

  2、插一段代码,看内核如何返回错误码。可以看出,在错误码前面加上一个负号就变成了返回值

    /* Check type and command number */
        if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
            return -ENOTTY;

3、继续以-ENOTTY为例,ENOTTY的值为25,-ENOTTY的值是多少呢。负数在计算机中以二进制补码形式存储。

      补码=~源码+1(源码按位取反后加1)

      那么-25的补码就为 0xFFFFFFE7。仔细看一下这个值,在0xfffff000~0xffffffff之间,所以它就是个错误指针。

      所以错误码取负值后在内存中存储的值就是内核的错误指针。
三、IS_ERR_VALUE宏定义分析

#define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)

  1、unlikely宏啥意思现还没深入研究,好像是高速编译器哪个不可能发生,用来优化代码,先不管。

  2、(unsigned long)-MAX_ERRNO的值为 0xFFFFF001,也就是大于等于0xFFFFF001的指针为非法指针。

  3、根据上面的分析,负的错误码与非法指针等价,IS_ERR_VALUE宏既可以用来判断返回错误码(负值)的函数,又可以用来判断返回错误指针的函数。
四、ERR_PTR宏定义分析

    static inline void * __must_check ERR_PTR(long error)
    {
        return (void *) error;
    }

  1、字面上来看,把一个long型error转换为指针类型,猜测一下是把负的错误码转换为 void *

  2、看别人怎么用。可以看出,ERR_PTR宏把负的错误码转换为 void *指针。在返回指针的函数中可以这样用,返回一个非法地址,这个跟用户态错误就返回空指针是不同的

    static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
    {
        struct ac97c_platform_data *pdata;
        struct device_node *node = dev->of_node;
     
        if (!node) {
            dev_err(dev, "Device does not have associated DT data\n");
            return ERR_PTR(-EINVAL);
        }
     
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
            return ERR_PTR(-ENOMEM);
     
        pdata->reset_pin = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
     
        return pdata;
    }

五、PTR_ERR宏定义分析

    static inline long __must_check PTR_ERR(__force const void *ptr)
    {
        return (long) ptr;
    }

1、字面上来看把指针转换为整数类型,合理猜测是把非法指针转换为错误码

2、看别人怎么用。IS_ERR宏就是调用了IS_ERR_VALUE,后面分析。可以看出先判断一下指针是不是非法的,如果是非法的,则将错误指针通过PTR_ERR转换为错误码,并返回一个整形数值。

    static int act8945a_i2c_probe(struct i2c_client *i2c,
                      const struct i2c_device_id *id)
    {
        int ret;
        struct regmap *regmap;
     
        regmap = devm_regmap_init_i2c(i2c, &act8945a_regmap_config);
        if (IS_ERR(regmap)) {
            ret = PTR_ERR(regmap);
            dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
            return ret;
        }
     
        i2c_set_clientdata(i2c, regmap);
     
        ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE,
                       act8945a_devs, ARRAY_SIZE(act8945a_devs),
                       NULL, 0, NULL);
        if (ret) {
            dev_err(&i2c->dev, "Failed to add sub devices\n");
            return ret;
        }
     
        return 0;
    }

六、PTR_ERR宏定义分析

    static inline bool __must_check IS_ERR(__force const void *ptr)
    {
        return IS_ERR_VALUE((unsigned long)ptr);
    }

  这个宏就是调用了IS_ERR_VALUE,来判断指针是否非法。
 

你可能感兴趣的:(IS_ERR_VALUE等宏的理解)