| | 300 | |
| | 301 | == BUGFIX: jfbterm (4) == |
| | 302 | |
| | 303 | * [wiki:jazz/09-01-4 09-01-14@GMT+8 原紀錄 BUGFIX: jfbterm (3)] |
| | 304 | |
| | 305 | * 在看 fbcommon.c 時,發現在這組出現錯誤的 mmap 前曾跑過另一組 mmap, 因此把參數印出來對照看看。 |
| | 306 | * gdb debug 程序 |
| | 307 | {{{ |
| | 308 | file jfbterm |
| | 309 | set args -e ls |
| | 310 | show args |
| | 311 | break fbcommon.c:500 |
| | 312 | break fbcommon.c:557 |
| | 313 | break fbcommon.c:566 |
| | 314 | run |
| | 315 | p fb_fix |
| | 316 | c |
| | 317 | p fb_fix |
| | 318 | c |
| | 319 | p fb_fix.smem_len |
| | 320 | p p->soff |
| | 321 | p p->slen |
| | 322 | p fb_fix.mmio_len |
| | 323 | p p->moff |
| | 324 | p p->mlen |
| | 325 | }}} |
| | 326 | {{{ |
| | 327 | root@intrepid:~/jfbterm-0.4.7-dev# gdb |
| | 328 | GNU gdb 6.8-debian |
| | 329 | Copyright (C) 2008 Free Software Foundation, Inc. |
| | 330 | License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> |
| | 331 | This is free software: you are free to change and redistribute it. |
| | 332 | There is NO WARRANTY, to the extent permitted by law. Type "show copying" |
| | 333 | and "show warranty" for details. |
| | 334 | This GDB was configured as "x86_64-linux-gnu". |
| | 335 | (gdb) file jfbterm |
| | 336 | Reading symbols from /root/jfbterm-0.4.7-dev/jfbterm...done. |
| | 337 | (gdb) set args -e ls |
| | 338 | (gdb) show args |
| | 339 | Argument list to give program being debugged when it is started is "-e ls". |
| | 340 | (gdb) break fbcommon.c:500 |
| | 341 | Breakpoint 1 at 0x40303d: file fbcommon.c, line 500. |
| | 342 | (gdb) break fbcommon.c:557 |
| | 343 | Breakpoint 2 at 0x40327e: file fbcommon.c, line 557. |
| | 344 | (gdb) break fbcommon.c:566 |
| | 345 | Breakpoint 3 at 0x403301: file fbcommon.c, line 566. |
| | 346 | (gdb) run |
| | 347 | Starting program: /root/jfbterm-0.4.7-dev/jfbterm -e ls |
| | 348 | ...略... |
| | 349 | Breakpoint 1, tfbm_open (p=0x6146e0) at fbcommon.c:501 |
| | 350 | 501 if (fb_var.yres_virtual != fb_var.yres) { |
| | 351 | (gdb) p fb_fix |
| | 352 | $1 = {id = "▒\204▒▒Q\177\000\000\006\000\000\000\000\000\000", smem_start = 21037808, |
| | 353 | smem_len = 4269392626, type = 32593, type_aux = 0, visual = 0, |
| | 354 | xpanstep = 65535, ypanstep = 65535, ywrapstep = 65535, line_length = 1, mmio_start = 15, |
| | 355 | mmio_len = 21076240, accel = 0, reserved = {53071, 64, 0}} |
| | 356 | (gdb) c |
| | 357 | Continuing. |
| | 358 | ...略... |
| | 359 | Breakpoint 2, tfbm_open (p=0x6146e0) at fbcommon.c:557 |
| | 360 | 557 p->smem = (u_char*)mmap(NULL, p->slen, PROT_READ|PROT_WRITE, |
| | 361 | (gdb) p fb_fix |
| | 362 | $2 = {id = "VESA VGA\000\000\000\000\000\000\000", smem_start = 4026531840, |
| | 363 | smem_len = 1572864, type = 0, type_aux = 0, visual = 3, xpanstep = 0, |
| | 364 | ypanstep = 0, ywrapstep = 0, line_length = 1024, mmio_start = 0, |
| | 365 | mmio_len = 0, accel = 0, reserved = {0, 0, 0}} |
| | 366 | (gdb) c |
| | 367 | Continuing. |
| | 368 | |
| | 369 | Breakpoint 3, tfbm_open (p=0x6146e0) at fbcommon.c:566 |
| | 370 | 566 if(p->mlen == 0) |
| | 371 | (gdb) p fb_fix.smem_len |
| | 372 | $3 = 1572864 |
| | 373 | (gdb) p p->soff |
| | 374 | $4 = 0 |
| | 375 | (gdb) p p->slen |
| | 376 | $5 = 1572864 |
| | 377 | (gdb) p fb_fix.mmio_len |
| | 378 | $6 = 0 |
| | 379 | (gdb) p p->moff |
| | 380 | $7 = 0 |
| | 381 | (gdb) p p->mlen |
| | 382 | $8 = 0 |
| | 383 | }}} |
| | 384 | || fb_fix.smem_len = 1572864 || p->soff = 0 || p->slen = 1572864 || mmap 成功 || |
| | 385 | || fb_fix.mmio_len = 0 || p->moff = 0 || p->mlen = 0 || mmap 失敗 (因為 length = 0) || |
| | 386 | * 從數據看起來,無論是從 SSH 登入,或在本機 tty 使用,所得到的 fb_fix.mmio_len = 0 是主要原因。只是 mmio 所代表的意涵,fbcommon.h 程式碼並無註解。 |
| | 387 | * 繼續往 fb_fix.mmio_len 的源頭追,是 tfbm_get_fix_screen_info 函式去更新 fb_fix 這個結構。資料是透過 ioctl 去詢問核心中對應的 FBIOGET_FSCREENINFO。 |
| | 388 | {{{ |
| | 389 | <fbcommon.c> |
| | 390 | |
| | 391 | 509 tfbm_get_fix_screen_info(p->fh, &fb_fix); |
| | 392 | |
| | 393 | 244 static void tfbm_get_fix_screen_info(int fh, struct fb_fix_screeninfo *fix) |
| | 394 | 245 { |
| | 395 | 246 if (ioctl(fh, FBIOGET_FSCREENINFO, fix)) { |
| | 396 | 247 print_strerror_and_exit("ioctl FBIOGET_FSCREENINFO"); |
| | 397 | 248 } |
| | 398 | 249 } |
| | 399 | }}} |
| | 400 | * [http://lxr.linux.no/linux+v2.6.11/drivers/video/fbmem.c#L804 定義在 Kernel 2.6.11/drivers/video/fbmem.c 中 FBIOGET_FSCREENINFO 的 ioctl handler] |
| | 401 | {{{ |
| | 402 | 804 case FBIOGET_FSCREENINFO: |
| | 403 | 805 return copy_to_user(argp, &info->fix, |
| | 404 | 806 sizeof(fix)) ? -EFAULT : 0; |
| | 405 | }}} |
| | 406 | * [http://lxr.linux.no/linux+v2.6.27.7/drivers/video/fbmem.c#L1247 定義在 Kernel 2.6.27/drivers/video/fbmem.c 中 FBIOGET_FSCREENINFO 的 ioctl handler] |
| | 407 | {{{ |
| | 408 | 1247 case FBIOGET_FSCREENINFO: |
| | 409 | 1248 ret = fb_get_fscreeninfo(inode, file, cmd, arg); |
| | 410 | 1249 break; |
| | 411 | }}} |
| | 412 | * fb_get_fscreeninfo 會呼叫 fb_ioctl 並以 cmd = FBIOGET_FSCREENINFO 去處理,看起來最後執行的程式碼是跟 2.6.11 一樣。 |
| | 413 | {{{ |
| | 414 | 1013 static int |
| | 415 | 1014 fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, |
| | 416 | 1015 unsigned long arg) |
| | 417 | |
| | 418 | 1018 struct fb_info *info = registered_fb[fbidx]; |
| | 419 | |
| | 420 | 1046 case FBIOGET_FSCREENINFO: |
| | 421 | 1047 return copy_to_user(argp, &info->fix, |
| | 422 | 1048 sizeof(fix)) ? -EFAULT : 0; |
| | 423 | }}} |
| | 424 | * 從 fb.h 的定義,我們可以確定 mmio_len 是從 info (型態為 fb_info) 結構中抓出 fb_fix_screeninfo 型態的 fix 回傳給使用者。 |
| | 425 | {{{ |
| | 426 | <linux-2.6.27.7/include/linux/fb.h> |
| | 427 | |
| | 428 | 152 struct fb_fix_screeninfo { |
| | 429 | |
| | 430 | 156 __u32 smem_len; /* Length of frame buffer mem */ |
| | 431 | |
| | 432 | 164 unsigned long mmio_start; /* Start of Memory Mapped I/O */ |
| | 433 | 165 /* (physical address) */ |
| | 434 | 166 __u32 mmio_len; /* Length of Memory Mapped I/O */ |
| | 435 | |
| | 436 | 808 struct fb_info { |
| | 437 | |
| | 438 | 811 struct fb_var_screeninfo var; /* Current var */ |
| | 439 | 812 struct fb_fix_screeninfo fix; /* Current fix */ |
| | 440 | }}} |
| | 441 | * 目前懷疑是 uvesafb 攔截了 FBIOGET_FSCREENINFO 的 ioctl 並回傳了不正確的 fb_fix_screeninfo 內容。因此先來寫一個測試程式,透過 FBIOGET_FSCREENINFO 的 ioctl 把 fb_fix_screeninfo 內容取出來。 |
| | 442 | * [參考] http://www.harlan.idv.tw/Computer/EmbeddedLinux/Chapter4.htm |