参照元†
- FIXME: これは何?
- ARM のコードは L_PTE_MT_ シリーズのマクロを使って、pte_t の 2~5 ビットの値を変更する。しかし ARMv7 のページテーブルは pte_t とビット配置が異なり、pte をそのままページテーブルのエントリに書きこめない。そのため変換する必要があるのだろう。たぶん。
返り値†
L_PTE_MT_ シリーズの実装。
arch/arm/include/asm/pgtable-2level.h:
#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0x00) << 2) /* 0000 */
#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 0x01) << 2) /* 0001 */
#define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 0x02) << 2) /* 0010 */
#define L_PTE_MT_WRITEBACK (_AT(pteval_t, 0x03) << 2) /* 0011 */
#define L_PTE_MT_MINICACHE (_AT(pteval_t, 0x06) << 2) /* 0110 (sa1100, xscale) */
#define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 0x07) << 2) /* 0111 */
#define L_PTE_MT_DEV_SHARED (_AT(pteval_t, 0x04) << 2) /* 0100 */
#define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 0x0c) << 2) /* 1100 */
#define L_PTE_MT_DEV_WC (_AT(pteval_t, 0x09) << 2) /* 1001 */
#define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 0x0b) << 2) /* 1011 */
#define L_PTE_MT_VECTORS (_AT(pteval_t, 0x0f) << 2) /* 1111 */
#define L_PTE_MT_MASK (_AT(pteval_t, 0x0f) << 2)
arch/arm/include/asm/pgtable-3level.h:
#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0) << 2) /* strongly ordered */
#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 1) << 2) /* normal non-cacheable */
#define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 2) << 2) /* normal inner write-through */
#define L_PTE_MT_WRITEBACK (_AT(pteval_t, 3) << 2) /* normal inner write-back */
#define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 7) << 2) /* normal inner write-alloc */
#define L_PTE_MT_DEV_SHARED (_AT(pteval_t, 4) << 2) /* device */
#define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 4) << 2) /* device */
#define L_PTE_MT_DEV_WC (_AT(pteval_t, 1) << 2) /* normal non-cacheable */
#define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 3) << 2) /* normal inner write-back */
#define L_PTE_MT_MASK (_AT(pteval_t, 7) << 2)
CONFIG_ARM_LPAE 無効: arch/arm/mm/proc-v7-2level.S†
/*
* cpu_v7_set_pte_ext(ptep, pte)
*
* Set a level 2 translation table entry.
*
* - ptep - pointer to level 2 translation table entry
* (hardware version is stored at +2048 bytes)
* - pte - PTE value to store
* - ext - value for extended PTE bits
*/
ENTRY(cpu_v7_set_pte_ext)
#ifdef CONFIG_MMU
str r1, [r0] @ linux version
bic r3, r1, #0x000003f0
bic r3, r3, #PTE_TYPE_MASK
orr r3, r3, r2
orr r3, r3, #PTE_EXT_AP0 | 2
- ptep が指す pte_t の値を r1 と r3 に入れて、r3 の値は下記の加工をする。
- r3 のビット 4~9(AP[0:1], TEX[0:2], AP[2])をクリアする。
- r3 のビット 0, 1(ARM のページテーブル第2レベル記述子の種類を示すビット)をクリアする。
- r3 と引数 ext のビット毎 OR を取って、r3 に入れる。
- r3 の AP[0] を 1 に、bit1(スモールページの意味)を 1 にする。
- PTE_EXT_ 系のビット位置
- PTE_TYPE_MASK: bit0:1, XN と bit1(特に名前がない)
- PTE_EXT_AP0: bit4, AP[0]
tst r1, #1 << 4
orrne r3, r3, #PTE_EXT_TEX(1)
- L_PTE_MT_ シリーズ(ビット 2~5 を占めている)のビット 1、すなわち pte_t のビット 4 を r3 のビット 6(TEX[0])に書く。
- PTE_EXT_ 系のビット位置
eor r1, r1, #L_PTE_DIRTY
tst r1, #L_PTE_RDONLY | L_PTE_DIRTY
orrne r3, r3, #PTE_EXT_APX
tst r1, #L_PTE_USER
orrne r3, r3, #PTE_EXT_AP1
- !RDONLY && DIRTY なら r3 の AP[2] を 0、それ以外は 1 にする。
- USER を r3 の AP[1] にコピーする。
- AP[0] は必ず 1(上の解説参照)なので、ここで AP[2:0] が揃う。
- L_PTE_ 系のビット位置
- L_PTE_DIRTY : bit6(2level), bit55(3level)
- L_PTE_RDONLY: bit7(2level), bit58(3level)
- L_PTE_USER : bit8(2level), bit6(3level)
- PTE_EXT_ 系のビット位置
- PTE_EXT_APX: bit9, AP[2]
- PTE_EXT_AP1: bit5, AP[1]
- こう設定するので、
RDONLY | DIRTY | xor DIRTY | AP[2] 結果 |
0 | 0 | 1 | 1 |
0 | 1 | 0 | 0 |
1 | 0 | 1 | 1 |
1 | 1 | 0 | 1 |
- 最終的にはこうなる。
USER | RDONLY | DIRTY | AP[2:0] 結果 | 特権 R | 特権 W | ユーザ R | ユーザ W |
0 | 0 | 0 | 101 | Yes | No | No | No |
0 | 0 | 1 | 001 | Yes | Yes | No | No |
0 | 1 | 0 | 101 | Yes | No | No | No |
0 | 1 | 1 | 101 | Yes | No | No | No |
1 | 0 | 0 | 111 | Yes | No | Yes | No |
1 | 0 | 1 | 011 | Yes | Yes | Yes | Yes |
1 | 1 | 0 | 111 | Yes | No | Yes | No |
1 | 1 | 1 | 111 | Yes | No | Yes | No |
tst r1, #L_PTE_XN
orrne r3, r3, #PTE_EXT_XN
- XN ビットを r3 の XN にコピー。
- L_PTE_ 系のビット位置
- L_PTE_XN: bit9(2level), bit54(3level)
- PTE_EXT_ 系のビット位置
tst r1, #L_PTE_YOUNG
tstne r1, #L_PTE_VALID
eorne r1, r1, #L_PTE_NONE
tstne r1, #L_PTE_NONE
moveq r3, #0
- YOUNG かつ VALID なのに NONE がセットされていたら、r3 を 0 に、つまり無効なページにする。無効なページにアクセスすると必ずフォールトが発生する。
- L_PTE_ 系のビット位置
- L_PTE_YOUNG: bit1(2level), bit10(3level)
- L_PTE_VALID: bit0(2level), bit0(3level)
- L_PTE_NONE : bit11(2level), bit57(3level)
ARM( str r3, [r0, #2048]! )
THUMB( add r0, r0, #2048 )
THUMB( str r3, [r0] )
ALT_SMP(W(nop))
ALT_UP (mcr p15, 0, r0, c7, c10, 1) @ flush_pte
#endif
bx lr
ENDPROC(cpu_v7_set_pte_ext)
CONFIG_ARM_LPAE 有効: arch/arm/mm/proc-v7-3level.S†
/*
* cpu_v7_set_pte_ext(ptep, pte)
*
* Set a level 2 translation table entry.
* - ptep - pointer to level 3 translation table entry
* - pte - PTE value to store (64-bit in r2 and r3)
*/
ENTRY(cpu_v7_set_pte_ext)
#ifdef CONFIG_MMU
tst rl, #L_PTE_VALID
beq 1f
tst rh, #1 << (57 - 32) @ L_PTE_NONE
bicne rl, #L_PTE_VALID
bne 1f
eor ip, rh, #1 << (55 - 32) @ toggle L_PTE_DIRTY in temp reg to
@ test for !L_PTE_DIRTY || L_PTE_RDONLY
tst ip, #1 << (55 - 32) | 1 << (58 - 32)
orrne rl, #PTE_AP2
biceq rl, #PTE_AP2
1: strd r2, r3, [r0]
ALT_SMP(W(nop))
ALT_UP (mcr p15, 0, r0, c7, c10, 1) @ flush_pte
#endif
ret lr
ENDPROC(cpu_v7_set_pte_ext)
コメント†