Linux内核源码分析方法

Linux内核源码分析方法
Linux内核源码分析方法

Linux内核源码分析方法

一、内核源码之我见

Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次。如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径。我们都知道,想成为优秀的程序员,需要大量的实践和代码的编写。编程固然重要,但是往往只编程的人很容易把自己局限在自己的知识领域内。如果要扩展自己知识的广度,我们需要多接触其他人编写的代码,尤其是水平比我们更高的人编写的代码。通过这种途径,我们可以跳出自己知识圈的束缚,进入他人的知识圈,了解更多甚至我们一般短期内无法了解到的信息。Linux内核由无数开源社区的“大神们”精心维护,这些人都可以称得上一顶一的代码高手。透过阅读Linux 内核代码的方式,我们学习到的不光是内核相关的知识,在我看来更具价值的是学习和体会它们的编程技巧以及对计算机的理解。

我也是通过一个项目接触了Linux内核源码的分析,从源码的分析工作中,我受益颇多。除了获取相关的内核知识外,也改变了我对内核代码的过往认知:

1.内核源码的分析并非“高不可攀”。内核源码分析的难度不在于源码本身,而在于如何使用更合适的分析代码的方式和手段。内核的庞大致使我们不能按照分析一般的demo程序那样从主函数开始按部就班的分析,我们需要一种从中间介入的手段对内核源码“各个击破”。这种“按需索取”的方式使得我们可以把握源码的主线,而非过度纠结于具体的细节。

2.内核的设计是优美的。内核的地位的特殊性决定着内核的执行效率必须足够高才可以响应目前计算机应用的实时性要求,为此Linux内核使用C语言和汇编的混合编程。但是我们都

知道软件执行效率和软件的可维护性很多情况下是背道而驰的。如何在保证内核高效的前提下提高内核的可维护性,这需要依赖于内核中那些“优美”的设计。

3.神奇的编程技巧。在一般的应用软件设计领域,编码的地位可能不被过度的重视,因为开发者更注重软件的良好设计,而编码仅仅是实现手段问题——就像拿斧子劈柴一样,不用太多的思考。但是这在内核中并不成立,好的编码设计带来的不光是可维护性的提高,甚至是代码性能的提升。

每个人对内核的了理解都会有所不同,随着我们对内核理解的不断加深,对其设计和实现的思想会有更多的思考和体会。因此本文更期望于引导更多徘徊在Linux内核大门之外的人进入Linux的世界,去亲自体会内核的神奇与伟大。而我也并非内核源码方面的专家,这么做也只是希望分享我自己的分析源码的经验和心得,为那些需要的人提供参考和帮助,说的“冠冕堂皇”一点,也算是为计算机这个行业,尤其是在操作系统内核方面贡献自己的一份绵薄之力。闲话少叙(已经罗嗦了很多了,囧~),下面我就来分享一下自己的Linix内核源码分析方法。

二、内核源码难不难?

从本质上讲,分析Linux内核代码和看别人的代码没有什么两样,因为摆在你面前的一般都不是你自己写出来的代码。我们先举一个简单的例子,一个陌生人随便给你一个程序,并要你看完源码后讲解一下程序的功能的设计,我想很多自我感觉编程能力还可以的人肯定觉得这没什么,只要我耐心的把他的代码从头到尾看完,肯定能找到答案,并且事实确实是如此。那么现在换一个假设,如果这个人是Linus,给你的就是Linux内核的一个模块的代码,你还会觉得依然那么

轻松吗?不少人可能会有所犹豫。同样是陌生人(Linus要是认识你的话当然不算,呵呵~)给

你的代码,为什么给我们的感觉大相径庭呢?我觉得有以下原因:

1.Linux内核代码在“外界”看来多少有些神秘感,而且它很庞大,猛地摆在面前可能感

觉无法下手。比如可能来源于一个很细小的原因——找不到main函数。对于简单的demo程序,我们可以从头至尾的分析代码的含义,但是分析内核代码这招就彻底失效了,因为没有人能把Linux代码从头到尾看上一遍(因为确实没有必要,用到时看就可以了)。

2.不少人也接触过大型软件的代码,但多数属于应用型项目,代码的形式和含义都和自己常接触的业务逻辑相关。而内核代码不同,它处理的信息多数和计算机底层密切相关。比如操作系统、编译器、汇编、体系结构等相关的知识的欠缺,也会让阅读内核代码障碍重重。

3.分析内核代码的方法不够合理。面对大量的并且复杂的内核代码,如果不从全局的角度入手,很容易陷入代码细节的泥淖中。内核代码虽然庞大,但是它也有它的设计原则和架构,否则维护它对任何人来说都是一个噩梦!如果我们理清代码模块的整体设计思路,再去分析代码的实现,可能分析源码就是一件轻松快乐的事情了。

针对这些问题,我个人是这样理解的。如果没有接触过大型软件项目,可能分析Linux内核代码是一个很好的积累大型项目经验的机会(确实,Linux代码是我目前接触到的最大的项目了!)。如果你对计算机底层了解的不够透彻,那么我们可以选择边分析边学习的方式去积累底层的知识。可能刚开始分析代码的进度会稍显迟缓,但是随着知识的不断积累,我们对Linux内核的“业务逻辑”会逐渐明朗起来。最后一点,如何从全局的角度把握分析的源码,这也是我想与大家分享的经验。

三、内核源码分析方法

第一步:资料搜集

从人认识新事物的角度来讲,在探索事物本质之前,必须有一个了解新鲜事物的过程,这个过程是的我们对新鲜事物产生一个初步的概念。比如我们想学习钢琴,那么我们需要先了解弹奏钢琴需要我们学习基本的乐理、简谱、五线谱等基础知识,然后学习钢琴弹奏的技巧和指法,最后才能真正的开始练习钢琴。

分析内核代码也是如此,首先我们需要定位要分析的代码涉及的内容。是进程同步和调度的代码,是内存管理的代码,还是设备管理的代码,还是系统启动的代码等等。内核的庞大决定着我们不能一次性将内核代码全部分析完成,因此我们需要给自己一个合理的分工。正如算法设计告诉我们的,要解决一个大问题,首先要解决它所涉及的子问题。

定位好要分析的代码范围,我们就可以动用手头的一切资源,尽可能的全面了解该部分代码的整体结构和大致功能。

这里所说的一切资源是指无论是Baidu、Google大型网络搜索引擎,还是操作系统原理教材和专业书籍,亦或是他人提供的经验和资料,甚至是Linux源码提供的文档、注释和源码标识符的名称(不要小看代码中的标识符的命名,有时它们能提供关键的信息)。总之这里的一切资源指的就是你能想到的一切可用资源。当然,我们不太可能通过这种形式的信息搜集获得所有的我们想要的信息,我们只求尽可能全面即可。因为信息搜集的越全面,之后分析代码的过程能使用的信息就更多,分析过程的困难就会越小。

这里举一个简单的例子,假定我们要分析Linux的变频机制实现的代码。目前为止我们仅仅是知道这个名次而已,透过字面含义我们可以大致猜测它应该和CPU的频率调节相关。通过信息搜集,我们应该能得到如下的相关的信息:

