嵌入式linux应用开发完全手册_第1页
嵌入式linux应用开发完全手册_第2页
嵌入式linux应用开发完全手册_第3页
嵌入式linux应用开发完全手册_第4页
嵌入式linux应用开发完全手册_第5页
已阅读5页,还剩105页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 内 容 提 要本书全面介绍了嵌入式 Linux 系统开发过程中,从底层系统支持到上层 GUI 应用的方方面面,内容涵盖 Linux 操作系统的安装及相关工具的使用、配置,嵌入式编程所需要的基础知识(交叉编译工具的选项设置、Makefile 语法、ARM 汇编指令等),硬件部件的使用及编程(囊括了常见硬件,比如 UART、I2C、 LCD 等),U-Boot、Linux 内核的分析、配置和移植,根文件系统的构造(包括移植 busybox、glibc、制作映象文件等),内核调试技术(比如添加 kgdb 补丁、栈回溯等),驱动程序编写及移植(LED、按键、扩展串口、网卡、硬盘、SD 卡、LCD 和

2、USB 等),GUI 系统的移植(包含两个 GUI 系统:基于Qtopia 和基于 X),应用程序调试技术。 本书从最简单的点亮一个LED 开始,由浅入深地讲解,使读者最终可以配置、移植、裁剪内核,编写驱动程序,移植 GUI 系统,掌握整个嵌入式Linux 系统的开发方法。 本书由浅入深,循序渐进,适合刚接触嵌入式 Linux 的初学者学习,也可作为大、中专院校嵌入式相关专业本科生、研究生的教材。 前言背景知识 嵌入式 Linux 在嵌入式领域发展迅速、需求旺盛,但是嵌入式 Linux 的入门很难。初学者多是自己琢磨,效率不高。学习过程中碰到的问题千奇百怪,解决后却往往发现是极其低级的错误,以

3、作者为例,初学时在论坛疯狂发帖求教,现在回头一看不免感叹:怎么会提出这么弱智的问题?但是,当时就是被这类问题折磨得寝食难安。 相对于嵌入式 Linux 常识的匮乏,更大的困难是缺乏完善的知识结构:只了解硬件,或是只了解软件。对于有志于从事底层系统开发(比如改造 Bootloader、钻研内核、为新硬件编写驱动程序)的人,对于想从上层软件开发转到底层软件开发的人,应该看得懂电路原理图,看得懂芯片数据手册,清楚地知道软件是怎样和硬件发生作用的。 同样,对于想从硬件岗位转到软件岗位的人,对于想从传统单片机(比如 51 单片机)编程进一步学习“有操作系统的”嵌入式编程的人,需要找到一个学习的切入点:先

4、掌握各个硬件部件的简单编程,再将它们组合起来构成一个相对复杂的软件系统比如 Bootloader,进而编写基于操作系统的驱动程序,最后深入钻研操作系统内核。 对于尚未参加工作的在校生来说,缺乏实际的操作经验可能是就业的最大障碍。很多人买了开发板想进一步练习,却发现不知从何入手。 鉴于上述种种困难及需求,作者结合自己的学习经历、工作心得写成此书,期望能帮助读者加快嵌入式 Linux 的入门速度,并体会到深入学习嵌入式 Linux 的乐趣。 关于本书 本书以 S3C2410、S3C2440 开发板为例,从分析硬件上电执行的第一条指令开始,到构造出一个类似 PDA、基于 Linux 的桌面 GUI

5、系统,带领读者学习、掌握从最底层到最高层的软件编写方法。 本书主要涉及以下主题: 开发环境的搭建(包括安装 Linux 系统及日常使用的工具); 开发板上各硬件部件的使用方法及实际的编程操作; 2前言嵌入式 Linux 系统的构造(包括 Bootloader、内核、文件系统等);嵌入式 Linux 驱动程序的编写方法及大量实例; GUI 系统的移植(两个 GUI 系统:基于 Qtopia 和基于 X);调试技术(包括内核调试技术和应用程序调试技术)。 本书所有章节都以理论结合代码的方式进行讲解,并可按照书中说明进行实际操作,力求让读者“知其然,也知其所以然”。 本书内容及组织方式 本书按照嵌入

