在编写设备驱动程序时,linux中__iomem的用途是什么?

时间:2013-09-30 17:46:55

标签: linux memory-management linux-kernel linux-device-driver

我已经看到__iomem用于存储ioremap()的返回类型,但我在ARM体系结构中使用了u32并且它运行良好。

那么__iomem在这里有什么区别?在哪种情况下我应该使用它?

1 个答案:

答案 0 :(得分:38)

很多类型演员都会很好地工作"。但是,这不是很严格。没有什么可以阻止你将u32转换为u32 *并取消引用它,但这不遵循内核API并且容易出错。

__iomemSparse使用的cookie,用于查找内核中可能的编码错误的工具。如果您没有在启用Sparse的情况下编译内核代码,则无论如何都会忽略__iomem

首先安装Sparse,然后将C=1添加到make来电。例如,在构建模块时,请使用:

make -C $KPATH M=$PWD C=1 modules

__iomem的定义如下:

# define __iomem        __attribute__((noderef, address_space(2)))

为所有I / O访问添加(和要求)像__iomem这样的cookie是一种更严格的方法,可以避免编程错误。您不希望使用绝对地址从/向I / O内存区域读取/写入,因为您通常使用虚拟内存。因此,

void __iomem *ioremap(phys_addr_t offset, unsigned long size);
通常调用

来获取I / O物理地址offset的虚拟地址,以字节为单位指定长度sizeioremap()会返回一个包含__iomem Cookie的指针,因此现在可以readl() / writel()等内联函数一起使用(尽管它已经#39} ;现在最好使用接受ioread32()地址的更明确的宏iowrite32() / __iomem)。

此外,Sparse使用noderef属性来确保您不要取消引用__iomem指针。解除引用应该适用于I / O实际上是内存映射的某些体系结构,但是其他体系结构使用特殊指令来访问I / O,在这种情况下,取消引用不会起作用。

让我们看一个例子:

void *io = ioremap(42, 4);

Sparse不高兴:

warning: incorrect type in initializer (different address spaces)
    expected void *io
    got void [noderef] <asn:2>*

或者:

u32 __iomem* io = ioremap(42, 4);
pr_info("%x\n", *io);

Sparse也不高兴:

warning: dereference of noderef expression

在上一个示例中,第一行是正确的,因为ioremap()将其值返回到__iomem变量。但是,我们尊重它,我们不应该这样做。

这让稀疏快乐:

void __iomem* io = ioremap(42, 4);
pr_info("%x\n", ioread32(io));

底线:始终使用__iomem所需的内容(作为返回类型或参数类型),并使用Sparse确保您这样做。另外:不要取消引用__iomem指针。

修改:关于__iomem的开始和使用它的功能,这里是一个很棒的LWN article