0

I came across some macros with the definitions like this:

#ifdef __CHECKER__
# define __user     __attribute__((noderef, address_space(1)))

And I know those are merely to be used with sparse(__CHECKER__) and GCC ignores them completely.But what I don't get is that what does address_space() actually mean? What are the possible values for it? Looks like the only documentation for it is a post from linus in the mailing list around 16 years ago which says:

When you do use parse, it is another matter entirely. For "sparse", that "__iomem" has lots of meaning:
# define __iomem __attribute__((noderef, address_space(2)))

ie "iomem" means two separate things: it means that sparse should complain if the pointer is ever dereferenced (it's a "noderef" pointer) directly, and it's in "address space 2" as opposed to the normal address space (0).

From similar Q&As like this and this I figured out that 3 means per-cpu pointers and 1 seems to be related to the pointers received from userspace.And also 0 for normal pointers.

But what does address_space(2) actually mean?
Are {0,1,2,3} the only possible values?

Thanks.

Parsa Mousavi
  • 1,052
  • 1
  • 13
  • 31

2 Answers2

2

address_space() and noderef are attributes. What may be confusing is that they are not GCC attributes. They are Sparse attributes and so they only are meaningful to Sparse when __CHECKER__ is defined and Sparse is enabled.

address_space() attribute puts a specific restriction on a pointer marking it as such. My understanding is that the numbers that are arguments were chosen arbitrarily and denote that a pointer belongs to a certain class. Thus, if you follow the rules, you should clearly annotate a pointer as belonging to a specific class (such as __user or __iomem, etc) and not mix pointers from different classes. Using these annotations, Sparse as a static checker helps you to spot cases of incorrect usage.

For address_space(2) aka __iomem I have found a good description here: What is the use of __iomem in linux while writing device drivers? The post from Linus is a excellent description as well.

Besides {0,1,2,3} there's also {4} which marks __rcu pointers as a separate class. I don't think there are more at this time.

Aleksey
  • 623
  • 5
  • 10
  • 1
    With the help of our friend ```grep``` I found out that there was also a ```# define __pmem __attribute__((noderef, address_space(5)))``` in the 4.x kernels(I don't know the exact versions , but what I'm talking about here is 4.4).But that's no longer there in 5.7 for example.However thanks :) – Parsa Mousavi Jul 25 '20 at 01:50
0

This attribute is to be used on pointers to specify that the corresponding memory is in an address space different than usual kernel memory. So, it must not be accessed by simply dereferencing the pointer but needs to be accessed via some specific set of functions (or macros). Sparse treats pointers with different address spaces as distinct types and will warn on casts (implicit or explicit) mixing the address spaces.

The address space used to be identified by a small number but in current kernels an identifier is used. The admissible values (for the kernel) are:

  • __user/1: is used for user-space memory (to be accessed via get_user()/put_user(), copy_from_user()/copy_to_user(), ...)
  • __iomem/2: is used for I/O memory (to be accessed via ioread{8,16,32,64}(), writel()/readl(), ...)
  • __percpu/3: is used for 'per-CPU' memory (to be accessed get_cpu_var()/put_cpu_var(), ..., it also needs to be allocated or declared specically: alloc_percpu(), DECLARE_PER_CPU(), ...)
  • __rcu/4: is used for 'RCU' memory (to be accessed via rcu_dereference(), ...)
  • 0: is the default, used for normal kernel memory.

Some documentation is available at https://sparse.docs.kernel.org/en/latest/annotations.html.

lucvoo
  • 501
  • 4
  • 15