6、式 Linux 初学者的学习过程,从简单到复杂,从底层软件到上层软件进行讲解,全书分 5 篇,共 27 章。 第 1 篇(第 1 章至第 4 章)为嵌入式 Linux 开发环境构建篇,主要讲解以下内容。 第 1 章介绍基于 ARM 的嵌入式 Linux 系统的基本概念。 第 2 章讲解嵌入式开发环境的建立,包括在 PC 上安装、配置 Linux 操作系统,安装随书光盘。 第 3 章介绍交叉编译工具的选项、Makefile 的语法以及本书用到的 ARM 汇编指令及相关知识,这章可以当作阅读后续章节时的参考手册。 第 4 章介绍了一些日常工作要用到工具,比如源码阅读、编辑工具等。 第 2 篇(第

7、5 章至第 14 章)为 ARM9 嵌入式系统基础实例篇,具体内容如下。 本篇首先根据 S3C2410、S3C2440 的数据手册介绍各硬件部件的使用方法,然后介绍怎样编写程序来操作它们。文中穿插介绍了连接器的很多使用技巧,读者可以由此接触到“程序的内部结构”,这是单纯的上层开发人员所缺乏的。通过读写各个硬件部件的寄存器来操作硬件, 读者还可以深刻体会到“软件”和“硬件”是怎样发生作用的,是第 3 篇、第 4 篇的基础。 第 3 篇(第 15 章至第 18 章)为嵌入式 Linux 系统移植篇,主要讲解以下内容。 第 15 章深入分析 U-Boot(它负责引导内核)的代码结构,并详细介绍了将它

8、移植到开发板上的方法。 第 16 章首先分析了内核的代码结构,然后深入分析它的启动过程,最后将它移植到开发板上。 第 17 章先从整体上介绍了 Linux 文件系统的目录结构FHS 标准。然后构造文件系统:移植常用工具的集合 Busybox,移植 glibc 库,建立各个目录,建立配置文件。最后修改、编译一些工具,使用它们来制作 yaffs、jffs2 文件系统映象文件。 第 18 章介绍了 3 种内核调试技术:printk、kgdb 补丁、使用 Oops 信息进行栈回溯。 第 4 篇(第 19 章至第 24 章)为嵌入式 Linux 设备驱动开发篇,具体内容如下。在第 19 章中总体介绍了驱

9、动程序的编写、移植方法,在第 20 章介绍了内核的异常处理体系结构就是怎样使用中断。 其他章节都是一些例子:先总体介绍相关硬件的驱动程序架构,然后根据开发板的特性进行修改。 第 5 篇(第 25 章至第 27 章)为嵌入式 Linux 系统应用开发篇,主要讲解以下内容。 第 25 章移植了一个基于 Qtopia 的 GUI 系统,并且以简单的“Hello, world”程序为例编写、调试 GUI 程序。 前言3 第 26 章移植了一个基于 X 的 GUI 系统,里面涉及众多软件,读者可以体会到上层应用的开发过程,并且获得移植大型软件的经验。这章还介绍了一个名为 Scratchbox 的交叉编译

10、工具包,它虚拟出一个可以直接编译软件的目标机器,使得“交叉编译”变为“本地编译”,大幅减少了为非 x86 平台移植软件所需的工作量。 第 27 章介绍了几种简便的应用程序调试技术,包括使用 strace 工具跟踪系统调用和信号,使用memwatch 检查程序的内存漏洞,使用库函数backtrace 和backtrace_symbols来定位段错误。 本书特色由浅入深,从最简单的点亮 LED 讲起直至移植 GUI 系统。实例丰富,每个实例都详尽地介绍原理及分析代码。 结构合理,先总体介绍概念、架构,然后进行具体操作。包括初学者所碰到的常见问题。 参与本书编写的人员 本书由韦东山负责编写并统编全部

11、书稿,陈汉仪、于明俭对本书的写作提供了大力支持, 在此表示感谢。 感谢我的父母和女友,在本书写作过程中给了我强大的精神支持,鼓励、支持我,使我能够坚持写完本书。 同时参与编写的还有柴作朋、单辉、丁鹏、冯发勇、付贤会、葛仕明、何国宝、何圆明、何化成、黄永华、李志宏、廖娟、林清妹、陆江萍、祁晓璐、谭爱华、魏明辉、张帮芹、周 霜、朱旭琪等,在此一并表示感谢。 我们为本书开通了专用的网站,网址是 ,读者可以直接同我们交流, 共同学习和提高。 由于水平有限,书中难免遗漏和不足之处,恳请广大读者提出宝贵意见。本书责任编辑的联系方式是 huangyanptpress.

