24

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

那么__iomem这里有什么不同呢?我应该在什么情况下准确地使用它?

4

1 回答 1

54

许多类型转换只会“运作良好”。但是,这不是很严格。没有什么能阻止您将 a 转换u32为 au32 *并取消引用它,但这不遵循内核 API 并且容易出错。

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

首先安装它,然后添加C=1到您的make呼叫中来使用 Sparse。例如,在构建模块时,使用:

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

__iomem定义如下:

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

为所有 I/O 访问添加(并要求)类似 cookie__iomem是一种更严格并避免编程错误的方法。您不想使用绝对地址读取/写入 I/O 内存区域,因为您通常使用虚拟内存。因此,

void __iomem *ioremap(phys_addr_t offset, unsigned long size);

通常调用以获取offset指定长度size(以字节为单位)的 I/O 物理地址的虚拟地址。ioremap()返回一个带有__iomemcookie 的指针,因此它现在可以与像readl()/之类的内联函数一起使用writel()(尽管现在最好使用更明确的宏ioread32()/ iowrite32(),例如),它接受__iomem地址。

此外,noderefSparse 使用该属性来确保您不会取消引用__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);

Sparse 也不高兴:

warning: dereference of noderef expression

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

这让 Sparse 很高兴:

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

底线:总是__iomem在需要的地方使用(作为返回类型或作为参数类型),并使用 Sparse 来确保你这样做了。另外:不要取消引用__iomem指针。

编辑:这是一篇很棒的LWN 文章,介绍了它的起源__iomem和使用它的功能。

于 2013-09-30T19:45:35.110 回答