Linux设备驱动开发详解:基于最新的Linux4.0内核.html.pdf

上传人:紫竹语嫣 文档编号:5514689 上传时间:2020-05-27 格式:PDF 页数:196 大小:19.13MB
返回 下载 相关 举报
Linux设备驱动开发详解:基于最新的Linux4.0内核.html.pdf_第1页
第1页 / 共196页
Linux设备驱动开发详解:基于最新的Linux4.0内核.html.pdf_第2页
第2页 / 共196页
Linux设备驱动开发详解:基于最新的Linux4.0内核.html.pdf_第3页
第3页 / 共196页
Linux设备驱动开发详解:基于最新的Linux4.0内核.html.pdf_第4页
第4页 / 共196页
Linux设备驱动开发详解:基于最新的Linux4.0内核.html.pdf_第5页
第5页 / 共196页
点击查看更多>>
资源描述

《Linux设备驱动开发详解:基于最新的Linux4.0内核.html.pdf》由会员分享,可在线阅读,更多相关《Linux设备驱动开发详解:基于最新的Linux4.0内核.html.pdf(196页珍藏版)》请在三一文库上搜索。

1、推荐序一 技术日新月异,产业斗转星移,滚滚红尘,消逝的事物太多,新事物的诞生也更迅猛。众多新生事物如灿烂烟花,转瞬即逝。当我们仰望星空时,在浩如烟海的专业名词中寻找,赫然发现,Linux的生 命力之旺盛顽强,斗志之昂扬雄壮,令人称奇。它正以摧枯拉朽之势迅速占领包括服务器、云计算、消费电子、工业控制、仪器仪表、导航娱乐等在内的众多应用领域,并逐步占据许多WINCE、VxWorks 的传统嵌入式市场。 Linux所及之处,所向披靡。这与Linux的社区式开发模式,迅速的迭代不无关系。Linux每23月更新一次版本,吸纳新的体系架构、芯片支持、驱动、内核优化和新特性,这使得Linux总是能够在第一

2、时间内迎合用户的需求,快速地适应瞬息万变的市场。由Linux以及围绕着Linux进行产品研发的众多企业和爱好者构成了一个庞大的Linux生态圈。而本书,无疑给这个庞大的生态圈注入了养料。 然而,养料的注入应该是持续不断的。至今,Linux内核的底层BSP、驱动框架和内核实现发生了许多变更,本书涵盖了这些新的变化,这将给予开发者更多新的帮助。内核的代码不断重构并最优化, 而本书也无疑是一次重大的重构。 生命不息,重构不止。 周立功 推荐序二 在翻译了Understanding the Linux Kernel和Linux Kernel Development这两本书后,每当有读者询问如何学习Li

3、nux内核时,我都不敢贸然给出建议。如此庞大的内核,各个子系统之间的关系错综 复杂,代码不断更新和迭代,到底该从何入手?你的出发点是哪里?你想去的彼岸又是哪里?相应的学习方法都不同。 一旦踏入Linux内核领域,要精通Linux内核的精髓,几乎没有捷径可走。尽管通往山顶的路有无数条,但每条路上都布满荆棘,或许时间和毅力才是斩荆披棘的利器。 从最初到现在,Linux内核的版本更新达上千个,代码规模不断增长,平均每个版本的新增代码有4万行左右。在源代码的10个主要子目录(arch、init、include、kernel、mm、IPC、fs、lib、net、 drivers)中,驱动程序的代码量呈线

4、性增长趋势。 从软件工程角度来看内核代码的变化规律,Linux的体系结构相对稳定,子系统数变化不大,平均每个模块的复杂度呈下降趋势,但系统整体规模和复杂性分别呈超线性和接近线性增长趋势。drivers和 arch等模块的快速变化是引起系统复杂性增加的主因。那么,在代码量最多的驱动程序中,有什么规律可循?最根本的又是什么? 本书更多的是关于Linux内核代码背后机理的讲解,呈现给读者的是一种思考方法,让读者能够在思考中举一反三。尽管驱动程序只是内核的一个子系统,但Linux内核是一种整体结构,牵一发而动全 局,对Linux内核其他相关知识的掌握是开发驱动的基础。本书的内容包括中断、定时器、进程生

