
U-boot使用) Y1 C1 d! l; q3 s- v% C9 D5 I9 J 在移植U-Boot之前,我们肯定要先使用一下U-Boot,得先体验一下U-Boot是个什么东西。STM32MP157开发板光盘资料里面已经提供了一个正点原子团队已经移植好的U-Boot,本章我们就直接编译这个移植好的U-Boot,然后烧写到EMMC里面启动,启动U-Boot以后就可以学习使用U-Boot的命令。 10.1 U-Boot简介6 j$ ?1 j4 m0 @$ }/ u Linux 系统要启动需要通过bootloader 程序引导,也就说芯片上电以后先运行一段bootloader程序。这段bootloader程序会先初始化DDR等外设,然后将Linux内核从flash(NAND,NOR FLASH,SD,EMMC 等)拷贝到 DDR 中,最后启动 Linux 内核。当然了,bootloader 的实际工作要复杂的多,但是它最主要的工作就是启动 Linux 内核,bootloader 和 Linux 内核的关系就跟 PC 上的 BIOS 和 Windows 的关系一样,bootloader 就相当于 BIOS。所以我们要先搞定bootloader,很庆幸,有很多现成的 bootloader 软件可以使用,比如 U-Boot、vivi、RedBoot 等等,其中以 U-Boot 使用最为广泛,为了方便书写,本书会将 U-Boot 写为 uboot。; }9 j0 U$ T5 N n( w! R5 ^2 }4 F uboot 的全称是 Universal Boot Loader,uboot 是一个遵循 GPL 协议的开源软件,uboot是一个裸机代码,可以看作是一个裸机综合例程。现在的 uboot 已经支持液晶屏、网络、USB等高级功能。如图10.1.1所示:8 C. ?. W. m1 S+ o5 M$ O ( ?* H2 R2 {# Q ![]() 图10.1.1 uboot官网 我们可以在 uboot 官网下载 uboot 源码,点击图10.1.1中左侧 Topics 中的“Source Code”,打开以后如图10.1.2所示:- e* ]; P, c& a' d( ?- | ![]() 4 L0 b8 q+ e7 Y& k9 h" A 图10.1.2 uboot源码界面 点击图10.1.2中的“FTP”,进入其 FTP 服务器即可看到 uboot 源码,如图10.1.3所示:* m" W$ a# \. u2 e3 a# \ " ?$ W0 z7 [ i. h# M% I ![]() 图10.1.3 uboot源码) i& v) X, h( W: C* B0 ` 图10.1.3中就是 uboot 原汁原味的源码文件,目前最新的版本是 2020.10。但是我们一般不会直接用 uboot 官方的 U-Boot 源码的。uboot 官方的 uboot 源码是给半导体厂商准备的,半导体厂商会下载 uboot 官方的 uboot 源码,然后将自家相应的芯片移植进去。也就是说半导体厂商会自己维护一个版本的 uboot,这个版本的 uboot 相当于是他们定制的。既然是定制的,那么肯定对自家的芯片支持会很全,虽然 uboot 官网的源码中一般也会支持他们的芯片,但是绝对是没有半导体厂商自己维护的 uboot 全面。ST提供了2020.01版本的uboot,在6.1.1小节获取ST官方系统源码中我们已经得到了ST官方uboot源码, 进入到如下目录: /stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi uboot源码如图10.1.4所示:; d- D! {. b% e4 ? j5 l+ z ![]() : h1 u/ w/ }5 n 图10.1.4 ST官方uboot源码0 @# o, w' Y% l- d6 Y' I1 O7 S7 V, l 图10.1.4中的“u-boot-stm32mp-2020.01-r0”就是ST官方uboot源码包,它支持了STM32MP1家族全系列芯片(后续ST也会一直更新,添加新的SOC进去),而且支持各种启动方式,比如EMMC、NAND 等等,这些都是 uboot 官方所不支持的。但是图10.1.4中的 uboot 是针对ST 自家评估板的,如果要在我们自己的板子上跑,那么就需要对其进行修改,使其支持我们自己做的板子,正点原子的 STM32MP157开发板就是自己做的板子,虽然大部分都参考了 ST 官方的STM32MP157 EVK开发板,但是还是有很多不同的地方,所以需要修改 ST 官方的 uboot,使其适配正点原子的 STM32MP157开发板。所以当我们拿到开发板以后,是有三种uboot 的,这三种 uboot的区别如表10.1.1所示: 种类 描述 Q& T) I6 L# I# O uboot官方的uboot代码 由uboot官方维护开发的uboot版本,版本更新快,基本包含所有常用的芯片。 半导体厂商的uboot代码 半导体厂商维护的一个uboot,专门针对自家的芯片,在对自家芯片支持上要比uboot官方的好。 开发板厂商的uboot代码 开发板厂商在半导体厂商提供的uboot基础上加入了对自家开发板的支持。 表10.1.1 三种uboot的区别 那么这三种uboot该如何选择呢?首先uboot官方的基本是不会用的,因为支持太弱了。最常用的就是半导体厂商或者开发板厂商的 uboot,如果你用的半导体厂商的评估板,那么就使用半导体厂商的 uboot,如果你是购买的第三方开发板,比如正点原子的 STM32MP157开发板,那么就使用正点原子提供的 uboot 源码(也是在半导体厂商的 uboot 上修改的)。当然了,你也可以在购买了第三方开发板以后使用半导体厂商提供的 uboot,只不过有些外设驱动可能不支持,需要自己移植,这个就是我们常说的 uboot 移植。本节是 uboot 的使用,所以就直接使用正点原子已经移植好的 uboot,这个已经放到了开发板光盘中了,路径为:开发板光盘1、程序源码1、正点原子Linux出厂系统源码u-boot-stm32mp-2020.01-gdb8d2374-v1.0.tar.bz2。 10.2 U-Boot初次编译 10.2.1 编译 首先需要在 Ubuntu 中安装一些库,否则编译uboot会报错,安装命令如下:8 H/ z0 ?% f( w o: ?3 p, i sudo apt-get install libncurses5-dev bison flex 在 Ubuntu 中创建存放 uboot 的目录,比如我这里新建了一个名为“alientek_uboot”的文件夹用于存放正点原子提供的 uboot 源码。alientek_uboot文件夹创建成功以后使用 FileZilla 软件将正点原子提供的 uboot 源码拷贝到此目录中,正点原子提供的 uboot 源码已经放到了开发板光盘中,路径为:开发板光盘1、程序源码1、正点原子Linux出厂系统源码u-boot-stm32mp-2020.01-xxxxxxxx-v1.0.tar.bz2(“xxxxxxxxx”为uboot打包时候的版本号,每次打包其版本号都不同!所以大家不要纠结于开发板光盘中的uboot源码打包版本号是否和教程里面的一致)。将stm32mp-2020.01-xxxxxxxx-v1.0.tar.bz2拷贝到前面新建的 alientek_uboot 文件夹下,完成以后如图10.2.1.1所示:3 s ?6 g4 V& Q7 P4 L% N ![]() 图10.2.1.1 正点原子出厂uboot源码' W) a0 B( Q( i 使用如下命令对其进行解压缩: tar -vxf u-boot-stm32mp-2020.01-gdb8d2374-v1.0.tar.bz2 解压完成以后如图10.2.1.2所示:- N* N! T$ I( h' w+ C 2 N1 n9 d( N% L S' R ![]() % t: o! D0 s1 Y( Q0 F 图10.2.1.2 解压后的Uboot) j/ J2 _% F; b- w) E 图10.2.1.2中除了u-boot-stm32mp-2020.01-gdb8d2374-v1.0.tar.bz2这个正点原子提供uboot源码压缩包以外,其他的文件和文件夹都是解压出来的 uboot 源码。执行以下命令,编译正点原子提供的uboot。2 w' p/ Q0 U- N$ w4 _. F$ O, N . ^0 D6 H" @& a& u2 f( l+ @+ M2 D% g6 `
上面命令每次编译的时候都要指定ARCH、CROSS_COMPILE和DEVICE_TREE,这三个含义如下: ARCH:指定所使用的平台架构,这里肯定是arm。 CROSS_COMPILE:所使用的交叉编译器前缀,本教程使用的是交叉编译器前缀为arm-none-linux-gnueabihf-。! B0 @7 z% s1 B6 g8 I7 W DEVICE_TREE:设备树文件,uboot也支持设备树,所以在编译的时候需要指定设备树文件,不同的硬件其设备树文件肯定不同,这里为stm32mp157d_atk,也就是正点原子的STM32MP157开发板对应的设备树。 编译的时候每次都输入ARCH和CROSS_COMPILE比较麻烦,为了方便起见,我们可以直接修改uboot的Makefile文件,在里面直接对ARCH和CROSS_COMPILE进行赋值,也就是直接将ARCH设置为arm,CROSS_COMPILE设置为arm-none-linux-gnueabihf-,修改完成以后如图10.2.1.3所示:& g" D; q/ k, P' ?1 P3 b' Y' D2 E ![]() - Z7 S4 e X1 u6 [ 图10.2.1.3 设置ARCH和CROSS_COMPILE值 注意!不能在Makefile里面对DEVICE_TREE进行复制,因为没用,必须在编译的时候手动输入!% u* u. F6 W$ D( Q$ u% G 设置好Makefile里面的ARCH和CROSS_COMPILE以后就可以将编译命令简化为如下所示:4 b$ N0 c9 n; ?+ b8 V+ [ 3 l+ W5 h8 Q2 x8 U# z Q8 N6 D
上述命令和前面的相比就要简洁很多,最后的“make V=1”是真正的编译命令,V=1表示编译uboot的时候输出详细的编译过程,方便我们观察uboot编译过程。直接输入“make”命令的话默认使用单线程编译,编译速度会比较慢,可以通过添加“-j”选项来使用多线程编译,比如使用8线程编译,最后的编译命令就是: make V=1 DEVICE_TREE=stm32mp157d-atk all -j8 //8线程编译 uboot编译完成如图10.2.1.4所示:; C' e( A5 r+ u! _ H9 F3 l3 }1 m ^) k2 |! ] ![]() 图10.2.1.4 uboot编译成功) Q5 D, S. z. Y 编译完成以后的 就会在uboot源码目录下生成相应的镜像文件,如图10.2.1.5所示:* L! E' X, G7 Z6 v# k l; o: A4 T V. j; s) p2 ~ T ![]() 图10.2.1.5 编译后生成的uboot可执行文件 可以看出,编译完成以后 uboot 源码多了一些文件,重点是u-boot.bin和u-boot.stm32这两个文件。u-boot.bin是uboot的二进制可执行文件,u-boot.stm32是在u-boot.bin前面添加了256个字节头部信息。STM32MP1内部ROM代码和TF-A在运行uboot的时候要求前面添加头部信息,所以这就是为什么uboot也有这个头部信息的原因。) P6 [! v3 {2 E5 r" E 10.2.2 烧写 使用STM32CubeProgrammer将上面编译出来的u-boot.stm32镜像烧写到开发板的EMMC里面,修改前面创建的tf-a.tsv文件,添加uboot烧写指令(其实在9.3.2小节已经讲过了),在最后面添加下面这行:- T( @& o7 _' p& ^ 示例代码10.2.2.1 uboot烧写指令 P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32 修改以后的tf-a.tsv如图10.2.2.1所示:. Q$ [' `$ H% c ![]() 图10.2.2.1 修改后的tf-a.tsv- o: C7 C* u9 r! l1 C 最后将上一小节编译出来的u-boot.stm32,拷贝到前面创建的images目录下(在做TF-A实验的就有u-boot.stm32这个文件,我们只要替换就行)。: a9 U' E! a5 e. e3 x 一切准备就绪以后就可以使用STM32CubeProgrammer软件通过USB OTG将uboot烧写到开发板上的EMMC里面,等到烧写完成。完成以后设置开发板上的拨码开关,设置从EMMC启动,然后用USB Type-C线将开发板上的USB_TTL接口与电脑连接起来,因为我们要在串口终端里面输入命令来操作uboot。 打开MobaXterm,设置好串口参数,最后复位开发板。在 MobaXterm 上出现“Hit any key tostop autoboot: ”倒计时的时候按下键盘上的回车键,默认是 1 秒倒计时,在 1 秒倒计时结束以后如果没有按下回车键的话 uboot 就会使用默认参数来启动 Linux 内核了(如果内核存在的话,如果Linux内核不存在那么就会进入到uboot的命令行模式)。如果在 1 秒倒计时结束之前按下回车键,那么就会进入 uboot 的命令行模式,如图10.2.2.2所示:4 A- D) i4 H4 L ![]() 图10.2.2.2 uboot启动log信息9 i9 S6 G$ x% @4 v6 N3 q0 Y+ }' O 从图10.2.2.2可以看出,当进入到 uboot 的命令行模式以后,左侧会出现一个“STM32MP=>”标志。uboot 启动的时候会输出一些信息,这些信息如下所示:
简单讲解一下uboot启动过程的log信息: 第 1 行是 uboot 版本号和编译时间,可以看出,当前的 uboot 版本号是 2020.01,编译时间是 2020 年 11月 24 日 17: 17。 第3行是CPU的信息,可以看出CPU型号为STM32MP157DAA。& q) O9 {! K6 X% Q" H 第4行是板子信息,当前板子是ST公司的STM32MP157D eval开发板,这个信息是可以改的,因为正点原子是直接参考ST公司的EVK开发板移植的uboot,所以这部分信息也就没改。 第5行是板子的一些信息,比如工作在trusted模式下。2 w* J3 J" F. P- K, a+ U( D 第6行是DDR的大小为1GB。 第7~12行它们的频率分别为,MPU频率、MCU频率、A**线频率、PER的频率、DDR频率。 第13行是看门狗信息,喂狗时间为32s。4 @* G$ N& g# H 第14行是NAND的大小,因为正点原子的STM32MP157开发板没有NAND,所以这里就是0MB。 第15行是板子上MMC设备,一共有两个,SD/MMC0 (SD卡)和SD/MMC1 (EMMC)。5 y: b d* f+ B" O 第16行是从MMC里获取环境变量。 第17~19行是标准输入、标准输出和标准错误所使用的终端,这里都使用串口(serial)作为终端。 第20~23行是网络相关信息,网络的MAC地址从OTP里获取,因为我们的OTP没有设置MAC地址,所以就获取失败。这里的网络是可以用的,只是因为没有MAC地址所以提示没有找到网络,可以自行添加相关环境变量来设置MAC地址,后面会讲如何设置。; B, X9 J+ v) I 第 25 行是倒计时提示,默认倒计时 1 秒,倒计时结束之前按下回车键就会进入 Linux 命令行模式。如果在倒计时结束以后没有按下回车键,那么 Linux 内核就会启动,Linux 内核一旦启动,uboot 就会寿终正寝。 uboot的主要作用是引导kernel,我们现在已经进入 uboot 的命令行模式了,进入命令行模式以后就可以给 uboot 发号施令了。当然了,不能随便发号施令,得看看 uboot 支持哪些命令,然后使用这些uboot 所支持的命令来做一些工作,下一节就讲解 uboot 命令的使用。 10.3 U-Boot命令使用0 \, Z% ~) a7 W* ^# ^" o( n 进入uboot的命令行模式以后输入“help”或者“?”,然后按下回车即可查看当前uboot所支持的命令,如图10.3.1所示:3 T( r' |8 m" Q+ w( d: r! X, v - X/ ?$ m0 A/ B9 n- Z4 e, K ![]() 图10.3.1 uboot的命令列表(部分)* ~4 Y5 [! e B" k 图10.3.1中只是 uboot 的一部分命令,具体的命令列表以实际为准。图10.3.1中的命令并不是 uboot 所支持的所有命令,说过 uboot 是可配置的,需要什么命令就使能什么命令。所以图10.3.1中的命令是正点原子提供的 uboot 中使能的命令,uboot 支持的命令还有很多,而且也可以在 uboot 中自定义命令。这些命令后面都跟有命令说明,用于描述此命令的作用,但是命令具体怎么用呢?我们输入“help(或?) 命令名”既可以查看命令的详细用法,以“bootz”这个命令为例,我们输入如下命令即可查看“bootz”这个命令的用法: ? bootz 或 help bootz 结果如图10.3.2所示:) z) r* H; E0 V( Z( H3 U$ z. n" b ! ?3 v4 }; n2 q7 e: r( G ![]() 7 G3 w; e( H/ S! c 图10.3.2 bootz 命令使用说明7 j" _- B8 c, W6 d/ D 图10.3.2列出了“bootz”这个命令的详细说明,其它的命令也可以使用此方法查询具体的使用方法。接下来我们学习一下一些常用的 uboot 命令。 10.3.1 查询命令. W* y8 n( d- T( d' N 常用的和信息查询有关的命令有 3 个:bdinfo、printenv 和 version。先来看一下 bdinfo 命令,此命令用于查看板子信息,直接输入“bdinfo”即可,结果如图10.3.1.1示:9 `7 o+ _8 k5 x + ]: s% A6 i: Y3 T2 a ![]() 6 v& e; {8 r( O' h6 } 图10.3.1.1 bdinfo 命令5 I/ w9 s- ?1 A 从图10.3.1.1中可以看出 DRAM 的起始地址和大小、BOOT参数保存起始地址、波特率、sp(堆栈指针)起始地址等信息。命令“printenv”用于输出环境变量信息,uboot 也支持 TAB 键自动补全功能,输入“print”然后按下 TAB 键就会自动补全命令。直接输入“print”也可以,因为整个uboot命令中只有printenv的前缀是“print”,所以当输入print以后就只有printenv命令了。输入“print”,然后按下回车键,环境变量如图10.3.1.2所示: ![]() 6 j$ s0 `7 ^7 F& Q9 ] 图10.3.1.2 printenv 命令部分结果 图10.3.1.2只是printenv命令的部分内容,STM32MP1系列的环境变量有很多,比如 baudrate、board、board_name、boot_device、bootcmd、bootdelay等等。uboot 中的环境变量都是字符串,既然叫做环境变量,那么它的作用就和“变量”一样。比如 bootdelay 这个环境变量就表示 uboot 启动延时时间,默认 bootdelay=1,也就默认延时 1秒。前面说的 1 秒倒计时就是由 bootdelay 定义的,如果将 bootdelay 改为 5 的话就会倒计时 5s了。uboot 中的环境变量是可以修改的,有专门的命令来修改环境变量的值,稍后我们会讲解。7 {$ P, F# b3 |- f 命令 version 用于查看 uboot 的版本号,输入“version”,uboot 版本号如图10.3.1.3所示: ![]() ( X4 O. U5 a0 i& M 图10.3.1.3 version命令结果 ————————————————8 M: R# V. I. p: z 版权声明:正点原子1 I [0 g% E6 ?- t% S , _) F' C1 Q. d; R! m 1 ]/ T! z9 E! A& ^1 H" y9 s6 V |
基于STM32MP1和STM32MP2在嵌入式Linux平台上部署有效的安全保护机制
利用STM32MP1和STM32MP2为嵌入式Linux提供有效的安全措施:供当今决策者参考的3条宝贵经验
STM32MP1 WiFi连接
【STM32MP157】从ST官方例程中分析RPMsg-TTY/SDB核间通信的使用方法
【STM32MPU 安全启动】 TF-A BL2 TrustedBoot原理学习
《STM32MPU安全启动》学**结
《STM32MPU安全启动》学习笔记之optee 如何加载CORTEX-M核和使能校验
《STM32MPU安全启动》学习笔记之TF-A BL2校验optee和uboot的流程以及如何使能
《STM32MPU 安全启动》课程学习心得+开启一扇通往嵌入式系统安全领域深处的大门。
《STM32MPU安全启动》 课程学习心得