私は、LinuxがI / O共有メモリを管理してそれを使用するデバイスと通信する方法について非常に混乱しています。
私が正しく理解した場合、Linuxカーネルは0x100000でマッピングを開始してから(レガシーRAMデータの最初のメガバイトを避け、それを連続したメモリ位置に保存するため)、保護モードに入った後に次のようになります。
- 32ビットシステムには、次のマッピングがあります。
ZONE_NORMALは896MB未満である必要があるため、カーネルリニア1GBと物理896MBの間のマッピングは常に可能です。今は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によって3GiBと4GiBの間の物理メモリアドレスに割り当てられます。ドライバがメモリへのアクセスを要求すると、カーネルはそれをカーネルの仮想アドレス空間内の場所にマッピングします。
しかし、他の2つの質問のどれも共有メモリとは関係がないようです。
どちらの場合も、カーネル空間のアドレスがPAGE_OFFSETより大きい場合はioremapマップを参照する必要があります(ページングで確認)、PAGE_OFFSETより低い場合は単純なNEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSETを使用して確認できます。そうですか?
精神的にはそうです。どちらの場合も、ハードウェアはページテーブルを使用します。
答え2
あなたの質問は次のとおりです。 ioremapはどのように機能しますか?
vaddr = ioremap(paddr_io_mapped_device、サイズ);
vaddrはカーネル空間から返された仮想アドレスです。カーネルは仮想アドレス範囲(vaddr、size)のページテーブルエントリを作成し、それを物理アドレスpaddr_io_shared_deviceにマップします。したがって、仮想アドレス範囲にアクセスすると、io_mapped デバイス内の物理アドレスにアクセスするのと同じです。
重要なのは、返されたvaddrは次のとおりです。キャッシュできません。アドレス範囲を読み書きするたびに、キャッシュではなく io_mapped デバイスから読み書きします。