簡単に言えば、私は実際の住所カーネル内部(または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型ポインタ型。%p
printk は、カーネル情報の漏洩を防ぐためにハッシュされたポインタアドレスを内部的に印刷します。だからポインタが奇妙に見えます。実際の仮想アドレスを確認するには、を使用するか、%px
ブートno_hash_pointers
パラメータに追加します。詳しい使用方法はリンクを参照してください。