12、,欢迎来信交流。 编 者 2008 年 6 月 目录第 1 篇 嵌入式 Linux 开发环境构建篇1 章1.1嵌入式Linux 开发概述2第嵌入式系统介绍21.1.1 嵌入式系统的定义和特点21.1.2 嵌入式技术的发展历史3基于 ARM 处理器的嵌入式 Linux 系统ARM 处理器介绍51.2.2在嵌入式系统中选择嵌入式 Linux 的理由8第2 章嵌入式Linux 开发环境构建102.1硬件环境构建102.1.1 主机与目标板结合的交叉开发模式102.1.2 硬件要求11软件环境构建..52.2.6主机

13、Linux 操作系统的安装12主机 Linux 操作系统上网络服务的配置与启动18在主机 Linux 操作系统中安装基本的开发环境23光盘的内容结构及安装23安装交叉编译工具链25书中写作风格的约定28第3 章嵌入式编程基础知识293.1交叉编译工具选项说明293.1.1 arm-linux-gcc 选项293.1.2 arm-linux-ld 选项38 2目录3.1.3 arm-linux-objcopy 选项413.1.4 arm-linux-objdump 选项433.1.5汇编代码、机器码和存储器的关系以及数据的表示443.2Makefile 介绍453.2.1Makefile 规则4

14、53.2.2 Makefile 文件里的赋值方法463.2.3 Makefile 常用函数46常用 ARM 汇编指令及 ATPCS 规则523.3.1 本书使用的所有汇编指令523.3.2 ARM-THUMB 子程序调用规则 ATPCS553.3第 4 章Windows、Linux 环境下相关工具、命令的使用584.1Windows 环境下的工具介绍5..4代码阅读、编辑工具 Source Insight58文件传输工具 Cuteftp63远程登录工具 SecureCRT63TFTP 服务器软件 Tftpd32644.2Linux 环境下的工具、命令介绍65

15、...6代码阅读、编辑工具 KScope65远程登录工具 C-kermit69编辑命令 vi69查找命令 grep、find 命令71在线手册查看命令 man72其令:tar、diff、patch73第 2 篇 ARM9 嵌入式系统基础实例篇第 5 章GPIO 接口765.1GPIO 硬件介绍765.1.1 通过寄存器来操作 GPIO 引脚765.1.2 怎样使用软件来访问硬件77GPIO 操作实例:LED 和按键80.3硬件设计80程序设计及代码详解80实例测试86存储器控制87第 6 章6.1使用存储控制器

16、访问外设的原理87 目录.26.1.3S3C2410/S3C2440 的地址空间87存储控制器与外设的关系89存储控制器的寄存器使用方法916.2存储控制器操作实例:使用 SDRAM946.2.1 代码详解及程序的复制、跳转过程946.2.2 实例测试97第 7 章内存管理单元MMU987.1内存管理单元 MMU 介绍9...6S3C2410/S3C2440 MMU 特性98S3C2410/S3C2440 MMU 地址变换过程99内存的访问权限检查107TLB 的作用109Cache 的作用110S3C2410/S3C24

17、40 MMU、TLB、Cache 的控制指令1137.2MMU 使用实例:地址映射1.27.2.3程序设计113代码详解114实例测试124第 8 章NAND Flash 控制器1258.1NAND Flash 介绍和 NAND Flash 控制器使用12..4Flash 介绍125NAND Flash 的物理结构127NAND Flash 访问方法128S3C2410/S3C2440 NAND Flash 控制器介绍1348.2NAND Flash 控制器操作实例:读 Flash1358.2.1读 NAND Flash 的步骤1358.

18、2.2代码详解137第 9 章中断体系结构1439.1S3C2410/S3C2440 中断体系结构1439.1.1ARM 体系 CPU 的 7 种工作模式1439.1.2S3C2410/S3C2440 中断控制器1469.1.3中断控制器寄存器149中断控制器操作实例:外部中断1519.2.1按键中断代码详解1519.2.2实例测试1589.2 4目录第 10 章系统时钟和定时器15910.1时钟体系及各类时钟部件159.210.1.3S3C2410/S3C2440 时钟体系159PWM 定时器161WATCHDOG 定时器16410.2MPLL 和定时器操作实例16610

