Chinaunix首页 | 论坛 | 博客
  • 博客访问: 71698
  • 博文数量: 68
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-27 21:43
文章分类
文章存档

2014年(68)

我的朋友

分类: LINUX

2014-07-05 22:04:27

     在三年前做android手机内核移植的时候,如果需要自己重新编译内核的话,内核配置都是从手机中运行的内核中获取的,这个方法也是从XDA学来的:/proc/config.gz。最近重游LDD3的时候,在调试那章中又认真看了一下:
(摘自《LDD3》第四章)

  1. CONFIG_IKCONFIG
  2. CONFIG_IKCONFIG_PROC
  3. 这些选项出现在“General setup(一般设置)”菜单中,会让完整的内核配置状态包含到内核中,并可通过/proc访问。大多数内核开发者清楚地知道自己所使用的配置,因此并不需要这两个选项(会使得内核变大)。然而,如果读者要调试的内核是由其他人建立的,则上述选项会比较有用。

     首先这两个配置的位于(init/Kconfig):

  1. General setup-->
  2. <*> Kernel .config support(对应CONFIG_IKCONFIG)
  3. [*] Enable access to .config through /proc/config.gz(对应CONFIG_IKCONFIG_PROC)
    如果要内核保存内核的配置,必须先选择 <*> Kernel .config support,这个选项作用是让内核在编译的时候将.config文件做gz压缩后将其转换为一个放置于只读数据段的大字符数组“static const char kernel_config_data”中最后通过config.o连接进内核。
    如果在这个基础上选择了“[*] Enable access to .config through /proc/config.gz”就在保持内核配置到数组的基础上,提供一个用户空间读取这个数组的procfs文件接口。实现这个功能的是由内核的kernel/Makefile和kernel/configs.c共同完成的。下面详细解析一下:

首先我们看一下kernel/Makefile有关部分 :

  1. ......
  2. obj-$(CONFIG_IKCONFIG) += configs.o -------------------------------------(1)
  3. ......
  4. $(obj)/configs.o: $(obj)/config_data.h ----------------------------------(2)
  5. # config_data.h contains the same information as ikconfig.h but gzipped.
  6. # Info from config_data can be extracted from /proc/config*
  7. targets += config_data.gz
  8. $(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE --------------------------(4)
  9. $(call if_changed,gzip)
  10. quiet_cmd_ikconfiggz = IKCFG $@
  11. cmd_ikconfiggz = (echo "static const char kernel_config_data[] __used = MAGIC_START"; cat $< | scripts/bin2c; echo "MAGIC_END;") > $@ ----------------------------------(5)
  12. targets += config_data.h
  13. $(obj)/config_data.h: $(obj)/config_data.gz FORCE -----------------------(3)
  14. $(call if_changed,ikconfiggz)

(1)如果配置了CONFIG_IKCONFIG就要生产 configs.o 文件

(2) configs.o 文件依赖 $(obj)/config_data.h文件,隐含的生成条件是通过configs.c文件编译生成。而在configs.c文件中包含了$(obj)/config_data.h文件。

(3) $(obj)/config_data.h文件的生成依赖$(obj)/config_data.gz,并强制每次编译都重新生成$(obj)/config_data.h文件(FORCE)。这个文件的生成规则是(5)

(4)$(obj)/config_data.gz文件的生成依赖$(KCONFIG_CONFIG)(也就是内核配置文件.config),并强制每次编译都重新生成$(obj)/config_data.gz(FORCE)。这个文件的生成是通过将.config执行gzip压缩生成的。

(5)这里其实就是执行一个shell指令,将$(obj)/config_data.gz文件中的数据通过内核工具程序scripts/bin2c放入一个名为“kernel_config_data”的字符数组中,并以MAGIC_START(宏:"IKCFG_ST")开头,MAGIC_END(宏: "IKCFG_ED")结尾。

    最后这个configs.o文件会被连接进内核,如果你的内核中配置了CONFIG_KALLSYMS,那么你就可以在/proc/kallsyms中看到“kernel_config_data”这个符号。

    如果你配置了CONFIG_IKCONFIG_PROC,那么configs.c中的procfs文件系统接口模块就会被编译进去,其实就是实现了对这个字符数组的读取和定位的功能。

上面的生产过程介绍完了,现在用一个图来总结一下过程 :
上面介绍了内核映像中内核配合信息的生成,接下来就看要如何获取了。从上面的介绍中其实不能看出获取的方法有两种:
1、在运行时通过/proc/config.gz获取:
     在控制台输入命令:cat /proc/config.gz | gzip -d > (你要保存配置的文件名)
     这个方法简单,但是也有他的局限性,首先必须配置CONFIG_IKCONFIG_PROC,其次必须在系统运行时进行获取。

2、可以直接通过编译好的内核映像:vmlinux、zImage、uImage等直接获取
     这个方法其实也非常简单,内核黑客们已经帮我们做好了提取工具了:scripts/extract-ikconfig。使用起来超简单:
     (如果是交叉编译,那就在宿主机)输入如下命令:(内核源码路径)scripts/extract-ikconfig (内核映像路径) > (你要保存配置的文件名)
     这个工具对于gz压缩方式是支持一贯不错,从2.6.37开始支持bzip2、 lzma 和 lzo压缩方式,从2.6.39开始支持 xz压缩方式。这些从内核的git log中可以看出。          

3、从内核逻辑地址空间提取:
     从上面的的生成介绍中我们可以知道,配置文件的压缩文件其实就在内核映像的只读数据段中。如果内核在运行的时候,其实数据在内核逻辑地址空间中可以找到。方法概况如下:
     (1)通过/proc/kallsyms找到“kernel_config_data”这个符号对应的内核逻辑地址
     (2)通过/dev/kmem和上面得到的逻辑地址获取数据。压缩文件数据就在:"IKCFG_ST"与"IKCFG_ED"之间。
      这个步骤需要自己写一小段的C代码,可以参考devkmem的代码(《对于驱动调试有用的两个小工具(devmem2、devkmem)》
阅读(521) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~