《Linux4.0设备驱动开发详解》笔记--第二章:Linux内核及内核编程

时间:2022-04-05 10:29:40

2.1 Linux内核发展及演变

  • 1991年10月5日 Linus Torvalds创建
  • 五个支柱:Unix系统、Minix系统、GNU计划、POSIX标准和Internet
  • 每2-3个月更新一次大的版本号

2.2 Linux2.6后的内核特点

  1. 新的调度器:高负荷下的出色性能,更好的处理器扩展,采用CFS算法,新增调度类:SCHED_DEADLINE,它实现了EDF(最早截止期限优先)算法
  2. 内核抢占:提高系统的实时性,增强系统的交互性,但也有不可抢占的空间:中断上下文、软中断上下文和自旋锁的区间,如果打上RT-Preempt补丁,即可支持硬实时。
  3. 改进线程模型:采用NPTL(本地POSIX线程库)模型,操作速度极大提高,更加遵循POSIX规范
  4. 虚拟化内存变化:融合了r-map(反向映射,通过页结构快速找到页面的映射)技术,改善虚拟内存在一定大小负载下的性能
  5. 文件系统:新增基于B树的Btrfs,是下一代的Linux文件系统
  6. 音频:高级Linux音频体系结构ALSA取代缺陷很多的OSS,支持USB音频和MIDI设备,并支持双工重放等功能
  7. Linux3.7以后实现一个Linux可以适用于所有的arm系统

2.3 Linux内核组成

2.3.1 Linux内核代码的目录结构

  • arch:和硬件体系结构相关的代码,每个平台每个目录
  • block:块设备驱动的I/O调度
  • crypto:常用加密和散列算法,还有一些压缩以及CRC校验算法
  • documentation:内核各部分的通用解释和注释
  • fs:支持的各种文件系统
  • include:内核API级别的头文件,与系统相关的头文件放在include/linux子目录下
  • init:内核代码的初始化代码
  • ipc:进程间通信代码
  • lib:库文件代码
  • mm:内存管理代码
  • script:配置内核的脚本文件
  • usr:用于打包和压缩的cpio等

2.3.2 内核组成部分

  • 进程调度:多数进程是由用户空间创建,通过系统调用进入内核空间,内核编程是可以启动内核线程来处理并发任务,这些线程没有用户空间
  • 内存管理:控制多个进程安全的共享内存区域,通过MMU完成进程从虚拟空间向物理空间的转换
  • 虚拟文件系统:隐藏各个硬件的具体细节,为所有的设备提供了统一的接口,是文件系统的抽象
  • 网络接口:对各种网络标标准的存取和各种网络硬件的支持,分为网络协议和网络驱动程序
  • 进程间通信:信号量、共享内存、消息队列、管道以及Unix域套接字等

2.3.3 内核空间和用户空间

  • 内核可以进行任何操作,但应用程序被禁止对硬件的直接访问和对内存的未授权访问
  • 这两个名词用来区分程序执行的两种不同的状态,他们使用不同的地址空间,用户空间可以通过系统调用和硬件中断来访问内核空间

2.4 内核的编译及加载

2.4.1 Linux内核配置系统组成

  • Makefile:分布于内核源代码
  • 配置文件(Kconfig):给用户提供配置选项
  • 配置工具:命令解析器和配置用户界面,都是脚本语言
  • 通过make config、make menuconfig生成.config文件记录哪部分被编入内核,哪部分被编译成模块
  • source可以引入每一层的Kconfig

2.4.2 Kconfig和Makefile

2.4.2.1linux增加程序需要完成以下3项工作

  • 将编写的源码复制到Linux内核源代码相应得目录中
  • 在目录的Kconfig文件中增加关于源代码相应的编译配置选项
  • 在目录的Makefile文件中增加对新源代码的编译条目

2.4.1.2Makefile语法规则

  • 目标定义:用来定义哪些内容要作为模块编译,哪些要编译并链接进内核,如:obj-y/m/n += foo.o,obj-$(CONFIG_ISDN) += isdn.o
  • 多文件模块的定义:如下,模块名为ext2,有balloc.o、dir.o等目标文件最终链接生成ext2.o直至ext2.ko文件,是否包含xattr.o、acl.o等文件取决于内核配置文件的配置情况。
obj-$(CONFIG_EXT2_FS) += ext2.o
ext2-y :=balloc.o dir.o file.o ...
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o ...
ext2-$(CONGIF_EXT2_FS_XIP) += xip.o
  • 目标层次迭代:如下, 当CONFIG_EXT2_FS的值为y或者m时,kbuild将会把ext2目录列入向下的目录中
obj-$(CONFIG_EXT2_FS) += ext2/

2.4.2.3Kconfig语法规则

配置选项

大多数内核配置选项对应的Kconfig中的一个配置选项,”config” 关键字定义新的配置选项,之后的几行代码定义了诶配置选项的属性。配置选项的属性包含:类型,数据提示,依赖关系,选择关系以及帮助信息、默认值等

config MODVERSIONS
bool "Module versioning support"
help
Usually, you have to use modules compiled with your kernel.
Saying Y here makes it ...
  • 每个配置选择必须包含指定的类型,包括bool,tristate, string, hex 和int,其中tristate和string是基本的类型,其他类型都是基于这两种类型,类型定以后可以紧跟输入提示,下面两段脚本是等价的
bool "Networking support"

bool
prompt "Networking support"
  • 输入提示的一般格式为以下形式,其中可选的if用来表示该提示的依赖关系。
prompt <prompt> [if <expr>]

默认值的格式为以下形式,如果用户不设置对应的选项则配置选项的值就是默认值

default <expr> [if <expr>]
  • 依赖关系的格式为以下形式,多重依赖中间要用“&&”间隔
depends on (或者requires) <expr>

依赖关系也可以用在菜单中的其他选项,如下两段脚本是等价的

bool "foo" if BAR
default y if BAR

depends on BAR
bool "foo"
default y
  • 选择关系的格式如下,如果A选择了B,那么A选中的情况下自动选中B
select <symbol> [if <expr>]
  • 数据范围格式如下
range <symbol> <symbol> [if <expr>]
  • Kconfig中的expr定义如下
<expr> :: <symbol>
<symbol> '=' <symbol>
<symbol> '!' <symbol>
'(' <expr> ')'
'!' <expr>
<expr> '&&' <expr>
<expr> '||' <expr>

symbol分为两类,一类由菜单入口配置项定义的非常数symbol,另一类是作为expr组成部分常数symbol。比如

config SHDMA_R8A73A4
def_bool y
depends on ARCH_R8A73A4 && SH_DMA != n

表达式“depends on ARCH_R8A73A4 && SH_DMA !=n”暗示只有当ARCH_R873A4被选中,而SH_DMA没有选中的时候,才可能出现这个SHDMA_R8A73A4。

  • 为int和hex类型的选项设置可以接受的输入值范围,用户只能输入大于等于第一个symbol,且小于等于第二个symbol的值
  • 帮助信息的格式为
help(或---help---)
开始
...
结束

菜单结构

配置选项在菜单结构的中的位置可有两种方法决定。
第一种方法为:

menu "Network device support"
depends on NET
config NETDEVICES
...

所有处于“menu”和“endmenu”中的选项都会成为“Network device support”的子菜单,而且,所有的子菜单(config)选项都会继承父菜单(menu)的依赖关系,比如,“Network device support”对“NET”的依赖会被加载到配置选项NETDEVICES的依赖列表中。
注意:menu后面跟的“Network device support”项仅仅是一个菜单,没有对应真实的匹配项,也不具备不同的三种状态,这与config的区别。

另一种方法为:
同过分析依赖关系生成菜单结构。如菜单项在一定程度上依赖与前面的选项,他就能成为该选项的子菜单。如果父选项为“n”,子选项不可见;如果父选项可见,子选项才可见。例如:

config MODULES
bool "Enable loadable module support"

config MODVERSIONS
bool "Set version information on all module symbol"
depends on MODULES

comment "module support disabled"
depends on !MODULES

MODVERSIONS直接依赖MODULES,只有MODULES不为“n”时,该选项才可见。
除此之外,Kconfig中还可能使用“choices … endchoice”、”comment”、“if…endif”这样的语法结构。其中“choices … endchoice”的结构

choice
<choice options>
<choice block>
endchoice

它定义一个选择群,其接受的选项(choice potions)可以是前面描述的任何属性,例如,LDD6410的VGA输出分辨率可以是1024*768或者是800*600,在driver/video/samsung/Kconfig中就定了如下choice

choice
depends on FB_S3C_VGA
prompt "Select VGA Resolution for S3C Framebuffer"
default FB_S3C_VGA_1024_768
config FB_S3C_VGA_1024_768
bool "1024*768@60Hz"
---help---
TBA
config FB_S3C_VGA_640_480
bool "640*480@60Hz"
---help---
TAB
endchoice

上述例子中,prompt配合choice起到提示的作用。
具体例子见《Linux设备驱动开发详解》第三版 P72-73

2.4.3 Linux内核的引导

  1. 上电 => SOC嵌入bootrom 引导=> CPU0上的bootloader
  2. 其他非CPU0进入WFI状态等待CPU0唤醒
  3. CPU0引导bootloader唤醒非CPU0,唤醒后和CPU0都投入运行
  4. CPU0导致用户空间的init程序被调用,init派生出其他进程,其他进程在派生出其他进程
  5. bootloader代表为uboot,其代码仓库:http://git.devx.de/u-boot.git/
  6. zimage:是由未压缩的解压算法和压缩的内核组成,bootloader负责解压