19、.程序设计166代码详解.16610.2.3实例测试170第 11 章通用异步收发器UART17111.1UART 原理及 UART 部件使用方法17.211.1.3UART 原理说明171S3C2410/S3C2440 UART 的特性172S3C2410/S3C2440 UART 的使用17311.2UART 操作实例17711.2.1代码详解17711.2.2实例测试180I2C 接口181I2C 总线协议及硬件介绍18112.1.1I2C 总线协议18112.1.2S3C2410/S3C2440 I2C 总线控制器184I2C 总线操作实例187

20、12.2.1I2C 接口 RTC 芯片 M41t11 的操作方法18712.2.2程序设计18812.2.3 设置/读取 M41t11 的源码详解18812.2.4 I2C 实例的连接脚本19512.2.5实例测试196第 12 章12.112.2第 13 章LCD 控制器19713.1LCD 和 LCD 控制器19713.1.1LCD 显示器19713.1.2S3C2410/S3C2440 LCD 控制器介绍199TFT LCD 显示实例21013.2.1程序设计21013.2.2代码详解21013.2.3实例测试22113.2 目录5第 14 章ADC 和触摸屏接口22214.1ADC 和

21、触摸屏硬件介绍及使用22.214.1.3S3C2410/S3C2440 ADC 和触摸屏接口概述222S3C3410/S3C2440 ADC 接口的使用方法224触摸屏原理及接口22614.2ADC 和触摸屏操作实例230.214.2.314.2.414.2.5硬件设计230程序设计230测试 ADC 的代码详解230测试触摸屏的代码详解232实例测试237第 3 篇 嵌入式 Linux 系统移植篇移植U-Boot240第 15 章15.1Bootloader 简介24015.1.1Bootloader 的概念24015.1.2Bootloader 的

22、结构和启动过程24115.1.3常用 Bootloader 介绍246U-Boot 分析与移植246.315.2.415.2.515.2.615.2.7U-Boot 工程简介246U-Boot 源码结构247U-Boot 的配置、编译、连接过程249U-Boot 的启动过程源码分析257U-Boot 的移植264U-Boot 的常用命令288使用 U-Boot 来执行程序292移植Linux 内核293第 16 章16.116.2Linux 版本及特点293Linux 移植准备294.216.2.316.2.4获取内核源码294内核源

23、码结构及 Makefile 分析295内核的 Kconfig 分析304Linux 内核配置选项30916.3Linux 内核移植313 6目录.216.3.316.3.416.3.5Linux 内核启动过程概述313修改内核以支持 S3C2410/S3C2440 开发板314修改 MTD 分区327移植 YAFFS 文件系统330编译、烧写、启动内核333第 17 章构建 Linux 根文件系统33517.1Linux 文件系统概述335.217.1.3Linux 文件系统的特点335Linux 根文件系统目录结构336Linux 文件属性介绍3401

24、7.2移植 Busybox34.217.2.3Busybox 概述341init 进程介绍及用户程序启动过程342编译/安usybox34617.3使用glibc 库35017.3.1glibc 库的组成35017.3.2安装 glibc 库35117.4构建根文件系统35.217.4.317.4.417.4.5构建 etc 目录352构建 dev 目录354构建其他目录356制作/使用 yaffs 文件系统映象文件356制作/使用 jffs2 文件系统映象文件360第 18 章Linux 内核调试技术36218.1内核打印函数 printk3621

25、8.1.1 printk 的使用36218.1.2 串口控制台364内核源码级别的调试方法366.3内核调试工具 KGDB 的作用与原理366给内核添加 KGDB 功能支持 S3C2410/S3C2440367结合可视化图形前端 DDD 和 gdb 来调试内核37218.3Oops 信息及栈回溯375.218.3.318.3.4Oops 信息来源及格式375配置内核使 Oops 信息的栈回溯信息更直观376使用 Oops 信息调试内核的实例376使用 Oops 的栈信息手工进行栈回溯380 目录7第 4 篇 嵌入式 Linux 设备驱

