¿Cómo acceder a las direcciones físicas desde el espacio de usuario en Linux?

En un sistema basado en ARM que ejecuta Linux, tengo un dispositivo cuya memoria está asignada a una dirección física. Desde un progtwig de espacio de usuario donde todas las direcciones son virtuales, ¿cómo puedo leer el contenido de esta dirección?

Puede asignar un archivo de dispositivo a una memoria de proceso de usuario mediante la llamada al sistema mmap(2) . Por lo general, los archivos del dispositivo son asignaciones de memoria física al sistema de archivos. De lo contrario, tiene que escribir un módulo kernel que crea dicho archivo o proporciona una forma de asignar la memoria necesaria a un proceso de usuario.

Otra forma es reasignar partes de / dev / mem a la memoria de un usuario.

Editar: Ejemplo de mmaping / dev / mem (este progtwig debe tener acceso a / dev / mem, por ejemplo, tener derechos de root):

 #include  #include  #include  #include  #include  int main(int argc, char *argv[]) { if (argc < 3) { printf("Usage: %s  \n", argv[0]); return 0; } off_t offset = strtoul(argv[1], NULL, 0); size_t len = strtoul(argv[2], NULL, 0); // Truncate offset to a multiple of the page size, or mmap will fail. size_t pagesize = sysconf(_SC_PAGE_SIZE); off_t page_base = (offset / pagesize) * pagesize; off_t page_offset = offset - page_base; int fd = open("/dev/mem", O_SYNC); unsigned char *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, page_base); if (mem == MAP_FAILED) { perror("Can't map memory"); return -1; } size_t i; for (i = 0; i < len; ++i) printf("%02x ", (int)mem[page_offset + i]); return 0; } 

busybox devmem

busybox devmem es una pequeña utilidad de CLI que mmaps /dev/mem .

Puedes conseguirlo en Ubuntu con: sudo apt-get install busybox

Uso: lea 4 bytes desde la dirección física 0x12345678 :

 sudo busybox devmem 0x12345678 

Escriba 0x9abcdef0 en esa dirección:

 sudo busybox devmem 0x12345678 w 0x9abcdef0 

Fuente: https://github.com/mirror/busybox/blob/1_27_2/miscutils/devmem.c#L85

MAP_SHARED

Cuando mmapping /dev/mem , es probable que desee utilizar:

 open("/dev/mem", O_RDWR | O_SYNC); mmap(..., PROT_READ | PROT_WRITE, MAP_SHARED, ...) 

MAP_SHARED hace que las escrituras vayan a la memoria física inmediatamente, lo que hace que sea más fácil de observar, y tiene más sentido para las grabaciones de registros de hardware.

CONFIG_STRICT_DEVMEM y nopat

Para usar /dev/mem para ver y modificar la memoria RAM regular en kernel v4.9, debe puño:

  • deshabilitar CONFIG_STRICT_DEVMEM (establecido por defecto en Ubuntu 17.04)
  • pasar la opción de línea de comando del kernel nopat para x86

Los puertos IO todavía funcionan sin esos.

Ver también: mmap de / dev / mem falla con un argumento inválido para la dirección de virt_to_phys, pero la dirección está alineada con la página

Lavado de caché

Si intenta escribir en RAM en lugar de en un registro, la memoria puede ser almacenada en la memoria caché por la CPU: ¿Cómo vaciar el caché de la CPU para una región de espacio de direcciones en Linux? y no veo una forma muy portátil / fácil de enjuagarlo o marcar la región como incableable:

  • ¿Cómo vaciar el caché de la CPU para una región de espacio de direcciones en Linux?
  • ¿Es posible asignar, en el espacio de usuario, un bloque de memoria no cacheable en Linux?

¿Entonces /dev/mem no se puede usar de manera confiable para pasar memorias intermedias de memoria a los dispositivos?

Esto no se puede observar en QEMU lamentablemente, ya que QEMU no simula cachés.

Cómo probarlo

Ahora viene la parte divertida. Aquí hay algunas configuraciones geniales:

  • Memoria de usuario
    • asignar variable volatile en un proceso de usuario
    • obtener la dirección física con /proc//maps + /proc//pagemp
    • modifique el valor en la dirección física con devmem , y observe cómo el proceso de userland reactjs
  • Memoria Kernelland
    • asignar memoria de kernel con kmalloc
    • obtener la dirección física con virt_to_phys y pasarla a userland
    • modificar la dirección física con devmem
    • consultar el valor del módulo kernel
  • Dispositivo de plataforma virtual IO mem y QEMU
    • crear un dispositivo de plataforma con direcciones de registros físicos conocidos
    • use devmem para escribir en el registro
    • Ver printf s salir del dispositivo virtual en respuesta