linux memory-management linux-kernel linux-device-driver

¿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.