Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

README.md

📔 第 02 章 从内核出发 学习笔记

1. 获取内核源码

Linux内核官方地址:https://www.kernel.org/ 。获取到最新的tar形式压缩文件。

  • 使用Git

    Linux内核的Git源代码地址:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

    git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

    clone 代码完成后,更新到最新的分支。

  • 安装内核源代码

    • 直接git 获取的源代码,无需解压操作。
    • 内核压缩以GNU zip(gzip)bzip2 两种形式发布。但是下载的代码以 tar.gz 结尾。
    # 以 bzip2结尾
    tar -xvjf linux-6.9.tar.bz2
    # GNU的zip
    tar -xvzf linux-6.9.tar.gz
    • 内核源码一般安装在 /usr/src/linux/ 目录下。
    • 注意:不要以 root 身份对内核进行修改,仅以 root 身份安装新内核。
  • 使用补丁

    • 直接在内部源码树中运行:

      patch -pl <../patch-x.y.z>

2. 内核源码树

3. 编译内核

3.1 配置内核

  • 在编译内核之前,都需要配置所需的各种选项。而配置方式有多种:

    • 以 CONFIG_FEATURE 形式表示,其前缀为 CONFIG。

    • 内核提供了make命令行工具来简化内核配置。用户只需要选择yes、no或nodule即可。

      make config
    • 图形界面工具方式配置(ncurse库编写而成):

      make menuconfig
    • 基于 gtk+ 的图形工具:

      make gconfig
  • 配置选项被存放在内核源码树下的 .config 文件中。

  • 在配置完成后,直接使用 make 命令进行编译。

3.2 减少编译的垃圾信息

make > .. /destritus # 可以减少垃圾信息,但不会错过错误报告和警告信息

make > /dev/null  # 因为错误和警告都会在屏幕上显示,所以可以使用命令将无用的信息重定向到null黑洞中

3.3 衍生多个编译作业

通过make程序把编译过程分成多个并行的task,保证每个task都是并行执行,有助于加快处理器系统上的编译过程,提高处理器的利用率。

make -jn # n 是每个处理器上衍生出的线程任务数

make -j32 > /dev/null

3.4 安装新内核

模块的安装是自动的,也是独立于体系结构的。以root身份运行:

% make modules_install

命令执行后,就会把所有已编译的模块安装到主目录 /lib/modules 下。

4. 内核开发的特点

  • 内核编程时既不能访问C库,也不能访问标准的C头文件
  • 内核编程必须使用GNU C
  • 缺乏像用户空间的内存保护机制
  • 难以执行浮点运算
  • 内核给每个进程只有一个很小的定长堆栈
  • 内核支持异步中断、抢占和SMP,必须时刻注意同步和异步
  • 考虑可移植性的问题。

4.1 无libc库亦或是无标准头文件

  • 与用户空间的应用程序不同,内核不能链接使用标准C函数库。

  • 头文件指的是组成内核源代码树的内核头文件。

    • 内核源代码文件不能包含外部头文件,和不能使用外部库一样。
    • 基本的头文件位于源代码树顶级目录下的 include 目录中。
    • 体系结构相关的头文件位于 arch/<arch>/include/asm 目录下。
  • 内核不能使用 printf() 打印,但是提供了 printk() 函数。

    • printk() 函数:把格式化好的字符串拷贝到内核日志缓冲区上。syslog通过读取缓冲区来获取内核信息。

4.2 GNU C

Linux是C语言编写的,但内核并不完全符合ANSI C标准。

内核开发者使用的C语言覆盖了ISO C99 和 GNU C扩展特性。

内核代码中使用到的C语言扩展特性:

  • 内联(inline)函数

    • C99和 GNU C均支持内联函数。
    • 优点:可以消除函数调用和返回所带来的开销(寄存器存储和恢复)。
    • 缺点:代码变长,占用更多的内存空间或者更多的指令缓存。
    • 定义一个内联函数时,需要使用static作为关键字,并用inline限定。
    • 必须在使用之前在头文件中定义好函数。
    • 内核中,为了类型安全和易读性,优先使用内联而不是复杂的宏。
  • 内联汇编

    • gcc支持C函数中嵌入汇编代码。
  • 分支声明

    • gcc编译器内置了优化指令给条件选择语句。

4.3 没有内存保护机制

  • 如果一个用户程序试图进行一次非法的内存访问,内核会发现错误,发送SIGSEGV信号,并结束整个进程。

  • 内核中常见的错误:内核的内存错误会导致oops。

  • 内核中的内存不分页(用掉一个字节,物理内存就会减少一个字节)。

4.4 不要轻易在内核中使用浮点数

  • 不要在内核中使用浮点操作。

4.5 容积小而规定的栈

  • 用户空间的程序可以从栈上分配大量的空间存放变量,也可以进行内存的动态增长。

  • 内核栈的准确大小随着体系结构而变。

4.6 同步和并发

  • 内核容易产生竞争。内核的许多特性要求能并发访问共享数据,也要求有同步机制以保证不出现竞争条件。常见的情况:

    • Linux是抢占多任务操作系统。
    • Linux内核支持对称多处理器系统(SMP)
    • 中断的异步。

4.7 可移植性的重要性

  • 不同的体系结构和平台,就有不同的代码,但是为了兼容性的目标,就有一定的准则去达到可移植性的目的。