我已经看到__iomem
用于存储ioremap()
的返回类型,但我在ARM体系结构中使用了u32
并且它运行良好。
那么__iomem
在这里有什么区别?在哪种情况下我应该使用它?
答案 0 :(得分:38)
很多类型演员都会很好地工作"。但是,这不是很严格。没有什么可以阻止你将u32
转换为u32 *
并取消引用它,但这不遵循内核API并且容易出错。
__iomem
是Sparse使用的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
的虚拟地址,以字节为单位指定长度size
。 ioremap()
会返回一个包含__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。