| 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 |