High Memory Handling

もともと、Linux Kernelのソースコードの一部なので、GPLv2扱いになる（はずの認識）。

> https://www.kernel.org/doc/html/latest/index.html
> 
> Licensing documentation
> 
> The following describes the license of the Linux kernel source code (GPLv2), how to properly mark the license of individual files in the source tree, as well as links to the full license text.
> 
> https://www.kernel.org/doc/html/latest/process/license-rules.html#kernel-licensing

https://www.kernel.org/doc/html/latest/vm/highmem.html

High Memory Handling
By: Peter Zijlstra <a.p.zijlstra@chello.nl>

# What Is High Memory?

> High memory (highmem) is used when the size of physical memory approaches or exceeds the maximum size of virtual memory. 

High memory (highmem)は、物理メモリのサイズが仮想メモリの最大サイズに近づくか、あまた超えるときに使用されます。

> At that point it becomes impossible for the kernel to keep all of the available physical memory mapped at all times. 

その時点で、カーネルが使用可能なすべての物理メモリを、常時マップした状態を保つことはできなくなります。

> This means the kernel needs to start using temporary mappings of the pieces of physical memory that it wants to access.

これは、カーネルがアクセスしようとする物理メモリの一部を、一時的にマッピングしはじめる必要があることを意味します。

.

> The part of (physical) memory not covered by a permanent mapping is what we refer to as ‘highmem’. 

永続的なマッピングだけではカバーされない(物理)メモリの部分は、`highmem`と称されます。。
> There are various architecture dependent constraints on where exactly that border lies.

境界がどこに位置するのかについては、アーキテクチャ依存に関する様々な制約があります。

.

> In the i386 arch, for example, we choose to map the kernel into every process’s VM space so that we don’t have to pay the full TLB invalidation costs for kernel entry/exit.

例えば、i386アーキの場合、kernelをすべてのプロセスの仮想マシン空間にマップすることを選択する。我々はkernel entry/exitのために、full TLB 無効化コストを支払う事が不要となる。

 This means the available virtual memory space (4GiB on i386) has to be divided between user and kernel space.

つまり、利用可能な仮想メモリ空間(i386では4GiB)が、ユーザーとカーネル空間の間で分割されることを意味します。

.

The traditional split for architectures using this approach is 3:1, 3GiB for userspace and the top 1GiB for kernel space:

このアプローチを採用したアーキテクチャの従来からの分割方法は、3:1です、3GiBはユーザー空間に、top 1GiBはカーネル空間に割り当てます。

.

```plaintext
+--------+ 0xffffffff
| Kernel |
+--------+ 0xc0000000
|        |
| User   |
|        |
+--------+ 0x00000000
```

> This means that the kernel can at most map 1GiB of physical memory at any one time, but because we need virtual address space for other things - including temporary maps to access the rest of the physical memory - the actual direct map will typically be less (usually around ~896MiB).

これは、カーネルが一度に最大で1GiBの物理メモリをマップできることを意味します。物理メモリの残りの部分にアクセスするための一時的なマップなど、他のもののために仮想アドレス空間が必要なため、実際の直接マップは通常はそれ以下になります（通常は約896MiB）。

.

> Other architectures that have mm context tagged TLBs can have separate kernel and user maps. Some hardware (like some ARMs), however, have limited virtual space when they use mm context tags.

mm context tagged TLBsを有する他のアーキテクチャでは、分割されたカーネルとユーザーマップを持つことができます。ただし、一部のハードウェア（例えば、ARMの一部）では、mm context tagsを用いると仮想空間に制限が発生します。

# Temporary Virtual Mappings

> The kernel contains several ways of creating temporary mappings:

kernelは一時的なマッピングを生成するためのいくつかの方法を有します。

.

> * vmap(). This can be used to make a long duration mapping of multiple physical pages into a contiguous virtual space. It needs global synchronization to unmap.

* vmap(). これは連続した仮想空間に複数の物理ページを長い期間にわかって作る事ができる。これは、unmapするためには、global synchronizationが必要になる。

> * kmap(). This permits a short duration mapping of a single page. It needs global synchronization, but is amortized somewhat. It is also prone to deadlocks when using in a nested fashion, and so it is not recommended for new code.

* kmap().これは単一ページに対する短い期間のマッピングを実行する。global synchronizationが必要が必要になるが、いくらかコストは軽減されている。入れ子にして利用するとデッドロックが発生することがあるので、新しいコードには推奨できない。

> * kmap_atomic(). This permits a very short duration mapping of a single page. Since the mapping is restricted to the CPU that issued it, it performs well, but the issuing task is therefore required to stay on that CPU until it has finished, lest some other task displace its mappings.
.
kmap_atomic() may also be used by interrupt contexts, since it is does not sleep and the caller may not sleep until after kunmap_atomic() is called.
.
It may be assumed that k[un]map_atomic() won’t fail.

