问题描述
我正在为ARM上的SPI LCD显示编写帧缓冲区.在完成此操作之前,我已经编写了一个仅内存的驱动程序,并在Ubuntu(Intel,Virtualbox)下对其进行了试用.驱动程序工作正常-我已经使用kmalloc分配了一块内存,对其进行页面对齐(实际上无论如何都是页面对齐的),并使用帧缓冲系统创建了/dev/fb1.如果相关的话,我有自己的mmap函数(deferred_io会忽略它,并通过它的外观使用它自己的函数).
I'm writing a framebuffer for an SPI LCD display on ARM. Before I complete that, I've written a memory only driver and trialled it under Ubuntu (Intel, Virtualbox). The driver works fine - I've allocated a block of memory using kmalloc, page aligned it (it's page aligned anyway actually), and used the framebuffer system to create a /dev/fb1. I have my own mmap function if that's relevant (deferred_io ignores it and uses its own by the look of it).
我已设置:
info->screen_base = (u8 __iomem *)kmemptr;
info->fix.smem_len = kmem_size;
当我使用测试程序打开/dev/fb1并对其进行映射时,它可以正常工作.我可以看到x11vnc发生了什么,以共享" fb1:
When I open /dev/fb1 with a test program and mmap it, it works correctly. I can see what is happening x11vnc to "share" the fb1 out:
x11vnc -rawfb map:/dev/fb1@320x240x16
并使用vnc查看器查看:
And view with a vnc viewer:
gvncviewer strontium:0
通过写入整个mmapped缓冲区,确保没有溢出,这似乎很好.
I've made sure I've no overflows by writing to the entire mmapped buffer and that seems to be fine.
当我添加deferred_io时出现问题.作为测试,我有1秒的延迟,调用的deferred_io函数除了pr_devel()打印外什么也不做.我遵循了文档.
The problem arises when I add in deferred_io. As a test of it, I have a delay of 1 second and the called deferred_io function does nothing except a pr_devel() print. I followed the docs.
现在,测试程序可以很好地打开/dev/fb1,mmap返回ok,但是一旦我写入该指针,就会出现内核崩溃.以下转储实际上是来自ARM机器的,但它也会在Ubuntu VM上引起恐慌:
Now, the test program opens /dev/fb1 fine, mmap returns ok but as soon as I write to that pointer, I get a kernel panic. The following dump is from the ARM machine actually but it panics on the Ubuntu VM as well:
root@duovero:~/testdrv# ./fbtest1 /dev/fb1
Device opened: /dev/fb3
Screen is: 320 x 240, 16 bpp
Screen size = 153600 bytes
mmap on device succeeded
Unable to handle kernel paging request at virtual address bf81e020
pgd = edbec000
[bf81e020] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in: hhlcd28a(O) sysimgblt sysfillrect syscopyarea fb_sys_fops bnep ipv6 mwifiex_sdio mwifiex btmrvl_sdio firmware_class btmrvl cfg80211 bluetooth rfkill
CPU: 0 Tainted: G O (3.6.0-hh04 #1)
PC is at fb_deferred_io_fault+0x34/0xb0
LR is at fb_deferred_io_fault+0x2c/0xb0
pc : [<c0271b7c>] lr : [<c0271b74>] psr: a0000113
sp : edbdfdb8 ip : 00000000 fp : edbeedb8
r10: edbeedb8 r9 : 00000029 r8 : edbeedb8
r7 : 00000029 r6 : bf81e020 r5 : eda99128 r4 : edbdfdd8
r3 : c081e000 r2 : f0000000 r1 : 00001000 r0 : bf81e020
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5387d Table: adbec04a DAC: 00000015
Process fbtest1 (pid: 485, stack limit = 0xedbde2f8)
Stack: (0xedbdfdb8 to 0xedbe0000)
[snipped out hexdump]
[<c0271b7c>] (fb_deferred_io_fault+0x34/0xb0) from [<c00db0c4>] (__do_fault+0xbc/0x470)
[<c00db0c4>] (__do_fault+0xbc/0x470) from [<c00dde0c>] (handle_pte_fault+0x2c4/0x790)
[<c00dde0c>] (handle_pte_fault+0x2c4/0x790) from [<c00de398>] (handle_mm_fault+0xc0/0xd4)
[<c00de398>] (handle_mm_fault+0xc0/0xd4) from [<c049a038>] (do_page_fault+0x140/0x37c)
[<c049a038>] (do_page_fault+0x140/0x37c) from [<c0008348>] (do_DataAbort+0x34/0x98)
[<c0008348>] (do_DataAbort+0x34/0x98) from [<c0498af4>] (__dabt_usr+0x34/0x40)
Exception stack(0xedbdffb0 to 0xedbdfff8)
ffa0: 00000280 0000ffff b6f5c900 00000000
ffc0: 00000003 00000000 00025800 b6f5c900 bea6dc1c 00011048 00000032 b6f5b000
ffe0: 00006450 bea6db70 00000000 000085d6 40000030 ffffffff
Code: 28bd8070 ebffff37 e2506000 0a00001b (e5963000)
---[ end trace 7e5ca57bebd433f5 ]---
Segmentation fault
root@duovero:~/testdrv#
我完全感到困惑-其他司机看起来和我的差不多,但我认为他们可以工作.实际上大多数人都使用vmalloc-为此,kmalloc和vmalloc有区别吗?
I'm totally stumped - other drivers look more or less the same as mine but I assume they work. Most use vmalloc actually - is there a difference between kmalloc and vmalloc for this purpose?
推荐答案
确认了此修复程序,所以我将回答自己的问题:
Confirmed the fix so I'll answer my own question:
deferred_io将信息mmap更改为自己的信息,该mmap设置故障处理程序以写入视频内存页面.在故障处理程序中
deferred_io changes the info mmap to its own that sets up fault handlers for writes to the video memory pages. In the fault handler it
- 根据info-> fix.smem_len检查范围,因此您必须进行设置
- 获取被写入的页面.
对于后一种情况,它将vmalloc与kmalloc区别对待(通过检查info-> screen_base来查看是否已分配vmalloc).如果已分配vmalloc,它将使用screen_base作为虚拟地址.如果尚未使用vmalloc,则假定感兴趣的地址是info-> fix.smem_start中的物理地址.
For the latter case, it treats vmalloc differently from kmalloc (by checking info->screen_base to see if it's vmalloced). If you have vmalloced, it uses screen_base as the virtual address. If you have not used vmalloc, it assumes that the address of interest is the physical address in info->fix.smem_start.
所以,要正确使用deferred_io
So, to use deferred_io correctly
- 设置screen_base(字符__iomem *)并将其指向虚拟地址.
- 将info-> fix.smem_len设置为视频缓冲区大小
- 如果您不使用vmalloc,则必须 使用virt_to_phys(vid_buffer)将info-> fix.smem_start设置为视频缓冲区的物理地址;
- set screen_base (char __iomem *) and point that to the virtual address.
- set info->fix.smem_len to the video buffer size
- if you are not using vmalloc, you must set info->fix.smem_start to the video buffer's physical address by using virt_to_phys(vid_buffer);
在Ubuntu上已确认可解决此问题.
Confirmed on Ubuntu as fixing the issue.
这篇关于在kmalloced缓冲区上使用deferred_io进行内核恐慌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!