您的位置 首页 IC

嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(六)

嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便。如

一、移植环境

  • 机:VMWare–Fedora 9
  • 开发板:Mini2440–64MB Nand,Kernel:2.6.30.4
  • 编译器:arm123.com.cn/linux/arm-linux-gcc-4.3.2.tgz” target=”_blank”>arm-linux-gcc-4.3.2.tgz
  • u-boot:u-boot-2009.08.tar.bz2

二、移植进程

10)u-boot运用tftp服务下载内核和运用nfs服务挂载nfs文件体系。
常识点:
  1. tftp服务的装置与装备及测验;
  2. nfs服务的装置与装备及测验;
  3. 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/目录下:

[root@localhosthome]# vi /etc/xinetd.d/tftp

service tftp
{
disable=no
socket_type=dgram
protocol=udp
wait=yes
user=root
server=/usr/sbin/in.tftpd
server_args=-s/home/tftp-root-c//主要是修正这儿,指定tftp服务器的主目录,-c选项是指能够创立文件
per_source=11
cps=100 2
flags=IPv4
}

创立方才指定的tftp服务器主目录,也要留意主目录的可读可写的权限:

[root@localhosthome]#mkdir /home/tftp-root
[root@localhosthome]#chmod 777 /home/tftp-root

发动和测验tftp服务:

[root@localhosthome]#service xinetd restart //重启xinetd服务就会发动其下的一切服务,也包含tftp服务
[root@localhosthome]#service iptables stop //封闭防火墙
[root@localhosthome]#tftp 主机IP地址
tftp>get要下载的文件

tftp>put要上传的文件

tftp>q
[root@localhosthome]#

  • nfs服务的装置与装备及测验

以root的身份在控制台输入setup,在体系服务选项中选中nfs服务,如下图:

装备NFS服务器的同享主目录,也要留意权限问题:

[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/
bin dev home lib mnt root sum100 tmp var
debug etc hostname linuxrc proc sbin sys usr
[root@localhost home]#

//在主机本地测验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服务正常:

  • u-boot到kernel的参数传递

咱们知道,在kernel装备选项Boot options中有一个Default kernel command string参数项,而在u-boot参数中也有一个bootargs参数项,他们都是供内核发动用的,那他们又有什么区别呢,内核发动时究竟是用哪一个呢?两种参数项别离如下图所示(kernel中的参数指定是从开发板Flash分区上挂载文件体系,u-boot中的参数指定的是从NFS挂载文件体系):

实际上,内核中的参数项是内核默许供给的,在内核装备时去指定,而u-boot供给的则在u-boot发动时传递到内核中替代内核供给的参数。所以当u-boot没有供给bootargs参数时,内核发动便是用内核装备时指定的参数,当u-boot供给了bootargs参数时就运用u-boot的参数。

那么,u-boot是假如将参数信息传递到内核中的呢?而内核又是怎样接纳u-boot传递过来的参数呢?这就涉及到一点点ARM寄存器的常识了。

咱们知道,ARM有7种作业形式和37个寄存器(31个通用寄存器和6个状况寄存器),如下图:

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中:

咱们能够看到,链表的安排是由一系列函数完成,u-boot规则,链表有必要以ATAG_CORE符号开端,以ATAG_NONE符号完毕,中心便是一些参数符号项,这点从代码中能够表现出来。那么在这些函数中有一个bd的参数是至关重要的,它是一个bd_info类型的结构体,界说在include/asm-arm/u-boot.h中,而这个结构体又被一个global_data类型的结构体所引证,界说在include/asm-arm/global_data.h中,如下:

那么,那个bd参数究竟是做什么用的呢?从界说中能够得知,bd记载了机器码、u-boot参数链表在内存中的地址等信息,那又问,它在什么当地进行记载的呢?它就在咱们自己开发板初始化代码中记载的,如:board/samsung/my2440/my2440.c中

留意:bd_t被gd_t所引证,而在global_data.h中咱们能够看到,u-boot界说了一个gd_t的大局指针变量*gd,所以在这儿就能够直接运用gd来设置bd了。

好了,咱们仍是接着剖析这个参数链表是怎样被传递的,安排参数链表的系列函数在一个叫do_bootm_linux的函数中被调用的,仍是界说在lib_arm/bootm.c中

从这个函数中咱们能够看到,要使参数传递收效有必要需求CONFIG_SETUP_MEMORY_TAGS和CONFIG_CMDLINE_TAG这两个宏的支撑,所以需求在include/configs/my2440.h中界说它们。本来我便是没界说它们,在运用NFS挂载文件体系时就出现问题。一起,theKernel这个函数指针是u-boot参数传递的至关点,咱们知道,函数在内存中碑文的时分其实便是一个地址,而在代码中首要将这个函数指针指向kernel的进口地址,最终还将0、机器码和u-boot参数项在内存中的地址带给这个进口地址,故碑文这个进口地址的时分即kernel发动的时分能够有这三个参数进行接纳。那么,这个进口地址(kernel发动地址或许说kernel进口地址)是怎样来的是谁指定的,又是多少呢?看代码,是从一个bootm_headers_t类型的结构体的成员ep取得的,而这个结构体是从调用do_bootm_linux的当地传递过来的。bootm_headers_t界说在include/image.h中,do_bootm_linux在common/cmd_bootm.c中被调用,如下:
从代码中能够清楚的看到对bootm_headers_t的成员ep进行了赋值,可是仍是不行直观这个进口地址究竟是多少?只知道是运用image_get_ep函数从bootm_headers_t中的legacy_hdr_os_copy上取得的,那它在什么当地被赋值的呢?本来在image_set_ep函数中,界说在tools/mkimage.c中,如下:
咱们再想想,这个mkimage.c是做什么用的?本来是用它来制造u-boot格局的内核——uImage,还记得怎样运用mkimage来制造uImage吧,在“u-boot-2009.08在2440上的移植详解(四)”中讲到,如下:

mkimage[-x]-A arch-O os-T type-C comp-a addr-e ep-n name-d data_file[:data_file…]image

选项:
-A:set architecture toarch//用于指定CPU类型,比方ARM
-O:set operatingsystemtoos//用于指定操作体系,比方Linux
-T:set image type totype//用于指定image类型,比方Kernel
-C:set compression typecomp//指定紧缩类型
-a:set load address toaddr(hex)//指定image的载入地址
-e:set entry point toep(hex)//内核的进口地址,一般为image的载入地址+0x40(信息头的巨细)
-n:set image name toname//image在头结构中的命名
-d:use image data fromdatafile//无头信息的image文件名
-x:set XIP(execute in place)//设置碑文方位

例如:
mkimage-nlinux-2.6.30.4-A arm-O linux-T kernel-C none-a 0x30008000-e 0x30008000-d zImage uImage.img

呵呵,信任此刻的你拨云见日,恍然大悟了吧!这个进口地址便是0x30008000,这也正是为什么u-boot必定要运用uImage的格局来发动内核的原因之一。留意:这儿有个kernel进口地址0x30008000,在上面还说到一个u-boot参数链表在内存中的地址0x30000100,试想假如这儿指定的kernel进口地址覆盖了参数链表的地址会怎样样?

好了,把上面每个进程从下往上看就能够知道u-boot参数项在u-boot端的传递的整个流程了,那么,接下来再剖析u-boot参数项在kernel端是怎样接纳的。

kernel发动的流程如下图所示:
在文件arch/arm/boot/compressed/head.S中,start是zImage的开端点,部分代码如下:

start:
……

.word0x016f2818@ Magic numbers to help the loader
.wordstart@ absolute load/run zImage address
.word_edata@ zImage end address
1:movr7, r1 @ save architecture ID
movr8, r2 @ save atags pointer
……

wont_overwrite:movr0, r4
movr3, r7
bldecompress_kernel
bcall_kernel

……

call_kernel:blcache_clean_flush
blcache_off
movr0, #0@ must be zero
movr1, r7@ restore architecture number
movr2, r8@ restore atags pointer
movpc, r4@ call kernel

……

首要,将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)
setmodePSR_F_BIT|PSR_I_BIT|SVC_MODE,r9 @ ensure svc mode @andirqs disabled
mrcp15,0,r9,c0,c0@ get processor id
bl __lookup_processor_type@ r5=procinfo r9=cpuid
movsr10,r5 @ invalid processor(r5=0)?
beq__error_p @ yes,errorp
bl __lookup_machine_type@ r5=machinfo
movsr8,r5 @ invalid machine(r5=0)?
beq__error_a @ yes,errora
bl __vet_atags
bl __create_page_tables