1.CPUFreq机制。

2.performance、powersave、userspace、ondemand、conservative调频策略。

3./driver/cpufreq/。

4./documention/cpufreq。

5.P state和C state。

……

分析Linux内核代码如果能搜集到这些信息,应该说是非常“幸运”了。毕竟有关Linux内核的资料确实不如.NET和JQuery那么丰富,不过这相比于十数年前,没有强大的搜索引擎,没有相关的研究资料的时期应该称得上是“大丰收”时代了!我们通过简单的“搜索”(可能会花费一到两天的时间吧),甚至找到了这部分代码所在的源码文件目录,不得不说这样的信息简直是“价值连城”!

第二步:源码定位

从资料搜集中,我们“有幸”找到了源码相关的源码目录。但是这并非意味着我们的确就是分析这个目录下的源代码。有时我们找到的目录有可能是分散的,也有时我们找到的目录下有很多和具体机器相关的代码,而我们更关心的是待分析代码的主要机制,而非与机器相关的特化代码(这样更有助于我们理解内核的本质)。因此,我们需要对资料中涉及代码文件的资料进行仔细甄选。当然,这一步也不太可能一次性完成,谁也不能保证一次就能选择出所有待分析的源码文件而且一个不漏。但是我们也不必担心,只要我们能抓住大多数模块相关的核心源文件,通过后期对代码的具体分析,就很自然的把它们全部找出来。

回到上述的例子中,我们认真的阅读/documention/cpufreq下的文档说明。目前的Linux源码会把模块相关的文档说明保存在源码目录的documention的文件夹下,如果待分析的模块没有文档说明,这多少会增加定位关键源码文件的难度,但是不会导致我们找不到我们要分析的源码。通过阅读文档说明,我们至少能关注到/driver/cpufreq/cpufreq.c这个源文件。通过这个对源文件的文档说明,结合之前搜罗到的调频策略,我们很容易关注到cpufreq_performance.c、

cpufreq_powersave.c、cpufreq_userspace.c、cpufreq_ondemand、cpufreq_conservative.c这五个源文件。所有涉及的文件都找完了吗?不用担心,从它们开始分析,迟早能找到其他的源文件。如果在windows下使用sourceinsight阅读内核源码的话,我们通过函数的调用和查找符号引用等功能,结合代码的分析可以很方便的找到另外的文件freq_table.c、cpufreq_stats.c和

/include/linux/cpufreq.h。

按照搜索出的信息流动方向,我们完全可以定位到需要分析的源码文件。源码定位这一步并非十分关键,因为我们不需要找出所有源码文件,我们可以把部分工作推迟到分析代码的过程中。源码定位也比较关键,找到一部分源码文件是分析源码的基础。

第三步:简单注释

在已定位好的源码文件中,分析每个变量、宏、函数、结构体等代码元素的大致含义和功能。之所以称此为简单注释,并非指这部分的注释工作很简单,而是指这部分的注释可以不必过分细化,只要大致描述出相关代码元素的含义即可。相反,这里的工作其实是整个分析流程中最困难的一步。因为这是第一次深入到内核代码的内部,尤其是对于首次分析内核源码的人来说,大量的生疏GNU的C语法和铺天盖地的宏定义会令人很绝望。此时只要沉下心来,弄清每个关键的难点,才能保证以后碰到类似的难点不会再被困住。而且,我们对内核相关的其他知识会不断的像树一样扩展开来。

比如在cpufreq.c文件开始就会出现“DEFINE_PER_CPU”宏的使用,我们通过查阅资料可以基本弄清这个宏的含义和功能。这里使用的手段和之前搜集资料使用的方法基本一致,另外我们也可以使用sourceinsight提供的转到定义等功能查看它的定义,或者使用LKML(Linux Kernel Mail List)查阅,实在不行我们还可以到https://www.360docs.net/doc/6417023012.html,提问寻求解答(想了解什么是LKML和stackoverflow?搜集资料吧!)。总之利用所有可能的手段,我们总能得到这个宏的含义——为每个CPU定义一个独立使用的变量。

我们也不要强求一次就能把注释描述的很准确(我们甚至都没必要弄清每个函数的具体实现流程,只要弄清大致功能含义即可),我们结合搜集到的资料和后边代码的分析不断的完善注释的含义(源码中原有的注释和标识符命名在此很有利用价值)。通过不断的注释,不断的查阅资料,不断的修改注释的含义。

当我们把所有涉及的源码文件简单注释完毕后我们可以达到如下效果:

1.基本弄清了源码中代码元素存在的含义。

2.找出了该模块所涉及的基本上全部的关键源码文件。

结合之前搜集到的信息和资料对该待分析代码的整体或者架构描述,我们可以将分析的结果和资料对比,以确定和修正我们对代码的理解。这样,通过一遍的简单注释,我们就可以从整体上把握了源码模块的主要结构。这也达到了我们简单注释的基本目的。

第四步:详细注释

完成代码的简单注释后,可以认为对模块的分析工作完成了一半了,剩下的内容就是对代码的深入分析和彻底理解。简单注释总是不能将代码元素的具体含义描述的十分精确,因此详细注释是十分有必要的。这一步中,我们需要弄清以下内容:

1.变量定义在何时被使用。

2.宏定义的代码何时被使用。

3.函数的参数和返回值的含义。

4.函数的执行流程和调用关系。

5.结构体字段的具体含义和使用条件。

我们甚至可以把这一步称为函数详细注释,因为函数之外的代码元素的含义基本上在简单注释中已经比较明确了。而函数本身的执行流程、算法等是这部分注释和分析的主要任务。

比如cpufreq_ondemand策略的实现算法(函数dbs_check_cpu中)是如何实现的。我们需要逐步分析该函数使用的变量和调用的函数等信息,弄清算法的来龙去脉。最好的结果,我们需要这些复杂函数的执行流程图和函数调用关系图,这是最直观的表达方式。

通过这一步的注释,我们基本上能完全把握待分析代码整体的实现机制了。而所有的分析工作可以认为完成了80%。这一步工作尤其关键,我们必须尽量让注释的信息足够的准确,才能更好的理解待分析代码的内部模块的划分。虽然Linux内核中使用了宏语法“module_init”和“module_exit”声明模块文件,但是对模块内部子功能的划分是建立在充分了解模块的功能基础上的。只有正确划分好模块,我们才能弄清模块提供了哪些外部函数和变量(使用

EXPORT_SYMBOL_GPL或者EXPORT_SYMBOL导出的符号)。才能继续下一步的模块内标识符依赖关系分析。

第五步:模块内部标识符依赖关系

通过第四步对代码模块的划分,我们就可以很“轻松”地逐个对模块进行分析了。一般的,我们可以从文件底部的模块出入口函数开始(“module_init”和“module_exit”声明的函数,一般都在文件最后),根据它们调用的函数(自己定义的或者其他模块的函数)和使用的关键变量

(本文件内的全局变量或者其他模块的外部变量)画出“函数-变量-函数”依赖关系图——我们称为标识符依赖关系图。

