GNU/Linux >> Linux の 問題 >  >> Linux

Linux でユーザー空間から物理アドレスにアクセスするには?

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_DEVMEMnopat

/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 はありますか?


Linux
  1. Linuxでグループからユーザーを削除する方法[クイックヒント]

  2. LinuxでCからIPアドレスを設定する方法

  3. Linuxカーネルバッファをユーザー空間にmmapする方法は?

  1. Linuxでグループにユーザーを追加またはグループから削除する方法

  2. Linux – SshからTtyにユーザーをログインさせる方法は?

  3. Linuxでユーザーのメモリ使用量を見つける方法

  1. LinuxでIPアドレスを見つける方法

  2. Linux から Windows 共有フォルダにアクセスする方法

  3. ユーザー空間からカーネル空間に(可能であれば)アクセスする方法は?