……

首要从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”)

.phys_io=S3C2410_PA_UART,
.io_pg_offst=(((u32)S3C24XX_VA_UART)>>18)&0xfffc,
.boot_params=S3C2410_SDRAM_PA+0x100,//留意:这个地址便是与u-boot中参数链表在内存中的物理地址相对应

.init_irq=s3c24xx_init_irq,
.map_io=smdk2440_map_io,
.init_machine=smdk2440_machine_init,
.timer=&s3c24xx_timer,
MACHINE_END

最终就翻开MMU,并跳转到 init/main.c的start_kernel()初始化体系。函数start_kernel()的部分代码如下:

asmlinkagevoid__init start_kernel(void)
{
……
setup_arch(&command_line);
……
}

函数setup_arch在arch/arm/kernel/setup.c中完成,部分代码如下:

void__init setup_arch(char**cmdline_p)
{
……
setup_processor();
mdesc=setup_machine(machine_arch_type);
……
parse_tags(tags);
……
}

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环境变量设置如下:

bootcmd参数项便是运用tftp把主机tftp主目录下的uImage下载到开发板SDRAM中的0x31000000方位,接着运用bootm指令碑文引导内核发动。

而bootargs参数项便是内核发动的指令行参数,u-boot便是把这个参数项传递给了内核,经过nfs挂载文件体系。这儿必定要留意serverip和ipaddr的设置(即服务器IP或许开发主机IP和开发板的IP)。别的要留意,内核要能运用nfs也要装备相应的选项,如下:

File systems —>
Network File Systems —>
<*> NFS file system support ## 必选
[*] Provide NFSv3 client support ## 可选
[*] Root file systemonNFS ## 必选
Networking —>
[*] Networking support
Networking options —>
[*] IP: kernel level autoconfiguration ## 必选

运转成果如下:

a. tftp下载内核,并引导内核发动:

b. u-boot传递的指令行参数被内核所接纳:

c. 内核经过nfs挂载文件体系:

d.检查挂载的nfs文件体系,发现彻底与主机nfs服务器主目录中的文件体系共同,阐明成功!

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/bandaoti/264644.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部