内核代码中充斥着大量的__iomem
修饰的void
类型的指针,像下面这样:
void __iomem *devm_ioremap_resource(struct device *dev,
const struct resource *res)
{
resource_size_t size;
void __iomem *dest_ptr;
char *pretty_name;
BUG_ON(!dev);
if (!res || resource_type(res) != IORESOURCE_MEM) {
dev_err(dev, "invalid resource\n");
return IOMEM_ERR_PTR(-EINVAL);
}
size = resource_size(res);
if (res->name)
pretty_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
dev_name(dev), res->name);
else
pretty_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
if (!pretty_name)
return IOMEM_ERR_PTR(-ENOMEM);
if (!devm_request_mem_region(dev, res->start, size, pretty_name)) {
dev_err(dev, "can't request region for resource %pR\n", res);
return IOMEM_ERR_PTR(-EBUSY);
}
dest_ptr = devm_ioremap(dev, res->start, size);
if (!dest_ptr) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
devm_release_mem_region(dev, res->start, size);
dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
}
return dest_ptr;
}
__iomem
的定义位于include/linux/compiler_types.h
中,规定了GCC相关的一些属性信息。
#ifdef __CHECKER__
# define __user __attribute__((noderef, address_space(1)))
# define __kernel __attribute__((address_space(0)))
# define __safe __attribute__((safe))
# define __force __attribute__((force))
# define __nocast __attribute__((nocast))
# define __iomem __attribute__((noderef, address_space(2)))
# define __must_hold(x) __attribute__((context(x,1,1)))
# define __acquires(x) __attribute__((context(x,0,1)))
# define __releases(x) __attribute__((context(x,1,0)))
# define __acquire(x) __context__(x,1)
# define __release(x) __context__(x,-1)
# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0)
# define __percpu __attribute__((noderef, address_space(3)))
# define __rcu __attribute__((noderef, address_space(4)))
# define __private __attribute__((noderef))
extern void __chk_user_ptr(const volatile void __user *);
extern void __chk_io_ptr(const volatile void __iomem *);
# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member))
#else /* __CHECKER__ */
# ifdef STRUCTLEAK_PLUGIN
# define __user __attribute__((user))
# else
# define __user
# endif
# define __kernel
# define __safe
# define __force
# define __nocast
# define __iomem
# define __chk_user_ptr(x) (void)0
# define __chk_io_ptr(x) (void)0
# define __builtin_warning(x, y...) (1)
# define __must_hold(x)
# define __acquires(x)
# define __releases(x)
# define __acquire(x) (void)0
# define __release(x) (void)0
# define __cond_lock(x,c) (c)
# define __percpu
# define __rcu
# define __private
# define ACCESS_PRIVATE(p, member) ((p)->member)
#endif /* __CHECKER__ */
这个宏定义 __iomem
是在 Linux 内核中用于标记 I/O 内存区域的。具体来说,它使用了两个 GCC 属性:
-
__attribute__((noderef))
:这个属性告诉编译器不要对标记的指针进行解引用检查。这在处理 I/O 内存时很重要,因为这些内存区域可能不遵循普通内存的访问规则。 -
__attribute__((address_space(2)))
:这个属性将指针标记为属于特定的地址空间。在 Linux 内核中,地址空间 2 通常用于 I/O 内存。这有助于编译器进行更好的优化和错误检查。
__CHECKER__
是与Sparse
相关的一个宏开关,从kernel顶层Makefile中可以看出,当指定参数C=1或C=2时会调用Sparse。Sparse是2004年由Linus创建的kernel代码静态检查工具。
192 # Call a source code checker (by default, "sparse") as part of the
193 # C compilation.
194 #
195 # Use 'make C=1' to enable checking of only re-compiled files.
196 # Use 'make C=2' to enable checking of *all* source files, regardless
197 # of whether they are re-compiled or not.
198 #
199 # See the file "Documentation/dev-tools/sparse.rst" for more details,
200 # including where to get the "sparse" utility.
从__CHECKER__和address_space(2)这两个信息可以看出,当基于Sparse进行通过__iomem修饰的void类型指针需要落到特定地址空间,否则会吐出警告信息。
__iomem存在的意义是kernel系统同时兼容了X86和ARM等类型的处理器平台,对于这两种典型的处理器平台而言,其寄存器访问方式是完全不同的。X86架构的处理器是基于IO指令进行寄存器访问的,而ARM架构的处理器是基于真实存在的32或64位的AMBA总线地址空间来访问寄存器的。
标签:__,attribute,iomem,dev,Linux,void,define From: https://www.cnblogs.com/linhaostudy/p/18473889