ubuntu内核编译调试

来源:互联网 发布:趣学python编程中文版 编辑:程序博客网 时间:2024/06/12 01:18

注,部分内容参照http://wiki.ubuntu.org.cn/index.php?title=UbuntuHelp:Kernel/Compile/zh&variant=zh-cn#.E7.BC.96.E8.AF.91.E5.86.85.E6.A0.B8.EF.BC.88.E4.BB.85.E9.92.88.E5.AF.B9.E5.86.85.E6.A0.B8.E6.BA.90.E7.A0.81.E6.9D.A5.E8.87.AA.E4.BA.8Egit_.E4.BB.93.E5.BA.93.EF.BC.8C.E6.88.96.E6.98.AFapt-get.E6.BA.90.EF.BC.89


系统安装完毕后,各软件的版本情况

wlan_ac@wlan:/boot$ ll
总用量 26776
drwxr-xr-x  3 root root     4096  3月 15 00:06 ./
drwxr-xr-x 23 root root     4096  3月 15 00:04 ../
-rw-r--r--  1 root root  1007780  1月 31 02:07 abi-3.11.0-15-generic
-rw-r--r--  1 root root   168536  1月 31 02:07 config-3.11.0-15-generic
drwxr-xr-x  3 root root    12288  3月 15 00:04 grub/
-rw-r--r--  1 root root 17118280  3月 15 00:06 initrd.img-3.11.0-15-generic
-rw-r--r--  1 root root   176764 11月 27  2011 memtest86+.bin
-rw-r--r--  1 root root   178944 11月 27  2011 memtest86+_multiboot.bin
-rw-------  1 root root  2768346  1月 31 02:07 System.map-3.11.0-15-generic
-rw-r--r--  1 root root  5962944  2月  5 04:12 vmlinuz-3.11.0-15-generic

安装必要的软件

sudo apt-get install fakeroot build-essential crash kexec-tools makedumpfile kernel-wedge
sudo apt-get build-dep linux
sudo apt-get install git-core libncurses5 libncurses5-dev libelf-dev asciidoc binutils-dev

获取源代码archive
sudo apt-get build-dep --no-install-recommends linux-image-$(uname -r)
apt-get source linux-image-$(uname -r)
工作目录home/wlan_ac下生成相关tar.gz文件以及子目录linux-lts-saucy-3.11.0


sudo make mrproper 清除代码(如果不需要重新编译整个内核,仅更新了部分代码,则不需要执行词句。)


修改内核配置(在目前没有需要)
进入/boot目录,看见系统当前配置文件config-3.11.0-15-generic
进行备份config-3.11.0-15-generic-org-bak
运行make menuconfig进入图形配置界面。通过加载系统当前配置/boot/config-3.11.0-15-generic 获得初始状态,然后可以通过修改该界面参数。修改之后可以选择保存到源代码所在目录/home/wlan_ac/linux-lts-saucy-3.11.0 后退出。
注意,系统默认生成的config文件名称为config.版本号。但是,编译内核时,需要在代码目录下指定需要使用的config文件,否则make dep失败.指定方法为,将需要编译的config文件修改为.config名称即可。

执行sudo make dep生成依赖关系


编译内核

执行gcc -v查看gcc版本为4.6.3

执行AUTOBUILD=1 fakeroot debian/rules binary-debs进行编译,系统提示rule目录下缺少文件。

执行sudo make bzImage,编译内核映像。

执行sudo make modules 编译模块。

内核装载

执行sudo make install 加载内核模块。

结果,加载期间机房断电!!启动后,现象非常奇怪,系统没有提示老版本linux的加载通道,只有新版本3.11.0.4的加载选项。选择进入后报错。

重新执行sudo make install,执行成功后再次启动系统。

界面给出了当前新内核的加载选项以及前版本加载选项。选择前版本,可以看到3.11.0.4和3.10.5.0两个版本。也就是说包括第一次加载了一半的系统也给出了选项。

目前的问题是:

启动新内核后,usb的键盘鼠标都不能用了。

用老系统安全模式重新登录,查阅资料,看到文章http://bbs.chinaunix.net/thread-1922275-1-1.html,联想到自己的情况确实也有modules加载失败的提示。

重新执行sudo make modules_install然后sudo make install

发现系统自动后,进入不稳定状态,经常出现标准版不能正常登录,修复版本可以normal reboot的状态。而且这个现象不稳定,重启后存在恢复可能。

担心是grub问题,按照网上介绍修改了分辨率问题,结果只是改善了显示效果,不解决实际问题。遂决定重新make mrproper。

结果发现一切照旧。

后来偶然发现原来系统本身没有问题,只是linux 默认启动等待10秒.在这10秒里,键盘鼠标无响应。

修改方法参照http://blog.csdn.net/binbinxyz/article/details/8498452为、

$ sudo cp /boot/grub/grub.cfg /boot/grub/grub.cfg.bak

$ sudo vi /boot/grub/grub.cfg
输入以下内容以快速查找定位相关配置信息
:/timeout
其中
set timeout=10

表示默认等待时间是10秒(注意:单位是秒)。


