問題
<オール>エウレカ
しかし、機能は存在します! 2.6 カーネル ソース コードの奥深くに埋もれているこの関数は、仮想アドレスから構造体ページを取得し、「テスト用」としてマークされ、#if 0:でブロックされます。
#if 0 /* This is just for testing */
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
{
unsigned long start = address;
int length = 1;
int nr;
struct page *page;
struct vm_area_struct *vma;
vma = find_vma(mm, addr);
if (!vma || !is_vm_hugetlb_page(vma))
return ERR_PTR(-EINVAL);
pte = huge_pte_offset(mm, address);
/* hugetlb should be locked, and hence, prefaulted */
WARN_ON(!pte || pte_none(*pte));
page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
WARN_ON(!PageHead(page));
return page;
}
解決策:上記の関数は実際にはカーネルにコンパイルされていないため、ドライバー ソースに追加する必要があります。
ユーザー側のワークフロー
<オール>カーネル ドライバーのワークフロー
<オール>免責事項
- 上記の手順は、数年後に回想されています。元のソース コードにアクセスできなくなりました。十分な注意を払って、私が手順を忘れていないことを確認してください。
- これが機能する唯一の理由は、起動時に 1 GB のヒュージ ページが割り当てられ、その物理アドレスが永久にロックされるためです。非 1GBhugepage に裏打ちされたユーザー仮想アドレスを DMA 物理アドレスにマップしようとしないでください!大変なことになるぞ!
- システムを注意深くテストして、1 GB のヒュージ ページが実際に物理メモリにロックされていること、およびすべてが正確に機能していることを確認します。このコードは私のセットアップでは問題なく動作しましたが、何か問題が発生した場合、大きな危険が伴います。
- このコードは、x86/x64 アーキテクチャ (物理アドレス ==バス アドレス) およびカーネル バージョン 2.6.XX でのみ動作することが保証されています。新しいカーネル バージョンではこれを行う簡単な方法があるかもしれませんが、現在は完全に不可能かもしれません。
これはカーネル空間では一般的に行われないため、例はあまり多くありません。
他のページと同様に、巨大なページは alloc_pages で割り当てられます。
struct page *p = alloc_pages(GFP_TRANSHUGE, HPAGE_PMD_ORDER);
HPAGE_PMD_ORDER はマクロであり、通常のページに関して単一のヒュージ ページの順序を定義します。上記は、透過的なヒュージ ページがカーネルで有効になっていることを意味します。
次に、取得したページ ポインターを通常の方法で kmap() を使用してマッピングすることができます。
免責事項:私は自分で試したことがないので、実験する必要があるかもしれません.確認すべきことの 1 つは、HPAGE_PMD_SHIFT が小さい「巨大な」ページの順序を表していることです。これらの巨大な 1 GB ページを使用したい場合は、おそらく PUD_SHIFT - PAGE_SHIFT など、別の順序を試す必要があります。
vi/vimのCコードで関数の呼び出し元と呼び出し先を見つける方法は?
親プロセスが終了したときに、subprocess.check_output() で作成された python 子プロセスを強制終了する方法は?