2017-03-22 1 views
0

現在、私は研究関連のプログラムをいくつか開発しており、特定のアドレスのpteが必要です。私の開発環境はJuno r1ボード(CPUはA53とA57)であり、arm64 Linuxカーネルを実行しています。Arm64 Linuxページテーブルウォーク

私はこのようないくつかの典型的なページ・テーブル・ウォーク・コード使用

int find_physical_pte(void *addr) 
{ 
    pgd_t *pgd; 
    pud_t *pud; 
    pmd_t *pmd; 
    pte_t *ptep; 
    unsigned long long address; 

    address = (unsigned long long)addr; 

    pgd = pgd_offset(current->mm, address); 
    printk(KERN_INFO "\npgd is: %p\n", (void *)pgd); 
    printk(KERN_INFO "pgd value: %llx\n", *pgd); 
    if (pgd_none(*pgd) || pgd_bad(*pgd)) 
     return -1; 

    pud = pud_offset(pgd, address); 
    printk(KERN_INFO "\npud is: %p\n", (void *)pud); 
    printk(KERN_INFO "pud value: %llx\n", (*pud).pgd); 
    if (pud_none(*pud) || pud_bad(*pud)) 
     return -2; 

    pmd = pmd_offset(pud, address); 
    printk(KERN_INFO "\npmd is: %p\n", (void *)pmd); 
    printk(KERN_INFO "pmd value: %llx\n",*pmd); 
    if (pmd_none(*pmd) || pmd_bad(*pmd)) 
     return -3; 

    ptep = pte_offset_kernel(pmd, address); 
    printk(KERN_INFO "\npte is: %p\n", (void *)ptep); 
    printk(KERN_INFO "pte value: %llx\n",*ptep); 
    if (!ptep) 
     return -4; 

    return 1; 
} 

をプログラムがアドレス(0xffffffc0008b2000)のためpteをチェックするときしかし、それは常に空pmdを返します。

私の推測では、最初の手順で間違ったpgdがあるということです。私はTims Notescurrent->mmを使用しているとpgd of TTBR0(ユーザスペースpgd)しか得られないと言いましたが、確認したアドレスはカーネルスペースアドレスですので、pgd of TTBR1を取得してください。

私の質問は:カーネルスペースアドレスのpteを取得したい場合は、pgdを取得するのにcurrent->mmを使用できますか?

私ができない場合は、代わりにやりたいことがありますか?

ご提案は大歓迎です!ありがとうございました。

サイモン

+0

'TTBCR'を使用し、ターゲットアドレスに基づいて' TTBR0'または 'TTBR1'のいずれかを返すルーチンを記述してください。これは 'current-> mm'より優れていますが、Linuxの亜種とは違って物理的なARM PTE値を扱っています。 TTBR1は、カーネル空間(新しいLinuxバージョン〜3.xx +)で使用され、ユーザスペースのコンテキストスイッチ上で変更されることはありません。注意:Linux armv8は、TTBR0にEL0を使用し、TTBR1にEL1を使用します。 CP15のクエリ 'unsigned int pa;もあります。 \ t mrc p15、0、%0、c7、c4、0 \ n ":\ t" \ t mcr p15、0、%0、c7、c8、2 \ n " " \ t isb \ n " " "= r"(pa): "0"(0xffff0000)); '物理アドレスの場合。 –

答えて

1

私はあなたが持っている問題は、あなたが現在のプロセスのstruct mm_struct *ポインタを渡しているということだと思います。しかし、カーネルの仮想アドレス空間から渡すアドレス。あなたはinitプロセス(&init_mm)にmmのポインタを渡す必要があります。

pgd = pgd_offset(&init_mm, address);

私は残りの部分は問題ないはずだと思いますが、私はそれをテストしていません。ファイル内のカーネルでどのように処理されているかを見ることもできますarch/arm64/mm/dump.c

+0

こんにちはジェイ、実際にはカーネルの観点からcurrent-> mmはinit_mmと同じですと思います。とにかく、ありがとうございました。 –

0

私はついにこの問題を解決しました。

実際には私のコードは正しいです。私が逃したのは、

アームのページテーブル設計では、いつもメモリがpgdまたはpmdに直接属していますが、私は常にpteエントリを探しています。

私が深くするかどうかを調べるためにビットをチェックした後、私はいつも正しくアドレスを翻訳できます。

関連する問題