gpt4 book ai didi

linux - 为什么我不应该在 ARMv6+ 的系统内存上使用 ioremap?

转载 作者:IT王子 更新时间:2023-10-29 01:04:54 27 4
gpt4 key购买 nike

我需要从内核中保留一个大的物理连续 RAM 缓冲区,并能够保证该缓冲区将始终使用特定的硬编码物理地址。该缓冲区应在内核的整个生命周期内保留。我已经编写了一个 chardev 驱动程序作为在用户空间中访问此缓冲区的接口(interface)。我的平台是一个嵌入式系统,采用 ARMv7 架构,运行 2.6 Linux 内核。

第 15 章 Linux Device Drivers, Third Edition关于该主题(第 443 页)有以下说法:

Reserving the top of RAM is accomplished by passing a mem= argument to the kernel at boot time. For example, if you have 256 MB, the argument mem=255M keeps the kernel from using the top megabyte. Your module could later use the following code to gain access to such memory: dmabuf = ioremap (0xFF00000 /* 255M */, 0x100000 /* 1M */);

我已经做到了这一点以及其他一些事情:

  1. 除了 mem 之外,我还在使用 memmap bootarg。 kernel boot parameters documentation建议在使用 mem 时始终使用 memmap 以避免地址冲突。
  2. 我在调用 ioremap 之前使用了 request_mem_region,当然,我在继续之前检查它是否成功。

这是我完成所有这些之后系统的样子:

# cat /proc/cmdline 
root=/dev/mtdblock2 console=ttyS0,115200 init=/sbin/preinit earlyprintk debug <strong>mem=255M memmap=1M$255M</strong>
# cat /proc/iomem
08000000-0fffffff : PCIe Outbound Window, Port 0
08000000-082fffff : PCI Bus 0001:01
08000000-081fffff : 0001:01:00.0
08200000-08207fff : 0001:01:00.0
18000300-18000307 : serial
18000400-18000407 : serial
1800c000-1800cfff : dmu_regs
18012000-18012fff : pcie0
18013000-18013fff : pcie1
18014000-18014fff : pcie2
19000000-19000fff : cru_regs
1e000000-1fffffff : norflash
40000000-47ffffff : PCIe Outbound Window, Port 1
40000000-403fffff : PCI Bus 0002:01
40000000-403fffff : 0002:01:00.0
40400000-409fffff : PCI Bus 0002:01
40400000-407fffff : 0002:01:00.0
40800000-40807fff : 0002:01:00.0
80000000-8fefffff : System RAM
80052000-8045dfff : Kernel text
80478000-80500143 : Kernel data
<strong>8ff00000-8fffffff : foo</strong>

到目前为止一切看起来都很好,我的驱动程序工作得很好。我能够直接读取和写入我选择的特定物理地址。

但是,在启动过程中,触发了一个可怕的警告():

BUG: Your driver calls ioremap() on system memory.  This leads
to architecturally unpredictable behaviour on ARMv6+, and ioremap()
will fail in the next kernel release. Please fix your driver.
------------[ cut here ]------------
WARNING: at arch/arm/mm/ioremap.c:211 __arm_ioremap_pfn_caller+0x8c/0x144()
Modules linked in:
[] (unwind_backtrace+0x0/0xf8) from [] (warn_slowpath_common+0x4c/0x64)
[] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_null+0x1c/0x24)
[] (warn_slowpath_null+0x1c/0x24) from [] (__arm_ioremap_pfn_caller+0x8c/0x144)
[] (__arm_ioremap_pfn_caller+0x8c/0x144) from [] (__arm_ioremap_caller+0x50/0x58)
[] (__arm_ioremap_caller+0x50/0x58) from [] (foo_init+0x204/0x2b0)
[] (foo_init+0x204/0x2b0) from [] (do_one_initcall+0x30/0x19c)
[] (do_one_initcall+0x30/0x19c) from [] (kernel_init+0x154/0x218)
[] (kernel_init+0x154/0x218) from [] (kernel_thread_exit+0x0/0x8)
---[ end trace 1a4cab5dbc05c3e7 ]---

