remap_pfn_range 呼び出しがカーネル BUG() をトリガーするのはなぜですか
ここBUG_ON
でのマクロremap_pfn_range
の呼び出し
2277 BUG_ON(addr >= end);
remap_pfn_range
を呼び出すremap_pud_range
を呼び出す を呼び出すをremap_pmd_range
呼び出すremap_pte_range
BUG_ON
ここへの、またはここVM_BUG_ON
からの後続の呼び出しremap_pmd_range
2191 VM_BUG_ON(pmd_trans_huge(*pmd));
そしてremap_pte_range
ここから
2171 BUG_ON(!pte_none(*pte));
BUG_ON
マクロはここで定義されます
なので
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0)
その上にBUG
マクロが定義されており、メッセージとパニックを出力します。
unlikely
マクロはここで定義されます
として# define unlikely(x) (__builtin_expect(!!(x), 0))
。
したがって、開始するターゲット ユーザー アドレスがとして定義されているaddr
以上の場合、BUG_ON は 1 を返し、BUG を呼び出します。end
end = addr + PAGE_ALIGN(size);
または、ここでpmd_trans_huge
定義されている場合
153 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
154 static inline int pmd_trans_splitting(pmd_t pmd)
155 {
156 return pmd_val(pmd) & _PAGE_SPLITTING;
157 }
158
159 static inline int pmd_trans_huge(pmd_t pmd)
160 {
161 return pmd_val(pmd) & _PAGE_PSE;
162 }
163
164 static inline int has_transparent_hugepage(void)
165 {
166 return cpu_has_pse;
167 }
0 を返します。これは、CONFIG_TRANSPARENT_HUGEPAGE がカーネルで構成されていない場合、またはpmd
(Page Metadate) 値または& _PAGE_PSE
または whenpte_none
は、対応するエントリが存在しない場合は 1 を返し、存在する場合は 0 を返します。
したがって!pte_none
、 に渡される条件として、対応するページ テーブル エントリが存在しない場合は 0 を返し、それ以外の場合は 1 を返しますBUG_ON
。
BUG
ページ テーブル エントリが既に存在する場合は、マクロの呼び出しが発生します。
!GB よりも少ない量のメモリを 300MB より大きく、たとえば 500MB や 800MB と指定するとどうなりますか?
したがって、開始アドレスが終了アドレスよりも大きいかCONFIG_TRANSPARENT_HUGEPAGE
、カーネルで構成されていないか、ページ メタデータが存在しないか、ページ テーブル エントリが既に存在することを参照しています。
コメントから明確にするために、あなたの呼び出しはremap_pfn_range
Page Table Entry ポインタを参照するか*pte
、すでにページテーブルエントリまたはを指していますpte
。
これはset_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));
、pte ポインターが既にページ テーブル エントリを指しているため、それを に設定できないため、失敗することを意味しpte
ますpte_mkspecial(pfn_pte(pfn, prot))
。
1G/3G 仮想アドレス分割のバイパス
次の記事を参照してくださいLinux カーネルの高メモリ
最小 1 GB の RAM を搭載した HIGHMEM に関する追加情報について説明している次のメーリング リストの投稿を参照してください。
カーネルおよび非カーネル仮想アドレス空間のユーザーランドへのマッピングに関する情報
カーネル仮想アドレスと非カーネル (vmalloc() によって返される) 仮想アドレスをユーザー空間にマップする 1 つの方法は、remap_pfn_range
. 詳細については、 Linux メモリ マッピングを参照してください。
古いカーネルでの nopage ハンドラーの使用を置き換える別の方法は、次のvm_insert_page
関数です。
追加のリソースは次のとおりです。