当然,模块内标识符依赖关系并非是单纯的树形结构,很多情况是错综复杂的网络关系。这时候,我们对代码的详细注释的作用就体现出来了。我们根据函数本身的含义,将模块进行子功能划分,抽取出每个子功能的标识符依赖树。

通过标识符依赖关系分析,可以很清晰的展示模块定义的函数调用了那些函数,使用了哪些变量,以及模块子功能之间的依赖关系——公用了哪些函数和变量等。

第六步:模块间相互依赖关系

一旦将所有的模块内部标识符依赖关系图整理完毕,根据模块使用的其他模块的变量或函数,可以很容易得到模块之间的依赖关系。

cpufreq代码的模块依赖关系可以表示为如下关系。

第七步:模块架构图

透过模块间的依赖关系图,可以很清楚的表达模块在整个待分析代码中的地位和功能。基于此,我们可以将模块分类,整理出代码的架构关系。

如cpufreq的模块依赖关系图所示,我们可以很清楚的看到所有的调频策略模块都是依赖于核心模块cpufreq、cpufreq_stats和freq_table的。如果我们把被依赖的三个模块抽象为代码的核心框架的话,这些调频策略模块都是建立在这个框架之上的,它们负责和用户层交互。而核心模块cpufreq提供了驱动等相关的接口负责与系统底层交互。因此,我们可以得到如下的模块架构图。

当然,结构图并非模块的无机拼接,我们还需要结合查阅的资料去丰富架构图的含义。因此,这里的架构图的细节会随着不同的人的理解有所偏差。但是架构图主体的含义很基本一致的。至此,我们完成了待分析的内核代码的所有分析工作。

四、总结

正如文章开始所说,我们不可能对全部的内核代码进行分析。因此,通过对待分析的代码进行信息搜集,然后按照上述的流程分析出代码的原本始末是了解内核本质的有效手段。这种按照具体需要分析内核代码的方式,为快速进入Linux内核的世界提供了可能。通过这种方式,不断的对内核的其他模块分析,最后综合得到自己对Linux内核的理解,也就达到了我们学习Linux 内核的目的。

最后向大家推荐两本学习内核的参考书。一本是《Linux内核的设计与实现》,该书为读者快速精简的介绍了Linux内核的主要功能和实现。但不会把读者带入Linux内核代码的深渊中,是了解内核架构和入门Linux内核代码的非常好的参考书,同时该书会提高读者对内核代码的兴趣。另一本是《深入理解Linux内核》,该书的经典我不必多说。我只是建议,如果想更好的学习本书,最好是结合着内核代码一起阅读。由于这本书对内核代码描述的十分详细,所以结合代码进行阅读可以帮助我们更好的理解内核代码。同时,在分析内核代码的过程中,也可以在本书中找到具有参考价值的资料。最后,愿大家早日进入内核的世界,体验Linux带给我们的惊喜!

Linux操作系统源代码详细分析

linux源代码分析:Linux操作系统源代码详细分析 疯狂代码 https://www.360docs.net/doc/6417023012.html,/ ?:http:/https://www.360docs.net/doc/6417023012.html,/Linux/Article28378.html 内容介绍: Linux 拥有现代操作系统所有功能如真正抢先式多任务处理、支持多用户内存保护虚拟内存支持SMP、UP符合POSIX标准联网、图形用户接口和桌面环境具有快速性、稳定性等特点本书通过分析Linux内核源代码充分揭示了Linux作为操作系统内核是如何完成保证系统正常运行、协调多个并发进程、管理内存等工作现实中能让人自由获取系统源代码并不多通过本书学习将大大有助于读者编写自己新 第部分 Linux 内核源代码 arch/i386/kernel/entry.S 2 arch/i386/kernel/init_task.c 8 arch/i386/kernel/irq.c 8 arch/i386/kernel/irq.h 19 arch/i386/kernel/process.c 22 arch/i386/kernel/signal.c 30 arch/i386/kernel/smp.c 38 arch/i386/kernel/time.c 58 arch/i386/kernel/traps.c 65 arch/i386/lib/delay.c 73 arch/i386/mm/fault.c 74 arch/i386/mm/init.c 76 fs/binfmt-elf.c 82 fs/binfmt_java.c 96 fs/exec.c 98 /asm-generic/smplock.h 107 /asm-i386/atomic.h 108 /asm- i386/current.h 109 /asm-i386/dma.h 109 /asm-i386/elf.h 113 /asm-i386/hardirq.h 114 /asm- i386/page.h 114 /asm-i386/pgtable.h 115 /asm-i386/ptrace.h 122 /asm-i386/semaphore.h 123 /asm-i386/shmparam.h 124 /asm-i386/sigcontext.h 125 /asm-i386/siginfo.h 125 /asm-i386/signal.h 127 /asm-i386/smp.h 130 /asm-i386/softirq.h 132 /asm-i386/spinlock.h 133 /asm-i386/system.h 137 /asm-i386/uaccess.h 139 //binfmts.h 146 //capability.h 147 /linux/elf.h 150 /linux/elfcore.h 156 /linux/errupt.h 157 /linux/kernel.h 158 /linux/kernel_stat.h 159 /linux/limits.h 160 /linux/mm.h 160 /linux/module.h 164 /linux/msg.h 168 /linux/personality.h 169 /linux/reboot.h 169 /linux/resource.h 170 /linux/sched.h 171 /linux/sem.h 179 /linux/shm.h 180 /linux/signal.h 181 /linux/slab.h 184 /linux/smp.h 184 /linux/smp_lock.h 185 /linux/swap.h 185 /linux/swapctl.h 187 /linux/sysctl.h 188 /linux/tasks.h 194 /linux/time.h 194 /linux/timer.h 195 /linux/times.h 196 /linux/tqueue.h 196 /linux/wait.h 198 init/.c 198 init/version.c 212 ipc/msg.c 213 ipc/sem.c 218 ipc/shm.c 227 ipc/util.c 236 kernel/capability.c 237 kernel/dma.c 240 kernel/exec_do.c 241 kernel/exit.c 242 kernel/fork.c 248 kernel/info.c 255 kernel/itimer.c 255 kernel/kmod.c 257 kernel/module.c 259 kernel/panic.c 270 kernel/prk.c 271 kernel/sched.c 275 kernel/signal.c 295 kernel/softirq.c 307 kernel/sys.c 307 kernel/sysctl.c 318 kernel/time.c 330 mm/memory.c 335 mm/mlock.c 345 mm/mmap.c 348 mm/mprotect.c 358 mm/mremap.c 361 mm/page_alloc.c 363 mm/page_io.c 368 mm/slab.c 372 mm/swap.c 394 mm/swap_state.c 395 mm/swapfile.c 398 mm/vmalloc.c 406 mm/vmscan.c 409

linux内核IMQ源码实现分析

