内核代码中充斥着大量的__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
# 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__ 是与Sparse 相关的一个宏开关,从kernel顶层Makefile中可以看出,当指定参数C=1或C=2时会调用Sparse。Sparse是2004年由Linus创建的kernel代码静态检查工具。
192
193
194
195
196
197
198
199
200
从__CHECKER__ 和address_space(2) 这两个信息可以看出,当基于Sparse进行通过__iomem 修饰的void 类型指针需要落到特定地址空间,否则会吐出警告信息。
__iomem 存在的意义是kernel系统同时兼容了X86 和ARM 等类型的处理器平台,对于这两种典型的处理器平台而言,其寄存器访问方式是完全不同的。X86 架构的处理器是基于IO指令进行寄存器访问的,而ARM 架构的处理器是基于真实存在的32或64位的AMBA 总线地址空间来访问寄存器的。
|