但是发现没有用。用秒表统计,修改后,选择内核版本后,界面超过一分钟无任何信息。按esc后,正常启动。

后仔细观察看到提示ata_id[6864]: HDIO_GET_IDENTITY failed for '/dev/sdb': Invalid argument.

根据http://ubuntuforums.org/showthread.php?t=2146901上的提示,问题的原因在于新增的硬盘没有分区表。

可是奇怪的是,系统提示出错的硬盘是/dev/sdb,而新增的硬盘其实是/dev/sda。问题是?

关于HDIO的详细解释参见http://ww2.cs.fsu.edu/~rosentha/linux/2.6.26.5/docs/ioctl/hdio.txt

其中描述

HDIO_GET_IDENTITYget IDE identification infousage:  unsigned char identity[512];  ioctl(fd, HDIO_GET_IDENTITY, identity);inputs:noneoutputs:  ATA drive identity information.  For full description, see  the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in  the ATA specification.error returns:  EINVAL(bdev != bdev->bd_contains) (not sure what this means)  ENOMSGIDENTIFY DEVICE information not availablenotes:  Returns information that was obtained when the drive was  probed.  Some of this information is subject to change, and  this ioctl does not re-probe the drive to update the  information.  This information is also available from /proc/ide/hdX/identify进入命令行,执行sudo hdparm -i /dev/sda 和 sudo hdparm -i /dev/sdb果然在/dev/sdb下提示获取硬件规格信息异常。具体内容如下wlan_ac@wlan:/proc$ sudo hdparm -i /dev/sdb/dev/sdb:SG_IO: bad/missing sense data, sb[]:  70 00 05 00 00 00 00 0a 00 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 HDIO_GET_IDENTITY failed: Invalid argumentwlan_ac@wlan:/proc$ sudo hdparm -i /dev/sda/dev/sda: Model=Hitachi HTS547575A9E384, FwRev=JE4OA60A, SerialNo=J2541054F8K52E Config={ HardSect NotMFM HdSw>15uSec Fixed DTR>10Mbs } RawCHS=16383/16/63, TrkSize=0, SectSize=0, ECCbytes=4 BuffType=DualPortCache, BuffSize=8192kB, MaxMultSect=16, MultSect=16 CurCHS=16383/16/63, CurSects=16514064, LBA=yes, LBAsects=1465149168 IORDY=on/off, tPIO={min:120,w/IORDY:120}, tDMA={min:120,rec:120} PIO modes:  pio0 pio1 pio2 pio3 pio4  DMA modes:  mdma0 mdma1 mdma2  UDMA modes: udma0 udma1 udma2 udma3 udma4 udma5 *udma6  AdvancedPM=yes: mode=0x80 (128) WriteCache=enabled Drive conforms to: unknown:  ATA/ATAPI-2,3,4,5,6,7 * signifies the current active mode 在ubuntu论坛发帖请教问题原因,结果被人建议不要用再用menuconfig了,理由是grub2现在已经默认安装好了。恩,mark一下,以后注意。http://apexu.com/apexu/tw/modules/publisher/item.php?itemid=1考虑到项目进度,内核编译阶段到此结束。遗留问题是登录界面需要esc的问题。,此后进入调试篇。++++++++++++++++++++++++++++++++++++我是调试篇的分割线++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 编写了内核模块的代码,标准格式模板如下:#include <linux/module.h>#include <linux/vermagic.h>#include <linux/compiler.h>static int __init  init_module(void){ printk("<1>Hello world 1.\n"); return 0;}static void __exit cleanup_module(void){    printk(KERN_ALERT "Goodbye world1.\n");}module_init(init_module);module_exit(cleanup_module);编译出错。发现是内核源代码路径问题,/usr/src下只有头文件将源代码放入/ usr/src并且在makefile中指定路径。结果依然出错,提示找不到Makefile。原来linux系统默认必须用这个文件名。修改makefile后,makefile如下ifneq ($(KERNELRELEASE),)obj-m =test_module.oelseKERNEL_DIR ?= /usr/src/linux-lts-saucy-3.11.0PWD := $(shell pwd)default:test_modulestest_modules:    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modulesendifclean:    rm -rf *.tmp*.o *.o *.ko* *.mod* *.cmd *odule* *~此时代码提示编译错误。make -C /usr/src/linux-lts-saucy-3.11.0 M=/home/wlan_ac/workspace/kernelPrj modulesmake[1]: 正在进入目录 `/usr/src/linux-lts-saucy-3.11.0'  CC [M]  /home/wlan_ac/workspace/kernelPrj/test_module.o/home/wlan_ac/workspace/kernelPrj/test_module.c:16:1: 错误: 对‘init_module’的静态声明出现在非静态声明之后include/linux/module.h:70:12: 附注: ‘init_module’的上一个声明在此/home/wlan_ac/workspace/kernelPrj/test_module.c:22:1: 错误: 对‘cleanup_module’的静态声明出现在非静态声明之后include/linux/module.h:71:13: 附注: ‘cleanup_module’的上一个声明在此/home/wlan_ac/workspace/kernelPrj/test_module.c:26:1: 错误: ‘init_module’重定义/home/wlan_ac/workspace/kernelPrj/test_module.c:15:20: 附注: ‘init_module’的上一个定义在此/home/wlan_ac/workspace/kernelPrj/test_module.c:27:1: 错误: ‘cleanup_module’重定义/home/wlan_ac/workspace/kernelPrj/test_module.c:21:20: 附注: ‘cleanup_module’的上一个定义在此make[2]: *** [/home/wlan_ac/workspace/kernelPrj/test_module.o] 错误 1make[1]: *** [_module_/home/wlan_ac/workspace/kernelPrj] 错误 2make[1]:正在离开目录 `/usr/src/linux-lts-saucy-3.11.0'make: *** [test_modules] 错误 2怀疑是因为引用了系统保留字作为函数名(该死的网络教程!!)修改后,编译正常。执行insmod test_module.ko,装载成功(不能少了ko!)执行lsmod 可以看到该模块已经装载。执行rmmod test_module.ko卸载成功但是,程序中的printk没有结果输出到终端屏幕。试图进入 /var/log/messages,发现/var/log下没有messages!查到http://blog.sina.com.cn/s/blog_966f8e8501011gu6.html中描述修改信息输出级别的方法,无效。终于看到一篇靠谱的文章,验证后发现很准确http://www.linuxidc.com/Linux/2011-02/32132.htm 不管怎么做,总是在控制台看不到printk的输出,而查看日志的方法非常受限于日志文件的大小和刷新。尝试很久,终于怀疑是ubuntu的特殊性导致的。专门查了ubuntu的文章,果然有了如下收获.文章链接http://blog.163.com/ljf_gzhu/blog/static/1315534402012112443956156/简要的说就是:在Linux中,驱动程序工作在内核态,内核与用户之间的交互是通过控制台(dev/console)实现的,控制台与终端的概念对于我们“年轻人”来说是容易混淆的,我本人到现在也不是彻底搞明白(菜鸟啊)。内核打印函数printk的输出被定向到文件 /dev/console,但是在Ubuntu环境中,我们使用的通常是虚拟终端 /dev/pts/n。其中n为虚拟终端的编号,如果你当前打开了第3个虚拟终端,那么第3个终端的对应的设备文件即为 /dev/pts/3。可以通过命令tty查看当前终端所对应的设备文件。        在弄清楚了上述概念之后,就不难明白为什么平时在图形界面终端(虚拟终端)下调试驱动程序时printk的输出都看不到了。有两种比较简单的方法可以查看驱动的输出信息,如下所示。方法一:dmesg命令说明:采用该方法的缺点是需要每次手动执行命令查看消息。方法二:cat /proc/kmsg &说明:别忘记在命令参数最后加个与号 & 让cat命令工作在后台。采用该方法的优点是只要驱动有消息输出马上就会在终端看到。:此处只给出解决方法(策略)而非原理(机制)。执行后,果然 看到了完整的输出!!加载和卸载查看模块的命令众所周知是insmod,rmmod,lsmod。修改编译的时候主要遇到的问题:1,头文件缺乏2,需要在makefile里指定源代码和头文件目录3.make clean时错误删除了源代码!!放一个ok的makefile上来。 ifneq ($(KERNELRELEASE),)obj-m =test_module.oecc-objs = elseKERNEL_DIR ?= /usr/src/linux-lts-saucy-3.11.0PWD := $(shell pwd)default:test_modulestest_modules:    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) -I /usr/src/linux-lts-saucy-3.11.0/include/ modulesendifclean:    rm -rf *.tmp *.o *.ko *.ko*  *.cmd  *.mod.* *~ *.symvers *.order出错的makeclean是rm -rf *.tmp *.o *.ko *.ko* *.mod.* *.cmd *odule* *~

