最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【转】Linux内核源码

工作和技术 crifan 1763浏览 0评论

【转】Linux内核源码

  首先研究 Linux 源代码树的顶层目录,它通常(但不总是)位于 /usr/src/linux-。我们不会研究得过于详细,因为 Linux 源代码经常会发生变化,但是,我们将尝试让给出的信息足以找出特定驱动程序或函数的位置。

  Makefile:这个文件是整个源代码树的顶层 makefile。它定义了很多实用的变量和规则,比如默认的 gcc 编译标记。

  Documentation/:这个目录中包含很多关于配置内核、运行 ramdisk 等任务的实用信息(但通常是过时的)。不过,与不同配置选项相应的帮助条目并不在这里 —— 它们在每个源代码目录的 Kconfig 文件中。

  arch/:所有与体系结构相关的代码都在这个目录以及 include/asm- 目录中。在此目录中,每种体系结构都有自己的目录。例如,用于基于 PowerPC 的计算机的代码位于 arch/ppc 目录中。在这些目录里,可以找到底层内存管理、中断处理、早期初始化、汇编例程,等等。

  crypto/:这是内核本身所用的加密 API。

  drivers/:按照惯例,在此目录的子目录中可以找到运行外围设备的代码。包括视频驱动程序、网卡驱动程序、底层 SCSI 驱动程序,以及其他类似的驱动程序。例如,在 drivers/net 中可以找到大部分网卡驱动程序。将一类驱动程序组合在一起的某些更高层代码,可能会(也可能不会)像底层驱动程序本身那些包含在同一目录中。

  fs/:通用文件系统的代码(称做 VFS,即 Virtual File System)和各个不同文件系统的代码都可以在这个目录中找到。ext2 文件系统是在 Linux 中最常广泛使用的文件系统之一;在 fs/ext2 中可以找到读取 ext2 格式的代码。并不是所有文件系统都会编译或运行;对某些寻找内核项目的人而言,更生僻的文件系统永远都是理想的候选者。

  include/:在 .c 文件的开头所包含的大部分头文件都可以在这个目录中找到。 asm- 目录下是与体系结构相关的包含(include )文件。部分内核构建过程创建从 asm 指定 asm- 的符号链接。这样,无需将其固定编码到 .c 文件 #include 就可以获得用于那个体系结构的正确文件。其他目录中包含的是 非-体系结构-相关 的头文件。如果在不只一个 .c 文件中使用了某个结构体、常量或者变量,那么它可能应该放入其中一个头文件中。

  init/:这个目录中的文件包括 main.c、创建 早期用户空间(early userspace) 的代码,以及其他初始化代码。可以认为 main.c 是内核“粘合剂(glue)”。在下一部分将深入讨论 main.c。早期用户空间提供了 Linux 内核引导起来时所需要的功能,而这些功能并不需要在内核本身运行。

  ipc/:IPC 的意思是 进程间通信(interprocess communication)。它包含了共享内存、信号量以及其他形式 IPC 的代码。

  kernel/:不适合放在任何其他位置的通用内核级代码位于此处。这里有高层系统调用代码,以及 printk() 代码、调度程序、信号处理代码,等等。文件名包含很多信息,所以可以使用 ls kernel/,并非能常准确地猜到每个文件的功能。

  lib/:这里是对所有内核代码都通用的实用例程。常见的字符串操作、调试例程,以及命令行解析代码都位于此处。

  mm/:这个目录中是高层次内核管理代码。联合使用这些例程以及底层的与体系结构相关的例程(通常位于 arch//mm/ 目录中)来实现虚拟内存(Virtual memory,VM)。在这里会完成早期内存管理(在内存子系统完全建立起来之前需要它),以及文件的内存映射、页高速缓存管理、内存分配、RAM 中页的清除(还有很多其他事情)。

  net/:这里是高层网络代码。底层网络驱动程序与此层次代码交换数据包,这个层次的代码可以根据数据包将数据传递给用户层应用程序,或者丢弃数据,或者在内核中使用它。net/core 包含大部分不同的网络协议都可以使用的代码,和某些位于 net/ 目录本身中的文件一样。特定的网络协议在 net/ 的子目录下实现。例如,在 net/ipv4 目录中可以找到 IP(版本 4)代码。

  scripts/:这个目录中包含的脚本可用于内核的构建,但并不将任何代码加入到内核本身之中。例如,各种配置工具可以将它们的文件放在这里。

  security/:在这里可以找到不同 Linux 安全模型的代码,比如 NSA Security-Enhanced Linux 以及套接字和网络安全钩子函数(hooks),以及其他安全选项。

  sound/:这里放置的是声卡驱动程序和其他与声音相关的代码。

  usr/:此目录中的代码用于构建包含 root 文件系统映像的 cpio-格式 的归档文件,用于早期用户空间。

  所有这些汇集在哪里?

  init/main.c 文件是整个 Linux 内核的中央联结点。每种体系结构都会执行一些底层设置函数,然后执行名为 start_kernel 的函数(在 init/main.c 中可以找到这个函数)。

  代码的执行顺序大致如下:

<font color="#333333" size="3">Architecture-specific set-up code (in arch//*)
 |
 v
The function start_kernel() (in init/main.c)
 |
 v
The function init() (in init/main.c)
 |
 v
The user level &quot;init&quot; program
</font>

  关于执行顺序的更多细节

  更详细地讲,发生的事情是:

  执行体系结构相关的设置代码:
    如果需要,解压缩并移动内核代码本身
    初始化硬件
    这可能包括底层内存管理的设置
    将控制权转交给函数 start_kernel()

  start_kernel() 去执行以下事情(以及其他事情):
    打印内核版本和命令行
    启动控制台输出
    启用中断
    校准延迟循环

  调用 rest_init(),这个函数会:
    启动一个内核线程来运行 init() 函数
    进入空闲循环
    init():
    启动其他处理器(在 SMP 机器上)
    启动设备子系统
    挂载 root 文件系统
    释放不使用的内核内存
    运行 /sbin/init(或者 /etc/init,或者…)

  此时,用户级 init 程序正在运行;它将完成启动网络设备并在控制台上运行 getty (登录程序)等任务。

  加入自己的 printk,并观察那个子系统的 printk 相对于自己的 printk 何时出现,就可以指出那个子系统是在 start_kernel() 中还是在 init() 中初始化的。例如,如果想要知道 ALSA 声音系统何时被初始化,那么将 printk 加入到 start_kernel() 和 init() 的起始处,然后找到“Advanced Linux Sound Architecture […]” 相对于您的 printk 在何处打印出来。

转载请注明:在路上 » 【转】Linux内核源码

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
79 queries in 0.194 seconds, using 22.13MB memory