1

我正在为 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 之间有区别吗?

4

2 回答 2

1

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

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

  • 检查 info->fix.smem_len 的界限,所以你必须设置它
  • 获取写入的页面。

对于后一种情况,它处理 vmalloc 与 kmalloc 不同(通过检查 info->screen_base 以查看它是否为 vmalloced)。如果你有vmalloced,它使用screen_base 作为虚拟地址。如果你没有使用过vmalloc,它假定感兴趣的地址是info->fix.smem_start 中的物理地址。

所以,要正确使用 deferred_io

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

在 Ubuntu 上确认解决了这个问题。

于 2014-03-09T18:09:49.557 回答
-1

真的很有趣,我目前也在实现基于 SPI 的显示 FB 驱动程序(Sharp Memory LCD 显示器和我的 VFDHack32 主机驱动程序)。我也面临类似的问题,它在 deferred_io 崩溃。你能分享你的源代码吗?我的在我的 GitHub 存储库中。PS记忆液晶显示器是单色的,所以我只是假装是彩色显示器,只是检查像素字节是空的(点关闭)还是不空的(点打开)。

于 2021-08-29T17:18:38.810 回答