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

uqjltbpv  于 2022-12-11  发布在  Linux
关注(0)|答案(2)|浏览(187)

我看到__iomem用于存储ioremap()的返回类型,但我在ARM架构中使用了u32,效果很好。
那么__iomem在这里有什么不同呢?我应该在什么情况下使用它呢?

ujv3wf0j

ujv3wf0j1#

很多类型转换都只是“工作得很好”。然而,这并不是很严格。没有什么可以阻止你将u32转换为u32 *并解引用它,但这不符合内核API,很容易出错。
__iomemSparse使用的cookie,Sparse是一个用于查找内核中可能的编码错误的工具。如果您没有在启用稀疏的情况下编译内核代码,__iomem将被忽略。
首先安装Sparse,然后将C=1添加到make调用中,即可使用Sparse。例如,生成模块时,请用途:

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,在这种情况下,取消引用将不起作用。
让我们看一个例子:

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

myss37ts

myss37ts2#

简单,直和短(S3)的解释。有一个文章https://lwn.net/Articles/653585/为更多的细节。

相关问题