作者 : 韩曙亮
转载请出名出处 : http://blog.csdn.net/shulianghan/article/details/38636827
一. 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;
-- 下载过程 :
代码语言:javascript复制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 内核源码目录 :
代码语言:javascript复制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 ;
-- 内核目录 :
代码语言:javascript复制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(?), 所需时间很长;
-- 配置详情 :
代码语言:javascript复制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 文件, 该文件中保存这 一个个的键值对;
-- 配置文件内容 :
代码语言:javascript复制#
# 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 行;
-- 配置代码 :
代码语言:javascript复制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 文件的内容决定该子目录如何进行编译;
-- 其它状况 : 不编译;
4. 内核编译
简单命令 : 直接使用 make 命令进行编译;
过滤命令行输入 : 将 make 编译信息输出到文件中, 警告 和 错误 会输出到命令行;
-- 输出发到文件 : 使用 make > ../make_log 命令, 会自动将无关的日志存放到 make_log 文件中, 错误和警告提示会显示出来;
-- 输出到黑洞 : 使用 make > /dev/null 命令, 输出的日志信息会自动;
并行编译 : make 可以进行多作业并行编译, 在多核的机器上这样进行编译效率很高;
-- 并行编译弊端 : 如果 Makefile 出现依赖错误, 并行编译会报错, 使用 单作业 make 可以编译通过, 内核无此类错误, 可以并行编译;
-- 使用命令 : make -jn , 其中 n 是一个整数, 例如 make -j4 就是开起 4 个作业同时编译;
-- 多作业编译并输出文件 : make -j4 > make_log, 开启四个作业同时进行编译, 并将编译输出信息存放到 make_log 中;
编译过程 : 使用 make -j4 > make_log 命令, 省略了一部份;
代码语言:javascript复制octopus@octopus:~/uplooking/kernel/linux-2.6.32.63$ make -j4 > make_log
scripts/mod/modpost.c: In function ‘get_markers’:
scripts/mod/modpost.c:1562: warning: ignoring return value of ‘asprintf’, declared with attribute warn_unused_result
scripts/mod/modpost.c: In function ‘add_marker’:
scripts/mod/modpost.c:1982: warning: ignoring return value of ‘asprintf’, declared with attribute warn_unused_result
scripts/kallsyms.c: In function ‘read_symbol’:
scripts/kallsyms.c:112: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result
WARNING: modpost: Found 2 section mismatch(es).
To see full details build your kernel with:
'make CONFIG_DEBUG_SECTION_MISMATCH=y'
5. 安装内核
(1) 安装内核
编译和安装系统 : 本人用的 Ubuntu 系统, 安装内核比较麻烦, 这里只列出 Redhat 系统安装内核的流程, 即 在 ubuntu 上编译, 在 Redhat 上安装;
a. 内核文件位置
文件位置 : 编译好的内核位于 arch 对应体系结构的目录下的 boot 目录下;
-- 使用默认编译好的配置内核地址 : arch/i386/boot ;
代码语言:javascript复制octopus@octopus:~/uplooking/kernel/linux-2.6.32.63/arch/i386/boot$ ls
bzImage
b. 拷贝内核文件
/boot 目录 : 内核文件存放在 /boot 目录下, 下面列举除了 boot 目录下的文件;
代码语言:javascript复制[root@ip28 boot]# ls
config-2.6.18-164.el5 initrd-2.6.18-164.el5.img System.map-2.6.18-164.el5
grub symvers-2.6.18-164.el5.gz vmlinuz-2.6.18-164.el5
-- 内核文件 : 其中的 vmlinuz-2.6.18-164.el5 就是内核, 将 bzImage 文件改名为 vmlinuz-2.6.32.63 即可, 后面是版本号, 该版本是 Linux 内核的 2.6.32.63 版本;
c. 修改 grub.conf 文件
文件位置 : 每个系统中该文件的位置不同, 在 redhat 中内核配置文件是 /etc/grub.conf 文件;
代码语言:javascript复制# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE: You do not have a /boot partition. This means that
# all kernel and initrd paths are relative to /, eg.
# root (hd0,0)
# kernel /boot/vmlinuz-version ro root=/dev/hda1
# initrd /boot/initrd-version.img
#boot=/dev/hda
default=0
timeout=5
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
hiddenmenu
title Red Hat Enterprise Linux Server (2.6.18-164.el5)
root (hd0,0)
kernel /boot/vmlinuz-2.6.18-164.el5 ro root=LABEL=/ console=tty0 console=ttyS0,9600n8 ide0=noprobe clock=tsccount
initrd /boot/initrd-2.6.18-164.el5.img
(2) 安装模块
模块安装介绍 : modules 安装可以自动完成, 首先切入到 root 权限下, 执行 make modules_install 命令, 即可将编译好的模块安装到 /lib/modules 目录下;
(3) 符号对照表
生成目录 : 编译的是时候在内核源码根目录生成一个 System.map 的对照表, 这份对照表是 内核中的符号 和 地址对应起来, 比如函数的地址, 变量的地址等;
代码语言:javascript复制00000000 A VDSO32_PRELINK
00000040 A VDSO32_vsyscall_eh_frame_size
000001d5 A kexec_control_code_size
00000400 A VDSO32_sigreturn
0000040c A VDSO32_rt_sigreturn
00000414 A VDSO32_vsyscall
00000424 A VDSO32_SYSENTER_RETURN
01000000 A phys_startup_32
c1000000 T _text
c1000000 T startup_32
c1000054 t default_entry
三. 内核开发
1. 关于头文件
不能使用标准库 : 内核中是不存在 标准库 和 标准头文件的;
-- 没有引用 : 标准库实质上就是调用内核中的东西, 此时内核还不存在;
-- 性能考虑 : 链接执行标准库性能很低, 对于内核来说降低性能是致命的;
使用头文件 : 内核中实现了大部分 C 函数, 只要将相关的头文件引入即可;
-- 基本头文件 : 这类头文件在 include 目录下的, 如 字符串处理相关的头文件路径是 include/linux/string.h, 引入 <linux/string.h> 即可使用里面的方法;
-- 体系结构相关头文件 : 这类头文件在 arch/architecture/include/asm 目录下, 如 x86 相关的体系结构头文件在 arch/x86/include/asm 目录下, 引入的时候引入 <asm/xxx.h> 即可;
2. 内核 C 语言标准
内核C语言符合的标准 : 内核不符合 ANSI C 标准, 符合 ISO C99 和 GNU C 标准;
(1) 内联函数
内联函数介绍 : 函数会在其调用的位置展开, 没有函数调用和返回的开销;
-- 函数调用开销 : 函数调用的时候需要 寄存器的存储和恢复;
-- 内联函数优点 : 编译器会把函数代码和其本身一起优化;
-- 内联函数缺点 : 代码展开后会占用跟多空间, 占用更多的指令缓存, 内核中把对时间要求高 并且 本身比较短 的函数定义为内联函数;
内联函数定义 : 使用 sttaic inline 限定函数;
-- 示例 : static inline void hello(char * argv);
-- 使用 static 限制 : 编译时不会为其创建函数体;
(2) 内联汇编
嵌入汇编 : 使用 asm() 指令嵌入汇编;
-- 前提 : C 语言中嵌入的汇编需要与体系结构对应才可以, 例如在笔记本上执行的 C 程序必须嵌入 x86 的汇编才可以, 不能使用 arm 汇编;
-- 示例 : asm volatile("mov %1, %0nt" : "=r"(output) : "r"(input));
-- 使用场景 : 在内核中 体系结构底层代码 或者 对时间要求严格的地方使用 汇编语言实现;
(3) 分支声明
选择优化 : gcc 编译器会根据分支选择优化, 条件很少出现的代码不进行优化, 条件很多时候出现的时候才优化;
-- 示例 : likely() 和 unlikely();
标记分支示例 : if(istrue){} 是条件;
-- 标记为很少发生的情况 : if(unlikely(istrue)){};
-- 标记为经常发生的情况 : if(likely(istrue)){};
3. 关于内存保护机制
用户空间的内存保护 : 当用户程序出现非法内存访问, 内核就会发送错误信号, 杀死整个进程;
内核出现内存非法访问 : 会导致整个内核 oops, 这种错误很常见, 而且很难排查;
-- 技巧 : 内核中的内存不分页, 用掉哪些内存都要记住, 否则会出现错误;
4. 关于浮点数
用户空间使用浮点数 : 用户进行浮点运算的时候, 内核会进行从整数到浮点数操作的模式转换;
内核空间使用浮点数 : 内核不能完美支持浮点操作, 其本身不能陷入, 如果非要使用的话 需要人工操作浮点寄存器, 过程相当繁琐;
5. 栈的大小
用户栈 : 用户空间的栈很大, 可以存放巨大的结构体等大数据;
内核栈 : 内核的栈很小, 32位 x86 体系结构上 是 8KB, 64 位的是 16 KB;
6. 同步和并发
内核的同步并发机制 : 内核经常产生竞争, 需要并发访问共享数据, 需要有同步机制保证不出现竞争条件;
-- Linux系统抢占属性 : Linux 是抢占式多任务操作系统, 内核必须和任务同步, 内核中一段代码可能会被另一段抢占, 几段代码可能访问同一资源, 因此需要 自旋锁 信号量等机制保护;
-- Linux 系统对称多处理(SMP)属性 : 多个处理器执行内核代码 可能会导致访问同一资源, 这里也使用 自旋锁 和 信号量机制;
-- 中断保护 : 中断可能在一段代码访问资源的时候到来, 中断处理程序又可能访问同一资源, 又出现多个代码访问同一资源;
四. 驱动简介
1. 驱动和模块
驱动概念 :
-- 实现位置 : 驱动在内核中实现, 一般在内核中的 driver 目录下;
-- 驱动作用 : 驱动的作用是提供 机制(实现什么功能), 不是提供 策略(用户如何使用这种功能), 编写访问硬件的内核代码的时候, 不要给用户强加策略;
可加载模块 : 可以在内核运行时加载的代码叫模块, 每个模块由目标代码组成, 可以在内核运行的时候动态连接到内核中;
-- 机制特点 : 这是一种可以动态加载功能单元来扩展功能的机制, 类似与插件;
-- 与驱动关系 : 内核为每个驱动创建不同的模块, 实现驱动的扩展性;
2. 驱动分类
驱动分类 : 驱动分为 字符设备, 块设备 和 网络设备;
a. 字符设备
字符设备概念 : 这种设备可以像字节流一样访问, 字符设备驱动程序实现这种特性;
-- 字符设备访问方式 : 通过 /dev 下的字符设备文件来访问, 该驱动程序需要实现 open close rad write 系统调用;
-- 顺序访问 : 大部分字符设备只能顺序访问数据, 指针不能前后移动, 如 串口驱动, 只能顺序读写数据;
-- 灵活访问 : 有些字符设备可以移动指针访问, 如 framebuffer 设备;
b. 块设备
块设备概念 : 这种设备按照文件块访问数据, 如 一块为 512 字节, 那么会按照 512 字节访问设备;
-- 块设备访问方式 : 通过 /dev 下面的文件系统访问;
-- 与字符设备区别 : 内核内部管理数据的方式不同, 内核和驱动的接口不同;
-- 访问方式 : 块设备除了提供与字符设备相同的接口之外, 还要提供专门面向块设备的接口;
-- 块设备与文件系统关系 : 块设备支持文件系统挂载, 其能够容纳文件系统, 应用程序可以通过文件系统访问块设备;
c. 网络设备
网络设备概念 : 网络设备不在 /dev 下表示, 是通过单独的网络接口来代表这种设备的;
-- 访问方式 : 网络设备需要通过网络接口进行访问;
-- 实现方式 : 内核与网络设备通信 与 字符设备 和 块设备都不同, 是调用一套数据传输相关的 api 完成这种操作;
3. 设备文件和设备驱动
设备文件简介 :
-- 概念 : 文件系统上的一个节点, 是一种特殊的文件, 每个设备文件代表了一个设备;
-- 位置 : 设备文件一般在 /dev 目录下;
-- 创建命令 : 使用 mknod 命令进行创建;
-- 设备接口 : 设备文件是应用程序和设备驱动之间的接口, 应用程序通过操作设备文件使用设备驱动的功能;
-- 与字符和块设备对应 : 字符设备 和 块设备 必定与一个设备文件对应;
驱动位置 :
-- 内核源码中的位置 : 内核中的驱动在根目录下的 drivers 目录下;
代码语言:javascript复制octopus@octopus:~/uplooking/kernel/linux-2.6.32.63/drivers$ pwd
/home/octopus/uplooking/kernel/linux-2.6.32.63/drivers
octopus@octopus:~/uplooking/kernel/linux-2.6.32.63/drivers$ ls
accessibility built-in.o dio hwmon Kconfig message oprofile ps3 sh usb
acpi cdrom dma i2c leds mfd parisc rapidio sn uwb
amba char edac ide lguest misc parport regulator spi video
ata clocksource eisa idle macintosh mmc pci rtc ssb virtio
atm connector firewire ieee1394 Makefile modules.order pcmcia s390 staging vlynq
auxdisplay cpufreq firmware ieee802154 mca mtd platform sbus tc w1
base cpuidle gpio infiniband md net pnp scsi telephony watchdog
block crypto gpu input media nubus power serial thermal xen
bluetooth dca hid isdn memstick of pps sfi uio zorro
-- Linunx系统中的位置 : /usr/src/linux-headers-3.11.0-15/drivers ;
代码语言:javascript复制root@octopus:/usr/src/linux-headers-3.11.0-15/drivers# ls
accessibility bus devfreq gpu infiniband mailbox mtd pinctrl remoteproc spi vfio zorro
acpi cdrom dio hid input Makefile net platform reset ssb vhost
amba char dma hsi iommu md nfc pnp rpmsg staging video
ata clk edac hv ipack media ntb power rtc target virt
atm clocksource eisa hwmon irqchip memory nubus pps s390 tc virtio
auxdisplay connector extcon hwspinlock isdn memstick of ps3 sbus thermal vlynq
base cpufreq firewire i2c Kconfig message parisc ptp scsi tty vme
bcma cpuidle firmware ide leds mfd parport pwm sfi uio w1
block crypto fmc idle lguest misc pci rapidio sh usb watchdog
bluetooth dca gpio iio macintosh mmc pcmcia regulator sn uwb xen
root@octopus:/usr/src/linux-headers-3.11.0-15/drivers# pwd
/usr/src/linux-headers-3.11.0-15/drivers
常用的驱动简介 :
-- block : 块设备驱动;
-- char : 虚拟中断驱动;
-- serial : 串口驱动;
-- net : 网络设备驱动;
-- vedio : framebuffer 设备驱动;
-- sound : 声卡驱动;
系统中设备驱动信息 : 使用 dmesg 命令查看;
代码语言:javascript复制octopus@octopus:~/uplooking/kernel/linux-2.6.32.63/drivers$ dmesg
[ 0.000000] Initializing cgroup subsys cpuset
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Initializing cgroup subsys cpuacct
[ 0.000000] Linux version 3.11.0-15-generic (buildd@akateko) (gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #25~precise1-Ubuntu SMP Thu Jan 30 17:42:40 UTC 2014 (Ubuntu 3.11.0-15.25~precise1-generic 3.11.10)
[ 0.000000] KERNEL supported cpus:
[ 0.000000] Intel GenuineIntel
[ 0.000000] AMD AuthenticAMD
[ 0.000000] NSC Geode by NSC
[ 0.000000] Cyrix CyrixInstead
[ 0.000000] Centaur CentaurHauls
[ 0.000000] Transmeta GenuineTMx86
作者 : 韩曙亮
转载请出名出处 : http://blog.csdn.net/shulianghan/article/details/38636827