linux-4.4/ARMv7_MMU
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
*参照元 [#p6167cc5]
#backlinks
*説明 [#q1f14b1f]
超マニアックです。
Linux カーネルの pte_t に設定する L_PTE_MT_BUFFERABLE な...
***前置き [#h3b5b930]
L_PTE_MT_ なんちゃらにどこで出会うかから説明します。
ドライバにて mmap() システムコールを実装する際に、下記の...
int hogedrv_mmap(struct file *filp, struct vm_area_struc...
{
if (filp->f_flags & O_SYNC) {
vma->vm_page_prot = pgprot_noncached(vma...
}
return remap_pfn_range(vma, vma->vm_start, vma->...
vma->vm_end - vma->vm_start, vma->vm_pag...
}
やりたいことをざっと説明すると、このドライバを open() し...
なお vma->vm_page_prot は pgprot_t 型の変数で、ページをマ...
***前置き その 2: 追ってみよう pgprot_noncached() [#bba34...
ページをマップするときの属性を指定を MMU にどうやって教え...
arch/arm/include/asm/pgtable.h:
#define __pgprot_modify(prot,mask,bits) \
__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
#define pgprot_noncached(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UN...
難しく見えますが大したことはなく、prot の値を L_PTE_MT_MA...
なお L_PTE_MT_ 系マクロの代表的なシンボルと値は下記の通り...
#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0x00) << ...
#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 0x01) << ...
#define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 0x02) << ...
#define L_PTE_MT_WRITEBACK (_AT(pteval_t, 0x03) << ...
#define L_PTE_MT_MINICACHE (_AT(pteval_t, 0x06) << ...
#define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 0x07) << ...
#define L_PTE_MT_DEV_SHARED (_AT(pteval_t, 0x04) << ...
ですので、pgprot_noncached() だと bit5~bit2 が 2進数の 0...
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BU...
この場合は bit5~bit2 が 2進数の 0001 に書き換えられます。
***追ってみよう remap_pfn_range() [#h24aabf1]
次に pgprot_t の値がなぜキャッシュ有効/無効の設定に寄与す...
手がかりは remap_pfn_range() で、第五引数に渡した vma->vm...
-- remap_pfn_range()
-- remap_pud_range()
-- remap_pmd_range()
-- remap_pte_range()
pte_t *pte;
...
pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
...
set_pte_at(mm, addr, pte, pte_mkspecial(pfn_p...
いくつかの関数を経由しますが、最終的にはマップしたいアド...
関数がゴチャゴチャ呼ばれてややこしいので、先に pfn_pte() ...
arch/arm/include/asm/pgtable-2level.h:
static inline pte_t pte_mkspecial(pte_t pte) { return pt...
ARM では素通しするだけの実装なので、無視して良いです。
arch/arm/include/asm/pgtable.h:
#define pfn_pte(pfn,prot) __pte(__pfn_to_phys(pfn)...
include/asm-generic/memory_model.h:
#define __pfn_to_phys(pfn) PFN_PHYS(pfn)
include/linux/pfn.h:
#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT)
まず pgprot_val() ですが pgprot_t から値を取り出すマクロ...
次に __pfn_to_phys() ですが PFN(Page Frame Number, ペー...
最後に __pte() は pte_t 型にキャストするためのマクロです...
以上を総合すると、pte_mkspecial(pfn_pte(pfn, prot)) がや...
set_pte_at(mm, addr, pte, (pfn << 12 | prot));
意味だけを見ればこんなもんです(型の問題で実際にこう書く...
***追ってみよう set_pte_at() [#k9fce554]
渡されたページテーブルエントリと pgprot_t の値の行方を見...
-- set_pte_at(..., pte_t *ptep, pte_t pteval)
-- set_pte_ext(ptep, pteval, ext)
-- cpu_set_pte_ext(ptep, pteval, ext)
-- cpu_v7_set_pte_ext(ptep, pteval, ext)
※ext は基本的には 0 です。
最終的にはアセンブラの関数にたどり着きます。実装は arch/a...
***前置き その 3: 追ってみよう ARMv7 の MMU [#l6797a5f]
この関数を追う前に、ARMv7 の MMU について少し説明しておき...
ARM MMU の第 2レベル記述子の構成は下記の通りです。
(ARM DDI406B B3-10 - B3.3.1 Translation table entry form...
| bit | 9| 8 7 6| 5 4| 3| 2| 1| 0|
| Lv2 entry| AP[2]| TEX[2:0]| AP[1:0]| C| B| 1| XN|
一方で Linux の pte_t の構成は下記の通りです。
| bit | 9| 8| 7| 6| 5 4 3 2| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3:0]| YOUN...
並べてみます。
| bit | 9| 8| 7| 6| 5 4...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3:2]...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1:0]...
以降、この表で Linux の pte_t の値から、ARM MMU の第 2レ...
***追ってみよう cpu_v7_set_pte_ext() [#y1c22098]
前置きはこのくらいにして cpu_v7_set_pte_ext() 関数を見て...
この関数はページテーブルエントリのうち、bit9~bit4, bit1...
| bit | 9| 8| 7| 6| 5| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3]| ...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1]| ...
| ----- |||||||||||
| Clear? | Yes | Yes | Yes | Yes | Yes | ...
| After Clear | -| -| -| -| -| ...
| After Set | -| -| -| -| -| ...
次に pte_t の MT[2] を TEX[0] にコピーします。
| bit | 9| 8| 7| 6| 5| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3]| ...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1]| ...
| ----- |||||||||||
| MT2 -> TEX0 | -| -| -| MT[2]| -| ...
さらに pte_t が !RDONLY && DIRTY なら AP[2] を 0、それ以...
| bit | 9| 8| 7| 6| 5| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3]| ...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1]| ...
| ----- |||||||||||
| Set AP | 0or1| -| -| MT[2]| USER| ...
最初の方で AP[0] を常に 1 にしていましたよね。その値と組...
具体的な値の対応表は下記の通りです。値がどういう意味を持...
|USER |RDONLY|DIRTY|AP[2:0] 結果|特権 R|特権 W|ユーザ R|...
|0 |0 |0 |101 |Yes |No |No |...
|0 |0 |1 |001 |Yes |Yes |No |...
|0 |1 |0 |101 |Yes |No |No |...
|0 |1 |1 |101 |Yes |No |No |...
|1 |0 |0 |111 |Yes |No |Yes |...
|1 |0 |1 |011 |Yes |Yes |Yes |...
|1 |1 |0 |111 |Yes |No |Yes |...
|1 |1 |1 |111 |Yes |No |Yes |...
続いて pte_t の XN ビット(bit9)を XN(bit0)にコピーし...
| bit | 9| 8| 7| 6| 5| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3]| ...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1]| ...
| ----- |||||||||||
| Set XN | 0or1| -| -| MT[2]| USER| ...
この後には、無効なページだったら All 0 にする処理とか、MM...
***追ってみようページテーブルエントリ [#i5ddbdf3]
ARMv6 までの MMU をご存じの方であれば、先ほど作成したペー...
何がおかしいかといえば、
-ARM MMU にて、メモリタイプとキャッシュ属性を指示するため...
-Linux の pte_t にて、メモリタイプとキャッシュ属性を指示...
辺りです。しかしこれで間違ってないんです。理由は ARMv7 の...
-モード 1つ目は ARMv6 までと同様の TEX[2:0] と C, B ビッ...
-モード 2つ目は ARMv7 からの機能で TEX 再マップ(TEX rema...
TEX 再マップが有効になると、指定できる属性が 8パターンに...
TEX 再マップを有効にしたとき、ARM MMU の第 2レベル記述子...
以上を踏まえて先ほどのページテーブルエントリを見直すと、
TEX[0]: MT[2]
C: MT[1]
B: MT[0]
こうなってましたね。なので MT[2:0] はなんと 8パターンのう...
***悲しみのビット達 [#f9db3002]
こんな感じで良くできていて感心しますが、使われないビット...
TEX 再マップモードでは TEX[2:1] ビットに意味がありません...
Linux の pte_t の MT[3:0] は 4ビットなので 16パターンの表...
***まとめ [#f4b3ff07]
まとめるの難しいですが、まとめると pgprot_noncached() を ...
これは TEX 再マップモードの ARMv7 MMU にとって、属性のパ...
参考までに Linux-4.4.1 でのパターン 0 の設定内容は、メモ...
**参考 [#a3db206e]
**関連モジュール [#ua333785]
-ARMv7 MMU の第 2レベル記述子を設定する関数。
--[[linux-4.4.1/cpu_v7_set_pte_ext()]]
-TEX 再マップで使う 8つのパターンを決めているレジスタ。
--[[linux-4.4.1/PRRR]]
--[[linux-4.4.1/NMRR]]
*コメント [#n2444dc7]
終了行:
*参照元 [#p6167cc5]
#backlinks
*説明 [#q1f14b1f]
超マニアックです。
Linux カーネルの pte_t に設定する L_PTE_MT_BUFFERABLE な...
***前置き [#h3b5b930]
L_PTE_MT_ なんちゃらにどこで出会うかから説明します。
ドライバにて mmap() システムコールを実装する際に、下記の...
int hogedrv_mmap(struct file *filp, struct vm_area_struc...
{
if (filp->f_flags & O_SYNC) {
vma->vm_page_prot = pgprot_noncached(vma...
}
return remap_pfn_range(vma, vma->vm_start, vma->...
vma->vm_end - vma->vm_start, vma->vm_pag...
}
やりたいことをざっと説明すると、このドライバを open() し...
なお vma->vm_page_prot は pgprot_t 型の変数で、ページをマ...
***前置き その 2: 追ってみよう pgprot_noncached() [#bba34...
ページをマップするときの属性を指定を MMU にどうやって教え...
arch/arm/include/asm/pgtable.h:
#define __pgprot_modify(prot,mask,bits) \
__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
#define pgprot_noncached(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UN...
難しく見えますが大したことはなく、prot の値を L_PTE_MT_MA...
なお L_PTE_MT_ 系マクロの代表的なシンボルと値は下記の通り...
#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0x00) << ...
#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 0x01) << ...
#define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 0x02) << ...
#define L_PTE_MT_WRITEBACK (_AT(pteval_t, 0x03) << ...
#define L_PTE_MT_MINICACHE (_AT(pteval_t, 0x06) << ...
#define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 0x07) << ...
#define L_PTE_MT_DEV_SHARED (_AT(pteval_t, 0x04) << ...
ですので、pgprot_noncached() だと bit5~bit2 が 2進数の 0...
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BU...
この場合は bit5~bit2 が 2進数の 0001 に書き換えられます。
***追ってみよう remap_pfn_range() [#h24aabf1]
次に pgprot_t の値がなぜキャッシュ有効/無効の設定に寄与す...
手がかりは remap_pfn_range() で、第五引数に渡した vma->vm...
-- remap_pfn_range()
-- remap_pud_range()
-- remap_pmd_range()
-- remap_pte_range()
pte_t *pte;
...
pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
...
set_pte_at(mm, addr, pte, pte_mkspecial(pfn_p...
いくつかの関数を経由しますが、最終的にはマップしたいアド...
関数がゴチャゴチャ呼ばれてややこしいので、先に pfn_pte() ...
arch/arm/include/asm/pgtable-2level.h:
static inline pte_t pte_mkspecial(pte_t pte) { return pt...
ARM では素通しするだけの実装なので、無視して良いです。
arch/arm/include/asm/pgtable.h:
#define pfn_pte(pfn,prot) __pte(__pfn_to_phys(pfn)...
include/asm-generic/memory_model.h:
#define __pfn_to_phys(pfn) PFN_PHYS(pfn)
include/linux/pfn.h:
#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT)
まず pgprot_val() ですが pgprot_t から値を取り出すマクロ...
次に __pfn_to_phys() ですが PFN(Page Frame Number, ペー...
最後に __pte() は pte_t 型にキャストするためのマクロです...
以上を総合すると、pte_mkspecial(pfn_pte(pfn, prot)) がや...
set_pte_at(mm, addr, pte, (pfn << 12 | prot));
意味だけを見ればこんなもんです(型の問題で実際にこう書く...
***追ってみよう set_pte_at() [#k9fce554]
渡されたページテーブルエントリと pgprot_t の値の行方を見...
-- set_pte_at(..., pte_t *ptep, pte_t pteval)
-- set_pte_ext(ptep, pteval, ext)
-- cpu_set_pte_ext(ptep, pteval, ext)
-- cpu_v7_set_pte_ext(ptep, pteval, ext)
※ext は基本的には 0 です。
最終的にはアセンブラの関数にたどり着きます。実装は arch/a...
***前置き その 3: 追ってみよう ARMv7 の MMU [#l6797a5f]
この関数を追う前に、ARMv7 の MMU について少し説明しておき...
ARM MMU の第 2レベル記述子の構成は下記の通りです。
(ARM DDI406B B3-10 - B3.3.1 Translation table entry form...
| bit | 9| 8 7 6| 5 4| 3| 2| 1| 0|
| Lv2 entry| AP[2]| TEX[2:0]| AP[1:0]| C| B| 1| XN|
一方で Linux の pte_t の構成は下記の通りです。
| bit | 9| 8| 7| 6| 5 4 3 2| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3:0]| YOUN...
並べてみます。
| bit | 9| 8| 7| 6| 5 4...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3:2]...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1:0]...
以降、この表で Linux の pte_t の値から、ARM MMU の第 2レ...
***追ってみよう cpu_v7_set_pte_ext() [#y1c22098]
前置きはこのくらいにして cpu_v7_set_pte_ext() 関数を見て...
この関数はページテーブルエントリのうち、bit9~bit4, bit1...
| bit | 9| 8| 7| 6| 5| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3]| ...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1]| ...
| ----- |||||||||||
| Clear? | Yes | Yes | Yes | Yes | Yes | ...
| After Clear | -| -| -| -| -| ...
| After Set | -| -| -| -| -| ...
次に pte_t の MT[2] を TEX[0] にコピーします。
| bit | 9| 8| 7| 6| 5| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3]| ...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1]| ...
| ----- |||||||||||
| MT2 -> TEX0 | -| -| -| MT[2]| -| ...
さらに pte_t が !RDONLY && DIRTY なら AP[2] を 0、それ以...
| bit | 9| 8| 7| 6| 5| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3]| ...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1]| ...
| ----- |||||||||||
| Set AP | 0or1| -| -| MT[2]| USER| ...
最初の方で AP[0] を常に 1 にしていましたよね。その値と組...
具体的な値の対応表は下記の通りです。値がどういう意味を持...
|USER |RDONLY|DIRTY|AP[2:0] 結果|特権 R|特権 W|ユーザ R|...
|0 |0 |0 |101 |Yes |No |No |...
|0 |0 |1 |001 |Yes |Yes |No |...
|0 |1 |0 |101 |Yes |No |No |...
|0 |1 |1 |101 |Yes |No |No |...
|1 |0 |0 |111 |Yes |No |Yes |...
|1 |0 |1 |011 |Yes |Yes |Yes |...
|1 |1 |0 |111 |Yes |No |Yes |...
|1 |1 |1 |111 |Yes |No |Yes |...
続いて pte_t の XN ビット(bit9)を XN(bit0)にコピーし...
| bit | 9| 8| 7| 6| 5| ...
| ARM Linux pte_t| XN| USER| RDONLY| DIRTY| MT[3]| ...
| Lv2 entry | AP[2]| TEX[2]| TEX[1]| TEX[0]| AP[1]| ...
| ----- |||||||||||
| Set XN | 0or1| -| -| MT[2]| USER| ...
この後には、無効なページだったら All 0 にする処理とか、MM...
***追ってみようページテーブルエントリ [#i5ddbdf3]
ARMv6 までの MMU をご存じの方であれば、先ほど作成したペー...
何がおかしいかといえば、
-ARM MMU にて、メモリタイプとキャッシュ属性を指示するため...
-Linux の pte_t にて、メモリタイプとキャッシュ属性を指示...
辺りです。しかしこれで間違ってないんです。理由は ARMv7 の...
-モード 1つ目は ARMv6 までと同様の TEX[2:0] と C, B ビッ...
-モード 2つ目は ARMv7 からの機能で TEX 再マップ(TEX rema...
TEX 再マップが有効になると、指定できる属性が 8パターンに...
TEX 再マップを有効にしたとき、ARM MMU の第 2レベル記述子...
以上を踏まえて先ほどのページテーブルエントリを見直すと、
TEX[0]: MT[2]
C: MT[1]
B: MT[0]
こうなってましたね。なので MT[2:0] はなんと 8パターンのう...
***悲しみのビット達 [#f9db3002]
こんな感じで良くできていて感心しますが、使われないビット...
TEX 再マップモードでは TEX[2:1] ビットに意味がありません...
Linux の pte_t の MT[3:0] は 4ビットなので 16パターンの表...
***まとめ [#f4b3ff07]
まとめるの難しいですが、まとめると pgprot_noncached() を ...
これは TEX 再マップモードの ARMv7 MMU にとって、属性のパ...
参考までに Linux-4.4.1 でのパターン 0 の設定内容は、メモ...
**参考 [#a3db206e]
**関連モジュール [#ua333785]
-ARMv7 MMU の第 2レベル記述子を設定する関数。
--[[linux-4.4.1/cpu_v7_set_pte_ext()]]
-TEX 再マップで使う 8つのパターンを決めているレジスタ。
--[[linux-4.4.1/PRRR]]
--[[linux-4.4.1/NMRR]]
*コメント [#n2444dc7]
ページ名: