一、内核结构

1.1 内核在操作系统中的位置

  

  • 用户进程:用户应用程序是运行在 Linux 操作系统最高层的一个庞大的软件集合。当一个用户程序
    在操作系统之上运行时,它成为操作系统中的一个进程。
  • 系统调用接口:在应用程序中, 可通过系统调用来调用操作系统内核中特定的过程, 以实现特定的服务。
    • 系统调用本身也是由若干条指令构成的过程。但它与一般的过程不同,主要区别是:系统调用是运行在内核态(或叫系统态),而一般过程是运行在用户态。在 Linux 中,系统调用是内核代码的一部分 
  • Linux内核:内核是操作系统的灵魂,它负责管理磁盘上的文件、内存,负
    责启动并运行程序,负责从网络上接收和发送数据包等。简言之,内核实际是抽象的资源操
    作到具体硬件操作细节之间的接口。
  • 硬件

1.2 Linux内核抽象结构

  

 

  (1)进程调度(SCHED)控制着进程对 CPU 的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际是仅等待 CPU 资源的进程,如果某个进程在等待其他资源,则该进程是不可运行进程。Linux 使用了比较简单的基于优先级的进程调度算法选择新的进程。 

  (2)内存管理(MM)允许多个进程安全地共享主内存区域。Linux 的内存管理支持虚拟内存,即在计算机中运行的程序,其代码、数据和堆栈的总量可以超过实际内存的大小,操 作系统只将当前使用的程序块保留在内存中,其余的程序块则保留在磁盘上。必要时,操作系统负责在磁盘和内存之间交换程序块。 

  内存管理从逻辑上可以分为硬件无关的部分和硬件相关的部分。硬件无关的部分提供了进程的映射和虚拟内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 

  (3)虚拟文件系统(Virtul File System,VFS)隐藏了各种不同硬件的具体细节,为所有设备提供了统一的接口,VFS 还支持多达数十种不同的文件系统,这也是 Linux 较有特色的一部分 

   虚拟文件系统可分为逻辑文件系统和设备驱动程序。逻辑文件系统指 Linux 所支持的文件系统,如 ext2,fat 等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 

  (4)网络接口(NET)提供了对各种网络标准协议的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序两部分。网络协议部分负责实现每一种可能的网络传输协议,网络设备驱动程序负责与硬件设备进行通信,每一种可能的硬件设备都有相应的设备驱动程序。 

  (5)进程间通信(IPC) 支持进程间各种通信机制。

  linux 进程切换图:

  

 

1.3 内核源代码目录结构

  • arch :包含和硬件体系结构相关的代码,每种平台占一个相应的目录,如 i386、 arm、arm64、 powerpc、 mips 等。 Linux 内核目前已经支持 30 种左右的体系结构。在 arch 目录下,存放的是各个平台以及各个平台的芯片对 Linux 内核进程调度、内存管理、中断等的支持,以及每个具体的 SoC 和电路板的板级支持代码
  • block:块设备驱动程序 I/O 调度。
  • crypto:常用加密和散列算法(如 AES、 SHA 等),还有一些压缩和 CRC 校验算法。
  • documentation:内核各部分的通用解释和注释。
  • drivers :设备驱动程序,每个不同的驱动占用一个子目录,如 char、 block、 net、mtd、 i2c 等。
  • fs:所支持的各种文件系统,如 EXT、 FAT、 NTFS、 JFFS2 等。
  • include:头文件,与系统相关的头文件放置在 include/linux 子目录下。
  • init:内核初始化代码。著名的 start_kernel() 就位于 init/main.c 文件中。
  • ipc:进程间通信的代码。
  • kernel :内核最核心的部分,包括进程调度、定时器等,而和平台相关的一部分代码放在 arch/*/kernel 目录下
  • lib:库文件代码。
  • mm:内存管理代码,和平台相关的一部分代码放在 arch/*/mm 目录下。
  • net:网络相关代码,实现各种常见的网络协议。
  • scripts:用于配置内核的脚本文件。
  • security:主要是一个 SELinux 的模块。
  • sound: ALSA、 OSS 音频设备的驱动核心代码和常用设备驱动。
  • usr:实现用于打包和压缩的 cpio 等。
  • virt:内核 API 级别头文件。

 

1.4 内核源码读法

1.4.1 系统的启动和初始化

  当u-boot 把内核装入到内存中后,并把控制权传递给内核时,内核开始启动。启动可以看 arch/*/kernel/head.S,head.S进行特定结构的设置,然后跳转到 init/main.c 中执行。

1.4.2 内存管理

  内存管理的代码主要在 /mm 中,特定结构的代码在 arch/*/mm。缺页中断处理的代码在 /mm/memory.c,内存映射和页高速缓存器的代码在 mm/filemap.c 。缓冲器高速缓存是在mm/buffer.c 中实现,而交换高速缓存是在 mm/swap_state.c 和 mm/swapfile.c 中实现。

