物理アドレスがソートされているが、仮想アドレスが4KiBでソートされないのはなぜですか?

物理アドレスがソートされているが、仮想アドレスが4KiBでソートされないのはなぜですか?

簡単に言えば、私は実際の住所カーネル内部(または9,932,111,872 0x250000000)は明らかに4KiBで並べ替え(ページサイズ)。カーネル関数を使用して__va()取得するときカーネル仮想アドレス、同様のものを取得します0xf570660f(起動ごとに異なります)。4KiBで整列しない

私は64ビットシステムなので、HIGHMEMもなく、リニアメモリモデルのため、4KiBでソートされた物理アドレスの仮想アドレスも4KiBでソートされなければならないと思いました。私が逃したものは何ですか?仮想アドレスは必要ありませんかphys_addr + PAGE_OFFSET?それともsparsememの影響ですか?しかし、おそらく4KiBでソートする必要がありますか?

詳細は次のとおりです。

私の作業環境はx86 64ビットQEMU VMにあります。モードでPMEMをDEV-DAX通常のメモリとして使用しようとしています。物理開始アドレス()を取得でき、0x250000000これが正しいことが確認されました。その後、必要に応じて使用できるようにカーネル空間の仮想アドレスに転送する必要があります。以下はいくつかのコードです。

static long nvpc_map_whole_dev(struct dax_device *dax_dev, void **kaddr, pfn_t *pfn)
{
    // get the device
    struct dev_dax_nvpc *dax_nvpc = (struct dev_dax_nvpc *)dax_get_private(dax_dev);
    
    // get the virtual address and the pfn_t
    *kaddr = __va(dax_nvpc->phys_start);
    *pfn = phys_to_pfn_t(dax_nvpc->phys_start, PFN_MAP);
    
    pr_info("[NVPC DEBUG]: paddr %#llx kaddr %p pfn %lu\n", dax_nvpc->phys_start, *kaddr, pfn_t_to_pfn(*pfn));
    pr_info("[NVPC DEBUG]: kaddr-paddr %#llx\n", __pa(*kaddr));
    return PHYS_PFN(dax_nvpc->size);
}

これが私が得た結果です:

ここに画像の説明を入力してください。

図のように、、、paddr dax_nvpc->phys_startすべてpfn合います。ところでkaddr(仮想アドレスが)混乱していますね。その後、それをkaddr物理アドレス(次の出力ライン)に戻すと、結果は正確です。

もっと重要なのは、ページフォルトなしでkaddrメモリで何でもできることです。kaddr + dax_nvpc->size

仮想アドレスが4KiBでソートされていない理由を教えてくれる人はいますか?私はどこかで愚かですか?また、仮想アドレスをページと並べ替える方法はありますか?

答え1

理由%pは、クイックチェックのためにprintk変更すると、カーネルアドレス出力が期待どおりに4KBにソートされるためです。%p%#llx

その理由はここにあります:カーネルドキュメント:printk型ポインタ型%pprintk は、カーネル情報の漏洩を防ぐためにハッシュされたポインタアドレスを内部的に印刷します。だからポインタが奇妙に見えます。実際の仮想アドレスを確認するには、を使用するか、%pxブートno_hash_pointersパラメータに追加します。詳しい使用方法はリンクを参照してください。

関連情報