2013/10/27(日)LDD2_Chap13

本コンテンツは更新中です。
書籍を置いてきたので、和文(本)を読めば進みが早いかもしれません。
が、単語の役され方次第で混乱するので原文も参照する必要があるでしょう。
内容理解という点では、進みは同じかもしれません。。

前置き

ざっくりとここを流し読み。基本、ドライバ開発者向けの資料なので、何もなければkernel空間での話だと思う。
DMAを触るためには、kernelのメモリ管理を知らなければならない、ということですね。
メモリ枯渇も目にすることが多いけれど、意味がわからないことがあるので、
ちょっとお勉強…。このレベルでもguruには程遠いというので、精進が足りなさすぎる…のね。

http://www.xml.com/ldd/chapter/book/ch13.html

アドレスの種類

name 説明
User virtual addresses,仮想アドレスユーザ空間のプログラムから見える一般的なアドレスです。 ユーザアドレスは、32bitか64bitの長さで、ハードウェアアーキテクチャと 各プロセス毎の仮想アドレス空間に基づきます。
Physical addresses, 物理アドレスこのアドレスは、プロセッサとシステムのメモリとの間で使用される。 物理アドレスは32bitまたは64bitの量である。 32ビットシステムでも、いくつかの状況では、64ビットの物理アドレスを使用することができます。
Bus addresses, バスアドレスこのアドレスは周辺バスとメモリの間で使用される。 多くの場合、それらは、プロセッサによって使用される物理アドレスと同じであるが、それは必ずしもそうではない。 バスアドレスは、もちろん、非常にアーキテクチャに依存している。
Kernel logical addresses, カーネル論理アドレスこれらはカーネルの通常のアドレス空間を構成しています。 これらのアドレスは、ほとんどまたはメインメモリのすべてのマップします。 そして、これらは物理アドレスであるかのように頻繁に扱われます。 ほとんどのアーキテクチャでは、(カーネル)論理アドレスとそれに関連付けられた 物理アドレスは、一定のオフセットだけ異なる。 (カーネル)論理アドレスは、ハードウェアのネイティブポインタサイズを使用するので、 重度に使用する*1 32ビットシステム上の物理メモリのすべてに対処できない可能性があります。 論理アドレスは通常型unsigned long型またはvoid*の変数に格納されています。 kmallocのから返されたメモリは、(カーネル)論理アドレスを持っています。
Kernel virtual addresses, カーネル仮想アドレスこれらは、必ずしも物理アドレスに直接マッピングされていないという点で、(カーネル)論理アドレスとは異なる。 すべての論理アドレスは、カーネル仮想アドレスである; vmalloc()で割り当てられたメモリは、仮想アドレスも持ちます。ただし物理アドレスに直接マッピングされていません。 kmap関数も、仮想アドレスを返します。 仮想アドレスは、通常はポインタ変数に格納されています。

論理アドレスを使用している場合、マクロ __pa()(<asm/page.h>で定義されている)は、それに関連する物理アドレスを返します。
物理アドレスは、__va()マクロで(カーネル)論理アドレスにマッピングできます。ただしlow-memoryページに対してのみです。
異なるカーネル関数は、異なるアドレスの型を要求します。
必要なアドレスの種類が明示的となるように定義された別のCの型があったならば良いだろうが、我々はそのような運を持っていません。
どちらのアドレス型をどこで使うのかを明確にします。

High and Low Memory

論理アドレスと、カーネル仮想アドレスとの差は、大量のメモリが装備されている32bitシステム上で強調される。
32bitだと、4GBのメモリを表現することができる。
最近までは、32bitシステムのLinuxは、それよりも大幅に少ないメモリに限定されていました。
しかし、仮想アドレス空間を設定することで解決することができます。(超意訳)
そのシステムでは、論理アドレスを設定することができ、より多くのメモリを扱うことができませんでした。
それが必要なので、すべてのメモリをカーネルアドレスに直接マップしました。

最近の開発では、メモリの制限を排除しており、32bitシステムでは、今のシステムメモリである4GBを優に超えるメモリで作業できます。
(もちろん、プロセッサ自身がより多くのメモリをアドレスできると仮定する)
しなしながら、多くのメモリを直接論理アドレスにマッピングする方法についての制限は残っている。

メモリの最下部(上限1〜2GB、kernel config.とハードウェアに依存します)だけは、論理アドレスを持っています。残り(high-memory)は違います。
high-memoryは、64bit物理アドレスを必要とすることができます。
そして、カーネルは、それを操作するための明示的な仮想アドレスのマッピングを設定する必要があります。
したがって、多くのカーネル関数は、メモリ不足に制限される。
high memoryは、ユーザ空間プロセスページのために予約される傾向にある。

"high memory"という語は、PCの世界で別の意味を持っているため、誰かを混乱させることがあります。
ここでは、語彙を以下のように定義します。
Type describe
Low memoryカーネル空間に存在する、論理アドレスメモリ。 よく遭遇するほぼすべてのシステムで、すべてのメモリはlow memoryです。
On almost every system you will likely encounter, all memory is low memory.
High memoryカーネル空間に論理アドレスが存在しないメモリ。 32bitでアドレッシングできるよりも多い物理メモリを搭載したシステム。
と、いいつつも、実際には memory mapped I/Oが存在するので、
自由に使える空間は32bit全域では無いわけですが。。
時間も無いのでキーワードだけ。

The Memory Map and struct page

high memoryをサポートするため、struct pageが存在する。
参照カウントとwait queueを有しており、low-memoryにmapされていればそのアドレスを持つ。
low-memoryにmapされていない状態もある。

ruct page *virt_to_page(void *kaddr);
カーネル論理アドレスを引数に渡す。vmalloc()やhigh memoryのアドレスでは、機能しない。
void *page_address(struct page *page);
page構造体のポインタを渡して、このページが指すカーネルアドレスを返す。
high-memoryの場合、mapされている場合に返してくる。
#include <linux/highmem.h>
void *kmap(struct page *page);
void kunmap(struct page *page);
low-memoryでも、high-memoryでも適切に機能し、カーネル仮想アドレスを返す。
high-memoryの場合、適切な(システムに依存した定められた)空間にmapしてから返してくれる。
限られた空間なので、kunmap()の呼び出しは必須である。

Page Tables

kernelのメモリ管理にかかわる構造体。<asm/page.h>にて定義されている。
(ARMで云うなら、4Kpageまで分解するのにテーブルルックアップを3回必要とするので、そのソフトウェア版と見ればよい、か?(消化中))
略語 name description
?struct mm_struct
PGDpgd_tPage Directory.
PMDpmd_tPage mid-level Directory.
PTEpte_tPage Table.
?struct page



*1 : heavily equipped 32-bit systems.

補足事項?

"BSS"は、歴史的な遺物です。
古いアセンブリ演算子から来ていて、意味は"Block Started by Symbol"です。