27

struct page *リストを取得して記述子テーブルを作成し、デバイスとメモリを共有する既存のコードがあります。そのコードの上位層は現在、ユーザー空間と一緒に、vmallocまたはユーザー空間から割り当てられたバッファーを期待しvmalloc_to_pageており、対応するstruct page *.

上位層は、 を介して取得したメモリだけでなく、あらゆる種類のメモリに対処する必要がありますvmalloc。これは、 で取得されたバッファkmalloc、カーネル スレッドのスタック内のポインタ、または私が認識していないその他のケースである可能性があります。私が持っている唯一の保証は、この上位層の呼び出し元が、問題のメモリ バッファがその時点でカーネル空間にマップされていることを確認する必要があることです (つまり、この時点buffer[i]ですべてにアクセスすることが有効です)。任意のポインタに対応するを取得するにはどうすればよいですか?0<=i<sizestruct page*

疑似コードに入れると、次のようになります。

lower_layer(struct page*);
upper_layer(void *buffer, size_t size) {
    for (addr = buffer & PAGE_MASK; addr <= buffer + size; addr += PAGE_SIZE) {
        struct page *pg = vmalloc_to_page(addr);
        lower_layer(pg);
    }
}

upper_layerそして、有効なバッファに対処するために変更する必要があります(変更せずにlower_layer)。

私はvirt_to_pageLinux デバイス ドライバーが「論理アドレス、vmallocまたはハイ メモリからのメモリではなく」で動作することを示していることを発見しました。さらに、is_vmalloc_addrアドレスが から来ているかどうかvmallocvirt_addr_validテストし、アドレスが有効な仮想アドレスであるかどうかをテストします ( の飼料virt_to_page; これにはkmalloc(GFP_KERNEL)と カーネル スタックが含まれます)。他のケースについてはどうですか: グローバル バッファ、ハイ メモリ (今のところ無視できますが、いつか来るでしょう)、おそらく私が気付いていない他の種類ですか? したがって、質問を次のように再定式化できます。

  1. カーネル内のすべての種類のメモリ ゾーンとは?
  2. どうすればそれらを区別できますか?
  3. それぞれのページ マッピング情報を取得するにはどうすればよいですか?

問題がある場合、コードは ARM (MMU を使用) で実行されており、カーネルのバージョンは少なくとも 2.6.26 です。

4

5 に答える 5

15

私はあなたが望むのは、ページテーブルのウォークであると思います(警告、実際のコードではなく、ロックの欠落など):

struct mm_struct *mm = current->mm;
pgd = pgd_offset(mm, address);
pmd = pmd_offset(pgd, address);  
pte = *pte_offset_map(pmd, address);  
page = pte_page(pte);

しかし、これには非常に注意する必要があります。たとえば、取得した kmalloc アドレスは、ページが整列されていない可能性があります。これは私にとって非常に危険な API のように思えます。

于 2011-05-23T15:42:48.837 に答える
7

構造体ページへのアドレスのマッピング

Linux には、仮想アドレスを物理アドレスにマッピングし、構造体ページを物理アドレスにマッピングするための高速な方法が必要です。Linux は、グローバル配列がシステム内の物理メモリを表すすべての構造体ページへのポインターを持っているため、仮想メモリと物理メモリの両方でグローバル mem_map 配列がどこにあるかを知ることでこれを実現します。すべてのアーキテクチャは非常によく似たメカニズムでこれを実現しますが、説明のために、x86 のみを注意深く調べます。

物理カーネル アドレスから仮想カーネル アドレスへのマッピング

任意の仮想アドレスは、PAGE_OFFSET を差し引くだけで物理アドレスに変換できます。これは基本的に、マクロ __pa() を使用した関数 virt_to_phys() が行うことです。

/* from <asm-i386/page.h> */
132 #define __pa(x)        ((unsigned long)(x)-PAGE_OFFSET)

/* from <asm-i386/io.h> */
 76 static inline unsigned long virt_to_phys(volatile void * address)
 77 {
 78         return __pa(address);
 79 }

明らかに、逆の操作には PAGE_OFFSET の追加が含まれます。これは、関数 phys_to_virt() とマクロ __va() によって実行されます。次に、これが構造体ページの物理アドレスへのマッピングにどのように役立つかを見ていきます。

virt_to_phys() を使用して仮想アドレスを物理アドレスに変換できない例外が 1 つあります。 具体的には、PPC およびARM アーキテクチャでは、virt_to_phys() を使用して、consistent_alloc() 関数によって返されたアドレスを変換することはできません。Consistent_alloc() は、PPC および ARM アーキテクチャで使用され、DMA で使用するために非キャッシュからメモリを返します。

カーネル内のすべての種類のメモリ ゾーンとは? <---こちらをご覧ください

于 2011-05-23T16:21:24.117 に答える
3

ユーザー空間に割り当てられたメモリの場合はget_user_pages、 を使用します。これにより、malloc されたメモリに関連付けられたページのリストが得られ、それらの参照カウンターもインクリメントされます (処理がpage_cache_release完了したら、各ページで呼び出す必要があります)。

vmalloc されたページの場合vmalloc_to_pageは、あなたの友人であり、何もする必要はないと思います。

于 2014-08-27T17:25:32.913 に答える
2

64 ビット アーキテクチャの場合、gby の回答は次のように調整する必要があります。

 pgd_t * pgd;
 pmd_t * pmd;
 pte_t * pte;
 struct page *page = NULL;
 pud_t * pud;
 void * kernel_address;

 pgd = pgd_offset(mm, address);
 pud = pud_offset(pgd, address);
 pmd = pmd_offset(pud, address);
 pte = pte_offset_map(pmd, address);
 page = pte_page(*pte);

 // mapping in kernel memory:
 kernel_address = kmap(page);

 // work with kernel_address....

 kunmap(page);
于 2015-06-04T13:03:06.287 に答える
1

あなたは試すことができvirt_to_pageます。それがあなたが望むものかどうかはわかりませんが、少なくとも探し始める場所です.

于 2011-05-16T09:51:18.763 に答える