26、动开发篇第 19 章字符设备驱动程序38419.1Linux 驱动程序开发概述38419.1.1 应用程序、库、内核、驱动程序的关系38419.1.2 Linux 驱动程序的分类和开发步骤38519.1.3 驱动程序的加载和卸载387字符设备驱动程序开发38719.2.1 字符设备驱动程序中重要的数据结构和函数38719.2.2 LED 驱动程序源码分析38919.2第 20 章Linux 异常处理体系结构39620.1Linux 异常处理体系结构概述39620.1.1 Linux 异常处理的层次结构39620.1.2 常见的异常400Linux 中断处理体系结构4020

27、.20.2.4中断处理体系结构的初始化401用户注册中断处理函数的过程404中断的处理过程406卸载中断处理函数40920.3使用中断的驱动程序示例41020.3.1 按键驱动程序源码分析41020.3.2 测试程序情景分析415第 21 章扩展串口驱动程序移植41921.1串口驱动程序框架概述41921.1.1 串口驱动程序术语介绍41921.1.2 串口驱动程序的 4 层结构420扩展串口驱动程序移植42321.2.1 串口驱动程序低层代码分析42321.2.2 修改代码以支持扩展串口42521.2.3 测试扩展串口42921.2第 22 章网卡驱动程序移植43122.1

28、CS8900A 网卡驱动程序移植43122.1.1CS8900A 网卡特性43122.1.2CS8900A 网卡驱动程序修改432 8目录22.2DM9000 网卡驱动程序移植44122.2.1DM9000 网卡特性44122.2.2DM9000 网卡驱动程序修改442第 23 章IDE 接口和 SD 卡驱动程序移植45023.1IDE 接口驱动程序移植45023.1.1 IDE 接口相关概念介绍45023.1.2 IDE 接口驱动程序移植45223.1.3 IDE 接口驱动程序测试461SD 卡驱动程序移植464.323.2.4SD 卡相关概念介绍46

29、4SD 卡驱动程序移植465SD 卡驱动程序测试472磁盘分区表473第 24 章LCD 和 USB 驱动程序移植47524.1LCD 驱动程序移植47524.1.1 LCD 和 USB 键盘驱动程序框架47524.1.2 S3C2410/S3C2440 LCD 控制器驱动程序移植479USB 驱动程序移植48924.2.1USB 驱动程序概述48924.2配置内核支持 USB 键盘、USB 鼠标和 USB 硬盘.24.2.249124.2.3USB 设备的使用492第 5 篇 嵌入式 Linux 系统应用开发篇基于Qtopia 的 GUI 开发496第 25 章25.1嵌入式 GUI 介绍4

30、9625.1.1 Linux 桌面 GUI 系统的发展49625.1.2 嵌入式 Linux 中的几种 GUI499Qtopia 移植50.325.2.4主机开发环境的搭建501交叉编译、安装 Qtopia 2.2.0502开发自己的 Qt GUI 程序514在主机上使用模拟软件开发、调试嵌入式 Qt GUI 程序518第 26 章基于X 的 GUI 开发52426.1X Window 概述524 目录926.1.1 X 协议介绍52426.1.2 窗口管理器(Window manager)52626.1.3桌面环境(Desktop environme

31、nt)52626.2交叉编译工具包 Scratchbox526.226.2.326.2.4Scratchbox 介绍527安装 Scratchbox 及编译工具528在 Scratchbox 里安装交叉编译工具链529安装其他开发工具53526.3移植 X53626.3.1编译软件的基本知识53626.3.2 编译 X 的依赖软件53926.3.3 编译 Xorg542移植Matchbox54726.4.226.4.3下载源代码548编译 Matchbox548运行、试验 Matchbox55026.5移植 GTK+55326.5.1GTK+介绍5532

32、6.5.2GTK+移植553移植基于 GTK+/X 的 GUI 程序55526.6.1 xterm 移植55626.6.2 gtkboard 移植55726.626.6.3裁剪文件系统560第 27 章Linux 应用程序调试技术56427.1使用 strace 工具跟踪系统调用和信号56427.1.1 strace 介绍及移植56427.1.2 使用 strace 来调试程序565内存调试工具56827.2.1 使用 memwatch 进行内存调试56827.2.2 其他内存工具介绍:mtrace、dmalloc、yamd571段错误的调试方法57327.3.1 使用库函数 backtrac

