0
点赞
收藏
分享

微信扫一扫

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​

U-Boot移植​

上一章节我们讲解了uboot的使用,对uboot有了一个初步的了解。前两章我们都是使用的正点原子提供的uboot,本章我们就来学习如何将Xilinx官方的uboot移植到正点原子的ZYNQ MPSoC开发板上,学习如何在uboot中添加我们自己的板子。



U-Boot源码获取及目录分析

获取U-Boot源码

Xilinx官方提供的uboot源码发布在github网站,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux


12.1.1 Xilinx发布的uboot源码

可以从github网站clone或下载uboot源码,注意要与Petalinux版本一致,否则可能会出现一些问题,我们使用的是2019.2版本的Petalinux,所以选择的uboot要带2019.2(Tags带2019.2。不过我们不从上面的github网站下载,因为在11.2节使用Petalinux配置和编译U-Boot时,Petalinux工具就已经生成了uboot源码,如11.2.2 uboot源码所示,所以没有必要从github网站下载。

本章的uboot移植需要使用该源码,为了方便访问以及和后面章节的linux内核源码放在同一目录下,方便管理,我们在当前用户home目录下新建一个名为git.d的文件夹,并将Petalinux生成的uboot源码拷贝到该文件夹下,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_02


12.1.2拷贝uboot源码到git.d目录

进入~/git.d/u-boot-xlnx目录,输入“git status”和“git remote -v”命令,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_03


12.1.3 git status

可以看到当前uboot源码位于devtool分支,而且与Xilinx发布在github网站的uboot源码是同步的,没有做任何修改。由于笔者没有在github网站找到devtool分支以及tags,所以将其切换到与Petalinux 2019.2版本兼容的最新的tags标签上,也就是tag xilinx-v2019.2,并在此tag上创建分支u-boot-xlnx,命令如下:

git fetch origin tag xilinx-v2019.2​
git checkout tags/xilinx-v2019.2 -b u-boot-xlnx

结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_04


12.1.4 创建u-boot-xlnx分支

当然了,也可以使用默认的devtool分支,没有实质上的区别。

U-Boot工程目录分析

在移植uboot之前,我们需要先了解uboot工程目录结构,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_05


12.1.5解压后的uboot

上图中除了oe-logsoe-workdiroe-local-files这三个Petalinux工具相关的文件外,其他的文件和文件夹都是uboot源码本身的。这些文件夹或文件的含义如下表所示:

12.1.1目录列表

类 型

名字

描述

备注

文件夹

api

与硬件无关的API函数

uboot自带

arch

与芯片架构体系相关的代码

board

不同板子(开发板)的定制代码

cmd

uboot命令相关代码

common

通用代码

configs

配置文件

disk

磁盘分区相关代码

doc

文档

drivers

通用设备驱动代码

dts

设备树

env

环境变量相关代码

examples

示例代码

fs

文件系统

include

头文件

lib

库文件

Licenses

许可证相关文件

net

网络相关代码

post

上电自检程序

scripts

脚本文件

test

测试代码

tools

工具文件夹

文件

.checkpatch.conf

路径检查配置文件

uboot自带

.gitignore

git工具相关文件

uboot自带

.mailmap

邮件列表

config.mk

某个Makefile会调用此文件

uboot自带

Kbuild

用于生成一些和汇编有关的文件

uboot自带

Kconfig

图形配置界面描述文件

MAINTAINERS

维护者联系方式文件

Makefile

顶层Makefile文件

README

相当于帮助文档

uboot自带


……



上表中的很多文件夹和文件我们都不需要去关注,我们要关注的文件夹或文件如下:

  1. arch文件夹这个文件夹里面存放着和芯片架构有关的文件,如下图所示:

12.1.6 arch文件夹

从上图可以看出有很多架构,比如arm、x86riscv等,我们现在用的是ARM芯片,所以只需要关注arm文件夹即可,进入arm文件夹里面内容如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux_06


12.1.7文件夹

mach开头的文件夹是跟具体的设备有关的,比如“mach-exynos”就是跟三星的exyons系列CPU有关的文件。我们使用的是Zynq UltraScale+ MPSoC,所以要关注“mach-zynqmp”这个文件夹。另外“cpu”这个文件夹也是和cpu架构有关的,文件夹内容如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_07


12.1.8 cpu文件夹

从上图可以看出有多种ARM架构相关的文件夹,Zynq UltraScale+ MPSoC使用的是Cortex-A53内核,Cortex-A53属于armv8,所以我们要关注“armv8”这个文件夹。cpu文件夹里面有个名为“u-boot.lds”的链接脚本文件,这个就是ARM芯片所使用的u-boot链接脚本文件。armv8文件夹里面的文件都是跟ARMV8架构有关的。

  1. board文件夹board文件夹就是和具体的开发板有关的,打开此文件夹,里面全是不同的板子,borad文件夹里面有个名为“xilinx”的文件夹,里面存放的是Xilinx厂商所有支持uboot的芯片系列,如下图所示:

12.1.9 xilinx文件夹

所有使用xilinx芯片的板子都放到此文件夹中。该文件夹下有7个文件夹,其中bootscripts用于生成启动脚本boot.scrcommon是所有开发板通用的、microblaze-generic表示使用microblaze软核IP的FPGA开发板、zynq表示使用ZYNQ-7000系列芯片的开发板、zynqmp表示使用ZYNQ MPSOC系列芯片的开发板、zynqmp_r5表示使用ZYNQ MPSoC系列芯片的R5处理器的开发板、versal表示使用Versal系列芯片的开发板。正点原子的开发板是ZYNQ MPSoC系列的开发板,我们后面移植uboot的时候就是参考zynqmp这个文件夹来定义我们的开发板。

  1. configs文件夹此文件夹为uboot配置文件,uboot是可配置的,但是你要是自己从头开始一个一个项目的配置,那就太麻烦了,因此一般半导体或者开发板厂商都会制作好一个配置文件。我们可以在这个做好的配置文件基础上来添加自己想要的功能,这些半导体厂商或者开发板厂商制作好的配置文件统一命名为“xxx_defconfig”,xxx表示开发板名字,这些defconfig文件都存放在configs文件夹,因此,Xilinx官方开发板的配置文件肯定也在这个文件夹中,如下图所示:

12.1.10 Xilinx芯片系列开发板配置文件

上图中的以“xilinx”开头的文件都是xilinx芯片系列的配置文件。其中“xilinx_zynqmp_zcu102_rev1_0_defconfig”、“xilinx_zynqmp_zcu102_revA_defconfig”、“xilinx_zynqmp_zcu102_revB_defconfig”是我们参考的Xilinx官方的ZYNQ ZCU102开发板配置文件的不同版本,后面我们使用“xilinx_zynqmp_zcu102_rev1_0_defconfig”这个版本的配置文件。

  1. Makefile文件这个是顶层Makefile文件,Makefile是支持嵌套的,也就是顶层Makefile可以调用子目录中的Makefile文件。Makefile嵌套在大项目中很常见,一般大项目里面所有的源代码都不会放到同一个目录中,各个功能模块的源代码都是分开的,各自存放在各自的目录中。每个功能模块目录下都有一个Makefile,这个Makefile只处理本模块的编译链接工作,这样所有的编译链接工作就不用全部放到一个Makefile中,可以使得Makefile变得简洁明了。
    uboot源码根目录下的Makefile是顶层Makefile,它会调用其它的模块的Makefile文件,比如drivers/cpu/Makefile。当然了,顶层Makefile要做的工作可远不止调用子目录Makefile这么简单。
  2. README

README文件描述了uboot的详细信息,包括uboot该如何编译、uboot中各文件夹的含义、相应的命令等等。建议大家详细的阅读此文件,可以进一步增加对uboot的认识。

关于uboot根目录中的文件和文件夹的含义就讲解到这里,接下来就要开始移植uboot了。

Petalinux使用外部U-Boot源码

上一节我们将Petalinux生成的uboot源码移动到~/git.d/u-boot-xlnx目录(绝对路径/home/shang/git.d/u-boot-xlnx),这样导致Petalinux工程无法使用访问uboot源码了,所以在移植uboot之前,我们了解下如何让Petalinux能访问移动后的uboot源码。

方法如下:

1. 进入到Petalinux工程目录下,设置好Petalinux工作环境后,输入“petalinux-config”命令配置Petalinux工程。

设置Linux Components Selection ---> u-boot (u-boot-xlnx) --->为“ext-local-src”,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_08


12.2.1配置u-boot

该配置项将u-boot来源配置为外部的本地源。设置好后按回车键返回。设置External u-boot local source settings ---> External u-boot local source path为“/home/shang/git.d/u-boot-xlnx”,也就是当前uboot源码存放的目录,结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_09


12.2.2 配置External u-boot local source path

保存配置并退出,现在该Petalinux工程就可以访问和使用/home/shang/git.d/u-boot-xlnx中的源码了。

但是笔者在使用petalinux2019.2时,按照上面步骤设置后,编译petalinux工程会出现报错,猜测可能是这个版本的petalinux存在bug。解决的方法是在u-boot-xlnx原来的位置建立一个指向/home/shang/git.d/u-boot-xlnx的链接,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_10


12.2.3建立u-boot-xlnx链接

需要注意的一点是在Petalinux工程中配置和编译u-boot时需要先清理~/git.d/u-boot-xlnx中的源码(命令make distclean),否则配置和编译会报错,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_11


12.2.4编译petalinux工程

Xilinx官方开发板uboot编译测试

uboot的移植并不是说我们完完全全的从零开始将uboot移植到我们现在所使用的开发板或者开发平台上。这个对于我们来说基本是不可能的,这个工作一般是半导体厂商做的,半导体厂商负责将uboot移植到他们的芯片上,因此半导体厂商都会自己做一个开发板,这个开发板就叫做原厂开发板,比如大家学习STM32的时候听说过的discover开发板就是ST自己做的。半导体厂商会将uboot移植到他们自己的原厂开发板上,测试好以后就会将这个uboot发布出去,这就是大家常说的原厂BSP包。我们一般做产品的时候就会参考原厂的开发板做硬件,然后在原厂提供的BSP包上做修改,将uboot或者linux kernel移植到我们的硬件上。这个就是uboot移植的一般流程:

  1. 在uboot中找到参考的开发平台,一般是原厂的开发板。
  2. 参考原厂开发板移植uboot到我们所使用的开发板上。正点原子的ZYNQ开发板参考的是Xilinx官方的ZYNQ ZCU102开发板做的硬件,因此我们在移植uboot的时候就可以以Xilinx官方的ZYNQ ZCU102开发板为蓝本。
    在移植之前,我们先编译一下Xilinx官方ZCU102开发板对应的uboot。编译uboot源码之前,需要先添加交叉编译工具链路径,然后设置环境变量ARCHCROSS_COMPILEARCH指定源码适配的芯片架构,即编译好的uboot运行在什么平台上,CROSS_COMPILE指定所用的交叉编译工具前缀。比如对于ZYNQ MPSoC而言,可以按照如下方式设置:
    export ARCH=arm
    export CROSS_COMPILE=arm-linux-gnueabihf-
    而对于我们使用的ZYNQMPSoC开发板,不用上面的方法设置环境变量,只需要执行10.5节的设置SDK的工作环境即可,SDK会自动设置相应的环境变量,如下图所示:

12.3.1 设置SDK的工作环境

查找Xilinx官方的开发板默认配置文件

12.1.2U-Boot工程目录分析章节中,configs目录下存放了很多跟Zynq有关的配置,如下图所示,

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_12


12.3.2 Xilinx官方Zynq MPsoc默认配置文件

从上图可以看出有很多的默认配置文件,其中以xilinx_zynqmp开头的是ZYNQ MPSoc相关开发板的配置文件。其中“xilinx_zynqmp_zcu102_rev1_0_defconfig”、“xilinx_zynqmp_zcu102_revA_defconfig”、“xilinx_zynqmp_zcu102_revB_defconfig”是ZYNQ ZCU102开发板的配置文件。

编译Xilinx官方开发板对应的uboot

注:需要先执行10.5设置SDK的工作环境

找到Xilinx官方ZYNQ ZCU102开发板对应的默认配置文件以后可以编译一下,这里我们使用“xilinx_zynqmp_zcu102_rev1_0_defconfig”配置文件。编译uboot命令如下:

make distclean​
make xilinx_zynqmp_zcu102_rev1_0_defconfig​
make -j8

编译完成以后结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux_13


12.3.3编译结果

从上图可以看出,编译成功。其中make distclean表示清除所有生成的文件,“make -j8”表示使用8核来编译uboot。“-j”参数用于设置主机使用多少个核来编译uboot,设置的核越多,编译速度越快。-j8表示使用8个核编译uboot,具体设置多少个要根据自己的虚拟机或者电脑配置,如果你给VMware分配了4个核,那么最多只能使用-j4。

编译完成以后会生成u-boot.binu-boot.elfu-boot.dtb等文件。需要下载到开发板上运行的文件有u-boot.elfu-boot.dtb。这两个文件是运行uboot必不可少的。

验证与驱动测试

使用Petalinux工具,测试还是比较方便的,可以直接生成BOOT.bin文件,不过每次生成BOOT.bin文件并将其拷贝到SD卡还是比较麻烦的。最简便的方法是直接使用JTAG下载,使用JTAG下载需要做的准备工作如下:

  1. 需要手动在Ubuntu虚拟机中安装JTAG驱动,安装方式见5.5小节Linux系统安装JTAG cable驱动
  2. 用下载器连接开发板和电脑,连接完成后,进入如下操作将下载器对接到虚拟机中——在Vmware软件的菜单栏点击“虚拟机(M)”菜单,在弹出的子菜单中移动到“可移动设备(D)”,会弹出相应的移动设备,里面带有“Digilent USB”的是JTAG的USB接口,连接该USB接口,如下图所示:

12.3.4在Vmware中连接JTAG的USB接口到虚拟机内

  1. 开发板的启动模式设置成JTAG启动,开发板上电后,按下PS的复位按键;
  2. 打开串口软件如SecureCRT或Putty,设置好MPSoc开发板所使用的串口并打开。

做好以上准备工作后,就可以使用JTAG进行下载了。

当然了,使用JTAG下载还是需要借助Petalinux工具的。首先我们设置好Petalinux的工作环境,然后进入第六章Petalinux设计流程实战章节建立的Petalinux工程目录中。由于编译生成的uboot文件不在Petalinux工程范围内,Petalinux无法使用,怎么解决呢?

用软链接就可以了,方法如下:

首先备份Petalinux工程images/linux目录下的u-boot.elfsystem.dtb文件,命令如下:

cd images/linux​
mv u-boot.elf u-boot.elf.bak​
mv system.dtb system.dtb.bak

然后软链接编译生成的u-boot.elfsystem.dtb文件,命令如下:

ln -s ~/git.d/u-boot-xlnx/u-boot.elf u-boot.elf

ln -s ~/git.d/u-boot-xlnx/u-boot.dtb system.dtb

结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux_14


12.3.5 软链接u-boot.elfsystem.dtb

前面我们说过使用SD卡下载比较麻烦,所以使用JTAG下载,但是笔者通过JTAG下载后,发现不能通过uboot启动内核,原因是对于MPSoc器件,petalinux2019.2不支持petalinux-boot命令下uboot启动linux内核,所以本次实验需要先将linux镜像文件放在SD卡中,然后uboot从SD卡启动镜像。接下来将linux镜像文件image.ub复制到SD卡分区1(boot分区)中,复制完成后按照9.6拷贝根文件系统到SD卡的ext4分区中的命令卸载SD卡,并将SD卡插到开发板上,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux_15


12.3.6复制image.ub到sd卡分区1

现在用JTAG下载u-boot文件,命令如下(注意,下载前要先设置petalinux环境变量):

petalinux-boot --jtag --fpga --u-boot

在更高版本的petalinux中,可以使用“petalinux-boot --jtag --fpga --u-boot”命令通过JTAG下载uboot并启动linux内核,但是petalinux2019.2不支持直接通过JTAG下载uboot并启动linux内核。本次测试,我们通过“petalinux-boot --jtag --fpga --u-boot”命令,先将uboot下载到开发板上,然后进入uboot,通过sd卡启动内核。

上面的命令将下载fpga(system.bit)、pmu firmware、FSBL、uboot和ATF(bl31.elf)。执行结果如下图所示(下载前需要按下开发板的PS复位按键,否则会下载失败):

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux_16


12.3.7 下载u-boot

观察串口接收软件,uboot启动倒计时很短,只有两秒,当出现倒计时的时候,立即按“enter”键进入uboot,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_17


12.3.8进入uboot

进入uboot后,使用“iminfo”命令查询镜像的起始地址为“0x8000000”,然后使用“fatload”文件系统命令将镜像文件image.ub从SD卡传输到内存中地址0x8000000处,最后通过“bootm”命令启动内核镜像,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_18


12.3.9串口软件接收情况

从上图可以看到,除了因为以太网的PHY地址不对导致不能找到以太网设备外,是可以正常启动linux内核的。当然了还有一些其他的小问题,比如只检测到了mmc0,这些问题主要跟设备树有关。至于启动linux内核后出现的问题,就不归属于uboot了,后面的章节会解决。

在U-Boot中添加自己的开发板

添加开发板默认配置文件

先在configs目录下创建MPSoC开发板的默认配置文件。复制xilinx_zynqmp_zcu102_rev1_0_defconfig,然后重命名为zynqmp_altk_defconfig,命令如下:

cd configs​
cp xilinx_zynqmp_zcu102_rev1_0_defconfig zynqmp_altk_defconfig

然后修改zynqmp_altk_defconfig文件,修改后的文件内容如下(因文件较长,故部分未改动内容以“……”代替):

示例代码mp_altk_defconfig文件

1 CONFIG_ARM=y​
2 CONFIG_SYS_CONFIG_NAME="zynqmp_altk"指定开发板头文件​
3 CONFIG_ARCH_ZYNQMP=y​
4 CONFIG_SYS_TEXT_BASE=0x8000000​
5 CONFIG_SYS_MALLOC_F_LEN=0x8000​
6 CONFIG_SPL=y​
7 CONFIG_DEBUG_UART_BASE=0xff000000​
8 CONFIG_DEBUG_UART_CLOCK=100000000​
9 CONFIG_SPL_SPI_FLASH_SUPPORT=y​
10 CONFIG_SPL_SPI_SUPPORT=y​
11 CONFIG_ZYNQMP_USB=y​
12 CONFIG_DEBUG_UART=y​
13 CONFIG_AHCI=y​
14 CONFIG_DISTRO_DEFAULTS=y​
15 CONFIG_FIT=y​
16 CONFIG_FIT_VERBOSE=y​
17 CONFIG_SPL_LOAD_FIT=y​
18 # CONFIG_DISPLAY_CPUINFO is not set​
19 CONFIG_BOARD_EARLY_INIT_R=y​
20 CONFIG_SPL_OS_BOOT=y​
21 CONFIG_SPL_RAM_SUPPORT=y​
22 CONFIG_SPL_RAM_DEVICE=y​
23 CONFIG_SPL_ATF=y​
24 CONFIG_SYS_PROMPT="ZynqMP> "​
……​
47 CONFIG_DEFAULT_DEVICE_TREE="zynqmp-altk"指定设备树​
48 CONFIG_ENV_IS_IN_FAT=y​
49 CONFIG_NET_RANDOM_ETHADDR=y​
50 CONFIG_SPL_DM=y​
51 CONFIG_SPL_DM_SEQ_ALIAS=y​
52 CONFIG_SCSI_AHCI=y​
53 CONFIG_SATA_CEVA=y​
54 CONFIG_CLK_ZYNQMP=y​
55 CONFIG_DFU_RAM=y​
56 CONFIG_USB_FUNCTION_FASTBOOT=y​
57 CONFIG_FASTBOOT_FLASH=y​
58 CONFIG_FASTBOOT_FLASH_MMC_DEV=0​
59 CONFIG_FASTBOOT_CMD_OEM_FORMAT=y​
60 CONFIG_FPGA_XILINX=y​
61 CONFIG_FPGA_ZYNQMPPL=y​
62 CONFIG_DM_GPIO=y​
63 CONFIG_XILINX_GPIO=y​
64 CONFIG_DM_I2C=y​
65 CONFIG_SYS_I2C_CADENCE=y​
66 CONFIG_I2C_MUX=y​
67 CONFIG_I2C_MUX_PCA954x=y​
68 CONFIG_LED=y​
69 CONFIG_LED_GPIO=y​
70 CONFIG_MISC=y​
71 CONFIG_I2C_EEPROM=y​
72 CONFIG_ZYNQ_GEM_I2C_MAC_OFFSET=0x20​
73 CONFIG_SYS_I2C_EEPROM_ADDR=0x0​
74 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW=0x0​
75 CONFIG_MMC_IO_VOLTAGE=y​
76 CONFIG_MMC_UHS_SUPPORT=y​
77 CONFIG_MMC_SDHCI=y​
78 CONFIG_MMC_SDHCI_ZYNQ=y​
79 CONFIG_SPI_FLASH=y​
……​
116 CONFIG_USB_GADGET_MANUFACTURER="Xilinx"​
117 CONFIG_USB_GADGET_VENDOR_NUM=0x03FD​
118 CONFIG_USB_GADGET_PRODUCT_NUM=0x0300​
119 CONFIG_USB_FUNCTION_THOR=y​
120 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y​
121 CONFIG_BOOTCOMMAND="run default_bootcmd"

可以看出,zynqmp_altk_defconfig文件基本和xilinx_zynqmp_zcu102_rev1_0_defconfig文件中的内容一样。修改的内容如下:

首先修改第2行,在第2行添加宏定义CONFIG_SYS_CONFIG_NAME="zynqmp_altk"

然后修改第47行,指定MPSoC开发板的设备树文件"zynqmp-altk",对应的是我们在12.4.4节创建的MPSoC开发板的设备树文件名;

在最后一行添加宏定义CONFIG_BOOTCOMMAND="run default_bootcmd"

添加开发板对应的头文件

在目录include/configs下添加MPSoC开发板对应的头文件。这里使用xilinx官方开发板的头文件xilinx_zynqmp.h并进行修改。在终端中输入如下命令:

cd ../include/configs/​
cp xilinx_zynqmp.h zynqmp_altk.h //复制xilinx_zynqmp.h为zynqmp_altk.h

执行结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_19


12.4.1添加头文件

zynqmp_altk.h文件的内容如下所示(无需修改):

示例代码 zynq_altk.h文件

1 #ifndef __XILINX_ZYNQMP_H​
2 #define __XILINX_ZYNQMP_H​
3 ​
4 #define CONFIG_REMAKE_ELF​
5 ​
6 /* #define CONFIG_ARMV8_SWITCH_TO_EL1 */​
7 ​
8 /* Generic Interrupt Controller Definitions */​
9 #define CONFIG_GICV2​
10 #define GICD_BASE 0xF9010000​
11 #define GICC_BASE 0xF9020000​
…… ​
95 /* Xilinx initial environment variables */​
96 #ifndef CONFIG_EXTRA_ENV_BOARD_SETTINGS​
97 #define CONFIG_EXTRA_ENV_BOARD_SETTINGS \​
98 "kernel_addr=0x80000\0" \​
99 "initrd_addr=0xa00000\0" \​
100 "initrd_size=0x2000000\0" \​
101 "fdt_addr=4000000\0" \​
102 "fdt_high=0x10000000\0" \​
103 "loadbootenv_addr=0x100000\0" \​
104 "sdbootdev=0\0"\​
……​
170 "usb_dfu_spl=booti $kernel_addr - $fdt_addr\0" \​
171 "usbhostboot=usb start && load usb 0 $fdt_addr system.dtb && " \​
172 "load usb 0 $kernel_addr Image && " \​
173 "booti $kernel_addr - $fdt_addr\0" \​
174 "xilinxcmd=echo !!! && echo !!! Booting cmd is deprecated (will be removed in 2020). && echo !!! Please move to distro bootcmd. && echo !!!\0" \​
175 PARTS_DEFAULT​
176 #endif​
177 ​
178 /* Monitor Command Prompt */​
179 /* Console I/O Buffer Size */​
180 #define CONFIG_SYS_CBSIZE 2048​
181 #define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE​
182 #define CONFIG_PANIC_HANG​
183 #define CONFIG_SYS_MAXARGS 64​
…… ​
352 #define CONFIG_SYS_SPL_MALLOC_START 0x20000000​
353 #define CONFIG_SYS_SPL_MALLOC_SIZE 0x100000​
354 ​
355 #ifdef CONFIG_SPL_SYS_MALLOC_SIMPLE​
356 # error "Disable CONFIG_SPL_SYS_MALLOC_SIMPLE. Full malloc needs to be used"​
357 #endif​
358 ​
359 #define CONFIG_BOARD_EARLY_INIT_F​
360 ​
361 #endif /* __XILINX_ZYNQMP_H */

可以看到zynqmp_altk.h里面有一些以“CONFIG_”开头的宏定义,这些宏定义可以用于配置或者裁剪uboot。如果我们要想使能或者禁止uboot的某些功能,可以在该文件中添加这个功能对应的CONFIG_XXX宏即可,如果不需要某个功能的话就删除掉对应的宏。

添加开发板对应的板级文件夹

uboot中每个板子都有一个对应的文件夹来存放板级文件,比如开发板上外设驱动文件等。Xilinx的ZYNQ MPSoC系列芯片的所有板级文件夹都存放在board/xilinx/zynqmp目录下,在这个目录下有个名为zynqmp-zcu102-rev1.0的文件夹,这个文件夹就是Xilinx官方ZC102开发板的板级文件夹。复制zynqmp-zcu102-rev1.0,将其重命名为zynqmp-altk,命令如下:

cd board/xilinx/zynqmp/​
cp -r zynqmp-zcu102-rev1.0 zynqmp-altk

进入zynqmp-altk目录中,可以看到只有一个名为“psu_init_gpl.c”的文件,该文件是PS的初始化文件,可以用于我们的MPSoc开发板。

添加开发板对应的设备树

uboot支持设备树,每个开发板都有一个对应的设备树文件。Xilinx的ZYNQ MPSoC系列芯片的所有设备树文件夹都存放在arch/arm64/dts/目录下,我们先看下该目录下Zynq UltraScale+ MPSoC相关的设备树文件,命令如下:

cd ~/git.d/u-boot-xlnx​
ls arch/arm/dts/zynqmp*

结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_20


12.4.2相关设备树文件

不同的开发板有不同的设备树文件,我们自己的开发板当然得用我们自己的设备树文件。设备树文件从哪来,可以参考其他开发板的设备树文件,手动编写,不过这样做工作量太大,一般不推荐这种方法。最简便直接的方法是用Petalinux工具生成的设备树文件。Petalinux工具会根据我们提供的开发板xsa文件自动生成相应的设备树文件,生成的设备树文件在Petalinux工程(第六章Petalinux设计流程实战章节建立的Petalinux工程)的components/plnx_workspace/device-tree/device-tree目录下,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux_21


12.4.3生成的设备树

后缀为dtsi和dts的都是设备树文件,是Petalinux根据xsa文件自动生成的。下面介绍这几个设备树文件的含义:

zynqmp.dtsiZynq UltraScale+ MPSoc系列芯片通用的PS部分的设备树文件;

zynqmp-clk-ccf.dtsiZynq UltraScale+ MPSoC系列芯片通用的时钟相关的设备树文件;

pcw.dtsi:开发板ps部分的设备树文件,在zynqmp.dtsi基础上生成的,使能相应的外设;

pl.dtsi:开发板pl部分IP的设备树文件(Xilinx发布的包含驱动的IP);

system-top.dts:Petalinux生成设备树镜像文件dtb的核心文件,该文件include上面介绍的文件,以及Petalinux用户可编辑的system-user.dtsi文件,system-user.dtsi文件在6.3.7节使用过;

system-conf.dtsi:Petalinux根据用户的配置生成的额外的设备树文件,不同于上面介绍的设备树文件,是根据xsa文件自动生成的,xsa文件不变,它们也不变,该文件会随着用户对Petalinux工程的不同配置而相应变动。

要想在uboot源码中添加开发板的设备树文件,可以将system-top.dts文件及其依赖文件添加到uboot源码中。打开system-top.dts文件,其内容如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_22


12.4.4 system-top.dts文件的内容

可以看到总共include五个设备树文件,其中zynqmp.dtsizynqmp-clk-ccf.dtsi是通用文件,不用添加,剩下的pcw.dtsipl.dtsisystem-user.dtsi需要添加。进入到第六章创建的Petalinux工程的components/plnx_workspace/device-tree/device-tree目录下,然后输入如下命令将设备树文件复制到uboot源码相应目录:

cp pcw.dtsi pl.dtsi ~/git.d/u-boot-xlnx/arch/arm/dts/​
cp system-top.dts ~/git.d/u-boot-xlnx/arch/arm/dts/zynqmp-altk.dts​
cp ~/workspace/petalinux/ALIENTEK-ZYNQ/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi ~/git.d/u-boot-xlnx/arch/arm/dts/

其中我们将system-top.dts文件重命名为zynqmp-altk.dts,与12.4.1节保持一致。结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_23


12.4.5添加设备树文件

添加完开发板的设备树文件后,还需要进行相应的修改才可以使用。

进入到uboot源码的arch/arm/dts目录下,编辑system-user.dtsi文件,只需改前10行的内容即可。

修改前的前10行的内容:

/include/ "system-conf.dtsi"​
#include <dt-bindings/gpio/gpio.h>​
#include <dt-bindings/input/input.h>​
/ {​
model = "Alientek Zynq MpSoc Development Board";​
leds {​
compatible = "gpio-leds";​
修改后的前10行的内容:​
#include <dt-bindings/gpio/gpio.h>​
#include <dt-bindings/input/input.h>​
/ {​
model = "Alientek Zynq MpSoc Development Board";​
compatible = "xlnx,zynqmp-altk", "xlnx,zynqmp";​
leds {​
compatible = "gpio-leds";

删除了原内容第一行的“/include/"system-conf.dtsi"”,添加了“compatible = "xlnx,zynqmp-altk", "xlnx,zynqmp";”。关于设备树的内容后面在讲解linux驱动的时候会详细讲解。

接下来在arch/arm/dts目录中的Makefile中添加开发板的设备树文件。打开arch/arm/dts/Makefile文件,找到“dtb-$(CONFIG_ARCH_ZYNQMP)”所在行,在其下方添加“zynqmp-altk.dtb \”,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux_24


12.4.6修改Makefile文件

到此为止,正点原子MPSoc开发板就已经添加到uboot中了。

在uboot源码目录中输入“git status”命令,可以看到移植过程中,我们修改了哪些文件,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_25


12.4.7移植中修改的文件

接下来就是编译移植后的uboot。

修改U-Boot图形界面配置文件

uboot支持图形界面配置,关于uboot的图形界面配置下一章会详细的讲解。修改文件arch/arm/mach-zynq/Kconfig,将第48行的SYS_CONFIG_NAME配置项的内容修改如下:

示例代码 Kconfig文件

48 config SYS_CONFIG_NAME​
49 string "Board configuration name"​
50 default "zynqmp_altk"​
51 help​
52 This option contains information about board configuration name.​
53 Based on this option include/configs/<CONFIG_SYS_CONFIG_NAME>.h header​
54 will be used for board configuration.

修改完成以后的Kconfig文件如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_26


12.4.8修改后的Kconfig文件

到此为止,DFZU2EG_4EV MPSoC开发板就已经添加到uboot中了,接下来就是编译这个新添加的开发板。

使用新添加的板子配置编译uboot

在uboot源码根目录下新建一个名为zynqmp.sh的shell脚本,在这个shell脚本里面输入如下内容:

示例代码 zynq.sh脚本文件

1 #!/bin/bash​
2 make distclean​
3 make zynqmp_altk_defconfig​
4 make -j8

第3行我们使用的默认配置文件就是12.4.1节中新建的zynqmp_altk_defconfig配置文件。给予zynqmp.sh可执行权限,然后运行脚本来完成编译,命令如下:

chmod 777 zynqmp.sh   //给予可执行权限​
./zynqmp.sh //运行脚本编译uboot

等待编译完成,编译完成以后输入如下命令,查看一下12.4.2小节中添加的zynqmp_altk.h这个头文件有没有被引用。

grep -nR "zynqmp_altk.h"

如果有很多文件都引用了zynqmp_altk.h这个头文件,那就说明新板子添加成功,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_27


12.4.9查找结果

编译完成以后就可以使用12.3.3验证与驱动测试小节中的方法进行下载测试。串口软件输出结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_linux_28


12.4.10启动过程

从上图可以看到,我们基本移植成功了,也验证了这种下载方式是没有问题的。uboot的最终目的就是启动Linux内核,所以还是需要通过启动Linux内核来判断uboot移植是否真的成功。在启动Linux内核之前我们先来学习两个重要的环境变量bootcmd和bootargs。

bootcmd和bootargs环境变量

环境变量是uboot中非常重要的一种变量,可以让我们在不修改uboot源码的情况下改变uboot运行的特性。uboot中有两个非常重要的环境变量bootcmd和bootargs,接下来看一下这两个环境变量。bootcmd和bootagrs是采用类似shell脚本语言编写的,里面有很多的变量引用,这些变量其实都是环境变量,有很多是Xilinx自己定义的。文件include/configs/zynqmp_altk.h中的宏CONFIG_EXTRA_ENV_SETTINGS保存着这些环境变量的默认值,内容如下:

示例代码宏CONFIG_EXTRA_ENV_SETTINGS默认值

155 /* Extra U-Boot Env settings */​
156 #define CONFIG_EXTRA_ENV_SETTINGS \​
157 SERIAL_MULTI \​
158 CONSOLE_ARG \​
159 DFU_ALT_INFO_RAM \​
160 DFU_ALT_INFO_MMC \​
161 PSSERIAL0 \​
162 "nc=setenv stdout nc;setenv stdin nc;\0" \​
163 "ethaddr=00:0a:35:00:1e:53\0" \​
164 "bootenv=uEnv.txt\0" \​
165 "importbootenv=echo \"Importing environment from SD ...\"; " \​
166 "env import -t ${loadbootenv_addr} $filesize\0" \​
167 "loadbootenv=load mmc $sdbootdev:$partid ${loadbootenv_addr} ${bootenv}\0" \​
168 "sd_uEnvtxt_existence_test=test -e mmc $sdbootdev:$partid /uEnv.txt\0" \​
169 "uenvboot=" \​
170 "if run sd_uEnvtxt_existence_test; then " \​
171 "run loadbootenv; " \​
172 "echo Loaded environment from ${bootenv}; " \​
173 "run importbootenv; " \​
174 "fi; " \​
175 "if test -n $uenvcmd; then " \​
176 "echo Running uenvcmd ...; " \​
177 "run uenvcmd; " \​
178 "fi\0" \​
179 "autoload=no\0" \​
180 "sdbootdev=0\0" \​
181 "clobstart=0x10000000\0" \​
182 "netstart=0x10000000\0" \​
183 "dtbnetstart=0x23fff000\0" \​
184 "loadaddr=0x10000000\0" \​
185 "bootsize=0x500000\0" \​
186 "bootstart=0x0\0" \​
187 "boot_img=BOOT.BIN\0" \​
188 "load_boot=tftpboot ${clobstart} ${boot_img}\0" \​
189 "update_boot=setenv img boot; setenv psize ${bootsize}; setenv installcmd \"install_boot\"; run load_boot test_img; setenv img; setenv psize; setenv installcmd\0" \​
190 "sd_update_boot=echo Updating boot from SD; mmcinfo && fatload mmc ${sdbootdev}:1 ${clobstart} ${boot_img} && run install_boot\0" \​
191 "install_boot=sf probe 0 && sf erase ${bootstart} ${bootsize} && " \​
192 "sf write ${clobstart} ${bootstart} ${filesize}\0" \​
193 "bootenvsize=0x20000\0" \​
194 "bootenvstart=0x500000\0" \​
195 "eraseenv=sf probe 0 && sf erase ${bootenvstart} ${bootenvsize}\0" \​
196 "jffs2_img=rootfs.jffs2\0" \​
197 "load_jffs2=tftpboot ${clobstart} ${jffs2_img}\0" \​
198 "update_jffs2=setenv img jffs2; setenv psize ${jffs2size}; setenv installcmd \"install_jffs2\"; run load_jffs2 test_img; setenv img; setenv psize; setenv installcmd\0" \​
199 "sd_update_jffs2=echo Updating jffs2 from SD; mmcinfo && fatload mmc ${sdbootdev}:1 ${clobstart} ${jffs2_img} && run install_jffs2\0" \​
200 "install_jffs2=sf probe 0 && sf erase ${jffs2start} ${jffs2size} && " \​
201 "sf write ${clobstart} ${jffs2start} ${filesize}\0" \​
202 "kernelsize=0xa80000\0" \​
203 "kernelstart=0x520000\0" \​
204 "kernel_img=image.ub\0" \​
205 "load_kernel=tftpboot ${clobstart} ${kernel_img}\0" \​
206 "update_kernel=setenv img kernel; setenv psize ${kernelsize}; setenv installcmd \"install_kernel\"; run load_kernel test_crc; setenv img; setenv psize; setenv installcmd\0" \​
207 "sd_update_kernel=echo Updating kernel from SD; mmcinfo && fatload mmc ${sdbootdev}:1 ${clobstart} ${kernel_img} && run install_kernel\0" \​
208 "install_kernel=sf probe 0 && sf erase ${kernelstart} ${kernelsize} && " \​
209 "sf write ${clobstart} ${kernelstart} ${filesize}\0" \​
210 "cp_kernel2ram=sf probe 0 && sf read ${netstart} ${kernelstart} ${kernelsize}\0" \​
211 "dtb_img=system.dtb\0" \​
212 "load_dtb=tftpboot ${clobstart} ${dtb_img}\0" \​
213 "update_dtb=setenv img dtb; setenv psize ${dtbsize}; setenv installcmd \"install_dtb\"; run load_dtb test_img; setenv img; setenv psize; setenv installcmd\0" \​
214 "sd_update_dtb=echo Updating dtb from SD; mmcinfo && fatload mmc ${sdbootdev}:1 ${clobstart} ${dtb_img} && run install_dtb\0" \​
215 "loadbootenv_addr=0x00100000\0" \​
216 "fault=echo ${img} image size is greater than allocated place - partition ${img} is NOT UPDATED\0" \​
217 "test_crc=if imi ${clobstart}; then run test_img; else echo ${img} Bad CRC - ${img} is NOT UPDATED; fi\0" \​
218 "test_img=setenv var \"if test ${filesize} -gt ${psize}\\; then run fault\\; else run ${installcmd}\\; fi\"; run var; setenv var\0" \​
219 "netboot=tftpboot ${netstart} ${kernel_img} && bootm\0" \​
220 "default_bootcmd=run cp_kernel2ram && bootm ${netstart}\0" \​
221 ""

CONFIG_EXTRA_ENV_SETTINGS中有很多有价值的信息,比如第219行的netboot变量,就可以让我们从网络启动linux。

环境变量bootcmd

bootcmd保存着uboot默认命令,uboot倒计时结束以后就会执行bootcmd中的命令。这些命令一般都是用来启动Linux内核的,比如读取SD或者eMMC中的Linux内核镜像文件和设备树文件到DRAM中,然后启动Linux内核。可以在uboot启动以后进入命令行设置bootcmd环境变量的值。如果QSPI中没有保存bootcmd的值,那么uboot就会使用默认的值,开发板第一次运行uboot的时候都会使用默认值来设置bootcmd环境变量,默认环境变量在文件include/env_default.h中定义。打开文件include/env_default.h,在此文件中有如下所示内容:

示例代码默认环境变量

14 env_t environment __UBOOT_ENV_SECTION__ = {​
15 ENV_CRC, /* CRC Sum */​
16 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT​
17 1, /* Flags: valid */​
18 #endif​
19 {​
20 #elif defined(DEFAULT_ENV_INSTANCE_STATIC)​
21 static char default_environment[] = {​
22 #else​
23 const uchar default_environment[] = {​
24 #endif​
……​
31 #ifdef CONFIG_USE_BOOTARGS​
32 "bootargs=" CONFIG_BOOTARGS "\0"​
33 #endif​
34 #ifdef CONFIG_BOOTCOMMAND​
35 "bootcmd=" CONFIG_BOOTCOMMAND "\0"​
36 #endif​
37 #ifdef CONFIG_RAMBOOTCOMMAND​
38 "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"​
39 #endif​
40 #ifdef CONFIG_NFSBOOTCOMMAND​
41 "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"​
42 #endif​
43 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)​
44 "bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0"​
45 #endif​
……​
91 #ifdef CONFIG_ENV_VARS_UBOOT_CONFIG​
92 "arch=" CONFIG_SYS_ARCH "\0"​
93 #ifdef CONFIG_SYS_CPU​
94 "cpu=" CONFIG_SYS_CPU "\0"​
95 #endif​
96 #ifdef CONFIG_SYS_BOARD​
97 "board=" CONFIG_SYS_BOARD "\0"​
98 "board_name=" CONFIG_SYS_BOARD "\0"​
99 #endif​
100 #ifdef CONFIG_SYS_VENDOR​
101 "vendor=" CONFIG_SYS_VENDOR "\0"​
102 #endif​
103 #ifdef CONFIG_SYS_SOC​
104 "soc=" CONFIG_SYS_SOC "\0"​
105 #endif​
106 #endif​
107 #ifdef CONFIG_EXTRA_ENV_SETTINGS​
108 CONFIG_EXTRA_ENV_SETTINGS​
109 #endif​
110 "\0"​
111 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED​
112 }​
113 #endif​
114 };

从上述代码中的第14行可以看出environment是个env_t类型的变量,env_t类型如下:

示例代码env_t结构体

148 typedef struct environment_s {​
149 uint32_t crc; /* CRC32 over data bytes */​
150 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT​
151 unsigned char flags; /* active/obsolete flags */​
152 #endif​
153 unsigned char data[ENV_SIZE]; /* Environment data */​
154 } env_t;

env_t结构体中的crc为CRC值,flags是标志位,data数组就是环境变量值。因此,environment就是用来保存默认环境变量的,在示例代码默认环境变量中指定了很多环境变量的默认值,比如bootcmd的默认值就是CONFIG_BOOTCOMMAND,bootargs的默认值就是CONFIG_BOOTARGS。我们可以在platform-altk.h文件中通过设置宏CONFIG_BOOTCOMMAND来设置bootcmd的默认值,Petalinux工具设置的CONFIG_BOOTCOMMAND值如下:

示例代码 CONFIG_BOOTCOMMAND默认值

215 /* BOOTCOMMAND */​
216 #define CONFIG_BOOTCOMMAND "run default_bootcmd"

看起来很简单,我们来分析下。以下分析的内容都来自include/configs/platform-altk.h中的宏CONFIG_EXTRA_ENV_SETTINGS定义处。

216行,“run default_bootcmd”使用的是uboot的run命令来运行default_bootcmddefault_bootcmdPetalinux工具生成的。default_bootcmd内容如下:

212 "default_bootcmd=run uenvboot; run cp_kernel2ram && bootm ${netstart}\0" \

default_bootcmd里面用到的变量有uenvbootcp_kernel2ramnetstartuenvboot变量的内容如下:

164 "bootenv=uEnv.txt\0" \​
165 "importbootenv=echo \"Importing environment from SD ...\"; " \​
166 "env import -t ${loadbootenv_addr} $filesize\0" \​
167 "loadbootenv=load mmc $sdbootdev:$partid ${loadbootenv_addr} ${bootenv}\0" \​
168 "sd_uEnvtxt_existence_test=test -e mmc $sdbootdev:$partid /uEnv.txt\0" \​
169 "uenvboot=" \​
170 "if run sd_uEnvtxt_existence_test; then " \​
171 "run loadbootenv; " \​
172 "echo Loaded environment from ${bootenv}; " \​
173 "run importbootenv; " \​
174 "fi; " \​
175 "if test -n $uenvcmd; then " \​
176 "echo Running uenvcmd ...; " \​
177 "run uenvcmd; " \​
178 "fi\0" \

uboot使用了类似shell脚本语言的方式来编写变量。uenvboot做的事情是首先判断SD卡是否存在环境变量文件uEnv.txt,显然SD卡中没有uEnv.txt文件,然后判断uenvcmd变量值的长度是否为零,由于uenvcmd变量未定义,所以开发板启动时不打印uenvboot中的信息。

cp_kernel2ramnetstart变量的内容如下:

180 "sdbootdev=0\0" \​
182 "netstart=0x10000000\0" \​
198 "kernel_img=image.ub\0" \​
202 "cp_kernel2ram=mmcinfo && fatload mmc ${sdbootdev} ${netstart} ${kernel_img}\0" \

可以看到netstart变量值为0x10000000,是文件加载到内存的地址。使用netstart变量名是因为使用tftpboot命令从网络下载内核镜像文件时,存放在内存中的位置由netstart指定。

cp_kernel2ram先执行mmcinfo命令,打印mmc信息,执行成功后从mmc0中加载内核镜像文件image.ub到内存DRAM0x10000000处。

当我们明确知道我们所使用的板子的时候就可以大幅简化宏CONFIG_BOOTCOMMAND的设置,比如我们要从SD启动,那么宏CONFIG_BOOTCOMMAND就可简化为:

#define CONFIG_BOOTCOMMAND \​
"mmcinfo && fatload mmc 0 0x10000000 image.ub;" \​
"bootm 0x10000000;"

或者可以直接在uboot中设置bootcmd的值,命令如下:

setenv bootcmd ' mmcinfo && fatload mmc 0 0x10000000 image.ub; bootm 0x10000000;'

环境变量bootargs

bootargs保存着uboot传递给Linux内核的参数。ZYNQ MPSoC的bootargs由设备树指定,在12.4.4节我们可以看到bootargs的值为空,也就是说ZYNQ MPSoC一般不用向linux内核传递参数。不过此处我们还是简单地讲解下bootargs。以下面的命令做介绍:

setenv bootargs ‘cnotallow=${console},${baudrate} root=${mmcroot} rootfstype=ext4’

假设cnotallow=ttyPS0,baudrate=115200,mmcroot=/dev/mmcblk0p2 rootwait rw,因此将其展开后就是:

setenv bootargs ‘cnotallow=ttyPS0,115200 root=/dev/mmcblk0p2 rootwait rw rootfstype=ext4’

可以看出bootargs的值为“cnotallow= ttyPS0,115200 root= /dev/mmcblk1p2 rootwait rw rootfstype=ext4。bootargs设置了很多的参数的值,这些参数Linux内核会使用到,常用的参数有:

1、console

console用来设置linux终端(或者叫控制台),也就是通过什么设备来和Linux进行交互,是串口还是LCD屏幕。如果是串口的话应该是串口几等等。一般设置串口作为Linux终端,这样我们就可以在电脑上通过串口工具来和linux交互了。这里设置console为ttyPS0,因为linux启动以后ZYNQ MPSoC的串口0在linux下的设备文件就是/dev/ttyPS0,在Linux下,一切皆文件。

ttyPS0后面有个“,115200”,这是设置串口的波特率,cnotallow= ttyPS0,115200综合起来就是设置ttyPS0(也就是串口0)作为Linux的终端,并且串口波特率设置为115200

2、root

root用来设置根文件系统的位置,root=/dev/mmcblk0p2用于指明根文件系统存放在mmcblk0设备的分区2中。开发板启动linux以后会存在/dev/mmcblk0/dev/mmcblk1/dev/mmcblk0p1/dev/mmcblk0p2/dev/mmcblk1p1/dev/mmcblk1p2这样的文件,其中/dev/mmcblkx(x=0~n)表示mmc设备,而/dev/mmcblkxpy(x=0~n,y=1~n)表示mmc设备x的分区y。在开发板中/dev/mmcblk0表示SD卡,而/dev/mmcblk0p2表示SD卡的分区2。

root后面有“rootwait rw”,rootwait表示等待mmc设备初始化完成以后再挂载,否则的话mmc设备还没初始化完成就挂载根文件系统会出错的。rw表示根文件系统是可以读写的,不加rw的话可能无法在根文件系统中进行写操作,只能进行读操作。

3、rootfstype

此选项一般配合root一起使用,rootfstype用于指定根文件系统类型,如果根文件系统为ext格式的话此选项无所谓。如果根文件系统是yaffs、jffs或ubifs的话就需要设置此选项,指定根文件系统的类型。

bootargs常设置的选项就这三个,后面遇到其他选项的话再讲解。

uboot启动Linux测试

uboot已经移植好了,bootcmd和bootargs这两个重要的环境变量也讲解了,接下来就要测试一下uboot能不能完成它的工作:启动Linux内核。我们测试两种启动Linux内核的方法,一种是直接从SD卡启动,一种是从网络启动。

从SD卡启动Linux系统

从SD卡启动也就是将编译出来的Linux镜像文件image.ub保存在SD卡中,uboot从SD卡中读取该文件并启动。由于目前我们还没有讲解如何移植linux,所以这里我们就以第六章生成的image.ub为例,该文件已经烧写到了SD卡中,我们可以直接读取来测试。

按照12.3.3验证与驱动测试中的步骤,先检查一下SD卡的分区1中有没有image.ub文件,输入命令“ls mmc 1:1”(注意和12.3.3节不同,SD卡位置已经改变为mmc 1),结果如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_29


12.6.1 SD卡分区1文件

从上图中可以看出,此时SD卡分区1中存在image.ub这个文件,所以我们可以测试新移植的uboot能不能启动linux内核。

接下来使用“fatload”命令将镜像传输到内存中,然后用“bootm”命令启动Linux内核,如果Linux内核启动成功的话就会输出如图下图所示的启动信息:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_30


12.6.2内核启动成功

从网络启动Linux系统

从网络启动linux系统的唯一目的就是为了调试。不管是为了调试linux系统还是linux下的驱动。每次修改linux系统文件或者linux下的某个驱动以后都要将其烧写到SD中去测试,这样太麻烦了。我们可以设置linux从网络启动,也就是将linux镜像文件和根文件系统都放到Ubuntu下某个指定的文件夹中,这样每次重新编译linux内核或者某个linux驱动以后只需要使用cp命令将其拷贝到这个指定的文件夹中即可,这样就不用需要频繁的烧写SD,这样就加快了开发速度。我们可以通过tftp从Ubuntu中下载image.ub文件或者Image和设备树文件,根文件系统的话也可以通过nfs挂载,不过本小节我们不讲解如何通过nfs挂载根文件系统,这个在讲解根文件系统移植的时候再讲解。这里我们使用tftp从Ubuntu中下载image.ub,前提是要将image.ub文件放到Ubuntu下的tftpboot目录中,这些文件我们在第六章编译Petalinux工程的时候Petalinux工具已经帮我们复制到/tftpboot目录中了(前提是已经按照4.3节搭建好tftp服务器)。

接下来按照11.4.8节中的步骤使用tftpboot网络协议将image.ub下载到ddr中(需要先按照11.4.4节设置开发板和服务器ip地址),如12.6.3所示,然后使用bootm命令启动镜像,如所示:

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_配置文件_31


12.6.3使用tftpboot网络协议下载镜像

《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第十二章 U-Boot移植​_开发板_32


12.6.4 使用“bootm”命令启动linux

uboot移植到此结束,简单总结一下uboot移植的过程:

  1. 不管是购买的开发板还是自己做的开发板,基本都是参考半导体厂商的dmeo板,而半导体厂商会在他们自己的开发板上移植好uboot、linux kernel和systemfs等,最终制作好BSP包提供给用户。我们可以在官方提供的BSP包的基础上添加我们的板子,也就是俗称的移植。
  2. 我们购买的开发板或者自己做的板子一般都不会原封不动的照抄半导体厂商的demo板,都会根据实际的情况来做修改,既然有修改就必然涉及到uboot下驱动的移植。
  1. 一般uboot中需要解决串口、QSPI、eMMC或SD卡、网络和LCD驱动,因为uboot的主要目的就是启动Linux内核,所以不需要考虑太多的外设驱动。

在uboot中添加自己的板子信息,根据自己板子的实际情况来修改uboot中的驱动。

举报

相关推荐

0 条评论