这一部分主要是一些理论的东西比较多 ;有一些内容需要了解:
①Linux体系架构
②Linux内核结构
③Linux内核源码目录结构
首先就是第一部分Linux体系架构:
Linux体系架构是由用户空间和内核空间构成的;从安全性的角度分析,为了保护内核。现代CPU通常都实现了不同的工作模式。以ARM为例:ARM实现了7种工作模式,不同模式下CPU可以执行的指令或者访问的寄存器不同:
(1)用户模式 usr
(2)系统模式 sys
(3)管理模式 svc
(4)快速中断 fiq
(5)外部中断 irq
(6)数据访问终止 abt
(7)未定义指令异常
– 以(2)X86为例:X86实现了4个不同级别的权限,Ring0—Ring3 ;Ring0下可以执行特权指令,可以访问IO设备;Ring3则有很多的限制
– 以Android为例:将应用放到Java虚拟机上面运行,应用更加远离底层
• 用户空间和内核空间是程序执行的两种不同状态,我们可以通过“系统调用”和“硬件中断“来完成用户空间到内核空间的转移
第二部分Linux内核结构,也是前边图里Kernel部分,也是我们在Ubuntu中解压的文件夹iTop4412_Kernel_3.0,这个文件夹里配置完编译后就可以生成Linux内核编译文件zImage文件;下边是内核结构图
图中所示:
System Call Interface (SCI层)– 为用户空间提供了一套标准的系统调用函数来访问Linux内核。
Procees Management(PM)– 进程管理是创建进程(fork、exec),停止进程(kill、exit),并控制他们之
间的通信(signal等)。还包括进程调度,控制活动进程如何共享CPU;
Memory Management(MM)– 内存管理的主要作用是控制多个进程安全的共享内存区域;
Virtual File Systems(VFS)
– 虚拟文件系统,隐藏各种文件系统的具体细节,为文件操作提供统一的接口
– Linux提供了一个大的通用模型,使这个模型包含了所有文件系统功能的集合(一切皆文件)
Device Drivers设备驱动(这部分比较重要,关系到设备注册设备驱动注册)
– Linux内核中有大量的代码在设备驱动程序部分,用于控制特定的硬件设备。
– Linux驱动一般分为网络设备、块设备、字符设备、杂项设备
第三部分就是目录结构,Linux内核源码采用树形结构。功能相关的文件放到不同的子目录下面,使程序更具有可读性。下面是目录(内核文件解压后的文件夹里)的截图:
arch文件夹:是平台目录。。内核支持的所有CPU架构,在该目录下都有对应的子目录。每个CPU的子目录,又进一步分解为boot,mm,kernel等子目录,分别控制系统引导,内存管理,系统调用。还有动态调频,主频率设置部分等;在这个文件夹里有一个arm文件夹,这也是我们现在这款CPU的架构;下面有一张arch下的目录图:
binary目录:无源码的驱动以二进制放到该文件中,比如想发布测试,但是不想提供源码就提供这个二进制文件;
block目录:部分块设备的驱动程序;
crypto目录:加密压缩CRC校验;
Documentation目录:内核的使用说明,一般很少用到;
drivers目录(重要):设备驱动文件部分,该部分是讯为建立;
firmware目录:固件接口;
fs目录:存放各种文件系统的实现代码;
include目录(重要):通用的头文件在include/linux;
init目录:内核初始化代码,该部分也是讯为建立;
lpc目录:进程通信的源码;
virt目录:内核虚拟机,该部分好像是安卓之类运行的时候就是创建一个虚拟机后再虚拟机上运行的;
kernel目录:Linux核心功能源码,程序调度,控制进程,模块化等;
lib目录:库文件代码;
mm目录:实现内存管理(与平台体系无关的部分);
net目录:网络协议实现代码(有IPV4、6、802、DNS等);
samples目录:内核编程的示范,讯为提供;
scripts目录:配置裁剪内核的工具脚本;
security目录:包括不同的Linux安全模型代码;
sound目录:音频设备的驱动程序;
tools目录:将.C编译成目标文件,连接合并成可运行的内核镜像文件等;
usr目录:实现用于打包和压缩的CPIO等;
学习的重点是驱动开发相关的知识、函数的调用、驱动的协议、简单的硬件知识
了解上边这些理论知识后,下面就是驱动块编写和编译的一些笔记:
①.c必备的头文件:#include <linux/init.h>包含初始化宏定义的头文件,代码中的函数module_init和module_exit在此文件中、#include <linux/module.h>;
所有的Linux 代码必须遵循GPL 协议和作者申明:MODULE_LICENSE(_license)添加遵循GPL协议,必须的!、MODULE_AUTHOR(_author)代码作者;
编写驱动模块时还必须要有入口函数和出口函数(这里是.c文件);
MODULE_LICENSE("Dual BSD/GPL");
/*声明是开源的,没有内核版本限制*/
MODULE_AUTHOR("TOPEET");
/*声明作者*/
module_init(x) /*初始化函数,– 入口函数*/
module_exit(x) /*卸载函数,– 出口函数*/
有了上边的一些必要的申明和函数后,可编写下边一个示例:
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");
static int hello_init(void)
{
printk(KERN_EMERG "HELLO WORLD enter!\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_EMERG "HELLO WORLD exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
②编译时的脚本文件,Makefile文件;这个文件只要会照着格式写就完了,没必要了解太深;
#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件itop4412_hello.o
obj-m += mini_linux_module.o
#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0
#当前目录变量
PWD ?= $(shell pwd)
#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
make -C $(KDIR) M=$(PWD) modules
#make clean执行的操作是删除后缀为o的文件
clean:
rm -rf *.o
这个Makefile文件最好是通过ssh拖到在Ubuntu上,最好不要在电脑上编写,可能会出现Tab键的错误,如果有这个错误那就vim一下,把make前的Tab格重新修改一下,保存退出;
有了上边的.c文件和Makefile文件后就可以在Ubuntu上进行驱动模块编译了,把这两个问价放到同一个文件夹里,进入这个文件夹,输入make命令进行编译;编译后生成.ko文件,将该文件倒到开发板,直接运行就ok了;下边还有一些会用到的命令:
加载模块、查看模块、卸载模块命令
– insmod加载模块命令
– lsmod查看模块命令
– rmmod卸载模块命令
在开发板运行的结果就不记录了,自己动手实践一下更有满足感;
送给阅读过这篇文章的人:从原始到奴隶,从封建到共和,人类都是在突破生存和自由的一种环境。就像小时候,我们盼望着长大,长大后就能摆脱束缚,所以成长的过程就是思想成熟的过程。我们经常会觉得今是而昨非,所以生活就是一个不断认为自己以前是个SB的过程。当我们不断突破对自由的这个理解的时候,你会发现身边的人越来越少,就像长大这两个字,连偏旁部首都没有,从开始就意味着我们长大以后必然是孤独的!
要享受这份孤独,因为只有在孤独的时候你才能更加清楚的了解自己,看清自己,想清楚一些事情;
下篇文章见。