Linuxを実行しているARMベースのシステムで、物理アドレスにメモリマップされたデバイスがあります。すべてのアドレスが仮想であるユーザースペースプログラムから、このアドレスからコンテンツを読み取るにはどうすればよいですか?
2 に答える
busybox devmem
busybox devmem
mmapsを使用する小さなCLIユーティリティです/dev/mem
。
あなたはUbuntuでそれを得ることができます:sudo apt-get install busybox
使用法:物理アドレスから4バイトを読み取ります0x12345678
:
sudo busybox devmem 0x12345678
0x9abcdef0
そのアドレスに書き込みます:
sudo busybox devmem 0x12345678 w 0x9abcdef0
ソース:https ://github.com/mirror/busybox/blob/1_27_2/miscutils/devmem.c#L85
mmapMAP_SHARED
mmappingするときは/dev/mem
、次を使用する可能性があります。
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
- カーネルモジュールから値を照会する
- カーネルメモリを
- IOmemおよびQEMU仮想プラットフォームデバイス
- 既知の物理レジスタアドレスを使用してプラットフォームデバイスを作成する
devmem
レジスタへの書き込みに使用- それに応じて時計
printf
が仮想デバイスから出てきます
ボーナス:仮想アドレスの物理アドレスを決定する
mmap(2)
システムコールを使用して、デバイスファイルをユーザープロセスメモリにマップできます。通常、デバイスファイルは、物理メモリからファイルシステムへのマッピングです。それ以外の場合は、そのようなファイルを作成するか、必要なメモリをユーザープロセスにマップする方法を提供するカーネルモジュールを作成する必要があります。
もう1つの方法は、/ dev/memの一部をユーザーメモリに再マッピングすることです。
編集:mmaping / dev / memの例(このプログラムは/ dev / memにアクセスできる必要があります。たとえば、ルート権限があります):
#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;
}