Sie können eine Gerätedatei mit mmap(2) einem Benutzerprozessspeicher zuordnen Systemaufruf. Normalerweise sind Gerätedateien Abbildungen des physischen Speichers auf das Dateisystem. Andernfalls müssen Sie ein Kernelmodul schreiben, das eine solche Datei erstellt oder eine Möglichkeit bietet, den benötigten Speicher einem Benutzerprozess zuzuordnen.
Eine andere Möglichkeit besteht darin, Teile von /dev/mem einem Benutzerspeicher zuzuordnen.
Bearbeiten:Beispiel für mmaping /dev/mem (dieses Programm muss Zugriff auf /dev/mem haben, z. B. Root-Rechte haben):
#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 ist ein winziges CLI-Dienstprogramm, das /dev/mem mmmaps .
Sie können es in Ubuntu erhalten mit:sudo apt-get install busybox
Verwendung:4 Bytes von der physikalischen Adresse 0x12345678 lesen :
sudo busybox devmem 0x12345678
Schreiben Sie 0x9abcdef0 an diese Adresse:
sudo busybox devmem 0x12345678 w 0x9abcdef0
Quelle:https://github.com/mirror/busybox/blob/1_27_2/miscutils/devmem.c#L85
mmap MAP_SHARED
Beim Mapping /dev/mem , möchten Sie wahrscheinlich verwenden:
open("/dev/mem", O_RDWR | O_SYNC);
mmap(..., PROT_READ | PROT_WRITE, MAP_SHARED, ...)
MAP_SHARED bewirkt, dass Schreibvorgänge sofort in den physischen Speicher gehen, was die Beobachtung erleichtert und für Hardware-Registerschreibvorgänge sinnvoller ist.
CONFIG_STRICT_DEVMEM und nopat
Um /dev/mem zu verwenden Um den regulären RAM auf Kernel v4.9 anzuzeigen und zu ändern, müssen Sie zuerst:
- deaktiviere
CONFIG_STRICT_DEVMEM(standardmäßig auf Ubuntu 17.04 eingestellt) - übergeben Sie den
nopatKernel-Befehlszeilenoption für x86
IO-Ports funktionieren auch ohne diese.
Siehe auch:mmap von /dev/mem schlägt mit ungültigem Argument für virt_to_phys-Adresse fehl, aber Adresse ist seitenausgerichtet
Cache leeren
Wenn Sie versuchen, in den RAM statt in ein Register zu schreiben, wird der Speicher möglicherweise von der CPU zwischengespeichert:Wie wird der CPU-Cache für einen Bereich des Adressraums in Linux geleert? und ich sehe keinen sehr tragbaren/einfachen Weg, um es zu leeren oder die Region als nicht zwischenspeicherbar zu markieren:
- Wie schreibt man Kernel Space Memory (physische Adresse) mit O_DIRECT in eine Datei?
- Wie wird der CPU-Cache für eine Region des Adressraums in Linux geleert?
- Ist es möglich, im Benutzerbereich einen nicht zwischenspeicherbaren Speicherblock unter Linux zuzuweisen?
Also vielleicht /dev/mem kann nicht zuverlässig verwendet werden, um Speicherpuffer an Geräte zu übergeben?
Dies ist in QEMU leider nicht zu beobachten, da QEMU keine Caches simuliert.
So testen Sie es
Nun zum lustigen Teil. Hier sind ein paar coole Setups:
- Userland-Speicher
- weisen Sie
volatilezu Variable in einem Userland-Prozess - erhalten Sie die physische Adresse mit
/proc/<pid>/maps+/proc/<pid>/pagemap - Ändern Sie den Wert an der physikalischen Adresse mit
devmem, und beobachten Sie, wie der Userland-Prozess reagiert
- weisen Sie
- Kernelland-Speicher
- Kernelspeicher mit
kmalloczuweisen - erhalten Sie die physische Adresse mit
virt_to_physund an Userland zurückgeben - ändern Sie die physikalische Adresse mit
devmem - den Wert vom Kernelmodul abfragen
- Kernelspeicher mit
- IO mem und virtuelles QEMU-Plattformgerät
- Erstellen Sie ein Plattformgerät mit bekannten physischen Registeradressen
- benutze
devmemin das Register schreiben - schau dir
printfan s kommen vom virtuellen Gerät als Antwort
Bonus:Ermitteln Sie die physische Adresse für eine virtuelle Adresse
Gibt es eine API zum Ermitteln der physischen Adresse aus der virtuellen Adresse in Linux?