﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-流浪妖精のSKY-文章分类-Linux系统实现</title><link>http://www.cnitblog.com/flutist1225/category/4179.html</link><description>&lt;div align="right"&gt;&lt;iframe src="http://weather.265.com/weather.htm" width="168" height="54" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;!--- daliy English --&gt;
&lt;span id="dict_daily"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;script language="JavaScript" src="http://dict.cn/daily.php" defer="defer"&gt;&lt;br /&gt;
&lt;/script&gt;
&lt;!--Music --&gt;
&lt;span style="display:none"&gt;
&lt;embed src="http://www.c188.com/all/1111wmatt98/new3/new2/1368/6.wma" loop=true autostart=true volume=100 type=audio/x-pn-realaudio-plugin Initfn=load-types mime-types=mime.types &gt;
&lt;/span&gt;</description><language>zh-cn</language><lastBuildDate>Sun, 02 Oct 2011 17:32:21 GMT</lastBuildDate><pubDate>Sun, 02 Oct 2011 17:32:21 GMT</pubDate><ttl>60</ttl><item><title>2.6内核的配置详解</title><link>http://www.cnitblog.com/flutist1225/articles/19969.html</link><dc:creator>Flutist</dc:creator><author>Flutist</author><pubDate>Sun, 03 Dec 2006 12:18:00 GMT</pubDate><guid>http://www.cnitblog.com/flutist1225/articles/19969.html</guid><wfw:comment>http://www.cnitblog.com/flutist1225/comments/19969.html</wfw:comment><comments>http://www.cnitblog.com/flutist1225/articles/19969.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/flutist1225/comments/commentRss/19969.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/flutist1225/services/trackbacks/19969.html</trackback:ping><description><![CDATA[
		<p>本文以Gentoo的2.6.10-r6的内核为例，讲述了如何配置、编译2.6版本的内核。</p>
		<p>首先对内核进行菜单配置，<br /><strong># cd /usr/src/linux<br /># make menuconfig<br /></strong>进入图形界面的内核配置。</p>
		<p>代码成熟度选项，<br />Code maturity level options  ---&gt;<br />  [*] Prompt for development and/or incomplete code/drivers<br />  [*]   Select only drivers expected to compile cleanly</p>
		<p>    打开使用开发中、不完全的代码/驱动会让内核配置多出很多选项，由于我们需要使用一些正在开发中的功能，因此必需打开这一选项。<br /></p>
		<div dir="ltr" style="TEXT-ALIGN: left">通用设置选项，<br />General setup  ---&gt;<br />  ()  Local version - append to kernel release<br />  [*] Support for paging of anonymous memory (swap)<br />  [*] System V IPC<br />  [*] POSIX Message Queues<br />  [*] BSD Process Accounting<br />  [*]   BSD Process Accounting version 3 file format<br />  [*] Sysctl support<br />  [ ] Auditing support<br />  (15) Kernel log buffer size (16 =&gt; 64KB, 17 =&gt; 128KB)<br />  [*] Support for hot-pluggable devices<br />  [*] Kernel Userspace Events<br />  [*] Kernel .config support<br />  [*]   Enable access to .config through /proc/config.gz<br />  [*] Configure standard kernel features (for small systems)  ---&gt;<br />    --- Configure standard kernel features (for small systems)<br />    [ ]   Load all symbols for debugging/kksymoops<br />    [*]   Enable futex support<br />    [*]   Enable eventpoll support<br />    [*]   Optimize for size<br />    [*]   Use full shmem filesystem<br />    (0)   Function alignment<br />    (0)   Label alignment<br />    (0)   Loop alignment<br />    (0)   Jump alignment</div>
		<div dir="ltr" style="TEXT-ALIGN: left"> </div>
		<div dir="ltr" style="TEXT-ALIGN: left">Local version - append to kernel release：这里填入的是64字符以内的字符串，你在这里填上的字符口串可以用uname -a命令看到。<br /><br />Support for paging of anonymous memory (swap)：这是使用交换分区或者交换文件来做为虚拟内存的，当然要选上了。<br /><br />System V IPC：表示系统5的Inter Process Communication，它用于处理器在程序之间同步和交换信息，如果不选这项，很多程序运行不起来的。<br /><br />POSIX Message Queues：这是POSIX的消息队列，它同样是一种IPC。建议你最好将它选上。<br /><br />BSD Process Accounting：这是充许用户进程访问内核将账户信息写入文件中的。这通常被认为是个好主意，建议你最好将它选上。<br /><br />Sysctl support：这个选项能不重新编译内核修改内核的某些参数和变量，如果你也选择了支持/proc，将能从/proc/sys存取可以影响内核的参数或变量。建议你最好将它选上。<br /><br />Auditing support：审记支持，用于和内核的某些子模块同时工作，例如SELinux。只有选择此项及它的子项，才能调用有关审记的系统调用。<br /><br />Kernel log buffer size：内核日志缓存的大小，12 =&gt; 4 KB，13 =&gt; 8 KB，14 =&gt; 16 KB单处理器，15 =&gt; 32 KB多处理器，16 =&gt; 64 KB for x86 NUMAQ or IA-64，17 =&gt; 128 KB for S/390。<br /><br />Support for hot-pluggable devices：是否支持热插拔的选项，肯定要选上。不然USB、PCMCIA等这些设备都用不了。<br /><br />Kernel Userspace Events：内核中分为系统区和用户区，这里系统区和用户区进行通讯的一种方式，选上。<br /><br />Kernel .config support：将.config配置信息保存在内核中，选上它及它的子项使得其它用户能从/proc中得到内核的配置。还记得另一篇贴子我是如何取得启动光盘的内核配置信息，并在此基础上配置新的内核吗？<br /><br />Configure standard kernel features (for small systems)：这是为了编译某些特殊的内核使用的，通常你可以不选择这一选项，你也不用对它下面的子项操心了。<br /><br />Load all symbols for debugging/kksymoops：是否装载所有的调试符号表信息，如果你不需要对内核调试，不需要选择此项。<br /><br />Enable futex support：不选这个内核不一定能正确的运行使用glibc的程序，当然要选上。<br /><br />Enable eventpoll support：不选这个内核将不支持事件轮循的系统调用，最好选上。<br /><br />Optimize for size：这个选项使gcc使用-Os的参数而不是-O2的参数来优化编译，以获得更小尺寸的内核，建议选上。<br /><br />Use full shmem filesystem：除非你在很少的内存且不使用交换内存时，才不要选择这项。<br /><br />后面的这四项都是在编译时内存中的对齐方式，0表示编译器的默认方式。使用内存对齐能提高程序的运行速度，但是会增加程序对内存的使用量。<br /><div dir="ltr" style="TEXT-ALIGN: left"><p>可加载模块，<br />Loadable module support  ---&gt;<br />  [*] Enable loadable module support<br />  [*] Module unloading<br />  [ ]     Forced module unloading<br />  [*] Module versioning support (EXPERIMENTAL)<br />  [ ] Source checksum for all modules<br />  [*] Automatic kernel module loading</p><p>Enable loadable module support，很多人喜欢将全部功能、硬件支持一股脑的编进内核，而不是使用模块的方式。这样做非常不好（个人觉得）。其实我也做过嵌入式的开发，在针对特定硬件的平台下尽可能将内核编小，将始终是支持模块加载的。例如我们开发的防火墙就是做为内核的模块被加载的。使用模块支持，你的系统能具有更好的可扩充性。还有一个原因就是自己编写的功能模块、设备驱动模块（假设编写的质量不高）以模块方式工作引起Kernel Panic的机率要远远低于不支持模块全部编进内核的方式。讲了这么多，终于可以理直气壮的选上这一功能了。<br /><br />Module unloading，不选这个功能，加载的模块就不能卸载。没什么需要多解释的，建议最好选上。<br /><br />Forced module unloading，这个选项能强行卸载模块，即使内核认为这样并不安全，也就是说你可以把正在使用中的模快卸载掉。如果你不是内核开发人员或者骨灰级的玩家，不要选择这个选项。<br /><br />Module versioning support (EXPERIMENTAL)，这个功能可以让你使用其它版本的内核模块，由于我自己写一些模块，所以我会用到这个选项，因为内核更新太快了，我的头文件更新根本赶不上内核的更新。还有，虽然我在Gentoo下开发，但实际真实环境用的却是从kernel.org下载的内核。虽然我选择了这个选项，不过建议你不要选择这个选项。<br /><br />Source checksum for all modules，这个功能是为了防止更改了内核模块的代码但忘记更改版本号而造成版本冲突。我估计现在没有哪家公司在开发中还没使用版本控制工具，所以不需要这项了。如果你不是自己写内核模块，那就更不需要这一选项了。<br /><br />Automatic kernel module loading，这个选项能让内核自动的加载部份模块，建议你最好选上。举个例子说明一下，如模块eth1394依赖于模块ieee1394。如果选择了这个选项，可以直接加载模块eth1394；如果没有选择这个选项，必需先加载模块ieee1394，再加载模块eth1394，否则将出错。</p><p></p><p><strong>2.6内核的配置与编译(4)</strong></p><p>处理器内型及特性，<br />Processor type and features  ---&gt;<br />  Subarchitecture Type (PC-compatible)  ---&gt;<br />  Processor family (Pentium-4/Celeron(P4-based)/Pentium-4 M/Xeon)  ---&gt;<br />  [ ] Generic x86 support<br />  [*] HPET Timer Support<br />  [*] Symmetric multi-processing support<br />  (2)   Maximum number of CPUs (2-255)<br />  [*]   SMT (Hyperthreading) scheduler support<br />  [ ] Preemptible Kernel<br />  [ ] Machine Check Exception<br />  &lt;M&gt; Toshiba Laptop support<br />  &lt;M&gt; Dell laptop support<br />  &lt; &gt; /dev/cpu/microcode - Intel IA32 CPU microcode support<br />  &lt; &gt; /dev/cpu/*/msr - Model-specific register support<br />  &lt; &gt; /dev/cpu/*/cpuid - CPU information support<br />  Firmware Drivers  ---&gt;<br />    &lt; &gt; BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)<br />  High Memory Support (4GB)  ---&gt;<br />  [ ] Allocate 3rd-level pagetables from highmem<br />  [ ] Math emulation<br />  [*] MTRR (Memory Type Range Register) support<br />  [ ] Boot from EFI support (EXPERIMENTAL)<br />  [*] Enable kernel irq balancing<br />  [ ] Use register arguments (EXPERIMENTAL)</p><p>Subarchitecture Type，这没什么好说的，如果用PC机的话都选这个。<br /><br />Processor family，这也没什么好说的，选择你机器对应的处理器即可。<br /><br />Generic x86 support，这一选项针对x86系列的CPU使用更多的常规优化。如果你在上面一项选的是i386、i586之类的才选这个。<br /><br />HPET Timer Support，HPET是替代8254芯片的下一代时钟处理器。这里你可以安全的选上这一选项。如果硬件不支持的话，将仍使用8254时钟处理器。<br /><br />Symmetric multi-processing support，对称多处理器支持，在单CPU的机器上，不选这个选项会更快一些。由于超线程技术，看起来是两颗CPU，因些要选上这个选项。<br /><br />Maximum number of CPUs (2-255)，支持的最大CPU数。<br /><br />SMT (Hyperthreading) scheduler support，超线程支持，如果你的CPU是P4超线程的，应该选上这一选项。<br /><br />Preemptible Kernel，这个选项能使应用程序即使内核在高负载时也很可靠，建议最好选上。<br /><br />Machine Check Exception，这个选项能让CPU检测到系统故障时通知内核，一般我用组装的台式机会选这项。本本嘛，我感觉还是非常可靠的，所以就不选它了。<br /><br />Toshiba Laptop support，Dell laptop support，这两项都是对本本的支持，其实编译内核的原则应该是让内核能在特定的环境下运行，由于我编译的内核可能公司的其它人也会使用，所以我尽可能的不针对特定的硬件。将对特定的硬件支持编译成模块。<br /><br />/dev/cpu/microcode - Intel IA32 CPU microcode support，这个选项是让你使用不随Linux内核发行的IA32 microcode，但是你必需有IA32 microcode的二进制文件。<br /><br />/dev/cpu/*/msr - Model-specific register support，这个选项能让特权CPU访问x86的MSR寄存器。由于超线程并不是真正的多处理器环境，所以不要选择这个。<br /><br />/dev/cpu/*/cpuid - CPU information support，这个选项能从/dev/cpu/x/cpuid获得CPU的唯一标识符。<br /><br />BIOS Enhanced Disk Drive calls determine boot disk，台式机的有些BIOS支持从某块特定的硬盘启动，由于本本只能装一块硬盘，所以就不选择这项了。如果你的BIOS不支持这个功能而你选上的话，有可能无法启动。<br /><br />High Memory Support (4GB)，4GB的内存支持，已经足够了。<br /><br />Allocate 3rd-level pagetables from highmem，除非你真的有几G的内存，选择这个是没有意义的。<br /><br />Math emulation，估计现在没人有386或486SX的处理器了吧，那就不要选这个。<br /><br />MTRR (Memory Type Range Register) support，这个选项必需要选上。<br /><br />Boot from EFI support (EXPERIMENTAL)，由于我使用的是GRUB，所以选上这个也没什么用，如果你打算使用EFI的功能，你可以到<a href="http://elilo.sourceforge.net/" target="_blank"><font color="#000080">http://elilo.sourceforge.net</font></a>看看。<br /><br />Enable kernel irq balancing，选上这个选项能让内核进行IRQ均衡。<br /><br />Use register arguments (EXPERIMENTAL)，使用-mregparm=3参数编译内核，将前3个参数以寄存器方式进行参数调用。GCC的版本必需大于等于3.0。</p><p>电源管理，<br />Power management options (ACPI, APM)  ---&gt;<br />  [*] Power Management support<br />  [ ]   Power Management Debug Support<br />  [ ]   Software Suspend (EXPERIMENTAL)<br />      ACPI (Advanced Configuration and Power Interface) Support  ---&gt;<br />      APM (Advanced Power Management) BIOS Support  ---&gt;<br />      CPU Frequency scaling  ---&gt;</p><p>Power Management support，电源管理没什么好说的，不想浪费电就选上。如果不选你可以跳过这部份。<br /><br />Power Management Debug Support，电源管理的调试信息支持，如果不是要调试内核有关电源管理部份，请不要选择这项。<br /><br />Software Suspend (EXPERIMENTAL)，休眠到硬盘。也就是将内存写入交换分区中，下次启动可以通过参数resume=/dev/swappartition（例如：resume=/dev/hda6）来恢复上次机器运行的状态。这项功能对于系统引导时启动许多服务的机器来说很有用，可以节约启动时间。这项功能根据自己的需要选择吧，如果你选择这项功能，记得恢复休眠后重做交换分区。</p><p>ACPI (Advanced Configuration and Power Interface) Support  ---&gt;<br />  [*] ACPI Support<br />  [ ]   Sleep States (EXPERIMENTAL)<br />  &lt;M&gt;   AC Adapter<br />  &lt;M&gt;   Battery<br />  &lt;M&gt;   Button<br />  &lt;M&gt;   Video<br />  &lt;M&gt;   Fan<br />  &lt;M&gt;   Processor<br />  &lt;M&gt;     Thermal Zone<br />  &lt;M&gt;   ASUS/Medion Laptop Extras<br />  &lt;M&gt;   IBM ThinkPad Laptop Extras<br />  &lt;M&gt;   Toshiba Laptop Extras<br />  (0) Disable ACPI for systems before Jan 1st this year <br />  [ ] Debug Statements<br />  [ ] Power Management Timer Support</p><p>ACPI Support，这是一种电源管理方式，你可以看看你的BIOS是否支持。如果支持的话建议你选上这项。<br /><br />Sleep States (EXPERIMENTAL)，这项功能可以让系统进入休眠状态（不是休眠到硬盘）。休眠是指系统仍然通着电，只是进入最大幅度的省电状态；而休眠到硬盘是指系统已经断电。不过如果你不是驱动程序的电源管理部份的开发人员，建议你最好不要选择这项。相信未来linux下的驱动对电源支持的功能会越来越好，或者也搞个硬件兼容列表，到时就可以放心的使用这项功能了。<br /><br />AC Adapter，检测是电源供电还是电池供电，通常只对本本有用。<br /><br />Battery，通过/proc/acpi/battery得到电池的信息，通常这也是针对笔记本的。<br /><br />Button，捕获Power、Sleep、Lid（我也不知道这是什么按钮）等按钮是否按下，并做相应的动作。<br /><br />Video，集成在板上的显卡的ACPI支持，对有些板卡可能不起作用。<br /><br />Fan，风扇的支持。这一点很明显，不选这项我的本本的风扇一直在转，选上以后风扇只是间断的转转。<br /><br />Processor，当机器负荷轻时节省处理器的用电，处理器可是电脑中的第一用电大户（可能老式的CRT显示器和它有的一比）。<br /><br />Thermal Zone，这个我也不太清楚是什么，只是据说大部份的台式机和笔记本都支持，不选还可能把处理器烧掉。<img class="inlineimg" title="微笑" alt="" src="file:///C:/Documents%20and%20Settings/bekars/Local%20Settings/Temp/CyberArticle/401_files/smile[1].gif" border="0" />如果你不会让模块正常工作，还是把它编进内核吧，怪吓人的。<br /><br />ASUS/Medion Laptop Extras、IBM ThinkPad Laptop Extras、Toshiba Laptop Extras，这三种本本的扩展支持。你的内核如果只是自己用，选个该选的就行了。<br /><br />(0) Disable ACPI for systems before Jan 1st this year，输入四位数的年份，在该年的1月1日前不使用ACPI的功能。0表示一直使用。<br /><br />Debug Statements，详细的ACPI调试信息，不搞开发就别选。<br /><br />Power Management Timer Support，我的本本支持HPET（要是忘了是什么，再看看前面），所以不选它。要是你的机器不支持，应该把它选上。</p><p>APM (Advanced Power Management) BIOS Support  ---&gt;<br />  &lt;M&gt; APM (Advanced Power Management) BIOS support<br />  [ ]   Ignore USER SUSPEND <br />  [*]   Enable PM at boot time<br />  [ ]   Make CPU Idle calls when idle<br />  [ ]   Enable console blanking using APM<br />  [ ]   RTC stores time in GMT<br />  [ ]   Allow interrupts during APM BIOS calls<br />  [*]   Use real mode APM BIOS call to power off</p><p>APM (Advanced Power Management) BIOS support，高级电源管理的支持，一般来说笔记本应该选上，台式机可以不选。<br /><br />Ignore USER SUSPEND，只有NEC Versa M系列的笔记本需要选择这一项。<br /><br />Enable PM at boot time，启动时支持电源管理，选上这个选项能让系统自动的进行电源管理，除非在启动时死机，才不要选这项。<br /><br />Make CPU Idle calls when idle，系统空闲时调用空闲指令。只有老式的CPU才用这项。其实调用空闲指令还是让CPU执行了一条指令。这个选项在内核循环中调用空闲指令。<br /><br />Enable console blanking using APM，支持关闭监视器。据说这项功能对所有的笔记本都无效。如果你都按我的建议配置，系统是能自动休眠的（使用ACPI）。你也不用担心你的显示器一直亮着的。<br /><br />RTC stores time in GMT，按Unix的标准，硬件的时钟应该设为格林威治时间。还是那句老话，因为我还要用Windows，所以硬件时钟设成了本地时间，当然就不要选这项了。<br /><br />Allow interrupts during APM BIOS calls，允许APM的BIOS调用时中断。多数的机器不需要这项，Thinkpad的一些新机器需要这项。如果休眠时挂机（包括睡下去就醒不来），再把这项选上。<br /><br />Use real mode APM BIOS call to power off，建议最好选上此项，保证软件关机。如果你有兴趣可以试试你的机器不选这项能不能正常的软件关机（多数机器不能）。</p><p> </p><p>补充一点，如果既选择了ACPI又选择了APM，先加载的将被使用。<br /><br />通过这么多的例子，大家应该可以看出来在menuconfig中，圆括号内是参数，可以选择某一选项或者输入具体的参数。方括号只能选择“Y”或“N”，尖括号除了选择“Y”和“N”还可以选择“M”。“Y”表示将该选项包括在内核中，menuconfig中以“*”表示。“N”表示不使用此选项的功能，“M”表示将此选项的功能编译成模块。<br /><br />ACPI是为了取代APM而设计的，因此尽量使用ACPI的功能，实在不行再加载apm模块。</p><p>[*] CPU Frequency scaling<br />[ ]   Enable CPUfreq debugging<br />&lt; &gt;   /proc/cpufreq interface (deprecated) <br />      Default CPUFreq governor (performance)  ---&gt;<br />---   'performance' governor<br />&lt;M&gt;   'powersave' governor<br />&lt;M&gt;   'userspace' governor for userspace frequency scaling<br />[ ]     /proc/sys/cpu/ interface (2.4. / OLD)<br />&lt;M&gt;   'ondemand' cpufreq policy governor<br />&lt;*&gt;   CPU frequency table helpers<br />&lt;M&gt; ACPI Processor P-States driver<br />&lt;M&gt; AMD Mobile K6-2/K6-3 PowerNow! <br />&lt;M&gt; AMD Mobile Athlon/Duron PowerNow!<br />&lt;M&gt; AMD Opteron/Athlon64 PowerNow!<br />&lt;M&gt; Cyrix MediaGX/NatSemi Geode Suspend Modulation<br />&lt;M&gt; Intel Enhanced SpeedStep <br />[ ]   Use ACPI tables to decode valid frequency/voltage pairs<br />---   Built-in tables for Banias CPUs<br />&lt;M&gt; Intel Speedstep on ICH-M chipsets (ioport interface) <br />&lt;M&gt; Intel SpeedStep on 440BX/ZX/MX chipsets (SMI interface)<br />&lt;M&gt; Intel Pentium 4 clock modulation<br />&lt; &gt; nVidia nForce2 FSB changing<br />&lt;M&gt; Transmeta LongRun<br />&lt;M&gt; VIA Cyrix III Longhaul<br />--- shared options<br />[ ] /proc/acpi/processor/../performance interface (deprecated)<br />[ ] Relaxed speedstep capability checks</p><p>CPU Frequency scaling，这一选项允许改变CPU的主频，使CPU在低负荷或使用电池时降低主频，达到省电的目的。<br /><br />Enable CPUfreq debugging，是否允许调试CPU改变主频的功能，如果要调试，还需要在启动时加上参数。cpufreq.debug=&lt;value&gt;<br />1：变频技术的内核调试<br />2：变频技术的驱动调试<br />4：变频技术的调节器调试<br /><br />/proc/cpufreq interface (deprecated) ，是否允许/proc/cpufreq来调节主频，建议使用默认的sysfs来调节。<br /><br />Default CPUFreq governor (performance) ---&gt;，默认的主频调节，圆括号内的是你选择的结果，这里表示以性能为主。<br /><br />'powersave' governor，最大限度的节约电能调节器。<br /><br />'userspace' governor for userspace frequency scaling，用户自定义调节器。<br /><br />/proc/sys/cpu/ interface (2.4. / OLD)，兼容2.4内核的用户调节器。<br /><br />'ondemand' cpufreq policy governor，自动调节主频。<br /><br />CPU frequency table helpers，多数的CPU需要这一项来调节主频。<br /><br />ACPI Processor P-States driver，报告处理器的状态。<br /><br />AMD Mobile K6-2/K6-3 PowerNow!，AMD移动版K6处理器的变频驱动。<br /><br />AMD Mobile Athlon/Duron PowerNow!，AMD移动版毒龙、雷乌的变频驱动。<br /><br />AMD Opteron/Athlon64 PowerNow!，AMD64处理器的变频驱动。<br /><br />Cyrix MediaGX/NatSemi Geode Suspend Modulation，Cyrix处理器的变频驱动。<br /><br />Intel Enhanced SpeedStep，Intel的变频技术支持。<br /><br />Use ACPI tables to decode valid frequency/voltage pairs，使用BIOS中的主频／电压参数。<br /><br />--- Built-in tables for Banias CPUs，迅驰一代的主频／电压参数。<br /><br />Intel Speedstep on ICH-M chipsets (ioport interface) ，Intel ICH-M南桥芯片组的支持。<br /><br />Intel SpeedStep on 440BX/ZX/MX chipsets (SMI interface)，Intel 440BX/ZX/MX南桥芯片级的支持。<br /><br />Intel Pentium 4 clock modulation，P4处理器的时钟模块支持。<br /><br />nVidia nForce2 FSB changing，nVidia nForce2的支持。<br /><br />Transmeta LongRun，Transmeta处理器的支持。<br /><br />VIA Cyrix III Longhaul，VIA Cyrix处理器的支持。<br /><br />/proc/acpi/processor/../performance interface (deprecated)，从/proc/acpi/processor/../performance获得CPU的变频信息。<br /><br />Relaxed speedstep capability checks，不全面检测Intel Speedstep，有的系统虽然支持Speedstep技术，却无法通过全面的检测。</p><p>总线类型，<br />[*] PCI support <br />      PCI access mode (Any)  ---&gt;<br />[ ] Message Signaled Interrupts (MSI and MSI-X)<br />[ ] Legacy /proc/pci interface<br />[ ] PCI device name database<br />[*] ISA support <br />[*]   EISA support<br />[*]     Vesa Local Bus priming<br />[*]     Generic PCI/EISA bridge<br />[*]     EISA virtual root device<br />[ ]     EISA device name database<br />[ ] MCA support<br />&lt; &gt; NatSemi SCx200 support<br />    PCCARD (PCMCIA/CardBus) support  ---&gt;<br />    PCI Hotplug Support  ---&gt;<br /><br />PCI support，没有人不知道这是什么总线类型吧，实在不知道就去google查吧，这个当然要选上。</p><p>PCI access mode (Any)，强列建议选Any，系统将优先使用MMConfig，然后使用BIOS，最后使用Direct检测PCI设备。</p><p>Message Signaled Interrupts (MSI and MSI-X)，建议你不要选择这项，设备将使用默认的IRQ中断。如果选择这项，充许设备通过PCI总线写入内存堆栈产生一个中断。</p><p>Legacy /proc/pci interface，是否使用/proc/pci目录下的信息文件来描述PCI设备的信息。现在的系统多数都使用lspci工具来得到这样的信息。</p><p>PCI device name database，如果你不打算使用lspci工具，就把这项和上面的一项选上。lspci和hotplug都不需要内核中的设备信息库了。</p><p>ISA support，是否使用工业总线。如果你没有老式的ISA设备，可以不选这项。现在基本上都没有ISA的设备了。不过需要注意的是如果你做嵌入式系统的开发，一些PC104的总线可能会桥接到EISA或者是。VESA总线上。</p><p>EISA support，扩展工业总线。</p><p>Vesa Local Bus priming，VESA总线，也是扩展工业总线的一种。我的老486DX66的机器上的显卡就是这种总线，块板上大概还有2个EISA插槽各3个ISA插槽。</p><p>PCI/EISA bridge，PCI、EISA两种总线的桥。</p><p>EISA virtual root device，EISA总线的虚拟根设备。</p><p>EISA device name database，内核中的EISA设备信息库。</p><p>MCA support，微通道总线。IBM的台式机和笔记本上可能会有这种总线，包括它的p系列、e系列、z系列机器上都用到了这种总线。</p><p>NatSemi SCx200 support，这个我不知道是什么东西，看帮助是松下的一种半导体处理器的驱动。</p><p>    总之，只要你的主板没有ISA插槽，而且你也不是搞嵌入式开发，工业自动化控制的。不要选“ISA support”就是了，如今的ISA设备在x86体系上基本是是见不到了。不过自己制板的话，还是ISA的板子最好做。</p><p></p><p><strong>2.6内核的配置与编译(10)</strong></p><p></p><p>PCCARD (PCMCIA/CardBus) support  ---&gt;<br />    &lt;M&gt; PCCard (PCMCIA/CardBus) support<br />    [ ]   Enable PCCARD debugging<br />    [ ]   Enable obsolete PCCARD code<br />    &lt;M&gt;   16-bit PCMCIA support<br />    [*]   32-bit CardBus support<br />    --- PC-card bridges<br />    &lt;M&gt; CardBus yenta-compatible bridge support<br />    &lt;M&gt; Cirrus PD6729 compatible bridge support<br />    &lt;M&gt; i82092 compatible bridge support<br />    &lt;M&gt; i82365 compatible bridge support<br />    &lt;M&gt; Databook TCIC host bridge support</p><p>PCCard (PCMCIA/CardBus) support，一般只有笔记本电脑上才会有PCMCIA插槽，如果你是台式机的话，可以不选这一项，然后跳过这一部份。</p><p>Enable PCCARD debugging，通常不需要选择调试PCMCIA设备，除非你是设备驱动的开发人员。</p><p>Enable obsolete PCCARD code，老式的PCMCIA设备只持。现在很少有这样的设备了，除非你买这样的设备时带了张Linux的驱动光盘才需要选上。而且估计你也只能在二手市场上买到这样的设备。</p><p>16-bit PCMCIA support，16位的PCMCIA总线支持。</p><p>32-bit CardBus support，32位的PCMCIA总线支持，通常也叫PCMCIA II总线。</p><p>下面的是不同产家的PCMCIA芯片的驱动支持，如果你知道你的本本用的是什么芯片组的话，可以只选它而不选其它的。要是你不知道可以象我一样的全部选上，然后用modprobe一种一种的试。最后我终于知道我的HP zv5028的本本用的是yenta-compatible的芯片组了。<br />--- PC-card bridges<br />&lt;M&gt; CardBus yenta-compatible bridge support<br />&lt;M&gt; Cirrus PD6729 compatible bridge support<br />&lt;M&gt; i82092 compatible bridge support<br />&lt;M&gt; i82365 compatible bridge support<br />&lt;M&gt; Databook TCIC host bridge support</p><p>PCI Hotplug Support  ---&gt;<br />  &lt;M&gt; Support for PCI Hotplug (EXPERIMENTAL)<br />  &lt; &gt;   Fake PCI Hotplug driver (NEW)<br />  &lt; &gt;   Compaq PCI Hotplug driver (NEW)<br />  &lt; &gt;   IBM PCI Hotplug driver (NEW)<br />  &lt; &gt;   ACPI PCI Hotplug driver (NEW)<br />  [ ]   CompactPCI Hotplug driver (NEW)<br />  &lt; &gt;   PCI Express Hotplug driver (NEW)<br />  &lt; &gt;   SHPC PCI Hotplug driver (NEW)<br />  <br />Support for PCI Hotplug (EXPERIMENTAL)，一般来讲只有服务器上会有热插拔的设备，如果你使用的是台式机，你可以不选择此项并跳过这一部份。（其实我也没有选这一项，只是为了讲解的方便而选上的。）</p><p>Fake PCI Hotplug driver (NEW)，选上这一选项能让你的机器模拟PCI热插拔。注意，它并不是真正意义上的热插拔，决对不允许带电插拔设备除非你的主板上集成了PCI热插拔芯片并且你的PCI设备本身支持热插拔。</p><p>Compaq PCI Hotplug driver (NEW)，Compaq服务器上的热插拔芯片组的支持。</p><p>IBM PCI Hotplug driver (NEW)，IBM服务器上的热插拔芯片组的支持。</p><p>ACPI PCI Hotplug driver (NEW)，PCI热插拔设备是否支持ACPI电源管理（一般来说都是支持的）。</p><p>CompactPCI Hotplug driver (NEW)，精简PCI总线的热插拔设备的支持，通常在嵌入式系统中会用到精简PCI总线。</p><p>PCI Express Hotplug driver (NEW)，PCI加速总线的热插拔设备的支持。现在PCI Express总线的显卡挺火的。但用于服务器上的PCI加速总线的设备我还没见过。（我是井底之蛙）</p><p>SHPC PCI Hotplug driver (NEW)，SHPC热插拔控制芯片的支持。文件系统，<br />&lt;*&gt; Second extended fs support<br />[*]   Ext2 extended attributes<br />[*]     Ext2 POSIX Access Control Lists<br />[*]     Ext2 Security Labels<br />&lt;*&gt; Ext3 journalling file system support<br />[*]   Ext3 extended attributes<br />[*]     Ext3 POSIX Access Control Lists<br />[*]     Ext3 Security Labels<br />[ ] JBD (ext3) debugging support<br />&lt;*&gt; Reiserfs support<br />[ ]   Enable reiserfs debug mode<br />[ ]   Stats in /proc/fs/reiserfs<br />[*]   ReiserFS extended attributes<br />[*]     ReiserFS POSIX Access Control Lists<br />[*]     ReiserFS Security Labels<br /><m></m>JFS filesystem support<br />[*]   JFS POSIX Access Control Lists<br />[ ]   JFS debugging<br />[ ]   JFS statistics<br /><m></m>XFS filesystem support<br />[*]   Realtime support (EXPERIMENTAL)<br />[*]   Quota support<br />[*]   Security Label support<br />[*]   POSIX ACL support<br />&lt; &gt; Minix fs support<br />&lt; &gt; ROM file system support<br />[*] Quota support<br />&lt; &gt;   Old quota format support<br /><m></m>   Quota format v2 support<br />[*] Dnotify support<br />&lt; &gt; Kernel automounter support<br />&lt; &gt; Kernel automounter version 4 support (also supports v3)<br />    CD-ROM/DVD Filesystems  ---&gt;<br />    DOS/FAT/NT Filesystems  ---&gt;<br />    Pseudo filesystems  ---&gt;<br />    Miscellaneous filesystems  ---&gt;<br />    Network File Systems  ---&gt;<br />    Partition Types  ---&gt;<br />    Native Language Support  ---&gt;<br />    <br />　　有人说在编译内核时应该将/boot分区和/分区的文件系统编译进内核，其它的可以编译成模块。对，但不确切。让我们来一起了解一下linux系统的启动顺序。在内核被加载后，如果initrd参数传入了内核，内核会去调用指定的文件。当然，initrd和System.map通常都是/boot下。但是同样可以用initrd=(hd1,2)/initrd.img这样的方式指定。内核启动完成后将调用/sbin/init，（如果是链接要保证目标文件能被内核加载）。不同的系统的启动脚本可能不太一样，这里不详细介绍。启动脚本向内核加载模块时可能用/sbin/modprobe或/sbin/insmod，由此看来/sbin的文件系统是要内核支持的。编译的内核模块一般在/lib/modules/的版本目录下，所以/lib/modules的文件系统是要内核支持的。一旦其它文件系统的模块能加载，系统就能向正常的访问内核中的文件系统一样访问模块支持的文件系统了。由于启动脚本、fstab自动加载等文件一般在/etc目录下，因此/etc的文件系统是要内核支持的。<br />　　这里概要的介绍了保证系统正常启动的几个关键点，可能我反而把它讲复杂了。如果你能理解上面的这段话，你应该能清楚的知道哪些文件系统是要编译进内核的，哪些是可以编译成模块的。如果你不太理解上面的这段话，下篇贴子我将详细介绍每个选项及几种常用的文件系统。当然这里面包含了我的偏见，如果你觉得我的说法不准确，有误导看官的地方，请一定指出来。我在此先表示多谢了。</p><p>可执行文件格式，<br />[*] Kernel support for ELF binaries<br />&lt; &gt; Kernel support for a.out and ECOFF binaries<br />&lt;*&gt; Kernel support for MISC binaries</p><p>Kernel support for ELF binaries，ELF是开放平台下最常用的二进制文件，它支持不同的硬件平台。</p><p>Kernel support for a.out and ECOFF binaries，这是早期UNIX系统的可执行文件格式，目前已经被ELF格式取代。</p><p>Kernel support for MISC binaries，此选项允许插入二进制的封装层到内核中，当使用Java、.NET、Python、Lisp等语言编写的程序时非常有用。<br /></p><p>接下来应该讲硬件设备部份，但考虑到硬件部份是针对具体硬件的，大数Linux玩家都是硬件的DIYer。因此对这一部份应该很熟悉。硬件设备部份将放到最后讲，下一篇将讲文件系统部份。</p><p>&lt;*&gt; Second extended fs support<br />[*]   Ext2 extended attributes<br />[*]     Ext2 POSIX Access Control Lists<br />[*]     Ext2 Security Labels<br />&lt;*&gt; Ext3 journalling file system support<br />[*]   Ext3 extended attributes<br />[*]     Ext3 POSIX Access Control Lists<br />[*]     Ext3 Security Labels<br />[ ] JBD (ext3) debugging support<br />&lt;*&gt; Reiserfs support<br />[ ]   Enable reiserfs debug mode<br />[ ]   Stats in /proc/fs/reiserfs<br />[*]   ReiserFS extended attributes<br />[*]     ReiserFS POSIX Access Control Lists<br />[*]     ReiserFS Security Labels<br /><m></m>JFS filesystem support<br />[*]   JFS POSIX Access Control Lists<br />[ ]   JFS debugging<br />[ ]   JFS statistics<br /><m></m>XFS filesystem support<br />[*]   Realtime support (EXPERIMENTAL)<br />[*]   Quota support<br />[*]   Security Label support<br />[*]   POSIX ACL support<br />&lt; &gt; Minix fs support<br />&lt; &gt; ROM file system support<br />[*] Quota support<br />&lt; &gt;   Old quota format support<br /><m></m>   Quota format v2 support<br />[*] Dnotify support<br />&lt; &gt; Kernel automounter support<br />&lt; &gt; Kernel automounter version 4 support (also supports v3)<br />    CD-ROM/DVD Filesystems  ---&gt;<br />    DOS/FAT/NT Filesystems  ---&gt;<br />    Pseudo filesystems  ---&gt;<br />    Miscellaneous filesystems  ---&gt;<br />    Network File Systems  ---&gt;<br />    Partition Types  ---&gt;<br />    Native Language Support  ---&gt;<br />    <br />Second extended fs support，标准的Linux文件系统，建议将这种文件系统编译进内核。</p><p>Ext2 extended attributes，Ext2文件系统的结点名称、属性的扩展支持。</p><p>Ext2 POSIX Access Control Lists，POSIX系统的访问权限列表支持。也就是Owner/Group/Others的Read/Write/Execute权限。请参考Unix标准文件系统权限。</p><p>Ext2 Security Labels，扩展的安全标签，例如SElinux之类的安全系统会使用到这样的扩展安全属性。</p><p>Ext3 journalling file system support，如果你熟悉Redhat Linux，你一定会习惯Ext3文件系统。</p><p>Ext3 extended attributes，Ext3文件系统的结点名称、属性的扩展支持。</p><p>Ext3 POSIX Access Control Lists，POSIX系统的访问权限列表支持。</p><p>Ext3 Security Labels，扩展的安全标签支持。</p><p>JBD (ext3) debugging support，Ext3的调试。除非你是文件系统的开发者，否则不要选上这一项。</p><p>Reiserfs support，如果你熟悉Suse Linux，你一定会习惯Reiserfs文件系统。</p><p>Enable reiserfs debug mode，Reiserfs的调试。除非你是文件系统的开发者，否则不要选上这一项。</p><p>Stats in /proc/fs/reiserfs，在/proc/fs/reiserfs文件中显示Reiserfs文件系统的状态。一般来说不需要选择这一项。</p><p>ReiserFS extended attributes，Reiserfs，文件系统的结点名称、属性的扩展支持。</p><p>ReiserFS POSIX Access Control Lists，POSIX系统的访问权限列表支持。</p><p>ReiserFS Security Labels，扩展的安全标签支持。</p><p>JFS filesystem support，JFS是IBM公司设计用于AIX系统上的文件系统。后来这一文件系统也能应用于Linux系统。</p><p>JFS POSIX Access Control Lists，POSIX系统的访问权限列表支持。</p><p>JFS debugging，JFS的调试。除非你是文件系统的开发者，否则不要选上这一项。</p><p>JFS statistics，在/proc/fs/jfs文件中显示Reiserfs文件系统的状态。一般来说不需要选择这一项。</p><p>XFS filesystem support，XFS是SGI公司为其图形工作站设计的一种文件系统，后来这一文件系统也能应用于Linux系统。</p><p>Realtime support (EXPERIMENTAL)，实时卷的支持，能大幅提高大文件的读写速度。不过并不太安全，建议暂时不要选择这一选项。</p><p>Quota support，XFS文件系统的配额支持。</p><p>Security Label support，扩展的安全标签支持。</p><p>POSIX ACL support，POSIX系统的访问权限列表支持。</p><p>Minix fs support，Minix可能是最早的Linux系统所使用的文件系统。后来被Ext2文件系统所取代。</p><p>ROM file system support，内存文件系统的支持。除非你是嵌入式系统的开发者，明确知道你要干什么，否则不要选这一项。</p><p>Quota support，配额支持。也就是说限制某个用户或者某组用户的磁盘占用空间。</p><p>Old quota format support，旧版本的配额支持。</p><p>Quota format v2 support，新版本（第二版）的配额支持。</p><p>Dnotify support，基于目录的文件变化的通知机制。</p><p>Kernel automounter support，内核自动加载远程文件系统的支持。</p><p>Kernel automounter version 4 support (also supports v3)，新的（第四版）的内核自动加载远程文件系统的支持，也支持第三版。</p></div></div>