5、命周期、uevent、并发、编译乱序、执行乱序、等待队列、I/O模型、内存管理等,实例代码也被大幅重构。 明代著名的思想家王明阳有句名言“知而不行,是为不知;行而不知,可以致知”。因此在研读本书时,你一定要亲身实践,在实践之后要提升思考,如此,你才可以越过代码本身而看到内核的深层 机理。 陈莉君 西安邮电大学 前言 Linux从未停歇前进的脚步。Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,现在仍然在没日没夜地合并补丁、升级内核。做技术的人,从来没有终南捷径,拼得就是 坐冷板凳的傻劲。 这是一个连阅读都被碎片化的时代,在这样一个时代,人们趋向于

6、激进、浮躁,内心的不安宁使我们极难静下心来研究什么。我见过许多Linux工程师,他们的简历上写着“精通”Linux内核,有多年的 工作经验,而他们的“精通”却只是把某个寄存器从0改成1,从1改成0的不断重复;我也见过许多Linux工程师,他们终日埋头苦干,敲打着自己的机器和电路板,却从未冷静下来思考,并不断重构和升华 自己的知识体系。 这是要把“牢底”坐穿的程序员,这样“忙忙碌碌”的程序员,从来都不算是好程序员。 对于优秀的程序员,其最优秀的品质是能够心平气和地学习与思考问题,透析代码背后的架构、原理和设计思想。没有思想的代码是垃圾代码,没有思想的程序员,只是在完成低水平重复建设的体力 活。很

7、多程序员从不过问自己写的代码最后在机器里面是怎么跑的,很多事情莫名其妙地发生了,很多bug莫名其妙地消失了他们永远都在得过且过。 由此,衍生出了本书的第一个出发点,那就是带给读者更多关于Linux开发思想的讲解,帮助读者奠定根基。本书呈现给读者的更多的是一种思考方法,而不是知识点的简单罗列。 本书除对基础理论部分进行了详细的讲解外,还加强了对驱动编程所涉及的Linux内核最底层机理的讲解,内容包括中断、定时器、进程生命周期、uevent、并发、编译乱序、执行乱序、等待队列、I/O 模型、内存管理等。这些知识点非常重要,是真正证明程序员理解了Linux的部分内容,程序员只有打好根基,才能游刃有余

8、。 本书没有大量描述各种具体驱动类型的章节,如Sound、PCI、MTD、tty等,而将更多的焦点转移到了驱动编程背后的内核原理,并试图从Linux内核的上百个驱动子系统中寻找出内部规律,以培养读者 举一反三的能力。 Linux内核有上百个驱动子系统,这一点从内核的drivers子目录中就可以看出来: 好吧,傻子才会一个目录一个目录地去看,一个目录一个目录地从头学起。我们势必要寻找各种驱动子系统的共性,摸索规律。在本书中,我们将更多地看到各驱动子系统的类比,以及驱动子系统的 层次化设计。 技术工作从来都不能一劳永逸。世界变化得太快,当前技术革新的速度数倍于我们父辈、祖辈、祖祖辈经历过的任何时代

9、。证明你是“真球迷”还是“伪球迷”的时候到了,这个时代是伪程序员的地 狱,也是真程序员的天堂。 从浩如烟海的知识体系、不断更新的软件版本中终生学习,不断攻克一个个挑战,获取新养分,寻找新灵感,这实在是黑暗的码农生涯中不断闪现的璀璨光芒。 Linux的内核版本不断更新,出现了Linux 3.0、Linux 3.1、Linux 3.2、Linux 3.19、Linux 4.0、Linux 4.1,变化的是软件的架构,不变的是Linus的热情。 这无疑也是本书的第二个出发点,更新Linux驱动编程的知识体系以迎合最新的时代需求。因此,本书有大量关于设备树、ARM Linux移植、Linux电源管理、

