在kmalloced缓冲区上使用deferred_io的内核恐慌

时间:2014-03-09 17:01:26

标签: linux-kernel linux-device-driver framebuffer panic

我正在为ARM上的SPI LCD显示器编写帧缓冲。在我完成之前,我已经编写了一个仅内存驱动程序并在Ubuntu(Intel,Virtualbox)下进行了试用。驱动程序工作正常 - 我使用kmalloc分配了一块内存,页面对齐它(实际上它的页面对齐),并使用帧缓冲系统创建/ dev / fb1。我有自己的mmap函数,如果它是相关的(deferred_io忽略它并使用它自己的外观)。

我已经设定:

info->screen_base = (u8 __iomem *)kmemptr;
info->fix.smem_len = kmem_size;

当我使用测试程序打开/ dev / fb1并对其进行mmap时,它可以正常工作。我可以看到发生了什么x11vnc“分享”fb1:

x11vnc -rawfb map:/dev/fb1@320x240x16  

使用vnc查看器查看:

gvncviewer strontium:0

我通过写入整个mmapped缓冲区确保我没有溢出,这看起来很好。

当我添加deferred_io时出现问题。作为对它的测试,我有1秒的延迟,并且被调用的deferred_io函数除了pr_devel()打印之外什么都不做。我跟着docs

现在,测试程序打开/ dev / fb1很好,mmap返回ok,但是一旦我写入指针,我就会遇到内核恐慌。以下转储实际上来自ARM机器,但它也在Ubuntu VM上发生恐慌:

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之间是否存在差异?

1 个答案:

答案 0 :(得分:1)

确认修复,所以我会回答我自己的问题:

deferred_io将信息mmap更改为自己的信息mmap,设置故障处理程序以写入视频内存页面。在故障处理程序中它

  • 检查info-&gt; fix.smem_len的边界,因此您必须设置
  • 获取写入的页面。

对于后一种情况,它将vmalloc与kmalloc区别对待(通过检查info-&gt; screen_base来查看它是否为vmalloced)。如果你有vmalloced,它使用screen_base作为虚拟地址。如果您尚未使用vmalloc,则会假定感兴趣的地址是info-&gt; fix.smem_start中的物理地址。

所以,正确使用deferred_io

  • 设置screen_base(char __iomem *)并将其指向虚拟地址。
  • 将info-&gt; fix.smem_len设置为视频缓冲区大小
  • 如果您不使用vmalloc,则必须使用virt_to_phys(vid_buffer)
  • 将info-&gt; fix.smem_start设置为视频缓冲区的物理地址

确认Ubuntu解决了这个问题。