一. Linux 内核简介
1. 内核功能简介
(1) 操作系统 和 内核 简介
操作系统 :
-- 功能 : 完成基本功能 和 系统管理;
-- 组成 : 内核(kernel), 设备驱动程序(driver), 启动引导程序(bootloader), 命令行(shell), 用户界面(UI), 文件系统(filesystem), 管理工具;
内核组成 :
-- 中断 : 响应中断的中断服务程序;
-- 调度 : 管理进程间调度的程序, 主要是调度 CPU 执行时间;
-- 内存 : 内存管理模块;
-- 通信 : 网络 进程间通信模块;
内核提供的保护机制 :
-- 系统态 : 能访问所有的内存空间 和 硬件设备, 用户态不能访问的空间是内核空间;
-- 用户态 : 只允许使用部分硬件资源的部分功能, 只能访问内核分配的内存;
(2) 系统调用
系统调用 : 应用程序 通过 系统调用 与内核通信;
-- 调用过程 : 一般先调用 库函数, 在通过库函数 调用内核方法;
库函数与系统调用关系 :
-- 系统调用是库函数的一部份 : 有的库函数需要多个系统调用来完成;
-- 一一对应 : 有的库函数 与 系统调用是一一对应的关系, 这种情况下, 相当与应用程序直接在内核运行, 即陷入内核;
(3) 硬件设备管理 和 中断
设备与内核通信过程 :
-- a. 打断内核 : 先发出异步中断信号, 打断处理器当前操作, 打断内核操作;
-- b. 查找中断 : 内核根据中断号查找中断服务程序, 调用程序的中断处理函数;
-- c. 中断示例 : 在编辑器中滑动鼠标滚轮, 鼠标会发出一个中断信号给内核, 鼠标的缓冲区有数据出现, 内核查找到中断来自鼠标, 调用中断处理程序, 执行想要的操作;
中断程序简介 :
-- 内核作用 : 执行哪个中断需要依靠内核来判断;
-- 中断运行环境 : 中断程序在一个与进程无关的, 专门用于运行中断处理程序的空间中执行, 这样做能保证在第一时间响应中断处理请求;
CPU的三个操作 : 每个 CPU 必定是三个中的一个;
-- 用户 进程 : 在用户空间, 执行用户进程;
-- 内核 进程 : 在内核空间, 处于进程上下文, 执行进程相关操作;
-- 内核 中断 : 在内核空间, 处于中断上下文, 处理中断;
(4) 内核划分
内核划分 : 内核是个很大的可执行文件, 会处理很多请求, 内核维持这几个并发的进程, 每个进程都会请求系统资源, 如 内存, 网络 CPU 等;
-- 进程管理 : 负责创建 销毁进程, 处理进程的输入输出, 以及进程间的交互;
-- 内存管理 : 内核的多个模块 与 内存管理系统通过一套函数进行交互操作;
-- 文件系统 : 内核在非结构化的硬件上建立起一套结构化的文件系统, Linux 支持多个文件系统, ext 是标准的文件系统;
-- 设备控制 : 每个操作系统都要映射到一个物理设备上, 内核中需要包含所有的驱动;
-- 网络控制 : 网络是由操作系统进行控制的, 其消息一般是异步的;
(5) 用户空间 和 内核空间
用户空间 : 权限较低的空间, 该空间对 设备 和 内存的访问都会受到限制;
内核空间 : 权限最高, 该空间可以执行任何操作, 可以访问所有的设备 和 内存空间;
用户空间转到内核空间 : 应用程序发出一个系统调用 或者 被硬件中断挂起的时候, 会从用户空间转到内核空间;
(6) 内核模块
模块特点 :
-- 注册 : 模块需要预先注册, 才能进行动态加载;
-- 功能 : 模块实现驱动程序, 文件系统等功能;
-- 加载 : 加载之后模块运行于内核空间, 与内核组成一体;
模块相关函数 :
-- init_module : 加载模块时调用, 预先准备模块中的函数和变量;
-- cleanup_module : 模块卸载前调用;
模块相关命令 :
-- insmod : 加载模块, 格式 insmod file_name ;
-- rmmod : 卸载模块, 格式 rmmod file_name ;
-- lsmod : 列出当前使用的模块, 或者查看 /proc/modules 目录;
-- modprobe : 探测并加载内核模块, 给出模块名称, 自动寻找加载模块, 与 insmod 命令的不同之处是可以自动寻找依赖的模块;
-- depmod : 给模块生成依赖文件, 生成 /lib/modules/3.11.0-15-generic 文件;
2. Linux 与 UNIX 内核 对比
UNIX 内核运行状况 : UNIX 内核是一个 不可分割的静态可执行库, 其运行的时候 必须在一个 单独的地址空间中运行 这个可执行块;
Linux UNIX 内存管理比较 : MMU 方面;
-- UNIX 内存管理 : UNIX 必须有 MMU (Memory Management Unit 内存管理单元) 页机制, 该页机制加强对内存保护, 每个进程运行在不用的虚拟地址上;
-- Linux 内存管理 : Linux 可以运行在没有 MMU 的系统上;
单内核 : 从整体上将内核作为一个单独的过程来实现, 运行在一个单独的地址空间中;
-- 内核间服务通信 : 所有的内核服务都运行在同一空间, 可以直接互相调用;
-- 特点 : 该设计使系统简单, 性能比较高;
-- 但内核系统 : 多数的 UNIX 系统, Linux 系统;
微内核(设计) : 内核的功能分为多个独立过程, 每个过程叫做服务器, 所有的服务器都运行在独立空间中;
-- 服务器运行空间 : 只有一部份服务器能运行在内核空间中, 其它的服务器在用户空间中运行;
-- 服务器间消息传递 : 采用 进程间通信 IPC 机制, 内核的各个服务器通过 IPC 机制进行通信;
-- 服务器空间切换 : 在用户空间运行的服务器可以切换到内核空间运行;
微内核的一些设计缺陷 :
-- 开销大 : 微内核的 IPC 进程间通信开销很大, 比函数调用要多;
-- 上下文切换 : 运行在 内核空间 和 用户空间的 服务器之间进行切换需要时间;
实际实施的微内核 :
-- 服务器位置 : 多数的服务器位于内核空间, 服务器之间可以相互进行函数调用, 尽量避免使用 IPC 机制 和 上下文切换;
-- 微内核系统 : Windows 和 Mac OS;
Linux 内核设计 : 模块化的 多线程 以及内核可调度;
-- 运行空间 : Linux 内核是单内核, 运行在内核空间, 直接调用函数, 无需 IPC 消息传递;
-- 吸取的微内核的精华 : 模块化设计, 抢占式内核, 支持内核线程, 动态装载内核模块;
Linux 与 UNIX 差异 :
-- 对动态加载模块的支持 : Linux 在需要的时候 动态卸载 和 加载部分内核代码, UNIX 内核是不可分割的可执行库;
-- 对 SMP 机制的支持 : SMP (Symmetric Multi-Processing) 对称多处理机制, 多 CPU 机器上 各 CPU 共享内核和总线资源, Linux 支持, 传统 UNIX 不支持;
-- 对抢占支持 : Linux 内核允许在内核执行任务的时候, 优先执行一些任务; 多数 UNIX 不支持;
-- 对线程支持 : Linux 内核不区分线程和进程, 所有的进程对与内核都是一样的;
二. 下载 配置 编译内核源码
1. 下载内核源码
(1) 从官网下载内核
内核官网 : https://www.kernel.org/ ;
-- 2.6 最稳定版下载地址 : https://www.kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.32/linux-2.6.32.63.tar.xz ;
-- 3.16.1 最新的稳定版本内核地址 : https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.16.1.tar.xz ;
-- 3.14.17 最新内核下载地址(不稳顶) : https://www.kernel.org/pub/linux/kernel/v3.x/testing/linux-3.17-rc1.tar.xz ;
tar.xz 压缩文件解压方法 : tar -xvJf linux-2.6.32.63.tar.xz ;
(2) 使用 Git 下载
Git下载地址 : git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git ;
-- 下载代码命令 : git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git;
-- 提交代码命令 : git pull;
-- 下载过程 :
octopus@octopus:~/develop/git/linux_kernel$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git Cloning into 'linux-2.6'... remote: Counting objects: 3754628, done. remote: Compressing objects: 100% (566292/566292), done. remote: Total 3754628 (delta 3165631), reused 3747365 (delta 3158382) Receiving objects: 100% (3754628/3754628), 793.85 MiB | 435 KiB/s, done. Resolving deltas: 100% (3165631/3165631), done.
2. 内核源码树介绍
Ubuntu 内核源码地址 : /usr/src/linux-headers-3.11.0-15 ;
-- Ubuntu 内核源码目录 :
root@octopus:/usr/src/linux-headers-3.11.0-15# ls arch crypto drivers fs init Kbuild kernel Makefile net scripts sound ubuntu virt block Documentation firmware include ipc Kconfig lib mm samples security tools usr
标准Linux内核 :
-- 2.6 最稳定版内核 : linux-2.6.32.63.tar.xz, 解压命令 tar -xvJf linux-2.6.32.63.tar.xz ;
-- 内核目录 :
octopus@octopus:~/uplooking/kernel/linux-2.6.32.63$ ls arch CREDITS drivers include Kbuild MAINTAINERS net samples sound virt block crypto firmware init kernel Makefile README scripts tools COPYING Documentation fs ipc lib mm REPORTING-BUGS security usr
内核目录文件解析 :
-- arch : 特定体系结构源码, 这里为 x86 arm 不同型号的 cpu 准备了不同的源码;
-- block : 块设备相关 I/O 层;
-- crypto : 加密相关的 api;
-- Documention : 内核源码文档;
-- drivers : 设备驱动程序;
-- firmware : 使用驱动程序需要的设备固件;
-- fs : 文件系统;
-- including : 内核头文件;
-- init : 内核引导和初始化;
-- ipc : 进程通信代码;
-- kernel : 内核的核心系统;
-- lib : 通用的内核函数;
-- mm : 内存管理模块;
-- net : 网络系统模块;
-- sample : 示例代码;
-- scripts : 编译内核的脚本;
-- security : 安全模块;
-- sound : 语音模块;
-- usr : 用户空间代码;
-- tools : Linux 工具;
-- virt : 虚拟化基础结构;
文件介绍 :
-- COPYING : 内核许可证;
-- CREDITS : 内核开发者列表;
-- MAINTAINERS : 维护者列表;
-- Makefile : make 编译脚本;
3. 内核配置
(1) 命令行配置
使用 make config 命令 : 该命令会逐一遍历所有配置项, 用户自己选择 yes(y) no(N) module(?), 所需时间很长;
-- 配置详情 :
octopus@octopus:~/uplooking/kernel/linux-2.6.32.63$ make config scripts/kconfig/conf arch/x86/Kconfig * * Linux Kernel Configuration * * * General setup * Prompt for development and/or incomplete code/drivers (EXPERIMENTAL) [N/y/?]
(2) 使用图形界面
使用 make menuconfig 命令 :
-- 图形界面 :
(3) make menu 配置解析
配置保存文件 : make menu 图形界面保存的配置文件是在根目录下的 .config 文件, 该文件中保存这 一个个的键值对;
-- 配置文件内容 :
# # Automatically generated make config: don't edit # Linux kernel version: 2.6.32.63 # Mon Aug 18 17:17:46 2014 # # CONFIG_64BIT is not set CONFIG_X86_32=y # CONFIG_X86_64 is not set CONFIG_X86=y CONFIG_OUTPUT_FORMAT="elf32-i386" CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig" CONFIG_GENERIC_TIME=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_CLOCKSOURCE_WATCHDOG=y CONFIG_GENERIC_CLOCKEVENTS=y Kconfig 中变量解析 : -- tristate : 能取值 y, n 和 m, 对应配置界面中的 <>; -- bool : 是 tristate 的一种, 只能取值 y 和 n, 对应配置界面的 []; -- string : 取值字符串; -- hex : string 的一种, 取值十六进制数; -- int : string 的一种, 取值十进制数;
显示详细配置解析 : 在 menuconfig 中将光标停在配置项, 然后按下 ? 键, 即可弹出详细配置信息;
-- 示例图片 : 其中说明了该配置项作用, 以及配置文件位置, 该配置项的位置在 /arch/Kconfig 中的第 5 行;
-- 配置代码 :
Kconfig 中的配置解析 :
-- config : 变量名;
-- tristate : menuconfig 界面中显示的选项名称;
-- default : 默认值;
-- depends on : 依赖哪些变量;
-- select : 选择变量;
-- help : 帮助信息, menuconfig 中光标移动到选项上, 点击 ? 显示的信息;
Makefile 对 .config 的依赖 :
a. obj-$(CONFIG_PLIP) + = plip.o 选项 : CONFIG_PLIP 这个选项定义在 .config 文件中;
-- CONFIG_PLIP=y : 那么将编译本目录下的 plip.c 文件并将其功能集成进 zimage;
-- CONFIG_PLIP=n : 不编译;
-- CONFIG_PLIP=m : 那么将编译本目录下的 plip.c 文件生成模块 plip.ko;
b. obj-$(CONFIG_GIANFAR) + = gianfar_driver.o 选项 :
-- CONFIG_GIANFAR = y : 编译本目录下的 ianfar.c,gianfar_ethtool.c,gianfar_mii.c,gianfar_sysfs.c 文件并将其功能集成进 zimage;
-- CONFIG_GIANFAR = n : 不编译;
-- CONFIG_GIANFAR = m : 以上文件生成模块gianfar_driver.ko;
c. obj-$(CONFIG_ATL1) + = atl1 选项 :
-- CONFIG_ATL1 = y : 递归进入本目录的字目录 atl1, 并根据该子目录下的 Makefile 文件的内容决定该子目录如何进行编译;
-- 其它状况 : 不编译;