1.1、嵌入式Linux软件结构与分布
在一般情况下嵌入式Linux系统中的软件主要分为以下几部分:
1) 引导加载程序:其中包括内部ROM中的固化启动代码和Boot Loader两部分。内部固化ROM是厂家在芯片生产时候固化的,作用基本上是引导Boot Loader。有的芯片比较复杂,比如Omap3,他在flash中没有代码的时候有许多启动方式:USB、UART或以太网等等。而S3C24x0则很简单,只有Norboot和Nandboot。
2) Linux kernel 和drivers。
3) 文件系统。包括根文件系统和建立于Flash内存设备之上的文件系统(EXT4、UBI、CRAMFS等等)。它是提供管理系统的各种配置文件以及系统执行用户应用程序的良好运行环境的载体。
4) 应用程序。用户自定义的应用程序,存放于文件系统之中。
在Flash 存储器中,他们的一般分布如下:
1.2、嵌入式Linux中BootLoader
在linux内核的启动运行除了内核映像必须在主存的适当位置,CPU还必须具备一定的条件:
1. CPU 寄存器的设置: | R0=0; R1=Machine ID(即Machine Type Number,定义在linux/arch/arm/tools/mach-types); R2=内核启动参数在 RAM 中起始基地址; |
2. CPU 模式: | 必须禁止中断(IRQs和FIQs); CPU 必须 SVC 模式; |
3. Cache 和 MMU 的设置: | MMU 必须关闭; 指令 Cache 可以打开也可以关闭; 数据 Cache 必须关闭; |
而Boot Loader并不是Linux才需要,是几乎所有的运行操作系统的设备都具备的。我们的PC的BOIS就是BootLoader的一部分(只是前期引导,后面一般还有外存中的各种BootLoader),对于Linux PC来说,BootLoader = BIOS + GRUB/LILO。
二、Boot Loader的功能和选择
通过上面的讲述,我们可以知道:BootLoader是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境,最后从别处(Flash、以太网、UART)载入内核映像并跳到入口地址。
由于BootLoader直接操作硬件,所以她严重依赖于硬件,而且依据所引导操作系统的不同,也有不同的选择,对于嵌入式世界中更是如此。就S3C24x0而言,如果是引导Linux,一般选用韩国的mizi公司设计的vivi或者DENX软件工程中心的U-boot,如果是引导Win CE,就选用Eboot。如果是开发StrongARM 构架下的LART,就可选用由Jan-Derk Bakker 和 Erik Mouw发布的Blob(Boot Loader Object)。如果是要引导eCos系统,就可以选用同是Redhat公司开发的Redboot。
所以在嵌入式世界中建立一个通用的 BootLoader 几乎是不可能的,而有可能的是让一个 Boot Loader代码支持多种不同的构架和操作系统,并让她方便移植。U-boot就是支持多平台多操作系统的一个杰出代表。如果在开发S3C2440时熟悉了U-boot,再转到别的平台的时候就可以很快地完成这个平台下的U-boot移植,而且U- boot的代码结构越来越合理,对于新功能的添加也十分容易。
*推荐阅读: 嵌入式系统 Boot Loader 技术内幕
1、获取帮助
命令:help 或 ?
功能:查看当前U-boot版本中支持的所有命令。
如果你想获取某条命令的更详细的帮助,可以使用:
help <你想要查的指令>
或者? <你想要查的指令>,
甚至 h <你想要查的指令缩写>。
2、 内存/寄存器操作指令
常用的Nand Flash指令如下:
指令 | 功能 |
nand info | 显示可使用的Nand Flash |
nand device [dev] | 显示或设定当前使用的Nand Flash |
nand read addr off size | Nand Flash读取命令,从Nand的off偏移地址处读取size字节的数据到SDRAM的addr地址。 |
nand write addr off size | Nand Flash烧写命令,将SDRAM的addr地址处的size字节的数据烧写到Nand的off偏移地址。 |
nand write[.yaffs[1]] addr off size | 烧写yaffs映像专用的命令,.yaffs1 for 512+16 NAND |
nand erase [clean] [off size] | Nand Flash檫除命令,擦除Nand Flash的off偏移地址处的size字节的数据 |
nand bad | 显示Nand Flash的坏块 |
nand dump[.oob] off | 显示Nand Flash中的数据(16进制) |
nand scrub | 彻底擦除整块Nand Flash中的数据,包括OOB。可以擦除软件坏块标志。 |
nand markbad off | 标示Nand的off偏移地址处的块为坏块 |
格式: nm [.b, .w, .l] address
格式: mm [.b, .w, .l] address
格式: md [.b, .w, .l] address [# of objects]
格式: mw [.b, .w, .l] address value [count]
格式:cp [.b, .w, .l] source target count
[.b, .w, .l]代表了查看和修改形式:Byte、word、long
你可以试着修改LED相连的GPIO寄存器的数据寄存器值,可以控制LED的点亮!
先熄灭后点亮LED1的范例:(这个实验要结合芯片数据手册和mini2440的原理图来理解)
[u-boot@MINI2440]#md 0x56000014 1
[u-boot@MINI2440]#nm.w 0x56000014
3、Nor Flash指令
flinfo 打印Flash存储器的信息,并列出所有Sector。
flinfo N 单独打Flash存储器N Block的信息。(在有多块Nor Flash时使用)
后面带有(RO)的说明这个Sector已经写保护了。
因为Nor Flash的读取接口和SDRAM是一样的,所以Nor Flash的读取也是使用md命令。
但由于Nor Flash的烧写时序和SDRAM的写入不同,烧写Nor Flash 不能使用mm等命令,只能使用cp命令从内存拷贝到Nor Flash,而且烧写之前必须解除保护并擦除!命令如下:
protect :对Flash 写保护的操作,可以使能和解除写保护。
格式:
protect on/off start end
protect on/off start +end
protect on/off N:SF[-SL]
protect on/off bank N
protect on/off all
第1 个参数on 代表使能写保护;off 代表解除写保护。
第2 、3 参数是指定Flash 写保护操作范围
start end是照起始地址和结束地址定义范围,start是擦除块的起始地址;end 是擦除末尾块的结束地址。
例如:擦除Sector 2和Sector 3区域命令为erase 20000 3ffff 。
start +end是照起始地址和操作字节数定义范围,这种方式最常用。start是擦除块的起始地址;end 是擦除的字节数。
例如:擦除Sector 2和Sector 3区域命令为erase 20000 +20000
N:SF[-SL]是按照组和扇区,N 表示Flash 的Block号,SF 表示擦除起始Sector号,SL 表示擦除结束Sector号。
例如:擦除Block1 的Sector 2和Sector 3区域命令为erase 1:2-3。
bank N是擦除整个Block,擦除Block号为N 的整个Flash。
all是擦除全部Flash。
注意:Nor Flash擦除的最小单位是Sector,也就是0x10000字节,如果你定义的大小不满1 Sector或超过Sector的边界,那么被定义到的Sector会被全部擦除。
erase :擦除Flash的命令
格式:
erase start end
erase start +end
erase N:SF[-SL]
erase bank N
erase all
参数是指定Flash 擦除操作范围,跟写保护的方式相同。
4、USB 操作指令
指令 | 功能 |
usb reset | 初始化USB控制器 |
usb stop [f] | 关闭USB控制器 |
usb tree | 已连接的USB设备树 |
usb info [dev] | 显示USB设备[dev]的信息 |
usb storage | 显示已连接的USB存储设备 |
usb dev [dev] | 显示和设置当前USB存储设备 |
usb part [dev] | 显示USB存储设备[dev]的分区信息 |
usb read addr blk# cnt | 读取USB存储设备数据 |
SD卡的使用命令比较简单,只有初始化和设备信息的显示,读写是通过文件系统命令实现的。
mmc init [dev] - 初始化MMC子系统
mmc device [dev] - 查看和设置当前设备
使用和USB类似,在所有的命令使用前,必须先插入SD卡,然后使用:mmc init,以初始化MMC 控制器,获取设备信息。
6、 系统引导指令 boot 和bootd 都是运行ENV”bootcmd”中指定的指令。
bootm 指令是专门用于启动在SDRAM中的用U-boot的mkimage工具处理过的内核映像。
格式:bootm [addr [arg ...]]
addr 是内核映像所在的SDRAM中的地址
当启动的是Linux内核时,'arg' 可以使 initrd 的地址。
eeprom - I2C 接口的EEPROM 读写指令
格式:
eeprom read addr off cnt
eeprom write addr off cnt
第一个参数addr 是要写入或读出的数据在SDRAM中的存放地址;
第二个参数off 是在EEPROM中的偏移;
第三个参数cnt 是读写的数据字节数。
date - 设置和读取RTC
格式:
date [MMDDhhmm[[CC]YY][.ss]]
MM:月份
DD:日期
hh:小时
mm 分钟
CC:年份的前两个数字
YY:年份的后两个数字
ss:秒数
9、脚本运行指令run var [...]
var :ENV中的脚本名10、系统重启指令
reset -重启CPU
11、环境变量 环境变量 | 解释说明 |
bootdelay | 执行自动启动(bootcmd中的命令)的等候秒数 |
baudrate | 串口控制台的波特率 |
netmask | 以太网的网络掩码 |
ethaddr | 以太网的MAC地址 |
bootfile | 默认的下载文件名 |
bootargs | 传递给Linux内核的启动参数 |
bootcmd | 自动启动时执行命令 |
serverip | TFTP服务器端的IP地址 |
ipaddr | 本地的IP地址 |
stdin | 标准输入设备,一般是串口 |
stdout | 标准输出,一般是串口,也可以是LCD(VGA) |
stderr | 标准出错,一般是串口,也可以是LCD(VGA) |
要看到你的板上的ENV值可使用printenv命令。
你会发现有些有的ENV上面没有,原因是如果你没有设置这个环境变量就不会打印出,你也可以自己定义ENV,并在命令中使用${ENV}来调用它。同时你也可以删除这个ENV。设置ENV的命令是setenv,格式为:
setenv name value
第1个参数是环境变量的名称。
当你设置了ENV,它只保存在内存中,如果你要它保存在存放ENV的固态存储器中,请使用:saveenv。
[u-boot@apple_guet]#saveenv
如果在启动的时候会看到U-boot打印出:“Warning - bad CRC, using default environment”,说明U-boot没有在存放ENV的固态存储器中找到有效的ENV,只好使用你在编译的时候定义的默认ENV。如果U-boot存放ENV的固态存储器的驱动是OK的,那么只要运行 saveenv就可以把默认ENV写入固态存储器,下次启动就不会有这个警告了。
ENV可以放在许多固体存储器中,对于mini2440来说Nor Flash、Nand Flash或EEPROM都可以,就看你如何配置了(include/configs下的配置文件)。例如:
Nor Flash:
#defineCONFIG_ENV_IS_IN_FLASH 1
#defineCONFIG_ENV_OFFSET 0X40000
#defineCONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
Nand Flash:
#defineCONFIG_ENV_IS_IN_NAND 1
#defineCONFIG_ENV_OFFSET 0X40000
#defineCONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
EEPROM:
#defineCONFIG_ENV_IS_IN_EEPROM 1/* use EEPROM for environment vars */
#defineCONFIG_ENV_OFFSET 0x000/* environment starts at offset 0 */
#defineCONFIG_ENV_SIZE 0x400/* 1KB */
CONFIG_ENV_OFFSET是在整个存储器中的偏移地址;
CONFIG_ENV_SIZE是指其使用的大小。
注意:CONFIG_ENV_OFFSET和 CONFIG_ENV_SIZE的设置,不要覆盖了其他分区。
1) 通过网络、串口、U盘、SD卡等方式将文件传输到SDRAM;
2) 使用Nand Flash或Nor Flash相关的读写命令将SDRAM中的数据烧入Flash。
如果使用 SD卡或者U盘形式更新U-boot,那么首先SD卡或者U盘中必须有FAT32文件系统,并在里面存放了u-boot.bin 文件。
4.1、 通过SD卡烧入Nand Flash
[u-boot@apple_guet]#mmc init
[u-boot@apple_guet]#fatload mmc 1 0x30008000 u-boot.bin
[u-boot@apple_guet]#nand erase 0 0x40000
[u-boot@apple_guet]#nand write 0x30008000 0 0x40000
4.2、通过U盘烧入Nor Flash
[u-boot@apple_guet]#usb start
[u-boot@apple_guet]#usb part0
[u-boot@apple_guet]#fatload usb 0:4 0x30008000 u-boot.bin
[u-boot@apple_guet]#protect off all
[u-boot@apple_guet]#erase 0x0 0x3ffff
[u-boot@MINI2440]#cp.b 0x30008000 0x0 0x3ffff
4.3、通过TFTP服务烧入Nand Flash
[u-boot@apple_guet]#tftpboot 30008000 192.168.1.100:u-boot.bin
[u-boot@MINI2440]#nand erase 0 0x40000
[u-boot@apple_guet]#nand write 0x30008000 0 0x40000
4.4、通过NFS 服务烧入Nand Flash
[u-boot@apple_guet]#nfs 30008000 192.168.1.100:/home/tekkaman/development/share/u-boot.bin
[u-boot@apple_guet]#nand erase 0 0x40000
[u-boot@apple_guet]#nand write 0x30008000 0 0x40000
五、内核引导
内核的引导步骤如下:
2) 通过网络、串口、U盘、SD卡等方式将处理过的内核映像传输到SDRAM的一定位置(一般使用0x30008000)
3) 然后使用”bootm"等内核引导命令来启动内核。
5.1、mkimage工具作用
因为在用bootm命令引导内核的时候,bootm需要读取一个64字节的文件头,来获取这个内核映象所针对的CPU体系结构、OS、加载到内存中的位置、在内存中入口点的位置以及映象名等等信息。这样bootm才能为OS设置好启动环境,并跳入内核映象的入口点。而mkimage就是添加这个文件头的专用工具。具体的实现请看U-boot中bootm的源码和mkimage的源码。
mkimage工具的使用:
参数说明:
-A指定CPU的体系结构,可用值有:alpha、arm、x86、ia64、mips、mips64、ppc、s390、sh、sparc、sparc64、m68k等
-O指定操作系统类型,可用值有:openbsd、netbsd、freebsd、4_4bsd、linux、svr4、esix、solaris、irix、sco、dell、ncr、lynxos、vxworks、psos、qnx、u-boot、rtems、artos
-T指定映象类型,可用值有:standalone、kernel、ramdisk、multi、firmware、script、filesystem
-C指定映象压缩方式,可用值有:
none不压缩(一般使用这个,因为zImage是已经被bzip2压缩过的自解压内核)
gzip用gzip的压缩方式
bzip2用bzip2的压缩方式
-a指定映象在内存中的加载地址,映象下载到内存中时,要按照用mkimage制作映象时,这个参数所指定的地址值来下载
-e指定映象运行的入口点地址,这个地址就是-a参数指定的值加上0x40(因为前面有个mkimage添加的0x40个字节的头)
-n指定映象名
-d指定制作映象的源文件
5.2、使用范例:
首先SD卡中必须有FAT32文件系统,并在里面存放了处理过的内核映像文件。
[u-boot@apple_guet]#mmc init
[u-boot@apple_guet]# fatload mmc 1 30008000 zImage.img
[u-boot@apple_guet]#bootm 30008000
2、通过TFTP服务引导内核
[u-boot@apple_guet]# tftpboot 0x30008000 192.168.1.122:zImage.img
[u-boot@apple_guet]# bootm 30008000
3、通过NFS服务引导内核
[u-boot@apple_guet]# nfs 30008000 192.168.1.100:/home/tekkaman/development/share/zImage.img
[u-boot@apple_guet]# bootm 30008000
4、通过Nand Flash引导内核:
[u-boot@apple_guet]# nfs 30008000 192.168.1.100:/home/tekkaman/development/share/zImage.img
Bytes transferred = 2277540 (22c0a4 hex)
[u-boot@apple_guet]# nand erase 0x80000 0x300000
[u-boot@apple_guet]# nand write 30008000 0x80000 300000
内核引导:
[u-boot@apple_guet]# nand read 30008000 0x80000 300000
[u-boot@apple_guet]# bootm 30008000