2012-08-09 13 views
13

Tengo un programa simple que intenta acceder a la memoria física en el espacio de usuario, donde el núcleo almacena la primera página de la estructura. En una máquina de 64 bits de esta dirección es:¿Cómo acceder a mmaped/dev/mem sin bloquear el kernel de Linux?

  • núcleo de dirección virtual: ffffea0000000000
  • dirección física: 0000620000000000

Estoy intentando acceder a esta dirección física a través de mmap en el espacio de usuario. Pero el siguiente código bloquea el kernel.

int *addr; 
if ((fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0) { 
    printf("Error opening file. \n"); 
    close(fd); 
    return (-1); 
} 
/* mmap. address of first struct page for 64 bit architectures 
* is 0x0000620000000000. 
*/ 
addr = (int *)mmap(0, num*STRUCT_PAGE_SIZE, PROT_READ, MAP_PRIVATE, 
      fd, 0x0000620000000000); 
printf("addr: %p \n",addr); 
printf("addr: %d \n",*addr); /* CRASH. */ 
+1

¿Cuál es el valor que devuelve mmap() en addr? – BjoernD

+1

@BjoernD: Intenté lo anterior en un x86 de 32 bits (reemplazando el desplazamiento de mmap como 0x01000000); addr = 0xffffffff. Y sí, se bloquea, por supuesto, en la desreferencia. ¿Cual es la solución? – kaiwan

+3

0xffffffff == -1 -> mmap() está devolviendo un error. De acuerdo con la página man, el motivo del error se da en la variable 'errno'. Así que es posible que desee comprobar tat. – BjoernD

Respuesta

18

Creo que he encontrado el problema - tiene que ver con/dev/mem de protección de mapeo de memoria en el x86.

Pl se refieren a este artículo LWN: "x86: introducir restricciones/dev/mem con una opción de configuración" http://lwn.net/Articles/267427/

CONFIG_NONPROMISC_DEVMEM

ahora (i probado esto en una reciente 3.2.21 del núcleo) , la opción de configuración parece llamarse CONFIG_STRICT_DEVMEM.

he cambiado de configuración del núcleo:

$ grep DEVMEM .config 
# CONFIG_STRICT_DEVMEM is not set 
$ 

Cuando el prg anterior se realizó con el kernel anterior, con CONFIG_STRICT_DEVMEM SET: muestra dmesg:

[29537.565599] Program a.out tried to access /dev/mem between 1000000->1001000. 
[29537.565663] a.out[13575]: segfault at ffffffff ip 080485bd sp bfb8d640 error 4 in a.out[8048000+1000] 

Esto se debe a la protección del núcleo ...

Cuando se reconstruyó el kernel (con CONFIG_STRICT_DEVMEM DESACTIVADO) y el PRG anteriormente se corrió:

# ./a.out 
mmap failed: Invalid argument 
# 

Esto es debido a que el parámetro de 'compensar' es> 1 MB (no válidos en x86) (era de 16 MB).

Después de hacer el desplazamiento a estar dentro de 1 MB mmap:

# ./a.out 
addr: 0xb7758000 
*addr: 138293760 
# 

funciona! Vea el artículo anterior de LWN para más detalles.

En las arquitecturas x86 con soporte PAT (tabla de atributos de página), el kernel sigue evitando el mapeo de las regiones DRAM. La razón de esto como se menciona en el kernel source es:

This check is nedded to avoid cache aliasing when PAT is enabled 

Esta verificación causará un error similar a la mencionada anteriormente. Por ejemplo:

Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

Esta restricción se puede eliminar inhabilitando PAT. PAT se puede desactivar agregando el argumento "nopat" a la línea de comandos del kernel en el momento del inicio.

+0

Hola Kaiwan, gracias para señalar la variable de configuración interesante. 'CONFIG_STRICT_DEVMEM no está configurado' en mi caso. Kernel (3.4.6 y 3.1.0). Después de cambiar el desplazamiento, el programa funciona. Pero estaba interesado en acceder a esa dirección, ya que contiene la primera página de la estructura. ¿es posible? – Vinay

+0

También establezco el desplazamiento en 0x0000000000000000 y obtengo una dirección de devolución válida. Pero si configuro el desplazamiento en alguna dirección aleatoria, por ejemplo 0x00000000000000ff, no obtengo una dirección válida. ¿Tengo que establecer la dirección en el límite de la página? – Vinay

+1

ARM requiere el uso de un límite de página para mmap(). De una pequeña prueba en IA32 parece ser el caso allí también ... (y has probado el x86_64 supongo). Además, con su comentario sobre el acceso a la primera página de la estructura, con CONFIG_STRICT_DEVMEM desactivado, pensé que funcionaría (en un límite de página) .. no estoy seguro de esto ... – kaiwan

3

En las arquitecturas x86 con soporte PAT (tabla de atributos de página), el kernel puede evitar el mapeo de regiones DRAM (incluso si se compila sin configurar CONFIG_NONPROMISC_DEVMEM).

La razón de esto como se menciona en el kernel source es:

This check is nedded to avoid cache aliasing when PAT is enabled 

Esta verificación causará un error similar que aparezca en dmesg como el mencionado en la respuesta de Kaiwan por encima de arriba. Por ejemplo:

Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

Esta restricción se puede eliminar inhabilitando PAT.

PAT se puede desactivar agregando el argumento nopat a la línea de comandos del kernel en el momento del inicio.

+0

Esta respuesta (correcta) parece haber sido copiada en la respuesta anterior por un usuario anónimo 8 minutos después de haber respondido. Si quiere que se elimine, avísenme y lo editaré, ya que lo considero injusto si lo hago sin su consentimiento. –

+0

Fui yo. Yo fui quien lo agregó a la respuesta anterior y luego lo agregué como una respuesta separada porque (al parecer) no sé cómo usar la herramienta: D. –

+0

¡Bien! Avíseme si lo quiere eliminar de la respuesta anterior. Aclamaciones. –

Cuestiones relacionadas