问题描述:

       在编译内核模块驱动时,如果出现如下警告信息:

warning: the frame size of 1040 bytes is larger than 1024 bytes。主要是因为内核中设置了堆栈报警大小,其默认为1024bytes。我们主要将其修改为4096既可以消除告警信息。

如果解决:

(1)make menuconfig

(2)kernel hacking

(3)修改warn for stack frames larger than 的数值,将其修改为4096(最好不要大过这个数值)

(4)重新编译内核模块则不会出现如上的告警信息。

小结

关于内核里的程序开发

1.大内存的申请,不推荐使用临时局部变量。因为临时局部变量占用了线程的堆栈空间。而,内核线程的堆栈空间限制为1024字节。即使重新编译内核,最大也不会超过4k。

但是如果使用全局变量定义或者局部静态变量定义,占用的是全局空间,因此不会需要收到1024字节的限制。

2.内核线程创建后,需要通过执行wake_up_process(),启动线程。并在模块退出时主动调用kthread_stop()进行线程的释放。

3.线程内部为了在线程运行期间,及时接收到线程退出的命令,并且及时退出线程,需要周期性调用kthread_should_stop()判断线程当前的状态。该函数返回成功,则break循环。

4.线程运行期间,如果空闲,需要调用schedule_timeout_interruptible(time)及时交出cpu使用权。

 



0 0
原创粉丝点击