Exynos 4412 Cortex-A9嵌入式Linux驱动开发学习笔记-第一期

2019-07-12 16:24发布

一、Linux 体系结构

如下图所示,Linux 体系结构,从大的方面可以分为用户空间(User Space)和内核空间 (Kernel Space)。
用户空间中包含了 C 库,用户的应用程序。在某些体系结构图中还包含了 shell,当然 shell脚本也是 Linux 体系中不可缺少的一部分。
内核空间包括硬件平台、平台依赖代码、内核、系统调用接口。
另外,用户空间和内核空间是程序执行的两种不同状态,我们可以通过“系统调用”和“硬件中断”来完成用户空间到内核空间的转移。

二、了解 Linux 内核结构

如下图所示,是 Linux 内核结构图。
SCI 层(System Call Interface),这一层是给应用用户空间提供一套标准的系统调用函数来访问 Linux。前面分析 Linux 体系结构的时候,介绍过任何一类现代操作系统都不会允许上层应用直接访问底层,在 Linux 中,内核提供了一套标准接口,上层应用就可以通过这一套标准接口来访问底层。 PM(Procees Management),这一部分包括具体创建创建进程(fork、exec),停止进程(kill、exit),并控制他们之间的通信(signal 等)。还包括进程调度,控制活动进程如何共享 CPU。这一部分是 Linux 已经做好的,在写驱动的时候,只需要调用对应的函数即可实现这些功能,例如创建进程、进程通信等等。 MM(Memory Management),内存管理的主要作用是控制多个进程安全的共享内存区域。 VFS(Virtual File Systems),虚拟文件系统,隐藏各种文件系统的具体细节,为文件操作提供统一的接口。在 Linux 中“一切皆文件”,这些文件就是通过 VFS 来实现的。Linux 提供了一个大的通用模型,使这个模型包含了所有文件系统功能的集合。如下图所示,是一个虚拟文件系统的结构图。
Device Drivers 设备驱动,这一部分就是需要学习和掌握的。Linux 内核中有大量的代码在设备驱动程序部分,用于控制特定的硬件设备。 Linux 驱动一般分为网络设备、块设备、字符设备、杂项设备,需要我们编写的只有字符设备,杂项设备是不容易归类的一种驱动,杂项设备和字符设备有很多重合的地方。 网络协议栈,Linux 内核中提供了丰富的网络协议实现。

 三、了解 Linux 内核源码目录结构

 
