在学习系统移植的相关知识,在学习和调试过程中,发觉了好多问题,也解决了好多问题,但总是对于我们的开发结果有一种莫名其妙的觉得,纠其缘由,主要对于我们的开发环境没有一个深刻的认识,有时侯几个简单的命令就可以完成极其复杂的功能,而且我们有没有想过,为何会有这样的疗效?
若果没有去追问,只是机械地完成,但是见到实验疗效,这样做虽然并没有真正的把握系统移植的本质。
在做每一个步骤的时侯,首先问问自己,为何要这样做,之后再问问自己正在做哪些?搞明白这几个问题,我认为就差不多了,之后不管更换哪些平台,哪些芯片,哪些开发环境,你都不会迷糊,很快还会上手。对于嵌入式的学习方式,我个人方式就是:从宏观上掌握(解决为何的问题),微观上研究(解决正在做哪些的问题),下边以自己学习的arm-cortex_a8开发板为目标,介绍下自己的学习技巧和经验。
嵌入式Linux系统移植主要由四大部份组成:
一、搭建交叉开发环境
二、bootloader的选择和移植
三、kernel的配置、编译、和移植
四、根文件系统的制做
第一部份:搭建交叉开发环境
先介绍第一分部的内容:搭建交叉开发环境,首先必须得思索两个问题,哪些是交叉环境?为何须要搭建交叉环境?
先回答第一个问题,在嵌入式开发中,交叉开发是很重要的一个概念,开发的第一个环节就是搭建环境,第一步不能完成,前面的步骤从无谈起,这儿所说的交叉开发环境主要指的是:在开发主机上(一般是我的pc机)开发出才能在目标机(一般是我们的开发板)上运行的程序。嵌入式比较特殊的是不能在目标机上开发程序(狭义上来说),由于对于一个原始的开发板,在没有任何程序的情况下它根本都跑不上去,为了让它就能跑上去,我们还必需要利用pc机进行烧写程序等相关工作,开发板能够跑上去,这儿的pc机就是我们说的开发主机,想想若果没有开发主机,我们的目标机基本上就是难以开发,这也就是电子行业的一句格言:搞电子,说白了,就是玩笔记本!
之后回答第二个问题,为何须要交叉开发环境?主要诱因有以下几点:
缘由1:嵌入式系统的硬件资源有好多限制,例如cpu显存相对较低,显存容量较小等,想想让几百MHZ外频的MCU去编译一个Linuxkernel会让我们等的不耐烦,相对来说,pc机的速率更快,硬件资源愈发丰富,因而借助pc机进行开发会提升开发效率。
缘由2:嵌入式系统MCU体系结构和指令集不同,因而须要安装交叉编译工具进行编译,这样编译的目标程序才才能在相应的平台上诸如:ARM、MIPS、POWEPC上正常运行。
交叉开发环境的硬件组成主要由以下几大部份:
1.开发主机
2.目标机(开发板)
3.两者的链接介质,常用的主要有3种形式:(1)并口线(2)USB线(3)网线
对应的硬件介质,还必需要有相应的软件“介质”支持:
1.对于并口,一般用的有并口调试助手linux移植过程详解,putty工具等,工具好多,功能都差不多,会用一两款就可以;
2.对于USB线,其实必需要有USB的驱动才可以,通常芯片公司会提供,例如对于三星的芯片,USB下载主要由DNW软件来完成;
3.对于网线,则必需要有网路合同支持才可以,常用的服务主要两个
第一:tftp服务:
主要用于实现文件的下载,例如开发调试的过程中,主要用tftp把要测试的bootloader、kernel和文件系统直接下载到显存中运行,而不须要预先烧写到Flash芯片中,一方面,在测试的过程中,常常须要频繁的下载,假如每次把这种要测试的文件都烧写到Flash中之后再运行也可以,而且缺点是:过程比较麻烦,但是Flash的擦写次数是有限的;另外一方面:测试的目的就是把这种目标文件加载到显存中直接运行就可以了,而tftp就正好才能实现这样的功能,因而,更没有必要把这种文件都烧写到Flash中去。
第二:nfs服务:
主要用于实现网路文件的挂载,实际上是实现网路文件的共享,在开发的过程中,一般在系统移植的最后一步会制做文件系统,这么这是可以把制做好的文件系统放置在我们开发主机PC的相应位置,开发板通过nfs服务进行挂载,因而测试我们制做的文件系统是否正确,在整个过程中并不须要把文件系统烧写到Flash中去,并且挂载是手动进行挂载的,bootload启动后,kernel运行上去后会按照我们设置的启动参数进行手动挂载,因而,对于开发测试来讲,这些方法特别的便捷,才能提升开发效率。
另外,还有一个名子叫samba的服务也比较重要,主要用于文件的共享,这儿说的共享和nfs的文件共享不是同一个概念,nfs的共享是实现网路文件的共享,而samba实现的是开发主机上Windows主机和Linux虚拟机之间的文件共享,是一种跨平台的文件共享,便捷的实现文件的传输。
以上这几种开发的工具在嵌入式开发中是必备的工具,对于嵌入式开发的效率提升作出了伟大的贡献,因而,要对这几个工具熟练使用,这样你的开发效率会提升好多。等测试完成之后,才会把相应的目标文件烧写到Flash中去,也就是等发布产品的时侯才做的事情,因而对于开发人员来说,所有的工作永远是测试。
通过上面的工作,我们早已打算好了交叉开发环境的硬件部份和一部份软件,最后还缺乏交叉编译器,读者可能会有疑惑,为何要用交叉编译器?上面早已讲过,交叉开发环境必然会用到交叉编译工具,浅显地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上的程序,开发主机PC平台(X86CPU)上编译出能运行在以ARM为内核的CPU平台上的程序,编译得到的程序在X86CPU平台上是不能运行的,必须放在ARMCPU平台上能够运行,尽管两个平台用的都是Linux系统。相对于交叉编译,平时做的编译叫本地编译,也就是在当前平台编译,编译得到的程序也是在本地执行。拿来编译这些跨平台程序的编译器就叫交叉编译器,相对来说,拿来做本地编译的工具就叫本地编译器。所以要生成在目标机上运行的程序,必需要用交叉编译工具链来完成。
这儿又有一个问题,不就是一个交叉编译工具吗?为何又叫交叉工具链呢?缘由很简单,程序不能光编译一下就可以运行,还得进行汇编和链接等过程,同时还须要进行调试,对于一个很大工程,还须要进行工程管理等等,所以,这儿说的交叉编译工具是一个由编译器、连接器和协程组成的综合开发环境,交叉编译工具链主要由binutils(主要包括汇编程序as和链接程序ld)、gcc(为GNU系统提供C编译器)和glibc(一些基本的C函数和其他函数的定义)3个部份组成。有时为了减少libc库的大小,也可以用别的c库来取代glibc,比如uClibc、dietlibc和newlib。
这么,怎么得到一个交叉工具链呢?是从网上下载一个“程序”然后安装就可以使用了吗?回答这个问题之前先思索这样一个问题,我们的交叉工具链顾名思义就是在PC机上编译出才能在我们目标开发平台例如ARM上运行的程序,这儿就又有一个问题了,我们的ARM处理器机型特别多,莫非有专门针对我们某一款的交叉工具链吗?如果有的话,可以想一想,那么多处理器平台,每位平台专门订制一个交叉工具链置于网路上,之后供你们去下载,想想可能须要找许久才会找到适宜你的编译器,毕竟这些做法不太合理,且浪费资源!为此,要得到一个交叉工具链,如同我们移植一个Linux内核一样,我们只关心我们须要的东西,编译我们须要的东西在我们的平台上运行,不须要的东西我们不选择不编译,所以,交叉工具链的制做方式和系统移植有着好多相像的地方,也就是说,交叉开发工具是一个支持好多平台的工具集的集合(类似于Linux源码),之后我们只需从这种工具集中找出跟我们平台相关的工具就行了,这么怎么能够找到跟我们的平台相关的工具,这就是涉及到一个怎样制做交叉工具链的问题了。
一般建立交叉工具链有如下三种方式:
方式一:分步编译和安装交叉编译工具链所须要的库和源代码,最终生成交叉编译工具链。该方式相对比较困难,适宜想深入学习建立交叉工具链的读者。若果只是想使用交叉工具链,建议使用下述的方式二建立交叉工具链。
方式二:通过Crosstool-ng脚本工具来实现一次编译,生成交叉编译工具链,该方式相对于方式一要简单许多,而且出错的机会也十分少,建议大多数情况下使用该方式建立交叉编译工具链。
方式三:直接通过网上下载早已制做好的交叉编译工具链。该方式的优点不用多说,其实是简单省事,但与此同时该方式有一定的恶果就是局限性太大,由于虽然是他人建立好的,也就是固定的,没有灵活性,所以建立所用的库以及编译器的版本似乎并不适宜你要编译的程序,同时似乎会在使用时出现许多莫名其妙的错误,建议读者慎用此方式。
crosstool-ng是一个脚本工具,可以制做出适宜不同平台的交叉编译工具链,在进行制做之前要安装一下软件:
$sudoapt-getinstallg++libncurses5-devbisonflextexinfoautomakelibtoolpatchgcjcvscvsdgawk
crosstool脚本工具可以在下载到本地,之后解压,接出来就是进行安装配置了,这个配置优点类似内核的配置。主要的过程有以下几点:
1.设定源码包路径和交叉编译器的安装路径
2.更改交叉编译器针对的架构
3.降低编译时的并行进程数,以降低运行效率,推动编译,由于这个编译会比较慢。
4.关掉JAVA编译器,降低编译时间
5.编译
6.添加环境变量
7.刷新环境变量。
8.测试交叉工具链
到此,嵌入式Linux系统移植四大部份的第一部份工作全部完成,接出来可以进行后续的开发了。
第二部份:bootloader的选择和移植
01BootLoader概念
就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立显存空间的映射图,因而将系统的软硬件环境带到一个合适的状态,便于为最终调用操作系统内核打算好正确的环境,他就是所谓的引导加载程序(BootLoader)。
02为何系统移植之前要先移植BootLoader?
BootLoader的任务是引导操作系统,所谓引导操作系统,就是启动内核,让内核运行就是把内核加载到显存RAM中去运行,那先问两个问题:第一个问题,是谁把内核迁往显存中去运行?第二个问题:我们说的显存是SDRAM,你们都晓得,这些显存和SRAM不同,最大的不同就是SRAM只要系统上电就可以运行,而SDRAM须要软件进行初始化能够运行,这么在把内核搬运到显存运行之前必需要先初始化显存吧,这么显存是由谁来初始化的呢?虽然这两件事情都是由bootloader来干的,目的是为内核的运行打算好软硬件环境,没有bootloadr我们的系统其实不能跑上去。
03bootloader的分类
首先更正一个错误的说法,好多人说bootloader就是U-boot,这些说法是错误的,准确来说是u-boot是bootloader的一种。也就是说bootloader具有好多种类,
由上图可以看出,不同的bootloader具有不同的使用范围,其中最令人瞩目的就是有一个叫U-Boot的bootloader,是一个通用的引导程序,并且同时支持X86、ARM和PowerPC等多种处理器构架。U-Boot,全称UniversalBootLoader,是遵照GPL条款的开放源码项目,是由英国DENX小组开发的用于多种嵌入式CPU的bootloader程序,对于Linux的开发,日本的u-boot作出了巨大的贡献,并且是开源的。
u-boot具有以下特性:
①开放源码;
②支持多种嵌入式操作系统内核,如Linux、NetBSD,VxWorks,QNX,RTEMS,ARTOS,LynxOS;
③支持多个处理器系列,如PowerPC、ARM、x86、MIPS、XScale;
④较高的可靠性和稳定性;
⑤高度灵活的功能设置,适宜U-Boot调试、操作系统不同引导要求、产品发布等;
⑥丰富的设备驱动源码,如并口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等;
⑦较为丰富的开发调试文档与强悍的网路技术支持;
虽然,把u-boot可以理解为是一个大型的操作系统。
04u-boot的目录结构
*board目标板相关文件,主要包含SDRAM、FLASH驱动;
*common独立于处理器体系结构的通用代码,如显存大小侦测与故障检查;
*cpu与处理器相关的文件。如mpc8xx子目录下含并口、网口、LCD驱动及中断初始化等文件;
*driver通用设备驱动,如CFIFLASH驱动(目前对INTELFLASH支持较好)
*docU-Boot的说明文档;
*examples可在U-Boot下运行的示例程序;如hello_world.c,timer.c;
*includeU-Boot头文件;尤其configs子目录下与目标板相关的配置头文件是移植过程中常常要更改的文件;
*lib_xxx处理器体系相关的文件,如lib_ppc,lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;
*net与网路功能相关的文件目录,如bootp,nfs,tftp;
*post上电自检文件目录。尚有待于进一步建立;
*rtcRTC驱动程序;
*tools用于创建U-BootS-RECORD和BIN镜像文件的工具;
05u-boot的工作模式
U-Boot的工作模式有启动加载模式和下载模式。启动加载模式是Bootloader的正常工作模式,嵌入式产品发布时,Bootloader必须工作在这些模式下,Bootloader将嵌入式操作系统从FLASH中加载到SDRAM中运行,整个过程是手动的。下载模式就是Bootloader通过个别通讯手段将内核映像或根文件系统映像等从PC机中下载到目标板的SDRAM中运行linux伊甸园,用户可以借助Bootloader提供的一些令插口来完成自己想要的操作,这些模式主要用于测试和开发。
06u-boot的启动过程
大多数BootLoader都分为stage1和stage2两大部份,U-boot也不例外。依赖于cpu体系结构的代码(如设备初始化代码等)一般都置于stage1且可以用汇编语言来实现,而stage2则一般用C语言来实现,这样可以实现复杂的功能,但是有更好的可读性和移植性。
1、stage1(start.s代码结构)
U-boot的stage1代码一般置于start.s文件中,它用汇编语言写成,其主要代码部份如下:
(1)定义入口。因为一个可执行的image必须有一个入口点,而且只能有一个全局入口,一般这个入口置于rom(Flash)的0x0地址,因而,必须通知编译器以使其晓得这个入口,该工作可通过更改联接器脚本来完成。
(2)设置异常向量(exceptionvector)。
(3)设置CPU的速率、时钟频度及中断控制寄存器。
(4)初始化显存控制器。
(5)将rom中的程序复制到ram中。
(6)初始化堆栈。
(7)转入ram中执行,该工作可使用指令ldrpc来完成。
2、stage2(C语言代码部份)
lib_arm/board.c中的startarmboot是C语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数主要完成如下操作:
(1)调用一系列的初始化函数。
(2)初始化flash设备。
(3)初始化系统显存分配函数。
(4)假如目标系统拥有nand设备,则初始化nand设备。
(5)假如目标系统有显示设备,则初始化该类设备。
(6)初始化相关网路设备,填写ip,c地址等。
(7)步入命令循环(即整个boot的工作循环)linux移植过程详解,接受用户从并口输入的命令,之后进行相应的工作。
07基于cortex-a8的s55pcpc100bootloader启动过程剖析
s5pc100支持两种启动方法,分别为USB启动方法和NandFlash启动方法:
1.S55PCPC100USB启动过程
[1]A8reset,执行iROM中的程序
[2]iROM中的程序按照S55PCPC100的配置管脚(SW1开关4,拨到4旁边),判定从那里启动(USB)
[3]iROM中的程序会初始化USB,之后等待PC机下载程序
[4]借助DNW程序,从PC机下载SDRAM的初始化程序到iRAM中运行,初始化SDRAM
[5]SDRAM初始化完毕arm linux,iROM中的程序继续接管A8,之后等待PC下载程序(BootLoader)
[6]PC借助DNW下载BootLoader到SDRAM
[7]在SDRAM中运行BootLoader
2.S55PCPC100Nandflash启动过程
[1]A8reset,执行IROM中的程序
[2]iROM中的程序按照S55PCPC100的配置管脚(SW1开关4,拨到靠4那儿),判定从那里启动(Nandflash)
[3]iROM中的程序驱动Nandflash
[4]iROM中的程序会拷贝Nandflash前16k到iRAM
[5]前16k的程序(BootLoader前半部份)初始化SDRAM,之后拷贝完整的BootLoader到SDRAM并运行
[6]BootLoader拷贝内核到SDRAM,并运行它
[7]内核运行上去后,挂载rootfs,但是运行系统初始化脚本
08u-boot移植(基于cortex_a8的s55pcpc100为例)
1.构建自己的平台
(1).下载源码包2010.03版本,比较稳定
(2).解压后添加我们自己的平台信息,以smdkc100为参考版,移植自己s55pcpc100的开发板
(3).更改相应目录的文件名,和相应目录的Makefile,指定交叉工具链。
(4).编译
(5).针对我们的平台进行相应的移植,主要包括更改SDRAM的运行地址,从0x20000000
(6).“开关”相应的宏定义
(7).添加Nand和网卡的驱动代码
(8).优化go命令
(9).重新编译makedistclean(彻底删掉中间文件和配置文件)makes5pc100_config(配置我们的开发板)make(编译出我们的u-boot.bin镜像文件)
(10).设置环境变量,即启动参数,把编译好的u-boot下载到显存中运行,过程如下:
1.配置开发板网路
ip地址配置:
$setenvipaddr192.168.0.6配置ip地址到显存的环境变量
$saveenv保存环境变量的值到nandflash的参数区
网路测试:
在开发开发板上ping虚拟机:
$ping192.168.0.157(虚拟机的ip地址)
假如网路测试失败,从下边几个方面检测网路:
1.网线联接好
2.开发板和虚拟机的ip地址是否配置在同一个网关
3.虚拟机网路一定要采用桥接(VM--Setting-->option)
4.联接开发板时,虚拟机须要设置成静态ip地址
2.在开发板上,配置tftp服务器(虚拟机)的ip地址
$setenvserverip192.168.0.157(虚拟机的ip地址)
$saveenv
3.拷贝u-boot.bin到/tftpboot(虚拟机上的目录)
4.通过tftp下载u-boot.bin到开发板显存
$tftp20008000(显存地址即可)u-boot.bin(要下载的文件名)
假如里面的命令未能正常下载:
1.serverip配置是否正确
2.tftp服务启动失败,重启tftp服务
#sudoservicetftpd-hparestart
5.烧录u-boot.bin到nandflash的0地址
$nanderase0(起始地址)40000(大小)擦出nandflash0-256k的区域
$nandwrite20008000((缓存u-boot.bin的显存地址)0(nandflash上u-boot的位置)40000(烧录大小)
6.切换开发板的启动方法到nandflash
1.关掉开发板
2.把SW1的开关4拨到4的这边
3.启动开发板,它就从nandflash启动