GNU/Linux >> Tutoriales Linux >  >> Linux

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

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

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

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

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Usage: %s <phys_addr> <offset>\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 CLI que mmaps /dev/mem .

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

Uso:leer 4 bytes de la dirección física 0x12345678 :

sudo busybox devmem 0x12345678

Escribe 0x9abcdef0 a esa dirección:

sudo busybox devmem 0x12345678 w 0x9abcdef0

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

mapa MAP_SHARED

Al hacer mmapp /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 escrituras de registros de hardware.

CONFIG_STRICT_DEVMEM y nopat

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

  • deshabilitar CONFIG_STRICT_DEVMEM (establecido de forma predeterminada en Ubuntu 17.04)
  • pase el nopat opción de línea de comando del kernel para x86

Los puertos IO aún funcionan sin ellos.

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

Vaciado de caché

Si intenta escribir en la RAM en lugar de en un registro, la CPU puede almacenar en caché la memoria:¿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 vaciarlo o marcar la región como no almacenable en caché:

  • ¿Cómo escribir la memoria espacial del kernel (dirección física) en un archivo usando O_DIRECT?
  • ¿Cómo vaciar la memoria 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 almacenable en caché en Linux?

Así que tal vez /dev/mem no se puede usar de manera confiable para pasar búferes de memoria a dispositivos?

Desafortunadamente, esto no se puede observar en QEMU, ya que QEMU no simula cachés.

Cómo probarlo

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

  • Memoria de la zona de usuario
    • asignar volatile variable en un proceso de espacio de usuario
    • obtener la dirección física con /proc/<pid>/maps + /proc/<pid>/pagemap
    • modifique el valor en la dirección física con devmem , y observe cómo reacciona el proceso de la zona de usuario
  • Memoria Kernelland
    • asignar memoria del kernel con kmalloc
    • obtener la dirección física con virt_to_phys y pásalo de vuelta a la zona de usuario
    • modifique la dirección física con devmem
    • consultar el valor del módulo kernel
  • IO mem y dispositivo de plataforma virtual QEMU
    • crear un dispositivo de plataforma con direcciones de registro físicas conocidas
    • usa devmem escribir en el registro
    • ver printf s salen del dispositivo virtual en respuesta

Bonificación:determine la dirección física para una dirección virtual

¿Hay alguna API para determinar la dirección física de la dirección virtual en Linux?


Linux
  1. Cómo agregar o eliminar un usuario de un grupo en Linux

  2. Cómo eliminar un usuario de un grupo en Linux [Consejo rápido]

  3. ¿Cómo acceder a la carpeta compartida de Windows desde Linux?

  4. ¿Cómo acceder (si es posible) al espacio del kernel desde el espacio del usuario?

  5. Cómo encontrar el uso de la memoria del usuario en Linux

Cómo permitir o denegar el acceso SSH a un usuario o grupo en particular en Linux

Cómo extraer direcciones de correo electrónico de un archivo de texto en Linux

Cómo restringir el acceso SSH a ciertos usuarios en Linux

Cómo cambiar de usuario en Linux

Cómo cambiar la dirección IP en Linux

Linux:¿cómo se divide un espacio de direcciones virtuales de proceso de 64 bits en Linux?