*参照元 [#j78e2739] #backlinks *説明 [#o202c748] -パス: 複数あり --CONFIG_ARM_LPAE 無効: [[linux-4.4.1/arch/arm/mm/proc-v7-2level.S]] --CONFIG_ARM_LPAE 有効: [[linux-4.4.1/arch/arm/mm/proc-v7-3level.S]] --[[linux-4.4.1/CONFIG_ARM_LPAE]] -FIXME: これは何? --ARM のコードは L_PTE_MT_ シリーズのマクロを使って、pte_t の 2~5 ビットの値を変更する。しかし ARMv7 のページテーブルは pte_t とビット配置が異なり、pte をそのままページテーブルのエントリに書きこめない。そのため変換する必要があるのだろう。たぶん。 **引数 [#sa43dcc7] -ptep -- -pte -- **返り値 [#qe3bdba6] - -- **参考 [#wab5af0c] 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) *実装 [#td122eaa] **CONFIG_ARM_LPAE 無効: arch/arm/mm/proc-v7-2level.S [#o4e2bc40] /* * 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 - --[[linux-4.4.1/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_ 系のビット位置 --PTE_EXT_TEX(1): bit6 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 |AP[1] 結果| |0 |0 | |1 |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_ 系のビット位置 --PTE_EXT_XN: bit0, XN 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] ) -FIXME: なんで 2048足すの?? 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 [#c917eee9] /* * 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) *コメント [#n3bd63a0]