33、e 和 backtrace_symbols 定位段错误57327.3.2 段错误调试实例57427.227.3参考文献578 第 15 章 移植 U-Boot本章目标了解 Bootloader 的作用及工作流程了解 U-Boot 的代码结构、编译过程移植 U-Boot 掌握常用的 U-Boot 命令15.1Bootloader 简介15.1.1Bootloader 的概念 1. Bootloader 的引入从前面的硬件实例可以知道, 系统上电之后, 需要一段程序来进行初始化: 关闭WATCHDOG、改变系统时钟、初始化存储控制器、将更多的代码复制到内存中等。如果它能将操作系统内核复制到内存中运

34、行,无论从本地(比如 Flash)还是从远端(比如通过网络),就称这段程序为 Bootloader。 简单地说,Bootloader 就是这么一小段程序,它在系统上电时开始执行,初始化硬件设备、准备好软件环境,最后调用操作系统内核。 可以增强 Bootloader 的功能,比如增加网络功能、从 PC 上通过串口或网络下载文件、烧写文件、将 Flash 上压缩的文件解压后再运行等,这就是一个功能更为强大的 Bootloader, 也称为 Monitor。实际上,在最终产品中用户并不需要这些功能,它们只是为了方便开发。 Bootloader 的实现非常依赖于具体硬件,在嵌入式系统中硬件配置千差万别

35、,即使是相同的 CPU,它的外设(比如 Flash)也可能不同,所以不可能有一个 Bootloader 支持所有的CPU、所有的电路板。即使是支持 CPU 架构比较多的 U-Boot,也不是一拿来就可以使用的 (除非里面的配置刚好与你的板子相同),需要进行一些移植。 2. Bootloader 的启动方式CPU 上电后,会从某个地址开始执行。比如 MIPS 结构的 CPU 会从 0xBFC00000 取第一条指令,而 ARM 结构的 CPU 则从地址 0x0000000 开始。嵌入式开发板中,需要把存储器件 15.1Bootloader 简介241ROM 或 Flash 等映射到这个地址,Bo

36、otloader 就存放在这个地址开始处,这样一上电就可以执行。 在开发时,通常需要使用各种命令操作 Bootloader,一般通过串口来连接 PC 和开发板, 可以在串口上输入各种命令、观察运行结果等。这也只是对开发人员才有意义,用户使用产品时是不用接串口来控制 Bootloader 的。从这个观点来看,Bootloader 可以分为以下两种操作模式(Operation Mode)。 (1) 启动加载(Boot loading)模式。 上电后,Bootloader 从板子上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。产品发布时,Bootloader 工作在

37、这种模式下。 (2) 下载(Downloading)模式。 在这种模式下,开发人员可以使用各种命令,通过串口连接或网络连接等通信手段从主机(Host)下载文件(比如内核映象、文件系统映象),将它们直接放在内存运行或是烧入 Flash 类固态存储设备中。 板子与主机间传输文件时,可以使用串口的 xmodem/ymodem/zmodem 协议,它们使用简单,只是速度比较慢;还可以使用网络通过 tftp、nfs 协议来传输,这时,主机上要开启 tftp、nfs 服务;还有其他方法,比如 USB 等。 像 Blob 或 U-Boot 等这样功能强大的 Bootloader 通常同时支持这两种工作模式,

38、而且允许用户在这两种工作模式之间进行切换。比如,U-Boot 在启动时处于正常的启动加载模式, 但是它会延时若干秒(这可以设置),等待终端用户按下任意键,而将 U-Boot 切换到下载模式。如果在指定时间内没有用户按键,则 U-Boot 继续启动Linux 内核。 15.1.2Bootloader 的结构和启动过程 1概述在移植之前先了解 Bootloader 的一些通用概念,对理解它的代码会有所帮助。嵌入式 Linux 系统从软件的角度通常可以分为以下 4 个层次。 (1) 引导加载程序,包括固化在固件(firmware)中的 boot 代码(可选)和 Bootloader 两大部分。 有些

