转载自水木清华 欢迎大家补充
1. 请推荐一些好的Linux内核参考书?
2. 源代码问题 2.1 如何得到某一版本的Linux内核源代码? 2.2 请问xx命令、xx库的源码是哪个文件? 2.3 linux-2.x.x.tar.gz.sign 文件有什么用途? 2.4 请推荐一些源代码查看工具? 2.5 内核patch如patch-2.6.3怎么用? 2.6 如何统计linux内核有多少行代码? 2.7 xx结构的定义在哪个内核源文件中? 2.8 volatile和__volatile__是什么意思? 2.9 do{ ... } while(0)是什么意思? 2.10 list_entry的定义是怎么回事? 2.11 校内查看linux 内核源代码地址
3. 模块编程问题 3.1 模块编程需要注意什么? 3.2 为什么insmod一个模块时显示版本不匹配? 3.3 为什么出现Unresolved Symbol错误? 3.4 为什么出现no license错误? 3.5 为什么看不到用printk打印的信息?
4. 内核开发问题 4.1 怎么制作、使用patch文件? 4.2 在内核中可以使用系统调用吗? 4.3 在内核中怎么打开并操作一个文件? 4.4 在内核中读写文件时为什么会出现EFAULT(-14)错误? 4.5 怎么在系统中增加一个自己的系统调用? 4.6 怎么在内核中加入我自己的驱动程序? 4.7 怎么通过程序得到cpu和mem使用率? 4.8 如何获得高精度的系统时间? 4.9 怎么进行系统性能调谐? 4.10 内核中怎么进行互斥?
5. 其它问题 5.1 如何学习Linux内核? 5.2 如何下载精华区? 5.3 init进程是核心进程吗?init与初始进程是不是一回事? 5.4 initrd(.img)有什么用?
6. 关于本FAQ 7. Changelog
1. 请推荐一些好的Linux内核参考书? a.《Linux Device Drivers, 2nd Edition》,有中文译本 b.《Understanding the Linux Kernel, 2nd Edition》 c.《Linux内核源代码情景分析》,分上下两册 d.《边干边学-Linux内核指导》 e.《Linux内核2.4版源代码分析大全》 f.《Linux Kernel Development》 g.《IA-64 Linux Kernel: Design and Implementation》 注:a电子版可在http://www.oreilly.com/catalog/linuxdrive2/下载; f和g比较新,在国内比较难买到。 也可以版面查询文章标题 "Linux内核书籍推荐&介绍"
2. 源代码问题 2.1 如何得到某一版本的Linux内核源代码? a. http://www.kernel.org或ftp://ftp.kernel.org,这是Linux内核版本的发布 网站。 b. 很多镜像或本地网站也提供部分Linux内核版本的下载,多用ftp搜索引擎。 linuxaid.com提供的mirror: ftp://ftp.linuxaid.lkams.kernel.org/pub/mirrors/kernel/linux/kernel c. 一般的Linux发行版如Redhat之类会随盘提供相应的内核源代码,不过这个源代 码往往是改动过的,与标准Linux内核有差异。
2.2 请问xx命令、xx库的源码是哪个文件? a. 一个系统除了内核以外,还需要有shell、gcc等一系列工具和命令以及C库等一 系列库,这些作为应用程序其源代码都不在内核中,需要另外下载相应的源代码。 b. 对于Redhat系统,可以用rpm -qf命令来查找某一命令所在的软件包,然后再找 相应的源代码包安装。 c. gnu.org有很多软件源代码如bash/glibc/binutils/make/gcc的源代码。 d. 可在http://www.rpmfind.net或http://www.google.com去搜一搜。
2.3 linux-2.x.x.tar.gz.sign 文件有什么用途? 这是一个数字签名文件,用来校验linux-2.x.x.tar.gz这个文件在签名后是没有 被第三方修改过,更详细的信息参考http://www.kernel.org/signature.html。
2.4 请推荐一些源代码查看工具? a. Windows系统可以用Source Insight,Linux系统可以用Source Navigator。 b. vim或emacs编辑器,配合cscope、ctags、etags等交叉索引工具。 c. vim或emacs编辑器,配合grep、egrep等文本搜索工具,不过最好要对源代码目 录结构有所熟悉 d. LXR,以网页的形式通过浏览器浏览,安装复杂(debian下安装容易,请版面 搜寻lxr) 校外:可以直接访问http://lxr.linux.no/source/在线阅读Linux内核源代码。 校内:可以访问http://10.214.14.127/lxr/http/source/,如果需要特定版本 可以联系vatano,只有空间足够就放上去。 e. GNU global,可以在命令行用,也可以生成hypertext,类似lxr,但更省事。
2.5 内核patch如patch-2.6.3怎么用? a. 内核patch一般是针对前一个版本,如patch-2.6.3是针对2.6.2的内核。 b. 内核patch一般是和ChangeLog对应,如patch-2.6.3对应于ChangeLog-2.6.3。 c. 在内核patch中查找Makefile关键字可得到相关信息,如在patch-2.6.0中有: diff -Nru a/Makefile b/Makefile --- a/Makefile Wed Dec 17 19:00:07 2003 +++ b/Makefile Wed Dec 17 19:00:07 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 0 -EXTRAVERSION = -test11 +EXTRAVERSION = d. 找到了针对的内核就可以用patch来升级内核了。
2.6 如何统计linux内核有多少行代码? 尝试以下shell命令: find /usr/src/linux-2.x.x ->
2.7 xx结构的定义在哪个内核源文件中? a. 请使用源码查看工具,见问题2.4。 b. 如果用grep等文本搜索工具,主要在include/linux和include/asm两个目录下 搜索。
2.8 volatile和__volatile__是什么意思? a. volatile是C语言定义的关键字,gcc为了需要又定义了__volatile__,它和 volatile表达的是同一意思。 b. volatile的本意是"易变的",由于访问寄存器的速度快于访存,所以编译器一般 都会作优化以减少访存。如果变量加上volatile修饰,则编译器就不会对此变量 的读写操作进行优化,即不通过寄存器缓冲而直接访存。 c. __asm__ __volatile__一起指示编译器不要改动优化后面的汇编语句。
2.9 do{ ... } while(0)是什么意思? a. 主要是为了避免宏在不同情况展开可能会出现的一些错误。 b. 在http://www.kernelnewbies.org/faq/上有详细介绍。
2.10 list_entry的定义是怎么回事? a. list_entry的定义在内核源文件include/linux/list.h中: #define list_entry(ptr, type, member) / ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) b. 其功能是根据list_head型指针ptr换算成其宿主结构的起始地址,该宿主结构是 type型的,而ptr在其宿主结构中定义为member成员。如下图:
req-->|type型对象起始地址 | |... ... ptr-->|ptr指针所指的member成员地址 | |... ...
ptr指向图中所示的位置,通过(unsigned long)(&((type*)0)->member)得到ptr 和req之间的差值,ptr减去这个差值就得到了type型宿主结构的指针req,返回 类型为(type*)。
2.11 校内查看Linux内核源代码的地址 http://10.214.14.127/lxr/http/source/
3. 模块编程问题 3.1 模块编程需要注意什么? a. 在gcc编译选项中增加-c b. 在gcc编译选项中定义两个宏:-DMODULE -D__KERENL__ 或直接在源文件中定义这两个宏: #define MODULE #define __KERNEL__ c. 在源文件中包括module.h文件: #i nclude <linux/module.h> d. 假定你现在运行的内核的源码目录绝对路径是MyKernelSrcPath,在gcc编译时 增加选项: -I $MyKernelSrcPath/include (如-I /usr/src/linux/include) 注意MyKernelSrcPath必须是指向与当前运行的系统内核匹配的(版本一致)、 能编译成功的(保证源代码目录的完整性)、已经config过的(保证有.config和 include/linux/autoconf.h文件)内核源码目录 注意:通常不要 -I /usr/include/linux e. 如果要用inline功能,需要在gcc编译选项中增加-O2 f. init_module()函数必须return 0,否则会出现Device or resource busy错误。
3.2 为什么insmod一个模块时显示版本不匹配? a. 见上面3.1->d b. 某些时候用insmod -f能够成功加载,但需谨慎使用。
3.3 为什么出现Unresolved Symbol错误? a. 首先查看文件/proc/ksyms,看内核有没有输出这个符号,不同的内核版本如 2.2和2.4输出的符号会有些变化。 b. 如果内核输出的符号带有版本控制信息如符号printk_R12345678,则性质同 问题3.2。 c. 注意:现在有很多版本都不输出sys_call_table了,另想办法吧!
3.4 为什么出现no license错误? 在源文件加入下面一行(加在文件头部,尾部均可): MODULE_LICENSE("GPL");
3.5 为什么看不到用printk打印的信息? a. 打印消息受级别的限制,消息级别可以通过printk设置,如: printk("<n>something"); /* 其中0<=n<=7 */ 假设控制台的消息级别为m, 当n<m时消息打印到控制台,否则不打印。 这样一方面可以提高要打印消息本身的级别(数字越小级别越高), 另一方面可以改变控制台的消息级别(可从1到8),如改为8可用以下命令: # echo "8" > /proc/sys/kernel/printk b. 用dmesg命令看。 c. 当系统运行klogd和syslogd时,内核消息就会由klogd分发到syslogd, syslogd会根据配置文件/etc/syslog.conf作相应处理,具体可以查看syslogd 和syslog.conf的man页。
4. 内核开发问题 4.1 怎么制作、使用patch文件? a. patch文件是由diff命令生成的,使用patch文件用patch命令,具体可查看diff 和patch的man页和info。 b. diff命令的常用选项组合是urN,如: diff -urN linux/ my_linux/ >mypatch.diff
4.2 在内核中可以使用系统调用吗? a. 可以。内核源代码中就有使用系统调用的例子,如open()、execve()等。 b. 在内核中使用系统调用必须要在源文件中包括以下两行: #define __KERNEL_SYSCALLS__ #i nclude <linux/unistd.h> c. 内核中使用系统调用的相关定义可查看文件include/asm/unistd.h。 如果要用的系统调用该文件中没有定义,可以按照其格式自行添加。 d. 如果要在模块中使用系统调用,必须要自己定义errno如: int errno; 内核在lib/errno.c中定义了errno,但该符号不导出,所以模块编程时需要自己 定义errno,用以存放系统调用出错号。
4.3 在内核中怎么打开并操作一个文件? a. 直接用open()、read()等系统调用,见问题4.2。 b. 用filp_open()函数打开文件,得到struct file *的指针fp。 使用指针fp进行相应操作,如读文件可以用fp->f_ops->read。 最后用filp_close()函数关闭文件。 filp_open()、filp_close()函数在fs/open.c定义,在include/linux/fs.h中 声明。 c. 自己写包装函数,可参照文件fs/exec.c中的open_exec()和kernel_read()函数。 在http://www.linuxforum.net/forum/showflat.php?Cat=&Board=linuxK &Number=363455&page=&view=&sb=&o=&vc=1上有些代码可以参照。
4.4 在内核中读写文件时为什么会出现EFAULT(-14)错误? a. 内核文件系统提供的read()和write()之类的函数,期望是对用户态程序服务的, 所以它会验证读写缓冲区不超过用户空间的上限即0xC000 0000。但现在内核中 要读写文件,缓冲区在内核中即地址会超过0xC000 0000。 b. 在读写文件前先得到当前fs:mm_segment_t old_fs=get_fs(); 并设置当前fs为内核fs:set_fs(KERNEL_DS); 在读写文件后再恢复原先fs: set_fs(old_fs); set_fs()、get_fs()等相关宏在文件include/asm/uaccess.h中定义。
4.5 怎么在系统中增加一个自己的系统调用? 去http://www.linuxaid.com.cn/engineer/ideal/kernel/new_syscall.htm 和http://www.xenotime.net/linux/syscall_ex/看看。
4.6 怎么在内核中加入自己的驱动程序? a. 去http://www-900.ibm.com/developerWorks/cn/linux/kernel/l-kerconf/ index.shtml看看,了解一下整个内核的配置编译系统。 b. 在相应位置建立自己的源码目录、文件、Makefile等。 c. 修改上层Makefile,把自己的程序加入到内核编译系统中。 d. 修改上层Config.in,把自己的程序加入到内核配置系统中。 e. 确保自己的初始化函数被调用。有两种方法,一是显式调用,即在原来的系统 初始化函数中直接加入对自己的调用,如字符设备就在drivers/char/mem.c中的 chr_dev_init()函数中加入,块设备就在drivers/block/ll_rw_blk.c中的 blk_dev_init()函数中加入。另一种方法是用initcall,用宏module_init来申 明你的初始化函数,操作系统在初始化到一定阶段后会自动通过init/main.c中 的do_initcalls()函数来统一调用这些初始化函数。module_init宏在文件 include/linux/init.h中定义。
4.7 怎么通过程序得到cpu和mem使用率? a. 这些信息的最终来源都是/proc目录下的文件,如/proc/stat等。 b. procps包下的命令如top、vmstat等实现了这些功能,可以参照其源代码。 c. procps包可从Redhat发行版中得到,也可从http://www.surriel.com/procps/ 处获得。
4.8 如何获得高精度的系统时间? a. Linux中jiffy是时钟的基本单位,对于一般的系统来说配置成10ms。大多数时 钟相关的系统调用都是基于jiffy,所以精度不会太高。 b. 可以考虑使用TSC(time stamp counter)、rtc(real time clock)等寄存器来获得 高精度时钟,具体可查看相关的硬件手册。
4.9 怎么进行系统性能调谐? a. IBM developworks: http://www-900.ibm.com/developerWorks/cn/linux/l-kperf/index.shtml http://www-900.ibm.com/developerWorks/cn/linux/management/tune/index.sht ml b. Linux Performance Tuning项目:http://linuxperf.nl.linux.org/ c. http://www.fixdown.com/article/article/724.htm
4.10 内核中怎么进行互斥? a. Linux内核中有两种机制实现互斥:semaphore和spinlock。semaphore是让进 程睡眠等待资源,这一般假设无法预测资源什么时候可以获得;spin_lock一般 用在SMP中,它假设所等待的资源马上就会被释放,所以循环等待资源。 semaphore只能用于非中断环境(典型的中断环境过程包括象timer之类的中断 服务程序,softirq等)的进程间互斥,spinlock可以用于所有的进程间包括不同 cpu的进程间的互斥,spinlock主要用于保护短小的临界区,使用时必须要特别注 意死锁问题。 b. semaphore是通过进程调度来实现互斥的。进程请求获取semaphore时,如果 semaphore空闲则该进程获得semaphore,设置标志并返回;如果semaphore忙 (其它用户已经获得semaphore)则系统构建等待队列并通过进程调度机制让本进 程睡眠。进程释放semaphore时,系统按一定规则通过等待队列唤醒一个睡眠进 程。对semaphore可执行up()和down()操作,详见include/asm/semaphore.h文件。 c. spinlock主要是为SMP互斥而引入的。在请求获取spinlock时,如果空闲则获得 spinlock,设置标志并返回。如果spinlock已经被其它用户获得而处于忙状态, 系统就会一直占用CPU资源,不停查询spinlock的状态直到获得spinlock。
5. 其它问题 5.1 如何学习Linux内核? 请先阅读本版精华区内核学习目录的相关文章。
5.2 如何下载精华区? a. 除了88提供的下载,还可以通过脚本下载-_-
5.3 init进程是核心进程吗?init与初始进程是不是一回事? Linux操作系统在系统初始化之初就捏造了一个原始进程(原始进程在系统初始化 完毕后就演化成idle进程),当系统初始化进行到一定阶段,原始进程会创建(通 过kernel_thread()函数)出来init进程,init进程继续进行系统初始化工作并在最 后执行execve("/sbin/init",...),这样init就从原来的核心进程摇身一变成用户 进程(用户程序/sbin/init)了。init进程的pid为1,原始进程(idle进程)的 pid为0。所有其它的进程都由init进程派生,用ps或pstree命令可以看到这一点。
5.4 initrd(.img)有什么用? a. initrd(.img)是一个文件系统映像,里面一般包含一些特殊的硬件模块尤其是存 储设备如scsi/raid/ext3模块,以便在保持内核足够小的同时又支持尽可能多的硬 件设备,常被安装程序使用。 initrd(.img)也不是必需的,只要必要的模块编译进内核就可以不用initrd(.img)。 b. 在使用了initrd(.img)时,系统引导的大致过程如下: 1)Loader程序(如lilo和grub)加载内核和initrd(.img) 2)内核解压缩initrd(.img)为正常的RAM盘文件系统并挂接为根分区 3)执行linuxrc,在此过程中会加载硬件模块 4)在linuxrc终止后,真正的根文件系统被挂接 5)在根文件系统上完成正常的引导过程。对于正常的系统而言,执行/sbin/init, 这时控制就会转到正常的大家所熟知的启动过程。而对于安装程序,只需将控制 转到安装过程的第一阶段,由它完成后续的安装环境的加载,设备的进一步初始 化等操作。 c. 要使用initrd(.img)首先内核必须配置成支持initrd: CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y 其次要在Loader脚本中增加相应指示。如在grub.conf中增加一行: initrd /boot/initrd-2.4.20.img d. 可用mkinitrd命令创建initrd(.img)文件: mkinitrd imagefilename kernelversion 如对于2.4.20的内核可以: mkinitrd /boot/initrd-2.4.20.img 2.4.20 e. 具体可查看Documentation/initrd.txt和man mkiinitrd。mkinitrd命令执行的详 细过程可以直接查看/sbin/mkinitrd(shell脚本)文件。
6. 关于本FAQ 本FAQ主要根据本版以前的文章整理而成。 特别感谢mada、pepp等网友提出宝贵意见!
|
相关推荐
Linux内核模块开发指南 !
Linux内核模块开发常用内核接口Linux内核模块开发常用内核接口
Linux内核动态模块开发分析.pdf
Linux内核分析及常见问题解答
你是否曾经疑问过我们编写的内核模块是什么时候,如何加载到内核的,本文将为你揭开迷惑。
LINUX内核模块编程LINUX内核模块编程LINUX内核模块编程
突破Linux内核模块校验机制 突破Linux内核模块校验机制
Linux内核驱动模块编程指南。 适合需要些内核驱动的工程设计人员或学生使用。
LInux内核模块开发
LINUX内核经典面试题 ,20) 如何加载、卸载一个模块? 21) 模块和应用程序分别运行在什么空间? 22) Linux中的浮点运算由应用程序实现还是内核实现? 23) 模块程序能否使用可链接的库函数? 24) TLB中缓存的是什么...
4. Linux内核模块开发 5. Linux内核启动流程 第二天 1. Linux内存管理 2. Linux进程地址空间 3. Linux内核地址空间 4. Linux内核链表 5. Linux内核定时器 第三天 1. Linux进程控制 2. Linux进程调度 3. Linux系统...
介绍linux内核模块的开发,内核驱动的编写,对从事驱动开发的人员可能会有用
如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核.txt如何编译你自己的linux内核....
Package sysinfo 是一个提供 Linux 操作系统/内核/硬件系统信息的 Go 库。它完全独立,不依赖主机系统,不执行外部程序,甚至不导入其他 Go 库。 我找不到任何可以提供我需要的数据/功能集的独立库。于是又一个...
linux内核中有关于list 、kfifo等数据结构的实现,从源码中抽取出list部分,可以在linux应用编程中使用。有详细的抽取过程原理,ubunt12.04上完成
linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核编译2.6.39linux内核...
嵌入式Linux内核及其驱动开发
理解Linux内核最好预备的知识点:懂C语言懂一点操作系统的知识熟悉少量相关算法懂计算机体系结构Linux内核的特点:结合了unix操作系统的一些基础概念Linux内核的任务:1.从技术层面讲,内核是硬件与软