ユーザプロセスのメモリをデバイスドライバから任意のタイミングで読み書きする方法のまとめ
Sample code to read/write user process's memory on virtual address from Linux device driver at any given time
https://github.com/mnishz/read_write_user_memory_from_driver
簡単な経緯
仕事で、上に書いたようなことを実現する必要があった。
read()
, write()
, ioctl()
等でユーザプロセスの仮想アドレスを渡して、その関数内でcopy_to_user()
, copy_from_user()
から読み書きすることはできたが、ドライバ側でその仮想アドレスを覚えておいて関数を抜けた後に同様に読み書きしようとするとうまくいかなかった。ユーザプロセスの仮想アドレスしか持ち合わせていない状態でどうやって読み書きしているのかまで追えていないが、コンテキストが絡んでいるのかなーと想像する。
以下、どうやればできるかなと試行錯誤した結果のまとめ。
やり方
ユーザプロセス側
- ユーザプロセス側からヒープメモリを確保する (スタックでも問題ないかも)
- スワップアウトされないように
mlock()
しておく (多分必要) - 仮想アドレスを物理アドレスに変換する
- 参考にしたサイト: https://stackoverflow.com/a/28987409
-
ioctl()
で物理アドレスを渡す
デバイスドライバ側
- 受け取った物理アドレスを
copy_from_user()
でカーネル側にコピーする -
ioremap()
で物理アドレスをカーネルの仮想アドレスにマッピングする - マッピングした仮想アドレスから任意のタイミングでユーザメモリを読み書きできる
サンプルコードで何をやっているのか
user_proc_A ではメモリを確保して ioctl()
で物理アドレスをドライバに渡したあと、値が変わるのをループで待っている。user_proc_B で別の ioctl()
を投げるとドライバが user_proc_A のメモリを書き換えて、それにより user_proc_A がループを抜けて終了する。
参考リンク
https://qiita.com/take-iwiw/items/26d5f7f4894ccc4ce227
https://www.ibm.com/developerworks/jp/linux/library/l-kernel-memory-access/index.html
http://mmi.hatenablog.com/entry/2017/03/21/151320