¿Cuál es el uso de__iomem en linux al escribir controladores de dispositivo?
memory-management linux-kernel (1)
He visto que __iomem se usa para almacenar el tipo de retorno de ioremap() , pero he usado u32 en la arquitectura ARM para ello y funciona bien.
Entonces, ¿qué diferencia hace __iomem aquí? ¿Y en qué circunstancias debo usarlo exactamente?
Muchos de los tipos de fundición van a "funcionar bien". Sin embargo, esto no es muy estricto. Nada le impide lanzar un u32 a un u32 * y u32 * referencia, pero esto no está siguiendo la API del kernel y es propenso a errores.
__iomem es una cookie utilizada por Sparse , una herramienta que se utiliza para encontrar posibles fallas de codificación en el kernel. Si no compila el código del kernel con Sparse habilitado, __iomem se ignorará de todos modos.
Use Sparse primero instalándolo y luego agregando C=1 a su llamada de make . Por ejemplo, al construir un módulo, use:
make -C $KPATH M=$PWD C=1 modules
__iomem se define así:
# define __iomem __attribute__((noderef, address_space(2)))
Agregar (y requerir) una cookie como __iomem para todos los accesos de E / S es una forma de ser más estricto y evitar errores de programación. No desea leer / escribir desde / a las regiones de memoria de E / S con direcciones absolutas porque usualmente usa memoria virtual. Así,
void __iomem *ioremap(phys_addr_t offset, unsigned long size);
normalmente se llama para obtener la dirección virtual de un offset dirección física de E / S, para un size longitud especificado en bytes. ioremap() devuelve un puntero con una cookie __iomem , por lo que ahora se puede usar con funciones en línea como readl() / writel() (aunque ahora es preferible usar las macros más explícitas ioread32() / iowrite32() , por ejemplo) , que aceptan direcciones __iomem .
Además, noderef utiliza el atributo noderef para asegurarse de no desreferir un puntero __iomem . La desreferenciación debería funcionar en algunas arquitecturas donde la E / S está realmente asignada a la memoria, pero otras arquitecturas usan instrucciones especiales para acceder a las E / S y, en este caso, la desreferenciación no funciona.
Veamos un ejemplo:
void *io = ioremap(42, 4);
Sparse no es feliz:
warning: incorrect type in initializer (different address spaces)
expected void *io
got void [noderef] <asn:2>*
O:
u32 __iomem* io = ioremap(42, 4);
pr_info("%x/n", *io);
Sparse tampoco es feliz:
warning: dereference of noderef expression
En el último ejemplo, la primera línea es correcta, porque ioremap() devuelve su valor a una variable __iomem . Pero entonces, lo deferimos, y se supone que no debemos hacerlo.
Esto hace feliz a Sparse:
void __iomem* io = ioremap(42, 4);
pr_info("%x/n", ioread32(io));
Línea inferior: siempre use __iomem donde sea necesario (como un tipo de retorno o como un tipo de parámetro), y use Sparse para asegurarse de que lo hizo. También: no desreferenciar un puntero __iomem .
Edición : Aquí hay un gran artículo de __iomem sobre el inicio de __iomem y las funciones que lo utilizan.