Chinaunix

标题: fudan_abc的Linux内核修炼之道 [打印本页]

作者: ilttv.cn    时间: 2010-03-01 22:51
标题: fudan_abc的Linux内核修炼之道
本帖最后由 ilttv.cn 于 2010-07-30 11:11 编辑

fudan_abc的Linux那些事儿系列,应该很多人都看过,现在新书《Linux内核修炼之道》要出来,博客blog.csdn.net/fudan_abc上已经有更新了,下面从里面转点内容,大家可以瞅瞅撒~

书已经可以买到了,网上购买链接为: 卓越当当china-pub

前言


至此落笔之际,恰至Linux问世18周年,18年的成长,如梦似幻,风雨颇多,感慨颇多。

犹自忆起多年以前一位前辈训导时的箴言:今天的必然正是由之前一系列的偶然所决定的。过去的某年某月,我偶然初识Linux就身陷其中,至今仍找不到出去的路,而正是这次乃至之后的多次偶然相联合,从而决定了今日的我要在此写下这些话。那么,当您偶然地拿起这本书,偶然地看到这段话,您是否会问自己:这样的偶然又会导致什么样的必然?

如果您依然决定继续这次的偶然之旅,那么首先请认识两个人,准确的说是一个人和一只企鹅。这个人自然就是Linus Torvalds,我们也可是称他为Linus或李纳斯,正是这位来自芬兰的天才,在1991年1月2日,攥着在圣诞节和生日得到的钱,偶然地做出了一个重大的财政决定,分期三年买一台价格3500美元得相貌平平得计算机,从而Linux开始了。

企鹅则是Linux的标志,很多人可能不知道Linus,但是却可能知道这只企鹅,这是一个奇怪的现象,就像很多人知道微软,却不知道比尔盖茨。不管怎么说,是Linus塑造了这只企鹅,并让它有一副爽透了的样子,就像刚刚吞下一扎啤酒。除此之外,这只企鹅还要很特别,其他的企鹅都是黑嘴巴黑脚蹼,但它却是黄嘴巴黄脚蹼,这使它看上去好像是鸭子与企鹅的杂交品种,也许它是唐老鸭在南极之旅中与一只当地企鹅一夜倾情的结晶。

其次,在您继续之前,我还想请您问自己一个问题:我在强迫自己学习内核么?我很希望您能回答不是,但希望与现实往往都有段不小的距离,因为很多时候,我都发现身边的人是因为觉得内核很高深而强迫自己喜欢的。强迫自己去喜欢一个人是多么痛苦的事情。或许,针对这个问题,最让人愉悦的回答是“说实话,我学习的热情从来都没有低落过。”正如Linus在自己的自传《Just for Fun》中希望的那样。

本书的组织形式

本书将Linux内核的学习分为四个层次:全面了解,掌握基本功;兴趣导向,选择重点深度钻研;融入社区,参与开发做贡献;坚持,坚持,再坚持。总结起来,就是“全面了解抓基本,兴趣导向深钻研;融入社区做贡献,坚持坚持再坚持。”(如果您是一个修真小说爱好者,尽可以将其与炼气、筑基、结丹和元婴等层次相对应。)

第一层次修炼的内容包括了前三章,目的是希望您能够对Linux以及内核有个全面的认识和了解,掌握分析Linux内核源代码的分析方法。

第1章主要介绍了Linux的18年成长史,或许您会乐意陪我一起缅怀下这过去的十八年。

第2章介绍内核的配置和编译过程,和任何大型软件源码的学习一样,学会编译和配置是第一步。

第3章介绍学习内核需要的基础,内核的体系结构、目录结构、代码特点,浏览内核代码的工具,最后,突出强调了内核源码分析过程中极为重要的两个角色——Kconfig和Makefile,并以USB子系统为例,演示了如何利用这两个角色进行代码分析。


第二层次的修炼包括了第4~11章的内容,对内核多数部分的工作原理进行介绍。按照认识的发展规律,在第一层次修炼中已经对内核有个全局的认识和了解之后,接下来就应该以兴趣为导向,寻找一个子系统或模块,对其代码深入钻研和分析,不懂的地方就通过社区、邮件列表或者直接发Email给 maintainer请教等途径弄懂,切勿得过且过,这样分析下来,对同步、中断等等内核的很多机制也同样会非常了解,俗话说一通则百通就是这个道理。

因此第二层次的各个章节里,只是阐释重点的概念和工作原理,帮助您在分析该部分代码时进行理解,并不求详尽。

第4章讨论系统的初始化,万事开头难,系统的初始化是一个很复杂的过程,不过对于内核源码的学习来说,以这个部分开始应该是个不错的选择。特别是子系统初始化的讨论,应该是您选择任何内核子系统开始分析时都需要了解的内容。

第5章讨论系统调用,它是应用程序和内核间的桥梁,学习并理解它是我们走向内核的一个很好的过渡。

第6章讨论内核的中断处理机制,包括几乎任何一本内核书籍都没有涉及的通用IRQ层。

第7章讨论进程的内核抽象,以及进程如何被创建和销毁。如果我们将计算机上运行的操作系统以及各种各样的软件看作一系列有机的生命体,而不是死的指令集合,那么这就是一个进程的世界,只不过与我们人类世界不同的是,进程世界里的个体是一个一个鲜活的进程,而不是人。人的世界有道德与法律去制约管理,进程的世界同样也有自己的管理机制,这就是第7章所要展示的内容——进程管理。

第8章讨论进程的调度,重点讨论了在内核历史上具有重要地位的O(1)调度器和最新的CFS调度起。

第9章讨论内存管理,内存就是进程的家,这里讨论内核如何为每个进程都分配一个家,并尽量的去做到“居者有其屋”,以及保证每个家的安全。

第10章讨论文件系统,主要是虚拟文件系统(VFS),它通过在各种具体的文件系统之上建立一个抽象层,屏蔽了不同文件系统间的差异。

第11章讨论设备驱动,对于驱动开发来说,设备模型的理解是根本,spec、datasheet与内核源代码的利用是关键。
通过第二层次的修炼,您应该对至少一到两个部分有了很深入的理解,对内核代码采用的通用手法也已经很拈熟,那么您应该开始进入第三层次,努力融入到内核的开发社区,此时的您已经不会再是社区中潜水小白的角色,而是会针对某个问题发表自己的见解。您已经可以尝试参与到内核的开发中去,即使仅仅修改了内核中的一个错误单词,翻译了一份大家需要的文档,也是做出了自己的贡献,会得到大家的认可。
本书中第三层次只包括了两章的内容,这是因为内核的修炼之道越往后便越依赖于自己,任何参考书都替代不了自己不断的反思与总结。

第12章讨论参与内核开发需要了解的一些基础信息。

第13章讨论了内核的调试技术,与第12章一样,您可以仅仅将这些内容看成内核修炼中的一些tips。

至于最后的第四层次,更是仅有两个字——坚持。能够在内核的修炼之道上走多远,都取决于我们能够坚持多久,或许一个用一个公式概括更为合适:心态+兴趣+激情+时间+X=Y。

革命尚未成功,我等仍需努力。——与君共勉之。

