7

我有一个 2GB 内存的设置,我想将 1GB(或更多)物理内存映射到用户空间虚拟地址。这在理论上是可行的,因为使用 32 位设置,3GB 的虚拟地址可供用户登陆应用程序使用。

我使用以下参数更新了内核命令行:mem=1G memmap=1G$1G 强制内核查看 1GB 的 RAM 并保留最后的 1GB。

我有我的自定义驱动程序,它将处理用户空间mmap()调用并使用函数将物理地址 0x40000000 (1G) 映射到用户空间地址remap_pfn_range()

但是该函数会在remap_pte_range(). 相同的调用用于 300MB 重映射而不是 1GB。

我通常习惯于调用ioremap()我的驱动程序将物理地址映射到内核虚拟地址。在这种情况下,我不能因为 1G/3G 虚拟地址拆分(内核为 1G,应用程序为 3G)。所以我想知道是否可以将物理地址映射到用户空间虚拟地址而不在内核中映射这些物理地址?

这是一个 32 位 x86 内核,即“i386”架构。

4

1 回答 1

5

为什么您的 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_ONVM_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 指针已经指向页表条目,因此不能设置为ptethat is pte_mkspecial(pfn_pte(pfn, prot))

绕过 1G /3G 虚拟地址拆分

请参阅以下文章Linux 内核中的高内存

请参阅以下邮件列表帖子,其中讨论了有关至少 1GB RAM 的 HIGHMEM 的一些附加信息。

有关将内核和非内核虚拟地址空间映射到用户空间的信息

将内核虚拟地址和非内核(由 vmalloc() 返回)虚拟地址映射到用户空间的一种方法是使用remap_pfn_range. 有关更多信息,请参阅Linux 内存映射

在旧内核上替换 nopage 处理程序使用的另一种方法是vm_insert_page函数

其他资源包括:

于 2012-03-11T00:53:55.783 回答