我看到__iomem用于存储ioremap()的返回类型,但我在ARM架构中使用了u32,效果很好。那么__iomem在这里有什么不同呢?我应该在什么情况下使用它呢?
__iomem
ioremap()
u32
ujv3wf0j1#
很多类型转换都只是“工作得很好”。然而,这并不是很严格。没有什么可以阻止你将u32转换为u32 *并解引用它,但这不符合内核API,很容易出错。__iomem是Sparse使用的cookie,Sparse是一个用于查找内核中可能的编码错误的工具。如果您没有在启用稀疏的情况下编译内核代码,__iomem将被忽略。首先安装Sparse,然后将C=1添加到make调用中,即可使用Sparse。例如,生成模块时,请用途:
u32 *
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);
通常会呼叫,以取得指定长度size(以字节为单位)之I/O实体地址offset的虚拟地址。ioremap()会传回含有__iomem Cookie的指标,因此,* 现在 * 可以与内联函数(如readl()/writel())一起使用(尽管现在更倾向于使用更明确的宏ioread32()/iowrite32(),例如),这些宏接受__iomem地址。另外,稀疏矩阵使用noderef属性来确保你不会取消引用__iomem指针。取消引用应该在一些I/O实际上是内存Map的架构上工作,但其他架构使用特殊的指令来访问I/O,在这种情况下,取消引用将不起作用。让我们看一个例子:
size
offset
readl()
writel()
ioread32()
iowrite32()
noderef
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指针。
编辑:这里有一个关于__iomem的开始和使用它的函数的LWN article。
myss37ts2#
简单,直和短(S3)的解释。有一个文章https://lwn.net/Articles/653585/为更多的细节。
2条答案
按热度按时间ujv3wf0j1#
很多类型转换都只是“工作得很好”。然而,这并不是很严格。没有什么可以阻止你将
u32
转换为u32 *
并解引用它,但这不符合内核API,很容易出错。__iomem
是Sparse使用的cookie,Sparse是一个用于查找内核中可能的编码错误的工具。如果您没有在启用稀疏的情况下编译内核代码,__iomem
将被忽略。首先安装Sparse,然后将
C=1
添加到make
调用中,即可使用Sparse。例如,生成模块时,请用途:__iomem
的定义如下:为所有I/O访问添加(并要求)
__iomem
这样的cookie是一种更加严格并避免编程错误的方法。您不希望使用绝对地址读写I/O内存区域,因为您通常使用虚拟内存。因此,通常会呼叫,以取得指定长度
size
(以字节为单位)之I/O实体地址offset
的虚拟地址。ioremap()
会传回含有__iomem
Cookie的指标,因此,* 现在 * 可以与内联函数(如readl()
/writel()
)一起使用(尽管现在更倾向于使用更明确的宏ioread32()
/iowrite32()
,例如),这些宏接受__iomem
地址。另外,稀疏矩阵使用
noderef
属性来确保你不会取消引用__iomem
指针。取消引用应该在一些I/O实际上是内存Map的架构上工作,但其他架构使用特殊的指令来访问I/O,在这种情况下,取消引用将不起作用。让我们看一个例子:
稀疏很不高兴:
或者:
稀疏不高兴了:
在最后一个例子中,第一行是正确的,因为
ioremap()
将它的值返回给了__iomem
变量,但是我们遵从它,我们不应该这样做。这让“稀疏”很高兴:
底线:总是在需要的地方使用
__iomem
(作为返回类型或作为参数类型),并使用Sparse来确保您这样做了。另外:不要取消引用__iomem
指针。编辑:这里有一个关于
__iomem
的开始和使用它的函数的LWN article。myss37ts2#
简单,直和短(S3)的解释。有一个文章https://lwn.net/Articles/653585/为更多的细节。