第一章:嵌入式系统设计基础
- 嵌入式系统的定义
IEEE定义:嵌入式系统是“控制、监视或者辅助设备、机器和车间运行的装置
嵌入式系统是以应用为中心,以计算机技术为基础,采用可剪裁软硬件,适用于对功能、可靠性、成本、体积、功耗等有严格要求的专用计算机系统
- 嵌入式系统与桌面通用系统的区别
- 嵌入式系统中运行的任务是
专用而确定的
:形式多样、面向特定应用
;桌面通用系统需要支持大量的、需求多样的应用程序
- 嵌入式系统可采用多种类型的处理器和处理器体系结构;通用计算机采用少数的处理器类型和体系结构
- 嵌入式系统往往对
实时性
提出较高的要求 - 嵌入式系统中使用的操作系统一般是
实时操作系统
- 嵌入式系统的运行需要
高可靠性保障
,比桌面系统的故障容忍能力弱很多 - 嵌入式系统大多有
功耗约束
- 嵌入式系统比桌面通用系统
可用资源少得多
- 嵌入式系统的开发是一项
综合的计算机应用技术
,需要专用工具和特殊方法
- 嵌入式处理器的基本特征
- 微处理器由三大部分组成:
控制单元、算术逻辑单元、寄存器
;存储器分为主存和外存 - 在嵌入式系统中一般不采用硬盘而采用电子盘外存:
采用flash芯片存储数据,体积小、功耗低、抗震
- 嵌入式系统的大多数输入、输出接口和部分设备已经集成在嵌入式微处理器中
- 相比通用处理器,嵌入式处理器有以下特点:(1)
体积小、集成度高、价格较低
(2)可扩展的处理器结构
(3)功耗低
(4)对实时多任务有很强的支持能力
(5)具有功能很强的存储保护能力
- 嵌入式处理器的种类及特点(MCU、DSP、MPU、SOC)
嵌入式微处理器种类 | 特点 |
---|---|
(嵌入式微控制器)MCU | 又称单片机. (1)以某一微处理器内核为核心 (2)芯片内部集成 (ROM/EPROM、RAM、总线、总线逻辑、定时/计时器、WatchDog、I/O、串行口、脉宽调制输出、A/D、D/A、Flash RAM、EEPROM等各种必要功能和外设 ) (3)特点:单片化、体积大大减小,从而使成本和功耗下降、可靠性提高 |
(嵌入式DSP处理器)DSP | (1)采用哈弗结构和专用的硬件乘法器 (2)使用快速DSP指令(RISC) (3)适用于处理器运算速度要求较高、向量运算较多的应用领域 |
(嵌入式微处理器)MPU | (1)由通用计算机的CPU演变而来 (2)微处理器装配在专门设计的电路板上 |
(嵌入式片上系统)SOC | (1)一种系统集成芯片,功能可以完全由硬件完成,也可以由软硬件完成 (2)高密度、高速度、高抗干扰性 |
- 典型嵌入式处理器的特点及应用场景(ARM、MIPS、POWERPC)
典型嵌入式处理器 | 特点 | 应用场景 |
---|---|---|
ARM | (1)体积小、低功耗、低成本、高性能 (2)支持Thumb/ARM双指令集 (3)大量使用寄存器 (4)寻址方式灵活 (5)固定长度的指令 | 1.Cortex M系列处理器:低端嵌入式应用市场 2. 经典ARM及Cortex R系列处理器:中高端嵌入式应用市场 3.Cortex A系列处理器:高端嵌入式应用市场 |
MIPS | 高性能、高处理能力的高端嵌入式处理器 | 应用于消费类电子、下一代网络、宽带产品、智能卡、机顶盒、数字电视、DVD |
POWERPC | 可伸缩性好、方便灵活 | 应用于DSL调制解调器、SOHO路由器、远程接入服务器、DSLAM、执行局交换机设备、无线基站、企业路由器 |
- 嵌入式软件系统的体系结构及各个层次的任务
由下往上依次是驱动层、操作系统层、中间件层以及应用层
- 驱动层:
-
板级初始化程序
-
与系统软件相关的驱动
-
与应用软件相关的驱动
- 操作系统层:
包括嵌入式内核、嵌入式TCP/IP网络系统、嵌入式文件系统、嵌入式GUI系统和电源管理等部分
- 中间件层:主要包括嵌入式CORBA、嵌入式Java、嵌入式DCOM和面向应用领域的中间件软件
- 应用层:(1)
由多个相对独立的应用任务组成
(2)每个应用任务完成特定的工作,由操作系统调度各个任务的运行
- 嵌入式操作系统的主要特性
可配置、可剪裁,实时任务调度策略
适应多种处理器、可剪裁、轻量型、实时可靠、可固化
适应多种处理器
:像嵌入式微处理器一样,嵌入式操作系统也是多姿多彩的可根据应用的情况进行剪裁、配置
- 一般包括一个实时内核,其调度算法一般采用
基于优先级的可抢占的调度算法
高可靠
嵌入式操作系统
- 典型嵌入式操作系统的特点及应用场景(Linux、VXwork、QNX、uc/OS)
嵌入式操作系统 | 特点 | 应用场景 |
---|---|---|
Linux | (1)广泛的硬件支持 (2) 内核高效稳定 (3)开放源码,软件丰富 (4)优秀的开发工具 (5)完善的网络通信和文件管理机制 | Android、MeeGo |
VXwork | 高可靠性、高实时性、可剪裁性好、但非常昂贵 | 用于美国“极地登陆者”号、“深空二号”和火星气候轨道器等登陆火星探测器上 |
QNX | 高可靠性、高安全性、高度伸缩性、可灵活剪裁 | 广泛嵌入到汽车、智能机器、智能仪器仪表、机顶盒、通讯设备、PDA等应用,目前作为黑莓手机及黑莓平板电脑的操作系统 |
uc/OS | 开源、结构小、可剥夺、实时的 (缺点:不支持时间片轮转调度法) | 用于控制类等低端应用中。如照相机行业、医疗检测仪器、音响设施等 |
第二章:ARM处理器
- ARM微处理器的特点
高性能、低成本、低功耗
大量的寄存器,都可用于多种用途
Load/Store体系结构,非常强大的多寄存器Load和Store指令
3地址指令(两个源操作数寄存器和结果寄存器独立设定)
每条指令都条件执行,包含能在单时钟周期执行的单条指令内完成一项普通的移位操作和一项普通的ALU操作
通过协处理器指令集来扩展ARM指令集,包括在编程模式下增加了新的寄存器和数据类型
在Thumb体系结构中以高密度16位压缩形式表示指令集
- CISC与RISC体系结构的特点及区别
特点 | |
---|---|
CISC | (1)指令的种类繁多 (2) 指令功能强大 (3)指令机器码长度因指令不同而不同 (4)指令执行时间有较大的差异 (5)高性能微指令结构耗用大量晶体管,造成体积成本增加 |
RISC | (1)具有一个短小精悍的指令集 (2)指令具有相同的机器码位长 (3)95%的指令执行时间为一个时钟周期 (4)节省了大量晶体管,但无法实现高性能指令 (5)采用载入(Load/Store)模式 |
指标 | RISC | CISC |
---|---|---|
指令集 | 一个周期执行一条指令,通过简单指令的组合实现复杂操作;指令长度固定 | 指令长度不固定,执行需要多个周期 |
流水线 | 流水线每周期前进一步 | 指令的执行需要调用微代码的一个微程序 |
寄存器 | 更多通用寄存器 | 用于特定目的的专用寄存器 |
Load/Store结构 | 独立的Load/Store指令完成数据在寄存器和外部存储器之间的传输 | 处理器能够直接处理存储器中的数据 |
- 冯.洛依曼结构和哈弗结构的特点及区别
哈佛结构是一种将程序指令存储和数据存储分开的存储器结构。
- 特点:
是一种并行体系结构,即程序存储器和数据存储器是两个独立的存储器,每个存储器都独立编址、独立访问
。
哈佛结构可以允许在一个机器周期内同时获得指令字和操作数,从而提高了执行速度和数据的吞吐率。
哈佛结构的微处理器通常具有较高的执行效率
。其程序指令和数据指令分开组织和储存的,执行时可以预先读取下一条指令。
冯.洛依曼结构把程序本身当作数据来对待,程序和该程序的处理的数据用同样的方法存储。
- 特点:
计算机处理的数据和指令一律用二级制数表示。
计算机硬件由运算器、控制器、存储器、输入设备和输出设备五大部分组成。
- ARM微处理器的工作状态及区别
ARM状态,此时处理器执行32位的、字对齐的ARM指令
Thumb状态,此时处理器执行16位的、半字节对齐的Thumb指令
- ARM体系结构的存储器格式
ARM体系结构将存储器看作是从零地址开始的字节的线性组合
从零字节到三字节放置第一个存储的数据
从第四个字节到第七个字节放置第二个存储的字数据,依次排列
作为32位的微处理器,ARM体系结构所支持的最大寻址空间为4GB
ARM体系结构可以用两种方法存储字数据,分别是大端格式、小端格式
- ARM处理器的7种工作模式
工作模式 | 说明 |
---|---|
用户模式(usr) | ARM处理器正常的程序执行状态 |
快速中断模式(fiq) | 用于高速数据传输和信道处理 |
外部中断模式(irq) | 用于通用的中断处理 |
管理模式(svc) | 操作系统使用的保护模式 |
数据访问终止模式(abt) | 当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护 |
系统模式(sys) | 运行具有特权的操作系统任务 |
未定义指令终止模式(und) | 当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真 |
- ARM状态下的寄存器组织(未分组的寄存器<R0~R7>、分组寄存器< R8- R12>、R13、R14>、PC寄存器)
- R0~R7为
未分组的寄存器
,也就是说对于任何处理器模式,这些寄存器都对应于相同的32位物理寄存器
- 寄存器R8~R14为
分组寄存器
。它们所对应的物理寄存器取决于当前的处理器模式,几乎所有允许使用通用寄存器的指令都允许使用分组寄存器
(寄存器R13常作为堆栈指针、R14为链接寄存器) - 寄存器R15用作
程序计数器(PC)
,在ARM状态下,位[1:0]为0,位[31:2]用于保存PC
;在Thumb状态下,位[0]为0,位[31:1]用于保存PC
有关寄存器emmm太多了,此处仅总结一点点比较重要的
- 程序状态寄存器(CPSR)的结构及作用(SPSR?)
CPSR反映了当前处理器的状态
:
- 4个条件代码标志(负(N)、零(Z)、进位©和溢出(V) );
- 2个中断禁止位,分别控制一种类型的中断;
- 5个对当前处理器模式进行编码的位;
- 1个用于指示当前执行指令(ARM还是Thumb)的位。
CPSR:当前程序状态寄存器,反映当前处理器的状态
SPSR:备份程序状态字,保存异常发生前的CPSR
- 异常的基本概念
异常:非预知的引发处理器暂时脱离正常指令序列并转到另外的程序段去运行的现象称之为异常,所运行的程序段称为异常处理程序。是一种当前指令队列无法预知的程序调用过程
- 异常的响应及返回
异常发生会使得正常的程序流程被暂时停止。
对异常的响应:
- 1.
将下一条指令的地址存入相应连接寄存器LR,以便程序在处理异常返回时能从正确的位置重新开始执行
- 2.
将CPSR复制到相应的SPSR中
- 3.
根据异常类型,强制设置CPSR的运行模式位
- 4.
强制PC从相关的异常向量地址取下一条指令执行,从而跳转到相应的异常处理程序处,同时设置中断禁止位,以禁止中断发生
异常返回:
- 1.
将连接寄存器LR的值减去相应的偏移量后送到PC中
- 2.
将SPSR复制回CPSR中
- 3.
若在进入异常处理时设置了中断禁止位,要在此清除
- ARM处理器的寻址方式
寻址方式 | 说明 |
---|---|
立即寻址 | 也叫立即数寻址,操作数没有存储在寄存器或存储器中,而是包含在指令的操作码中 |
寄存器寻址 | 利用寄存器中的内容作为操作数,寄存器本身就是操作数地址 |
寄存器移位寻址 | 操作数由寄存器的数值进行相应移位而得到 |
寄存器间接寻址 | 以寄存器中的内容作为操作数的地址 |
基址变址寻址 | 将寄存器的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址 |
多寄存器寻址 | 一条指令可以完成多个寄存器的传送,这种寻址方式可以用一条指令完成传送最多16个通用寄存器的值 |
堆栈寻址 | 使用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶 |
相对寻址 | 以程序计数器PC的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址 |
- ARM的指令格式(立即数、条件码)
ARM指令的基本格式如下:
<opcode> {<cond>} {s} <Rd> , <Rn>{,op2}
其中<>号内的项是必须的, {}号内的项是可选的,各项的说明如下:
opcode:指令助记符; cond:执行条件
S:是否影响CPSR寄存器的值
Rd:目标寄存器; Rn:第1个操作数的寄存器
op2:第2个操作数
立即数:通常把在立即寻址方式指令中给出的数称为立即数(判断有点复杂)
条件码:当处理条件工作在ARM状态时,几乎所有的指令均根据CPSR中条件码的状态和指令的条件域有条件的执行
。当指令的执行条件满足时,指令被执行,否则指令被忽略
每一条ARM指令包含4位的条件码,位于指令的最高四位
- ARM9的指令系统(跳转指令、数据处理指令、存储器访问指令(Load/Store))
存储器访问指令:
- 把数据从存储器到寄存器的传送叫
加载(Load)
,数据从寄存器到存储器的传送叫存储(Store)
- Load/Store指令可分为三类:(1)
单寄存器数据加载/存储指令
(2)多寄存器加载/存储指令
(3)数据交换指令
数据处理指令:
只能对寄存器的内容进行操作,不允许对存储器中的数据进行操作,也不允许指令直接使用存储器的数据或在寄存器与存储器之间传送数据
- 分为3大类:(1)
数据传送指令
(2)算术逻辑运算指令
(3)比较指令
跳转指令:即分支指令,能够跳到指定地址或根据跳转地址的最低位来切换处理器状态
助记符 | 说明 | 操作 | 条件码位置 |
---|---|---|---|
B label | 分支指令 | PC<–label | B {cond} |
BL label | 带链接的分支指令 | LR<-PC-4, PC<-label | BL{cond} |
BX Rm | 带状态切换的分支指令 | PC<-Rm,切换处理器状态 | BX{cond} |
第三章:嵌入式Linux(基础操作+基础编程)
- Linux发展的5大支柱
Unix操作系统
Minix操作系统
GNU计划
POSIX标准
Internet
- Linux的发行版(ReadHat家族与Debian家族)
ReadHat:使用数量最多的Linux发行版
Debian:自由社会使用最多的发行版
- Linux版本的发展
从Linux诞生以来,Linux内核就没有停止过升级,从1991年0.01版本到1999年具有里程碑意义的2.2版本,一直到我们现在看到的x.x.xx版本
- Linux内核版本有两种:
稳定版和开发版
- Linux内核的
命名机制
:num.num.num(第一个数字是主版本号、第二个数字是次版本号、第三个数字是修订版本号)
- Linux基本命令(文件目录相关命令、压缩打包相关命令)
文件、目录相关命令
目录命令:
命令 | 作用 |
---|---|
ls / ls -l | 列目录 |
pwd | 显示当前目录名称 |
cd /etc --> cd ../bin | 更改当前目录 (即从etc目录到bin目录) |
mkdir mydir-->rmdir mydir | 建立和删除目录 |
文件操作命令:
命令 | 功能 |
---|---|
file | 显示指定文件的类型 |
touch | 建立指定名称的文件或更新文件时间 |
cp | 复制文件或目录 |
rm | 删除文件或目录 |
mv | 移动文件或目录,文件或目录重命名 |
find | 在指定目录查找符合条件的文件 |
find ./ -name 'file*'
//寻找前缀为file的文件
find ./ -iname 'file*'
//与上个命令相同,不过不区分要查找文件的首字母大小写
文本文件查看命令:
命令 | 功能 |
---|---|
cat | 显示文本文件内容 |
more | 分页显示文本文件内容 |
less | 分页显示文本文件内容,并可方便反复浏览 |
head | 显示文件首部内容 |
tail | 显示文件尾部内容 |
压缩打包相关命令:
文件后缀 | 解压命令 | 示例 |
---|---|---|
.a | tar xv | tar xv hello.a |
.z | uncompress | uncompress hello.z |
.gz | gunzip | gunzip hello.gz |
.tar.gz/.tgz | tar xvzf | tar xvzf hello.tar.z |
.tar.bz2 | tar jxvf | tar jxvf hello.tar.bz2 |
.rpm | 安装:rmp -i 解压:rmp2cpio | 安装:rpm -i hello.rpm 解压:rmp2cpio hello.rpm |
.deb | 安装:dpkg -i 解压:dpkg-dep --fsys-tarfile | 安装:dpkg -i hello.deb 解压:dpkg-dep --fsys-tarfile hello.deb |
-zip | unzip | unzip hello.zip |
- Linux程序开发过程及其使用的工具
- vi三种工作模式的相互转换关系
- GCC编译处理流程及文件类型
预处理
:分析各种预处理命令,如#define,#include,#if编译
:根据输入文件产生汇编语言程序汇编
:将汇编语言输入,产生扩展名为.o的目标文件链接
:以.o目标文件,库文件作为输入,生成可执行文件
- GCC的常用选项及GCC的常用编译指令
GCC常用选项:这个点看看PPT就好,太多了。。。。
GCC常用编译指令:
选项 | 用法 | 作用 |
---|---|---|
无选项编译链接 | gcc hello.c | 将hello.c预处理、汇编、编译并链接形成可执行文件,这里未指定输出文件,默认输出为a.out |
选项-o | gcc hello.c -o hello | 将hello.c预处理、汇编、编译并链接形成可执行文件helllo,-o选项用来指定输出文件的文件名 |
选项-E | gcc -E hello.c -o hello.i | 将hello.c预处理输出hello.i文件 |
选项-S | gcc -S hello.i | 将预处理输出文件hello.i汇编成hello.s文件 |
选项-c | gcc -c hello.s | 将汇编输出文件hello.s编译输出为hello.o文件 |
无选项链接 | gcc hello.o -o hello | 将编译输出文件hello.o链接成最终可执行文件hello |
选项-O | gcc -O1 hello.c hello | 使用编译优化级别1编译程序,级别为1~3,级别越大优化效果越好,但编译时间越长 |
选项-Wall | gcc -Wall hello.c -o hello | 能够显示所有的警告信息,以便于修改调试 |
- Makefile里的主要规则
个人觉得PPt讲解有点复杂,可以参考这篇文章简单编写Makefile
第四章:嵌入式软件编程技术
- 汇编语言的简单程序编程
- GUN ARM汇编语句格式
- 常用的预定义寄存器名称
- GNU汇编程序中的标号symbol
- 汇编程序段
- 定义段
- GNU汇编语言定义入口点
- GNU汇编中的常数
【理解下面的例题,会考其中的代码】
例1:用GNU ARM汇编1程序设计实现20的阶乘,并将其64位结果放在R9和R8寄存器中(其中R9放高32位,R8放低32位)
程序代码及注释如下:
.global _start
.text
_start:
MOV R8, #20 @低32位初始化为20
MOV R9, #0 @高32位初始化为0
SUB R0,R8, #1 @初始化计数器
Loop:
MOV R1,R9 @暂存高位值
UMULL R8,R9,R0,R8 @[R9 : R8] = R0 * R8
MLA R9,R1,R0,R9 @R9 = R1 * R0 + R9
SUBS R0,R0,#1 @计数器递减
BNE Loop @计数器不为0时继续循环
.Stop:
B Stop
.end @文件结束
- 可重入函数
如果某个函数可被多个任务并发调用而不会造成数据错误,则称该函数具有可重入性
可重入函数可在任意时刻打断,稍后继续运行时不会造成错误
- 中断及处理的硬件部分及软件部分
中断处理过程
硬件部分:
复制CPSR到SPSR_< mode>
设置正确的CPSR位
切换到< mode>
保存返回地址到LR_< mode>
设置PC跳转到相应的异常向量表入口
软件部分:
把SPSR和LR压栈
把中断服务程序的寄存器压栈
开中断,允许嵌套中断
中断服务程序执行完后,恢复寄存器
弹出SPSR和PC,恢复执行
- 高级语言与低级语言混合编程
若汇编代码较为简洁,可使用直接采用内联汇编,即在C语言中内嵌汇编语句的方法
否则要将汇编程序以文件的形式加入到项目中,按照ATPCS(ARM/Thumb过程调用标准)的规定与C程序相互调用与访问
(此处省略ATPCS规则)
汇编程序调用C语言的方法:
汇编程序编写要遵循ATPCS规则,以保证程序调用时参数正确传递
首先在汇编程序中使用IMPORT伪指令事先声明将要调用的C语言函数
然后通过BL指令来调用C函数
C语言调用汇编程序:
汇编程序编写也要遵循ATPCS规则,以保证程序调用时参数正确传递
首先在汇编程序使用EXPORT伪指令声明被调用的子程序,表示该子程序将在其他文件中调用
然后在C程序中使用extern关键字声明要调用的汇编子程序为外部函数
第五章:开发环境和调试技术
1.嵌入式软件开发流程
()里的内容为中间得到的结果,(重定向与下载)为操作,即将系统映像下载到目标板上
代码编程
(c/汇编源程序)–>交叉编译
(OBJ文件)–>交叉链接
–>(系统映像文件
)–>(重定向与下载到
)目标板
(再与宿主机开发平台一同进行调试
)
2.交叉编译与本地编译的区别
交叉调试 | 本地调试 |
---|---|
调试器和被调试程序运行在不同的计算机上 | 调试器和被调试程序运行在同一台计算机上 |
可独立运行 | 需要操作系统的支持 |
被调试程序的装载由调试器完成 | 被调试程序的装载由Loader程序完成 |
需要通过外部通信的方式来控制被调试程序 | 不需要通过外部通信的方式来控制被调试程序 |
可以调试不同指令集的程序 | 只能调试相同指令集的程序 |
3.主从机通信环境构建
通过串口、网络、USB或JTAG
建立通信连接
串口通讯特点:(应用场合:Windows下的超级终端和Linux下的minicom
)
- 驱动实现最简单
传输速度慢,距离短,不适合大数据量、长距离数据传输
- 需要在宿主机、目标机两端均提供驱动
- 常用于宿主机-目标机的字符流通讯
网络通讯特点:
- 驱动实现相对复杂,一般采用精简的网络通讯协议,如
TFTP进行通讯
- 常用于宿主机-目标机的
大数据量数据传输,可以作为串口通讯的补充
- 需要在宿主机、目标机两端均提供驱动
- 宿主机端实现服务器,目标机端提供客户端
USB特点:
简单易用
- 通常分主从设备端,主机端为主设备端,目标端为从设备端
- 主机端需要安装驱动程序,识别从设备后,可以传输数据
JTAG接口
4.开发环境构建中的仿真技术
- 宿主机端的仿真
- 目标机端的仿真
-硬件仿真开发(ROM Emulator、ICE、OCD)
-软件仿真开发 - Android仿真器
5.远程调试的方法(stub)及常见的三种方法
Prink
:调试内核代码时最常用的技术,在内核代码中加入prink()
,可以把所有关心的信息打印到屏幕上KGDB
:提供了一种使用GDB
调试Linux内核的机制,可以在内核中进行设置断点、检查变量值、单步跟踪程序运行等操作。使用KGDB
调试,需要两台机器买一台开发机,另一台目标机,两台机器之间通过串口或网口相连KDB
:由SGI公司开发的遵循GPL许可证的Linux内核调试工具
第六章:BootLoader技术
- 嵌入式系统启动流程
硬件加电
引导加载程序
:Boot代码、BootLoader等操作系统内核,如Linux内核
:根据特定的目标嵌入式硬件系统,定制的内核及启动参数加载文件系统
:包括根文件系统以及建立于flash内存设备上的文件系统运行用户程序
:1. 用户编写的完成特定功能的程序 2.一些用户程序运行在一个嵌入式图形用户界面上
- 典型引导加载方式
PC机中:磁盘启动方式
(BIOS、Boot Loader)
- BIOS负责检测并启动加载控制卡上的BIOS
- Boot Loader将内核映像从硬盘读到RAM中,设置相关参数,然后跳转到内核的入口点去运行,即开始启动操作系统
嵌入式系统中:网络启动
、flash启动
- 网络启动:需要有串口、以太网接口或者其他连接方式
- flash启动
- BootLoader概念
-
概念 :
在操作系统内核运行之前运行的一段小程序
-
功能
1.初始化硬件设备
2.建立内存空间的映射图
3.调整系统的软硬件环境,以便操作系统内核启动
-
一般不通用
1.依赖于处理器架构
2.依赖于具体的板级配置
3.不同的CPU有不同的Boot Loader
- BootLoader操作模式
启动加载模式
自主模式,是BootLoader的正常工作模式
下载模式
1.用户干预进入下载模式,在控制台打印提示信息,等待用户输入
2.可通过串口连接或网络连接等通信手段从主机下载文件
通用bootloader一般同时支持两种工作模式
1.如Blob或U-Boot
2.允许用户在这两种工作模式之间进行切换
- BootLoader的stage1与stage2主要步骤【不考】
stage1主要步骤:
硬件设备初始化
为加载BootLoader的stage2准备RAM空间
拷贝BootLoader的stage2到RAM空间
设置好堆栈
-跳转到stage2的C入口点
stage2主要步骤:
初始化本阶段要使用到的硬件设备
检测系统内存映射
将kernel映像和根系统映像从flash上读到RAM空间
为内核设置启动参数
调用内核
第七章:ARM-Linux内核
- Linux内核的组成
进程调度程序
:负责控制进程访问CPU。保证进程能够公平地访问CPU,同时保证内核可以准时执行一些必需的硬件操作内核管理程序
:使多个进程可以安全地共享机器地主存系统,并支持虚拟内存虚拟文件系统
:通过提供一个所有设备的公共文件接口,VFS抽象了不同硬件设备的细节。此外,VFS支持与其他操作系统兼容的不同的文件系统格式网络接口
:提供对许多建网标准和网络硬件的访问进程间通信
:子系统为进程与进程之间的通信提供了一些机制
- 内核源代码目录结构
- MMU主要作用
用一组寄存器实现:地址映射
;地址访问保护与限制
- 内核空间与用户空间
内核空间
:Linux内核的运行空间
用户空间
:用户程序所在的空间
内核空间
可以执行任意命令,调用系统的一切资源;
用户空间
只能执行简单的运算,不能直接调用系统资源,必须通过系统接口(又称 system call),才能向内核发出指令
- 作业、任务、程序、进程、线程之间的关系
Linux进程由三部分组成:
- 正文段
:存放程序代码的数据,具有只读的属性
- 用户数据段
:是进程在运行过程中处理数据的集合,它们是进程直接进行操作的所有数据,以及进程直接使用的进程堆栈
- 系统数据段
:存放着进程的控制信息,即进程控制块(PCB)
,它存放了程序的运行环境
- Linux进程创建–fork()
Linux系统中的进程
- 进程是
程序在处理机上的一次执行过程
,进程是处于执行期的程序,它是分配系统资源和调度的实体
- 进程包括
可执行的程序代码、打开的文件、挂起的信号、内核数据、地址空间、处理机状态、一个或多个可执行的线程等
Linux系统中的线程
- Linux系统将线程
看作是一种特殊的进程。线程被视为一个与其他进程共享某些资源的进程
- Linux进程状态转换
- Linux进程创建
frok()
:创建普通进程,copy on write(要复制父进程的页表)vfork()
:共享创建,完全无拷贝。几乎与fork函数一样,除了不拷贝父进程的页表项。子进程作为父进程的一个单独线程在其地址空间运行,父进程阻塞,直到子进程退出或执行exec()。子进程不能向地址空间写入。clone()
:介于frok()和vfork()之间,可以指定共享什么,拷贝什么
- ARM-Linux模块机制【考一个填空题】
(这里需要个人总结一下,背不了这么多)
内核模块
:
- 内核模块是一种没有经过链接,不能独立运行的目标文件,是在内核空间中运行的程序。经过链接装载到内核里面成为内核的一部分,可以访问内核的公用符号(函数和变量)
- 内核模块可以让操作系统内核在需要时载入和执行,在不需要时由操作系统卸载。它们扩展了操作系统内核的功能却不需要重新启动系统
- 如果没有内核模块,我们不得不一次又一次重新编译生成单内核操作系统的内核镜像来加入新的功能。
Linux支持动态可加载内核模块
- 模块的编译需要配置过的内核源码,生成的内核模块后缀为.ko
可根据需要动态加载/卸载,载入内核后,便为内核的一部分,与其他部分地位一致
- 内核更加模块化
- 配置更加灵活
Linux的模块主要由6部分组成:
- 1.模块的加载函数(必须)
- 2.模块的卸载函数(必须)
- 3.模块许可证(LICENSE)
- 4.模块参数(可选)
- 5.模块导出符号(可选)
- 6.模块作者等信息声明(可选)
内核模块相关命令:
- lsmod:列出内核已载入模块的状态
- insmod:向Linux内核添加删除模块
- rmmod:删除内核中的一模块
- modprobe:Linux内核添加删除模块
- depmod:分析可加载模块的依赖性,生成modules.dep文件和映射文件
- modinfo:显示内核模块的信息
第八章:嵌入式文件系统
- Linux常见文件系统
文件系统 | 最大文件名长度 | 最大文件大小 | 最大分区大小 |
---|---|---|---|
ext2 | 255bytes | 2TB | 16TB |
ext3 | 255bytes | 2TB | 16TB |
ext4 | 255bytes | 16TB | 1EB |
XFS | 255bytes | 8EB | 8EB |
Btrfs | 255bytes | 16EB | 16EB |
- XFS和Btrfs都使用了
B-tree
- NOR型闪存与NAND型闪存的特点
NOR型闪存的特点:
具有独立地址线、数据线,支持随机快速访问,容量较小
具有芯片内执行的功能,按照字节为单位进行随机写
NOR型闪存适合用来存储少量的可执行代码
NAND型闪存的特点:
地址线、数据线共用。单元尺寸比NOR型器件小,具有更高的价格容量比,可以达到高存储密度和大容量
读、写操作单位采用512字节的页面
NAND更适合作为高密度数据存储
- NAND闪存管理中的问题
Flash的写入操作只能把对应位置的1修改为0,而不能把0修改为1,因此,一般情况下,向Flash写入内容,需要先擦除对应的存储区间,这种擦除是以块为单位进行的
损耗均衡
:闪存上的每个块都具有擦除次数的上限,被称为擦除周期问题坏块处理问题
:NAND器件中的坏块是随机分布的,由于消除坏块的代价太高,因而使用NAND器件的初始化阶段进行扫描以发现坏块,并将坏块标记为不可用掉电保护问题
:文件系统应能保证在系统突然断电时,最大限度地保护数据,使文件恢复到掉电前地一个一致性状态
- 常见的FLASH文件系统
日志文件系统
Jffs2
:日志闪存文件系统版本2,主要用于NOR型闪存,基于MTD驱动层yaffs
:专为嵌入式系统使用NAND型闪存而设计的一种日志型文件系统,自带NAND芯片地驱动CRAMFS
:具有简单、压缩和只读等特点,不能直接在Flash上运行ROMFS
:简单的、紧凑的、只读的文件系统
- 根文件系统的作用及目录结构
根文件系统的作用:
- Linux内核在系统启动期间进行的最后操作之一就是安装根文件系统
- 根文件系统一直是
所有类UNIX系统不可或缺的组件
;根文件系统首先是内核启动时所mount的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行
目录结构:(链接库、设备文件、系统应用程序、系统初始化文件)
目录 | 内容 |
---|---|
bin | 必要的用户命令(二进制文件) |
sbin | 必要的系统管理员命令 |
usr | 大多数用户使用的应用程序和文件目录 |
proc | 提供内核和进程信息的proc文件系统 |
dev | 设备文件及其他特殊文件 |
etc | 系统配置文件 |
lib | 必要的链接库 |
*boot | 引导加载程序使用的静态文件 |
*home | 用户主目录 |
mnt | 临时挂载的文件系统的挂载点 |
*opt | 附加软件的安装目录 |
*root | root用户主目录 |
tmp | 临时文件目录 |
var | 监控程序和工具程序存放的可变数据 |
- 如何创建根文件系统
这个就是我们实验所做的内容的一部分,具体直接考【嵌入式课程实验报告】QEMU模拟Cortex-A9运行U-boot和Linux
第九章:嵌入式驱动设计
- 外部设备与CPU的通讯信息
控制信息
:告诉要进行什么处理状态信息
:当前设备的状态数据信息
:不同的设备,传输数据类型及编码各异
- 输入、输出方式控制
直接控制I/O方式
:通过指令直接对端口进行输入、输出控制。如x86的in、out指令内存映射方式
:可以访问较大的地址空间,实现快速数据交换中断方式
:采用中断实现数据的输入/输出DMA方式
:采用DMA控制器,实现数据传输
(1)数据量不大的情况下,如字符设备,常采用中断方式
(2)大量数据传输的I/O设备,如磁盘、网卡等设备,常采用DMA方式,以减少CPU资源占用
- 驱动程序与应用程序的区别
Linux中以模块的形式加载各种驱动程序:
- 1)
主动与被动的区别
。应用程序有一个main函数,总是从函数开始主动执行一个任务,而驱动程序安装之后,便停止工作,并等待被应用程序调用 - 2)
使用的库函数不同
- 3)
程序运行的区域不同
。驱动程序工作在内核态
;应用程序工作在应用态
- 设备分类
字符设备
:无需缓冲直接读写块设备
:(1)通过buffer或cache进行读写 (2)支持块的随机访问网络设备
:通过BSD套接口访问
- 设备文件和设备号之间的关系
每个设备文件都对应有两个设备号:
主设备号
,标识设备的种类,使用的驱动程序次设备号
,标识使用同一设备驱动程序的不同硬件设备
- 设备文件接口
Linux应用程序可以通过设备文件的一组固定的入口点来访问驱动程序,这组入口点是由每个设备的设备驱动程序提供的
系统试图使它对各类设备的输出、输入看起来就像是对普通文件一样。因此,把设备映射为一种特殊的文件
- 分配和释放设备号
在使用cdev_add()向系统注册字符设备之前应先申请设备号,采用如下函数:
- 已知设备号:
int register_chrdev_region(dev_t from, unsigned count, const char *name);
#from:设备编号的起始值,此设备号为0;count申请分配的连续设备号的个数;name:和设备关联的名称
- 未知设备号:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
释放设备号:
使用上面两种方式申请的设备号,都应该在不使用设备时,释放设备号。设备号的释放统一使用下面的函数:
void unregister_chrdev_region(dev_t from, unsigned count);
- 内核空间与用户空间之间复制数据的方法
在用户空间不能直接访问内核空间的内存,因此借助下面两个函数,分别用来把数据从用户空间拷贝到内核空间,以及从内核空间拷贝到用户空间:
#从用户态拷贝到内核态:
unsigned long copy_from_user(void *to, const void _user* from, unsigned long count);
#从内核态拷贝到用户态:
unsigned long copy_to_user(void _user* to, const void *from, unsigned long count);