10、GPIO、时钟、定时器、pinmux、DMA等内 容。我们的操作平台也转移到了QEMU模拟的4核Cortex-A9电路板上,书中的实例基本都转移到了市面流行的新芯片上。 最近两三年,老是听许多程序员抱怨,市面上缺乏讲解新内核的资料、缺乏从头到尾讲解设备树的资料,但是我想说,这实在不是什么难点。难点仍然是本书基于第一个出发点要解决的问题,如果有 好的基础,以优秀程序员极强的学习能力,应该很快就可以掌握这些新知识。机制没有变,变化的只是策略。 因此学习能力也是优秀程序员的又一个重要品质。没有人生下来就是天才,良好的学习能力也是通过后天的不断学习培养的。可以说,学得越多的人,学新东西的速度一定越快,

11、学习能力也变得越 强。因为,知识的共通性实在太多。 读者在阅读本书时,不应该企图把它当成一本工具书和查API的书,而是应该把它当作一本梳理理论体系、开发思想、软件架构的书。唯如此,我们才能适应未来新的变化。 时代的滚滚车轮推动着Linux内核的版本不断向前,也推动着每个人的人生。红尘滚滚, 我不去想是否能够成功, 既然选择了远方, 便只顾风雨兼程。 最后,本书能得以出版,要感谢带领我向前的人生导师和我的众多小伙伴,他们或者在我人生的关键时刻改变了我,或者给我黑暗的程序生涯带来了无尽的快乐和动力。我的小伙伴,他们力挺我、鼓 励我,也辱骂我、奚落我,这些都是真挚的友情。 谨以此书,致以对杨平先生、

12、何昭然、方毅伟、李华毅、宋志武、杜向龙、叶祥振、刘昊、王榕、何晔、王立赛、曾过、刘永生、段丙华、章君义、王文琪、卢鹏、刘涛、徐西宁、吴赫、任桥伟、秦 龙廷、胡良兵、张家旺、王雷、Bryan Wu、Eric Miao、Cliff Cai、Qipan Li、Guoying Zhang、陈健松、Haoyu Zhong、刘洪涛、季久峰、邴杰、孙志忠、吴国举、Bob Liu、赵小吾、EJ Zhao、贺亚锋、刘仕杰、 Hao Yin等老师和小伙伴的深深感激;谨以此书,致以对我的父母大人、老婆大人、兄长和姐姐、伟大丈母娘的深深感激,本书的写作时间超过一年,其过程是一种巨大的肉体和精神折磨,没有他们的默默 支

13、持和不断鞭策,本书是不可能完成的;谨以此书,对为本书做出巨大贡献的编辑、策划老师,尤其是张国强老师致以深深的感激! 由于篇幅的关系,我没有办法一一列举我要感激的所有人,但是,这些年从你们那里获得的,远远大于我付出的,所以,在内心深处,唯有怀着对你们的深深感恩,不断前行。岁月如歌,吾歌狂行。 全书结构 本书首先介绍Linux设备驱动的基础。第1章简要地介绍了设备驱动,并从无操作系统的设备驱动引出了Linux操作系统下的设备驱动,介绍了本书所基于的开发环境。第2章系统地讲解了Linux驱动工程 师应该掌握的硬件知识,为工程师打下Linux驱动编程的硬件基础,详细介绍了各种类型的CPU、存储器和常见

14、的外设,并阐述了硬件时序分析方法和数据手册阅读方法。第3章将Linux设备驱动放在Linux 2.6 内核背景中进行讲解,说明Linux内核的编程方法。由于驱动编程也在内核编程的范畴,因此,这一章实质是为编写Linux设备驱动打下软件基础。 其次,讲解Linux设备驱动编程的基础理论、字符设备驱动及设备驱动设计中涉及的并发控制、同步等问题。第4、5章分别讲解Linux内核模块和Linux设备文件系统;第69章以虚拟设备globalmem和 globalfifo为主线,逐步给其添加高级控制功能;第10、11章分别阐述Linux驱动编程中所涉及的中断和定时器、内核和I/O操作处理方法。 接着,剖析

15、复杂设备驱动的体系结构以及块设备、网络设备驱动。该篇讲解了设备与驱动的分离、主机控制器驱动与外设驱动的分离,并以大量实例(如input、tty、LCD、platform、I2C、SPI、USB 等)来佐证。其中第12章和第17章遥相呼应,力图全面地展示驱动的架构。Linux有100多个驱动子系统,逐个讲解和学习都是不现实的,授人以鱼不如授人以渔,因此我们将更多的焦点放在了架构讲解方 面,以便读者可以举一反三。 本书最后4章分析了Linux的设备树、Linux移植到新的SoC上的具体工作以及Linux内核和驱动的一些调试方法。这些内容,对于理解如何从头开始搭建一个Linux,以及整个Linux板