1.4.3 内核

  内核中,特定结构的代码在 arch/*/kernel,调度程序在 kernel/sched.c,fork 的代码在 kernel/fork.c,task_struct 数据结构在 include/linux/sched.h 中。

1.4.4 PCI

  PCI 伪驱动程序在 drivers/pci/pci.c ,其定义在 include/linux/pci.h。

1.4.5 进程间通信

  所有 System V IPC 对象权限都包含在 ipc_perm 数据结构中,这可以在include/linux/ipc.h 中找到, System V 消息是在 ipc/msg.c 中实现, 共享内存在 ipc/shm.c 中,信号量在 ipc/sem.c 中,管道在 ipc/pipe.c 中实现。

1.4.6 中断处理

  内核的中断处理代码是几乎所有的微处理器所特有的。

1.4.7 设备驱动程序

  Linux 内核源代码的很多行是设备驱动程序。Linux 设备驱动程序的所有源代码都保存在/driver,根据类型可进一步划分为:
  /block
    块设备驱动程序如 ide(在 ide.c)。如果想看包含文件系统的所有设备是如何被初始化的,应当看 drivers/block/genhd.c 中的 device_setup(),device_setup()不仅初始化了硬盘,当一个网络安装 nfs 文件系统时,它也初始化网络。块设备包含了基于 IDE 和 SCSI的设备。
  /char
    这是看字符设备(如 tty,串口及鼠标等)驱动程序的地方。
  /cdrom
    Linux 的所有 CDROM 代码都在这里, 如在这儿可以找到 Soundblaster CDROM 的驱动程序。
    注意 ide CD 的驱动程序是 ide-cd.c,放在 drivers/block;SCSI CD 的驱动程序是 scsi.c,放在 drivers/scsi。
  /pci
    这是 PCI 伪驱动程序的源代码,在这里可以看到 PCI 子系统是如何被映射和初始化的。
  /scsi
    在这里可以找到所有的 SCSI 代码及 Linux 所支持的 scsi 设备的所有设备驱动程序。
  /net
    在这里可以找到网络设备驱动程序,如 DECChip 21040 PCI 以太网驱动程序在 tulip.c 中。
  /sound
    这是所有声卡驱动程序的所在地。

1.4.8 文件系统

  EXT2 文件系统的源代码全部 在 fs/ext2/ 目录下,而其数据结构的定义在 include/linux/ ext2_fs.h,ext2_fs_i.h 及 ext2_fs_sb.h 中。虚拟文件系统的数据结构在 include/linux/fs.h 中描述,而代码是在 fs/* 中。 缓冲区高速缓存与更新内核的守护进程的实现是在 fs/buffer.c 中。

1.4.9 网络

  网络代码保存在/net 中,大部分的 include 文件在 include/net 下,BSD 套节口代码在 net/socket.c 中,IP 第 4 版本的套节口代码在 net/ipv4/af_inet.c。
  一般的协议支持代码(包括 sk_buff 处理例程)在 net/core 下,TCP/IP 联网代码在 net/ipv4 下,网络设备驱动程序在/drivers/net 下。

1.4.10 模块

  内核模块的代码部分在内核中,部分在模块包中,前者全部在 kernel/modules.c 中,而数据结构和内核守护进程 kerneld 的信息分别在 include/linux/module.h 和include/linux/kerneld.h 中。
  如果想看 ELF 目标文件的结构,它位于 include/linux/elf.h 中。

1.5 zImage生成过程

  通过内核初始化、内核配置、内核构建、内核安装过程,形成Linux内核并处于可启动状态。

  

1.5.1 内核初始化

  make distclean:执行 mrproper 命令,清除内核编译后生成的所有对象文件、备份文件等。

  make mrproper:只清除包括 .config 文件在内的、为内核编译及链接而生成的诸多设置文件。

  这两个命令可以使内核恢复到刚解压的状态。

  make clean:删除大多数生成的文件,留下编译的扩展模块。

  顶层的 Makefile 中可以查看到这三个命令

  

1.5.2 内核配置

  • 内核配置的三个工具:
    • make xconfig
    • make menuconfig
    • make gconfig
  • 在 scripts/Kconfig/Makefile 中可以查看到这些对象,各对象会执行与之对应的二进制文件。

  

  • 也可以使用 arch/$ARCH/configs 下的默认配置文件,进行修改。执行 make xxx_defconfig,就会生成  .config文件。
  • .config 文件是只构建自身内核所需的内核配置目录。在 CONFIG_XXX变量值中用y、n、m这三个状态进行内核配置的目录。这种形态的内核配置系统叫做 kconfig 。根据 kconfig 提供的三个状态(y n m)决定是否构建内核。
    • y:相应的二进制文件与 vmlinux 链接
    • n:不构建
    • m:虽然不会和 vmlinux 链接,但是作为模块执行编译。
  • mconf 通过 .config 配置文件生成 autoconf.h 头文件。可通过 scripts/kconfig/confdata.c 的conf_write_autoconf 函数得知 autoconf.h 的生成过程  
  • 内核利用以 .config 文件为背景生成的 autoconf.h 文件,在预处理阶段决定是否包含#ifdef 中的语句

1.5.3 内核构建

  • 构建内核是指编译内核并链接二进制文件,由此生成一个二进制文件 zImage 的过程。
  • 从顶端的 Makefile 开始编译内核,并通过因 Kbuild 系统而存在的 script 目录上的多个脚本文件生成 zImage 。

  

  

  

  

  

  KBUILD_IMAGE 的变量名为 zImage,最后执行 arch/arm/boot/Makefile 中的 Makefile 对象,如下:

  

  $(call if_changed,objcopy) 将执行script/Makefile.lib 中声明的  cmd_objcopy 。

  

  

  接着执行 arch/arm/boot/compressed/Makefile:

  

  生成 vmlinux 的映像结构如下:

  

  zImage的生成过程:

  

  

1.5.4 内核安装

  

 

 

  

  

 

posted @ 2018-03-10 22:46  游戏进行中  阅读(848)  评论(0编辑  收藏  举报