完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:正点原子Linux开发板
2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》 关注官方微信号公众号,获取更多资料:正点原子 前几章我们重点讲解了如何移植uboot到I.MX6U-ALPHA开发板上,从本章开始我们就开始学习如何移植Linux内核。同uboot一样,在具体移植之前,我们先来学习一下Linux内核的顶层Makefile文件,因为顶层Makefile控制着Linux内核的编译流程。 35.1 Linux内核获取关于Linux的起源以及发展历史,这里就不啰嗦了,网上相关的介绍太多了!即使写到这里也只是水一下教程页数而已,没有任何实际的意义。有限的时间还是放到有意义的事情上吧,Linux由Linux基金会管理与发布,Linux官网为,所以你想获取最新的Linux版本就可以在这个网站上下载,网站界面如图35.1.1所示: 图35.1.1 linux官网 从图35.1.1可以看出最新的稳定版Linux已经到了5.1.4,大家没必要追新,因为4.x版本的Linux和5.x版本没有本质上的区别,5.x更多的是加入了一些新的平台、新的外设驱动而已。 NXP会从https://www.kernel.org下载某个版本的Linux内核,然后将其移植到自己的CPU上,测试成功以后就会将其开放给NXP的CPU开发者。开发者下载NXP提供的Linux内核,然后将其移植到自己的产品上。本章的移植我们就使用NXP提供的Linux源码,NXP提供Linux源码已经放到了开发板光盘中,路径为:1、例程源码-》4、NXP官方原版Uboot和Linux-》linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2。 35.2 Linux内核编译初次编译先看一下如何编译Linux源码,这里编译一下I.MX6U-ALPHA开发板移植好的Linux源码,已经放到了开发板光盘中,路径为:1、例程源码-》3、正点原子修改后的Uboot和Linux-》linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2。在Ubuntu中新建名为"alientek_linux"的文件夹,然后将linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2这个压缩包拷贝到前面新建的alientek_linux文件夹中并解压,命令如下: tar -vxjf linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2 解压完成以后的Linux源码根目录如图35.2.1所示: 图35.2.1 正点原子提供的Linux源码根目录 以EMMC核心板为例,讲解一下如何编译出对应的Linux镜像文件。新建名为"mx6ull_alientek_emmc.sh"的shell脚本,然后在这个shell脚本里面输入如下所示内容: 示例代码35.2.1 mx6ull_alientek_emmc.sh文件内容 1 #!/bin/sh 2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean 3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig 4 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig 5 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16 使用chmod给予x6ull_alientek_emmc.sh可执行权限,然后运行此shell脚本,命令如下: ./mx6ull_alientek_emmc.sh 编译的时候会弹出Linux图形配置界面,如图35.2.3所示: 图35.2.3 Linux图形配置界面 Linux的图行界面配置和uboot是一样的,这里我们不需要做任何的配置,直接按两下ESC键退出,退出图形界面以后会自动开始编译Linux。等待编译完成,完成以后如图35.2.4所示: 图35.2.4 Linux编译完成 编译完成以后就会在arch/arm/boot这个目录下生成一个叫做zImage的文件,zImage就是我们要用的Linux镜像文件。另外也会在arch/arm/boo/dts下生成很多.dtb文件,这些.dtb就是设备树文件。 编译Linux内核的时候可能会提示"recipefortarget 'arch/arm/boot/compressed/piggy.lzo' failed",如图35.2.5所示: 图35.2.5 lzop未找到 图35.2.5中的错误提示lzop未找到,原因是没有安装lzop库,输入如下命令安装lzop库即可解决: sudoapt-getinstalllzop lzop库安装完成以后在重新编译一下Linux内核即可。 看一下编译脚本mx6ull_alientek_emmc.sh的内容,文件内容如下: 示例代码35.2.1 mx6ull_alientek_emmc.sh文件内容 1 #!/bin/sh 2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean 3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig 4 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig 5 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16 第2行,执行"makedistclean",清理工程,所以mx6ull_alientek_emmc.sh每次都会清理一下工程。如果通过图形界面配置了Linux,但是还没保存新的配置文件,那么就要慎重使用mx6ull_alientek_emmc.sh编译脚本了,因为它会把你的配置信息都删除掉! 第3行,执行"makexxx_defconfig",配置工程。 第4行,执行"makemenuconfig",打开图形配置界面,对Linux进行配置,如果不想每次编译都打开图形配置界面的话可以将这一行删除掉。 第5行,执行"make",编译Linux源码。 可以看出,Linux的编译过程基本和uboot一样,都要先执行"makexxx_defconfig"来配置一下,然后在执行"make"进行编译。如果需要使用图形界面配置的话就执行"makemenuconfig"。 35.3 Linux工程目录分析将正点原子提供的Linux源码进行解压,解压完成以后的目录如图35.3.1所示: 图35.3.1未编译的Linux源码目录 图35.3.1就是正点原子提供的未编译的Linux源码目录文件,我们在分析Linux之前一定要先在Ubuntu中编译一下Linux,因为编译过程会生成一些文件,而生成的这些恰恰是分析Linux不可或缺的文件。编译完成以后使用tar压缩命令对其进行压缩并使用Filezilla软件将压缩后的uboot源码拷贝到Windows下。 编译后的Linux目录如图35.3.2所示: 图35.3.2 编译后的Linux目录 图35.3.2中重要的文件夹或文件的含义见表35.3.1所示: 表35.3.1 Linux目录 表35.3.1中的很多文件夹和文件我们都不需要去关心,我们要关注的文件夹或文件如下: 1、arch目录 这个目录是和架构有关的目录,比如arm、arm64、avr32、x86等等架构。每种架构都对应一个目录,在这些目录中又有很多子目录,比如boot、common、configs等等,以arch/arm为例,其子目录如图35.3.2所示: 图35.3.2 arch/arm子目录 图35.3.2是arch/arm的一部分子目录,这些子目录用于控制系统引导、系统调用、动态调频、主频设置等。arch/arm/configs目录是不同平台的默认配置文件:xxx_defconfig,如图35.3.3所示: 图35.3.3 配置文件 在arch/arm/configs中就包含有I.MX6U-ALPHA开发板的默认配置文件:imx_v7_defconfig,执行"make imx_v7_defconfig"即可完成配置。arch/arm/boot/dts目录里面是对应开发平台的设备树文件,正点原子I.MX6U-ALPHA开发板对应的设备树文件如图35.3.4所示: 图35.3.4 正点原子I.MX6U开发板对应的设备树 arch/arm/boot目录下会保存编译出来的Image和zImage镜像文件,而zImage就是我们要用的linux镜像文件。 arch/arm/mach-xxx目录分别为相应平台的驱动和初始化文件,比如mach-imx目录里面就是I.MX系列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目录 头文件目录。 9、init目录 此目录存放Linux内核启动的时候初始化代码。 10、ipc目录 IPC为进程间通信,ipc目录是进程间通信的具体实现代码。 11、kernel目录 Linux内核代码。 12、lib目录 lib是库的意思,lib目录都是一些公用的库函。 13、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源码的目录信息,建议仔细阅读一下此文件。 关于Linux源码目录就分析到这里,接下来分析一下Linux的顶层Makefile。 35.4 VSCode工程创建在分析Linux的顶层Makefile之前,先创建VSCode工程,创建过程和uboot一样。创建好以后将文件.vscode/settings.json改为如下所示内容: 示例代码35.4.1.1 settings.json文件内容 1{ 2"search.exclude":{ 3"**/node_modules": true, 4"**/bower_components": true, 5"**/*.o":true, 6"**/*.su":true, 7"**/*.cmd":true, 8"Documentation":true, 9 10/* 屏蔽不用的架构相关的文件 */ 11"arch/alpha":true, 12"arch/arc":true, 13"arch/arm64":true, 14"arch/avr32":true, 15"arch/[b-z]*":true, 16"arch/arm/plat*":true, 17"arch/arm/mach-[a-h]*":true, 18"arch/arm/mach-[n-z]*":true, 19"arch/arm/mach-i[n-z]*":true, 20"arch/arm/mach-m[e-v]*":true, 21"arch/arm/mach-k*":true, 22"arch/arm/mach-l*":true, 23 24/* 屏蔽排除不用的配置文件 */ 25"arch/arm/configs/[a-h]*":true, 26"arch/arm/configs/[j-z]*":true, 27"arch/arm/configs/imo*":true, 28"arch/arm/configs/in*":true, 29"arch/arm/configs/io*":true, 30"arch/arm/configs/ix*":true, 31 32/* 屏蔽掉不用的DTB文件 */ 33"arch/arm/boot/dts/[a-h]*":true, 34"arch/arm/boot/dts/[k-z]*":true, 35"arch/arm/boot/dts/in*":true, 36"arch/arm/boot/dts/imx1*":true, 37"arch/arm/boot/dts/imx7*":true, 38"arch/arm/boot/dts/imx2*":true, 39"arch/arm/boot/dts/imx3*":true, 40"arch/arm/boot/dts/imx5*":true, 41"arch/arm/boot/dts/imx6d*":true, 42"arch/arm/boot/dts/imx6q*":true, 43"arch/arm/boot/dts/imx6s*":true, 44"arch/arm/boot/dts/imx6ul-*":true, 45"arch/arm/boot/dts/imx6ull-9x9*":true, 46"arch/arm/boot/dts/imx6ull-14x14-ddr*":true, 47}, 48"files.exclude":{ 49"**/.git": true, 50"**/.svn": true, 51"**/.hg": true, 52"**/CVS": true, 53"**/.DS_Store": true, 54"**/*.o":true, 55"**/*.su":true, 56"**/*.cmd":true, 57"Documentation":true, 58 59/* 屏蔽不用的架构相关的文件 */ 60"arch/alpha":true, 61"arch/arc":true, 62"arch/arm64":true, 63"arch/avr32":true, 64"arch/[b-z]*":true, 65"arch/arm/plat*":true, 66"arch/arm/mach-[a-h]*":true, 67"arch/arm/mach-[n-z]*":true, 68"arch/arm/mach-i[n-z]*":true, 69"arch/arm/mach-m[e-v]*":true, 70"arch/arm/mach-k*":true, 71"arch/arm/mach-l*":true, 72 73/* 屏蔽排除不用的配置文件 */ 74"arch/arm/configs/[a-h]*":true, 75"arch/arm/configs/[j-z]*":true, 76"arch/arm/configs/imo*":true, 77"arch/arm/configs/in*":true, 78"arch/arm/configs/io*":true, 79"arch/arm/configs/ix*":true, 80 81/* 屏蔽掉不用的DTB文件 */ 82"arch/arm/boot/dts/[a-h]*":true, 83"arch/arm/boot/dts/[k-z]*":true, 84"arch/arm/boot/dts/in*":true, 85"arch/arm/boot/dts/imx1*":true, 86"arch/arm/boot/dts/imx7*":true, 87"arch/arm/boot/dts/imx2*":true, 88"arch/arm/boot/dts/imx3*":true, 89"arch/arm/boot/dts/imx5*":true, 90"arch/arm/boot/dts/imx6d*":true, 91"arch/arm/boot/dts/imx6q*":true, 92"arch/arm/boot/dts/imx6s*":true, 93"arch/arm/boot/dts/imx6ul-*":true, 94"arch/arm/boot/dts/imx6ull-9x9*":true, 95"arch/arm/boot/dts/imx6ull-14x14-ddr*":true, 96} 97} 创建好VSCode工程以后就可以开始分析Linux的顶层Makefile了。 35.5 顶层Makefile详解Linux的顶层Makefile和uboot的顶层Makefile非常相似,因为uboot参考了Linux,前602行几乎一样,所以前面部分我们大致看一下就行了。 1、版本号 顶层Makefile一开始就是Linux内核的版本号,如下所示: 示例代码35.5.1 顶层Makefile代码段 1 VERSION =4 2 PATCHLEVEL =1 3 SUBLEVEL =15 4 EXTRAVERSION = 可以看出,Linux内核版本号为4.1.15。 2、MAKEFLAGS变量 MAKEFLAGS变量设置如下所示: 示例代码35.5.2 顶层Makefile代码段 16 MAKEFLAGS +=-rR --include-dir=$(CURDIR) 3、命令输出 Linux编译的时候也可以通过"V=1"来输出完整的命令,这个和uboot一样,相关代码如下所示: 示例代码35.5.3 顶层Makefile代码段 69 ifeq ("$(origin V)","command line") 70 KBUILD_VERBOSE = $(V) 71 endif 72 ifndef KBUILD_VERBOSE 73 KBUILD_VERBOSE =0 74 endif 75 76 ifeq ($(KBUILD_VERBOSE),1) 77 quiet = 78 Q = 79else 80 quiet=quiet_ 81 Q = @ 82 endif 4、静默输出 Linux编译的时候使用"make-s"就可实现静默编译,编译的时候就不会打印任何的信息,同uboot一样,相关代码如下: 示例代码35.5.4 顶层Makefile代码段 87 ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4 88 ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),) 89 quiet=silent_ 90 endif 91else # make-3.8x 92 ifneq ($(filter s%-s%,$(MAKEFLAGS)),) 93 quiet=silent_ 94 endif 95 endif 96 97 export quiet Q KBUILD_VERBOSE 5、设置编译结果输出目录 Linux编译的时候使用"O=xxx"即可将编译产生的过程文件输出到指定的目录中,相关代码如下: 示例代码35.5.5 顶层Makefile代码段 116 ifeq ($(KBUILD_SRC),) 117 118 # OK, Make called in directory where kernel src resides 119 # Do we want to locate output files in a separate directory? 120 ifeq ("$(origin O)","command line") 121 KBUILD_OUTPUT := $(O) 122 endif 6、代码检查 Linux也支持代码检查,使用命令"make C=1"使能代码检查,检查那些需要重新编译的文件。"make C=2"用于检查所有的源码文件,顶层Makefile中的代码如下: 示例代码35.5.6 顶层Makefile代码段 172 ifeq ("$(origin C)","command line") 173 KBUILD_CHECKSRC = $(C) 174 endif 175 ifndef KBUILD_CHECKSRC 176 KBUILD_CHECKSRC =0 177 endif 7、模块编译 Linux允许单独编译某个模块,使用命令"make M=dir"即可,旧语法"make SUBDIRS=dir"也是支持的。顶层Makefile中的代码如下: 示例代码35.5.7 顶层Makefile代码段 179 # Use make M=dir to specify directory of external module to build 180 # Old syntax make ... SUBDIRS=$PWD is still supported 181 # Setting the environment variable KBUILD_EXTMOD take precedence 182 ifdef SUBDIRS 183 KBUILD_EXTMOD ?= $(SUBDIRS) 184 endif 185 186 ifeq ("$(origin M)","command line") 187 KBUILD_EXTMOD := $(M) 188 endif 189 190 # If building an external module we do not care about the all: rule 191 # but instead _all depend on modules 192 PHONY += all 193 ifeq ($(KBUILD_EXTMOD),) 194 _all: all 195else 196 _all: modules 197 endif 198 199 ifeq ($(KBUILD_SRC),) 200 # building in the source tree 201 srctree :=. 202else 203 ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR))) 204 # building in a subdirectory of the source tree 205 srctree :=.. 206else 207 srctree := $(KBUILD_SRC) 208 endif 209 endif 210 objtree :=. 211 src := $(srctree) 212 obj := $(objtree) 213 214 VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD)) 215 216 export srctree objtree VPATH 外部模块编译过程和uboot也一样,最终导出srctree、objtree和VPATH这三个变量的值,其中srctree=.,也就是当前目录,objtree同样为"."。 |
|
相关推荐
|
|
590 浏览 0 评论
AI模型部署边缘设备的奇妙之旅:如何在边缘端部署OpenCV
2241 浏览 0 评论
tms320280021 adc采样波形,为什么adc采样频率上来波形就不好了?
1233 浏览 0 评论
1788 浏览 0 评论
1464 浏览 0 评论
74820 浏览 21 评论
浏览过的版块 |
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 00:36 , Processed in 1.128429 second(s), Total 63, Slave 45 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号