- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在构建一个基于配备 arm64 CPU 的 UltraScale+ FPGA 的数据采集系统。数据通过 DMA 传输到 RAM。驱动程序中的 DMA 缓冲区保留如下:
virt_buf[i] = dma_zalloc_coherent(&pdev->dev, BUF_SIZE, &phys_buf[i],GFP_KERNEL);
在驱动的mmap函数中,映射到用户空间的方式是这样的:
#ifdef ARCH_HAS_DMA_MMAP_COHERENT
printk(KERN_INFO "Mapping with dma_map_coherent DMA buffer at phys: %p virt %p\n",phys_buf[off],virt_buf[off]);
res = dma_mmap_coherent(&my_pdev->dev, vma, virt_buf[off], phys_buf[off], vsize);
#else
physical = phys_buf[off];
res=remap_pfn_range(vma,vma->vm_start, physical >> PAGE_SHIFT , vsize, pgprot_noncached(vma->vm_page_prot));
printk(KERN_INFO "Mapping with remap_pfn_range DMA buffer at phys: %p virt %p\n",physical,virt_buf[off]);
#endif
在我的 UltraScale+ CPU 上使用了 remap_pfn_range。在用户空间应用程序中,数据从缓冲区中读取,当前立即发送长度限制为 MAX_DGRAM(最初等于 572)的 UDP 数据包。
int i = 0;
int bleft = nbytes;
while(i<nbytes) {
int bts = bleft < MAX_DGRAM ? bleft : MAX_DGRAM;
if (sendto(fd,&buf[nbuf][i],bts,0, res2->ai_addr,res2->ai_addrlen)==-1) {
printf("%s",strerror(errno));
exit(1);
}
bleft -= bts;
i+= bts;
}
一切都在 32 位 Zynq FPGA 上完美运行。然而,在我将其移至 64 位 UltraScale+ FPGA 后,在传输了数百次之后,我开始收到随机错误。
[ 852.703491] Unhandled fault: alignment fault (0x96000021) at 0x0000007f82635584
[ 852.710739] Internal error: : 96000021 [#4] SMP
[ 852.715235] Modules linked in: axi4s2dmov(O) ksgpio(O)
[ 852.720358] CPU: 0 PID: 1870 Comm: a4s2dmov_send Tainted: G D O 4.4.0 #3
[ 852.728001] Hardware name: ZynqMP ZCU102 RevB (DT)
[ 852.732769] task: ffffffc0718ac180 ti: ffffffc0718b8000 task.ti: ffffffc0718b8000
[ 852.740248] PC is at __copy_from_user+0x8c/0x180
[ 852.744836] LR is at copy_from_iter+0x70/0x24c
[ 852.749261] pc : [<ffffffc00039210c>] lr : [<ffffffc0003a36a8>] pstate: 80000145
[ 852.756644] sp : ffffffc0718bba40
[ 852.759935] x29: ffffffc0718bba40 x28: ffffffc06a4bae00
[ 852.765228] x27: ffffffc0718ac820 x26: 000000000000000c
[ 852.770523] x25: 0000000000000014 x24: 0000000000000000
[ 852.775818] x23: ffffffc0718bbe08 x22: ffffffc0710eba38
[ 852.781112] x21: ffffffc0718bbde8 x20: 000000000000000c
[ 852.786407] x19: 000000000000000c x18: ffffffc000823020
[ 852.791702] x17: 0000000000000000 x16: 0000000000000000
[ 852.796997] x15: 0000000000000000 x14: 00000000c0a85f32
[ 852.802292] x13: 0000000000000000 x12: 0000000000000032
[ 852.807586] x11: 0000000000000014 x10: 0000000000000014
[ 852.812881] x9 : ffffffc0718bbcf8 x8 : 000000000000000c
[ 852.818176] x7 : ffffffc0718bbdf8 x6 : ffffffc0710eba2c
[ 852.823471] x5 : ffffffc0710eba38 x4 : 0000000000000000
[ 852.828766] x3 : 000000000000000c x2 : 000000000000000c
[ 852.834061] x1 : 0000007f82635584 x0 : ffffffc0710eba2c
[ 852.839355]
[ 852.840833] Process a4s2dmov_send (pid: 1870, stack limit = 0xffffffc0718b8020)
[ 852.848134] Stack: (0xffffffc0718bba40 to 0xffffffc0718bc000)
[ 852.853858] ba40: ffffffc0718bba90 ffffffc0006a1b2c 000000000000000c ffffffc06a9bdb00
[ 852.861676] ba60: 00000000000005dc ffffffc071a0d200 0000000000000000 ffffffc0718bbdf8
[ 852.869488] ba80: 0000000000000014 ffffffc06a959000 ffffffc0718bbad0 ffffffc0006a2358
[...]
[ 853.213212] Call trace:
[ 853.215639] [<ffffffc00039210c>] __copy_from_user+0x8c/0x180
[ 853.221284] [<ffffffc0006a1b2c>] ip_generic_getfrag+0xa4/0xc4
[ 853.227011] [<ffffffc0006a2358>] __ip_append_data.isra.43+0x80c/0xa70
[ 853.233434] [<ffffffc0006a3d50>] ip_make_skb+0xc4/0x148
[ 853.238642] [<ffffffc0006c9d04>] udp_sendmsg+0x280/0x740
[ 853.243937] [<ffffffc0006d38e4>] inet_sendmsg+0x7c/0xbc
[ 853.249145] [<ffffffc000651f5c>] sock_sendmsg+0x18/0x2c
[ 853.254352] [<ffffffc000654b14>] SyS_sendto+0xb0/0xf0
[ 853.259388] [<ffffffc000084470>] el0_svc_naked+0x24/0x28
[ 853.264682] Code: a88120c7 a8c12027 a88120c7 36180062 (f8408423)
[ 853.270791] ---[ end trace 30e1cd8e2ccd56c5 ]---
Segmentation fault
root@Xilinx-ZCU102-2016_2:~#
奇怪的是,当我简单地从缓冲区中读取单词时,它不会导致任何对齐错误。
看来,send 函数不正确地使用了__copy_from_user 函数,导致未对齐的内存访问。问题是:是内核错误,还是我做错了什么?
但是,通常情况下,发送不是从8字节边界开始的数据 block 不会触发对齐错误。该问题发生的概率相对较低。我无法隔离导致错误的条件。
我已经通过调整 MAX_DGRAM 使其成为 8 的倍数解决了这个问题。但是我担心,如果将映射缓冲区中的数据提交给更复杂的处理,这个问题可能会再次出现。有人报告了与 memcpy 函数相关的 arm64 架构中的类似问题(例如 [ https://bugs.launchpad.net/linux-linaro/+bug/1271649] )。
将相干 DMA 缓冲区映射到用户空间以避免内存对齐错误的正确方法是什么?
最佳答案
该驱动程序需要更新。 ARCH_HAS_DMA_MMAP_COHERENT
很长一段时间都没有被 PowerPC 以外的任何东西定义,甚至看起来像是被遗忘的遗留物。
已经有一个通用的 dma_mmap_coherent()
实现 since 3.6 ,因此可以而且应该无条件地使用。当前代码的结果是,多亏了#ifdef,你总是走另一条路,然后多亏了pgprot_noncached()
。您最终使缓冲区的用户空间映射强有序(AArch64 术语中的设备 nGnRnE)。这通常是一个坏主意,因为用户空间代码会假定它始终在普通内存上运行(除非明确设计为不这样做),并且可以安全地执行未对齐或独占访问之类的操作,这两种操作都可能在设备类型内存上出现严重错误.我什至不打算问内核从用户空间映射内核缓冲区* 中复制数据是一种什么样的疯狂行为,但足以说明内核 - 通过 copy_{to,from,in}_user()
- 还假定用户空间地址被映射为普通内存,因此对于未对齐的访问是安全的。坦率地说,我有点惊讶这在 32 位 ARM 上并没有类似地爆炸,所以我猜你的数据恰好总是至少对齐 4 字节 - 这也可以解释为什么读取单词(使用 32 位访问)很好,如果只有 64 位双字访问可能未对齐。
简而言之,只需使用 dma_mmap_coherent()
,并摆脱开放编码的不良等效项。这将为用户空间提供一个正常的不可缓存映射(或硬件一致设备的可缓存映射),它将按预期工作。就假设 dma_addr_t
是一个物理地址而言,它也没有被破坏,正如您的驱动程序代码似乎所做的那样 - 这是另一件迟早会出现并咬你一口的东西(ZynqMP 有一个系统 MMU,因此您大概可以更新到 4.9 内核,连接一些流 ID,将它们添加到 DT,然后观察这个假设以新的和令人兴奋的方式发生变化。
* 虽然我确实想到,在某些情况下,从页面的末尾复制有时可能会过度读取到下一页,如果下一页恰好是,这可能会在不知不觉中触发这种情况设备/强序映射,导致 this patch in 4.5 . Linus 对这种内存布局的回应是 "...and nobody sane actually does that..."
关于arm64 上的 Linux : sendto causes "Unhandled fault: alignment fault (0x96000021)" when sending data from mmapped coherent DMA buffer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41093013/
我正在使用 Test Cafe 中使用 Resemble.JS 库的函数来比较实际屏幕截图和基本屏幕截图。在我的夹具中,我有两个测试,由于屏幕截图不匹配,两个测试都应该在报告中失败,但唯一的第一个测试
这个问题在这里已经有了答案: What does IndexOutofRangeException mean? (3 个答案) 关闭 9 年前。 string Query = "SELECT [AA
错误日志: System.TypeInitializationException was unhandled Message="The type initializer for 'MaxDavid
使用 Python 2.7 和 Django 1.10.4,我尝试将我的应用程序部署到 pythonanywhere,但我不断收到此错误。 错误日志 wsgi.py import os import
我有一个名为 Form1 的表单: 有一个 ComboBox 和一个 TextBox,当我从 ComboBox 中选择 US$ 时,它必须从数据库中检索数据并显示TextBox 中的 150。 这是我
我正在尝试制作 slider 益智游戏,但在我的 form1 中调用 myBoard.paint(e.Graphics) 时,我不断收到错误“NullReferenceException 未处理”。请
我目前正在开发一个数据库,用于跟踪停在 parking 场的车辆。但是,我在将新记录保存到数据库表时遇到了一些问题。现在我对编程还很陌生,所以我无法理解我收到的错误。我试过查找它并发现了类似的情况,但
我编写了一个 Android 应用程序 (4.4.2),它在大多数时间都能正确连接/断开 BLE 外围设备。但是,每隔一段时间我就会在 Bluetootgatt.java onClientConnec
当我尝试运行 Facebook C# SDK 附带的 WP7 示例应用程序时,我收到此异常: File or assembly name 'Microsoft.Contracts, Version=1
我正在尝试学习如何在 Scala 中使用 Try with 进行理解。 在下面的示例代码中( result1 ), 如果 for comprehension 中的最后一条语句抛出未处理的异常, 代码不
我遇到了一个小问题,在调试了所有应用程序后,我注意到这是导致问题的文件,并向我返回了 UnhandledPromiseRejection 'use strict' const connection =
我对 Java(特别是 Android)相当陌生。我试图让用户从图库中选择图像,然后应用程序会将图像从图库复制到应用程序目录中的文件夹(以及显示他们在图像按钮中选择的图片)。但是,我收到“未处理的异常
我已从 iOS SDK 4.2 升级到 iOS SDK 5.0。当我现在尝试编译当前项目时,出现以下错误。 关于这里出了什么问题的任何想法?我已经阅读了所有我能找到的“mtouch failed wi
由于我正在考虑使用 WCF,所以我认为最好只是按照一个简单的教程来尝试一下。 3 小时后,我只有一个异常(exception)要显示。它不会消失。 我排除了没有加载 app.config 的可能性。如
我正在尝试在带有 .net 4.5 的 VS 2012 中使用带有 Telerik OpenAccess 的 WCF Plain 服务。 我尝试了 telerik 开发人员手册并创建了服务和客户端。
我遇到了这个错误 Program.exe 中 0x0049b946 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000090。 错误指向这一行: // thread
对于我的 Monodroid 应用程序,我想在出现未处理的异常后执行以下操作: 将错误发送到服务器。 通知用户应用程序已崩溃(可能使用 toast 消息)。 优雅地退出应用程序。 我已经实现了#1,但
我使用 JQuery 的表排序器对表进行排序,但我遇到了空表抛出异常的问题。所以我在脚本中添加了一个条件,但现在问题出在条件上。 : $(document).ready(function ($) {
我的构造函数的目标是: 打开一个文件读入特定字符串(“%%%%%”)之间存在的所有内容将每个读取行放在一个变量(历史记录)中将最终变量添加到 char 类型的双指针 (_stories)关闭文件。 但
我正在使用 Visual Studio 2005 和 IIS 6.0.. 我在事件日志中有这个警告。我试图找到它是什么。我工作时从未经历过这个异常(exception)。可以做什么,在哪里可以做,不再
我是一名优秀的程序员,十分优秀!