一、移植环境
-
主 机:VMWare–Fedora 9
-
开发板:Mini2440–64MB Nand,Kernel:2.6.30.4
-
编译器:arm-linux-gcc-4.3.2.tgz
-
u-boot:u-boot-2009.08.tar.bz2
二、移植进程
-
tftp服务的装置与装备及测验;
-
nfs服务的装置与装备及测验;
-
u-boot到kernel的参数传递(要点)。
咱们知道运用tftp下载内核和运用nfs挂载文件体系的优点是,当咱们从头编译内核或文件体系后不必从头把这些镜像文件再烧录到flash上,而是把这些镜像文件放到开发主机的tftp或nfs服务的主目录下,经过网络来加载他们,不必频频的往flash上烧,这样一能够维护flash的运用寿命,二能够便利的调试内核或文件体系,进步开发功率。可见,让u-boot完成这个功用是一件很有含义的作业。
完成这样的功用很简略,网上也有许多材料。但有许多细节的东西假如稍不留意就导致失利,这儿就结合自己完成的进程进行叙述和一些问题的剖析。
-
tftp服务的装置与装备及测验
要运用tftp服务及测验它要装置两个软件包,一个便是tftp服务器,别的一个便是tftp客户端,这儿装置客户端仅仅用于在主机本地测验tftp服务器是否正常运转的,来保证u-boot能够拜访tftp服务(u-boot中已有tftp客户端的功用,其实在前面几篇中都现已运用了tftp下载内核或文件体系到开发板上,假如那里都做到了,这儿就能够直接越过)。
首要运用rpm指令检查你的主机上是否现已装置了tftp服务器和客户端,假如没有装置就去下载这两个软件包进行装置或许能够运用yum指令进行在线装置,yum会主动的去查找合适你主机渠道的最新软件包进行下载装置,假如主机现已装置了,则会提示软件包现已装置了最新的版别。如下图所示:
装备tftp服务器,主要是装备tftp的主目录及拜访权限。因tftp服务依赖于xinetd服务,所以一般tftp服务装置好后其装备文件一般会在/etc/xinetd.d/目录下:
-
nfs服务的装置与装备及测验
以root的身份在控制台输入setup,在体系服务选项中选中nfs服务,如下图:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/1032542.png” style=”padding:0px;margin:0px;border:0px;” />
装备NFS服务器的同享主目录,也要留意权限问题:
-
u-boot到kernel的参数传递
咱们知道,在kernel装备选项Boot options中有一个Default kernel command string参数项,而在u-boot参数中也有一个bootargs参数项,他们都是供内核发动用的,那他们又有什么区别呢,内核发动时究竟是用哪一个呢?两种参数项别离如下图所示(kernel中的参数指定是从开发板Flash分区上挂载文件体系,u-boot中的参数指定的是从NFS挂载文件体系):
那么,u-boot是假如将参数信息传递到内核中的呢?而内核又是怎样接纳u-boot传递过来的参数呢?这就涉及到一点点ARM寄存器的常识了。
咱们知道,ARM有7种作业形式和37个寄存器(31个通用寄存器和6个状况寄存器),如下图:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/1032545.png” style=”padding:0px;margin:0px;border:0px;” />
ARM作业形式之间的转化便是运用这些寄存器进行,而u-boot参数的传递也运用了三个通用寄存器R0、R1和R2。关于ARM作业形式和寄存器在这儿就不做讲叙了,今后再讲,这儿你就了解成u-boot在发动的时分把参数存放到这三个寄存器中,到内核发动时再把寄存器中的参数取出,当然,他们并不是就这样简略的操作。下面咱们看代码逐个剖析。
首要,咱们来剖析一下u-boot是怎样处理和发送要传递的参数,而u-boot要传递的参数又有哪些呢?除了咱们最简单知道的bootargs(即内核commandline)参数项外,要传递的参数还有MACH_TYPE(即咱们所说的机器码)、体系根设备信息(标志,页面巨细)、内存信息(开端地址,巨细)、RAMDISK信息(开端地址,巨细)、紧缩的RAMDISK根文件体系信息(开端地址,巨细)。由此可见要传递的参数许多,这时分,u-boot就供给一种叫做参数链表(tagged list)的方法把这些参数安排起来,链表结构体界说在:include/asm-arm/setup.h中,而完成链表的安排在lib_arm/bootm.c中:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/1032546.png” style=”padding:0px;margin:0px;border:0px;” />650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/1032547.png” style=”padding:0px;margin:0px;border:0px;” />
咱们能够看到,链表的安排是由一系列函数完成,u-boot规则,链表有必要以ATAG_CORE符号开端,以ATAG_NONE符号完毕,中心便是一些参数符号项,这点从代码中能够表现出来。那么在这些函数中有一个bd的参数是至关重要的,它是一个bd_info类型的结构体,界说在include/asm-arm/u-boot.h中,而这个结构体又被一个global_data类型的结构体所引证,界说在include/asm-arm/global_data.h中,如下:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/1032548.png” style=”padding:0px;margin:0px;border:0px;” />650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/1032549.png” style=”padding:0px;margin:0px;border:0px;” />
那么,那个bd参数究竟是做什么用的呢?从界说中能够得知,bd记载了机器码、u-boot参数链表在内存中的地址等信息,那又问,它在什么当地进行记载的呢?它就在咱们自己开发板初始化代码中记载的,如:board/samsung/my2440/my2440.c中
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325410.png” style=”padding:0px;margin:0px;border:0px;” />
留意:bd_t被gd_t所引证,而在global_data.h中咱们能够看到,u-boot界说了一个gd_t的大局指针变量*gd,所以在这儿就能够直接运用gd来设置bd了。
好了,咱们仍是接着剖析这个参数链表是怎样被传递的,安排参数链表的系列函数在一个叫do_bootm_linux的函数中被调用的,仍是界说在lib_arm/bootm.c中
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325411.png” style=”padding:0px;margin:0px;border:0px;” />
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325412.png” style=”padding:0px;margin:0px;border:0px;” />650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325413.png” style=”padding:0px;margin:0px;border:0px;” />
mkimage [-x]-A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file…] image 选项: 例如: |
呵呵,信任此刻的你拨云见日,恍然大悟了吧!这个进口地址便是0x30008000,这也正是为什么u-boot必定要运用uImage的格局来发动内核的原因之一。留意:这儿有个kernel进口地址0x30008000,在上面还说到一个u-boot参数链表在内存中的地址0x30000100,试想假如这儿指定的kernel进口地址覆盖了参数链表的地址会怎样样?
好了,把上面每个进程从下往上看就能够知道u-boot参数项在u-boot端的传递的整个流程了,那么,接下来再剖析u-boot参数项在kernel端是怎样接纳的。
start: .word 0x016f2818 @ Magic numbers to help the loader wont_overwrite: mov r0, r4 …… call_kernel: bl cache_clean_flush …… |
首要,将u-boot传递过来的r1(机器码)、r2(参数链表在内涵中的物理地址)别离保存到ARM寄存器r7、r8中,再将r7作为参数传递给解压函数decompress_kernel(),在这个解压函数中再将r7传递给大局变量__machine_arch_type,然后在跳转到vmlinux进口之前再将r7、r8复原到r1、r2中。
在arch/arm/kernel/head.S文件中,内核vmlinux进口的部分代码如下:
ENTRY(stext) …… |
首要从ARM特别寄存器(CP15)中取得ARM内核的类型,从处理器内核描绘符(proc_info_list)表(__proc_info_begin—__proc_info_end)中查询有无此ARM 内核的类型,假如无就出错退出。处理器内核描绘符界说在include/asm-arm/procinfo.h中,详细的函数完成在 arch/arm/mm/proc-xxx.S中,在编译衔接进程中将各种处理器内核描绘符组合成表。接着从机器描绘(machine_desc)表(__mach_info_begin—__mach_info_end)中查询有无r1寄存器指定的机器码,假如没有就出错退出,所以这也阐明晰为什么在u-boot中指定的机器码必定要与内核中指定的共同,不然内核就无法发动。机器编号mach_type_xxx在arch/arm/tools/mach-types文件中阐明,每个机器描绘符中包含一个仅有的机器编号,机器描绘符的界说在 include/asm-arm/mach/arch.h中,详细完成在arch/arm/mach-xxxx文件夹中,在编译衔接进程中将根据同一种处理器的不同机器描绘符组合成表。例如,S3C2440处理器的机器码为1008的机器描绘符如下所示:
MACHINE_START(SMDK2440,”SMDK2440″) .init_irq = s3c24xx_init_irq, |
最终就翻开MMU,并跳转到 init/main.c的start_kernel()初始化体系。函数start_kernel()的部分代码如下:
asmlinkage void __init start_kernel(void) |
函数setup_arch在arch/arm/kernel/setup.c中完成,部分代码如下:
void __init setup_arch(char**cmdline_p) |
setup_processor()函数从处理器内核描绘符表中找到匹配的描绘符,并初始化一些处理器
变量。setup_machine()用机器编号(在解压函数decompress_kernel 中被赋值)作为参数回来机器描绘符。从机器描绘符中取得内核参数的物理地址,赋值给tags 变量。然后调用parse_tags()函数剖析内核参数链表,把各个参数值传递给大局变量。这样内核就收到了u-boot传递的参数。
-
tftp下载内核和nfs挂载文件体系
好了,上面tftp服务和nfs服务都现已预备好了,u-boot到kernel的参数传递也没问题了,接下来就设置一下u-boot环境变量中的参数项和kernel的装备选项使之能运用tftp主动下载kernal和经过网络主动挂载nfs文件体系。u-boot环境变量设置如下:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325416.png” style=”padding:0px;margin:0px;border:0px;” />
bootcmd参数项便是运用tftp把主机tftp主目录下的uImage下载到开发板SDRAM中的0x31000000方位,接着运用bootm指令履行引导内核发动。
而bootargs参数项便是内核发动的指令行参数,u-boot便是把这个参数项传递给了内核,经过nfs挂载文件体系。这儿必定要留意serverip和ipaddr的设置(即服务器IP或许开发主机IP和开发板的IP)。别的要留意,内核要能运用nfs也要装备相应的选项,如下:
File systems —> |
运转成果如下:
a. tftp下载内核,并引导内核发动:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325417.png” style=”padding:0px;margin:0px;border:0px;” />
b. u-boot传递的指令行参数被内核所接纳:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325418.png” style=”padding:0px;margin:0px;border:0px;” />
c. 内核经过nfs挂载文件体系:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325419.png” style=”padding:0px;margin:0px;border:0px;” />
d. 检查挂载的nfs文件体系,发现彻底与主机nfs服务器主目录中的文件体系共同,阐明成功!
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325420.png” style=”padding:0px;margin:0px;border:0px;” />
[root@localhost home]# vi /etc/exports //假如没有这个文件就创立它,增加下面一行装备信息,留意格局必定要正确,不然导致服务不正常 /home/filesystem *(rw,no_root_squash,sync) 注释:“/home/filesystem”是NFS服务器的主目录,留意目录的权限 “*”表明一切的IP都能够拜访NFS主目录 “rw”表明可读可写 ”no_root_squash“表明登入到NFS主机的用户假如是ROOT用户,他就具有ROOT的权限 “sync”表明同步 [root@localhost home]# service nfs restart //从头发动NFS服务,使装备文件收效 |
测验NFS服务是否正常。将事前预备好的文件体系放到NFS主目录下,如下:
[root@localhost home]# ls /home/filesystem/ //在主机本地测验NFS服务,将NFS主目录下的文件体系挂载到/mnt目录下,192.168.1.101是主机的IP [root@localhost home]#mount -o nolock -t nfs 192.168.1.101:/home/filesystem /mnt |
能够看到/mnt目录下的内容和NFS主目录/home/filesystem下的内容彻底共同,阐明NFS服务正常:
650) this.width=650;” src=”http://www.embeddedlinux.org.cn/uploads/allimg/130316/10325421.png” style=”padding:0px;margin:0px;border:0px;” />
[root@localhost home]# vi /etc/xinetd.d/tftp service tftp |
创立方才指定的tftp服务器主目录,也要留意主目录的可读可写的权限:
[root@localhost home]#mkdir /home/tftp-root |
发动和测验tftp服务:
[root@localhost home]#service xinetd restart //重启xinetd服务就会发动其下的一切服务,也包含tftp服务 tftp>put 要上传的文件 tftp>q |