linux下写设备驱动时__iomem有什么用? [英] What is the use of __iomem in linux while writing device drivers?
问题描述
我看到__iomem
是用来存储ioremap()
的返回类型的,但是我在ARM架构中使用过u32
它运行良好.
I have seen that __iomem
is used to store the return type of ioremap()
, but I have used u32
in ARM architecture for it and it works well.
那么 __iomem
在这里有什么区别?我应该在什么情况下使用它?
So what difference does __iomem
make here? And in which circumstances should I use it exactly?
推荐答案
很多类型转换都将运行良好".但是,这不是很严格.没有什么能阻止您将 u32
转换为 u32 *
并取消引用它,但这不遵循内核 API 并且容易出错.
Lots of type casts are going to just "work well". However, this is not very strict. Nothing stops you from casting a u32
to a u32 *
and dereference it, but this is not following the kernel API and is prone to errors.
__iomem
是 Sparse 使用的 cookie,这是一个使用的工具找出内核中可能存在的编码错误.如果您没有在启用 Sparse 的情况下编译内核代码,__iomem
无论如何都会被忽略.
__iomem
is a cookie used by Sparse, a tool used to find possible coding faults in the kernel. If you don't compile your kernel code with Sparse enabled, __iomem
will be ignored anyway.
首先安装 Sparse,然后将 C=1
添加到您的 make
调用中来使用它.例如,在构建模块时,使用:
Use Sparse by first installing it, and then adding C=1
to your make
call. For example, when building a module, use:
make -C $KPATH M=$PWD C=1 modules
<小时>
__iomem
定义如下:
# define __iomem __attribute__((noderef, address_space(2)))
为所有 I/O 访问添加(并要求)像 __iomem
这样的 cookie 是一种更严格并避免编程错误的方法.您不想从/向具有绝对地址的 I/O 内存区域读取/写入,因为您通常使用虚拟内存.因此,
Adding (and requiring) a cookie like __iomem
for all I/O accesses is a way to be stricter and avoid programming errors. You don't want to read/write from/to I/O memory regions with absolute addresses because you're usually using virtual memory. Thus,
void __iomem *ioremap(phys_addr_t offset, unsigned long size);
通常被调用来获取一个 I/O 物理地址的虚拟地址 offset
,对于指定的长度 size
(以字节为单位).ioremap()
返回一个带有 __iomem
cookie 的指针,所以这个 现在可以用于内联函数,比如 readl()
/writel()
(尽管现在最好使用更明确的宏 ioread32()
/iowrite32()
,例如),接受 __iomem
地址.
is usually called to get the virtual address of an I/O physical address offset
, for a specified length size
in bytes. ioremap()
returns a pointer with an __iomem
cookie, so this may now be used with inline functions like readl()
/writel()
(although it's now preferable to use the more explicit macros ioread32()
/iowrite32()
, for example), which accept __iomem
addresses.
此外,Sparse 使用 noderef
属性来确保您不会取消引用 __iomem
指针.取消引用应该适用于某些 I/O 确实是内存映射的架构,但其他架构使用特殊指令来访问 I/O,在这种情况下,取消引用将不起作用.
Also, the noderef
attribute is used by Sparse to make sure you don't dereference an __iomem
pointer. Dereferencing should work on some architecture where the I/O is really memory-mapped, but other architectures use special instructions for accessing I/Os and in this case, dereferencing won't work.
让我们看一个例子:
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
", *io);
Sparse 也不开心:
Sparse is not happy either:
warning: dereference of noderef expression
在最后一个示例中,第一行是正确的,因为 ioremap()
将其值返回给 __iomem
变量.但是,我们尊重它,我们不应该这样做.
In the last example, the first line is correct, because ioremap()
returns its value to an __iomem
variable. But then, we deference it, and we're not supposed to.
这让 Sparse 很高兴:
This makes Sparse happy:
void __iomem* io = ioremap(42, 4);
pr_info("%x
", ioread32(io));
底线:总是在需要的地方使用 __iomem
(作为返回类型或作为参数类型),并使用 Sparse 来确保你这样做了.另外:不要取消引用 __iomem
指针.
Bottom line: always use __iomem
where it's required (as a return type or as a parameter type), and use Sparse to make sure you did so. Also: do not dereference an __iomem
pointer.
编辑:这是一篇关于LWN 文章的精彩LWN 文章code>__iomem 和使用它的函数.
Edit: Here's a great LWN article about the inception of __iomem
and functions using it.
这篇关于linux下写设备驱动时__iomem有什么用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!