(三)zc702Linux启动过程

 接上一篇第一次一股脑成功编译完成后,编译后的输出文件保存在poky/build/tmp/deploy/images/zc702-zynq7/目录下,有u-boot、内核镜像、根文件系统、设备树文件等。列表如图:

u-boot.img是u-boot的镜像文件,u-boot.elf为u-boot可编译形式文件;core-image-minimal-zc702-zynq7.tar.gz是根文件系统的压缩文件,uEnv.txt为一些环境变量,来告诉u-boot主板的内核镜像和设备树在哪里;uImage就是内核镜像了;uImage-zynq-zc702.dtb为设备树文件。以上这些都是之后启动过程中要用到的文件。

一、Linux的启动流程

以上就是ZYNQ7的Linux启动流程了。

二、SD卡启动方式

ZC702可以配置为从SD卡启动Yocto Linux发行版。以下说明如何设置可启动SD卡:

1、使用dd擦除第一个扇区(本次使用的是sdb,一般只有一个分区的话sdb1就是sdb的第一分区,而我们是要对sdb分区而不是对sdb1分区!!!)

dd if=/dev/zero of=/dev/sdb bs=1024 count=1

2、对SD卡进行分区:

sudo fdisk /dev/sdb

n -> p -> 1 分区1

n -> p -> 2 分区2

对第一分区设置启动标志,并设置分区ID:

a -> 1 t -> 1 -> c t -> 2 -> 83

检查新分区是否正确然后写入更改:

p -> w

3、格式化分区

  • 始终使用fat格式化可引导分区。第二个分区可以是ext2 / ext4。
  • mkfs.vfat -F 32 -n boot / dev / sdc1 - 这将使用FAT格式化第一个分区。
  • mkfs.ext4 -L root / dev / sdc2 - 这将使用ext4格式化第二个分区

4、在分区挂载文件系统,sdb1是第一分区(boot),sdb2是第二分区(将放置根文件系统)。

~$ sudo mkdir -p /mnt/sdb1

~$ sudo mount /dev/sdb1 /mnt/sdb1

~$ sudo mkdir -p /mnt/sdb2

~$ sudo mount /dev/sdb2 /mnt/sdb2

将构建输出复制到SD卡上:

需要将以下文件从poky / build / tmp / deploy / < image > /复制到SD卡的第一个分区(引导分区)

$ sudo cp boot .bin / mnt / sdb1 /

$ sudo cp u - boot .img / mnt / sdb1 /

$ sudo cp uImage / mnt / sdb1 /

$ sudo cp .dtb / mnt / sdb1 /

$ sudo cp uEnv .txt / mnt / sdb1 /

再将根文件系统解压缩至第二个分区:

$ sudo tar x - C / mnt / sdb2 / - f core - image - minimal - zc702 - zynq7 .tar .gz

三、上电启动

以上是SD卡启动的一般流程,但是,我手里的板子型号是ZC7035的,meta-xilinx提供的机型里面并没有这个型号,因此需要自己建立自己的型号。这个功能是可以实现的,有一点麻烦,需要另起一篇一探究竟。这里就先用它支持的702变出的系统先在7035上看看能不能跑起来。

制作BOOT.BIN

板子上预装的u-boot是用的Xilinx官方套件开发的,因此U-BOOT是烧到flash里面的,采用的是FIT Image的内核启动方式,换句话说就是他只认识BOOT.BIN文件,现在我打算先用他的u-boot,之后再进一步做u-boot的定制,因此我们需要将u-boot.elf、.bit 、.FSBL.elf文件用Xilinx SDK合成BOOT.BIN文件。放到SD卡的第一分区,代替boot.bin。(这只是我个人的一些想法,因为内存的原因刚把Xilinxsdk卸载,所以还没有机会实践)

再说一下用XilinxSDK和petalinux开发(官方套件),启动需要用到的文件:

  • .bit      :PL侧启动文件
  • image.ub:由petalinux生成,是一个很复杂的映像,简单来说,包含内核镜像,init RD映像、devicetree和它们的寻址信息及其他信息。
  • BOOT.BIN:包含.bit、u-boot.elf、FSBL.elf,由XilinxSDK生成
  • system.dtb:设备树文件
  • 根文件系统:放到SD卡的第二分区

