1.12k likes | 1.42k Views
第九章 BootLoader. ◆ 理解Bootloader的概念与作用 ◆ 熟悉ViVi的配置与编译 ◆ 了解ViVi代码的主要结构与作用 ◆ 熟悉uboot移植与使用方法以及启动过程与工作原理。. 9.1 Bootloader 基础. 9.1.1 Bootloader 的简介 系统上电之后,需要一段程序来进行初始化:关闭 WATCHDOG 、改变系统时钟、初始化存储控制器、将更多的代码复制到内存中等等。如果它能将操作系统内核 ( 从本地 Flash 或通过网络 ) 复制到内存中运行,就称这段程序为 Bootloader 。.
E N D
◆理解Bootloader的概念与作用 ◆ 熟悉ViVi的配置与编译 ◆ 了解ViVi代码的主要结构与作用 ◆ 熟悉uboot移植与使用方法以及启动过程与工作原理。
9.1 Bootloader基础 9.1.1 Bootloader的简介 系统上电之后,需要一段程序来进行初始化:关闭WATCHDOG、改变系统时钟、初始化存储控制器、将更多的代码复制到内存中等等。如果它能将操作系统内核(从本地Flash或通过网络)复制到内存中运行,就称这段程序为Bootloader。
简单地说,Bootloader就是这么一小段程序,它在系统上电时开始执行,初始化硬件设备、准备好软件环境,最后调用操作系统内核。
Bootloader软件通常会通过串口来输入/输出。例如:输出出错或者执行结果信息到串口终端,从串口终端读取用户控制命令等。
Bootloader的实现严重依赖于具体硬件,在嵌入式系统中硬件配置千差万别,即使是相同的CPU,它的外设(比如Flash)也可能不同,所以需要进行一些移植。
大多数Bootloader包含两种不同的操作模式: (1)启动加载(Bootloading)模式 这种模式也称为自主(Autonomous)模式,也即Bootloader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。这种模式是Bootloader的正常工作模式,因此在嵌入式产品发布的时侯,Bootloader工作在这种模式下。
(2)下载(Downloading)模式 在这种模式下,目标机上的Bootloader将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如下载内核映像和根文件系统映像等。 从主机下载的文件通常首先被Bootloader保存到目标机的RAM中,然后再被Bootloader写到目标机上的Flash类固态存储设备中。
板子与主机间传输文件时,可以使用: ◆串口的xmodem/ymodem/zmodem协议,它们使用简单,只是速度比较慢; ◆使用网络通过tftp、nfs协议来传输,这时,主机上要开启tftp、nfs服务;还有其他方法,比如USB等。
像vivi或U-Boot等这样功能强大的Bootloader通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。像vivi或U-Boot等这样功能强大的Bootloader通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。 比如,U-Boot在启动时处于正常的启动加载模式,但是它会延时若干秒(这可以设置)等待终端用户按下任意键而将U-Boot切换到下载模式。如果在指定时间内没有用户按键,则U-Boot继续启动Linux内核。
1.网络启动方式 这种方式开发板不需要配置较大的存储介质。但是使用这种启动方式之前,需要把Bootloader安装到板上的EPROM或者Flash中。Bootloader通过以太网接口远程下载Linux内核映像或者文件系统。网络启动方式对于嵌入式系统开发来说非常重要。1.网络启动方式 这种方式开发板不需要配置较大的存储介质。但是使用这种启动方式之前,需要把Bootloader安装到板上的EPROM或者Flash中。Bootloader通过以太网接口远程下载Linux内核映像或者文件系统。网络启动方式对于嵌入式系统开发来说非常重要。
使用这种方式,目标板要有串口、以太网接口或者其他连接方式。 串口一般可以作为控制台,同时可以用来下载内核影像和文件系统。 串口通信传输速率过低,不适合用来挂接NFS文件系统。所以以太网接口成为通用的互连设备,一般的开发板都可以配置10 M以太网接口。
对于开发的嵌入式系统,可以把USB接口虚拟成以太网接口通信。这种方式在开发主机和开发板两端都需要驱动程序。 另外,可在服务器上配置启动相关网络服务。Bootloader下载文件一般都使用TFTP网络协议,还可以通过DHCP的方式动态配置IP地址。
DHCP/BOOTP服务为Bootloader分配IP地址并配置网络参数后,才能够支持网络传输功能。如果Bootloader可以直接设置网络参数,则可不使用DHCP。TFTP服务为Bootloader客户端提供文件下载功能,把内核映像和其他文件放在/tftpboot目录下。这样Bootloader可以通过简单的TFTP协议远程下载内核映像到内存,如图9.1.1所示。DHCP/BOOTP服务为Bootloader分配IP地址并配置网络参数后,才能够支持网络传输功能。如果Bootloader可以直接设置网络参数,则可不使用DHCP。TFTP服务为Bootloader客户端提供文件下载功能,把内核映像和其他文件放在/tftpboot目录下。这样Bootloader可以通过简单的TFTP协议远程下载内核映像到内存,如图9.1.1所示。 大部分引导程序都能够支持网络启动方式。例如:vivi与U-Boot也支持网络启动功能。
2.磁盘启动方式 传统的Linux系统运行在台式机或者服务器上,这些计算机一般都使用BIOS引导,并且使用磁盘作为存储介质。 进入BIOS设置菜单,可以探测处理器、内存、硬盘等设备,也可以设置BIOS从软盘、光盘或者某块硬盘启动。也就是说,BIOS并不直接引导操作系统。那么在硬盘的主引导区,还需要一个Bootloader,这个Bootloader可以从磁盘文件系统中把操作系统引导起来。
3.Flash启动方式 大多数嵌入式系统上都使用Flash存储介质。Flash有很多类型,包括NOR Flash、NAND Flash和其他半导体盘。其中,NOR Flash(也就是线性Flash)使用最为普遍。
NOR Flash可以支持随机访问,所以代码可以直接在Flash上执行。 Bootloader一般是存储在Flash芯片上的。另外,Linux内核映像和RAMdisk也可以存储在Flash上。通常需要把Flash分区使用,每个区的大小应该是Flash擦除块大小的整数倍。 下图所示,是Flash存储示意图。
Bootloader一般存贮在Flash的底端或者顶端,这要根据处理器的复位向量来设置。 要使Bootloader的入口位于处理器上电执行第一条指令的位置。 接着需要分配参数区,可以作为Bootloader的参数保存区域。然后是内核映像区。
Bootloader引导Linux内核,就是要从此处把内核映像解压到RAM中去,然后跳转到内核映像入口执行。Bootloader引导Linux内核,就是要从此处把内核映像解压到RAM中去,然后跳转到内核映像入口执行。 最后是文件系统区。 如果使用RAMdisk文件系统,则需要Bootloader解压文件系统到RAM中。 如果使用JFFS2文件系统,将直接挂接为根文件系统。 最后还可以分出一些数据区,这要根据实际需要和Flash大小来考虑。
这些分区是开发者定义的,Bootloader一般直接读/写对应的偏移地址。 在Linux内核空间,可以配置成MTD设备来访问Flash分区。但是,有的Bootloader也支持分区的功能,例如:Redboot可以创建Flash分区表,并且内核MTD驱动可以解析出Redboot的分区表。
除了NOR Flash,还有NAND Flash、Compact Flash、DiskOnChip等。 这些Flash具有芯片价格低、存储容量大的特点。 这些芯片一般通过专用控制器的I/O方式来访问,不能随机访问,因此引导方式跟NOR Flash也不同。在这些芯片上,需要配置专用的引导程序。 通常,这种引导程序起始的一段代码将整个引导程序复制到RAM中运行,从而实现自举启动,与磁盘启动相似。
9.1.2 Bootloader的种类 现在Bootloader种类繁多,比如x86上有LILO、GRUB等。 对于ARM架构的CPU,有U-Boot、Vivi等。它们各有特点,下面列出Linux的开放源代码的Bootloader及其支持的体系架构,如下表所示。
9.1.3 Bootloader的基本原理Bootloader是依赖于硬件而实现的,特别是在嵌入式领域。因此,在嵌入式领域里建立通用的Bootloader几乎是不可能的。尽管如此,仍然可以对Bootloader归纳出通用的概念,以指导用户对特定的Bootloader设计与实现。1.操作模式 大多数Bootloader都包含启动加载模式和下载模式两种不同的操作模式。
2.通信设备及协议 目标机上的Bootloader一般可通过串口与主机之间进行文件传输,传输协议通常是 xmodem/ymodem/zmodem协议中的一种。但是,串口传输的速度是有限的,因此通过以太网连接并借助TFTP协议来下载文件是个更好的选择。 此外,在通过以太网连接和 TFTP 协议来下载文件时,主机方必须有一个软件用来提供TFTP服务。
3.Bootloader 的功能与结构 由于Bootloader的实现依赖于CPU的体系结构,大多数Bootloader都分为stage1和 stage2两大部分。 依赖于CPU体系结构的代码,比如设备初始化代码等,通常都放在stage1 中,而且通常都通过汇编语言来实现,以达到短小精悍的目的; stage2则通常用C语言来实现,这样可以实现更复杂的功能,而且代码会具有更好的可读性和可移植性。
1)stage1 Bootloader的stage1通常包括以下工作: (1) 硬件设备初始化。 (2) 为加载Bootloader的stage2准备RAM空间。 (3) 拷贝Bootloader的stage2到RAM空间中。 (4) 设置堆栈。 (5) 跳转到stage2的C入口点。
2)stage2 stage2的代码通常用C语言来实现,以便于实现更复杂的功能以及取得更好的代码可读性和可移植性。但是与普通C语言应用程序不同的是,在编译和链接Bootloader程序时,不能使用glibc库中的任何支持函数。其原因是显而易见的。
从哪里跳转进main()函数呢?直接把main()函数的起始地址作为整个stage2 执行映像的入口点或许是最直接的想法,但是这样做有两个缺点: ① 无法通过main()函数传递函数参数; ② 无法处理main()函数的返回。 一种更为巧妙的方法是利用trampoline(弹簧床)的概念。
用汇编语言写一段trampoline小程序,并将这段trampoline小程序来作为stage2可执行映像的执行入口点。 然后在 trampoline汇编小程序中用CPU跳转指令跳入main()函数中去执行; 当main()函数返回时,CPU执行路径显然再次回到trampoline 程序。 简而言之,这种方法的思想就是:用这段trampoline小程序来作为main()函数的外部包裹(External Wrapper)。
9.2 ViVi Vivi是Mizi公司针对SAMSUNG的ARM架构CPU专门设计的,基本上可以直接使用,命令简单方便。不过其初始版本只支持串口下载,速度较慢。在网上出现了各种改进版本:支持网络功能、USB功能、烧写YAFFS文件系统映像等。
9.2.1 ViVi命令 ViVi有两种工作模式: 启动加载模式和下载模式 启动加载模式可以在一段时间后(时间可更改)自行启动Linux内核,这是ViVi的默认模式。 在下载模式下,ViVi为用户提供一个命令行接口,通过接口可以使用ViVi提供的一些命令。
下面将介绍这些命令的意义。 1) reset命令:复位Arm9系统。2) help命令:显示开发板上ViVi支持的所有命令。param help:显示param命令的用法。 3) part命令:用于对分区进行操作。通过part help,可以显示系统对part系列命令的帮助提示。可以显示系统对part系列命令的帮助提示,分别如表9.2.1所示。
4) load命令。下载程序到存储器(Flash或者RAM中)。通过load help,显示系统对load系列命令的帮助提示。load flash partname x:使用xmodom 协议通过串口下载文件并且烧写到partname分区。
例如: -load flash vivi x //注意,这里的vivi是分区名 -load flash kernel x -load flash root x load ram partname or addr x:使用xmodom协议通过串口下载文件到内存中。
5) param命令:用于对Bootloader参数进行操作。通过 param help,显示系统对param系列命令的帮助提示。param show:显示Bootloader的当前参数值。param reset:将Bootloader参数值复位成系统默认值。
param set paramname value:设置参数值。param set linux_cmd_line “linux bootparam”:设置Linux启动参数,参数linux bootparam表示要设置的Linux Kernel命令行参数。param save:保存参数设置。
6) boot命令:用于引导Linux kernel启动。通过boot help,显示系统对boot命令的帮助提示。 boot:以默认方式启动。boot ram ramaddr lenth:启动SDRAM中ramaddr处长度为lenth的Linux内核。
7) bon命令:用于对bon分区进行操作。通过bon help,显示系统对bon系列命令的帮助提示。bon分区是NAND Flash设备的一种简单的分区管理方式。 bon part info:显示系统中bon分区的信息。
bon part:建立系统的bon分区表。bon分区表被保存到NAND Flash的最后0x4000个字节中,即在NAND Flash的0x03FFC000~0x33FFFFFF范围内,分区表起始于0x03FFC000。
例如:下列代码分为三个区:0~192 KB、192 KB~1 MB、1 MB以上。vivi> bon part 0 192k 1M doing partition size = 0 size = 196608 size = 1048576check bad blockpart = 0 end = 196608
9.2.2 ViVi的配置与编译ViVi的配置与编译过程如下:1. 在宿主机上安装交叉编译器 首先以root 用户的身份登录到Linux下,进入/usr/local目录,创建名为arm的目录: cd /usr/local mkdir arm
将cross-2.95.3.tar.bz2文件解压到/usr/local/arm目录: tar jxvf cross-2.95.3.tar.bz2 –C /usr/local/arm 然后修改PATH变量:为了可以方便使用 arm-linux-gcc 编译器系统, 把arm-linux 工具链目录加入到环境变量PATH 中;
修改/etc/profile文件,添加pathmunge /usr/local/arm/2.95.3/bin,如下所示: # Path manipulation if [ `id -u` = 0 ]; then pathmunge /sbin pathmunge /usr/sbin pathmunge /usr/local/sbin pathmunge /usr/local/arm/2.95.3/bin fi pathmunge /usr/X11R6/bin after
保存上述修改,进入终端控制台输入: source /etc/profile //使刚才的环境变量生效 注意:设置环境变量后,重启或注销,设置的环境变量才能生效。 最后检测环境变量是否安装成功,在终端控制台输入: arm-linux-gcc -v