mmap(2)
を使用して、デバイス ファイルをユーザー プロセス メモリにマップできます。 システムコール。通常、デバイス ファイルはファイル システムへの物理メモリのマッピングです。それ以外の場合は、そのようなファイルを作成するか、必要なメモリをユーザー プロセスにマップする方法を提供するカーネル モジュールを作成する必要があります。
もう 1 つの方法は、/dev/mem の一部をユーザー メモリに再マッピングすることです。
編集:mmaping /dev/mem の例 (このプログラムには /dev/mem へのアクセス権が必要です。たとえば、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
/dev/mem
を mmap する小さな CLI ユーティリティです。 .
Ubuntu で次のように取得できます:sudo apt-get install busybox
使用法:物理アドレス 0x12345678
から 4 バイトを読み取る :
sudo busybox devmem 0x12345678
0x9abcdef0
と書く そのアドレスに:
sudo busybox devmem 0x12345678 w 0x9abcdef0
ソース:https://github.com/mirror/busybox/blob/1_27_2/miscutils/devmem.c#L85
mmap MAP_SHARED
/dev/mem
を mmap する場合 、おそらく使用したい:
open("/dev/mem", O_RDWR | O_SYNC);
mmap(..., PROT_READ | PROT_WRITE, MAP_SHARED, ...)
MAP_SHARED
これにより、書き込みがすぐに物理メモリに送られるため、監視が容易になり、ハードウェア レジスタの書き込みがより適切になります。
CONFIG_STRICT_DEVMEM
と nopat
/dev/mem
を使用するには カーネル v4.9 で通常の RAM を表示および変更するには、次のことを行う必要があります:
CONFIG_STRICT_DEVMEM
を無効にする (Ubuntu 17.04 ではデフォルトで設定されています)nopat
を渡します x86 のカーネル コマンド ライン オプション
IO ポートはそれらがなくても機能します。
参照:/dev/mem の mmap は virt_to_phys アドレスの無効な引数で失敗しますが、アドレスはページに合わせられます
キャッシュのフラッシュ
レジスタの代わりに RAM に書き込もうとすると、メモリが CPU によってキャッシュされる可能性があります:Linux でアドレス空間の領域の CPU キャッシュをフラッシュする方法は?そして、それをフラッシュしたり、領域をキャッシュ不可としてマークしたりするための非常にポータブルで簡単な方法がわかりません:
- O_DIRECT を使用してカーネル空間メモリ (物理アドレス) をファイルに書き込む方法
- Linux でアドレス空間の領域の CPU キャッシュをフラッシュする方法
- Linux でキャッシュ不可のメモリ ブロックをユーザー空間に割り当てることはできますか?
だから多分 /dev/mem
メモリ バッファをデバイスに渡すために確実に使用できませんか?
残念ながら、QEMU はキャッシュをシミュレートしないため、これは QEMU では観察できません。
テスト方法
さて、楽しい部分です。ここにいくつかのクールな設定があります:
- ユーザーランドの記憶
volatile
を割り当てる ユーザーランド プロセスの変数/proc/<pid>/maps
で物理アドレスを取得 +/proc/<pid>/pagemap
- 物理アドレスの値を
devmem
で変更します 、そしてユーザーランドのプロセスが反応するのを見てください
- カーネルランド メモリ
kmalloc
でカーネルメモリを割り当てますvirt_to_phys
で物理アドレスを取得 ユーザーランドに戻す- 物理アドレスを
devmem
で変更します - カーネル モジュールから値をクエリ
- IO メモリと QEMU 仮想プラットフォーム デバイス
- 既知の物理レジスタ アドレスを使用してプラットフォーム デバイスを作成する
devmem
を使用 レジスターに書き込むprintf
を見る s が応答して仮想デバイスから出てきます
おまけ:仮想アドレスの物理アドレスを決定
Linux で仮想アドレスから物理アドレスを決定する API はありますか?