……
作者: openspace    时间: 2010-03-02 08:11
这个得关注
作者: ilttv.cn    时间: 2010-03-02 09:36
大家有空可以去逛逛,提些意见,呵呵。
作者: Godbach    时间: 2010-03-02 10:01
fudan_abc兄让大家钦佩啊
作者: vermouth    时间: 2010-03-02 10:28
书还是得多看的。
作者: ilttv.cn    时间: 2010-03-02 18:25
Linux史记
至此落笔之际,恰至Linux问世18周年,18年的成长,风雨颇多,感慨颇多,谨以这些许年来的点滴之事为Linux的成人礼添彩。

如果你尚未与Linux亲密接触过,那么希望这里的内容可以成为你初识Linux的见证。如果你已经是个Linux达人,那么就选个安静的早晨,抑或下午,陪我一起缅怀下这过去的十八年吧。

Linux诞生记

1987年
MINIX诞生,而我也已端坐于学堂之中,隐去一身的稚气,能够摇头晃脑的吟诵几句诗赋了。若真是冥冥中自有定数的话,或许这时就暗定了4年后Linux的诞生。

1991年
Linus Torvalds,一个芬兰的大学生,对于他不能按照意愿访问大学UNIX服务器而感到很愤怒,于是开始为一个以后被称为“Linux”的内核而工作,并于这一年的10月5日发布了Linux 0.01。

1992年
4月,第一个Linux新闻组“comp.os.linux”建立。10月,第一个可以安装的Linux版本SLS发布。同年,我拿到了平生的第一个毕业证。

1993年
8月,第一本关于Linux的著作《Linux Installation and Getting Started Version 1》出版。而这一年,我最敬佩的语文老师患病离去了,从此,我知道了生活中不仅仅只有欢聚,还有伤别。

1994年
Linux 1.0发布,并采用GPL(GNU General Public License,通用公共许可证)协议。大家要Linus Torvalds想一只吉祥物,Linus突然想到小时候去动物园被一只企鹅追着满地打滚,还被咬了一口!既然想不到其它的吉祥物了,干脆就以这支企鹅来当吉祥物算了!

泰坦尼克的狂潮

1995年
4月,召开首届Linux博览会,一个以Linux为特征的商业展览博览会。几个月后,我迎来了第二个中学阶段。

1996年
Linux 2.0发布,它第一个支持了SMP(对称多处理器)架构。此时Linux的全球用户已经达到了350万左右。

1997年
首例Linux病毒“Bliss”被发现。电影《泰坦尼克号》所用的160台Alpha图形工作站中,有105台采用了Linux。

1998年
1月,第一份Linux新闻周刊出版,同时,Netscape宣布他们将在自由软件许可协议下发布浏览器的源代码,这为Linux和自由软件的发展提供了广阔空间。
2月,Eric Raymond和他的朋友门提出了“open source”的概念,申请了该商标特权并且组建了opensource.org网站,从而开始推动Linux的商业化发展。
4月,Linux广泛被美国国家公共新闻广播报道,标志Linux在主流、非技术性的媒体界首次出现。
5月,Google搜索引擎开始流行,不仅仅是因为它是最好的搜索引擎,而且还因为它是基于Linux和具有Linux特色的搜索网页。
6月,“从来没有一个用户向我提起Linux,Linux就像众多的免费产品一样,虽然它是很小的,却得到了一群忠诚的拥护者。”比尔盖茨在6月25日的《PC周刊》上说。
7月,KDE和GNOME的桌面之争在其拥护者之间愈演愈烈,Linus以实际行动中表明KDE非常好用,在这种情况下,KDE1.0诞生了。Oracle、Informix、Sybase都宣布将积极支持Linux。Linux开始成为一个家喻户晓的词。
9月,Dave Whitinge和Dwight Johnson创建了LinuxToday.com,该网站后来被Internet.com收购,不过它一直是访问量最高和最容易阅读的Linux入门网站。
12月,一篇来自IDC的报导说Linux的发行量在1998年涨了200%以上,它的市场占有率也增加了150%以上。Linux拥有17%的市场占有率并且增长率超过了市场上其它任何一个系统。

同年,我迎来了人生中一个非常重要的时刻:我上大学了!
作者: goter    时间: 2010-03-02 18:27
LZ什么时候出书啊?
作者: ilttv.cn    时间: 2010-03-02 18:39
回复 7# goter


    内核修炼之道就这两三个月就上市吧,那些事儿usb部分的合集也是这个时间,这个风格与博客上保持不变,另外还更新了很多有意思的东东,呵呵。
作者: goter    时间: 2010-03-02 18:42
回复 8# ilttv.cn
那就是要出两本实体书?不知道你是A呢还是B呢还是C呢
作者: ilttv.cn    时间: 2010-03-02 18:44
回复 9# goter


    呵呵,是两本吧,那些事儿本来没想着出的,就是写着娱乐大家的,博文视点的一编辑朋友说可以出,就整理了下。至于修炼之道,是人邮的一编辑朋友约的。
作者: accessory    时间: 2010-03-03 00:30
LZ是原作者?看过 “我是U盘”的前一部分,呵呵。

支持下牛人。

另外,Linus 本人被企鹅咬过的,所以他好像不是很喜欢企鹅。不知道大家是否知道这个典故。
作者: ilttv.cn    时间: 2010-03-03 09:52
回复 11# accessory

呵呵,我只知道他被咬过。
作者: ilttv.cn    时间: 2010-03-03 18:57
提前发生的革命

1999年
  1月,“Linux 2.2已经发布,我终于可以松口气了”创造者Linus Torvalds说。
  3月,首届LinuxWorld讨论会和博览会在加洲的圣何塞举行,作为Linux第一个大的商业化的贸易展示活动,它无疑向世界昭示了Linux的到来。
  8月,SG宣布了与Red Hat的合作关系,并且开始大规模的为内核的发展做贡献。Red Hat进行了首次公开募股,股价马上涨到了50美元,在那个时候这个价似乎很高。摩托罗拉公司与Lineo建立了合作关系,进入Linux领域并提供嵌入式系统产品,支持和培训服务。Sun宣布了在Sun公共源许可(Sun Community Source License)下发行StarOffice和开发一个网络版本的办公套件。
  9月,Red Hat的股票达到了135美元,这个价格在那个时候似乎是难以置信的高。
  10月,Sun宣布它将在Sun 公共源许可下公布Solaris的源代码。
  12月,VA Linux Systems的首次公开募股价格是30美元/股,这个价格很快涨到了300美元,它在NASDAQ历史上创造了最高的首次公开募股价格。
  这一年,网络进入了宿舍,QQ、mud等也进入了我们的生活。

