我已经看到__iomem
用于存储ioremap()
的返回types,但是我已经在ARM体系结构中使用了u32
,它工作的很好。
那么__iomem
在这里有什么不同? 在哪种情况下我应该使用它?
许多类型的演员将会“很好地工作”。 不过,这不是很严格。 没有什么能够阻止你将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()
这样的内联函数(尽管现在最好使用更明确的宏ioread32()
/ iowrite32()
) ,它接受__iomem
地址。
此外,Sparse使用__iomem
属性来确保不取消引用__iomem
指针。 解引用应该在一些I / O实际上是内存映射的体系结构上工作,而其他体系结构则使用特殊的指令访问I / O,在这种情况下,解引用将不起作用。
我们来看一个例子:
void *io = ioremap(42, 4);
稀疏不开心:
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);
稀疏也不高兴:
warning: dereference of noderef expression
在最后一个示例中,第一行是正确的,因为ioremap()
将其值返回给__iomem
变量。 但是,我们尊重它,我们不应该这样做。
这让稀疏感到开心:
void __iomem* io = ioremap(42, 4); pr_info("%x\n", ioread32(io));
底线:在需要的地方总是使用__iomem
(作为返回类型或参数类型),并使用Sparse确保您这样做。 另外:不要取消引用__iomem
指针。
编辑 :这是一个伟大的LWN文章关于__iomem
和函数使用它的开始。