如何在32位Linux内核下映射1GB(或更多)的物理内存

7
我有一个配备了2GB内存的设置,我想将1GB(或更多)物理内存映射到用户空间虚拟地址中。从理论上讲,在32位设置中,3GB的虚拟地址可供用户应用程序使用。
我使用以下参数更新了内核命令行:mem=1G memmap=1G$1G 以便强制内核看到1GB的RAM并保留最后1GB。
我的自定义驱动程序将处理用户空间的mmap()调用,并使用remap_pfn_range()函数将物理地址0x40000000(1G)映射到用户空间地址。
但是该函数会在remap_pte_range()中触发内核BUG()。与300MB重新映射相比,同样的调用曾经起作用。
我通常使用ioremap()在我的驱动程序中将物理地址映射到内核虚拟地址。在这种情况下,我不能这样做,因为1G / 3G虚拟地址被分割(1G用于内核,3G用于应用程序)。因此,我想知道是否可以将物理地址映射到用户空间虚拟地址,而不将这些物理地址映射到内核中?
这是一个32位的x86内核,即“i386”架构。
1个回答

5

为什么您的remap_pfn_range调用会触发内核BUG()

根据此处,在remap_pfn_range中调用BUG_ON宏。

remap_pfn_range调用remap_pud_range,后者调用remap_pmd_range,后者又调用remap_pte_range

remap_pmd_range此处和从remap_pte_range此处调用后续的BUG_ONVM_BUG_ON

2171 BUG_ON(!pte_none(*pte));

当目标用户地址从addr开始时大于或等于end,其中end = addr + PAGE_ALIGN(size);BUG_ON返回1并调用BUGBUG_ON宏在此处定义,如下所示:#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0),其中BUG宏在此处上方定义以打印消息并出现紧急情况。unlikely宏在此处定义,如下所示:# define unlikely(x) (__builtin_expect(!!(x), 0))。请注意,保留HTML标签。

或者当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 }

当内核中未配置CONFIG_TRANSPARENT_HUGEPAGE或pmd(页面元数据)值或&_PAGE_PSE时,返回0。

如果相应的条目不存在,则pte_none返回1,如果存在则返回0。

因此,当相应的页表条目不存在时,!pte_none返回0;否则,返回1,作为传递给BUG_ON的条件。

如果页面表条目已经存在,则调用BUG宏。

如果指定的内存量低于1GB但大于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_mkspecial(pfn_pte(pfn, prot))
绕过1G/3G虚拟地址分割
请参阅以下文章Linux内核中的高内存
请参阅以下邮件列表post,其中讨论了关于具有最小1GB RAM的HIGHMEM的一些额外信息。
映射内核和非内核虚拟地址空间到用户空间的信息。

一种将内核虚拟地址和非内核(通过vmalloc()返回的)虚拟地址映射到用户空间的方法是使用remap_pfn_range。有关详细信息,请参见Linux Memory Mapping

另一种替代旧内核上nopage处理程序的方式是使用vm_insert_page函数。

其他资源包括:


__builtin_expect(x, y) 总是返回 x。如果 x 为真,BUG_ON(x) 宏会触发。因此,你的逻辑链中有些问题。 - Gunther Piez
谢谢,否定的表达方式有点多了,我会根据情况更新回答。 - Appleman1234
抱歉缺乏细节。BUG() 宏由 remap_pte_range() BUG_ON(!pte_none(*pte)) 调用。 我必须为我的项目使用旧内核(2.6.18),但我没有找到配置 CONFIG_TRANSPARENT_HUGEPAGE - user1259743

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接