2000年
  1月,VA Linux Systems宣布创建我们非常熟悉的SourceForge,到这年底,SourceForge已经接到了超过12000个项目,拥有92000个注册的开发者。
  2月,最近的IDC 报告显示Linux现在成为“服务器电脑上第二个最受欢迎的操作系统”,在1999年占了25%的服务器操作系统销售额,Windows NT为38%,占第一位,NetWare为19%,排名第三,IDC以前曾预测过Linux将在2002或2003年到达第2位,这场革命提前发生了。
  3月,嵌入式Linux协会(Embedded Linux Consortium)成立。
  8月,HP、Intel、IBM以及NEC宣布开放源代码发展实验室(OSDL,Open Source Development Lab)成立。
  9月,Trolltech发布了GPL下的Qt库。
  11月,IBM宣布将在2001年投资10亿美元在Linux。首部基于Linux的手机IMT-2000在韩国发布。
  这一年的某一天,和同学坐在学校四大发明广场上观看同一首歌演出,困意盎然,期间那个粗犷的名歌星的一句话却惊醒了我:“希望你们交通大学为中国的交通事业做出更大的贡献”,大意如此,我顿时无语,他的语言竟然和他的外表一样粗犷。
  这一年的暑假,我第一次来到江南,在西湖断桥对面的饭馆里,透过落地窗恰恰看到湖里荷花的位置,要了份西湖醋鱼和一瓶啤酒,坐到下午四点钟,然后顺着苏堤白堤静静的走下去,直到绕湖一周再次回到断桥,已是晚上八点,坐在湖边的长凳上,一夜无语。

和平、爱情和Linux

2001年
  1月,期待已久的Linux 2.4发布。
  3月,Linux2.5内核高级会议在加州圣何塞举行,它或许是历史上Linux 内核hacker最完整的一次聚会。
  4月,IBM在几个城市鼓吹“和平、爱情和Linux”(Peace, Love and Linux)时遇到了麻烦。
  6月,Sharp宣布基于Lineo嵌入式系统的Linux PDA即将上市。
  这一年底,找工作的季节,我深刻认识了IT泡沫和9.11,找所谓的好工作无门和出国无门,我无奈选择考研。
2002年
  Linus Torvalds将Linux 2.4交由巴西18岁的内核开发人员Marcelo Tosatti维护,自己则带领Linux 2.5的开发工作。
  这一年,我从一个交大到了另一个交大,这个转变似乎很平淡,并不深刻。
作者: c/unix    时间: 2010-03-03 22:23
提示: 作者被禁止或删除 内容自动屏蔽
作者: ilttv.cn    时间: 2010-03-03 22:53
回复 14# c/unix


    呵呵,我是其中之一,fudan_abc是三个人。
作者: Godbach    时间: 2010-03-04 14:35
都是强人啊
作者: ilttv.cn    时间: 2010-03-05 09:42
Ubuntu 4.10

2003年
  1月,NEC宣布将在其手机中使用Linux,代表着Linux成功进军手机领域。
  6月,IDC分析师称,2003年Linux服务器在西欧的销售量将达到18.2万台,到2007年,销售量将增至这个数字的三倍,销售收入将翻一番,达到19亿美元。
  8月,韩国国家航空公司和IBM联合发布声明,表示韩国航空公司将把该公司的核心业务移植到IBM的eServer服务器当中完成,其中操作系统则采用Linux。
  9月,三星在推出了首款基于Linux系统平台的CDMA智能手机SCH-i519。
  11月,Linux 2.6发布,它被认为是第一款真正意义上的企业级内核,这是Linux内核从2001年以来第一次的大改动。
  这一年,我第一次在电视直播里看着自己喜欢的米兰夺得了冠军杯。

2004年
  1月,X.Org基金会成立。
  2月,Linux标准2.0出台,规范了所有能被称为Linux操作系统所应该有的特性。
  5月,基于Linux的路由系统出现。
  10月20日,Ubuntu 首个版本发布,在五年后的今天Ubuntu已经是Linux桌面发行版的一个成功典范。
  11月,Firefox 1.0发布,它成为大众关注的焦点,IE降低了1个点的市场份额——像这种事已经多年没有发生过了。Firefox已经成为了微软IE的强有力的对手。
  又到了找工作的季节,宣讲会、笔试、面试,我就要离开学校了么?

2005年
  10月,Firefox的下载量突破了1亿大关,这表明,只要产品好,开放源代码软件也能够获得普通用户的青睐。
  11月,Sun开放了除Java之外的几乎所有软件,这使得它在一夜间成为了最大的开放源码软件厂商之一。
  12月,Red Hat公布了第三季度业报,销售收入增长了43.6%,利润增长了114%。
  这一年夏天,遭遇了到目前为止最为严重的一次失窃,除了IQ卡,所有的卡都随着钱夹子消失了,到工行补办牡丹卡时,那慵懒的上海女人说,必须要上海土生土长的本地人来担保,仅仅拥有上海户口的人是不行的。

Richard Stallman的征婚启事

2006年
  6月,自由软件之父Richard Stallman在自己的网站http://www.stallman.org/ 上发布了一则“征婚启事”。
I'm a single atheist white man, 52, reputedly intelligent, with unusual interests in politics, science, music and dance.

I'd like to meet a woman with varied interests, curious about the world, comfortable expressing her likes and dislikes (I hate struggling to guess), delighting in her ability to fascinate a man and in being loved tenderly, who values joy, truth, beauty and justice more than "success"--so we can share bouts of intense, passionately kind awareness of each other, alternating with tolerant warmth while we're absorbed in other aspects of life.

My 22-year-old child, the Free Software Movement, occupies most of my life, leaving no room for more children, but I still have room to love a sweetheart. I spend a lot of my time traveling to give speeches, often to Europe, Asia and Latin America; it would be nice if you were free to travel with me some of the time.

If you are interested, write to rms at stallman dot org and we'll see where it leads.

我,单身,无神论者,白人,52岁,据说比较聪明,对于政治、科学、音乐和舞蹈有着不同寻常的兴趣。

我想寻找这样一位女士:爱好广泛,对世界充满好奇心,能够清晰表达她的爱憎(我痛恨动脑筋猜测),乐于使男人着迷,渴望被温柔地爱,对于快乐、真理、美和正义的评价高于“成功”。这样的话,我们就能不断对另一方产生热烈而又美好的了解,当我们被生活中其他东西吸引的时候,彼此就能感到宽容的温暖。

我有一个22岁的孩子——自由软件运动——他占据了我大部分的生活,没有精力再抚养更多的孩子了,但是我仍然会投入的爱我的爱人。我

有大量时间花在巡回演讲上,经常要去欧洲、亚洲和拉丁美洲。如果你有空在某些时间陪我一起旅行,那就最好了。

如果你有兴趣的话,请写信到 rms@stallman.org ,让我们看看会有什么结果。

  7月,Ubuntu被授予PC World 2006 World Class Award,证明了Ubuntu成为2006年世界最好的100个产品之一。Ubuntu越来越显示出他的不凡实力,虽说他是免费的,但是后台却是商业公司Canonical,加上太空人老板的聪明才智,逐渐的开始商业合作,比如和Sun合作,对有需要的客户提供Linux支持服务。
  8月,Linux业界另外一位狂人,Linuspire公司总裁Kevin Carmony宣布推出免费版本的Freespire 1.0,该版本中附带有二进制的商业硬件驱动程序,在Linux社区中引起轩然大波。27日,网站http://linux.inet.hr/poll_filesystem.html 上推出“Your favorite file system?”(你最喜欢的文件系统?)投票活动。
  9月,16日是“国际软件自由日”(SFD,Software Freedom Day 2006)。
  10月,Oracle Unbreakable Linux发布,Oralce成为第一个推出自有Linux服务的非操作系统软件厂商。17日,FSG(自由标准组,一个非赢利的致力于开发和促进自由开放软件的标准的组织)宣布与O'Reilly Media合作,共同为Linux应用程序开发人员提供类似MSDN的服务,该服务将作为LSB (Linux Standard Base) Developer Network的一个组成部分。
  11月,微软和Novell达成一揽子协议,号称要改善Linux和微软操作系统的兼容问题。看着昔日的对手用“+”连起来是否会觉得古怪?

  这一年,三次去青岛,回来时遭遇三次严重的飞机晚点,让我疑惑这个世界怎么了?

