gpt4 book ai didi

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

转载 作者:IT王子 更新时间:2023-10-29 00:33:15 25 4
gpt4 key购买 nike

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

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

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

但是函数在remap_pte_range()中触发了一个内核BUG()。同一调用过去使用 300MB 重映射而不是 1GB。

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

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

最佳答案

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

根据 hereremap_pfn_range 中调用 BUG_ON

2277 BUG_ON(addr >= end);

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

随后从 remap_pmd_range 调用 BUG_ONVM_BUG_ON here

2191 VM_BUG_ON(pmd_trans_huge(*pmd));

来自remap_pte_range here

2171 BUG_ON(!pte_none(*pte));

BUG_ON 宏已定义 here

作为

#define BUG_ON(condition) 做 { if (unlikely(condition)) BUG(); } while(0)

上面定义了BUGit打印消息并 panic 。

不太可能 定义了宏 here

as # define unlikely(x) (__builtin_expect(!!(x), 0))

所以当目标用户地址开始于addr大于等于end时定义为end = addr + PAGE_ALIGN(size); ,BUG_ON返回1,调用BUG。

或者当 pmd_trans_huge 定义为 here

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_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 指针已经指向页表条目,因此不能设置为 ptepte_mkspecial(pfn_pte(pfn, prot))

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

请参阅以下文章 High Memory In The Linux Kernel

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

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

将内核虚拟地址和非内核(由 vmalloc() 返回)虚拟地址映射到用户空间的一种方法是使用 remap_pfn_range。参见 Linux Memory Mapping了解更多信息。

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

其他资源包括:

关于c - 如何在 32 位 Linux 内核下映射 1GB(或更多)的物理内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9638035/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com