再和yocto构建的输出文件做个对比就可以看出来,其实细分到最下面的文件时都一样的,只是打包方式和启动方法不一样而已。

四、u-boot引导启动Linux系统

转载别人的,可以了解u-boot时如何一步步调用这些文件引导加载启动Linux系统的。


在bootrom起来后,按下任意键则放弃了自动引导,从而进入了u-boot的命令行。在这里你可以手动进行接下来系统的引导,但是我不会。虽然不会,但是用于板子上的系统有自动引导,我们可以分析自动引导,来了解u-boot是如何引导系统的。

在U-Boot的官网手册中看到了2个关键的环境变量和1个命令。
bootcmd: This variable defines a command string that is automatically executed
         when the initial countdown is not interrupted.
         This command is only executed when the variable bootdelay is also defined!
bootargs: The contents of this variable are passed to the Linux kernel as boot
          arguments (aka "command line").

run    - run commands in an environment variable

bootcmd中的命令就是出现“Hit any key to stop autoboot”提示后,不按任意键,会自动运行的命令。
bootargs是传递给Linux内核的参数。
run是运行环境变量中的命令,bootcmd中包含run命令。

所以分析引导过程要从bootcmd开始。
在U-Boot的命令行中输入printenv可显示所有的环境变量,我已经把相关的粘贴到了下面。
为方便阅读我添加了换行

  • bootcmd=
  •   run findfdt;
  •   run mmcboot;
  •   setenv mmcdev 1;
  •   setenv bootpart 1:2;
  •   run mmcboot;
  •   run nandboot;
  •  
  • findfdt=
  •   if test $board_name = A335BONE;
  •   then
  •     setenv fdtfile am335x-bone.dtb;
  •   fi;
  •   if test $board_name = A335BNLT;
  •   then
  •     setenv fdtfile am335x-boneblack.dtb;
  •   fi;
  •   if test $board_name = A33515BB;
  •   then
  •     setenv fdtfile am335x-evm.dtb;
  •   fi;
  •   if test $board_name = A335X_SK;
  •   then
  •     setenv fdtfile am335x-evmsk.dtb;
  •   fi;
  •   if test $fdtfile = undefined;
  •   then
  •     echo WARNING: Could not determine device tree to use;
  •   fi;
  •  
  • board_name=A335BNLT

首先是运行findfdt中的命令,目的是通过board_name来设置fdtfile,结果是fdtfile的值为am335x-boneblack.dtb。

  • mmcboot=
  •   mmc dev ${mmcdev};
  •   if mmc rescan;
  •   then
  •     echo SD/MMC found on device ${mmcdev};
  •     if run loadbootenv;
  •     then
  •       echo Loaded environment from ${bootenv};
  •       run importbootenv;
  •     fi;
  •     if test -n $uenvcmd;
  •     then
  •       echo Running uenvcmd ...;
  •       run uenvcmd;
  •     fi;
  •     if run loadimage;
  •     then
  •       run mmcloados;
  •     fi;
  •   fi;
  •  
  • mmcdev=0

"mmc dev 0"是将设备切换到0,通常有2个设备一个是SD卡,一个是eMMC。

  • loadbootenv=load mmc ${mmcdev} ${loadaddr} ${bootenv}
  •  
  • loadaddr=0x80200000
  •  
  • bootenv=uEnv.txt

这应该是从设备0的第1个分区装载uEnv.txt到地址0x80200000。
当默认的环境变量不符合要求时,可以用uEnv.txt设置新的环境变量。没有它也可以,先不用管,后面说。

importbootenv=echo Importing environment from mmc ...; env import -t $loadaddr $filesize

这是把uEnv.txt中的环境变量导入到U-Boot的环境变量中。“filesize”没有指定。

  • loadimage=load mmc ${bootpart} ${loadaddr} ${bootdir}/${bootfile}
  •  
  • bootpart=0:2
  •  
  • bootdir=/boot
  •  
  • bootfile=zImage