16、级支持包上上下下的关 系尤为重要。 另外,本书的主要代码都引用自Linux源代码,为保留原汁原味,均延用了代码的英文注释,而其他非引用的代码则使用了中文注释或无注释,特此说明。 本书配套的相关素材和代码,读者均可从与本书相关的微信公众号中获得,相关公众号是:Linuxer,欢迎扫描二维码。 宋宝华 2015年4月于上海浦东 第1章 Linux设备驱动概述及开发环境构建 本章导读 本章将介绍Linux设备驱动开发的基本概念,并对本书所基于的平台和开发环境进行讲解。 1.1节阐明设备驱动的概念和作用。 1.2节和1.3节分别讲解在无操作系统情况下和有操作系统情况下设备驱动的设计,通过对设计差异的分

17、析,讲解设备驱动与硬件和操作系统的关系。 1.4节对Linux操作系统的设备驱动进行了概要性的介绍,给出设备驱动与整个软硬件系统的关系,分析Linux设备驱动的重点、难点和学习方法。 1.5节对本书所基于的QEMU模拟的vexpress ARM Cortex-A9四核开发板和开发环境的安装进行介绍。 本章最后给出了一个设备驱动的“Hello World”实例,即最简单的LED驱动在无操作系统情况下和Linux操作系统下的实现。 1.1 设备驱动的作用 任何一个计算机系统的运转都是系统中软硬件共同努力的结果,没有硬件的软件是空中楼阁,而没有软件的硬件则只是一堆废铁。硬件是底层基础,是所有软件得以

18、运行的平台,代码最终会落实为硬 件上的组合逻辑与时序逻辑;软件则实现了具体应用,它按照各种不同的业务需求而设计,并完成用户的最终诉求。硬件较固定,软件则很灵活,可以适应各种复杂多变的应用。因此,计算机系统的软硬 件相互成就了对方。 但是,软硬件之间同样存在着悖论,那就是软件和硬件不应该互相渗透入对方的领地。为尽可能快速地完成设计,应用软件工程师不想也不必关心硬件,而硬件工程师也难有足够的闲暇和能力来顾及 软件。譬如,应用软件工程师在调用套接字发送和接收数据包的时候,不必关心网卡上的中断、寄存器、存储空间、I/O端口、片选以及其他任何硬件词汇;在使用printf()函数输出信息的时候,他不用 知

19、道底层究竟是怎样把相应的信息输出到屏幕或者串口。 也就是说,应用软件工程师需要看到一个没有硬件的纯粹的软件世界,硬件必须透明地呈现给他。谁来实现硬件对应用软件工程师的隐形?这个光荣而艰巨的任务就落在了驱动工程师的头上。 对设备驱动最通俗的解释就是“驱使硬件设备行动”。驱动与底层硬件直接打交道,按照硬件设备的具体工作方式,读写设备的寄存器,完成设备的轮询、中断处理、DMA通信,进行物理内存向虚拟 内存的映射等,最终让通信设备能收发数据,让显示设备能显示文字和画面,让存储设备能记录文件和数据。 由此可见,设备驱动充当了硬件和应用软件之间的纽带,应用软件时只需要调用系统软件的应用编程接口(API)就

20、可让硬件去完成要求的工作。在系统没有操作系统的情况下,工程师可以根据硬件设 备的特点自行定义接口,如对串口定义SerialSend()、SerialRecv(),对LED定义LightOn()、LightOff(),对Flash定义FlashWr()、FlashRd()等。而在有操作系统的情况下,驱动的架构则 由相应的操作系统定义,驱动工程师必须按照相应的架构设计驱动,这样,驱动才能良好地整合入操作系统的内核中。 驱动程序负责硬件和应用软件之间的沟通,而驱动工程师则负责硬件工程师和应用软件工程师之间的沟通。目前,随着通信、电子行业的迅速发展,全世界每天都会生产大量新芯片,设计大量新电路 板,也