微软 + Novell.png (26.75 KB, 下载次数: 34)

微软 + Novell.png

作者: xjtuwjp    时间: 2010-03-05 09:46
回复 15# ilttv.cn

楼主是西交的本,上交的硕?
作者: send_linux    时间: 2010-03-05 10:03
回复  goter


    内核修炼之道就这两三个月就上市吧,那些事儿usb部分的合集也是这个时间,这个风格与 ...
ilttv.cn 发表于 2010-03-02 18:39



    那个出版社呢?

到时候在CU做点活动吧,呵呵
作者: ilttv.cn    时间: 2010-03-05 10:35
回复 19# send_linux


    修炼之道这本是人民邮电出,那些事儿是博文视点出的,都是差不多的时间。

    呵呵,好啊,不过这个活动咋做来着,没概念。
作者: ilttv.cn    时间: 2010-03-05 10:36
本帖最后由 ilttv.cn 于 2010-03-05 10:37 编辑

回复 18# xjtuwjp


    对头,在西安待腻了,就从西交跑到上交了,呵呵。
作者: send_linux    时间: 2010-03-05 10:42
回复  send_linux


    修炼之道这本是人民邮电出,那些事儿是博文视点出的,都是差不多的时间。

  ...
ilttv.cn 发表于 2010-03-05 10:35



    既然有原书作者参与,那就好办多了啊,兄弟还在上海啊?
作者: xjtuwjp    时间: 2010-03-05 12:05
回复 21# ilttv.cn

学长呀,你离开西交那年,我刚进大学。看了你博客的很多文章,没有想到还是校友,呵呵
作者: 独孤九贱    时间: 2010-03-05 12:08
高手何其多,仰望一下,书出版了,一定买一本!
作者: ilttv.cn    时间: 2010-03-05 13:00
既然有原书作者参与,那就好办多了啊,兄弟还在上海啊?
send_linux 发表于 2010-03-05 10:42



    是啊,还在上海,呵呵。
作者: ilttv.cn    时间: 2010-03-05 13:01
回复  ilttv.cn

学长呀,你离开西交那年,我刚进大学。看了你博客的很多文章,没有想到还是校友,呵呵
xjtuwjp 发表于 2010-03-05 12:05


哎,还挺怀念南门的那个老赵烤肉的,呵呵。
作者: ilttv.cn    时间: 2010-03-05 13:01
高手何其多,仰望一下,书出版了,一定买一本!
独孤九贱 发表于 2010-03-05 12:08



    多谢多谢!
作者: 0vk0    时间: 2010-03-05 14:52
瞻仰中……
作者: 望花煮    时间: 2010-03-05 15:15
高手高手呀,,,    瞻仰学习。
作者: cssjtuer    时间: 2010-03-05 18:46
顶校友阿
顺便膜拜一下
作者: lelee007    时间: 2010-03-08 17:35
书出来了一定买一本仔细拜读!
作者: ilttv.cn    时间: 2010-03-10 09:46
Kernel地图:Kconfig与Makefile

Makefile不是Make Love

从前在学校,混了四年,没有学到任何东西,每天就是逃课,上网,玩游戏,睡觉。毕业的时候,人家跟我说Makefile我完全不知,但是一说 Make Love我就来劲了,现在想来依然觉得丢人。

毫不夸张地说,Kconfig和Makefile是我们浏览内核代码时最为依仗的两个文件。基本上,Linux内核中每一个目录下边都会有一个 Kconfig文件和一个Makefile文件。 对于一个希望能够在Linux内核的汪洋代码里看到一丝曙光的人来说,将它们放在怎么重要的地位都不过分。

我们去香港,通过海关的时候,总会有免费的地图和各种指南拿,有了它们在手里我们才不至于无头苍蝇般迷惘的行走在陌生的街道上。即使在内地出去旅游的时候一般来说也总是会首先找份地图,当然了,这时就是要去买了,拿是拿不到的,不同的地方有不同的特色, 只不过有的特色是服务,有的特色是索取。

Kconfig和Makefile就是Linux Kernel迷宫里的地图。地图引导我们去认识一个城市,而Kconfig和Makefile则可以让我们了解一个Kernel目录下面的结构。我们每次浏览kernel寻找属于自己的那一段代码时,都应该首先看看目录下的这两个文件。

利用Kconfig和Makefile寻找目标代码

就像利用地图寻找目的地一样,我们需要利用Kconfig和Makefile来寻找所要研究的目标代码。

比如我们打算研究U盘驱动的实现,因为U盘是一种storage设备,所以我们应该先进入到drivers/usb/storage/目录。但是该目录下的文件很多,那么究竟哪些文件才是我们需要关注的?这时就有必要先去阅读Kconfig和Makefile文件。

对于Kconfig文件,我们可以看到下面的选项。

34 config USB_STORAGE_DATAFAB
35         bool "Datafab Compact Flash Reader support (EXPERIMENTAL)"
36        depends on USB_STORAGE && EXPERIMENTAL
37        help
38          Support for certain Datafab CompactFlash readers.
39          Datafab has a web page at <http://www.datafabusa.com/>.

显然,这个选项和我们的目的没有关系。首先它专门针对Datafab公司的产品,其次虽然CompactFlash reader是一种flash设备,但显然不是U盘。因为drivers/usb/storage目录下的代码是针对usb mass storage这一类设备,而不是针对某一种特定的设备。U盘只是usb mass storage设备中的一种。再比如:

101 config USB_STORAGE_SDDR55
102         bool "SanDisk SDDR-55 SmartMedia support (EXPERIMENTAL)"
103         depends on USB_STORAGE && EXPERIMENTAL
104         help
105             Say Y here to include additional code to support the Sandisk SDDR-55
106             SmartMedia reader in the USB Mass Storage driver.

很显然这个选项是有关SanDisk产品的,并且针对的是SM卡,同样不是U盘,所以我们也不需要去关注。

事实上,很容易确定,只有选项CONFIG_USB_STORAGE才是我们真正需要关注的。

9 config USB_STORAGE
10      tristate "USB Mass Storage support"
11       depends on USB && SCSI
12      ---help---
13        Say Y here if you want to connect USB mass storage devices to your
14        computer's USB port. This is the driver you need for USB
15        floppy drives, USB hard disks, USB tape drives, USB CD-ROMs,
16        USB flash devices, and memory sticks, along with
17        similar devices. This driver may also be used for some cameras
18        and card readers.
19
20        This option depends on 'SCSI' support being enabled, but you
21          probably also need 'SCSI device support: SCSI disk support'
22        (BLK_DEV_SD) for most USB storage devices.
23
24        To compile this driver as a module, choose M here: the
25        module will be called usb-storage.

接下来阅读Makefile文件。