由于我没有“uenvcmd”这个环境变量,所以那个条件语句中的内容没有执行。我记着Arch Linux好像用了那个,那个变量应该在uEnv.txt中。于是直接到了loadimage,这里和载入uEnv.txt是相似的,“0:2”的意思是设备0的第2个分区,而载入uEnv.txt时没有指定分区,就默认第1分区了。loadimage的目的是将Linux内核载入内存

  • mmcloados=
  •     run mmcargs;
  •     if test ${boot_fdt} = yes || test ${boot_fdt} = try;
  •     then
  •         if run loadfdt;
  •         then
  •             bootz ${loadaddr} - ${fdtaddr};
  •         else
  •             if test ${boot_fdt} = try;
  •             then
  •                 bootz;
  •             else
  •                 echo WARN: Cannot load the DT;
  •             fi;
  •         fi;
  •     else
  •         bootz;
  •     fi;
  • mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype}
  • console=ttyO0,115200n8
  • mmcroot=/dev/mmcblk0p2 ro
  • mmcrootfstype=ext4 rootwait

这个就是设置bootargs这一个环境变量而已,用于向内核传递参数。

  • boot_fdt=try
  • loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile}
  • fdtaddr=0x80F80000

之前载入了Linux内核,这里载入了设备树文件。最后通过bootz后接2个地址就启动了系统。

总结如下:

  • mmc dev 0;
  •  
  • load mmc 0:2 0x80200000 /boot/zImage
  •  
  • setenv bootargs concole=ttyO0,115200n8 root=mmcroot=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait
  •  
  • load mmc 0:2 0x80F80000 /boot/am335x-boneblack.dtb
  •  
  • bootz 0x80200000 - 0x80F80000

这是默认环境变量的行为。而我们的系统可能与其不同。这就要修改环境变量。我知道有2种方式一种是在U-Boot的命令行中通过命令修改,另一种就是通过uEnv.txt了。这里介绍uEnv.txt的方式。先列出我uEnv.txt的内容,不用详细看,看我下面的说明。

  • bootfile=uImage
  •  
  • loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/dts/${fdtfile}
  •  
  • mmcloados=run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} =
  • try; then if run loadfdt; then bootm ${loadaddr} - ${fdtaddr}; else if
  • test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT;
  • fi; fi; else bootz; fi;
  •  
  • mmcroot=/dev/mmcblk0p2 rw
  •  
  • mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype} init=/usr/lib/systemd/systemd

一共6行,最后一行空白。
bootfile修改了内核名字,
loadfdt中只是在目录中加了“dts/”,
mmcloados主要是把bootz改成bootm。
mmcroot把只读改成了读写。
mmcargs只是在后面指定了init为systemd,也有其他方法,如init为指向systemd的软链接。

这里是从设备0启动系统,怎样知道自己的系统位于哪个设备呢,也许有某种约定,比如如果有SD卡,那么SD卡是0。
我不知道的话,可以在U-Boot的命令行中通过命令判断。如

  • U-Boot# mmc list
  • OMAP SD/MMC: 0
  • OMAP SD/MMC: 1

列出mmc设备。

  • U-Boot# mmc dev
  • mmc0 is current device

显示当前是那个设备。

  • U-Boot# mmc part
  • Partition Map for MMC device 0  --   Partition Type: DOS
  • Part    Start Sector    Num Sectors     UUID            Type
  •   1     2048            131072          29942d7e-01     0c Boot
  •   2     133120          15390720        29942d7e-02     83

显示当前设备的分区信息。

  • U-Boot# ls mmc 0:1
  •    100688   mlo
  •    308232   u-boot.img
  •       510   uenv.txt
  • 3 file(s), 0 dir(s)

从以上引用别人的对u-boot的分析,我们可以对照自己的yocto生成的文件,了解他们的用处。另一方面也佐证了我在上电启动合成BOOT.BIN的想法。下面是我的uEnv.txt:

猜你喜欢

转载自blog.csdn.net/yangteng0210/article/details/81611273
今日推荐