Linux I/O 共有メモリアクセス

Linux I/O 共有メモリアクセス

Linux が I/O 共有メモリを管理して、それを使用するデバイスと通信する方法がかなりわかりません。

私の理解が正しければ、Linux カーネルは 0x100000 にマップされて開始し (最初のメガバイトのレガシー RAM データを回避し、連続したメモリ位置に格納するため)、その後保護モードに入った後、次のようになります。

  • 32ビットシステムではこのようなマッピングがあります

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

ZONE_NORMAL は 896 MB 未満である必要があるため、カーネルの線形 1GB と物理的な 896 MB 間のマッピングは常に可能です。今のところ、ZONE_DMA は無視しましょう (PCI はメモリ内のどこでも DMA 転送を使用できるようになったため、これはレガシー システムのみを対象としていると読みました)

  • 64ビットシステムでは、カーネルの線形アドレス空間はPAGE_OFFSET= 0xffff810000000000から始まる必要があります。

どちらの場合も、カーネル空間のアドレスが PAGE_OFFSET より大きい場合は、ioremap マッピングを参照する必要があります (ページネーションによって解決されます)。PAGE_OFFSET より小さい場合は、単純な NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET で解決できます。これは正しいですか?

ボーナスの質問: カーネルが起動して実行され、整理が完了したとき、カーネルは物理的に 0x100000 以降 (最初の GB 内) にまだ存在しますか? 64 ビット システムでも同様ですか?

答え1

PC では、ハードウェア メモリ マップ IO 範囲は、BIOS によって 3 GiB から 4 GiB の間の物理メモリ アドレスに割り当てられます。ドライバーがメモリへのアクセスを要求すると、カーネルはそれをカーネル仮想アドレス空間のどこかにマップします。

他の 2 つの質問はどちらも共有メモリとは関係がないようですが、

どちらの場合も、カーネル空間のアドレスが PAGE_OFFSET より大きい場合は、ioremap マッピングを参照する必要があります (ページネーションによって解決されます)。PAGE_OFFSET より小さい場合は、単純な NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET で解決できます。これは正しいですか?

精神的には、そうです。どちらの場合でも、ハードウェアはページ テーブルを使用します。

答え2

質問は次のようになります。ioremap はどのように機能しますか。

vaddr = ioremap(paddr_io_mapped_device、サイズ);

vaddr はカーネル空間内の仮想アドレスとして返されます。カーネルは仮想アドレス範囲 (vaddr 、サイズ) のページ テーブル エントリを作成し、それを物理アドレス paddr_io_shared_device にマップします。したがって、仮想アドレス範囲にアクセスすると、io_mapped デバイス内の物理アドレスにアクセスするのと同じ効果が得られます。

重要なのは、返されるvaddrがキャッシュ不可アドレス範囲を読み書きするたびに、キャッシュからではなく、io_mapped デバイスから読み書きされます。

関連情報