我正在为 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 并对其进行映射时,它可以正常工作。我可以看到 x11vnc 发生了什么来“分享”fb1:
x11vnc -rawfb map:/dev/fb1@320x240x16
并使用 vnc 查看器查看:
gvncviewer strontium:0
我通过写入整个映射缓冲区来确保我没有溢出,这似乎很好。
当我添加 deferred_io 时出现问题。作为对其的测试,我有 1 秒的延迟,并且被调用的 deferred_io 函数除了 pr_devel() 打印之外什么都不做。我跟着文档。
现在,测试程序可以正常打开 /dev/fb1,mmap 返回正常,但是一旦我写入该指针,就会出现内核恐慌。以下转储实际上来自 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 之间有区别吗?