为什么您的 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
大于等于end
定义为end = addr + PAGE_ALIGN(size);
时,BUG_ON 返回 1 并调用 BUG。
或者当这里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
或者当pte_none
对应的条目不存在时返回1,如果存在则返回0。
因此!pte_none
,当相应的页表条目不存在时返回 0,否则返回 1 作为传递给 的条件BUG_ON
。
如果页表条目已经存在,则调用BUG
宏。
如果您指定的内存量低于 !GB 且大于 300MB,例如 500MB 或 800MB,会发生什么情况?
所以要么你的起始地址大于你的结束地址,要么你CONFIG_TRANSPARENT_HUGEPAGE
没有在内核中配置,或者你指的是页面元数据不存在或页面表条目已经存在。
从评论中澄清,您对remap_pfn_range
引用页表条目指针或*pte
已经指向页表条目的调用或pte
.
这意味着set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));
它将失败,因为 pte 指针已经指向页表条目,因此不能设置为pte
that is pte_mkspecial(pfn_pte(pfn, prot))
。
绕过 1G /3G 虚拟地址拆分
请参阅以下文章Linux 内核中的高内存
请参阅以下邮件列表帖子,其中讨论了有关至少 1GB RAM 的 HIGHMEM 的一些附加信息。
有关将内核和非内核虚拟地址空间映射到用户空间的信息
将内核虚拟地址和非内核(由 vmalloc() 返回)虚拟地址映射到用户空间的一种方法是使用remap_pfn_range
. 有关更多信息,请参阅Linux 内存映射。
在旧内核上替换 nopage 处理程序使用的另一种方法是vm_insert_page
函数
其他资源包括: