Linux BUG:无法处理内核分页请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13804682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
BUG: unable to handle kernel paging request at
提问by kohpe
I am writing a PCI driver for a simple test device.
我正在为一个简单的测试设备编写 PCI 驱动程序。
Hardware is recognized correctly with lspci (as you can see my driver vabshas been registered):
使用 lspci 正确识别硬件(如您所见,我的驱动程序vabs已注册):
04:02.0 Non-VGA unclassified device: Device bace:55aa
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Region 0: Memory at f0000000 (32-bit, prefetchable) [size=16M]
Kernel driver in use: vabs
Initialisation and deinitalisation of driver and PCI subystem works fine. I am getting a device number, and udev creates a device file.
驱动程序和 PCI 子系统的初始化和取消初始化工作正常。我得到了一个设备号,udev 创建了一个设备文件。
When reading from the device file I get the following error message:
从设备文件读取时,我收到以下错误消息:
BUG: unable to handle kernel paging request at 00000000f0000000
I request PCI ressources in the initialisation successfully. This returns 00000000f0000000 for memstart0, which is my base address 0 for PCI.
我在初始化中成功请求 PCI 资源。这为 memstart0 返回 00000000f0000000,这是我的 PCI 基址 0。
memstart0 = pci_resource_start( pdev, 0 );
memlen = pci_resource_len( pdev, 0 );
if( request_mem_region(memstart0,memlen,pdev->dev.kobj.name)==NULL ) {
dev_err(&pdev->dev,"Memory address conflict for device\n");
goto cleanup_mem;
}
Trying to read from this memio address with the following code gives the mentioned error:
尝试使用以下代码从此 memio 地址读取会出现上述错误:
ssize_t driver_read(struct file *instance, char __user *buffer, size_t max_bytes_to_read, loff_t *offset) {
u32 test;
dev_dbg(vabs_dev,"copying from %p\n", (void *) memstart0);
test = readl((void *) memstart0);
return max_bytes_to_read;
}
I also tried other access functions like memcpy_fromio, ioread32, and direct pointer access with the same result.
我还尝试了其他访问函数,如 memcpy_fromio、ioread32 和直接指针访问,结果相同。
The hardware works on a Windows machine. The only notable difference is that Windows reserves base address 0 as 00000000fd000000 while Linux reserves it as 00000000f0000000.
硬件在 Windows 机器上工作。唯一显着的区别是 Windows 将基地址 0 保留为 00000000f d000000,而 Linux 将其保留为 00000000f 0000000。
This is for non-profit educational purpose in a public school. Thanks for your help!
这是用于公立学校的非营利教育目的。谢谢你的帮助!
采纳答案by Nemo
Read Documentation/IO-mapping.txt(search for "iomap") and/or Chapter 15 of LDD3.
阅读Documentation/IO-mapping.txt(搜索“iomap”)和/或LDD3 的第 15 章。
request_mem_region
just ensures no other driver has already grabbed that memory region. You still need to map it into the kernel's VM space using iomap
before you can read/write it.
request_mem_region
只是确保没有其他驱动程序已经占用了该内存区域。iomap
在读/写它之前,您仍然需要将它映射到内核的 VM 空间使用。
Note that the whole pci_resource_start
etc. dance is somewhat deprecated. I believe the recommended approach these days is:
请注意,整体pci_resource_start
等舞蹈有点不赞成。我相信这些天推荐的方法是:
pci_request_regions(pdev, "myname"); /* to request regions for all BARs */
Then:
然后:
void __iomem *base = pci_iomap(pdev, 0, pci_resources_len(pdev,0)); /* to map BAR 0 */
Then:
然后:
ioread32(base + offset); /* Or readl(base + offset), but this is more generic */
And finally, at the end:
最后,最后:
pci_iounmap(pdev, base); /* Release kernel VM mapping (undoes pci_iomap) */
pci_release_regions(pdev); /* Release all regions (undoes pci_request_regions) */
You can do the first two manually by combining pci_resource_start
, pci_resource_len
, request_mem_region
, and iomap
. But the above is (a) shorter and (b) generic between memory-mapped devices and those that use the old x86 I/O space. (Not that there are a whole lot of those around anymore.)
您可以通过合并做前两个手动pci_resource_start
,pci_resource_len
,request_mem_region
,和iomap
。但是上面是(a)较短和(b)内存映射设备和使用旧 x86 I/O 空间的设备之间的通用性。(并不是说周围有很多人了。)