0 #
1 # Makefile for the USB Mass Storage device drivers.
2 #
3 # 15 Aug 2000, Christoph Hellwig
4 # Rewritten to use lists instead of if-statements.
5 #
6
7 EXTRA_CFLAGS    := -Idrivers/scsi
8
9 obj-$(CONFIG_USB_STORAGE)    += usb-storage.o
10
11 usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG)    += debug.o
12 usb-storage-obj-$(CONFIG_USB_STORAGE_USBAT)    += shuttle_usbat.o
13 usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09)    += sddr09.o
14 usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR55)    += sddr55.o
15 usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM)    += freecom.o
16 usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM)    += dpcm.o
17 usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200)    += isd200.o
18 usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB)    += datafab.o
19 usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT)    += jumpshot.o
20 usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA)    += alauda.o
21 usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)    += onetouch.o
22 usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA)    += karma.o
23
24 usb-storage-objs :=    scsiglue.o protocol.o transport.o usb.o \
25              initializers.o $(usb-storage-obj-y)
26
27 ifneq ($(CONFIG_USB_LIBUSUAL),)
28      obj-$(CONFIG_USB)    += libusual.o
29 endif

前面通过Kconfig文件的分析,我们确定了只需要去关注CONFIG_USB_STORAGE选项。在Makefile文件里查找 CONFIG_USB_STORAGE,从第9行得知,该选项对应的模块为usb-storage。

因为Kconfig文件里的其他选项我们都不需要关注,所以Makefile的11~22行可以忽略。第24行意味着我们只需要关注 scsiglue.c、protocol.c、transport.c、usb.c、initializers.c以及它们同名的.h头文件。

Kconfig和Makefile很好的帮助我们定位到了所要关注的目标,就像我们到一个陌生的地方要随身携带地图,当我们学习Linux内核时,也要谨记寻求Kconfig和Makefile的帮助。
作者: zboom    时间: 2010-03-10 17:04
膜拜一下牛人……
作者: hwind17    时间: 2010-03-10 22:14
fudan_abc兄一定要支持下
作者: ConquerorLiu    时间: 2010-03-11 19:04
支持,大牛!
你终于来这里发帖了,呵呵
之前主要是在csdn混把

fudan_abc的Linux那些事儿系列,应该很多人都看过,现在新书《Linux内核修炼之道》要出来,博客blog.csdn.n ...
ilttv.cn 发表于 2010-03-01 22:51

作者: ilttv.cn    时间: 2010-03-12 17:53
支持,大牛!
你终于来这里发帖了,呵呵
之前主要是在csdn混把
ConquerorLiu 发表于 2010-03-11 19:04



    呵呵,很早就在这里混过的
作者: ilttv.cn    时间: 2010-03-15 11:01
分析内核源码如何入手?(上)

透过现象看本质,兽兽门无非就是一些人体艺术展示。同样往本质里看过去,学习内核,就是学习内核的源代码,任何内核有关的书籍都是基于内核,而又不高于内核的。

既然要学习内核源码,就要经常对内核代码进行分析,而内核代码千千万,还前仆后继的不断往里加,这就让大部分人都有种雾里看花花不见的无助感。不过不要怕,孔老夫子早就留给我们了应对之策:敏于事而慎于言,就有道而正焉,可谓好学也已。这就是说,做事要踏实才是好学生好同志,要遵循严谨的态度,去理解每一段代码的实现,多问多想多记。如果抱着走马观花,得过且过的态度,结果极有可能就是一边看一边丢,没有多大的收获。

假设全国房价上涨1.5%,假设80后局长是农民子弟,⋯⋯,既然我们的人生充满了假设,那么我在这里假设你现在就迫不及待的希望研究内核中USB子系统的实现,应该没有意见吧?那好,下面就以USB子系统的实现分析为标本看看分析内核源码应该如何入手。

分析README

内核中USB子系统的代码位于目录drivers/usb,这个结论并不需要假设。于是我们进入到该目录,执行命令ls,结果显示如下:

atm  class  core  gadget  host  image  misc  mon  serial  storage Kconfig
Makefile  README usb-skeleton.c

目录drivers/usb共包含有10个子目录和4个文件,usb-skeleton.c是一个简单的USB driver的框架,感兴趣的可以去看看,目前来说,它还吸引不了我们的眼球。那么首先应该关注什么?如果迎面走来一个ppmm,你会首先看脸、脚还是其它?当然答案依据每个人的癖好会有所不同。不过这里的问题应该只有一个答案,那就是Kconfig、Makefile、README。

README里有关于这个目录下内容的一般性描述,它不是关键,只是帮助你了解。再说了,面对“read我吧read我吧”这么热情奔放的呼唤,善良的我们是不可能无动于衷的,所以先来看看里面都有些什么内容。

