特定の物理アドレスを特定の仮想アドレスにマップする必要がある Linux カーネル モジュールを作成していますが、それを行う方法が見つかりません。
2 に答える
OK、これが私の現在の解決策です。にマップphys_addr
するには、次のvirt_addr
コードを使用します。
page = pfn_to_page(virt_addr >> PAGE_SHIFT);
pte = get_locked_pte(&init_mm, phys_addr, &ptl);
set_pte_at(&init_mm, phys_addr, pte, mk_pte(page, VM_READ | VM_WRITE | VM_EXEC));
spin_unlock(ptl);
flush_tlb_all();
いくつかの説明: pfn_to_page
func を使用して、 my に対応するページ構造体を取得しますvirt_addr
。必要な物理アドレスと初期化されていないスピンロック ( )を必要とする func を使用して、ページ テーブル エントリ ( pte
)を取得します。次に、 func とマクロを使用して実際にページをマップし、スピンロックのロックを解除して、tlb キャッシュをフラッシュします。get_locked_pte
pte
ptl
set_pte_at
mk_pte
このソリューションは、コンテキストの切り替えには耐えられませんが、かなりうまく機能しているようです。
使用しているカーネルのバージョンと CPU アーキテクチャ/タイプを教えてください。一般的に言えば、マッピング先の特定の仮想アドレスがカーネル仮想アドレス (0xC0000000 など) と重複しない場合、およびデバイスが使用している物理アドレスがシステム メモリの物理アドレス範囲と重複しない場合は、以下を使用できます。低レベル関数 (存在しない場合は、アセンブル言語を使用して、カーネルの起動中に直接 MMU TLB エントリを設定できます) を使用して、カーネルの起動中に特定のアドレスを特定の仮想アドレスにマップするように MMU TLB エントリを設定します。2.6.10 カーネル バージョンと Freescale PowerPC CPU に基づく 1 つの例を提供できます。必要なことを行う関数 io_block_mapping があります。