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
- asignar
- 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
- asignar memoria del kernel con
- 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?