23 Here is a list of what each subdirectory here is, and what is contained in
24 them.
25
26 core/        - This is for the core USB host code, including the
27             usbfs files and the hub class driver ("khubd".
28
29 host/        - This is for USB host controller drivers.  This
30             includes UHCI, OHCI, EHCI, and others that might
31             be used with more specialized "embedded" systems.
32
33 gadget/        - This is for USB peripheral controller drivers and
34             the various gadget drivers which talk to them.
35
36
37 Individual USB driver directories.  A new driver should be added to the
38 first subdirectory in the list below that it fits into.
39
40 image/        - This is for still image drivers, like scanners or
41             digital cameras.
42 input/        - This is for any driver that uses the input subsystem,
43             like keyboard, mice, touchscreens, tablets, etc.
44 media/        - This is for multimedia drivers, like video cameras,
45             radios, and any other drivers that talk to the v4l
46             subsystem.
47 net/        - This is for network drivers.
48 serial/        - This is for USB to serial drivers.
49 storage/    - This is for USB mass-storage drivers.
50 class/        - This is for all USB device drivers that do not fit
51             into any of the above categories, and work for a range
52             of USB Class specified devices.
53 misc/        - This is for all USB device drivers that do not fit
54             into any of the above categories.

这个README文件描述了前边使用ls命令列出的那10个文件夹的用途。那么什么是USB Core?Linux内核开发者们,专门写了一些代码,负责实现一些核心的功能,为别的设备驱动程序提供服务,比如申请内存,比如实现一些所有的设备都会需要的公共的函数,并美其名曰USB Core。

时代总在发展,当年胖杨贵妃照样迷死唐明皇,而如今人们欣赏的则是林志玲这样的魔鬼身材。同样,早期的Linux内核,其结构并不是如今天这般有层次感,远不像今天这般错落有致,那时候drivers/usb/这个目录下边放了很多很多文件,USB Core与其他各种设备的驱动程序的代码都堆砌在这里,后来,怎奈世间万千的变幻,总爱把有情的人分两端。于是在drivers/usb/目录下面出来了一个core目录,就专门放一些核心的代码,比如初始化整个USB系统,初始化Root Hub,初始化主机控制器的代码,再后来甚至把主机控制器相关的代码也单独建了一个目录,叫host目录,这是因为USB主机控制器随着时代的发展,也开始有了好几种,不再像刚开始那样只有一种,所以呢,设计者们把一些主机控制器公共的代码仍然留在core目录下,而一些各主机控制器单独的代码则移到 host目录下面让负责各种主机控制器的人去维护。

那么USB gadget那?gadget白了说就是配件的意思,主要就是一些内部运行Linux的嵌入式设备,比如PDA,设备本身有USB设备控制器(USB Device Controller),可以将PC,也就是我们的主机作为master端,将这样的设备作为slave端和主机通过USB进行通信。从主机的观点来看,主机系统的USB驱动程序控制插入其中的USB设备,而USB gadget的驱动程序控制外围设备如何作为一个USB设备和主机通信。比如,我们的嵌入式板子上支持SD卡,如果我们希望在将板子通过USB连接到PC 之后,这个SD卡被模拟成U盘,那么就要通过USB gadget架构的驱动。

剩下的几个目录分门别类的放了各种USB设备的驱动,比如U盘的驱动在storage目录下,触摸屏和USB键盘鼠标的驱动在input目录下,等等。

我们响应了README的热情呼唤,它便给予了我们想要的,通过它我们了解了USB目录里的那些文件夹都有着什么样的角色。到现在为止,就只剩下内核的地图——Kconfig与Makefile两个文件了。有地图在手,对于在内核中游荡的我们来说,是件很愉悦的事情,不过,因为我们的目的是研究内核对USB子系统的实现,而不是特定设备或host controller的驱动,所以这里的定位很明显,USB Core就是我们需要关注的对象,那么接下来就是要对core目录中的内容进行定位了。

分析Kconfig和Makefile

进入到drivers/usb/core目录,执行命令ls,结果显示如下:

Kconfig  Makefile  buffer.c  config.c  devices.c  devio.c  driver.c
endpoint.c  file.c  generic.c  hcd-pci.c  hcd.c  hcd.h  hub.c  hub.h
inode.c  message.c  notify.c  otg_whitelist.h  quirks.c  sysfs.c  urb.c
usb.c  usb.h

然后执行wc命令,如下所示。

# wc –l ./*
   148 buffer.c
   607 config.c
   706 devices.c
  1677 devio.c
  1569 driver.c
   357 endpoint.c
   248 file.c
   238 generic.c
  1759 hcd.c
   458 hcd.h
   433 hcd-pci.c
  3046 hub.c
   195 hub.h
   758 inode.c
   144 Kconfig
    21 Makefile
  1732 message.c
    68 notify.c
   112 otg_whitelist.h
   161 quirks.c
   710 sysfs.c
   589 urb.c
   984 usb.c
   160 usb.h
16880 total

drivers/usb/core目录共包括24个文件,16880行代码。core不愧是core,为大家默默的做这么多事。不过这么多文件里不一定都是我们所需要关注的,先拿咱们的地图来看看接下来该怎么走。先看看Kconfig文件,可以看到下面的选项。

15 config USB_DEVICEFS
16         bool "USB device filesystem"
17         depends on USB
18         ---help---
19           If you say Y here (and to "/proc file system support" in the "File
20           systems" section, above), you will get a file /proc/bus/usb/devices
21           which lists the devices currently connected to your USB bus or
22           busses, and for every connected device a file named
23           "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the
24           device number; the latter files can be used by user space programs
25           to talk directly to the device. These files are "virtual", meaning
26           they are generated on the fly and not stored on the hard drive.
27
28           You may need to mount the usbfs file system to see the files, use
29           mount -t usbfs none /proc/bus/usb
30
31           For the format of the various /proc/bus/usb/ files, please read
32           <fileocumentation/usb/proc_usb_info.txt>.
33
34           Usbfs files can't handle Access Control Lists (ACL), which are the
35           default way to grant access to USB devices for untrusted users of a
36           desktop system. The usbfs functionality is replaced by real
37           device-nodes managed by udev. These nodes live in /dev/bus/usb and
38           are used by libusb.

选项USB_DEVICEFS与usbfs文件系统有关。usbfs文件系统挂载在/proc/bus/usb目录,显示了当前连接的所有USB设备及总线的各种信息,每个连接的USB设备在其中都会有一个对应的文件进行描述。比如文件/proc/bus/usb/xxx/yyy,xxx表示总线的序号,yyy表示设备所在总线的地址。不过不能够依赖它们来稳定地访问设备,因为同一设备两次连接对应的描述文件可能会不同,比如,第一次连接一个设备时,它可能是002/027,一段时间后再次连接,它可能就已经改变为002/048。

就好比好不容易你暗恋的mm今天见你的时候对你抛了个媚眼,你心花怒放,赶快去买了100块彩票庆祝,到第二天再见到她的时候,她对你说你是谁啊,你悲痛欲绝的刮开那100块彩票,上面清一色的谢谢你。

因为usbfs文件系统并不属于USB子系统实现的核心部分,与之相关的代码我们可以不必关注。

74 config USB_SUSPEND
75       bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)"
76       depends on USB && PM && EXPERIMENTAL
77       help
78         If you say Y here, you can use driver calls or the sysfs
79         "power/state" file to suspend or resume individual USB
80         peripherals.
81
82         Also, USB "remote wakeup" signaling is supported, whereby some
83         USB devices (like keyboards and network adapters) can wake up
84         their parent hub.  That wakeup cascades up the USB tree, and
85         could wake the system from states like suspend-to-RAM.
86
87         If you are unsure about this, say N here.

这一项是有关USB设备的挂起和恢复。开发USB的人都是节电节能的好孩子,所以协议里就规定了,所有的设备都必须支持挂起状态,就是说为了达到节电的目的,当设备在指定的时间内,如果没有发生总线传输,就要进入挂起状态。当它收到一个non-idle的信号时,就会被唤醒。节约用电从USB做起。不过这个与主题也没太大关系,相关代码也可以不用关注了。

剩下的还有几项,不过似乎与咱们关系也不大,还是去看看Makefile。

5 usbcore-objs    := usb.o hub.o hcd.o urb.o message.o driver.o \
6                         config.o file.o buffer.o sysfs.o endpoint.o \
7                         devio.o notify.o generic.o quirks.o
8
9 ifeq ($(CONFIG_PCI),y)
10         usbcore-objs    += hcd-pci.o
11 endif
12
13 ifeq ($(CONFIG_USB_DEVICEFS),y)
14         usbcore-objs    += inode.o devices.o
15 endif
16
17 obj-$(CONFIG_USB)       += usbcore.o
18
19 ifeq ($(CONFIG_USB_DEBUG),y)
20 EXTRA_CFLAGS += -DDEBUG
21 endif

Makefile可比Kconfig简略多了,所以看起来也更亲切点,咱们总是拿的money越多越好,看的代码越少越好。这里之所以会出现 CONFIG_PCI,是因为通常USB的Root Hub包含在一个PCI设备中。hcd-pci和hcd顾名而思义就知道是说主机控制器的,它们实现了主机控制器公共部分,按协议里的说法它们就是 HCDI(HCD的公共接口),host目录下则实现了各种不同的主机控制器。

CONFIG_USB_DEVICEFS前面的Kconfig文件里也见到了,关于usbfs的,与咱们的主题无关,inode.c和devices.c两个文件也可以不用管了。

那么我们可以得出结论,为了理解内核对USB子系统的实现,我们需要研究buffer.c、config.c、driver.c、 endpoint.c、file.c、generic.c、hcd.c  hcd.h、hub.c、message.c、notify.c、otg_whitelist.h、quirks.c、sysfs.c、urb.c 和usb.c文件。这么看来,好像大都需要关注的样子,没有减轻多少压力,不过这里本身就是USB Core部分,是要做很多的事为咱们分忧的,所以多点也是可以理解的。
作者: ilttv.cn    时间: 2010-03-17 12:55
分析内核源码如何入手?(下)

下面的分析,米卢教练说了,内容不重要,重要的是态度。就像韩局长对待日记的态度那样,严谨而细致。

只要你使用这样的态度开始分析内核,那么无论你选择内核的哪个部分作为切入点,比如USB,比如进程管理,在花费相对不算很多的时间之后,你就会发现你对内核的理解会上升到另外一个高度,一个抱着情景分析,抱着0.1内核完全注释,抱着各种各样的内核书籍翻来覆去的看很多遍又忘很多遍都无法达到的高度。请相信我!

让我们在Linux社区里发出号召:学习内核源码,从学习韩局长开始!

态度决定一切:从初始化函数开始
任小强们说房价高涨从现在开始,股评家们说牛市从5000点开始。他们的开始需要我们的钱袋,我们的开始只需要一台电脑,最好再有一杯茶,伴着几支小曲儿,不盯着钱总是会比较惬意的。生容易,活容易,生活不容易,因为总要盯着钱。

有了地图Kconfig和Makefile,我们可以在庞大复杂的内核代码中定位以及缩小了目标代码的范围。那么现在,为了研究内核对USB子系统的实现,我们还需要在目标代码中找到一个突破口,这个突破口就是USB子系统的初始化代码。

针对某个子系统或某个驱动,内核使用subsys_initcall或module_init宏指定初始化函数。在drivers/usb /core/usb.c文件中,我们可以发现下面的代码。

940 subsys_initcall(usb_init);
941 module_exit(usb_exit);

我们看到一个subsys_initcall,它也是一个宏,我们可以把它理解为module_init,只不过因为这部分代码比较核心,开发者们把它看作一个子系统,而不仅仅是一个模块。这也很好理解,usbcore这个模块它代表的不是某一个设备,而是所有USB设备赖以生存的模块,Linux 中,像这样一个类别的设备驱动被归结为一个子系统。比如PCI子系统,比如SCSI子系统,基本上,drivers/目录下面第一层的每个目录都算一个子系统,因为它们代表了一类设备。

subsys_initcall(usb_init)的意思就是告诉我们usb_init是USB子系统真正的初始化函数,而usb_exit() 将是整个USB子系统的结束时的清理函数。于是为了研究USB子系统在内核中的实现,我们需要从usb_init函数开始看起。

865 static int __init usb_init(void)
866 {
867   int retval;
868   if (nousb) {
869    pr_info("%s: USB support disabled\n", usbcore_name);
870    return 0;
871   }
872
873   retval = ksuspend_usb_init();
874   if (retval)
875    goto out;
876   retval = bus_register(&usb_bus_type);
877   if (retval)
878    goto bus_register_failed;
879   retval = usb_host_init();
880   if (retval)
881    goto host_init_failed;
882   retval = usb_major_init();
883   if (retval)
884    goto major_init_failed;
885   retval = usb_register(&usbfs_driver);
886   if (retval)
887    goto driver_register_failed;
888   retval = usb_devio_init();
889   if (retval)
890    goto usb_devio_init_failed;
891   retval = usbfs_init();
892   if (retval)
893    goto fs_init_failed;
894   retval = usb_hub_init();
895   if (retval)
896    goto hub_init_failed;
897   retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
898   if (!retval)
899    goto out;
900
901   usb_hub_cleanup();
902  hub_init_failed:
903   usbfs_cleanup();
904 fs_init_failed:
905   usb_devio_cleanup();
906 usb_devio_init_failed:
907   usb_deregister(&usbfs_driver);
908 driver_register_failed:
909   usb_major_cleanup();
910 major_init_failed:
911   usb_host_cleanup();
912 host_init_failed:
913   bus_unregister(&usb_bus_type);
914 bus_register_failed:
915   ksuspend_usb_cleanup();
916 out:
917   return retval;
918 }

(1)__init标记。

关于usb_init,第一个问题是,第865行的__init标记具有什么意义?

写过驱动的应该不会陌生,它对内核来说就是一种暗示,表明这个函数仅在初始化期间使用,在模块被装载之后,它占用的资源就会释放掉用作它处。它的暗示你懂,可你的暗示,她却不懂或者懂装不懂,多么让人感伤。它在自己短暂的一生中一直从事繁重的工作,吃的是草吐出的是牛奶,留下的是整个USB子系统的繁荣。

受这种精神所感染,我觉得有必要为它说的更多些。__init的定义在include/linux/init.h文件里

43 #define __init          __attribute__ ((__section__ (".init.text")))

好像这里引出了更多的疑问,__attribute__是什么?Linux内核代码使用了大量的GNU C扩展,以至于GNU C成为能够编译内核的唯一编译器,GNU C的这些扩展对代码优化、目标代码布局、安全检查等方面也提供了很强的支持。而__attribute__就是这些扩展中的一个,它主要被用来声明一些特殊的属性,这些属性主要被用来指示编译器进行特定方面的优化和更仔细的代码检查。GNU C支持十几个属性,section是其中的一个,我们查看GCC的手册可以看到下面的描述

‘section ("section-name")'
   Normally, the compiler places the code it generates in the `text'
section. Sometimes, however, you need additional sections, or you
need certain particular functions to appear in special sections.
   The `section' attribute specifies that a function lives in a
   particular section. For example, the declaration:

     extern void foobar (void) __attribute__ ((section ("bar")));

   puts the function ‘foobar' in the ‘bar' section.

   Some file formats do not support arbitrary sections so the
   ‘section' attribute is not available on all platforms. If you
   need to map the entire contents of a module to a particular
   section, consider using the facilities of the linker instead.

通常编译器将函数放在.text节,变量放在.data或.bss节,使用section属性,可以让编译器将函数或变量放在指定的节中。那么前面对__init的定义便表示将它修饰的代码放在.init.text节。连接器可以把相同节的代码或数据安排在一起,比如__init修饰的所有代码都会被放在.init.text节里,初始化结束后就可以释放这部分内存。

问题可以到此为止,也可以更深入,即内核又是如何调用到这些__init修饰的初始化函数?要回答这个问题,还需要回顾一下 subsys_initcall宏,它也在include/linux/init.h里定义

125 #define subsys_initcall(fn)             __define_initcall("4",fn,4)

这里又出现了一个宏__define_initcall,它用于将指定的函数指针fn放到initcall.init节里 而对于具体的subsys_initcall宏,则是把fn放到.initcall.init的子节.initcall4.init里。要弄清楚.initcall.init、.init.text和.initcall4.init这样的东东,我们还需要了解一点内核可执行文件相关的概念。

内核可执行文件由许多链接在一起的对象文件组成。对象文件有许多节,如文本、数据、init数据、bass等等。这些对象文件都是由一个称为链接器脚本的文件链接并装入的。这个链接器脚本的功能是将输入对象文件的各节映射到输出文件中;换句话说,它将所有输入对象文件都链接到单一的可执行文件中,将该可执行文件的各节装入到指定地址处。 vmlinux.lds是存在于arch/<target>/ 目录中的内核链接器脚本,它负责链接内核的各个节并将它们装入内存中特定偏移量处。

我可以负责任的告诉你,要看懂vmlinux.lds这个文件是需要一番功夫的,不过大家都是聪明人,聪明人做聪明事,所以你需要做的只是搜索 initcall.init,然后便会看到似曾相识的内容

__inicall_start = .;
.initcall.init : AT(ADDR(.initcall.init) – 0xC0000000) {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;

这里的__initcall_start指向.initcall.init节的开始,__initcall_end指向它的结尾。而.initcall.init节又被分为了7个子节,分别是

.initcall1.init
.initcall2.init
.initcall3.init
.initcall4.init
.initcall5.init
.initcall6.init
.initcall7.init

我们的subsys_initcall宏便是将指定的函数指针放在了.initcall4.init子节。其它的比如core_initcall将函数指针放在.initcall1.init子节,device_initcall将函数指针放在了.initcall6.init子节等等,都可以从 include/linux/init.h文件找到它们的定义。各个字节的顺序是确定的,即先调用.initcall1.init中的函数指针再调用.initcall2.init中的函数指针,等等。__init修饰的初始化函数在内核初始化过程中调用的顺序和.initcall.init节里函数指针的顺序有关,不同的初始化函数被放在不同的子节中,因此也就决定了它们的调用顺序。

至于实际执行函数调用的地方,就在/init/main.c文件里,内核的初始化么,不在那里还能在哪里,里面的do_initcalls函数会直接用到这里的__initcall_start、__initcall_end来进行判断。

(2)模块参数。

关于usb_init函数,第二个问题是,第868行的nousb表示什么?

知道C语言的人都会知道nousb是一个标志,只是不同的标志有不一样的精彩,这里的nousb是用来让我们在启动内核的时候通过内核参数去掉 USB子系统的,Linux社会是一个很人性化的世界,它不会去逼迫我们接受USB,一切都只关乎我们自己的需要。不过我想我们一般来说是不会去指定 nousb的吧。如果你真的指定了nousb,那它就只会幽怨的说一句“USB support disabled”,然后退出usb_init。

nousb在drivers/usb/core/usb.c文件中定义为:

static int nousb; /* Disable USB when built into kernel image */
module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
MODULE_PARM_DESC(autosuspend, "default autosuspend delay");

从中可知nousb是个模块参数。关于模块参数,我们都知道可以在加载模块的时候可以指定,但是如何在内核启动的时候指定?
打开系统的grub文件,然后找到kernel行,比如:

kernel  /boot/vmlinuz-2.6.18-kdb root=/dev/sda1 ro splash=silent vga=0x314

其中的root,splash,vga等都表示内核参数。当某一模块被编译进内核的时候,它的模块参数便需要在kernel行来指定,格式为“模块名.参数=值”,比如:

modprobe usbcore autosuspend=2

对应到kernel行,即为 :

usbcore.autosuspend=2

通过命令“modinfo -p ${modulename}”可以得知一个模块有哪些参数可以使用。同时,对于已经加载到内核里的模块,它们的模块参数会列举在/sys/module /${modulename}/parameters/目录下面,可以使用“echo -n ${value} > /sys/module/${modulename}/parameters/${parm}”这样的命令去修改。

(3)可变参数宏。

关于usb_init函数,第三个问题是,pr_info如何实现与使用?

pr_info只是一个打印信息的可辨参数宏,printk的变体,在include/linux/kernel.h里定义:

242 #define pr_info(fmt,arg...) \
243         printk(KERN_INFO fmt,##arg)

99年的ISO C标准里规定了可变参数宏,和函数语法类似,比如

#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)

里面的“…”就表示可变参数,调用时,它们就会替代宏体里的__VA_ARGS__。GCC总是会显得特立独行一些,它支持更复杂的形式,可以给可变参数取个名字,比如

#define debug(format, args...) fprintf (stderr, format, args)

有了名字总是会容易交流一些。是不是与pr_info比较接近了?除了‘##’,它主要是针对空参数的情况。既然说是可变参数,那传递空参数也总是可以的,空即是多,多即是空,股市里的哲理这里同样也是适合的。如果没有‘##’,传递空参数的时候,比如

debug ("A message");

展开后,里面的字符串后面会多个多余的逗号。这个逗号你应该不会喜欢,而‘##’则会使预处理器去掉这个多余的逗号。

关于usb_init函数,上面的三个问题之外,余下的代码分别完成usb各部分的初始化,接下来就需要围绕它们分别进行深入分析。因为这里只是演示如何入手分析,展示的只是一种态度,所以具体的深入分析就免了吧。
作者: new_learner    时间: 2010-05-12 19:18
No news?
作者: ilttv.cn    时间: 2010-07-30 11:10
内核学习的心理问题

对于学习来说,无论是在学校的课堂学习,还是这里说的内核学习,效果好或者坏,最主要取决于两个方面——方法论和心理。注意,我无视了智商的差异,这玩意儿玄之又玄,岔开了说,属于迷信的范畴。

前面又是Kernel地图,又是如何入手,说的都是方法论的问题,那么这里要面对的就主要是心理上的问题。

而心理上的问题主要有两个,一个是盲目,就是在能够熟练适用Linux之前,对Linux为何物还说不出个道道来,就迫不及待的盲目的去研究内核的源代码。这一部分人会觉得既然是学习内核,那么耗费时间在熟悉Linux的基本操作上纯粹是浪费宝贵的时间和感情。不过这样虽然很有韩峰同志的热情和干劲儿,但明显走入了一种心理误区。重述Linus的那句话:要先会使用它。

第二个就是恐惧。人类进化这么多年,面对复杂的物体和事情还是总会有天生的惧怕感,体现在内核学习上面就是:那么庞大复杂的内核代码,让人面对起来该情何以堪啊!

有了这种恐惧无力感存在,心理上就会去排斥面对接触内核源码,宁愿去抱着情景分析,搜集各种各样五花八门的内核书籍放在那里屯着,看了又忘,忘了又看,也不大情愿去认真细致得浏览源码。

这个时候,我们在心理上是脆弱得,我们忘记了芙蓉姐姐,工行女之所以红起来,不是她们有多好,而是因为她们得心理足够坚强。是的,除了向韩局长学习态度,我们还要向涌现出来的无数个芙蓉姐姐和工行女学习坚强的心理。

有必要再强调一次,学习内核,就是学习内核的源代码,任何内核有关的书籍都是基于内核,而又不高于内核的。内核源码本身就是最好的参考资料,其他任何经典或非经典的书最多只是起到个辅助作用,不能也不应该取代内核代码在我们学习过程中的主导地位。
作者: 0vk0    时间: 2010-07-30 17:37
谢谢了,要是有电子版就好了
作者: zd零    时间: 2010-07-30 19:40
太狠了!佩服!佩服!
作者: ilttv.cn    时间: 2010-08-02 09:52
电子版的貌似精华区里n年前就已经有了,呵呵,只不过书上的内容更新


回复 42# 0vk0




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2