* kmap_atomic(). これにより単一ページを非常に短い期間マッピングすることができます。魔ピングはそれを実行したCPUに制限されるため、他のタスクがそのマッピングを置き換えないように、完了するまでそのCPUで処理を続けなければなりません。
.
kmap_atomic()はまた割り込みコンテクストの中で利用することができます。それはsleepされず、また、呼び出し元はkunmap_atomic()を呼び出すまでスリープしません。
.
k[un]map_atomic()は失敗しないと想定する必要があります。

# Using kmap_atomic

> When and where to use kmap_atomic() is straightforward. 

kmap_atomic()をいつ、どこで使えばよいのか、ということは明快です。

> It is used when code wants to access the contents of a page that might be allocated from high memory (see __GFP_HIGHMEM), for example a page in the pagecache. 

これはコードがページキャッシュ内のページのように、high memory(__GFP_HIGHMEM)で確保されるページなどにアクセスする場合に利用されます。

> The API has two functions, and they can be used in a manner similar to the following

APIは２つの関数があり、それぞれ利用方法は下記のような方法となります。

.

```c
/* Find the page of interest. */
struct page *page = find_get_page(mapping, offset);

/* Gain access to the contents of that page. */
void *vaddr = kmap_atomic(page);

/* Do something to the contents of that page. */
memset(vaddr, 0, PAGE_SIZE);

/* Unmap that page. */
kunmap_atomic(vaddr);
```

> Note that the kunmap_atomic() call takes the result of the kmap_atomic() call not the argument.

kummap_atomic()がkmap_atomic()が呼び出された結果如何に関わらず、呼び出さることを気を付けてください。

> If you need to map two pages because you want to copy from one page to another you need to keep the kmap_atomic calls strictly nested, like:

もしあなたが２つのページをマッピングすることで、あるページから別のページにコピーしたい場合には、厳密な入れ子構造をもってkmap_atomic()を呼び出す必要があります。例えば、

```c
vaddr1 = kmap_atomic(page1);
vaddr2 = kmap_atomic(page2);

memcpy(vaddr1, vaddr2, PAGE_SIZE);

kunmap_atomic(vaddr2);
kunmap_atomic(vaddr1);
```

# Cost of Temporary Mappings

> The cost of creating temporary mappings can be quite high. 

一時的なマッピング生成するコストは非常に高くなる可能性があります。

> The arch has to manipulate the kernel’s page tables, the data TLB and/or the MMU’s registers.

アーキテクチャはカーネルのページテーブル、data TLB また/そして、MMU registerを操作する必要があります。

.

> If CONFIG_HIGHMEM is not set, then the kernel will try and create a mapping simply with a bit of arithmetic that will convert the page struct address into a pointer to the page contents rather than juggling mappings about. In such a case, the unmap operation may be a null operation.


 CONFIG_HIGHMEMが設定されていない場合、カーネルは、ページ構造体のアドレスを、マッピングをジャグリングする代わりに、ページの内容へのポインターに変換する少しの算術演算でマッピングを作成しようとします。 このような場合、マップ解除操作はnull操作になる可能性があります。

.

> If CONFIG_MMU is not set, then there can be no temporary mappings and no highmem. In such a case, the arithmetic approach will also be used.

CONFIG_MMUが設定されていない場合、一時的なマッピングやhighmemが存在しない可能性があります。 そのような場合でも、算術アプローチが利用されます。

.

# i386 PAE

> The i386 arch, under some circumstances, will permit you to stick up to 64GiB of RAM into your 32-bit machine. This has a number of consequences:

状況に基づき、i386アーキテーク茶でも、32ビットマシンに最大64GiBのRAMを取り付けることができます。 これには多くの影響があります。

> * Linux needs a page-frame structure for each page in the system and the pageframes need to live in the permanent mapping, which means:

* Linuxは、システムに含まれるそれぞれのページでpage-drame構造を要求し、pageframesはそれが意味する永続的なマッピングの中で有効である。つまり、

> * you can have 896M/sizeof(struct page) page-frames at most; with struct page being 32-bytes that would end up being something in the order of 112G worth of pages; the kernel, however, needs to store more than just page-frames in that memory…

* (i386では) 最大で896M/sizeof（struct page）のページフレームを持つことができます。struct pageは32バイトであり、112G相当のページになるでしょう。 ただし、カーネルは当該メモリにページフレーム以上のものを格納する必要があります…

> * PAE makes your page tables larger - which slows the system down as more data has to be accessed to traverse in TLB fills and the like. One advantage is that PAE has more PTE bits and can provide advanced features like NX and PAT.

* PAEはpage tablesをより大きくするでしょう。つまり、TLB fillsなどでトラバースするため、より多くのデータに対してアクセスする必要があり、システムが遅くなります。１つの利点は、PAEによってよりPTE bitを大きくできることで、NXやPATのような新たな特徴を提供できます。

> The general recommendation is that you don’t use more than 8GiB on a 32-bit machine - although more might work for you and your workload, you’re pretty much on your own - don’t expect kernel developers to really care much if things come apart.

一般的な推奨としては、32bit machineでは8GiBを越えて利用しないことです。これは、ユーザーとユーザー負荷に効果があるかもしれません。しかし、それはあなた自身でやってください。何か問題が起きたとしても、カーネル開発者が気にすることを本当に期待しないでください。