本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。 E-mail: wwwlkk@https://www.360docs.net/doc/6417023012.html, 来源: https://www.360docs.net/doc/6417023012.html,/?business&aid=6&un=wwwlkk#7 linux2.6.35内核IMQ源码实现分析 (1)数据包截留并重新注入协议栈技术 (1) (2)及时处理数据包技术 (2) (3)IMQ设备数据包重新注入协议栈流程 (4) (4)IMQ截留数据包流程 (4) (5)IMQ在软中断中及时将数据包重新注入协议栈 (7) (6)结束语 (9) 前言:IMQ用于入口流量整形和全局的流量控制,IMQ的配置是很简单的,但很少人分析过IMQ的内核实现,网络上也没有IMQ的源码分析文档,为了搞清楚IMQ的性能,稳定性,以及借鉴IMQ的技术,本文分析了IMQ的内核实现机制。 首先揭示IMQ的核心技术: 1.如何从协议栈中截留数据包,并能把数据包重新注入协议栈。 2.如何做到及时的将数据包重新注入协议栈。 实际上linux的标准内核已经解决了以上2个技术难点,第1个技术可以在NF_QUEUE机制中看到,第二个技术可以在发包软中断中看到。下面先介绍这2个技术。 (1)数据包截留并重新注入协议栈技术

(2)及时处理数据包技术 QoS有个技术难点:将数据包入队,然后发送队列中合适的数据包,那么如何做到队列中的数

激活状态的队列是否能保证队列中的数据包被及时的发送吗?接下来看一下,激活状态的队列的 证了数据包会被及时的发送。 这是linux内核发送软中断的机制,IMQ就是利用了这个机制,不同点在于:正常的发送队列是将数据包发送给网卡驱动,而IMQ队列是将数据包发送给okfn函数。

读Linux内核源代码

Linux内核分析方法 Linux的最大的好处之一就是它的源码公开。同时,公开的核心源码也吸引着无数的电脑爱好者和程序员;他们把解读和分析Linux的核心源码作为自己的最大兴趣,把修改Linux源码和改造Linux系统作为自己对计算机技术追求的最大目标。 Linux内核源码是很具吸引力的,特别是当你弄懂了一个分析了好久都没搞懂的问题;或者是被你修改过了的内核,顺利通过编译,一切运行正常的时候。那种成就感真是油然而生!而且,对内核的分析,除了出自对技术的狂热追求之外,这种令人生畏的劳动所带来的回报也是非常令人着迷的,这也正是它拥有众多追随者的主要原因: ?首先,你可以从中学到很多的计算机的底层知识,如后面将讲到的系统的引导和硬件提供的中断机制等;其它,象虚拟存储的实现机制,多任务机制,系统保护机制等等,这些都是非都源码不能体会的。 ?同时,你还将从操作系统的整体结构中,体会整体设计在软件设计中的份量和作用,以及一些宏观设计的方法和技巧:Linux的内核为上层应用提供一个与具体硬件不相关的平台; 同时在内核内部,它又把代码分为与体系结构和硬件相关的部分,和可移植的部分;再例如,Linux虽然不是微内核的,但他把大部分的设备驱动处理成相对独立的内核模块,这样减小了内核运行的开销,增强了内核代码的模块独立性。 ?而且你还能从对内核源码的分析中,体会到它在解决某个具体细节问题时,方法的巧妙:如后面将分析到了的Linux通过Botoom_half机制来加快系统对中断的处理。 ?最重要的是:在源码的分析过程中,你将会被一点一点地、潜移默化地专业化。一个专业的程序员,总是把代码的清晰性,兼容性,可移植性放在很重要的位置。他们总是通过定义大量的宏,来增强代码的清晰度和可读性,而又不增加编译后的代码长度和代码的运行效率; 他们总是在编码的同时,就考虑到了以后的代码维护和升级。甚至,只要分析百分之一的代码后,你就会深刻地体会到,什么样的代码才是一个专业的程序员写的,什么样的代码是一个业余爱好者写的。而这一点是任何没有真正分析过标准代码的人都无法体会到的。 然而,由于内核代码的冗长,和内核体系结构的庞杂,所以分析内核也是一个很艰难,很需要毅力的事;在缺乏指导和交流的情况下,尤其如此。只有方法正确,才能事半功倍。正是基于这种考虑,作者希望通过此文能给大家一些借鉴和启迪。 由于本人所进行的分析都是基于2.2.5版本的内核;所以,如果没有特别说明,以下分析都是基于i386单处理器的2.2.5版本的Linux内核。所有源文件均是相对于目录/usr/src/linux的。 方法之一:从何入手 要分析Linux内核源码,首先必须找到各个模块的位置,也即要弄懂源码的文件组织形式。虽然对于有经验的高手而言,这个不是很难;但对于很多初级的Linux爱好者,和那些对源码分析很

Linux内核源代码阅读与工具介绍

