看了这么长时间的 Linux 代码,终于能从 bug report 里读出点大概了。今天这个是关于 ATI 显卡驱动的 regression (咋翻译?)。
事情从这里开始,Radeon KMS regression still present in 2.6.33-rc6 [0],reporter 提到开机的时候总是 kernel panic,只有禁用 KMS (Kernel Mode Setting) [1],也就是需要传一个 radeon.modeset=0 参数给内核,才能启动。
然后有一张 panic 时的照片。里面包含了好多的信息,能帮助找到出问题的代码。
首先能看到出错指令的位置,在照片的倒数第五行:
0.097281] RIP [<0xffffffff811c1592>] radeon_agp_init+0x1d/0x2e7
根据这个,作者用 gdb 得出了出错的代码位置。
(gdb) l *(radeon_agp_init+0x1d)
我们能看到出错行是 radeon_agp.c 的第 136 行,但这一行挺长的,不知道到底是那个地方除了错:
if (rdev->ddev->agp->agp_info.aper_size < 32) {
这时看第二封邮件,Linus 把相应的代码编译成了汇编,注意被标出的那个 mov 指令,它的十六进制形式是 4c 8b 60 28,正是上边照片里的那串数字。也就是倒数第六行:
0.097281] Code: 0b 83 78 … 20 03 00 00 (4c) 8b 60 28 49 83 …
2f: 位置的那个 cmp $0x1f,%r12 指令对应 if 语句的那个 “> 32” (因为 0x1f == 31),所以 %r12 应该存有 aper_size,(由于 mov 0x28(%rax),%r12) 所以 %rax 应该存有 agp_info。这个 mov 出错,说明 agp_info 为空。rdev->ddev->agp->agp_info,顾名思义 :),是应该由 AGP 模块填好的,所以 Linus 指出问题可能是因为 DRM 初始化的时候 AGP 还没有初始化。
当然,随后的故事有点简单,一个开发者指出这是个已知的问题,而且已经被修复了。然后就是测试、提交代码。故事到此结束。但是可以看到,问题最终是在 AGP 模块里解决的,而不是引发 panic 的 DRM 模块。并且这个修复也挺有意思,牵扯到 agp_amd64 模块的初始化逻辑,值得一看。AGP 根本没有被初始化,才导致了整个的问题。
在我看来,整个故事中有关汇编、gdb 的部分是精彩之处。
[0] 其实在此五天之前作者就提出过这个问题,但没人回复…; 这提示我们要锲而不舍,问题没解决就要一直纠缠他们 :)
[1] KMS,大体上,指的是让内核来管理显卡,而之前是 X server (具体是 X server 的驱动,即 Device Dependent X / DDX,比如 xf86-video-ati 这个包) 来管理设备的,称作 UMS / User Mode Setting。Kernel 指 kernel space, user 指 user space。
事情从这里开始,Radeon KMS regression still present in 2.6.33-rc6 [0],reporter 提到开机的时候总是 kernel panic,只有禁用 KMS (Kernel Mode Setting) [1],也就是需要传一个 radeon.modeset=0 参数给内核,才能启动。
然后有一张 panic 时的照片。里面包含了好多的信息,能帮助找到出问题的代码。
首先能看到出错指令的位置,在照片的倒数第五行:
0.097281] RIP [<0xffffffff811c1592>] radeon_agp_init+0x1d/0x2e7
根据这个,作者用 gdb 得出了出错的代码位置。
(gdb) l *(radeon_agp_init+0x1d)
0xffffffff811c1592 is in radeon_agp_init
(drivers/gpu/drm/radeon/radeon_agp.c:136).我们能看到出错行是 radeon_agp.c 的第 136 行,但这一行挺长的,不知道到底是那个地方除了错:
if (rdev->ddev->agp->agp_info.aper_size < 32) {
这时看第二封邮件,Linus 把相应的代码编译成了汇编,注意被标出的那个 mov 指令,它的十六进制形式是 4c 8b 60 28,正是上边照片里的那串数字。也就是倒数第六行:
0.097281] Code: 0b 83 78 … 20 03 00 00 (4c) 8b 60 28 49 83 …
2f: 位置的那个 cmp $0x1f,%r12 指令对应 if 语句的那个 “> 32” (因为 0x1f == 31),所以 %r12 应该存有 aper_size,(由于 mov 0x28(%rax),%r12) 所以 %rax 应该存有 agp_info。这个 mov 出错,说明 agp_info 为空。rdev->ddev->agp->agp_info,顾名思义 :),是应该由 AGP 模块填好的,所以 Linus 指出问题可能是因为 DRM 初始化的时候 AGP 还没有初始化。
当然,随后的故事有点简单,一个开发者指出这是个已知的问题,而且已经被修复了。然后就是测试、提交代码。故事到此结束。但是可以看到,问题最终是在 AGP 模块里解决的,而不是引发 panic 的 DRM 模块。并且这个修复也挺有意思,牵扯到 agp_amd64 模块的初始化逻辑,值得一看。AGP 根本没有被初始化,才导致了整个的问题。
在我看来,整个故事中有关汇编、gdb 的部分是精彩之处。
[0] 其实在此五天之前作者就提出过这个问题,但没人回复…; 这提示我们要锲而不舍,问题没解决就要一直纠缠他们 :)
[1] KMS,大体上,指的是让内核来管理显卡,而之前是 X server (具体是 X server 的驱动,即 Device Dependent X / DDX,比如 xf86-video-ati 这个包) 来管理设备的,称作 UMS / User Mode Setting。Kernel 指 kernel space, user 指 user space。