2

ページなしの方法で仮想アドレスが物理アドレスにどのように変換されるかは誰でも知っています。Device Drivers book を参照すると、nopage メソッドは次のように指定されます。

struct page *simple_vma_nopage(struct vm_area_struct *vma,
                unsigned long address, int *type)
{
    struct page *pageptr;
    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
    unsigned long physaddr = address - vma->vm_start + offset;
    unsigned long pageframe = physaddr >> PAGE_SHIFT;

    if (!pfn_valid(pageframe))
        return NOPAGE_SIGBUS;
    pageptr = pfn_to_page(pageframe);
    get_page(pageptr);
    if (type)
        *type = VM_FAULT_MINOR;
    return pageptr;
}

page_shift は、仮想メモリ アドレスと物理メモリ アドレスのオフセットを表すために使用されるビット数です。しかし、オフセット変数とは何ですか? address や vm_start などの仮想アドレス変数の算術演算から物理アドレスを計算する方法は?

4

3 に答える 3

2

vm_pgoff のドキュメントがあまり明確ではないように感じます。これは、RAM のメモリ領域の最初のページのオフセットです。したがって、RAM が 0x00000000 で始まり、メモリ領域が 0x0000A000 で始まる場合、vm_pgoff = 10 となります。mmap システム コールを検討/再訪すると、渡す「オフセット」が開始バイトのオフセットであることがわかります。 「長さ」バイトがメモリ領域にマップされるファイル。このオフセットは、12 である PAGE_SHIFT 値 (つまり、ページ サイズごとに 4KB) に左シフトすることにより、アドレスに変換できます。

ここで、cr3 レジスタが線形アドレスから物理アドレスへの変換に使用されるかどうかに関係なく、「アドレス - vm_start」と言うと、アドレス間の部分のサイズが得られます。例: vm_start = 0xc0080000 アドレス = 0xc0090000

address - vm_start = 0x00010000
physaddr    = (address - vma->vm_start) + offset;
            = 0x00010000 + (10 << PAGE_SHIFT)
            = offset_to_page_that_fault + start_addr_of_memoryRegion_in_RAM  
            = 0x00010000 + 0x0000A000
            = 0x0001A000

これは物理アドレスであるため、PAGE_SHIFT 値、つまり 0x0001A000 >> 12 = 0x1A = 26 (10 進数) だけ右にシフトしてページ フレーム番号に変換する必要があるため、26 番目のページ フレームにファイルからのデータをロードする必要がありますマッピングされています。したがって、ディスク上のページの位置情報 (スワップ空間) を含む inode の struct address_sapce を使用して、ディスクからデータが取得されます。データが取り込まれると、このページ フォールトが発生した page_frame でこのデータを表す構造体ページを返します。これをユーザーに返します。

これは最新の私の理解ですが、テストしていません。

于 2013-01-29T18:08:50.703 に答える
0

「simple_region_start」は、サブリージョンをマッピングする必要がある物理メモリの開始からのオフセットです。

例:off =物理メモリの開始(ページ整列)= 0xd000 8000 simple_region_start = 0x1000したがって、マップするサブ領域の開始の物理アドレスは= 0xd000 8000 + 0x1000 = 0xd000 9000

現在、仮想サイズは、使用可能な物理メモリからマッピングする必要がある部分です。これは、ユーザーが適切に定義する必要があります。

simple_region_size=マップする必要のある部分の最後を指す物理アドレス。

したがって、使用可能な物理メモリから8KBをマッピングする場合は、次のように計算します。

simple_region_size = physical address just beyond the last of our portion
simple_region_size = 0xd000 9000 + 0x2000 (for the 8KBs)    
simple_region_size = 0xd000 B000

したがって、8KBの部分は物理アドレス[0xd000B000から0xd0009000]の範囲になります。したがって、物理サイズ、つまりpsize = 0x2000

健全性チェックを実行します。つまり、物理メモリの一部のサイズが、ユーザーがこのメモリ領域の完全長の仮想アドレス範囲を使用してマップしようとするサイズよりも小さい場合、例外が発生します。つまり、例のために言います。vsize = 0x3000

それ以外の場合は、API "remap_pfn_range"を使用して、物理アドレスを渡す物理メモリの部分をマップします。これはIOメモリであるため、以前のようにページフレーム番号ではありません。前述のAPI「io_remap_page_range」だったはずだと思います。

したがって、物理アドレス0xd000 9000から始まる物理メモリの部分を、vsizeのvma->vm_startから始まるユーザー線形アドレスにマップします。

NB以前と同じように、私はまだこれをテストしていません!

于 2013-02-03T13:14:21.477 に答える
0

いいえ、本の記述は正しいため、前述のように、「物理」は、「オフ」の物理アドレスから「simple_region_size」まで始まる物理メモリからマップする必要がある領域/部分の開始のアドレスにすぎません"「simple_region_size」の値はユーザーが決定します。同様に、「simple_region_start」はユーザーが決定します。

simple_region_start >= off

したがって、ユーザーがマップできる最大物理メモリは次のように決定されます。 psize = simple_region_size - off つまり、物理メモリの開始から部分の終了まで。

しかし実際には、このメモリ領域にどれだけマップされるかは、「vma->vm_end - vma->vm_start」で与えられ、vsize で表されます。したがって、ユーザーは意図した以上のものを取得できるため、健全性チェックを実行する必要がありました。

Kind regards,
Sanjeev Ranot
于 2013-02-04T08:41:42.717 に答える