Linux的内核源代码可以从很多途径得到。一般来讲,在安装的linux系统下,/usr/src/linux 目录下的东西就是内核源代码。另外还可以从互连网上下载,解压缩后文件一般也都位于linux目录下。内核源代码有很多版本,目前最新的版本是2.2.14。 许多人对于阅读Linux内核有一种恐惧感,其实大可不必。当然,象Linux内核这样大而复杂的系统代码,阅读起来确实有很多困难,但是也不象想象的那么高不可攀。只要有恒心,困难都是可以克服的。任何事情做起来都需要有方法和工具。正确的方法可以指导工作,良好的工具可以事半功倍。对于Linux内核源代码的阅读也同样如此。下面我就把自己阅读内核源代码的一点经验介绍一下,最后介绍Window平台下的一种阅读工具。 对于源代码的阅读,要想比较顺利,事先最好对源代码的知识背景有一定的了解。对于linux内核源代码来讲,基本要求是:⑴操作系统的基本知识;⑵对C语言比较熟悉,最好要有汇编语言的知识和GNU C对标准C的扩展的知识的了解。另外在阅读之前,还应该知道Linux内核源代码的整体分布情况。我们知道现代的操作系统一般由进程管理、内存管理、文件系统、驱动程序、网络等组成。看一下Linux内核源代码就可看出,各个目录大致对应了这些方面。Linux内核源代码的组成如下(假设相对于linux目录): arch这个子目录包含了此核心源代码所支持的硬件体系结构相关的核心代码。如对于X86平台就是i386。 include这个目录包括了核心的大多数include文件。另外对于每种支持的体系结构分别有一个子目录。 init此目录包含核心启动代码。 mm此目录包含了所有的内存管理代码。与具体硬件体系结构相关的内存管理代码位于arch/*/mm目录下,如对应于X86的就是arch/i386/mm/fault.c。 drivers系统中所有的设备驱动都位于此目录中。它又进一步划分成几类设备驱动,每一种也有对应的子目录,如声卡的驱动对应于drivers/sound。 ipc此目录包含了核心的进程间通讯代码。 modules此目录包含已建好可动态加载的模块。 fs Linux支持的文件系统代码。不同的文件系统有不同的子目录对应,如ext2文件系统对应的就是ext2子目录。 kernel主要核心代码。同时与处理器结构相关代码都放在arch/*/kernel目录下。 net核心的网络部分代码。里面的每个子目录对应于网络的一个方面。 lib此目录包含了核心的库代码。与处理器结构相关库代码被放在arch/*/lib/目录下。

linux源代码分析实验报告格式

linux源代码分析实验报告格式

Linux的fork、exec、wait代码的分析 指导老师:景建笃 组员:王步月 张少恒 完成日期:2005-12-16

一、 设计目的 1.通过对Linux 的fork 、exec 、wait 代码的分析,了解一个操作系统进程的创建、 执行、等待、退出的过程,锻炼学生分析大型软件代码的能力; 2.通过与同组同学的合作,锻炼学生的合作能力。 二、准备知识 由于我们选的是题目二,所以为了明确分工,我们必须明白进程的定义。经过 查阅资料,我们得知进程必须具备以下四个要素: 1、有一段程序供其执行。这段程序不一定是进程专有,可以与其他进程共用。 2、有起码的“私有财产”,这就是进程专用的系统堆栈空间 3、有“户口”,这就是在内核中有一个task_struct 结构,操作系统称为“进程控制 块”。有了这个结构,进程才能成为内核调度的一个基本单位。同时,这个结构又 是进程的“财产登记卡”,记录着进程所占用的各项资源。 4、有独立的存储空间,意味着拥有专有的用户空间:进一步,还意味着除前述的 系统空间堆栈外,还有其专用的用户空间堆栈。系统为每个进程分配了一个 task_struct 结构,实际分配了两个连续的物理页面(共8192字节),其图如下: Struct task_struct (大约1K) 系统空间堆栈 (大约7KB )两个 连续 的物 理页 面 对这些基本的知识有了初步了解之后,我们按老师的建议,商量分工。如下: 四、 小组成员以及任务分配 1、王步月:分析进程的创建函数fork.c ,其中包含了get_pid 和do_fork get_pid, 写出代码分析结果,并画出流程图来表示相关函数之间的相互调用关系。所占工作 比例35%。 2、张少恒:分析进程的执行函数exec.c,其中包含了do_execve 。写出代码分析结 果,并画出流程图来表示相关函数之间的相互调用关系。所占工作比例35% 。 3、余波:分析进程的退出函数exit.c,其中包含了do_exit 、sys_wait4。写出代码 分析结果,并画出流程图来表示相关函数之间的相互调用关系。所占工作比例30% 。 五、各模块分析: 1、fork.c 一)、概述 进程大多数是由FORK 系统调用创建的.fork 能满足非常高效的生灭机制.除了 0进程等少数一,两个进程外,几乎所有的进程都是被另一个进程执行fork 系统调 用创建的.调用fork 的进程是父进程,由fork 创建的程是子进程.每个进程都有一

Linux源代码分析_存储管理

文章编号:1004-485X (2003)03-0030-04 收稿日期:2003-05-10 作者简介:王艳春,女(1964 ),副教授,主要从事操作系统、中文信息处理等方面的研究工作。 Linux 源代码分析 存储管理 王艳春 陈 毓 葛明霞 (长春理工大学计算机科学技术学院,吉林长春130022) 摘 要:本文剖析了Linux 操作系统的存储管理机制。给出了Linux 存储管理的特点、虚存的实现方法,以及主要数据结构之间的关系。 关键词:Linux 操作系统;存储管理;虚拟存储中图分类号:T P316 81 文献标识码:A Linux 操作系统是一种能运行于多种平台、源代码公开、免费、功能强大、与Unix 兼容的操作系统。自其诞生以来,发展非常迅速,在我国也受到政府、企业、科研单位、大专院校的重视。我们自2000年开始对Linux 源代码(版本号是Linux 2 2 16)进行分析,首先剖析了进程管理和存储管理部分,本文是有关存储管理的一部分。主要介绍了Linux 虚存管理所用到的数据结构及其相互间的关系,据此可以更好地理解其存储管理机制,也可以在此基础上对其进行改进或在此后的研究中提供借鉴作用。作为一种功能强大的操作系统,Linux 实现了以虚拟内存为主的内存管理机制。即能够克服物理内存的局限,使用户进程在透明方式下,拥有比实际物理内存大得多的内存。本文主要阐述了Linux 虚存管理的基本特点和主要实现技术,并分析了Linux 虚存管理的主要数据结构及其相互关系。 1 Lin ux 虚存管理概述 Linux 的内存管理采用虚拟页式管理,使用多级页表,动态地址变换。进程在运行过程中可以动态浮动和扩展,为用户提供了透明的、灵活有效的内存使用方式。 1)32 bit 虚拟地址 在Linux 中,进程的4GB 虚存需通过32 bit 地址进行寻址。Linux 中虚拟地址与线性地址为同一概念,虚拟地址被分成3个子位段,而大小为4k,如图1所示。 2)Linux 的多级页表结构 图1 32位虚拟地址 标准的Linux 的虚存页表为三级页表,依次为页目录(Pag e Directory PGD)、中间页目录(Pag e Middle Directory PMD )、页表(Page Table PT E )。在i386机器上Linux 的页表结构实际为两级,PGD 和PMD 页表是合二为一的。所有有关PMD 的操作关际上是对PGD 的操作。所以源代码中形如*_pgd _*()和*_pmd_*()函数实现的功能也是一样的。 页目录(PGD)是一个大小为4K 的表,每一个进程只有一个页目录,以4字节为一个表项,分成1024个表项(或称入口点),表项的索引即为32位虚拟地址的页目录,该表项的值为所指页表的起始地址。页表(PTE)的每一个入口点的值为此表项所指的一页框(page frame),页表项的索引即为32位虚拟地址中的页号。页框(page reame)并不是物理页,它指的是虚存的一个地址空间。 3) 页表项的格式 图2 Linux 中页目录项和页表项格式 4)动态地址映射 Linux 虚存采用动态地址映射方式,即进程的地址空间和存储空间的对应关系是在程序的执行过 第26卷第3期长春理工大学学报 Vol 26N o 32003年9月 Journal of Changchun University of Science and T echnology Sep.2003

Linux内核源码分析方法

Linux内核源码分析方法 一、内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次。如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径。我们都知道,想成为优秀的程序员,需要大量的实践和代码的编写。编程固然重要,但是往往只编程的人很容易把自己局限在自己的知识领域内。如果要扩展自己知识的广度,我们需要多接触其他人编写的代码,尤其是水平比我们更高的人编写的代码。通过这种途径,我们可以跳出自己知识圈的束缚,进入他人的知识圈,了解更多甚至我们一般短期内无法了解到的信息。Linux内核由无数开源社区的“大神们”精心维护,这些人都可以称得上一顶一的代码高手。透过阅读Linux 内核代码的方式,我们学习到的不光是内核相关的知识,在我看来更具价值的是学习和体会它们的编程技巧以及对计算机的理解。 我也是通过一个项目接触了Linux内核源码的分析,从源码的分析工作中,我受益颇多。除了获取相关的内核知识外,也改变了我对内核代码的过往认知: 1.内核源码的分析并非“高不可攀”。内核源码分析的难度不在于源码本身,而在于如何使用更合适的分析代码的方式和手段。内核的庞大致使我们不能按照分析一般的demo程序那样从主函数开始按部就班的分析,我们需要一种从中间介入的手段对内核源码“各个击破”。这种“按需索取”的方式使得我们可以把握源码的主线,而非过度纠结于具体的细节。 2.内核的设计是优美的。内核的地位的特殊性决定着内核的执行效率必须足够高才可以响应目前计算机应用的实时性要求,为此Linux内核使用C语言和汇编的混合编程。但是我们都 知道软件执行效率和软件的可维护性很多情况下是背道而驰的。如何在保证内核高效的前提下提高内核的可维护性,这需要依赖于内核中那些“优美”的设计。 3.神奇的编程技巧。在一般的应用软件设计领域,编码的地位可能不被过度的重视,因为开发者更注重软件的良好设计,而编码仅仅是实现手段问题——就像拿斧子劈柴一样,不用太多的思考。但是这在内核中并不成立,好的编码设计带来的不光是可维护性的提高,甚至是代码性能的提升。 每个人对内核的了理解都会有所不同,随着我们对内核理解的不断加深,对其设计和实现的思想会有更多的思考和体会。因此本文更期望于引导更多徘徊在Linux内核大门之外的人进入Linux的世界,去亲自体会内核的神奇与伟大。而我也并非内核源码方面的专家,这么做也只是希望分享我自己的分析源码的经验和心得,为那些需要的人提供参考和帮助,说的“冠冕堂皇”一点,也算是为计算机这个行业,尤其是在操作系统内核方面贡献自己的一份绵薄之力。闲话少叙(已经罗嗦了很多了,囧~),下面我就来分享一下自己的Linix内核源码分析方法。 二、内核源码难不难? 从本质上讲,分析Linux内核代码和看别人的代码没有什么两样,因为摆在你面前的一般都不是你自己写出来的代码。我们先举一个简单的例子,一个陌生人随便给你一个程序,并要你看完源码后讲解一下程序的功能的设计,我想很多自我感觉编程能力还可以的人肯定觉得这没什么,只要我耐心的把他的代码从头到尾看完,肯定能找到答案,并且事实确实是如此。那么现在换一个假设,如果这个人是Linus,给你的就是Linux内核的一个模块的代码,你还会觉得依然那么 轻松吗?不少人可能会有所犹豫。同样是陌生人(Linus要是认识你的话当然不算,呵呵~)给 你的代码,为什么给我们的感觉大相径庭呢?我觉得有以下原因:

Linux内核源代码解读

Linux内核源代码解读!! 悬赏分:5 - 提问时间2007-1-24 16:28 问题为何被关闭 赵炯书中,Bootsect代码中有 mov ax , #BOOTSEG 等 我曾自学过80x86汇编,没有见过#的用法,在这为什么要用#? 另外, JMPI 的用法是什么?与JMP的区别是什么? 提问者: Linux探索者 - 一级 答复共 1 条 检举 系统初始化程序 boot.s 的分析 [转] 系统初始化程序 boot.s 的分析: 阚志刚,2000/03/20下午,在前人的基础之上进行整理完善 ******************************************************************************** ************** boot.s is loaded at 0x7c00 by the bios-startup routines, and moves itself out of the way to address 0x90000, and jumps there. 当PC 机启动时,Intel系列的CPU首先进入的是实模式,并开始执行位于地址0xFFF0处的代码,也就是ROM-BIOS起始位置的代码。BIOS先进行一系列的系统自检,然后初始化位于地址0的中断向量表。最后BIOS将启动盘的第一个扇区装入0x7C00(31K;0111,1100,0000,0000),并开始执行此处的代码。这就是对内核初始化过程的一个最简单的描述。 最初,Linux核心的最开始部分是用8086汇编语言编写的。当开始运行时,核心将自己装入到绝对地址0x90000(576K; 1001,0000,0000,0000,0000),再将其后的2k字节装入到地址0x90200(576.5k;1001,0000,0010,0000,0000)处,最后将核心的其余部分装入到0x10000(64k; 1,0000,0000,0000,0000). It then loads the system at 0x10000, using BIOS interrupts. Thereafter it disables all interrupts, moves the system down to 0x0000, changes to protected mode, and calls the start of system. System then must RE-initialize the protected mode in it's own tables, and enable interrupts as needed. 然后,关掉所有中断,把系统下移到0x0000(0k;0000,0000,0000,0000,0000)处,改变到保护模式,然后开始系统的运行.系统必须重新在保护模式下初始化自己的系统表格,并且打开所需的中断. NOTE 1! currently system is at most 8*65536(8*64k=512k; 1000,0000,0000,0000,0000) bytes long. This should be no problem, even in the future. I want to keep it simple. This 512 kB kernel size should be enough - in fact more would mean we'd have to move not just these start-up routines, but also do something about the cache-memory

Linux KVM虚拟化源代码分析文档

KVM虚拟机源代码分析 1,KVM结构及工作原理 1.1K VM结构 KVM基本结构有两部分组成。一个是KVM Driver ,已经成为Linux 内核的一个模块。负责虚拟机的创建,虚拟内存的分配,虚拟CPU寄存器的读写以及虚拟CPU的运行等。另外一个是稍微修改过的Qemu,用于模拟PC硬件的用户空间组件,提供I/O设备模型以及访问外设的途径。 图1 KVM基本结构 KVM基本结构如图1所示。其中KVM加入到标准的Linux内核中,被组织成Linux中标准的字符设备(/dev/kvm)。Qemu通KVM提供的LibKvm应用程序接口,通过ioctl系统调用创建和运行虚拟机。KVM Driver使得整个Linux成为一个虚拟机监控器。并且在原有的Linux两种执行模式(内核模式和用户模式)的基础上,新增加了客户模式,客户模式拥有自己的内核模式和用户模式。在虚拟机运行下,三种模式的分工如下: 客户模式:执行非I/O的客户代码。虚拟机运行在客户模式下。 内核模式:实现到客户模式的切换。处理因为I/O或者其它指令引起的从客户模式的退出。KVM Driver工作在这种模式下。 用户模式:代表客户执行I/O指令Qemu运行在这种模式下。

在KVM模型中,每一个Guest OS 都作为一个标准的Linux进程,可以使用Linux的进程管理指令管理。 在图1中./dev/kvm在内核中创建的标准字符设备,通过ioctl系统调用来访问内核虚拟机,进行虚拟机的创建和初始化;kvm_vm fd是创建的指向特定虚拟机实例的文件描述符,通过这个文件描述符对特定虚拟机进行访问控制;kvm_vcpu fd指向为虚拟机创建的虚拟处理器的文件描述符,通过该描述符使用ioctl系统调用设置和调度虚拟处理器的运行。 1.2K VM工作原理 KVM的基本工作原理:用户模式的Qemu利用接口libkvm通过ioctl系统调用进入内核模式。KVM Driver为虚拟机创建虚拟内存和虚拟CPU后执行VMLAUCH指令进入客户模式。装载Guest OS执行。如果Guest OS发生外部中断或者影子页表缺页之类的事件,暂停Guest OS的执行,退出客户模式进行一些必要的处理。然后重新进入客户模式,执行客户代码。如果发生I/O事件或者信号队列中有信号到达,就会进入用户模式处理。KVM采用全虚拟化技术。客户机不用修改就可以运行。 图2 KVM 工作基本原理

怎样读Linux内核源代码

Linux内核分析方法 2010-9-12 Linux的最大的好处之一就是它的源码公开。同时,公开的核心源码也吸引着无数的电脑爱好者和程序员;他们把解读和分析Linux的核心源码作为自己的最大兴趣,把修改Linux 源码和改造Linux系统作为自己对计算机技术追求的最大目标。 Linux内核源码是很具吸引力的,特别是当你弄懂了一个分析了好久都没搞懂的问题;或者是被你修改过了的内核,顺利通过编译,一切运行正常的时候。那种成就感真是油然而生!而且,对内核的分析,除了出自对技术的狂热追求之外,这种令人生畏的劳动所带来的回报也是非常令人着迷的,这也正是它拥有众多追随者的主要原因: ?首先,你可以从中学到很多的计算机的底层知识,如后面将讲到的系统的引导和硬件提供的中断机制等;其它,象虚拟存储的实现机制,多任务机制,系统保护机制 等等,这些都是非都源码不能体会的。 等等,这些都是非读源码不能体会的。 ?同时,你还将从操作系统的整体结构中,体会整体设计在软件设计中的份量和作用,以及一些宏观设计的方法和技巧:Linux的内核为上层应用提供一个与具体硬件不 相关的平台;同时在内核内部,它又把代码分为与体系结构和硬件相关的部分,和 可移植的部分;再例如,Linux虽然不是微内核的,但他把大部分的设备驱动处理 成相对独立的内核模块,这样减小了内核运行的开销,增强了内核代码的模块独立 性。 ?而且你还能从对内核源码的分析中,体会到它在解决某个具体细节问题时,方法的巧妙:如后面将分析到了的Linux通过Botoom_half机制来加快系统对中断的处理。 ?最重要的是:在源码的分析过程中,你将会被一点一点地、潜移默化地专业化。一个专业的程序员,总是把代码的清晰性,兼容性,可移植性放在很重要的位置。他 们总是通过定义大量的宏,来增强代码的清晰度和可读性,而又不增加编译后的代 码长度和代码的运行效率;他们总是在编码的同时,就考虑到了以后的代码维护和 升级。甚至,只要分析百分之一的代码后,你就会深刻地体会到,什么样的代码才是一个专业的程序员写的,什么样的代码是一个业余爱好者写的。而这一点是任何 没有真正分析过标准代码的人都无法体会到的。 然而,由于内核代码的冗长,和内核体系结构的庞杂,所以分析内核也是一个很艰难,很需要毅力的事;在缺乏指导和交流的情况下,尤其如此。只有方法正确,才能事半功倍。正是基于这种考虑,作者希望通过此文能给大家一些借鉴和启迪。 由于本人所进行的分析都是基于2.2.5版本的内核;所以,如果没有特别说明,以下分析都是基于i386单处理器的 2.2.5版本的Linux内核。所有源文件均是相对于目录/usr/src/linux的。 方法之一:从何入手

Linux内核源代码漫游

Li nu x内核源代码漫游创建时间:2001-10-1121时13分 Linux内核源代码漫游 Alessandro Rubini 著, rubini@pop.systemy.it 赵 炯译,gohigh@https://www.360docs.net/doc/6417023012.html, (https://www.360docs.net/doc/6417023012.html,) 本章试图以顺序的方式来解释Li nu x源代码,以帮助读者对源代码的体系结构以及很多相关的unix特性的实现有一个很好的理解。目标是帮助对Lin ux不甚了解的有经验的C 程序员对整个L i nu x的设计有所了解。这也就是为什么内核漫游的入点选择为内核本身的启始点:系统引导(启动)。 这份材料需要对C语言以及对Un i x的概念和P C机的结构有很好的了解,然而本章中并没有出现任何的C代码,而是直接参考(指向)实际的代码的。有关内核设计的最佳篇幅是在本手册的其它章节中,而本章仍趋向于是一个非正式的概述。 本章中所参阅的任何文件的路径名都是指主源代码目录树,通常是/u s r/s r c/li nu x。 这里所给出的大多数信息都是取之于Lin u x发行版 1.0的源代码。虽然如此, 有时也会提供对后期版本的参考。这篇漫游中开头有图标的任何小节都是强调 1.0版本后对内核的新的改动。如果没有这样的小节存在,则表示直到版本 1.0.9-1.1.76,没有作过改动。 有时候本章中会有象这样的小节,这是指向正确的代码以对刚讨论过的主题取得 更多信息的指示符。当然,这里是指源代码。 引导(启动)系统 当P C的电源打开后,80x86结构的CP U将自动进入实模式,并从地址0xF FFF0开始自动执行程序代码,这个地址通常是ROM-B IOS中的地址。PC机的BIOS将执行某些系统的检测,在物理地址0处开始初始化中断向量。此后,它将可启动设备的第一个扇区读入内存地址0x7C00处,并跳转到这个地方。启动设备通常是软驱或是硬盘。这里的叙述是非常简单的,但这已经足够理解内核初始化的工作过程了。 Li nux的最最前面部分是用8086汇编语言编写的(bo ot/bo ot s e c t.S),它将由BIOS 读入到内存0x7C00处,当它被执行时就会把自己移到绝对地址0x90000处,并将启动设备 (bo ot/s et u p.S)的下2k B字节的代码读入内存0x90200处,而内核的其它部分则被读入到地址0x10000处。在系统加载期间将显示信息"L oa d in g..."。然后控制权将传递给bo ot/S et u p.S中的代码,这是另一个实模式汇编语言程序。 启动部分识别主机的某些特性以及vg a卡的类型。如果需要,它会要求用户为控制台选择显示模式。然后将整个系统从地址0x10000移至0x1000处,进入保护模式并跳转至系统的余下部分(在0x1000处)。 下一步是内核的解压缩。0x1000处的代码来自于z B oo t/head.S,它初始化寄存器并调用d e c om p r e ss_k e rn e l(),它们依次是由z B oo t/i n f l at e.c、z B oot/u n z i p.c和z B oo t/m isc.c组成。被解压的数据存放到了地址0x10000处(1兆),这也是为什么Li nu x不能运行于少于2兆内存的主要原因。[在1兆内存中解压内核的工作已经完成,见M em o r y S av e rs--ED]将内核封装在一个gz i p文件中的工作是由z B oo t目录中的M ak ef il e以及工具 完成的。它们是值得一看的有趣的文件。 内核发行版1.1.75将b oot和z B oo t目录下移到了a rc h/i386/boo t中了,这个改动意味着对不同的体系结构允许真正的内核建造,不过我将仍然只讲解有关i386的信息。解压过的代码是从地址0x10100处开始执行的[这里我可能忘记了具体的物理地址 了, 第 1 页共 9 页

Linux 源代码分析

Linux内核(2.6.13.2)源代码分析 苗彦超 摘要: 1系统启动 1.1汇编代码head.S及以前 设置CPU状态初值,创建进程0,建立进程堆栈: movq init_rsp(%rip), %rsp,init_rsp定义 .globl init_rsp init_rsp: .quad init_thread_union+THREAD_SIZE-8 即将虚地址init_thread_union+THREAD_SIZE-8作为当前进程(进程0)核心空间堆栈栈底,init_thread_union定义于文件arch/x86_64/kernel/init_task.c中: union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = {INIT_THREAD_INFO(init_task)}; INIT_THREAD_INFO定义于文件include/asm-x86_64/thread_info.h中,初始化init_thread_union.task = &init_task,init_task同样定义于文件init_task.c中,初始化为: struct task_struct init_task = INIT_TASK(init_task); INIT_TASK宏在include/linux/init_task.h中定义。 全部利用编译时静态设置的初值,将进程0的控制结构设置完成,使进程0可以按普通核心进程访问。 init_task.mm = NULL; init_task.active_mm = INIT_MM(init_mm), init_https://www.360docs.net/doc/6417023012.html,m = “swapper” INIT_MM将init_mm.pgd初始化为swapper_pg_dir,即init_level4_pgt,定义与head.S中。进程0的名称为swapper。 利用下述汇编代码跳转到C函数执行: movl %esi, %edi// 传递函数参数 movq initial_code(%rip),%rax jmp *%rax initial_code: .quad x86_64_start_kernel 开始执行文件arch/x86_64/kernel/head64.c中的C函数x86_64_start_kernel(char * real_mode_data),1.2函数x86_64_start_kernel(char * real_mode_data) 1设置全部中断向量初始入口为early_idt_handler,加载中断描述符idt_descr 2clear_bss():BSS段清0 3pda_init(0):设置处理器0相关信息(processor datastructure area ?),重置CR3为init_level4_pgt 4copy_bootdata:复制BIOS启动参数到操作系统变量x86_boot_params中,再复制启动命令行参数由x86_boot_params到saved_command_line中,用printk显示saved_command_line,从此不再 与实模式数据打交道 5cpu_set:设置CPU 0 开始工作标志 6处理“earlyprintk=”、“numa”、“disableapic”等命令行参数 7setup_boot_cpu_data():设置CPU信息结构boot_cpu_data,使用cpuid指令

LINUX2.6内核代码分析――进程管理

摘要:随着计算机开发以及教学工作的深入,大家也不可避免的要接触到基于linux内核的各种操作系统。如何迈入linux的大门,并充分利用linux开源、灵活等特性呢?解读内核源码无疑是理解并掌握linux的关键。本篇文章,主要是对linux内核进程管理部分进行笼统的解读,帮助读者快速掌握linux进程管理的主线,对读者的理解起到抛砖引玉的作用。 关键词:linux2.6;内核代码;进程管理 一 linux是最受欢迎的自由电脑操作系统内核。它是一个用c语言写成,符合posix标准的类unix操作系统。linux最早是由芬兰黑客 linus torvalds为尝试在英特尔x86架构上提供自由免费的类unix操作系统而开发的。技术上说linux是一个内核。“内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。一个内核不是一套完整的操作系统。一套基于linux内核的完整操作系统叫作linux操作系统,或是gnu/linux。 linux内核的主要模块(或组件)分以下几个部分:存储管理、cpu和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。一般地,可以从linux 内核版本号来区分系统是否是linux稳定版还是测试版。以版本2.4.0为例,2代表主版本号,4代表次版本号,0代表改动较小的末版本号。在版本号中,序号的第二位为偶数的版本表明这是一个可以使用的稳定版本,如2.2.5,而序号的第二位为奇数的版本一般有一些新的东西加入,是个不一定很稳定的测试版本,如2.3.1。这样稳定版本来源于上一个测试版升级版本号,而一个稳定版本发展到完全成熟后就不再发展。本文是针对2.4.0版本内核进行分析。有于篇幅有限阅读前需要读者自行下载相应内核源码。 二 schedule()函数首先对所有进程进行检测,唤醒任何一个已经得到信号的任务。主要是任务数组中的每个进程,检测其报警定时值alarm。若alarmnr_active + expired->nr_active ii.prio_array_t *active, *expired, arrays[2];// 两个子队列 就绪队列根据时间片是否被用完分为了active队列和expired队列。queue是指定优先级进程list的指针,如queue[i]就是priority为 i 的进程的指针。bitmap是一张优先级的位图,或者可以说的位数组,每一位代表了一个优先级(类似uc/os-ii)。 max_prio指的是优先级的数量. 以上是对linux 2.4.0版本内核源码进程管理部分的概括分析,主要用来为linux源码解读做一个引导,起到抛砖引玉的作用。但是由于时间,篇幅等种种原因,无法将全部函数调用以及相关代码一一呈现在读者面前,还望见谅。

linux内核编译详细教程

详细教程:编译Linux最新内核 一、实验目的 学习重新编译Linux内核,理解、掌握Linux内核和发行版本的区别。 二、实验内容 在Linux操作系统环境下重新编译内核。实验主要内容: A. 查找并且下载一份内核源代码,本实验使用最新的Linux内核2.6.36。 B. 配置内核。 C. 编译内核和模块。 D. 配置启动文件。 本次实验环境是Linux2.6.35内核的环境下,下载并重新编译内核源代码(2.6.36);然后,配置GNU的启动引导工具grub,成功运行编译成功的内核。 三、主要仪器设备(必填) Linux环境:utuntu10.10,linux内核2.6.35 待编译内核:linux2.6.36 四、操作方法和实验步骤 【1】下载内核源代码 从https://www.360docs.net/doc/6417023012.html,/newlinux/files/jijiangmin网站上下载最新的Linux内核2.6.36。【2】部署内核源代码

打开终端,更改用户权限为root。具体做法是在终端输入sudo su,然后按提示输入密码。判断是否是root用户是使用whoami命令,若输出为root则已经切换到root账户。 输入mv linux-2.6.36.tar.gz /usr/src,目的是把下载的内核源代码文件移到/usr/src目录。 输入cd /usr/src切换到该目录下。 输入tar zxvf linux-2.6.36.tar.gz,目的是解压内核包,生成的源代码放在linux-2.6.36目录下。 输入cd linux-2.6.36,切换到该目录下。 输入cp /boot/config-,然后按下Tab键,系统会自动填上该目录下符合条件的文件名,然后继续输入.config,目的是使用在boot目录下的原配置文件。 【3】配置内核 配置内核的方法很多,主要有如下几种: #make menuconfig //基于ncurse库编制的图形工具界面 #make config //基于文本命令行工具,不推荐使用 #make xconfig //基于X11图形工具界面 #make gconfig //基于gtk+的图形工具界面 由于对Linux还处在初学阶段,所以选择了简单的配置内核方法,即make menuconfig。在终端输入make menuconfig,等待几秒后,终端变成图形化的内核配置界面。进行配置时,大部分选项使用其缺省值,只有一小部分需要根据不同的需要选择。 对每一个配置选项,用户有三种选择,它们分别代表的含义如下: <*>或[*]——将该功能编译进内核 []——不将该功能编译进内核

相关文档
最新文档