21、因此,会有大量设备驱动需要开发。这些驱动或运行在简单的单任务环境中,或运行在VxWorks、Linux、Windows等多任务操作系统环境中,它们发挥着不可替代的作用。 1.2 无操作系统时的设备驱动 并不是任何一个计算机系统都一定要有操作系统,在许多情况下,操作系统都不必存在。对于功能比较单一、控制并不复杂的系统,譬如ASIC内部、公交车的刷卡机、电冰箱、微波炉、简单的手机和 小灵通等,并不需要多任务调度、文件系统、内存管理等复杂功能,用单任务架构完全可以良好地支持它们的工作。一个无限循环中夹杂着对设备中断的检测或者对设备的轮询是这种系统中软件的典型架 构,如代码清单1.1所示。 代码清单1

22、.1 单任务软件典型架构 1 int main(int argc, char* argv) 2 3 while (1) 4 5 if (serialInt = 1) 6 /* 有串口中断 */ 7 8 ProcessSerialInt(); /* 处理串口中断 */ 9 serialInt = 0; /* 中断标志变量清0 */ 10 11 if (keyInt = 1) 12 /* 有按键中断 */ 13 14 ProcessKeyInt(); /* 处理按键中断 */ 15 keyInt = 0; /* 中断标志变量清0 */ 16 17 status = CheckXXX(); 18 s

23、witch (status) 19 20 http:/ 21 22 http:/ 23 24 在这样的系统中,虽然不存在操作系统,但是设备驱动则无论如何都必须存在。一般情况下,每一种设备驱动都会定义为一个软件模块,包含.h文件和.c文件,前者定义该设备驱动的数据结构并声明外 部函数,后者进行驱动的具体实现。譬如,可以像代码清单1.2那样定义一个串口的驱动。 代码清单1.2 无操作系统情况下串口的驱动 1 /* 2 *serial.h文件 3 */ 4 extern void SerialInit(void); 5 extern void SerialSend(const char buf*,i

24、nt count); 6 extern void SerialRecv(char buf*,int count); 7 8 /* 9 *serial.c文件 10 */ 11 /* 初始化串口 */ 12 void SerialInit(void) 13 14 http:/ 15 16 /* 串口发送 */ 17 void SerialSend(const char buf*,int count) 18 19 http:/ 20 21 /* 串口接收 */ 22 void SerialRecv(char buf*,int count) 23 24 http:/ 25 26 /* 串口中断处理函

25、数 */ 27 void SerialIsr(void) 28 29 http:/ 30 serialInt = 1; 31 其他模块想要使用这个设备的时候,只需要包含设备驱动的头文件serial.h,然后调用其中的外部接口函数。如要从串口上发送“Hello World”字符串,使用语句SerialSend(“Hello World”,11) 即可。 由此可见,在没有操作系统的情况下,设备驱动的接口被直接提交给应用软件工程师,应用软件没有跨越任何层次就直接访问设备驱动的接口。驱动包含的接口函数也与硬件的功能直接吻合,没有任 何附加功能。图1.1所示为无操作系统情况下硬件、设备驱动与应用软件的关

26、系。 图1.1 无操作系统时硬件、设备驱动和应用软件的关系 有的工程师把单任务系统设计成了如图1.2所示的结构,即设备驱动和具体的应用软件模块之间平等,驱动中包含了业务层面上的处理,这显然是不合理的,不符合软件设计中高内聚、低耦合的要求。 另一种不合理的设计是直接在应用中操作硬件的寄存器,而不单独设计驱动模块,如图1.3所示。这种设计意味着系统中不存在或未能充分利用可重用的驱动代码。 图1.2 驱动与应用高耦合的不合理设计 图1.3 应用直接访问硬件的不合理设计 1.3 有操作系统时的设备驱动 在1.2节中我们看到一个清晰的设备驱动,它直接运行在硬件之上,不与任何操作系统关联。当系统包含操作系

27、统时,设备驱动会变得怎样呢? 首先,无操作系统时设备驱动的硬件操作工作仍然是必不可少的,没有这一部分,驱动不可能与硬件打交道。 其次,我们还需要将驱动融入内核。为了实现这种融合,必须在所有设备的驱动中设计面向操作系统内核的接口,这样的接口由操作系统规定,对一类设备而言结构一致,独立于具体的设备。 由此可见,当系统中存在操作系统的时候,驱动变成了连接硬件和内核的桥梁。如图1.4所示,操作系统的存在势必要求设备驱动附加更多的代码和功能,把单一的“驱使硬件设备行动”变成了操作系 统内与硬件交互的模块,它对外呈现为操作系统的API,不再给应用软件工程师直接提供接口。 图1.4 硬件、驱动、操作系统和应

28、用程序的关系 那么我们要问,有了操作系统之后,驱动反而变得复杂,那要操作系统干什么? 首先,一个复杂的软件系统需要处理多个并发的任务,没有操作系统,想完成多任务并发是很困难的。 其次,操作系统给我们提供内存管理机制。一个典型的例子是,对于多数含MMU的32位处理器而言,Windows、Linux等操作系统可以让每个进程都可以独立地访问4GB的内存空间。 上述优点似乎并没有体现在设备驱动身上,操作系统的存在给设备驱动究竟带来了什么实质性的好处? 简而言之,操作系统通过给驱动制造麻烦来达到给上层应用提供便利的目的。当驱动都按照操作系统给出的独立于设备的接口而设计时,那么,应用程序将可使用统一的系统

29、调用接口来访问各种设 备。对于类UNIX的VxWorks、Linux等操作系统而言,当应用程序通过write()、read()等函数读写文件就可访问各种字符设备和块设备,而不论设备的具体类型和工作方式,那将是多么便利。 1.4 Linux设备驱动 1.4.1 设备的分类及特点 计算机系统的硬件主要由CPU、存储器和外设组成。随着IC制作工艺的发展,目前,芯片的集成度越来越高,往往在CPU内部就集成了存储器和外设适配器。譬如,相当多的ARM、PowerPC、MIPS 等处理器都集成了UART、I2C控制器、SPI控制器、USB控制器、SDRAM控制器等,有的处理器还集成了GPU(图形处理器)、视

30、频编解码器等。 驱动针对的对象是存储器和外设(包括CPU内部集成的存储器和外设),而不是针对CPU内核。Linux将存储器和外设分为3个基础大类。 字符设备。 块设备。 网络设备。 字符设备指那些必须以串行顺序依次进行访问的设备,如触摸屏、磁带驱动器、鼠标等。块设备可以按任意顺序进行访问,以块为单位进行操作,如硬盘、eMMC等。字符设备和块设备的驱动设计有 出很大的差异,但是对于用户而言,它们都要使用文件系统的操作接口open()、close()、read()、write()等进行访问。 在Linux系统中,网络设备面向数据包的接收和发送而设计,它并不倾向于对应于文件系统的节点。内核与网络设备

31、的通信与内核和字符设备、网络设备的通信方式完全不同,前者主要还是使用套接字 接口。 1.5 Linux设备驱动的开发环境构建 1.5.1 PC上的Linux环境 本书配套资源提供了一个Ubuntu的VirtualBox虚拟机映像,该虚拟机上安装了本书涉及的所有源代码、工具链和各种开发工具,读者无须再安装和配置任何环境。该虚拟机可运行于Windows、 Ubuntu等操作系统中,运行方法如下。 1)安装VirtualBox。 如果主机为Windows系统,请安装VirtualBox WIN版本: VirtualBox-4.3.20-96997-Win.exe 如果主机为Ubuntu系统,请安装V

32、irtualBox DEB版本: virtualbox-4.3_4.3.20-96996Ubuntuprecise_i386.deb 2)安装VirtualBox extension。 Oracle_VM_VirtualBox_Extension_Pack-4.3.20-96996.vbox-extpack 3)准备虚拟机镜像。 解压Baohua_Linux.vmdk.rar为Baohua_Linux.vmdk 4)新建虚拟机。 运行第1步安装的Oracle VM VirtualBox,单击“新建(N)”图标创建虚拟机,“类型”选择Linux,“版本”选择Ubuntu(32bit),名称可以取

33、名为“linux-training”,如图1.6所示。 图1.6 新建Ubuntu 32位虚拟机 单击“下一步(N)”按钮,设置内存,如图1.7所示。 图1.7 设置虚拟机的内存 继续单击“下一步(N)”按钮。设置硬盘,注意选择“使用已有的虚拟硬盘文件(U)”单选按钮,虚拟硬盘文件是第3步解压之后的“Baohua_Linux.vmdk”,如图1.8所示。 图1.8 设置虚拟机硬盘镜像 最后,单击“创建”按钮以完成虚拟机的构建工作。 5)启动虚拟机。 在VirtualBox上选择先前创建的“linux-training”虚拟机并单击“启动”图标,如图1.9所示。 图1.9 启动虚拟机 虚拟机的账

34、号和密码都是“baohua”,如果要执行特权命令,sudo密码也是“baohua”,如图1.10所示。 图1.10 虚拟机登录界面 本书配套的Ubuntu版本是14.04,但是内核版本升级到了4.0-rc1,以保证和本书讲解内容的版本一致。 注意事项: 如果发现VirtualBox不稳定或者有兼容性问题(经过测试,有极少数PC存在此问题),也可以安装VMware(Baohua_Linux.vmdk也是支持VMware的)。 如果光盘不小心损坏,可以从链接:http:/ 1.6 设备驱动Hello World:LED驱动 1.6.1 无操作系统时的LED驱动 在嵌入式系统的设计中,LED一般直接

35、由CPU的GPIO(通用可编程I/O)口控制。GPIO一般由两组寄存器控制,即一组控制寄存器和一组数据寄存器。控制寄存器可设置GPIO口的工作方式为输入或 者输出。当引脚被设置为输出时,向数据寄存器的对应位写入1和0会分别在引脚上产生高电平和低电平;当引脚设置为输入时,读取数据寄存器的对应位可获得引脚上的电平为高或低。 在本例子中,我们屏蔽具体CPU的差异,假设在GPIO_REG_CTRL物理地址中控制寄存器处的第n位写入1可设置GPIO口为输出,在地址GPIO_REG_DATA物理地址中数据寄存器的第n位写入1或0可在 引脚上产生高或低电平,则在无操作系统的情况下,设备驱动见代码清单1.3。

36、 代码清单1.3 无操作系统时的LED驱动 1 #define reg_gpio_ctrl *(volatile int *)(ToVirtual(GPIO_REG_CTRL) 2 #define reg_gpio_data *(volatile int *)(ToVirtual(GPIO_REG_DATA) 3 /* 初始化LED */ 4 void LightInit(void) 5 6 reg_gpio_ctrl |= (1 y) http:/ else http:/ 4)对于函数,“”另起一行,譬如: int add(int a, int b) return a + b; 在switc

37、h/case语句方面,Linux建议switch和case对齐,例如: switch (suffix) case G: case g: mem if git rev-parse -verify HEAD 2/dev/null /dev/null then against=HEAD else # Initial commit: diff against an empty tree object against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 fi git diff -cached $against - | ./scripts/checkpatch

38、.pl -no-signoff - 3.6 工具链 在Linux的编程中,通常使用GNU工具链编译Bootloader、内核和应用程序。GNU组织维护了GCC、GDB、glibc、Binutils等,分别见 于https:/gcc.gnu.org/,https:/www.gnu.org/software/gdb/,https:/www.gnu.org/software/libc/、https:/www.gnu.org/software/binutils/。 建立交叉工具链的过程相当烦琐,一般可以通过类似crosstool-ng这样的工具来做。crosstool-ng也采用了与内核相似的menu

39、config配置方法。在官网http:/www.crosstool-ng.org/上下载 crosstool-ng的源代码并编译安装后,运行ct-ng menuconfig,会出现如图3.12的配置菜单。在里面我们可以选择目标机处理器型号,支持的内核版本号等。 图3.12 crosstool-ng的配置菜单 当然,也可以直接下载第三方编译好的、开放的、针对目标处理器的交叉工具链,如在http:/ edition/上可以下载针对ARM、MIPS、高通Hexagon、Altera Nios II、Intel、AMD64等处理器的工具链,在http:/www.linaro.org/downloads

40、/可以下载针对ARM的工具链。 目前,在ARM Linux的开发中,人们趋向于使用Linaro(http:/www.linaro.org/)工具链团队维护的ARM工具链,它以每月一次的形式发布新的版本,编译好的可执行文件可从网 址http:/www.linaro.org/downloads/下载。Linaro是ARM Linux领域中最著名最具技术成就的开源组织,其会员包括ARM、Broadcom、Samsung、TI、Qualcomm等,国内的海思、中兴、全志和中 国台湾的MediaTek也是它的会员。 一个典型的ARM Linux工具链包含arm-linux-gnueabihf-gcc(后

41、续工具省略前缀)、strip、gcc、objdump、ld、gprof、nm、readelf、addr2line等。用strip可以删除可执行文件中的符号表和调 试信息等来实现缩减程序体积的目的。gprof在编译过程中在函数入口处插入计数器以收集每个函数的被调用情况和被调用次数,检查程序计数器并在分析时找出与程序计数器对应的函数来统计函数占用的 时间。objdump是反汇编工具。nm则用于显示关于对象文件、可执行文件以及对象文件库里的符号信息。其中,前缀中的“hf”显示该工具链是完全的硬浮点,由于目前主流的ARM芯片都自带VFP或者 NEON等浮点处理单元(FPU),所以对硬浮点的需求就更加强

42、烈。Linux的浮点处理可以采用完全软浮点,也可以采用与软浮点兼容,但是使用FPU硬件的softfp,以及完全硬浮点。具体的 ABI(Application Binary Interface,应用程序二进制接口)通过-mfloat-abi=参数指定,3种情况下的参数分别是-mfloat-abi=soft/softfp/hard。 在以前,主流的工具链采用“与软浮点兼容,但是使用FPU硬件的softfp”。softfp使用了硬件的FPU,但是函数的参数仍然使用整型寄存器来传递,完全硬浮点则直接使用FPU的寄存器传递参数。 下面一段程序: float mul(float a, float b) r

43、eturn a * b; void main(void) printf(“1.1 * 2.3 = %fn“, mul(1.1, 2.3); 对其使用arm-linux-gnueabihf-gcc编译并反汇编的结果是: 000 08394 : 8394: b480 push r7 8396: b083 sub sp, #12 8398: af00 add r7, sp, #0 839a: ed87 0a01vstrs0, r7, #4(null)839e: edc7 0a00vstrs1, r7 83a2: ed97 7a01 vldr s14, r7, #4(null) 83a6: edd7

44、7a00 vldr s15, r7 83aa: ee67 7a27 vmul.f32 s15, s14, s15 83ae: eeb0 0a67 vmov.f32 s0, s15 83b2: f107 070c add.w r7, r7, #12 83b6: 46bd mov sp, r7 83b8: bc80 pop r7 83ba: 4770 bxlr 0000 83bc : 83bc: b580 push r7, lr 83be: af00 add r7, sp, #0 83c0: ed9f 0a09vldrs0, pc, #36(null); 83e8 83c4: eddf 0a09v

45、ldrs1, pc, #36(null); 83ec 83c8: f7ff ffe4 b8394 83cc: eef0 7a40 vmov.f32 s15, s0 83d0: eeb7 7ae7 vcvt.f64.f32 d7, s15 83d4: f248 4044 movw r0, #33860 ; 0x8444 83d8: f2c0 0000 movt r0, #0 83dc: ec53 2b17 vmov r2, r3, d7 83e0: f7ff ef82 blx 82e8 83e4: bd80 pop r7, pc 83e6: bf00 nop 而使用没有“hf”前缀的arm-linux-gnueabi-gcc编译并反汇编的结果则为 000 0838c : 838c: b480 push r7 838e: b083 sub sp, #12 8390: af00 add r7, sp, #0 8392: 6078 str r0, r7, #48394: 6039 str r1, r7, #08396: ed97 7a01 vldr s14, r7, #4(null)839a: edd7 7a00 vldr s15, r7 839e: ee67 7a27 vmu

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/环境 > 建筑资料


经营许可证编号:宁ICP备18001539号-1