<img src ="http://www.cnitblog.com/flutist1225/aggbug/19969.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/flutist1225/" target="_blank">Flutist</a> 2006-12-03 20:18 <a href="http://www.cnitblog.com/flutist1225/articles/19969.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux 初始 RAM 磁盘（initrd）概述（转）（三星）</title><link>http://www.cnitblog.com/flutist1225/articles/19220.html</link><dc:creator>Flutist</dc:creator><author>Flutist</author><pubDate>Thu, 16 Nov 2006 07:00:00 GMT</pubDate><guid>http://www.cnitblog.com/flutist1225/articles/19220.html</guid><wfw:comment>http://www.cnitblog.com/flutist1225/comments/19220.html</wfw:comment><comments>http://www.cnitblog.com/flutist1225/articles/19220.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/flutist1225/comments/commentRss/19220.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/flutist1225/services/trackbacks/19220.html</trackback:ping><description><![CDATA[
		<p>
				<a name="N10059">
						<span class="atitle">
								<font size="4">
										<br />什么是初始 RAM 磁盘？</font>
						</span>
				</a>
		</p>
		<p>
				<em>初始 RAM 磁盘（initrd）</em>是在实际根文件系统可用之前挂载到系统中的一个初始根文件系统。initrd 与内核绑定在一起，并作为内核引导过程的一部分进行加载。内核然后会将这个 initrd 文件作为其两阶段引导过程的一部分来加载模块，这样才能稍后使用真正的文件系统，并挂载实际的根文件系统。</p>
		<p>initrd 中包含了实现这个目标所需要的目录和可执行程序的最小集合，例如将内核模块加载到内核中所使用的 <code>insmod</code> 工具。</p>
		<p>在桌面或服务器 Linux 系统中，initrd 是一个临时的文件系统。其生存周期很短，只会用作到真实文件系统的一个桥梁。在没有存储设备的嵌入式系统中，initrd 是永久的根文件系统。本文将对这两种情况进行探索。</p>
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N1006E">
						<span class="atitle">
								<font size="4">initrd 剖析</font>
						</span>
				</a>
		</p>
		<p>initrd 映像中包含了支持 Linux 系统两阶段引导过程所需要的必要可执行程序和系统文件。</p>
		<p>根据我们运行的 Linux 的版本不同，创建初始 RAM 磁盘的方法也可能会有所不同。在 Fedora Core 3 之前，initrd 是使用 <em>loop 设备</em> 来构建的。<em>loop 设备</em> 是一个设备驱动程序，利用它可以将文件作为一个块设备挂载到系统中，然后就可以查看这个文件系统中的内容了。在您的内核中可能并没有 loop 设备，不过这可以通过内核配置工具（<code>make menuconfig</code>）选择 <strong>Device Drivers &gt; Block Devices &gt; Loopback Device Support</strong> 来启用。我们可以按照下面的方法来查看 loop 设备的内容（initrd 文件的名字可能会稍有不同）：<br /><br /><a name="listing1"><strong>清单 1. 查看 initrd 的内容（适用于 FC3 之前的版本）</strong></a><br /></p>
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section"># mkdir temp ; cd temp<br /># cp /boot/initrd.img.gz .<br /># gunzip initrd.img.gz<br /># mount -t ext -o loop initrd.img /mnt/initrd<br /># ls -la /mnt/initrd#</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<p>现在我们就可以查看 /mnt/initrd 子目录中的内容了，这就代表了 initrd 文件的内容。注意，即使您的 initrd 映像文件不是以 .gz 结尾，它也可能是一个压缩文件，您可以给这个文件添加上 .gz 后缀，然后再使用 gunzip 对其进行解压。</p>
		<p>从 Fedora Core 3 开始，默认的 initrd 映像变成了一个经过压缩的 cpio 归档文件。我们不用再使用 loop 设备来将 initrd 作为压缩映像进行挂载，而是可以将其作为 cpio 归档文件来使用。要查看 cpio 归档文件的内容，可以使用下面的命令：</p>
		<a name="listing2">
				<strong>清单 2. 查看 initrd 的内容（适用于 FC3 及其以后的版本）</strong>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section"># mkdir temp ; cd temp<br /># cp /boot/initrd-2.6.14.2.img initrd-2.6.14.2.img.gz<br /># gunzip initrd-2.6.14.2.img.gz<br /># cpio -i --make-directories &lt; initrd-2.6.14.2.img</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>结果会生成一个很小的根文件系统，如清单 3 所示。在 ./bin 目录中有一组很少但却非常必要的应用程序，包括 <code>nash</code>（即 not a shell，是一个脚本解释器）、<code>insmod</code>（用来加载内核模块）和 <code>lvm</code>（逻辑卷管理工具）。</p>
		<br />
		<a name="listing3">
				<strong>清单 3. 默认的 Linux initrd 目录结构 </strong>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section"># ls -la<br />#drwxr-xr-x  10 root root    4096 May 7 02:48 .<br />drwxr-x---  15 root root    4096 May 7 00:54 ..<br />drwxr-xr-x  2  root root    4096 May 7 02:48 bin<br />drwxr-xr-x  2  root root    4096 May 7 02:48 dev<br />drwxr-xr-x  4  root root    4096 May 7 02:48 etc<br />-rwxr-xr-x  1  root root     812 May 7 02:48 init<br />-rw-r--r--  1  root root 1723392 May 7 02:45 initrd-2.6.14.2.img<br />drwxr-xr-x  2  root root    4096 May 7 02:48 lib<br />drwxr-xr-x  2  root root    4096 May 7 02:48 loopfs<br />drwxr-xr-x  2  root root    4096 May 7 02:48 proc<br />lrwxrwxrwx  1  root root       3 May 7 02:48 sbin -&gt; bin<br />drwxr-xr-x  2  root root    4096 May 7 02:48 sys<br />drwxr-xr-x  2  root root    4096 May 7 02:48 sysroot<br />#</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>清单 3 中比较有趣的是 init 文件就在根目录中。与传统的 Linux 引导过程类似，这个文件也是在将 initrd 映像解压到 RAM 磁盘中时被调用的。在本文稍后我们将来探索这个问题。</p>
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100D8">
						<span class="atitle">
								<font size="4">创建 initrd 所使用的工具</font>
						</span>
				</a>
		</p>
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<font size="4">
												<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
										</font>
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N100E0">
																				<strong>cpio 命令</strong>
																		</a>
																		<br />
																		<p>使用 <code>cpio</code> 命令，我们可以对 cpio 文件进行操作。cpio 是一种文件格式，它简单地使用文件头将一组文件串接在一起。cpio 文件格式可以使用 ASCII 和二进制文件。为了保证可移植性，我们可以使用 ASCII 格式。为了减小文件大小，我们可以使用二进制的版本。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>下面让我们回到最开始，来看一下 initrd 映像最初是如何构建的。对于传统的 Linux 系统来说，initrd 映像是在 Linux 构建过程中创建的。有很多工具，例如 <code>mkinitrd</code>，都可以用来使用必要的库和模块自动构建 initrd，从而用作与真实的根文件系统之间的桥梁。<code>mkinitrd</code> 工具实际上就是一个 shell 脚本，因此我们可以看到它究竟是如何来实现这个结果的。还有一个 <code>YAIRD</code>（即 Yet Another Mkinitrd）工具，可以对 initrd 构建过程的各个方面进行定制。</p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																</td>
																<td valign="top" align="right">
																		<strong>
																				<font color="#996699">
																				</font>
																		</strong>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N100FC">
						<span class="atitle">
								<font size="4">手工构建定制的初始 RAM 磁盘</font>
						</span>
				</a>
		</p>
		<p>由于在很多基于 Linux 的嵌入式系统上没有硬盘，因此 initrd 也会作为这种系统上的永久根文件系统使用。清单 4 显示了如何创建一个 initrd 映像文件。我使用了一个标准的 Linux 桌面，这样您即使没有嵌入式平台，也可以按照下面的步骤来执行了。除了交叉编译，其他概念（也适用于 initrd 的构建）对于嵌入式平台都是相同的。</p>
		<br />
		<a name="listing4">
				<strong>清单 4. 创建定制 initrd 的工具（mkird） </strong>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">#!/bin/bash<br /># Housekeeping...<br />rm -f /tmp/ramdisk.img<br />rm -f /tmp/ramdisk.img.gz<br /># Ramdisk Constants<br />RDSIZE=4000<br />BLKSIZE=1024<br /># Create an empty ramdisk image<br />dd if=/dev/zero of=/tmp/ramdisk.img bs=$BLKSIZE count=$RDSIZE<br /># Make it an ext2 mountable file system<br />/sbin/mke2fs -F -m 0 -b $BLKSIZE <br />/tmp/ramdisk.img $RDSIZE<br /># Mount it so that we can populatemount <br />/tmp/ramdisk.img <br />/mnt/initrd -t ext2 -o loop=/dev/loop0<br /># Populate the filesystem (subdirectories)<br />mkdir /mnt/initrd/binmkdir <br />/mnt/initrd/sysmkdir <br />/mnt/initrd/devmkdir <br />/mnt/initrd/proc<br /># Grab busybox and create the symbolic linkspushd <br />/mnt/initrd/bin<br />cp /usr/local/src/busybox-1.1.1/busybox .<br />ln -s busybox ash<br />ln -s busybox mount<br />ln -s busybox echo<br />ln -s busybox ls<br />ln -s busybox cat<br />ln -s busybox ps<br />ln -s busybox dmesg<br />ln -s busybox sysctlpopd<br /># Grab the necessary dev files<br />cp -a /dev/console /mnt/initrd/dev<br />cp -a /dev/ramdisk /mnt/initrd/dev<br />cp -a /dev/ram0 /mnt/initrd/dev<br />cp -a /dev/null /mnt/initrd/dev<br />cp -a /dev/tty1 /mnt/initrd/dev<br />cp -a /dev/tty2 /mnt/initrd/dev<br /># Equate sbin with binpushd /mnt/initrd<br />ln -s bin sbinpopd<br /># Create the init file<br />cat &gt;&gt; /mnt/initrd/linuxrc &lt;&lt; EOF<br />#!/bin/ashecho<br />echo "Simple initrd is active"<br />echomount -t proc /proc /proc<br />mount -t sysfs none /sys/bin/ash --loginEOF<br />chmod +x /mnt/initrd/linuxrc<br /># Finish up...<br />umount /mnt/initrd<br />gzip -9 /tmp/ramdisk.img<br />cp /tmp/ramdisk.img.gz /boot/ramdisk.img.gz</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N10111">
																				<strong>initrd Linux 发行版</strong>
																		</a>
																		<br />
																		<p>Minimax 是一个开放源码项目，其设计目标是成为一个全部封装在 initrd 中的 Linux 发行版。它的大小是 32MB，为了尽量小，它使用了 BusyBox 和 uClibc。除了非常小之外，它还使用了 2.6 版本的 Linux 内核，并提供了很多有用的工具。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>为了创建 initrd，我们最开始创建了一个空文件，这使用了 <code>/dev/zero</code>（一个由零组成的码流）作为输入，并将其写入到 ramdisk.img 文件中。所生成的文件大小是 4MB（4000 个 1K 大小的块）。然后使用 <code>mke2fs</code> 命令在这个空文件上创建了一个 ext2（即 second extended）文件系统。现在这个文件变成了一个 ext2 格式的文件系统，我们使用 loop 设备将这个文件挂载到 /mnt/initrd 上了。在这个挂载点上，我们现在就有了一个目录，它以 ext2 文件系统的形式呈现出来，我们可以对自己的 initrd 文件进行拼装了。接下来的脚本提供了这种功能。</p>
		<p>下一个步骤是创建构成根文件系统所需要的子目录：/bin、/sys、/dev 和 /proc。这里只列出了所需要的目录（例如没有库），但是其中包含了很多功能。</p>
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N1012A">
																				<strong>ext2 文件系统的替代品</strong>
																		</a>
																		<br />
																		<p>尽管 ext2 是一种通用的 Linux 文件系统格式，但是还有一些替代品可以减小 initrd 映像文件以及所挂载上来的文件系统的大小。这种文件系统的例子有 romfs（ROM 文件系统）、cramfs（压缩 ROM 文件系统）和 squashfs（高度压缩只读文件系统）。如果我们需要暂时将数据写入文件系统中，ext2 可以很好地实现这种功能。最后，e2compr 是 ext2 文件系统驱动程序的一个扩展，可以支持在线压缩。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>为了可以使用根文件系统，我们使用了 BusyBox。这个工具是一个单一映像，其中包含了很多在 Linux 系统上通常可以找到的工具（例如 ash、awk、sed、insmod 等）。BusyBox 的优点是它将很多工具打包成一个文件，同时还可以共享它们的通用元素，这样可以极大地减少映像文件的大小。这对于嵌入式系统来说非常理想。将 BusyBox 映像从自己的源目录中拷贝到自己根目录下的 /bin 目录中。然后创建了很多符号链接，它们都指向 BusyBox 工具。BusyBox 会判断所调用的是哪个工具，并执行这个工具的功能。我们在这个目录中创建了几个链接来支持 init 脚本（每个命令都是一个指向 BusyBox 的链接。）</p>
		<p>下一个步骤是创建几个特殊的设备文件。我从自己当前的 /dev 子目录中直接拷贝了这些文件，这使用了 <code>-a</code> 选项（归档）来保留它们的属性。</p>
		<p>倒数第二个步骤是生成 linuxrc 文件。在内核挂载 RAM 磁盘之后，它会查找 <code>init</code> 文件来执行。如果没有找到 <code>init</code> 文件，内核就会调用 linuxrc 文件作为自己的启动脚本。我们在这个文件中实现对环境的基本设置，例如挂载 /proc 文件系统。除了 /proc 之外，我还挂载了 /sys 文件系统，并向终端打印一条消息。最后，我们调用了 <code>ash</code>（一个 Bourne Shell 的克隆），这样就可以与根文件系统进行交互了。linuxrc 文件然后使用 <code>chmod</code> 命令修改成可执行的。</p>
		<p>最后，我们的根文件系统就完成了。我们将其卸载掉，然后使用 <code>gzip</code> 对其进行压缩。所生成的文件（ramdisk.img.gz）被拷贝到 /boot 子目录中，这样就可以通过 GNU GRUB 对其进行加载了。</p>
		<p>要构建初始 RAM 磁盘，我们可以简单地调用 <code>mkird</code>，这样就会自动创建这个映像文件，并将其拷贝到 /boot 目录中。</p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N1015E">
						<span class="atitle">
								<font size="4">测试定制的初始 RAM 磁盘</font>
						</span>
				</a>
		</p>
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<font size="4">
												<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
										</font>
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="N10166">
																				<strong>Linux 内核中对 initrd 的支持</strong>
																		</a>
																		<br />
																		<p>对于 Linux 内核来说，要支持初始 RAM 磁盘，内核必须要使用 <code>CONFIG_BLK_DEV_RAM</code> 和 <code>CONFIG_BLK_DEV_INITRD</code> 选项进行编译。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>新的 initrd 映像现在已经在 /boot 目录中了，因此下一个步骤是使用默认的内核来对其进行测试。现在我们可以重新启动 Linux 系统了。在出现 GRUB 界面时，按 C 键启动 GRUB 中的命令行工具。我们现在可以与 GRUB 进行交互，从而定义要加载哪个内核和 initrd 映像文件。<code>kernel</code> 命令让我们可以指定内核文件，<code>initrd</code> 命令可以用来指定 initrd 映像文件。在定义好这些参数之后，就可以使用 <code>boot</code> 命令来引导内核了，如清单 5 所示。</p>
		<br />
		<a name="listing5">
				<strong>清单 5. 使用 GRUB 手工引导内核和 initrd </strong>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">    GNU GRUB  version 0.95  (638K lower / 97216K upper memory)<br />[ Minimal BASH-like line editing is supported. For the first word, TAB <br /> lists possible command completions. Anywhere else TAB lists the possible<br />  completions of a device/filename. ESC at any time exits.]<br />grub&gt; kernel /bzImage-2.6.1   [Linux-bzImage, setup=0x1400, size=0x29672e]<br />grub&gt; initrd /ramdisk.img.gz   [Linux-initrd @ 0x5f2a000, 0xb5108 bytes]<br />grub&gt; boot<br />Uncompressing Linux... OK, booting the kernel.</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>在内核启动之后，它会检查是否有 initrd 映像文件可用（稍后会更详细介绍），然后将其加载，并将其挂载成根文件系统。在清单 6 中我们可以看到这个 Linux 启动过程最后的样子。在启动之后，ash shell 就可以用来输入命令了。在这个例子中，我们将浏览一下根文件系统的内容，并查看一下虚拟 proc 文件系统中的内容。我们还展示了如何通过 touch 命令在文件系统中创建文件。注意所创建的第一个进程是 <code>linuxrc</code>（通常都是 <code>init</code>）。</p>
		<br />
		<a name="listing6">
				<strong>清单 6. 使用简单的 initrd 引导 Linux 内核 </strong>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">...md: Autodetecting RAID array<br />smd: autorun<br />md: ... autorun DONE.<br />RAMDISK: Compressed image found at block <br />0VFS: Mounted root (ext2 file system).<br />Freeing unused kernel memory: 208k freed/<br />$ ls<br />bin         etc       linuxrc       proc        sysdev         lib       lost+found    sbin/<br />$ cat /proc/1/cmdline/bin/ash/linuxrc/ <br />$ cd bin/bin $ lsash      cat      echo     mount    sysctlbusybox  dmesg    ls       ps/bin<br />$ touch zfile/bin <br />$ lsash      cat      echo     mount    sysctlbusybox  dmesg    ls       ps       zfile</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N101BE">
						<span class="atitle">
								<font size="4">使用初始 RAM 磁盘来引导系统</font>
						</span>
				</a>
		</p>
		<p>现在我们已经了解了如何构建并使用定制的初始 RAM 磁盘，本节将探索内核是如何识别 initrd 并将其作为根文件系统进行挂载的。我们将介绍启动链中的几个主要函数，并解释一下到底在进行什么操作。</p>
		<p>引导加载程序，例如 GRUB，定义了要加载的内核，并将这个内核映像以及相关的 initrd 拷贝到内存中。我们可以在 Linux 内核源代码目录中的 ./init 子目录中找到很多这种功能。</p>
		<p>在内核和 initrd 映像被解压并拷贝到内存中之后，内核就会被调用了。它会执行不同的初始化操作，最终您会发现自己到了 <code>init/main.c:init()</code>（subdir/file:function）函数中。这个函数执行了大量的子系统初始化操作。此处会执行一个对 <code>init/do_mounts.c:prepare_namespace()</code> 的调用，这个函数用来准备名称空间（挂载 dev 文件系统、RAID 或 md、设备以及最后的 initrd）。加载 initrd 是通过调用 <code>init/do_mounts_initrd.c:initrd_load()</code> 实现的。</p>
		<p>
				<code>initrd_load()</code> 函数调用了 <code>init/do_mounts_rd.c:rd_load_image()</code>，它通过调用 <code>init/do_mounts_rd.c:identify_ramdisk_image()</code> 来确定要加载哪个 RAM 磁盘。这个函数会检查映像文件的 magic 号来确定它是 minux、etc2、romfs、cramfs 或 gzip 格式。在返回到 <code>initrd_load_image</code> 之前，它还会调用 <code>init/do_mounts_rd:crd_load()</code>。这个函数负责为 RAM 磁盘分配空间，并计算循环冗余校验码（CRC），然后对 RAM 磁盘映像进行解压，并将其加载到内存中。现在，我们在一个适合挂载的块设备中就有了这个 initrd 映像。</p>
		<p>现在使用一个 <code>init/do_mounts.c:mount_root()</code> 调用将这个块设备挂载到根文件系统上。它会创建根设备，并调用 <code>init/do_mounts.c:mount_block_root()</code>。在这里调用 <code>init/do_mounts.c:do_mount_root()</code>，后者又会调用 <code>fs/namespace.c:sys_mount()</code> 来真正挂载根文件系统，然后 <code>chdir</code> 到这个文件系统中。这就是我们在清单 6 中所看到的熟悉消息 <code>VFS: Mounted root (ext2 file system).</code> 的地方。</p>
		<p>最后，返回到 <code>init</code> 函数中，并调用 <code>init/main.c:run_init_process</code>。这会导致调用 <code>execve</code> 来启动 init 进程（在本例中是 <code>/linuxrc</code>）。linuxrc 可以是一个可执行程序，也可以是一个脚本（条件是它有脚本解释器可用）。</p>
		<p>这些函数的调用层次结构如清单 7 所示。尽管此处并没有列出拷贝和挂载初始 RAM 磁盘所涉及的所有函数，但是这足以为我们提供一个整体流程的粗略框架。</p>
		<br />
		<a name="listing7">
				<strong>清单 7. initrd 加载和挂载过程中所使用的主要函数的层次结构 </strong>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">init/main.c:init  <br />init/do_mounts.c:prepare_namespace    <br />init/do_mounts_initrd.c:initrd_load      <br />init/do_mounts_rd.c:rd_load_image        <br />init/do_mounts_rd.c:identify_ramdisk_image        <br />init/do_mounts_rd.c:crd_load    <br />lib/inflate.c:gunzip    <br />init/do_mounts.c:mount_root      <br />init/do_mounts.c:mount_block_root         <br />init/do_mounts.c:do_mount_root           <br />fs/namespace.c:sys_mount  <br />init/main.c:run_init_process    <br />execve</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N10229">
						<span class="atitle">
								<font size="4">无盘引导</font>
						</span>
				</a>
		</p>
		<p>与嵌入式引导的情况类似，本地磁盘（软盘或 CD-ROM）对于引导内核和 ramdisk 根文件系统来说都不是必需的。DHCP（Dynamic Host Configuration Protocol）可以用来确定网络参数，例如 IP 地址和子网掩码。TFTP（Trivial File Transfer Protocol）可以用来将内核映像和初始 ramdisk 映像传输到本地设备上。传输完成之后，就可以引导 Linux 内核并挂载 initrd 了，这与本地映像引导的过程类似。 </p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N10232">
						<span class="atitle">
								<font size="4">压缩 initrd</font>
						</span>
				</a>
		</p>
		<p>在构建嵌入式系统时，我们可能希望将 initrd 映像文件做得尽可能小，这其中有一些技巧需要考虑。首先是使用 BusyBox（本文中已经展示过了）。BusyBox 可以将数 MB 的工具压缩成几百 KB。</p>
		<p>在这个例子中，BusyBox 映像是静态链接的，因此它不需要其他库。然而，如果我们需要标准的 C 库（我们自己定制的二进制可能需要这个库），除了巨大的 glibc 之外，我们还有其他选择。第一个较小的库是 uClibc，这是为对空间要求非常严格的系统准备的一个标准 C 库。另外一个适合空间紧张的环境的库是 dietlib。要记住我们需要使用这些库来重新编译想在嵌入式系统中重新编译的二进制文件，因此这需要额外再做一些工作（但是这是非常值得的）。</p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N1023E">
						<span class="atitle">
								<font size="4">结束语</font>
						</span>
				</a>
		</p>
		<p>初始 RAM 磁盘最初是设计用来通过一个临时根文件系统来作为内核到最终的根文件系统之间的桥梁。initrd 对于在嵌入式系统中加载到 RAM 磁盘里的非持久性根文件系统来说也非常有用。 </p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="resources">
						<span class="atitle">
								<font size="4">参考资料 </font>
						</span>
				</a>
		</p>
		<strong>学习</strong>
		<br />
		<ul>
				<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/linux/library/l-initrd.html?S_TACT=105AGX52&amp;S_CMP=cn-a-l" target="_blank"><font color="#5c81a7">英文原文</font></a> 。<br /><br /></li>
				<li>“<a href="http://www.ibm.com/developerworks/cn/linux/l-linuxboot/"><font color="#5c81a7">Linux 引导过程内幕</font></a>”（developerWorks，2006 年 5 月）探索了 Linux 从最初的 bootstrap 到启动第一个用户空间应用程序的过程。 <br /><br /></li>
				<li>在 “<a href="http://www.ibm.com/developerworks/cn/linux/l-fireboot.html"><font color="#5c81a7">从 FireWire 设备引导 Linux</font></a>”（developerWorks，2004 年 7 月）中，我们可以学习在各种平台的各种设备上如何（使用 initrd）启动 Linux。 <br /><br /></li>
				<li>
						<a href="http://www.mkssoftware.com/docs/man4/cpio.4.asp">
								<font color="#5c81a7">cpio 文件格式</font>
						</a> 既简单又简洁。因此 Fedora 团队选择使用它作为 initrd 的格式就没什么奇怪的了。 <br /><br /></li>
				<li>
						<a href="http://www.netadmintools.com/html/mkinitrd.man.html">
								<font color="#5c81a7">mkinitrd</font>
						</a> 工具非常适合创建 initrd 映像文件。除了创建 initrd 映像之外，它还可以确定要为您的系统加载哪些模块，并将这些模块也全部加入到这个映像中。 <br /><br /></li>
				<li>
						<a href="http://people.debian.org/~psg/ddg/node159.html">
								<font color="#5c81a7">loop 设备</font>
						</a> 是一个非常有用的驱动程序，可以将映像文件作为文件系统挂载。 <br /><br /></li>
				<li>
						<a href="http://www.ibiblio.org/pub/Linux/docs/howto/other-formats/pdf/Network-boot-HOWTO.pdf">
								<font color="#5c81a7">Network Boot and Exotic Root HOWTO</font>
						</a> 不但介绍了从网络上引导 Linux 的过程，还介绍了诸如软盘引导、CD-ROM 引导和嵌入式环境中的内容。 <br /><br /></li>
				<li>在 <a href="http://www.ibm.com/developerworks/cn/linux/"><font color="#5c81a7">developerWorks Linux 专区</font></a> 中可以找到为 Linux 开发人员准备的更多资源。 <br /><br /></li>
				<li>随时关注 <a href="http://www.ibm.com/developerworks/offers/techbriefings/?S_TACT=105AGX52&amp;S_CMP=cn-a-l"><font color="#5c81a7">developerWorks 技术事件和网络广播</font></a>。 </li>
		</ul>
		<br />
		<strong>获得产品和技术</strong>
		<br />
		<ul>
				<li>
						<a href="http://www.gnu.org/software/cpio/">
								<font color="#5c81a7">cpio 文件格式</font>
						</a>（现在可以用作 Fedora Core 的一种 initrd 映像格式）具有很长的历史，可以在很多 UNIX 系统上使用。 <br /><br /></li>
				<li>
						<a href="http://www.linuxfromscratch.org/blfs/view/6.1/postlfs/shells.html">
								<font color="#5c81a7">ash shell</font>
						</a> 是 Bourne Shell 的一个克隆（它们大部分是兼容的），它虽然很小，但是完全可以正常工作。它非常适合在对空间要求非常严格的嵌入式系统上用作脚本解释器。 <br /><br /></li>
				<li>
						<a href="http://www.busybox.net/">
								<font color="#5c81a7">BusyBox</font>
						</a> 是一种缩减您下一个嵌入式 Linux 项目内存需求的好方法。 <br /><br /></li>
				<li>要进一步缩减 initrd 文件的大小，请考虑使用 glibc 的替代库，例如 <a href="http://uclibc.org/"><font color="#5c81a7">uClibc</font></a> 或 <a href="http://www.fefe.de/dietlibc/"><font color="#5c81a7">dietlib</font></a>。如果您喜欢使用 C++，那么可以试用一下 <a href="http://cxx.uclibc.org/"><font color="#5c81a7">uClibc++</font></a> 库的 Alpha 版本。 <br /><br /></li>
				<li>
						<a href="http://www.kotek.net/minimax/">
								<font color="#5c81a7">Minimax</font>
						</a> 是一个完全封装在 initrd 映像文件中的 Linux 发行版！ <br /><br /></li>
				<li>
						<a href="http://www.ibm.com/developerworks/offers/sek/?S_TACT=105AGX52&amp;S_CMP=cn-a-l">
								<font color="#5c81a7">订购免费的 SEK for Linux</font>
						</a>，这有两张 DVD，包括最新的 IBM for Linux 的试用软件，包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。 <br /><br /></li>
				<li>在您的下一个开发项目中采用 <a href="http://www.ibm.com/developerworks/downloads/?S_TACT=105AGX52&amp;S_CMP=cn-a-l"><font color="#5c81a7">IBM 试用软件</font></a>，这可以从 developerWorks 上直接下载。 <br /><br /></li>
		</ul>
		<br />
		<strong>讨论</strong>
		<br />
		<ul>
				<li>通过参与 <a href="http://www.ibm.com/developerworks/blogs/?S_TACT=105AGX52&amp;S_CMP=cn-a-l"><font color="#5c81a7">developerWorks blogs</font></a> 加入 developerWorks 社区。 <br /><br /></li>
		</ul>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="author">
						<span class="atitle">
								<font size="4">关于作者</font>
						</span>
				</a>
		</p>
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td colspan="3">
										<font size="4">
												<img height="5" alt="" src="http://www.ibm.com/i/c.gif" />
										</font>
								</td>
						</tr>
						<tr valign="top" align="left">
								<td>
										<p>
												<font size="4">
														<img height="80" alt="M. Tim Jones" src="http://www.ibm.com/developerworks/i/p-mjones.jpg" width="64" align="left" border="0" name="M. Tim Jones" valign="top" />
												</font>
										</p>
								</td>
								<td>
										<font size="4">
												<img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" />
										</font>
								</td>
								<td>
										<p>Tim Jones 是一名嵌入式软件工程师，他是 <em>GNU/Linux Application Programming</em>、<em>AI Application Programming</em> 以及 <em>BSD Sockets Programming from a Multilanguage Perspective</em> 等书的作者。他的工程背景非常广泛，从同步宇宙飞船的内核开发到嵌入式架构设计，再到网络协议的开发。Tim 是 Emulex Corp. 的一名资深软件工程师。</p>
								</td>
						</tr>
				</tbody>
		</table> <br /><img src ="http://www.cnitblog.com/flutist1225/aggbug/19220.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/flutist1225/" target="_blank">Flutist</a> 2006-11-16 15:00 <a href="http://www.cnitblog.com/flutist1225/articles/19220.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux2.6 内核的 Initrd 机制解析（转）（五星）</title><link>http://www.cnitblog.com/flutist1225/articles/19214.html</link><dc:creator>Flutist</dc:creator><author>Flutist</author><pubDate>Thu, 16 Nov 2006 05:53:00 GMT</pubDate><guid>http://www.cnitblog.com/flutist1225/articles/19214.html</guid><wfw:comment>http://www.cnitblog.com/flutist1225/comments/19214.html</wfw:comment><comments>http://www.cnitblog.com/flutist1225/articles/19214.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/flutist1225/comments/commentRss/19214.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/flutist1225/services/trackbacks/19214.html</trackback:ping><description><![CDATA[
		<p>
				<a name="N1003D">
						<span class="atitle">
								<font size="4">1．什么是 Initrd</font>
						</span>
				</a>
		</p>
		<p>initrd 的英文含义是 boot loader initialized RAM disk，就是由 boot loader 初始化的内存盘。在 linux内核启动前， boot loader 会将存储介质中的 initrd 文件加载到内存，内核启动时会在访问真正的根文件系统前先访问该内存中的 initrd 文件系统。在 boot loader 配置了 initrd 的情况下，内核启动被分成了两个阶段，第一阶段先执行 initrd 文件系统中的"某个文件"，完成加载驱动模块等任务，第二阶段才会执行真正的根文件系统中的 /sbin/init 进程。这里提到的"某个文件"，Linux2.6 内核会同以前版本内核的不同，所以这里暂时使用了"某个文件"这个称呼，后面会详细讲到。第一阶段启动的目的是为第二阶段的启动扫清一切障爱，最主要的是加载根文件系统存储介质的驱动模块。我们知道根文件系统可以存储在包括IDE、SCSI、USB在内的多种介质上，如果将这些设备的驱动都编译进内核，可以想象内核会多么庞大、臃肿。</p>
		<p>Initrd 的用途主要有以下四种：</p>
		<p>1. linux 发行版的必备部件</p>
		<p>linux 发行版必须适应各种不同的硬件架构，将所有的驱动编译进内核是不现实的，initrd 技术是解决该问题的关键技术。Linux 发行版在内核中只编译了基本的硬件驱动，在安装过程中通过检测系统硬件，生成包含安装系统硬件驱动的 initrd，无非是一种即可行又灵活的解决方案。</p>
		<p>2. livecd 的必备部件</p>
		<p>同 linux 发行版相比，livecd 可能会面对更加复杂的硬件环境，所以也必须使用 initrd。</p>
		<p>3. 制作 Linux usb 启动盘必须使用 initrd</p>
		<p>usb 设备是启动比较慢的设备，从驱动加载到设备真正可用大概需要几秒钟时间。如果将 usb 驱动编译进内核，内核通常不能成功访问 usb 设备中的文件系统。因为在内核访问 usb 设备时， usb 设备通常没有初始化完毕。所以常规的做法是，在 initrd 中加载 usb 驱动，然后休眠几秒中，等待 usb设备初始化完毕后再挂载 usb 设备中的文件系统。</p>
		<p>4. 在 linuxrc 脚本中可以很方便地启用个性化 bootsplash。</p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N1005E">
						<span class="atitle">
								<font size="4">2．Linux2.4内核对 Initrd 的处理流程</font>
						</span>
				</a>
		</p>
		<p>为了使读者清晰的了解Linux2.6内核initrd机制的变化，在重点介绍Linux2.6内核initrd之前，先对linux2.4内核的initrd进行一个简单的介绍。Linux2.4内核的initrd的格式是文件系统镜像文件，本文将其称为image-initrd，以区别后面介绍的linux2.6内核的cpio格式的initrd。 linux2.4内核对initrd的处理流程如下：</p>
		<p>1. boot loader把内核以及/dev/initrd的内容加载到内存，/dev/initrd是由boot loader初始化的设备，存储着initrd。</p>
		<p>2. 在内核初始化过程中，内核把 /dev/initrd 设备的内容解压缩并拷贝到 /dev/ram0 设备上。</p>
		<p>3. 内核以可读写的方式把 /dev/ram0 设备挂载为原始的根文件系统。</p>
		<p>4. 如果 /dev/ram0 被指定为真正的根文件系统，那么内核跳至最后一步正常启动。</p>
		<p>5. 执行 initrd 上的 /linuxrc 文件，linuxrc 通常是一个脚本文件，负责加载内核访问根文件系统必须的驱动， 以及加载根文件系统。</p>
		<p>6. /linuxrc 执行完毕，真正的根文件系统被挂载。</p>
		<p>7. 如果真正的根文件系统存在 /initrd 目录，那么 /dev/ram0 将从 / 移动到 /initrd。否则如果 /initrd 目录不存在， /dev/ram0 将被卸载。</p>
		<p>8. 在真正的根文件系统上进行正常启动过程 ，执行 /sbin/init。 linux2.4 内核的 initrd 的执行是作为内核启动的一个中间阶段，也就是说 initrd 的 /linuxrc 执行以后，内核会继续执行初始化代码，我们后面会看到这是 linux2.4 内核同 2.6 内核的 initrd 处理流程的一个显著区别。</p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="N1007F">
						<span class="atitle">
								<font size="4">3．Linux2.6 内核对 Initrd 的处理流程</font>
						</span>
				</a>
		</p>
		<p>linux2.6 内核支持两种格式的 initrd，一种是前面第 3 部分介绍的 linux2.4 内核那种传统格式的文件系统镜像－image-initrd，它的制作方法同 Linux2.4 内核的 initrd 一样，其核心文件就是 /linuxrc。另外一种格式的 initrd 是 cpio 格式的，这种格式的 initrd 从 linux2.5 起开始引入，使用 cpio 工具生成，其核心文件不再是 /linuxrc，而是 /init，本文将这种 initrd 称为 cpio-initrd。尽管 linux2.6 内核对 cpio-initrd和 image-initrd 这两种格式的 initrd 均支持，但对其处理流程有着显著的区别，下面分别介绍 linux2.6 内核对这两种 initrd 的处理流程。</p>
		<p>
				<a name="N10088">
						<span class="smalltitle">
								<strong>
										<font size="3">cpio-initrd 的处理流程</font>
								</strong>
						</span>
				</a>
		</p>
		<p>1． boot loader 把内核以及 initrd 文件加载到内存的特定位置。</p>
		<p>2． 内核判断initrd的文件格式，如果是cpio格式。</p>
		<p>3． 将initrd的内容释放到rootfs中。</p>
		<p>4． 执行initrd中的/init文件，执行到这一点，内核的工作全部结束，完全交给/init文件处理。</p>
		<p>
				<a name="N1009A">
						<span class="smalltitle">
								<strong>
										<font size="3">image-initrd的处理流程</font>
								</strong>
						</span>
				</a>
		</p>
		<p>1． boot loader把内核以及initrd文件加载到内存的特定位置。</p>
		<p>2． 内核判断initrd的文件格式，如果不是cpio格式，将其作为image-initrd处理。</p>
		<p>3． 内核将initrd的内容保存在rootfs下的/initrd.image文件中。</p>
		<p>4． 内核将/initrd.image的内容读入/dev/ram0设备中，也就是读入了一个内存盘中。</p>
		<p>5． 接着内核以可读写的方式把/dev/ram0设备挂载为原始的根文件系统。</p>
		<p>6． .如果/dev/ram0被指定为真正的根文件系统，那么内核跳至最后一步正常启动。</p>
		<p>7． 执行initrd上的/linuxrc文件，linuxrc通常是一个脚本文件，负责加载内核访问根文件系统必须的驱动， 以及加载根文件系统。</p>
		<p>8． /linuxrc执行完毕，常规根文件系统被挂载</p>
		<p>9． 如果常规根文件系统存在/initrd目录，那么/dev/ram0将从/移动到/initrd。否则如果/initrd目录不存在， /dev/ram0将被卸载。</p>
		<p>10． 在常规根文件系统上进行正常启动过程 ，执行/sbin/init。</p>
		<p>通过上面的流程介绍可知，Linux2.6内核对image-initrd的处理流程同linux2.4内核相比并没有显著的变化， cpio-initrd的处理流程相比于image-initrd的处理流程却有很大的区别，流程非常简单，在后面的源代码分析中，读者更能体会到处理的简捷。</p>
		<p>
				<a name="N100C1">
						<span class="smalltitle">
								<strong>
										<font size="3">4．cpio-initrd同image-initrd的区别与优势</font>
								</strong>
						</span>
				</a>
		</p>
		<p>没有找到正式的关于cpio-initrd同image-initrd对比的文献，根据笔者的使用体验以及内核代码的分析，总结出如下三方面的区别，这些区别也正是cpio-initrd的优势所在：</p>
		<p>
				<a name="N100CA">
						<span class="smalltitle">
								<strong>
										<font size="3">cpio-initrd的制作方法更加简单</font>
								</strong>
						</span>
				</a>
		</p>
		<p>cpio-initrd的制作非常简单，通过两个命令就可以完成整个制作过程</p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">#假设当前目录位于准备好的initrd文件系统的根目录下<br />bash# find . | cpio -c -o &gt; ../initrd.img<br />bash# gzip ../initrd.img</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>而传统initrd的制作过程比较繁琐，需要如下六个步骤</p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">#假设当前目录位于准备好的initrd文件系统的根目录下<br />bash# dd if=/dev/zero of=../initrd.img bs=512k count=5<br />bash# mkfs.ext2 -F -m0 ../initrd.img<br />bash# mount -t ext2 -o loop ../initrd.img  /mnt<br />bash# cp -r  * /mnt<br />bash# umount /mnt<br />bash# gzip -9 ../initrd.img</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>本文不对上面命令的含义作细节的解释，因为本文主要介绍的是linux内核对initrd的处理，对上面命令不理解的读者可以参考相关文档。</p>
		<p>
				<a name="N100EB">
						<span class="smalltitle">
								<strong>
										<font size="3">cpio-initrd的内核处理流程更加简化</font>
								</strong>
						</span>
				</a>
		</p>
		<p>通过上面initrd处理流程的介绍，cpio-initrd的处理流程显得格外简单，通过对比可知cpio-initrd的处理流程在如下两个方面得到了简化：</p>
		<p>1． cpio-initrd并没有使用额外的ramdisk,而是将其内容输入到rootfs中，其实rootfs本身也是一个基于内存的文件系统。这样就省掉了ramdisk的挂载、卸载等步骤。</p>
		<p>2． cpio-initrd启动完/init进程，内核的任务就结束了，剩下的工作完全交给/init处理；而对于image-initrd，内核在执行完/linuxrc进程后，还要进行一些收尾工作，并且要负责执行真正的根文件系统的/sbin/init。通过图1可以更加清晰的看出处理流程的区别：</p>
		<br />
		<br />
		<a name="N100FC">
				<strong>图1内核对cpio-initrd和image-initrd处理流程示意图</strong>
		</a>
		<br />
		<img height="221" alt="图1内核对cpio-initrd和image-initrd处理流程示意图" src="http://www-128.ibm.com/developerworks/cn/linux/l-k26initrd/images/image001.gif" border="0" />
		<br />
		<p>
				<a name="N1010C">
						<span class="smalltitle">
								<strong>
										<font size="3">cpio-initrd的职责更加重要</font>
								</strong>
						</span>
				</a>
		</p>
		<p>如图1所示，cpio-initrd不再象image-initrd那样作为linux内核启动的一个中间步骤，而是作为内核启动的终点，内核将控制权交给cpio-initrd的/init文件后，内核的任务就结束了，所以在/init文件中，我们可以做更多的工作，而不比担心同内核后续处理的衔接问题。当然目前linux发行版的cpio-initrd的/init文件的内容还没有本质的改变，但是相信initrd职责的增加一定是一个趋势。</p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N10115">
						<span class="atitle">
								<font size="4">5．linux2.6内核initrd处理的源代码分析</font>
						</span>
				</a>
		</p>
		<p>上面简要介绍了Linux2.4内核和2.6内核的initrd的处理流程，为了使读者对于Linux2.6内核的initrd的处理有一个更加深入的认识，下面将对Linuxe2.6内核初始化部分同initrd密切相关的代码给予一个比较细致的分析，为了讲述方便，进一步明确几个代码分析中使用的概念：</p>
		<p>
				<strong>rootfs</strong>: 一个基于内存的文件系统，是linux在初始化时加载的第一个文件系统,关于它的进一步介绍可以参考文献[4]。</p>
		<p>
				<strong>initramfs</strong>: initramfs同本文的主题关系不是很大，但是代码中涉及到了initramfs，为了更好的理解代码，这里对其进行简单的介绍。Initramfs是在 kernel 2.5中引入的技术，实际上它的含义就是：在内核镜像中附加一个cpio包，这个cpio包中包含了一个小型的文件系统，当内核启动时，内核将这个cpio包解开，并且将其中包含的文件系统释放到rootfs中，内核中的一部分初始化代码会放到这个文件系统中，作为用户层进程来执行。这样带来的明显的好处是精简了内核的初始化代码，而且使得内核的初始化过程更容易定制。Linux 2.6.12内核的 initramfs还没有什么实质性的东西，一个包含完整功能的initramfs的实现可能还需要一个缓慢的过程。对于initramfs的进一步了解可以参考文献[1][2][3]。</p>
		<p>
				<strong>cpio-initrd</strong>: 前面已经定义过，指linux2.6内核使用的cpio格式的initrd。</p>
		<p>
				<strong>image-initrd</strong>: 前面已经定义过，专指传统的文件镜像格式的initrd。</p>
		<p>
				<strong>realfs</strong>: 用户最终使用的真正的文件系统。</p>
		<p>内核的初始化代码位于 init/main.c 中的 static int init(void * unused)函数中。同initrd的处理相关部分函数调用层次如下图，笔者按照这个层次对每一个函数都给予了比较详细的分析，为了更好的说明，下面列出的代码中删除了同本文主题不相关的部分：</p>
		<br />
		<br />
		<a name="N1013C">
				<strong>图2 initrd相关代码的调用层次关系图</strong>
		</a>
		<br />
		<img height="294" alt="图2 initrd相关代码的调用层次关系图" src="http://www-128.ibm.com/developerworks/cn/linux/l-k26initrd/images/image002.gif" border="0" />
		<br />
		<p>init函数是内核所有初始化代码的入口，代码如下，其中只保留了同initrd相关部分的代码。</p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">static int init(void * unused)<br />{<br />[1]	populate_rootfs();<br />[2]	if (sys_access((const char __user *) "/init", 0) == 0)<br />		execute_command = "/init";<br />	else		prepare_namespace();<br />[3]	if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) &lt; 0)<br />		printk(KERN_WARNING "Warning: unable to open an initial console.\n");<br />	(void) sys_dup(0);<br />	(void) sys_dup(0);<br />[4]	if (execute_command)<br />		run_init_process(execute_command);<br />	run_init_process("/sbin/init");<br />	run_init_process("/etc/init");<br />	run_init_process("/bin/init");<br />	run_init_process("/bin/sh");<br />	panic("No init found.  Try passing init= option to kernel.");}</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>代码[1]：populate_rootfs函数负责加载initramfs和cpio-initrd，对于populate_rootfs函数的细节后面会讲到。</p>
		<p>代码[2]：如果rootfs的根目录下中包含/init进程，则赋予execute_command,在init函数的末尾会被执行。否则执行prepare_namespace函数，initrd是在该函数中被加载的。</p>
		<p>代码[3]：将控制台设置为标准输入，后续的两个sys_dup(0),则复制标准输入为标准输出和标准错误输出。</p>
		<p>代码[4]：如果rootfs中存在init进程，就将后续的处理工作交给该init进程。其实这段代码的含义是如果加载了cpio-initrd则交给cpio-initrd中的/init处理，否则会执行realfs中的init。读者可能会问：如果加载了cpio-initrd, 那么realfs中的init进程不是没有机会运行了吗？确实，如果加载了cpio-initrd,那么内核就不负责执行realfs的init进程了，而是将这个执行任务交给了cpio-initrd的init进程。解开fedora core4的initrd文件，会发现根目录的下的init文件是一个脚本，在该脚本的最后一行有这样一段代码： </p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">………..switchroot --movedev /sysroot</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>就是switchroot语句负责加载realfs,以及执行realfs的init进程。</p>
		<p>
				<a name="N10170">
						<span class="smalltitle">
								<strong>
										<font size="3">对cpio-initrd的处理</font>
								</strong>
						</span>
				</a>
		</p>
		<p>对cpio-initrd的处理位于populate_rootfs函数中。</p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">void __init populate_rootfs(void){<br />[1]  char *err = unpack_to_rootfs(__initramfs_start,<br />			 __initramfs_end - __initramfs_start, 0);<br />[2]	if (initrd_start) {<br />[3]		err = unpack_to_rootfs((char *)initrd_start,<br />			initrd_end - initrd_start, 1);<br />[4]		if (!err) {<br />			printk(" it is\n");<br />			unpack_to_rootfs((char *)initrd_start,<br />				initrd_end - initrd_start, 0);<br />			free_initrd_mem(initrd_start, initrd_end);<br />			return;<br />		}<br />[5]		fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700);<br />		if (fd &gt;= 0) {<br />			sys_write(fd, (char *)initrd_start,<br />					initrd_end - initrd_start);<br />			sys_close(fd);<br />			free_initrd_mem(initrd_start, initrd_end);<br />		}<br />}</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>代码[1]：加载initramfs， initramfs位于地址__initramfs_start处，是内核在编译过程中生成的，initramfs的是作为内核的一部分而存在的，不是 boot loader加载的。前面提到了现在initramfs没有任何实质内容。</p>
		<p>代码[2]：判断是否加载了initrd。无论哪种格式的initrd，都会被boot loader加载到地址initrd_start处。</p>
		<p>代码[3]：判断加载的是不是cpio-initrd。实际上 unpack_to_rootfs有两个功能一个是释放cpio包，另一个就是判断是不是cpio包， 这是通过最后一个参数来区分的， 0：释放 1：查看。</p>
		<p>代码[4]：如果是cpio-initrd则将其内容释放出来到rootfs中。</p>
		<p>代码[5]：如果不是cpio-initrd,则认为是一个image-initrd，将其内容保存到/initrd.image中。在后面的image-initrd的处理代码中会读取/initrd.image。</p>
		<p>对image-initrd的处理在prepare_namespace函数里，包含了对image-initrd进行处理的代码，相关代码如下：</p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">void __init prepare_namespace(void){<br />[1]	if (initrd_load())<br />		goto out;<br />out:		umount_devfs("/dev");<br />[2]		sys_mount(".", "/", NULL, MS_MOVE, NULL);<br />		sys_chroot(".");<br />		security_sb_post_mountroot();<br />		mount_devfs_fs ();}</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>代码[1]：执行initrd_load函数，将initrd载入，如果载入成功的话initrd_load函数会将realfs的根设置为当前目录。</p>
		<p>代码[2]：将当前目录即realfs的根mount为Linux VFS的根。initrd_load函数执行完后，将真正的文件系统的根设置为当前目录。</p>
		<p>initrd_load函数负责载入image-initrd，代码如下：</p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">int __init initrd_load(void){<br />[1]	if (mount_initrd) {<br />		create_dev("/dev/ram", Root_RAM0, NULL);<br />[2]		if (rd_load_image("/initrd.image") &amp;&amp; ROOT_DEV != Root_RAM0) {<br />			sys_unlink("/initrd.image");<br />			handle_initrd();<br />			return 1;<br />		}<br />	}<br />	sys_unlink("/initrd.image");<br />	return 0;<br />}</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>代码[1]：如果加载initrd则建立一个ram0设备 /dev/ram。</p>
		<p>代码[2]：/initrd.image文件保存的就是image-initrd，rd_load_image函数执行具体的加载操作，将image-nitrd的文件内容释放到ram0里。判断ROOT_DEV!=Root_RAM0的含义是，如果你在grub或者lilo里配置了 root=/dev/ram0 ,则实际上真正的根设备就是initrd了，所以就不把它作为initrd处理 ，而是作为realfs处理。</p>
		<p>handle_initrd()函数负责对initrd进行具体的处理，代码如下：</p>
		<br />
		<br />
		<table cellspacing="0" cellpadding="5" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<code>
												<pre class="section">	static void __init handle_initrd(void){<br />[1]	real_root_dev = new_encode_dev(ROOT_DEV);<br />[2]	create_dev("/dev/root.old", Root_RAM0, NULL);<br />	mount_block_root("/dev/root.old", root_mountflags &amp; ~MS_RDONLY);<br />[3]	sys_mkdir("/old", 0700);<br />	root_fd = sys_open("/", 0, 0);<br />	old_fd = sys_open("/old", 0, 0);<br />	/* move initrd over / and chdir/chroot in initrd root */<br />[4]	sys_chdir("/root");<br />	sys_mount(".", "/", NULL, MS_MOVE, NULL);<br />	sys_chroot(".");<br />	mount_devfs_fs ();<br />[5]	pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);<br />	if (pid &gt; 0) {<br />		while (pid != sys_wait4(-1, &amp;i, 0, NULL))<br />			yield();<br />	}<br />	/* move initrd to rootfs' /old */<br />	sys_fchdir(old_fd);<br />	sys_mount("/", ".", NULL, MS_MOVE, NULL);<br />	/* switch root and cwd back to / of rootfs */<br />[6]	sys_fchdir(root_fd);<br />	sys_chroot(".");<br />	sys_close(old_fd);<br />	sys_close(root_fd);<br />	umount_devfs("/old/dev");<br />[7]	if (new_decode_dev(real_root_dev) == Root_RAM0) {<br />		sys_chdir("/old");<br />		return;<br />	}<br />[8]	ROOT_DEV = new_decode_dev(real_root_dev);<br />	mount_root();<br />[9]	printk(KERN_NOTICE "Trying to move old root to /initrd ... ");<br />	error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);<br />	if (!error)<br />		printk("okay\n");<br />	else {<br />		int fd = sys_open("/dev/root.old", O_RDWR, 0);<br />		printk("failed\n");<br />		printk(KERN_NOTICE "Unmounting old root\n");<br />		sys_umount("/old", MNT_DETACH);<br />		printk(KERN_NOTICE "Trying to free ramdisk memory ... ");<br />		if (fd &lt; 0) {<br />			error = fd;<br />		} else {<br />			error = sys_ioctl(fd, BLKFLSBUF, 0);<br />			sys_close(fd);<br />		}<br />		printk(!error ? "okay\n" : "failed\n");	}	</pre>
										</code>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>handle_initrd函数的主要功能是执行initrd的linuxrc文件，并且将realfs的根目录设置为当前目录。</p>
		<p>代码[1]：real_root_dev，是一个全局变量保存的是realfs的设备号。</p>
		<p>代码[2]：调用mount_block_root函数将initrd文件系统挂载到了VFS的/root下。</p>
		<p>代码[3]：提取rootfs的根的文件描述符并将其保存到root_fd。它的作用就是为了在chroot到initrd的文件系统，处理完initrd之后要，还能够返回rootfs。返回的代码参考代码[7]。</p>
		<p>代码[4]：chroot进入initrd的文件系统。前面initrd已挂载到了rootfs的/root目录。</p>
		<p>代码[5]：执行initrd的linuxrc文件，等待其结束。</p>
		<p>代码[6]：initrd处理完之后，重新chroot进入rootfs。</p>
		<p>代码[7]：如果real_root_dev在 linuxrc中重新设成Root_RAM0，则initrd就是最终的realfs了，改变当前目录到initrd中，不作后续处理直接返回。</p>
		<p>代码[8]：在linuxrc执行完后，realfs设备已经确定，调用mount_root函数将realfs挂载到root_fs的 /root目录下，并将当前目录设置为/root。</p>
		<p>代码[9]：后面的代码主要是做一些收尾的工作，将initrd的内存盘释放。</p>
		<p>到此代码分析完毕。</p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N101E2">
						<span class="atitle">
								<font size="4">6．结束语</font>
						</span>
				</a>
		</p>
		<p>通过本文前半部分对cpio-initrd和imag-initrd的阐述与对比以及后半部分的代码分析，我相信读者对Linux 2.6内核的initrd技术有了一个较为全面的了解。在本文的最后，给出两点最重要的结论：</p>
		<p>1． 尽管Linux2.6既支持cpio-initrd，也支持image-initrd，但是cpio-initrd有着更大的优势，在使用中我们应该优先考虑使用cpio格式的initrd。</p>
		<p>2． cpio-initrd相对于image-initrd承担了更多的初始化责任，这种变化也可以看作是内核代码的用户层化的一种体现，我们在其它的诸如FUSE等项目中也看到了将内核功能扩展到用户层实现的尝试。精简内核代码，将部分功能移植到用户层必然是linux内核发展的一个趋势。</p>
		<br />
		<table cellspacing="0" cellpadding="0" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="N101F1">
						<span class="atitle">
								<font size="4">参考资料</font>
						</span>
				</a>
		</p>
		<p>从下面三篇文章中，可以获得更多的关于initramfs的知识：</p>
		<p>[1]<a href="http://tree.celinuxforum.org/pubwiki/moin.cgi/EarlyUserSpace"><font color="#5c81a7">http://tree.celinuxforum.org/pubwiki/moin.cgi/EarlyUserSpace</font></a></p>
		<p>[2]<a href="http://lwn.net/Articles/14776/"><font color="#5c81a7">http://lwn.net/Articles/14776/</font></a></p>
		<p>[3]<a href="http://www.ussg.iu.edu/hypermail/linux/kernel/0211.0/0341.html"><font color="#5c81a7">http://www.ussg.iu.edu/hypermail/linux/kernel/0211.0/0341.html</font></a></p>
		<p>从下面这篇文章中读者可以了解到关于linux VSF、rootfs的相关知识：</p>
		<p>[4] <a href="http://www-128.ibm.com/developerworks/cn/linux/l-vfs/"><font color="#5c81a7">http://www-128.ibm.com/developerworks/cn/linux/l-vfs/</font></a></p>
		<p>下面是一些initrd的参考资料：</p>
		<p>[5] <a href="http://www.die.net/doc/linux/man/man4/initrd.4.html"><font color="#5c81a7">http://www.die.net/doc/linux/man/man4/initrd.4.html</font></a></p>
		<p>[6] <a href="http://www.gd-linux.org/bbs/archive/index.php/t-1661.html"><font color="#5c81a7">http://www.gd-linux.org/bbs/archive/index.php/t-1661.html</font></a></p>
		<br />
<img src ="http://www.cnitblog.com/flutist1225/aggbug/19214.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/flutist1225/" target="_blank">Flutist</a> 2006-11-16 13:53 <a href="http://www.cnitblog.com/flutist1225/articles/19214.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>