39、 CPU 在运行 Bootloader 之前先运行一段固化的程序(固件,firmware),比如 x86结构的 CPU 就是先运行 BIOS 中的固件,然后才运行硬盘第一个分区(MBR)中的 Bootloader。在大多嵌入式系统中并没有固件,Bootloader 是上电后执行的第一个程序。 (2) Linux 内核。 特定于嵌入式板子的定制内核以及内核的启动参数。内核的启动参数可以是内核默认的,或是由 Bootloader 传递给它的。 (3) 文件系统。 包括根文件系统和建立于 Flash 内存设备之上的文件系统。里面包含了 Linux 系统能够运行所必需的应用程序、库等,比如可以给用户提

40、供操作 Linux 的控制界面的 shell 程序、动态连接的程序运行时需要的 glibc 或uClibc 库等。 (4) 用户应用程序。 特定于用户的应用程序,它们也存储在文件系统中。有时在用户应用程序和内核层之间 242第 15 章 移植U-Boot可能还会包括一个嵌入式图形用户界面。常用的嵌入式 GUI 有:Qtopia 和 MiniGUI 等。显然,在嵌入系统的固态存储设备上有相应的分区来存储它们,如图 15.1 所示为一个典型的分区结构。 图 15.1 嵌入式Linux 系统中的典型分区结构 “Boot parameters”分区中存放一些可设置的参数,比如 IP 地址、串口波特率、

41、要传递给内核的命令行参数等。正常启动过程中,Bootloader 首先运行,然后它将内核复制到内存中 (也有些内核可以在固态存储设备上直接运行),并且在内存某个固定的地址设置好要传递给内核的参数,最后运行内核。内核启动之后, 它会挂接( mount)根文件系统(“ Root filesystem”),启动文件系统中的应用程序。 2Bootloader 的两个阶段Bootloader 的启动过程可以分为单阶段(Single Stage)、多阶段(Multi-Stage)两种。通常多阶段的 Bootloader 能提供更为复杂的功能以及更好的可移植性。从固态存储设备上启动的 Bootloader

42、大多都是两阶段的启动过程。第一阶段使用汇编来实现,它完成一些依赖于CPU 体系结构的初始化,并调用第二阶段的代码;第二阶段则通常使用 C 语言来实现,这样可以实现更复杂的功能,而且代码会有更好的可读性和可移植性。 一般而言,这两个阶段完成的功能可以如下分类。 (1)Bootloader 第一阶段的功能。 硬件设备初始化。 为加载 Bootloader 的第二阶段代码准备 RAM 空间。复制 Bootloader 的第二阶段代码到 RAM 空间中。设置好栈。 跳转到第二阶段代码的 C 入口点。 在第一阶段进行的硬件初始化一般包括:关闭 WATCHDOG、关中断、设置 CPU 的速度和时钟频率、R

43、AM 初始化等。这些并不都是必需的,比如 S3C2410/S3C2440 的开发板所使用的 U-Boot 中,就将 CPU 的速度和时钟频率的设置放在第二阶段。 甚至,将第二阶段的代码复制到 RAM 空间中也不是必需的,对于 NOR Flash 等存储设备,完全可以在上面直接执行代码,只不过相比在 RAM 中执行效率大为降低。 (2)Bootloader 第二阶段的功能。 初始化本阶段要使用到的硬件设备。检测系统内存映射(memory map)。 将内核映象和根文件系统映象从 Flash 上读到 RAM 空间中。为内核设置启动参数。 调用内核。 为了方便开发,至少要初始化一个串口以便程序员与

44、Bootloader 进行交互。 15.1Bootloader 简介243所谓检测内存映射,就是确定板上使用了多少内存、它们的地址空间是什么。由于嵌入式开发中 Bootloader 多是针对某类板子进行编写,所以可以根据板子的情况直接设置,不需要考虑可以适用于各类情况的复杂算法。 Flash 上的内核映象有可能是经过压缩的,在读到 RAM 之后,还需要进行解压。当然, 对于有自解压功能的内核,不需要 Bootloader 来解压。 将根文件系统映象复制到 RAM 中,这不是必需的。这取决于是什么类型的根文件系统, 以及内核访问它的方法。 将内核存放在适当的位置后,直接跳到它的入口点即可调用内核

