如何映射1GB(或更多)的物理内存
我有一个2GB内存的设置,我想将1GB(或更多)的物理内存映射到用户空间虚拟地址。 理论上可以使用32位设置,3GB的虚拟地址可用于用户登陆应用程序。
我使用以下参数更新了内核命令行:mem = 1G memmap = 1G $ 1G强制内核查看1GB内存并保留最后1GB。
我有我的自定义驱动程序,它将处理用户空间mmap()调用,并使用函数remap_pfn_range()将物理地址0x40000000(1G)映射到用户空间地址。 但是该函数会在remap_pte_range()中触发一个内核BUG()。 这次调用使用300MB重映像而不是1GB。
我通常使用在我的驱动程序中调用ioremap()来将物理地址映射到内核虚拟地址。 在这种情况下,我不能因为1G / 3G虚拟地址分裂(1G用于内核,3G用于应用)。 所以我想知道是否可以将物理地址映射到用户空间虚拟地址,而无需在内核中映射这些物理地址?
提前致谢。
为什么您的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
。
随后在这里从remap_pmd_range
调用BUG_ON
或VM_BUG_ON
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
宏
as # 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,并且在条件传递到BUG_ON
。
如果页表项已经存在,则发生对BUG
宏的调用。
如果指定的内存量大于!GB大于300MB,比如500MB或800MB,会发生什么情况?
因此,无论您的起始地址是否大于您的结束地址,或者CONFIG_TRANSPARENT_HUGEPAGE
未在内核中配置,或者您所指的页面元数据不存在或页表项已存在。
从注释中澄清,您对remap_pfn_range
的调用引用了已经指向页表项或pte
Page Table Entry指针或*pte
pte
。
这意味着set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));
将会失败,因为pte指针已经指向一个页表项,因此不能设置为pte_mkspecial(pfn_pte(pfn, prot))
的pte
。
绕过1G / 3G虚拟地址分割
请参阅以下文章Linux内核中的高内存
请参阅以下邮件列表文章,其中讨论了有关HIGHMEM的至少1GB内存的其他信息。
将内核和非内核虚拟地址空间映射到用户域的信息
将内核虚拟地址和非内核映射到用户空间的一种方法是使用remap_pfn_range
。 有关更多信息,请参阅Linux内存映射。
vm_insert_page
函数替代旧内核上的nopage处理程序的用法的另一种方法是vm_insert_page
函数
其他资源包括: