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 を開いて mmap すると、正しく動作します。fb1を「共有」するためにx11vncが何が起こっているかを見ることができます:

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

そして、vnc ビューアーで表示します。

gvncviewer strontium:0

mmapd バッファー全体に書き込むことで、オーバーフローがないことを確認しましたが、問題ないようです。

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 に違いはありますか?

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 に答える