触发自:arc/arm/mm/ioremap.c

/*
* Don't allow RAM to be mapped - this causes problems with ARMv6+
*/
if (pfn_valid(pfn)) {
printk(KERN_WARNING "BUG: Your driver calls ioremap() on system memory. This leads\n"
KERN_WARNING "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n"
KERN_WARNING "will fail in the next kernel release. Please fix your driver.\n");
WARN_ON(1);
}

这究竟会导致什么问题?它们可以减轻吗?我有哪些选择?

最佳答案

So I've done exactly that, and it's working.

提供内核命令行(例如 /proc/cmdline)和生成的内存映射(即 /proc/iomem)来验证这一点。

What problems, exactly, could this cause?

在系统内存上使用 ioremap() 的问题是您最终会为内存分配冲突的属性,这会导致“不可预测”的行为。
见文章"ARM's multiply-mapped memory mess" ,它提供了您正在触发的警告的历史记录。

The ARM kernel maps RAM as normal memory with writeback caching; it's also marked non-shared on uniprocessor systems. The ioremap() system call, used to map I/O memory for CPU use, is different: that memory is mapped as device memory, uncached, and, maybe, shared. These different mappings give the expected behavior for both types of memory. Where things get tricky is when somebody calls ioremap() to create a new mapping for system RAM.

The problem with these multiple mappings is that they will have differing attributes. As of version 6 of the ARM architecture, the specified behavior in that situation is "unpredictable."

请注意,“系统内存”是由内核管理的 RAM。
您触发警告的事实表明您的代码正在为内存区域生成多个映射。

Can they be mitigated?

你必须确保你想要 ioremap() 的 RAM 不是“系统内存”,即由内核管理。
另见 this answer .


附录

这个与您有关的警告是 pfn_valid(pfn) 返回 TRUE 而不是 FALSE 的结果。
基于您为版本 2.6.37 提供的 Linux 交叉引用链接,pfn_valid() 只是返回

的结果
memblock_is_memory(pfn << PAGE_SHIFT);  

这反过来只是返回

的结果
memblock_search(&memblock.memory, addr) != -1;  

我建议对内核代码进行黑客攻击,以便揭示冲突。
在调用 ioremap() 之前,将 TRUE 赋值给全局变量 memblock_debug
以下补丁应该显示有关内存冲突的重要信息。
(memblock 列表按基地址排序,因此 memblock_search() 对该列表执行二进制搜索,因此使用 mid 作为索引。)

 static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
{
unsigned int left = 0, right = type->cnt;

do {
unsigned int mid = (right + left) / 2;

if (addr < type->regions[mid].base)
right = mid;
else if (addr >= (type->regions[mid].base +
type->regions[mid].size))
left = mid + 1;
- else
+ else {
+ if (memblock_debug)
+ pr_info("MATCH for 0x%x: m=0x%x b=0x%x s=0x%x\n",
+ addr, mid,
+ type->regions[mid].base,
+ type->regions[mid].size);
return mid;
+ }
} while (left < right);
return -1;
}

如果你想看到所有的内存块,然后调用memblock_dump_all(),变量memblock_debug为TRUE。

[有趣的是,这本质上是一个编程问题,但我们还没有看到您的任何代码。]


附录 2

由于您可能正在使用 ATAG(而不是设备树),并且您想要专用内存区域,请修复 ATAG_MEM 以反射(reflect)这个较小的物理内存大小。
假设您对启动代码进行了零更改,ATAG_MEM 仍指定完整的 RAM,因此这可能是导致警告的系统内存冲突的根源。
参见 this answer about ATAGsthis related answer .

关于linux - 为什么我不应该在 ARMv6+ 的系统内存上使用 ioremap?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43127794/

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