45、。调用内核之前,下列条件要满足。 (1)CPU 寄存器的设置。 R0=0。 R1=机器类型 ID;对于 ARM 结构的 CPU,其机器类型 ID 可以参见 linux/arch/arm/ tools/mach-types。 R2=启动参数标记列表在 RAM 中起始基地址。 (2) CPU 工作模式。 必须禁止中断(IRQs 和 FIQs)。 CPU 必须为 SVC 模式。 (3) Cache 和 MMU 的设置。 MMU 必须关闭。 指令 Cache 可以打开也可以关闭。数据 Cache 必须关闭。 如果用 C 语言,可以像下列示例代码一样来调用内核:3Bootloader 与内核的交互Boo

46、tloader 与内核的交互是单向的,Bootloader 将各类参数传给内核。由于它们不能同时运行,传递办法只有一个:Bootloader 将参数放在某个约定的地方之后,再启动内核,内核启动后从这个地方获得参数。 除了约定好参数存放的地址外,还要规定参数的结构。Linux 2.4.x 以后的内核都期望以标记列表(tagged list)的形式来传递启动参数。标记,就是一种数据结构;标记列表,就是挨着存放的多个标记。标记列表以标记 ATAG_CORE 开始,以标记 ATAG_NONE 结束。 标记的数据结构为 tag,它由一个 tag_header 结构和一个联合(union)组成。tag_h

47、eader 结构表示标记的类型及长度,比如是表示内存还是表示命令行参数等。对于不同类型的标记使用不同的联合(union),比如表示内存时使用 tag_mem32,表示命令行时使用 tag_cmdline。数据结构 tag 和 tag_header 定义在 Linux 内核源码的 include/asm/setup.h 头文件中,如下所示: void (*theKernel)(int zero, int arch, u32 params_addr) = (void (*)(int, int, u32)KERNEL_RAM_BASE;theKernel(0, ARCH_NUMBER, (u32)

48、kernel_params_start); 244第 15 章移植U-Boot下面以设置内存标记、命令行标记为例说明参数的传递。 (1)设置标记 ATAG_CORE。 标记列表以标记 ATAG_CORE 开始,假设 Bootloader 与内核约定的参数存放地址为 0x30000100,则可以以如下代码设置标记 ATAG_CORE: params = (struct tag *) 0x30000100;params-hdr.tag = ATAG_CORE;params-hdr.size = tag_size (tag_core);struct tag_header u32 size; u32

49、tag;struct tag struct tag_header hdr; union struct tag_corecore; struct tag_mem32mem;struct tag_videotextvideotext; struct tag_ramdisk ramdisk; struct tag_initrdinitrd; struct tag_serialnrserialnr; struct tag_revisionrevision; struct tag_videolfbvideolfb; struct tag_cmdline cmdline;/* Acorn specific

50、*/struct tag_acornacorn;/* DC21285 specific*/struct tag_memclk memclk; u; 15.1Bootloader 简介245其中,tag_next 定义如下,它指向当前标记的末尾:(2)设置内存标记。 假设开发板使用的内存起始地址为 0x30000000,大小为 0x4000000,则内存标记可以如下设置: (3)设置命令行标记。 命令行就是一个字符串,它被用来控制内核的一些行为。比如root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0表示根文件系统在 MTD2 分区上,系统启动后执

51、行的第一个程序为/linuxrc,控制台为 ttySAC0(即第一个串口)。 命令行可以在 Bootloader 中通过命令设置好,然后按如下构造标记传给内核。 (4)设置标记 ATAG_NONE。 标记列表以标记 ATAG_NONE 结束,如下设置:params-hdr.tag = ATAG_NONE; params-hdr.size = 0;char *p = root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0; params-hdr.tag = ATAG_CMDLINE;params-hdr.size = (sizeof (struct

52、tag_header) + strlen (p) + 1 + 4) 2;strcpy (params-u.cmdline.cmdline, p);params = tag_next (params);params-hdr.tag = ATAG_MEM;params-hdr.size = tag_size (tag_mem32);params-u.mem.start = 0x30000000; params-u.mem.size = 0x4000000;params = tag_next (params);#define tag_next(t) (struct tag *)(u32 *)(t) + (t)-hdr.size)params-u.core.flags = 0;params-u.core.pagesize = 0;params-u.core.rootdev = 0;params = tag_next (params); 246第 15 章 移植U-Boot15.1.3常用 Bootloader 介绍现在 Bootloader 种类繁多,比如

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论