【嵌入式开发】 Linux Kernel 下载 配置 编译 安装 及 驱动简介(一)

一. 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 行;




-- 配置代码 :



config OPROFILE
    tristate "OProfile system profiling (EXPERIMENTAL)"
    depends on PROFILING
    depends on HAVE_OPROFILE
    select RING_BUFFER
    select RING_BUFFER_ALLOW_SWAP
    help
   OProfile is a profiling system capable of profiling the
   whole system, include the kernel, kernel modules, libraries,
   and applications.
   If unsure, say N.


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 文件的内容决定该子目录如何进行编译;


-- 其它状况 : 不编译;





上一篇:【IOS 开发】Objective - C 入门 之 数据类型详解(二)


下一篇:【Android 系统开发】Android JNI 之 JNIEnv 解析(一)