Linux内核目录结构(2.6版本以上的kernel)
1、documentation: 没有内核代码,提供文档帮助。 2、arch: arch是architecture的缩写。所有与体系结构相关的代码都在这个目录以 include/asm-*/目录中。Linux支持的每种体系结构在arch目录下都有对应的目录,又进一 步分解为boot,mm,kernel等子目录: | kernel: 存放支持体系结构特有的诸如信号量处理和SMP之类特征的实现。 | lib: 存放体系结构特有的对诸如strlen和memcpy之类的通用函数的实现。 | mm: 存放体系结构特有的内存管理程序的实现。 除了这3个子目录以外,大多数体系结构在必要的情况下还有一个boot子目录,包括了在这种硬件平台上启动内核所使用的内存管理程序的实现。 3、drivers: 驱动代码,驱动是一个控制硬件的软件。这个目录是内核中最庞大的一个目录,显卡、网卡、SCSI适配器、PCI总线、USB总线和其他任何Linux支持的外围设备或总线的驱动程序都可以在这儿找到。 4、fs: 虚拟文件系统(VFS)的代码,和各个不同文件系统的代码都在这个目录中。Linux支持的所有文件系统在fs目录下面都有一个对应的子目录。比如ext2文件系统对应的是fs/ext2目录。 一个文件系统是存储设备和需要访问存储设备的进程之间的媒介。存储设备可能是本地的物理上可以访问的,比如硬盘或者CD-ROM驱动器,他们分别使用而系统ext2/ext3和isofs文件系统。 还有一些虚拟文件系统(proc),它是一个标准文件系统出现。然而,他其中的文件只存在于内存中,并不占磁盘空间。 5、include: 这个目录包含了内核中大部分的头文件,它按照下面的子目录进行分组。要修改处理器结构则只需编辑核心的makefile并重新运行Linux核心配置程序。 | include/asm-*/ 每一个对应着一个arch的子目录,比如include/asm-alpha、 Include/asm-arm等。每个子目录中的文件都定义了支持给定体系结构所必要的预处理函数和内联函数,这些内联函数多数都是全部或者部分的汇编语言实现。 | include/linux 与平台无关的头文件都在这个目录下,它通常会被链接到目录 /usr/include/linux(或者它里面的所有文件都会被复制到 /usrinclude/linux目录下边) 6、init: 内核的初始化代码。包括main.c、创建早起用户空间的代码及其他初始化代码。 7、ipc: IPC(进程间通信)。它包含了共享内存、信号量及其他形式的IPC代码。 8、kernel: 内核中最核心的部分,包括进程的调度(sched.c),以及进程的创建和撤销(fork.c和exit.c)和平台相关的另外一部分核心代码在arch/*/kernel目录下。 9、mm 此目录包含了与体系无关的部分内存管理代码。与体系结构相关的内存管理代码位于arch/*/mm下。
10、net
核心的网络部分代码,实现了各种常见的网络协议,入TCP/IP、IPX等。
11、lib
此目录包含了核心的库代码。实现了一个标准C库的通用子集,包括字符串和内存操作的函数(strlen、mmcpy等)以及有关sprintf和atoi系列函数。与arch/lib下的代码不同,这里的库代码都是C编写的,在内核新的移植版本中可以直接使用。与处理器结构相关库代码被放在arch/mm中。
12、block:
块设备驱动包括IDE(在ide.c中)驱动。块设备是以数据块方式接收和发送的数据的设备。最初block层代码一部分位于drivers目录,一部分位于fs目录。从2.6.15开始,block层的核心代码就被提取出来放在顶层的block目录中。如果你想寻找这些可包含文件系统的设备的初始化过程则应该在drivers/block/genhd.c中的device_setup()。当安装一个nfs文件系统时不但要初始化硬盘还需初始化网络。块设备包括IDE与SCSI设备。 13、firmware fireware中包含了让计算机读取和理解从设备发来的信号的代码。举例来说,一个摄像头管理它自己的硬件,但计算机必须了解摄像头给计算机发送的信号。Linux系统会使用vicam固件(firmware)来理解摄像头的通讯。否则,没有了固件,Linux系统将不知道如何处理摄像头发来的信息。另外,固件同样有助于将Linux系统发送消息给该设备。这样Linux系统可以告诉摄像头重新调整或关闭摄像头。 13、usr: 实现用于打包和压缩的cpio等。这个文件夹中的代码在内核编译完成后创建这些文件。 14、securtity: 这个目录下包含了不同的Linux安全模型的代码。它对计算机免于受到病毒和黑客的侵害很重要。否则,Linux系统可能会遭到损坏。 15、crypto: 内核本身所用的加密API,实现了常用的加密和散列算法,还有一些压缩和CRC校验算法。例:“sha1_generic.c”这个文件包含了SHA1加密算法的代码。 16、scripts: 该目录下没有内核代码,只是包含了用来配置内核的脚本文件。当运行make menuconfig或者make xconfig之类的命令配置内核时,用户就是和位于这个目录下的脚本进行交互的。
17、sound: 声卡驱动以及其他声音相关的源码。 18、samples
一些内核编程的范例 19、virt 此文件夹包含了虚拟化代码,它允许用户一次运行多个操作系统。通过虚拟化,客户机操作系统就像任何其他运行在Linux主机的应用程序一样运行。 20、tools 这个文件夹中包含了和内核交互的工具。 COPYING:许可和授权信息。Linux内核在GPLv2许可证下授权。该许可证授予任何人有权免费去使用、修改、分发和共享源代码和编译代码。然而,没有人可以出售源代码。 CREDITS : 贡献者列表 Kbuild : 这是一个设置一些内核设定的脚本。打个比方,这个脚本设定一个ARCH变量,这是开发者想要生成的内核支持的处理器类型。 Kconfig: 这个脚本会在开发人员配置内核的时候用到 MAINTAINERS : 这是一个目前维护者列表,他们的电子邮件地址,主页,和他们负责开发和维护的内核的特定部分或文件。当一个开发者在内核中发现一个问题,并希望能够报告给能够处理这个问题的维护者时,这是是很有用的。 Makefile :这个脚本是编译内核的主要文件。这个文件将编译参数和编译所需的文件和必要的信息传给编译器。 README : 这个文档提供给开发者想要知道的如何编译内核的信息。 REPORTING-BUGS : 这个文档提供如何报告问题的信息。 内核的代码是以“.c”或“.h”为扩展名的文件。 “.c”的扩展名表明内核是用众多的编程语言之一的C语言写的, “h”的文件是头文件,而他们也是用C写成。头文件包含了许多“.c”文件需要使用的代码,因为他们可以引入已有的代码而不是重新编写代码,这节省了程序员的时间。否则,一组执行相同的动作的代码,将存在许多或全部都是“c”文件。这也会消耗和浪费硬盘空间。(译注:头文件不仅仅可节省重复编码,而且代码复用也会降低代码错误的几率)