本帖最后由 正点原子运营 于 2024-2-22 17:06 编辑
第十三章 Linux内核移植
1)实验平台:正点原子 DFZU2EG_4EV MPSoC开发板
2) 章节摘自【正点原子】DFZU2EG_4EV MPSoC开发板之嵌入式Linux 驱动开发指南 V1.0
6)Linux技术交流QQ群:887820935
前面章节我们简单了解了一下Linux内核顶层Makefile和Linux内核的启动流程,本章我们就来学习一下如何将Xilinx官方提供的Linux内核移植到正点原子的MPSoc开发板上。需要说明的是当我们使用Petalinux工具的时候是不需要移植内核的,因为Petalinux工具可以根据硬件描述文件xsa使能相应配置。本章讲解内核移植(更准确的说是内核适配)是为了了解一般情况下(不使用Petalinux)的内核移植过程。通过本章的学习,我们将掌握如何将半导体厂商提供的Linux BSP包移植到我们自己的平台上。
1.1 Linux内核获取关于Linux的起源以及发展历史,网上相关的介绍太多了,这里不作过多介绍。Linux由Linux基金会管理与发布,Linux官网为https://www.kernel.org,所以你想获取最新的Linux版本就可以在这个网站上下载,网站界面如下图所示: 从上图可以看出最新的稳定版Linux已经到了5.17.9,大家没必要追新,因为4.x版本的Linux和5.x版本没有本质上的区别,5.x更多的是加入了一些新的平台、新的外设驱动而已。 Xilinx会从https://www.kernel.org下载某个版本的Linux内核,然后将其移植到自己的芯片平台上,测试成功以后就会将其开放给Xilinx的芯片平台开发者。开发者下载Xilinx提供的Linux内核,然后将其移植到自己的产品上。后面的移植我们使用Xilinx提供的Linux源码,Xilinx提供的Linux内核源码发布在https://github.com/Xilinx/linux-xlnx,可以clone或下载,注意要与Petalinux版本一致,否则会出现一些问题,我们使用的是2019.2版本的Petalinux,所以选择的linux内核源码要带2019.2(Tags带2019.2)。不过我们不从上面的github网站下载,因为在6.3.5节配置Linux内核时,Petalinux工具就已经生成了linux内核源码,如下图所示,所以没有必要从github网站下载。 后面的linux内核移植和驱动开发都需要使用该源码,为了方便访问和备份(版本管理),我们将Petalinux生成的linux内核源码拷贝到12.1.1节建立的git.d文件夹下,如下图所示: 图 13.1.3拷贝linux内核源码到git.d目录 1.2 Petalinux使用外部linux内核源码上一节我们将Petalinux生成的内核源码移动到~/git.d/linux-xlnx目录(绝对路径/home/shang/git.d/linux-xlnx),以后我们在该内核源码上移植修改、添加驱动等,Petalinux工程都无法使用该内核源码了,如何让Petalinux能访问使用呢? 方法如下: 1. 进入到Petalinux工程目录下,设置好Petalinux工作环境后,输入“petalinux-config”命令配置Petalinux工程。 设置Linux Components Selection --->linux-kernel (linux-xlnx) --->为“ext-local-src”,如下图所示: 该配置项将linux来源配置为外部的本地源。设置好后按回车键返回。设置External linux-kernel local source settings ---> External linux-kernellocal source path (NEW)为“/home/shang/git.d/linux-xlnx”,也就是当前内核源码存放的目录,结果如下图所示: 图 13.2.2配置External linux-kernel local sourcepath 保存配置并退出,现在该Petalinux工程就可以访问和使用/home/ shang /git.d/linux-xlnx中的内核源码了。 需要注意的一点是在Petalinux工程配置linux内核和编译时需要先清理/home/ shang /git.d/linux-xlnx中的内核(命令 make distclean),否则配置和编译会报错(12.2节外部uboot源码也要清理)。 1.3 Linux内核编译初次编译我们在13.1小节中将Petalinux生成的linux内核源码放到了git.d文件夹下。现在进入到该内核源码目录处,查看内核目录结构,命令如下: - cd ~/git.d/linux-xlnx/
- ls
复制代码可以看到Linux源码根目录如下图所示: 其中oe-logs和oe-workdir是Petalinux工具生成的链接目录,不是linux内核的源码目录。 现在我们讲解一下如何编译出对应的Linux镜像文件。新建名为“zynqmp.sh”的shell脚本,然后在这个shell脚本里面输入如下所示内容: - 示例代码 zynqmp.sh文件内容
- #!/bin/sh
- make distclean
- make xilinx_zynqmp_defconfig
- unset PKG_CONFIG_PATH
- make menuconfig
- make -j8
复制代码 第2行,执行“make distclean”,清理工程,所以zynqmp.sh每次都会清理一下工程。如果通过图形界面配置了Linux,但是还没保存新的配置文件,那么就要慎重使用zynqmp.sh编译脚本了,因为它会把你的配置信息都删除掉。 第3行,执行“make xxx_defconfig”,配置工程。该配置文件在/home/shang/git.d/linux-xlnx/arch/arm64/configs路径下。 第4行,执行“unset PKG_CONFIG_PATH”,取消环境变量PKG_CONFIG_PATH。打开图形配置界面需要先取消该环境变量,否则有问题。 第5行,执行“make menuconfig”,打开图形配置界面,对Linux进行配置,如果不想每次编译都打开图形配置界面的话可以将这一行删除掉。 第6行,执行“make”,编译Linux源码。如果读者ubuntu虚拟机使用的是多核处理器,可以在make命令后加参数“-jn”来加快编译,其中n表示处理器核数,笔者虚拟机是8核,所以这里参数为“-j8”。 可以看出,Linux的编译过程基本和uboot一样,都要先执行“make xxx_defconfig”来配置一下,然后再执行“make”进行编译。如果需要使用图形界面配置的话就执行“make menuconfig”。 使用chmod给予zynqmp.sh可执行权限,然后运行此shell脚本,命令如下: - chmod 777 zynqmp.sh
- ./zynqmp.sh
复制代码编译的时候会弹出Linux图形配置界面,如下图所示: Linux的图行界面配置和uboot是一样的,这里我们不需要做任何的配置,直接按两下ESC键退出,退出图形界面以后会自动开始编译Linux。等待编译完成,完成以后如下图所示: 编译完成以后就会在arch/arm64/boot这个目录下生成一个叫做Image的文件,如下图所示: Image就是我们要用的Linux内核镜像文件。Image.gz文件是Image文件的压缩文件,可以用uboot的bootz命令启动,不过Xilinx不用该文件。 另外也会在arch/arm64/boot/dts/xilinx下生成很多.dtb文件,这些.dtb就是设备树文件,比如zynqmp-zcu102-rev1.0.dtb文件就是xilinx zcu102开发板对应的设备树文件。 1.4 Linux内核源码工程目录分析我们在13.1节获取的linux内核源码目录如下图所示: 上图是petalinux生成的未编译的Linux源码目录文件,我们在分析Linux之前一定要先在Ubuntu中编译一下Linux,因为编译过程会生成一些文件,而生成的这些恰恰是分析Linux不可或缺的文件。编译后的Linux目录如下图所示: 上图中重要的文件夹或文件的含义如下表所示: 上表中的很多文件夹和文件我们都不需要去关心,我们要关注的文件夹或文件如下: 1、arch目录 这个目录是和架构有关的目录,比如arm、arm64、avr32、x86等等架构。每种架构都对应一个目录,在这些目录中又有很多子目录,比如boot、common、configs等等,以arch/arm64为例,其子目录如下图所示: 上图是arch/arm64的子目录,这些子目录用于控制系统引导、系统调用、动态调频、主频设置等。arch/arm64/configs目录是不同平台的默认配置文件:xxx_defconfig,如下图所示: 可以看到,总共有3个defconfig文件,其中两个以xilinx开头的都是用于Xilinx厂商soc系列的配置文件。xilinx_zynqmp_defconfig属于ZynqUltraScale+ MPSoC系列平台的通用默认配置文件,xilinx_versal_defconfig应该属于Versal系列平台的通用默认配置文件。执行“make xilinx_zynqmp_defconfig”即可完成配置。 arch/arm64/boot/dts/xilinx/目录里面是对应开发平台的设备树文件,xilinx zcu102开发板对应的设备树文件如下图所示: 图 13.4.5正点原子DFZU2EG_4EV MPSoC开发板对应的设备树 其中zynqmp-zcu102-rev1.0.dts为zcu102开发板1.0版本的设备树文件,编译后的设备树镜像文件为zynqmp-zcu102-rev1.0.dtb。 arch/arm64/boot目录中有编译出来的Image镜像文件,而Image就是我们要用的linux镜像文件。 arch/arm/mach-xxx目录分别为相应平台的驱动和初始化文件,比如mach-zynq目录里面就是ZYNQ 系列CPU的驱动和初始化文件。 2、block目录 block是Linux下块设备目录,像SD卡、eMMC、NAND、硬盘等存储设备就属于块设备,block目录中存放着管理块设备的相关文件。 3、crypto目录 crypto目录里面存放着加密文件,比如常见的crc、crc32、md4、md5、hash等加密算法。 4、Documentation目录 此目录里面存放着Linux相关的文档,如果要想了解Linux某个功能模块或驱动架构的功能,就可以在Documentation目录中查找有没有对应的文档。 5、drivers目录 设备驱动程序目录,此目录根据驱动类型的不同,分门别类进行整理,比如drivers/i2c就是I2C相关驱动目录,drivers/gpio就是GPIO相关的驱动目录,这是我们学习的重点。 6、firmware目录 此目录用于存放固件。 7、fs目录 此目录存放文件系统相关代码,比如fs/ext2、fs/ext4、fs/f2fs等,分别是ext2、ext4和f2fs等文件系统。 8、include目录 头文件目录。与系统相关的头文件被放置在内核 include/linux子目录下。 9、init目录 此目录存放Linux内核启动的时候初始化代码。 10、ipc目录 IPC为进程间通信,ipc目录是进程间通信的具体实现代码。 11、kernel目录 Linux内核代码。与平台相关的部分代码放在arch/*/kernel目录下,其中*代表各种处理器平台 12、lib目录 lib是库的意思,lib目录都是一些公用的库函数。 13、mm目录 此目录存放与平台无关的内存管理代码,与平台相关的内存管理代码放在arch/*/mm目录下。 14、net目录 此目录存放网络相关代码。 15、samples目录 此目录存放一些示例代码文件。 16、scripts目录 脚本目录,Linux编译的时候会用到很多脚本文件,这些脚本文件就保存在此目录中。 17、security目录 此目录存放安全相关的文件。 18、sound目录 此目录存放音频相关驱动文件,音频驱动文件并没有存放到drivers目录中,而是单独的目录。 19、tools目录 此目录存放一些编译的时候使用到的工具。 20、usr目录 此目录存放与initramfs有关的代码。 21、virt目录 此目录存放虚拟机相关文件。 22、.config文件 根uboot一样,.config保存着Linux最终的配置信息,编译Linux的时候会读取此文件中的配置信息。最终根据配置信息来选择编译Linux哪些模块,哪些功能。 23、Kbuild文件 有些Makefile会读取此文件。 24、Kconfig文件 图形化配置界面的配置文件。 25、Makefile文件 Linux顶层Makefile文件,建议好好阅读一下此文件。 26、README文件 此文件详细讲解了如何编译Linux源码,以及Linux源码的目录信息,建议仔细阅读一下此文件。 1.5 移植准备工作从本小节开始,我们对官方linux内核进行移植,使其能在正点原子MPSoC开发板上启动并正常工作。 进入到13.1节创建的linux内核源码目录~/git.d/linux-xlnx,输入如下命令清理linux内核源码: 初次移植不知道该添加哪些文件的时候,最好的方法就是看看别的开发板是怎么添加的,我们以Xilinx的ZCU102开发板为例,看看内核源码中有哪些文件或文件夹与ZCU102开发板有关。 输入如下命令,根据文件名称或文件夹名称,查找与ZCU102开发板有关的文件或文件夹: 结果如下图所示: 然后搜索内容中带有zcu102字样的文件,命令如下: - grep -irn --exclude-dir=.git "zcu102"
复制代码结果如下图所示: 由于Documentation文件夹是说明文档,不编译进内核,剩下的就是arch/arm64/boot/dts/xilinx目录下的Makefile和设备树dts文件了。 下面开始移植。
1.6 移植步骤
1.6.1 添加开发板默认配置文件编译内核之前需要先配置内核,配置内核用的文件为开发板的默认内核配置文件。开发板的默认内核配置文件在内核源码的arch/<ARCH>/configs目录下,ARCH对应开发板使用的芯片架构,对于我们使用的MPSoC开发板而言,ARCH为arm64。在添加之前先看下arch/arm64/configs目录下arm64架构不同平台的默认配置文件,如下图所示: 可以看到,总共有3个defconfig文件,其中两个以xilinx开头的都是用于Xilinx厂商soc系列的配置文件。前面说过,xilinx_zynqmp_defconfig是用于Zynq UltraScale+ MPSoc系列平台的通用默认配置文件,为了保持一致,我们依旧使用xilinx_zynqmp_defconfig作为开发板的默认配置文件。不过呢,我们还是可以修改xilinx_zynqmp_defconfig的。要想修改配置文件,首先得知道配置项的含义,如果直接打开xilinx_zynqmp_defconfig文件来修改的话,移除配置项到还可以,添加的话,就无从谈起了,所以我们得在图形配置界面修改配置项。此处我们就不修改了,保持默认的配置即可。 可以使用如下命令来配置正点原子MPSoC开发板对应的linux内核: - make xilinx_zynqmp_defconfig
复制代码 1.6.2 添加开发板对应的设备树文件Linux支持设备树,每个开发板都有对应的设备树文件。Xilinx的Zynq UltraScale+ MPSoc系列芯片的所有设备树文件都存放在arch/arm64/boot/dts/xilinx目录下,如下图所示: 图 13.6.2 ZynqUltraScale+ MPSoc系列芯片的所有设备树文件 其中zynqmp.dtsi、zynqmp-clk.dtsi和zynqmp-clk-ccf.dtsi设备树文件是Zynq UltraScale+ MPSoc系列芯片通用的基础设备树文件,我们在12.4.4小节有介绍。Makefile用于设置哪些设备树文件将被编译,其内容如下图所示: 当编译linux内核源码时,这些设备树文件也会默认编译,如果不想编译其中的某些设备树文件,可以删除或注释相应行。 不同的开发板有不同的设备树文件,我们自己的开发板当然得用我们自己的设备树文件。设备树文件从哪来,可以参考其他开发板的设备树文件,然后与自己的开发板对比,手动编写,不过这样做工作量太大,没什么意义,除非迫不得已,否则不推荐这种方法。最简便直接的方法是用Petalinux工具生成的设备树文件。Petalinux工具会根据我们提供的开发板xsa文件自动生成相应的设备树文件,生成的设备树文件在Petalinux工程(第六章Petalinux设计流程实战章节建立的Petalinux工程)的components/plnx_workspace/device-tree/device-tree目录下,如下图所示: 图 13.6.4 Petalinux生成的设备树文件 后缀为dtsi和dts的都是设备树文件,这些设备树文件都是Petalinux根据xsa自动生成的。关于这些设备树文件的含义在前面移植uboot的时候已经讲解过了。 要想在linux内核源码中添加开发板的设备树文件,可以将system-top.dts文件及其依赖文件添加到linux内核源码中。打开system-top.dts文件,其内容如下图所示: 图 13.6.5 system-top.dts文件的内容 可以看到总共include五个设备树文件,其中zynqmp.dtsi和zynqmp-clk-ccf.dtsi是通用文件,不用添加,剩下的pcw.dtsi、pl.dtsi和system-user.dtsi需要添加。 进入到第六章创建的Petalinux工程的components/plnx_workspace/device-tree/device-tree目录下,然后输入如下命令将设备树文件复制到linux内核源码相应目录: - cp pcw.dtsi pl.dtsi~/git.d/linux-xlnx/arch/arm64/boot/dts/xilinx/
- cp system-top.dts ~/git.d/linux-xlnx/arch/arm64/boot/dts/xilinx/
复制代码其中system-top.dts设备树文件是我们开发板的默认设备树文件。 然后切换到project-spec/meta-user/recipes-bsp/device-tree/files/目录下,将设备树文件system-user.dtsi复制到linux内核源码相应目录: - cp system-user.dtsi ~/git.d/linux-xlnx/arch/arm64/boot/dts/xilinx/
复制代码system-user.dtsi是用户设备树文件。为了方便管理,我们一般配置这个设备树文件添加外设。 复制结果如下图所示: 添加完开发板的设备树文件后,还需要进行相应的修改才可以使用。 进入到linux内核源码的arch/arm64/boot/dts/xilinx/目录下,编辑system-user.dtsi文件,修改前共有119行,内容如下: - 1 /include/ "system-conf.dtsi"
- 2 #include<dt-bindings/gpio/gpio.h>
- 3 #include <dt-bindings/input/input.h>
- 4
- 5 / {
- 6 model = "Alientek Zynq MpSocDevelopment Board";
- 7
- 8 leds {
- 9 compatible = "gpio-leds";
- 10
- 11 gpio-led0 {
- 12 label = "ps_led1";
- 13 gpios = <&gpio 38GPIO_ACTIVE_HIGH>;
- 14 linux,default-trigger ="timer";
- 15 };
- 16
- 17 gpio-led1 {
- 18 label = "ps_led2";
- 19 gpios = <&gpio 39GPIO_ACTIVE_HIGH>;
- 20 default-state = "on";
- 21 };
- 22
- 23 gpio-led2 {
- 24 label = "pl_led1";
- 25 gpios = <&axi_gpio_0 0 0 GPIO_ACTIVE_HIGH>;
- 26 linux,default-trigger ="timer";
- 27 };
- 28
- 29 gpio-led3 {
- 30 label = "pl_led2";
- 31 gpios = <&axi_gpio_0 1 0GPIO_ACTIVE_HIGH>;
- 32 default-state = "on";
- 33 };
- 34 };
- 35
- 36 keys {
- 37 compatible = "gpio-keys";
- …
- …
- …
- 97 &sdhci1 {
- 98 disable-wp;
- 99 no-1-8-v;
- 100 };
- 101
- 102 &i2c1 {
- 103 clock-frequency = <400000>;
- 104
- 105 eeprom@50 {
- 106 compatible = "24c64";
- 107 reg = <0x50>;
- 108 pagesize = <32>;
- 109 };
- 110 };
- 111
- 112 &dwc3_0 {
- 113 dr_mode = "host";
- 114 maximum-speed = "super-speed";
- 115 };
- 116
- 117 &usb0 {
- 118 dr_mode = "host";
- 119 };
复制代码修改后的内容如下: - 1 #include <dt-bindings/gpio/gpio.h>
- 2#include<dt-bindings/input/input.h>
- 3
- 4 / {
- 5 model = "Alientek Zynq MpSocDevelopment Board";
- 6 compatible = "xlnx,zynqmp-atk","xlnx,zynqmp";
- 7 };
- 8
- 9 &gem3 {
- 10 phy-handle = <ðernet_phy>;
- 11 local-mac-address = [00 0a 35 00 1e 53];
- 12
- 13 ethernet_phy: ethernet-phy@7 {
- 14 reg = <0x7>;
- 15 };
- 16};
- 17
- 18 &gem0 {
- 19 psu_ethernet_0_mdio: mdio {
- 20 #address-cells = <1>;
- 21 #size-cells = <0>;
- 22 phy1:phy@4 {
- 23 reg = <0x4>; /* YT8521 phy address */
- 24 };
- 25 gmii_to_rgmii_0: gmii_to_rgmii_0@0 {
- 26 compatible ="xlnx,gmii-to-rgmii-1.0";
- 27 phy-handle =<&phy1>;
- 28 reg = <0>;
- 29 };
- 30 };
- 31 };
- 32
- 33 &sdhci0 {
- 34 mmc-hs200-1_8v;
- 35 bus-width =<0x8>;
- 36 non-removable;
- 37 };
- 38
- 39 &sdhci1 {
- 40 disable-wp;
- 41 no-1-8-v;
- 42 };
- 43
- 44 &dwc3_0 {
- 45 dr_mode ="host";
- 46 maximum-speed = "super-speed";
- 47 };
- 48
- 49 &usb0 {
- 50 dr_mode = "host";
- 51 };
复制代码删除了原文件第一行的“/include/"system-conf.dtsi"”,在第6行添加了“compatible ="xlnx,zynqmp-atk", "xlnx,zynqmp";”。 删除第8行至第64行根节点下leds和keys两个节点,这两个节点在后面驱动章节中用到的时候再添加。 删除第102行至第110行iic节点。 gem3是ps端网口,gem0是pl端网口,sdhci0和sdhci1分别是emmc和sd卡接口,dwc3_0和usb0分别是usb3.0接口和usb2.0接口。上面这6个节点我们保留。 修改完设备树后,还需要在arch/arm64/boot/dts/xilinx目录中的Makefile文件中添加开发板的设备树文件。添加到Makefile中的设备树文件在编译内核的时候会自动编译。 打开arch/arm64/boot/dts/xilinx/Makefile文件,添加行“dtb-$(CONFIG_ARCH_ZYNQMP)+= system-top.dtb”,如下图所示: 可以看到像zc1232、zc1254、zc1751、zcu100、zcu102、zcu104、zcu106、zcu113、zcu1275、zcu1285这些设备树我们没有用到,可以直接删除,删除后的Makefile内容如下图所示: 这样编译linux内核的时候就可以从system-top.dts编译成system-top.dtb文件了。到此为止,MPSoC开发板就已经添加到linux内核源码中了。 在linux内核源码目录中输入“git status”命令,可以看到移植过程中,我们修改了哪些文件,如下图所示: 如果后面测试的时候只修改设备树文件的话可只重新编译设备树,在linux内核源码根目录下输入如下命令编译设备树: 命令“make dtbs”只编译设备树文件,也就是将.dts编译为.dtb,编译完成以后就可以使用新的设备树文件。 1.6.3 Linux内核编译与测试经过前两个小节,我们已经在Linux内核里面添加了正点原子MPSoC开发板的配置,接下接进行编译测试。在终端中输入如下命令配置编译linux内核源码: - make distclean
- make xilinx_zynqmp_defconfig
- make -j8
复制代码第1行,清理工程。 第2行,使用默认配置文件xilinx_zynqmp_defconfig来配置Linux内核。 第3行,编译Linux。参数“-j8”表示处理器使用8核来运行编译,读者可根据自己电脑配置自行设置此参数。 编译完成以后就会在目录arch/arm64/boot下生成Image镜像文件(Image.gz是Image镜像文件的压缩文件),在arch/arm64/boot/dts/xilinx目录下生成system-top.dtb文件,如图 13.6.10和图 13.6.11所示。 图13.6.11生成system-top.dtb文件 将/tftpboot目录下原有的Image镜像文件删除,重新复制编译生成的Image文件和system-top.dtb文件到/tftpboot目录下,如下图所示: 拷贝完成以后就可以测试了。将开发板启动模式调为JTAG模式,开发板连接下载器,电脑连接开发板的usb_uart接口,用网线连接PS端网口和电脑,最后连接开发板电源。 开发板硬件连接好后,打开虚拟机,按照图 12.3.4所示将jtag下载器连接到虚拟机内,进入到工程ALIENTEK-ZYNQ路径下,输入“sptl”命令设置环境变量,然后使用“petalinux-boot--jtag --fpga --u-boot”命令下载并启动uboot。同时观察串口终端软件上的打印信息,注意在倒计时结束前按回车键进入uboot模式,如下图所示: 进入uboot模式后输入如下命令设置网络环境变量: - setenv ipaddr 192.168.2.22
- setenv ethaddr 00:0a:35:00:1e:53
- setenv gatewayip 192.168.2.1
- setenv netmask 255.255.255.0
- setenv serverip 192.168.2.21
复制代码然后输入如下命令将Image和system-top.dtb下载到开发板并启动: - tftpboot 0x200000 Image
- tftpboot 0x100000 system-top.dtb
- booti 0x200000 - 0x100000
复制代码结果如下图所示: 图 13.6.14 uboot模式下启动linux内核 出现上图所示内容就表示Linux内核启动成功,说明我们已经在Xilinx提供的Linux内核源码中成功添加了正点原子MPSoC开发板。 1.7 根文件系统缺失错误在上一小节打印信息的最后,出现如下图所示的信息: 在上图中最后会有下面这一行: - end Kernel panic - notsyncing: VFS: Unable to mount root fs on unknown-block(0,0)
复制代码也就是提示内核崩溃,因为根文件系统目录不存在,VFS(虚拟文件系统)不能挂载根文件系统。即使根文件系统目录存在,如果根文件系统目录里面是空的依旧会提示内核崩溃。这个就是根文件系统缺失导致的内核崩溃。但是内核是启动了的,只是根文件系统不存在而已。 1.8 image.ub的来源从前面章节中我们知道,编译linux内核后得到的是Image镜像文件和dtb设备树文件,而我们在前面uboot移植章节使用uboot启动linux的时候使用的是image.ub镜像文件,那么image.ub文件是怎么产生的呢,它和Image文件、设备树文件有什么关系?是否一定需要image.ub文件才能启动内核呢? 在12.6节uboot启动Linux测试中我们使用了image.ub文件,在13.6.3节Linux内核编译与测试中,我们使用Image和设备树文件启动linux,结果是都可以正常启动linux,说明启动linux内核并不一定需要image.ub文件,而且从中我们也可以得出一个信息,image.ub文件一定是包含Image文件和设备树文件信息的。接下来,我们来探索下image.ub的来源。 既然image.ub文件包含Image文件和设备树文件信息,那么image.ub文件一定是由某个工具打包制作而得到的,常用的镜像制作工具是mkimage。mkimage工具位于u-boot-xlnx/tools目录下,初次使用前,要把mkimage文件复制到系统可执行命令文件夹内(也就是/usr/bin/),如下图所示: 我们先用mkimage来分析image.ub文件(命令mkimage -l images/linux/image.ub),结果如图 13.8.2所示。从显示的内容来看,image.ub确实是包括linux内核镜像和设备树的,另外从“FITdescription”的信息来看,image.ub文件是U-Boot fitImage。现在我们根据“FIT description”的信息来搜索哪个文件包含该内容,搜索结果如图 13.8.3所示。 可见包含该内容的文件不少。大致的看了一下以上文件,以“.its”结尾的文件是由run.do_assemble_fitimage_initramfs*文件生成的。我们打开build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/linux-xlnx-5.4+git999/fit-image.its文件,内容如下: - /dts-v1/;
- / {
- description = "U-Boot fitImagefor PetaLinux/5.4+git999/zynqmp-generic";
- #address-cells = <1>;
- images {
- kernel@1 {
- description = "Linuxkernel";
- data = /incbin/("linux.bin");
- type = "kernel";
- arch = "arm64";
- os = "linux";
- compression = "gzip";
- load = <0x80000>;
- entry = <0x80000>;
- hash@1 {
- algo = "sha256";
- };
- };
- fdt@system-top.dtb {
- description = "FlattenedDevice Tree blob";
- data = /incbin/("/home/cx/workspace/petalinux/ALIENTEK-ZYNQ/build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/recipe-sysroot/boot/devicetree/system-top.dtb");
- type = "flat_dt";
- arch = "arm64";
- compression = "none";
-
- hash@1 {
- algo = "sha256";
- };
- };
- };
- configurations {
- default = "conf@system-top.dtb";
- conf@system-top.dtb {
- description = "1Linux kernel, FDT blob";
- kernel = "kernel@1";
- fdt = "fdt@system-top.dtb";
-
-
- hash@1 {
- algo = "sha256";
- };
- };
- };
- };
复制代码可以看出该文件的内容与我们使用“mkimage -l images/linux/image.ub”命令得到的信息基本一致。另外,从该文件内容可以看到镜像的kernel来源于linux.bin,而设备树来源于工程目录下的build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/recipe-sysroot/boot/devicetree/system-top.dtb。从build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/temp/run.do_assemble_fitimage.22866是由vmlinux生成的。其实我们也可以用Image来代替linux.bin,下面我们使用Image和zynqmp-atk.dtb生成image.ub。 将build/tmp/work/zynqmp_generic-xilinx-linux/linux-xlnx/5.4+git999-r0/linux-xlnx-5.4+git999/fit-image.its文件复制到linux内核源码根目录下,也就是“~/git.d/linux-xlnx/”目录下,然后修改相应的内容,修改后的fit-image.its文件内容如下: - /dts-v1/;
- / {
- description = "U-BootfitImage for Alientek ZYNQ MPSoc";
- #address-cells = <1>;
- images {
- kernel-1 {
- description = "Linuxkernel";
- data = /incbin/("arch/arm64/boot/Image");
- type = "kernel";
- arch = "arm64";
- os = "linux";
- compression = "none";
- load = <0x80000>;
- entry = <0x80000>;
- hash-1 {
- algo = "sha256";
- };
- };
- fdt-1 {
- description = "FlattenedDevice Tree blob";
- data = /incbin/("arch/arm64/boot/dts/xilinx/system-top.dtb");
- type = "flat_dt";
- arch = "arm64";
- compression = "none";
-
- hash-1 {
- algo = "sha256";
- };
- };
- };
- configurations {
- default = "config-1";
-
- config-1 {
- description = "1Linux kernel, FDT blob";
- kernel = "kernel-1";
- fdt = "fdt-1";
- };
- };
- };
复制代码保存文件内容后,在终端中输入命令“mkimage -f fit-image.its image.ub”,如下图所示: 在内核源码根目录下可以找到生成的image.ub文件,如下图所示: 如何验证该文件确实可行呢。如果是通过SD卡启动开发板可以将生成的image.ub文件复制到SD卡中,如果是通过网络启动开发板,可以将其复制到/tftboot目录下,启动开发板测试。经测试,是可以启动内核的,如何启动可以参考错误!未找到引用源。节,启动结果如下图所示: 至此,我们终于知道了image.ub是怎么来的,怎么生成的了。另外image.ub既然是U-Boot fitImage,那U-Boot fitImage又是什么呢?限于篇幅就不再介绍了,可自行上网搜索,笔者找到一篇不错的介绍,推荐下,链接如下: 从该链接可知U-Boot fitImage主要来源于Unify Kernel的思想,其思想如下: “在编译linux kernel的时候,不必特意的指定具体的架构和SOC,只需要告诉kernel本次编译需要支持哪些板级的platform即可,最终将会生成一个Kernel image,以及多个和具体的板子(哪个架构、哪个SOC、哪个版型)有关的FDT image(dtb文件)。 bootloader在启动的时候,根据硬件环境,加载不同的dtb文件,即可使linux kernel运行在不同的硬件平台上,从而达到unify kernel的目标。” 关于fit更多的介绍和使用方法请参考本章的扩展阅读部分。
1.9 CPU调频策略1、设置MPSoC开发板的CPU调频策略 我们知道:主频越高,功耗也越高。为了节省CPU的功耗和减少发热,我们有必要根据当前CPU的负载状态,动态地提供刚好足够的主频给CPU。调频或称变频技术应运而生。变频技术作为电源管理技术以节能为目的加入linux内核。我们可以通过配置内核来选择不同的调频策略。 我们来看一下如何通过图形化界面配置Linux内核的CPU调频策略,输入“make menuconfig”打开Linux内核的图形化配置界面,如下图所示: 进入如下路径: - CPU PowerManagement
- ->CPU Frequency scaling
- ->Default CPUFreq governor
复制代码打开默认调频策略选择界面,如下图所示: 可以看到Linux内核一共有6种调频策略, ① Performance,最高性能,直接用最高频率,不考虑耗电。 ② Powersave,省电模式,通常以最低频率运行,系统性能会受影响,一般不会用这个。 ③ Userspace,可以在用户空间手动调节频率,可以看到这是默认的配置。 ④ Ondemand,定时检查负载,然后根据负载来调节频率。负载低的时候降低CPU频率以省电,负载高的时候提高CPU频率,增加性能。 ⑤ conservative:保守模式,类似于ondemand,但调整相对较缓。 ⑥ schedutil:4.7版本内核新增加的一种调度策略,可以直接使用调度程序提供的信息做出调整cpu频率的决策;也可以调用cpufreq驱动程序更改频率以立即调整CPU的性能,无需生成进程上下文或其他工作项。 我们可以根据实际需求选择合适的调频策略。 关于Linux内核的移植就讲解到这里,简单总结一下移植步骤: ① 在Linux内核中查找可以参考的板子,一般都是半导体厂商自己做的开发板。 ② 编译出参考板子对应的Image和.dtb文件。 ③ 使用参考板子的Image文件和.dtb文件在我们所使用的板子上启动Linux内核,看能否启动。 ④ 如果能启动的话就万事大吉,如果不能启动就需要调试Linux内核和修改设置树。不过一般都会参考半导体官方的开发板设计自己的硬件,所以大部分情况下都会启动起来。启动Linux内核用到的外设不多,一般就DRAM(Uboot都初始化好的)和串口。 ⑤ 修改相应的驱动,像USB、eMMC、SD卡等驱动官方的Linux内核都是已经提供好了,基本不会出问题。重点是网络驱动,因为Linux驱动开发一般都要通过网络调试代码,所以一定要确保网络驱动工作正常。如果是处理器内部MAC+外部PHY这种网络方案的话,一般网络驱动都很好处理,因为在Linux内核中是有外部PHY通用驱动的。只要设置好复位引脚、PHY地址信息基本上都可以驱动起来。 ⑥ Linux内核启动以后需要根文件系统,如果没有根文件系统的话肯定会崩溃,所以确定Linux内核移植成功以后就要开始根文件系统的构建。 |