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.
So what difference does __iomem
make here? And in which circumstances should I use it exactly?
__iomem is a kernel cookie used by Sparse, a semantic checker used by the kernel to find possible coding faults. To take advantage of the features offered by Sparse, it should be enabled at kernel compile time; if not, __iomem cookie will be ignored anyway.
Drivers are used to help the hardware devices interact with the operating system. In windows, all the devices and drivers are grouped together in a single console called device manager.
/proc/iomem lists ranges of physical memory addresses. You can access physical memory addresses directly from a user program by mapping /dev/mem , but you probably don't want to. You can access I/O ports directly from a user program with ioperm , but you probably don't want to.
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
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.
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
is defined like this:
# define __iomem __attribute__((noderef, address_space(2)))
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);
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.
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.
Let's look at an example:
void *io = ioremap(42, 4);
Sparse is not happy:
warning: incorrect type in initializer (different address spaces) expected void *io got void [noderef] <asn:2>*
Or:
u32 __iomem* io = ioremap(42, 4); pr_info("%x\n", *io);
Sparse is not happy either:
warning: dereference of noderef expression
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.
This makes Sparse happy:
void __iomem* io = ioremap(42, 4); pr_info("%x\n", ioread32(io));
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.
Edit: Here's a great LWN article about the inception of __iomem
and functions using it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With