ARM LinuxはTTBR1を使っているのか

LWNのSupporting KVM on the ARM architectureの記事にHYPモードのページテーブルに関して、以下のような説明がありました。

for the SVC and USR modes, the hardware has two separate page table base registers, which are used to provide the familiar address space split between user space and kernel. HYP mode only uses a single page table base register and therefore does not allow the address space split between user mode and kernel.

これを読むと、ARMアーキテクチャではLinuxはユーザスペースとカーネルスペースで別々のページテーブルを使っているので1つしかページテーブルを持たないHYPモードでは代わりができない、という風に読めました。私の把握してる範囲ではLinuxはページテーブルを1つしか使ってなかったように記憶していたので確認してみました。

結論から言うと、LPAEが有効になっていない場合はページテーブルは1つだけ使い、LPAEが有効になっている場合はターゲットボードやカーネルコンフィグによってはページテーブルを2つ使う場合があるようです。

以下、例によってリファレンスマニュアルとソースコードを読んで確認してみます。

ARMv7には、OSがカーネルとユーザ用にページテーブルを分けて持つことができるように、ページテーブルのアドレスを格納するレジスタ(x86のCR3相当)が2つ用意されています。これがTTBR0(ユーザ用)とTTBR1(カーネル用)です。またCP15にTranslation Table Base Control Register (TTBCR)というレジスタがあり*1、これを設定することでTTBR0とTTBR1の使い方を制御します。LPAEがなかった頃は、TTBCRの下位3ビット(TTBCR.N[2:0])でTTBR1をどのように使うかを指定することができ、Nを0に設定するとアドレス変換の際にTTBR1を使わずTTBR0のみを使うようになります。

TTBCRはv7_ttb_setupというアセンブリマクロで設定されるのですが、ARM(32bit)にはarch/arm/mm/proc-v7-2level.Sarch/arm/mm/proc-v7-3level.Sの2箇所にその定義があります。

proc-v7-2level.Sとproc-v7-3level.Sのどちらが使われるかは、arch/arm/mm/proc-v7.Sにあるifdefで決定されます。

#ifdef CONFIG_ARM_LPAE
#include "proc-v7-3level.S"
#else   
#include "proc-v7-2level.S"
#endif

LPAEが有効のときにproc-v7-3level.Sそうでないときproc-v7-2level.Sがincludeされます。

proc-v7-2level.Sのv7_ttb_setupは以下のようになっています。

        /*
         * Macro for setting up the TTBRx and TTBCR registers.
         * - \ttb0 and \ttb1 updated with the corresponding flags.
         */
        .macro  v7_ttb_setup, zero, ttbr0, ttbr1, tmp
        mcr     p15, 0, \zero, c2, c0, 2        @ TTB control register
        ALT_SMP(orr     \ttbr0, \ttbr0, #TTB_FLAGS_SMP)
        ALT_UP(orr      \ttbr0, \ttbr0, #TTB_FLAGS_UP)
        ALT_SMP(orr     \ttbr1, \ttbr1, #TTB_FLAGS_SMP)
        ALT_UP(orr      \ttbr1, \ttbr1, #TTB_FLAGS_UP)
        mcr     p15, 0, \ttbr1, c2, c0, 1       @ load TTB1
        .endm

ARM命令を知らないとわかりにくいかもしれませんが、1つ目のmcr命令でCP15にあるTTBCRにゼロ(\zero)を設定しています。つまり、TTBCR.Nは常に0に設定され、LPAEがoffのときはTTBR1は使われないことがわかります。

LPAEがonのときにどうなるかは、長くなりそうなので別エントリで解説する予定です。

*1:B4.1.153 TTBCR, Translation Table Base Control Register, VMSA