参看BLOG:http://blog.csdn.net/linuxdianc/article/details/5026426#
BootLoader
软件层次
一个嵌入式系统从软件角度来看分为三个层次:
1. 引导加载程序
包括固化在固件(fireware)中的boot程序(可选)(比如CMOS中的BIOS),和BootLoader(比如grub)两大部分
2.Linux内核
特定嵌入式平台的定制内核
3.文件系统
包括了系统命令和应用程序
PC机的引导加载程序由BIOS(其本质是一段固件程序)和GRUB和 LILO一起组成。BIOS在完成硬件检测和资源分配后,将硬盘中的引导程序读到系统内存中然后将控制权交给引导程序。引导程序的主要任务是将内核从硬盘上读到内存中,然后跳转到内核的入口点去运行,即启动操作系统
定义
在嵌入式系统中,通常没有想BIOS那样的固件程序,因此整个系统的加载启动任务就完全由BootLoader来完成。比如在一个基于ARM7TDMI core的嵌入式系统中,系统在上电或复位时都从地址0x00000000开始执行。而在这个地址处安排的通常就是系统的BootLoader程序
简单地说,BootLoader就是在操作系统运行之前运行的一段小程序。通过这段小程序,可以初始化硬件设备,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统做好准备。
安装
系统加电或复位后,所有的CPU通常都从CPU制造商预先安排地址开始执行。比如,S3C6410在复位后从地址0x00000000起开始执行。而嵌入式系统则将固态存储设备(比如:FLASH)安排在这个地址上,而bootloader程序又安排在固态存储器的最前端,这样就能保证在系统加电后,CPU首先执行BootLoader程序
流程
BootLoader的启动过程可分为单阶段(Single-Stage)和多阶段(Muti-Stage)两种,通常多阶段的BootLoader具有更复杂的功能,更好的可移植性。从固态存储设备上启动的BootLoader大多采用两阶段,即启动过程可以分为stage1和stage2:stage1完成初始化硬件,为stage2准备内存空间,并将stage2复制到内存中,设置堆栈,然后跳转到stage2.
BootLoader的stage1通常包括以下步骤:
----硬件设备初始化
----为加载BootLoader的stage2准备RAM空间
----拷贝BootLoader的stage2到RAM空间中
----设置好堆栈(目的是为stage2中的C程序的运行搭建环境)
----跳转到stage2的C入口点
该阶段的程序主要是由汇编代码写成
BootLoader的stage2通常包括以下步骤:
----初始化本阶段要使用的硬件设备(板载硬件,比如串口、网口)
----将内核映像和根文件系统映像从flash上读到RAM中
----调用内核
该阶段的程序主要是由C代码写成
工作模式
大多数BootLoader都包含两种不同的工作模式:“启动模式”和“下载模式”,这种区别仅对于开发人员才有意义,从最终用户的角度来看,BootLoader的作用就是用来加载操作系统,而不存在所谓的启动模式与下载模式。
启动模式:处理器一旦上电后,不需要干预便能自动地启动bootloader,并通过bootloader启动内核
下载模式:CPU上电后,目标机上的BootLoader将通过串口或网络等通信手段从主机(Host)下载文件,然后控制启动流程(常用于开发时)。
所以,用户常见的是启动模式
交叉工具链
工具链:gcc、gdb、ld等工具的集合便是工具链(sets)
交叉:软件产生于宿主机,运行于目标机的开发模式
安装
进行嵌入式开发前,首先需安装交叉工具链,步骤如下:
1.解压工具链到某一目录下,例:
tar xvzf arm-linux-gcc-4.5.1-v6-vfp.tgz –C/ (-C表示解压到后面指定的目录。如果没有-C则是默认解压到当前目录。解压后可以进入/4.5.1/bin/,可见很多工具)
2.修改/etc/profile,添加
export PATH=$PATH: /4.5.1/bin(如果不修改/etc/profile,那么每次运行工具如arm-linux-gcc则必须使用全路径:/4.5.1/bin/arm-linux-gcc)
3.让第二步对环境变量的修改生效
运行source /etc/profile
上述三步骤之后,可以在任何目录下运行arm-linux-gcc
http://blog.csdn.net/yinjiabin/article/details/7369071
http://blog.csdn.net/dreambegin/article/details/6794673
工具使用
----编译器:arm-linux-gcc
arm-linux-gcc hello.c –o hello
和gcc的用法完全一样,不过gcc编译的运行在X86上,而arm-linux-gcc编译的运行在arm上
----反汇编工具:arm-linux-objdump
arm-linux-objdum –D –S hello
将二进制文件编程汇编代码
arm-linux-objdum–D –S hello > log 导出到log文件中
----ELF文件查看工具:arm-linux-readelf
arm-linux-readelf –a hello
查看的信息中,常用的是:Data项的大小端模式
Machine项
arm-linux-readelf –d hello 查看hello使用的动态库
UBoot
用于多种嵌入式CPU(MIPS、X86、ARM、XScale等)的bootloader程序,UBoot不仅支持嵌入式Linux系统的引导,还支持VxWorks,QNX等多种嵌入式操作系统。
U-BOOT启动流程
开发板上电后,执行U-BOOT的第一条指令,然后顺序执行U-BOOT启动函数。看一下board/smdk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序,第一个哟链接的是cpu/arm920t/start.o,那么U-BOOT的入口指令一定位于这个程序中
下载
从下面地址可以下载到uboot的源代码:
Ftp://ftp.denx.de/pub/u-boot/
目录结构
进入到UBOOT目录,可以得到如下的目录结构:
|--board
|--common
|--cpu
|--disk
|--doc
|--drivers
|--dtt
|--examples
|--fs
|--include
----board:和开发板有关的文件。每一个开发板都以一个子目录出现在当前目录中,比如:smdk2410,子目录中存放于开发板相关的文件
----common:实现Uboot支持的命令
----cpu:与特定CPU架构相关的代码,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录arm920t等
----disk:对磁盘的支持
----doc:文档目录,uboot有非常完善的文档,推荐阅读
----drivers:uboot支持的设备驱动程序都放在该目录,比如各种网卡、支持CFI的Flash、串口、USB等
.....
----tools:uboot的工具,如:mkimage、crc等等
编译
Uboot的Makefile从功能上可以分成两个部分:
1.执行每种board相关的配置
2.编译生成uboot.bin文件
uboot.bin的生成也分为两步,以mini2440开发板为例来说明,如下(申明:该演示所使用的u-boot为经过移植后的u-boot,未经移植的u-boot并不支持该6410开发板,移植过程将在嵌入式linux系统移植专题班讲解):
可以在/4.5.1/根目录下查看Makefile,来知道uboot支持哪些开发板(比如在这里可以查看smdk6410):
1. 选择要使用的board:
$make mini2440_config
2. 编译生成u-boot.bin:
#makeCROSS_COMPILE=arm-linux-
编译好后有个uboot.bin文件。之后将该文件烧写到开发板中去
UBoot命令
常用命令
尽管UBOOT提供了丰富的命令集,但不同的单板所支持的命令并不一定一样(可配置),help命令可用于查看当前单板所支持的命令。
不同的board支持的命令不一定一样(可配置)
环境变量相关
print(Printenv) 查看环境变量
——用法:
printenv:
-print values of all environment variables
printenv name ...
-print value of environment variable `name`
setenv:添加、修改、删除环境变量(存在于内存中,只在本次单板开机中有效)
——用法:
setenv name value...
-set environment variable `name` to `value...`
setenv name
-delete environment varible `name`
saveenv保存环境变量(存在于flash中)。将当前定义的所有变量及其值存入flash中
文件下载
tftp:通过网络下载文件(开发板必须有ip地址ipaddr和serverip)可以通过ping serverip看网络是否连通
注意:使用tftp,需要先配置好网络
如:
Uboot>setenv ethaddr 12:34:45:78:9A:BC
Uboot>setenv ipaddr 192.168.1.1
Uboot>setenv serverip 192.168.1.254(tftp服务器的地址)
例:
Uboot>tftp c0800000 uImage
把serber(ip=环境变量中设置的serverip)中服务目录下的uImage通过TFTP读入到0xc0800000处
loadb:通过串口下载(速度慢,少用)
内存操作
md显示内存区的内容。
md采用十六进制和ASCII码两种形式来显示存储单元的内容。这条命令还可以采用长度标识符 .l ,.w和.b;
md[.b , .w , .l]address
如:
md.w 100000
00100000:(显示的内容)
00100010:(显示的内容)
mm:修改内存,地址自动递增
mm [.b , .w ,.l] address
mm提供了一种互动修改存储器内容的方法。它会显示地址和当前值,然后提示用户输入。如果你输入了一个合法的十六进制数,这个新的值将会被写入该地址。然后提示下一个地址。如果你没有输入任何值,只是按了一下回车,那么该地址的内容保持不变。如果想结束输入,则输入空格,然后回车
如:mm 100000
00100000:(显示的内容)
00100004:(显示的内容)
FLASH操作
flinfo:查看flash扇区信息
用法:Uboot>flinfo
protect :flash写保护
打开或关闭扇区写保护
——用法:
protect off all
关闭所有扇区的写保护
protect on all
打开所有扇区的写保护
protect off start end
关闭从start到end扇区的写保护(start为要关闭的第1个扇区的起始地址,end为要关闭的最后一个扇区的结束地址)
protect on start end
打开从start 到end 扇区的写保护
erase:擦除flash扇区
——用法:
erase start end
擦除从start 到end的扇区,start为要擦除的第1个扇区的起始地址,end为要擦除的最后一个扇区的结束地址(在使用cp命令向NOR型flash写入数据之前必须先使用erase命令擦除flash,因为nor flash按字节写入时,无法写入1,所以必须通过擦除来写入1)
如:erase 30000 1effff
cp:数据拷贝
——用法:
cp[.b , .w , .l]saddress daddress len(默认是.l,即32位的拷贝)
cp提供了一种内存与内存,内存与flash之间数据拷贝的方法
例:
cp.b 31000000 50000 d0000
将内存地址0x31000000处的数据(长度为0xd0000)拷贝到地址0x50000处(flash中)
cp.b 32000000 120000 c0000
将内存地址0x32000000处的数据(长度为0xc0000)拷贝到地址0x120000处(flash中)
注意:必须先用erase命令擦除flash,才能用cp命令执行成功
执行程序
go:执行内存中的二进制代码,一个简单的跳转到指定地址
——go addr [arg...]
-start application at address `addr` , passing `arg` as arguments
bootm:执行内存中的二进制代码
——bootm [addr[arg...]]
-boot application image stored in memory passing arguments `arg..`;when booting a linux kernel , `arg`can be the address of an initrd image
bootm要求所有可执行的二进制代码前部有固定格式的文件头,那么如何做这个文件头呢?——uboot下tools中有个mkimage工具可以
注意:bootm可以没有addr地址,这时它自动执行个默认的地址
开发板信息
bdinfo——显示开发板信息
bdinfo命令(简写为bdi)将在终端显示诸如内存地址和大小、时钟频率、MAC地址等信息。这些信息在传递给linux内核一些参数时可能会用到
自动启动
1.设置自动启动——通过设置环境变量:
比如:Mini2440=>setenv bootcmd tftp 31000000 uImage \; bootm 31000000
Mini2440=>saveenv
——执行了两个操作并保存